Boost logo

Boost :

Subject: Re: [boost] [uuids] On boost::uuids::uuid operator == performance.
From: Peter Dimov (pdimov_at_[hidden])
Date: 2012-04-17 08:04:40


Michael Kochetkov wrote:
> I have 6 years old Xeon 5130 and for your original code (with zeros):

The numbers I cited are for id1 random, id2 equal to id1.

    boost::uuids::uuid id1 = boost::uuids::random_generator()(), id2 = id1;

The random id1 avoids the smartness to keep a zero in a register, and id2
being equal to it at the start leads to a predictable nonzero number of
equalities (48830 out of the 100M total).

This is what I get with 2010:

operator==
    48830: 410

Eq16
    48830: 299

memcmp
    48830: 400

(I changed it to s += memcmp( id1.data, id2.data, 16 ) == 0; to match the
others. The original gave something: 356. 2010 is smart enough here to avoid
the trailing byte loop; it sees that the length is divisible by 16 and only
does DWORD compares.)

my_memcmp
    48830: 272

There you go. CPUs are odd beasts. I tried, just for the fun of it, the
totally unoptimized by hand

template<class It1, class It2> inline bool my_equal( It1 first, It1 last,
It2 first2 )
{
    for( ; first != last; ++first, ++first2 )
    {
        if( *first != *first2 ) return false;
    }

    return true;
}

and then

    s += my_equal( id1.begin(), id1.end(), id2.begin() );

and what do you think?

    48830: 274

Go figure.

> 2. the investigation of opinions of boost people (I have made another
> inquiry in "[boost] [function] The cost of boost::function" thread) shows
> that boost still is not ready for production usage.

Don't use it in production then. I do, and it works well for me. Already has
for ten years or so.

Appendix A, program:

#include <boost/uuid/uuid.hpp>
#include <boost/uuid/random_generator.hpp>

#include <iostream>

#include <windows.h>
#include <mmsystem.h>
#pragma comment( lib, "winmm.lib" )

typedef unsigned uint32_t;

inline bool Eq16( unsigned char const * p, unsigned char const * q )
{
    return *reinterpret_cast<const uint32_t*>( p ) ==
*reinterpret_cast<const uint32_t*>( q )
        && *reinterpret_cast<const uint32_t*>( p+4 ) ==
*reinterpret_cast<const uint32_t*>( q+4 )
        && *reinterpret_cast<const uint32_t*>( p+8 ) ==
*reinterpret_cast<const uint32_t*>( q+8 )
        && *reinterpret_cast<const uint32_t*>( p+12) ==
*reinterpret_cast<const uint32_t*>( q+12);
}

inline bool my_memcmp( unsigned char const * p, unsigned char const * q,
size_t n )
{
    for( size_t i = 0; i < n; ++i )
    {
        if( p[i] != q[i] ) return false;
    }

    return true;
}

template<class It1, class It2> inline bool my_equal( It1 first, It1 last,
It2 first2 )
{
    for( ; first != last; ++first, ++first2 )
    {
        if( *first != *first2 ) return false;
    }

    return true;
}

int main()
{
    boost::uuids::uuid id1 = boost::uuids::random_generator()(), id2 = id1;

    int const N = 100000000;

    DWORD t1 = timeGetTime();

    int s = 0;

    for( int i = 0; i < N; ++i )
    {
        //s += ( id1 == id2 );
        //s += Eq16( id1.data, id2.data );
        //s += memcmp( id1.data, id2.data, 16 ) == 0;
        //s += my_memcmp( id1.data, id2.data, 16 );
        s += my_equal( id1.begin(), id1.end(), id2.begin() );
        id2.data[ i % 16 ] += i & 0xFF;
    }

    DWORD t2 = timeGetTime();

    std::cout << s << ": " << t2 - t1 << std::endl;
}


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk