[Issue 5282] Optimize array comparison which use memcmp to something better and remove unnecessary indirections.

d-bugmail at puremagic.com d-bugmail at puremagic.com
Sun Nov 28 22:00:53 PST 2010


http://d.puremagic.com/issues/show_bug.cgi?id=5282


Rob Jacques <sandford at jhu.edu> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Keywords|                            |performance
                 CC|                            |sandford at jhu.edu
            Summary|Use memcmp or other         |Optimize array comparison
                   |appropriate optimizations   |which use memcmp to
                   |for array comparison where  |something better and remove
                   |possible                    |unnecessary indirections.


--- Comment #4 from Rob Jacques <sandford at jhu.edu> 2010-11-28 21:59:20 PST ---
Here are two optimized routines for bit-wise comparing two arrays for equality,
for both the dynamic/dynamic and dynamic/static case. These are significantly
faster than memcmp (~2.5x) and D's built-in == operator (~3.3x) for the
dynamic/dynamic case in a micro-benchmark. (The static case is naturally even
faster) The difference between memcmp and '==' appears to be due to inlining:
calling memcmp via a member function of a class (instead of from a free
function) had approximately the same performance as D's '=='. 

This seems to indicate that a) use of memcmp in druntime for equality tests
should be replaced with the below routine and b) DMD should be calling
free-function versions of these routines instead of using multiple
indirections.

(By the way, does anyone know where array comparisons live in D? I tried
modifying TypeInfo_Ag, but that didn't seem to work)

/// Returns: true if the contents of two arrays are bit-wise equal.
bool bitwiseEquality(T) (const T[] a, const T[] b) pure nothrow @trusted {
    if(a.length != b.length )
        return false;
    if(a.ptr is b.ptr)
        return true;
    size_t byte_length = a.length*T.sizeof;
    size_t alignment   = byte_length % ulong.sizeof;
    if(( (*(cast(ulong*)a.ptr) ^ *(cast(ulong*)b.ptr)) << 8 *
(ulong.sizeof-alignment) ))
        return false;
    alignment  += (!alignment) * ulong.sizeof;
    auto pa     = cast(ulong*)(cast(ubyte*)a.ptr + alignment);
    auto pb     = cast(ulong*)(cast(ubyte*)b.ptr + alignment);
    auto pa_end = cast(ulong*)(cast(ubyte*)a.ptr + byte_length);
    while (pa < pa_end)
        if(*pa++ != *pb++ )
            return false;
    return true;
}
/// Returns: true if the contents of two arrays are bit-wise equal.
bool bitwiseEquality(T, size_t N)(const T[] a, ref const T[N] b) pure nothrow
@trusted {
    static if(T.sizeof*N <= uint.sizeof) {
        return a.length == N && !( (*(cast(uint*)a.ptr)  ^ *(cast(uint*)b.ptr))
 & (uint.max >> 8*(uint.sizeof  - T.sizeof*N) ));
    } else static if(T.sizeof*N <= ulong.sizeof) {
        return a.length == N && !( (*(cast(ulong*)a.ptr) ^
*(cast(ulong*)b.ptr)) & (ulong.max>> 8*(ulong.sizeof - T.sizeof*N) ));
    } else { // Fall back to a loop
        if(a.length != N || (*(cast(ulong*)a.ptr) != *(cast(ulong*)b.ptr)) )
return false;
        enum alignment = T.sizeof*N % ulong.sizeof > 0 ? T.sizeof*N %
ulong.sizeof : ulong.sizeof;
        auto pa      = cast(ulong*)(cast(ubyte*)a.ptr + alignment);
        auto pb      = cast(ulong*)(cast(ubyte*)b.ptr + alignment);
        auto pa_end  = cast(ulong*)(cast(ubyte*)a.ptr + T.sizeof*N);
        while (pa < pa_end) {
            if(*pa++ != *pb++ ) return false;
        }
        return true;
    }
}

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------


More information about the Digitalmars-d-bugs mailing list