Question

I have this piece of code which accesses some information about a point on a 'x' and 'y' axis. This information is later used to draw some points onto the screen. This is how the code works:

//MAX_X_COORD has a value of 169 
//MAX_Y_COORD has a value of 55
void RedrawFromDATAtable() 
{
    COORD pos;
    HANDLE tmpbuf = CreateConsoleScreenBuffer(GENERIC_WRITE , NULL, NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
    WriteConsoleA(tmpbuf, " ", 1, NULL, NULL);
    if(SetConsoleActiveScreenBuffer(tmpbuf)==0)
    {MessageBoxA(NULL, "ERROR", "ERROR", 0);return;}
    bufferdata_ex *  dptr;
    //bufferdata_ex * y_dptr;
    int  * lcol(new int); //Increases speed by reducing function calls - Experienced about twice as fast drawing!

for(short x=0;x<MAX_X_COORD;x++)
    {
        //y_dptr = bridge->DATA[x];
        for(short y=0;y<MAX_Y_COORD;y++) 
        {

            //dptr = (y_dptr+y); //Rewrite to use a constant pointer!
            dptr = &(_bridge->DATA[x][y]);
            if(dptr->InUse==true)
            {
            {
                pos.X = x;
                pos.Y = y;
                SetConsoleCursorPosition(output, pos);
                //haschanged = false;
            }
            if(!(*lcol==dptr->color)) //Need for a new color?
            {   SetConsoleTextAttribute(output, dptr->color);lcol = &dptr->color;}

            char c((char)dptr->sym);
            WriteConsoleA(output, &c, 1, NULL, NULL);
                lcol = &dptr->color;
            }

        }

    }
SetConsoleTextAttribute(output, bridge->current_color);
SetConsoleCursorPosition(output, last_mouse_position);
SetConsoleActiveScreenBuffer(output);
CloseHandle(tmpbuf);
delete lcol;
}

Cut to the case!

Alright! So recently I had a thought that accessing the array like that would slow down my code. As far as I know then whenever you access an element in an array the processor will take the base adress of the array and from there by multiply the size of the elements by the index which is used to find the adress of the specified element. My thought here was that if I ask the processor to do that multiple times, instead of just creating a pointer to the adress, and then use that to process my elements, then it would slow down my code. So I rewrote the code to the following:

void RedrawFromDATAtable() 
{
    COORD pos;
    HANDLE tmpbuf = CreateConsoleScreenBuffer(GENERIC_WRITE , NULL, NULL, CONSOLE_TEXTMODE_BUFFER, NULL);
    WriteConsoleA(tmpbuf, " ", 1, NULL, NULL);
    if(SetConsoleActiveScreenBuffer(tmpbuf)==0)
    {MessageBoxA(NULL, "ERROR", "ERROR", 0);return;}
    bufferdata_ex *  dptr;
    bufferdata_ex * y_dptr;
    int  * lcol(new int); //Increases speed by reducing function calls - Experienced about twice as fast drawing!

for(short x=0;x<MAX_X_COORD;x++)
    {
        y_dptr = _bridge->DATA[x];
        for(short y=0;y<MAX_Y_COORD;y++) 
        {

            dptr = (y_dptr+y); //Rewrite to use a constant pointer!
            //dptr = &(bridge->DATA[x][y]);
            if(dptr->InUse==true)
            {
            {
                pos.X = x;
                pos.Y = y;
                SetConsoleCursorPosition(output, pos);
                //haschanged = false;
            }
            if(!(*lcol==dptr->color)) //Need for a new color?
            {   SetConsoleTextAttribute(output, dptr->color);lcol = &dptr->color;}

            char c((char)dptr->sym);
            WriteConsoleA(output, &c, 1, NULL, NULL);
                lcol = &dptr->color;
            }

        }

    }
SetConsoleTextAttribute(output, bridge->current_color);
SetConsoleCursorPosition(output, last_mouse_position);
SetConsoleActiveScreenBuffer(output);
CloseHandle(tmpbuf);
delete lcol;
}

The idea seems perfectly fine to me, but the problem is that the first piece of code is faster than the second piece of code! So my question is: Why is it the first piece of code is faster than the second piece of code?

For those who doesn't like to read:

Why is the first piece of code faster than the other? The first one takes 0.0919 seconds to finish where the second takes 0.226 seconds.

Also this is a copy of how the assembly handles the pointers:

    //No pointers
dptr = &(bridge->DATA[x][y]);
001B41C6  mov         eax,dword ptr [this]  
001B41C9  mov         ecx,dword ptr [eax+14h]  
001B41CC  movsx       edx,word ptr [x]  
001B41D0  imul        edx,edx,370h  
001B41D6  lea         eax,[ecx+edx+1D4h]  
001B41DD  movsx       ecx,word ptr [y]  
001B41E1  shl         ecx,4  
001B41E4  add         eax,ecx  
001B41E6  mov         dword ptr [dptr],eax  


//With pointers
//Pointing to DATA[x]
012C41A5  mov         eax,dword ptr [this]  
012C41A8  mov         ecx,dword ptr [eax+14h]  
012C41AB  movsx       edx,word ptr [x]  
012C41AF  imul        edx,edx,370h  
012C41B5  lea         eax,[ecx+edx+1D4h]  
012C41BC  mov         dword ptr [y_dptr],eax 


//Pointing to DATA[x]+y
012C41E0  movsx       eax,word ptr [y]  
012C41E4  shl         eax,4  
012C41E7  add         eax,dword ptr [y_dptr]  
012C41EA  mov         dword ptr [dptr],eax  

other than this part of the code, then the rest is identical.

Was it helpful?

Solution

Looking only at the assembly we see an extra mov (the assignment of y_dptr).
Seeing how this is done on every iteration in the (outer) loop and there are no other differences in the code, this could be your reason for performance decrease.
Other than that, there is really nothing in your code that takes advantage of the pointer magic you are trying to use.
f.e. You use dptr = (y_dptr+y); where you can lose either dptr or y_dptr by using increment on the pointer directly (y_dptr++;).
This is some pointer arithmetic magic you are not using and could be improved.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top