Web lists-archives.com

Re: calloc speed difference




Lee wrote:
Why is the cygwin gcc calloc so much slower than the
i686-w64-mingw32-gcc calloc?
   1:12 vs 0:11

$cat calloc-test.c
#include <stdio.h>
#include <stdlib.h>
#define ALLOCATION_SIZE (100 * 1024 * 1024)
int main (int argc, char *argv[]) {
     for (int i = 0; i < 10000; i++) {
         void *temp = calloc(ALLOCATION_SIZE, 1);
         if ( temp == NULL ) {
            printf("drat! calloc returned NULL\n");
            return 1;
         }
         free(temp);
     }
     return 0;
}


Could reproduce the difference on an older i7-2600K machine:

Cygwin: ~20s
MinGW: ~4s

Timing [cm]alloc() calls without actually using the allocated memory might produce misleading results due to lazy page allocation and/or zero-filling.

MinGW binaries use calloc() from msvcrt.dll. This calloc() does not call malloc() and then memset(). It directly calls:

  mem = HeapAlloc(_crtheap, HEAP_ZERO_MEMORY, size);

which possibly only reserves allocate-and-zero-fill-on-demand pages for later.

Cygwin's calloc() is different.

This variant of the above code adds one write access to each 4KiB page (guarded by "volatile" to prevent dead assignment optimization):

#include <stdio.h>
#include <stdlib.h>
#define ALLOCATION_SIZE (100 * 1024 * 1024)
int main (int argc, char *argv[]) {
    for (int i = 0; i < 1000; i++) {
        void *temp = calloc(ALLOCATION_SIZE, 1);
        if ( temp == NULL ) {
           printf("drat! calloc returned NULL\n");
           return 1;
        }
        for (int j = 0; j < ALLOCATION_SIZE; j += 4096)
          ((volatile char *)temp)[j] = (char)i;
        free(temp);
    }
    return 0;
}

Results:

Cygwin: ~310s
MinGW: ~210s

Christian


--
Problem reports:       http://cygwin.com/problems.html
FAQ:                   http://cygwin.com/faq/
Documentation:         http://cygwin.com/docs.html
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple