Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::set fast and slow, what is going on?

Tags:

c++

windows

set

stl

I've come up across a strange behaviour of std::set.

Here is the code:

#include <cstdio>
#include <windows.h>
#include <stdlib.h>

#include <vector>
#include <set>

using namespace std;

int main(int argc, char *argv[])
{
    set<int> b[100];

    for (int o=0; o<10; o++)
    {
        int tt = GetTickCount();

        for (int i=0; i<5000000; i++)
        {
            b[o].insert(i);
        }

        tt = GetTickCount() - tt;

        b[o].clear();

        printf("%d\n", tt);
    }

    return 0;
}

I'm running on Windows XP.

Here is the interesting part: this first printed time is about 3500 ms, while all next are over 9000 ms! Why is that happening?

Oh, and this only happens on release version (-O2 optimization).

It doesn't happen on Linux (after changing code to compile there).

One more thing: when I run it while profiling with Intel VTune it always takes about 3000 ms, so it's the way it should be.

UPDATE: Here is some new code:

#include <cstdio>
#include <windows.h>
#include <stdlib.h>

int main(int argc, char *argv[])
{
const int count = 10000000;
int **a = new int*[count];

for (int o=0; o<10; o++)
{
    int ttt = GetTickCount();

    for (int i=0; i<count; i++)
    {
        a[i] = new int;

        *a[i] = i;
    }

    int ttt2 = GetTickCount();

    for (int i=0; i<count; i++)
    {
        int r1 = rand() * 10000 + rand();
        int r2 = rand() * 10000 + rand();
        r1 = r1%count;
        r2 = r2%count;

        int *e = a[r1];
        a[r1] = a[r2];
        a[r2] = e;
    }

    int ttt3 = GetTickCount();

    for (int i=0; i<count; i++)
    {
        delete a[i];
    }

    int ttt4 = GetTickCount();

    printf("%d %d\n", ttt2-ttt, ttt4-ttt3);
}

return 0;
}

This is the same problem. What happens is I allocate many many small objects and then delete them in random order - so it is similar to how it looks in std::set. So this is Windows memory management problem. It can't really handle well many small allocs and deletes.

like image 626
tweety3d Avatar asked Nov 16 '11 11:11

tweety3d


1 Answers

I cannot explain exactly why this is happening but I could propose a solution. I've been able to reproduce this on my PC when I run the release build under the debugger (with F5). When I run the build from the command line or with Ctrl-F5 I don't get that kind of behavior.

This has something to do with the debug heap which is on by default when you launch under the debugger. It's described in great detail here. To prevent this from happening either

  1. Run from the command line or with Ctrl-F5 (Debug -> Start Without Debugging).
  2. Go to Project -> Properties -> Debugging -> Environment and add _NO_DEBUG_HEAP=1.

If I had to guess I would say that it has something to do with the implementation of the memory allocation tracking in Windows/VS runtime. Probably some internal lists fill up and reallocate or something else along these lines.

like image 192
detunized Avatar answered Oct 09 '22 12:10

detunized