Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Reducing Page Faults

0.00/5 (No votes)
25 Dec 2018 1  
Using native GDI will decrease page faults

Introduction

My application does a lot of page faults. From what I found on line, it is unlikely that it should cause any issues, but it got me interested to investigate: what is causing the huge number of page faults, and if there is a way to decrease it.

Background

Few years ago, I was trying to get my 12-year-old son interested in programming (sorry, even kept original name MyFirstGame). As a result, we designed a simple game.
Please note: This article is not about the game - I am just using the game to investigate page faults counts. While you are playing it, using standard .NET graphical objects, you get about 25000-page faults / seconds.

Using the Code

Code has a simple board (5 rows, 4 columns). Squares are randomly placed on each row, and the player should hit the black square to make it go away. If you did not click on it, and it reached the bottom, you lost, if you hit a white square, you lost. Board is drawn inside of the Form1 object, method "Draw", using standard .NET.

When you click on "Use GDI", gdi32.dll is used - in method Draw2. You can see drastic decrease in page faults as you do it.

(To make it easier to observe, I display page faults on screen every second, no need to open Task Manager.)

Also, average draw speed is ~10 times faster using GDI.

Draw method looks like this:

private void Draw(Graphics g)
{
    if (checkBoxUseGDI.Checked)
    {
        Draw2(g);
        return;
    }

    graphics.Clear(Color.White);

    int left = 0;
    int top = board.Top;
    for (int i = 0; i < 5; i++)
    {
        for (int j = 0; j < 4; j++)
        {
            Rectangle rect = new Rectangle(left, top, 100, 150);

            if (board.Cells[i, j] > -1)
            {
                graphics.FillRectangle(Brushes.Black, rect);
            }

            graphics.DrawRectangle(Pens.Black, rect);

            left += 100;
        }

        top += 150;
        left = 0;
    }
    g.DrawImage(bitmap, 0, 0);
}

Draw2 method looks like this:

private void Draw2(Graphics g)
{
    IntPtr hdc2 = g.GetHdc();
    IntPtr hdc = GDI.CreateCompatibleDC(hdc2);
    IntPtr hBitmap = GDI.CreateCompatibleBitmap(hdc, 401, 601);
    GDI.SelectObject(hdc, hBitmap);
    IntPtr brushWhite = GDI.CreateSolidBrush(0xFFFFFF);
    GDI.FillRgn(hdc, GDI.CreateRectRgn(0, 0, 401, 601), brushWhite);
    GDI.DeleteObject(brushWhite);
    IntPtr brushBlack = GDI.CreateSolidBrush(0x0);

    int left = 0;
    int top = board.Top;
    for (int i = 0; i < 5; i++)
    {
        for (int j = 0; j < 4; j++)
        {
            GDI.Rectangle(hdc, left, top, left + 101, top + 151);

            if (board.Cells[i, j] > -1)
            {
                GDI.FillRgn(hdc, GDI.CreateRectRgn(left, top, left + 101, top + 151), brushBlack);
            }

            left += 100;
        }

        top += 150;
        left = 0;
    }
    GDI.DeleteObject(brushBlack);

    GDI.BitBlt(hdc2, 0, 0, 401, 601, hdc, 0, 0, GDI.TernaryRasterOperations.SRCCOPY);
    g.ReleaseHdc(hdc2);

    GDI.DeleteDC(hdc);
    GDI.DeleteObject(hBitmap);
}

Points of Interest

I found this website to be very helpful: http://pinvoke.net/default.aspx

History

  • 26th December, 2018: Initial version

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here