cmpxchg for WORD faster than for BYTE

Viewed 1124

Yesterday I posted this question on how to write a fast spinlock. Thanks to Cory Nelson I seem to have found a method which outperforms the other methods discussed in my question. I use the CMPXCHG instruction to check if the lock is 0 and thereby free. CMPXCHG operates on ´BYTE´, WORD and DWORD. I would assume that the instruction would operate faster on BYTE. But I wrote a lock implementing each of the datatypes:

inline void spin_lock_8(char* lck)
{
    __asm
    {
        mov ebx, lck                        ;move lck pointer into ebx
        xor cl, cl                          ;set CL to 0
        inc cl                              ;increment CL to 1
        pause                               ;
        spin_loop:
        xor al, al                          ;set AL to 0
        lock cmpxchg byte ptr [ebx], cl     ;compare AL to CL. If equal ZF is set and CL is loaded into address pointed to by ebx
        jnz spin_loop                       ;jump to spin_loop if ZF
    }
}
inline void spin_lock_16(short* lck)
{
    __asm
    {
        mov ebx, lck
        xor cx, cx
        inc cx
        pause
        spin_loop:
        xor ax, ax
        lock cmpxchg word ptr [ebx], cx
        jnz spin_loop
    }
}
inline void spin_lock_32(int* lck)
{
    __asm
    {
        mov ebx, lck
        xor ecx, ecx
        inc ecx
        pause
        spin_loop:
        xor eax, eax
        lock cmpxchg dword ptr [ebx], ecx
        jnz spin_loop
    }
}
inline spin_unlock(<anyType>* lck)
{
    __asm
    {
        mov ebx, lck
        mov <byte/word/dword> ptr [ebx], 0
    }
}

The lock was then tested using the following pseudo-code (please note that the lcm-pointer always will point to an address dividable by 4):

<int/short/char>* lck;
threadFunc()
{
    loop 10,000,000 times
    {
        spin_lock_8/16/32 (lck);
        spin_unlock(lck);
    }
}
main()
{
    lck = (char/short/int*)_aligned_malloc(4, 4);//Ensures memory alignment
    start 1 thread running threadFunc and measure time;
    start 2 threads running threadFunc and measure time;
    start 4 threads running threadFunc and measure time;
    _aligned_free(lck);
}

I've gotten the following results measured in msecs on a processor with 2 physical cores able to run 4 threads (Ivy Bridge).

           1 thread    2 threads     4 threads
8-bit      200         700           3200
16-bit     200         500           1400
32-bit     200         900           3400

The data suggests that all functions take an equal amount of time to execute. But when multiple threads have to check if lck == 0 using a 16-bit can be significantly faster. Why is that? I do not suppose it has something to do with the alignment of the lck?

Thanks in advance.

2 Answers
Related