5

Which is the fastest?

I tried to test the speeds of the three methods in a basic capacity with this:

#include "stdafx.h"
#include "stdlib.h"
#include "stdio.h"
#include "time.h"

int _tmain(int argc, _TCHAR* argv[])
{
  const unsigned long long ARR_SIZ = 0x4fffffff;
  clock_t val_init_dur, calloc_dur, manual_dur;
  clock_t cur = clock();
  char* val_init = new char[ARR_SIZ]();
  clock_t after = clock();
  val_init_dur = after-cur;
  delete[] val_init;

  cur = clock();
  void* calloc_init = calloc(ARR_SIZ, sizeof(char));
  after = clock();
  calloc_dur = after-cur;
  free(calloc_init);

  cur = clock();
  char* manual_init = new char[ARR_SIZ];
  for (unsigned long i=0; i < ARR_SIZ; i++)
    manual_init[i] = 0;
  after = clock();
  manual_dur = after-cur;
  delete[] manual_init;

  printf("Value Initialization Duration: %d\n", val_init_dur);
  printf("Calloc Initialization Duration: %d\n", calloc_dur);
  printf("Manual Initialization Duration: %d\n", manual_dur);
  fgetc(stdin);
  return 0;
}

My results were:

Value Initialization Duration: 541

Calloc Initialization Duration: 493

Manual Initialization Duration: 3424

But I have several issues with my current test:

  • I don't know if I properly isolated the three different methods of initialization
  • I didn't test all methods of initializing an array of zeros (memset and malloc, which I suspect work like calloc)
  • The results are in seconds (ew!) which are horribly quantized. (No ms time?)
  • The value for ARR_SIZ is not the maximum permitted size by VS '12 (0x7FFFFFFF). I was unable to set the value any higher than what is in the code above as I was getting bad_alloc exceptions from the first new call, despite the code compiling.
  • I suspect that there is a faster way to manually initialize an array via iteration than how I did it

I italicized one of the bullet points above because I am very curious as to why that is the case.

Does anyone have advice how to improve my test code? Or even better, does anyone have a straightforward answer to the initial question of which is fastest?

Also: I have turned OFF compiler optimization

Edit: I updated my code to use clock(). Results updated as well.

Community
  • 1
  • 1
SyntaxTerror
  • 346
  • 1
  • 10
  • 1
    The tests are not equivalent because using calloc and maybe value initialization, does not actually 0 the memory until it is touched. Whereas your manual setting of the malloc'd memory to 0 causes it to be touched and therefore allocated. Try reading each element of the value and calloc'd memory and (assuming optimizer doesn't eliminate read because value not used) you should get the same results. – Neil Kirk Jul 24 '14 at 14:21
  • Don't use `time()` for this kind of measurement. Use `clock()` or even better the `` facilities. – T.C. Jul 24 '14 at 14:22
  • Does that work on an element basis? Like if I access a single array element is only that single element init'd to 0? Or is the whole array init'd when one elem is accessed? – SyntaxTerror Jul 24 '14 at 14:22
  • It depends on OS. Often memory is divided into pages. Commonly a page is not actually allocated by the OS until it is touched by the program. It is only "reserved". This is to speed up programs which don't end up using all the memory they allocate. If you remove the code which modifies the malloc'd memory, maybe it will speed up. – Neil Kirk Jul 24 '14 at 14:23
  • @Insertusernamehere The memory page the element is in will be allocated and zeroed out completely. If your whole array fits into that page, your whole array is zeroed out as a result. – JustSid Jul 24 '14 at 14:24
  • To clarify - all this happens behind the scenes by the OS. Your program is totally ok to assume the values are ready at 0 at any time. Also, a simpler OS may not do it this way. – Neil Kirk Jul 24 '14 at 14:24
  • So is there a mem alloc method that will actually 0 the memory when you call it? – SyntaxTerror Jul 24 '14 at 14:26
  • I don't think you understand. Why does it matter, so long as the memory is 0 by the time you read it? – Neil Kirk Jul 24 '14 at 14:27
  • I understand that it doesn't matter, practically speaking, but more of a what-method-should-I-avoid deal (other than manual init, clearly). – SyntaxTerror Jul 24 '14 at 14:28
  • 1
    If you have optimization on, they should be equivalent. GCC with full optimizations emit a `memset` call for both the value-init case and the manual initialization case. (It also optimizes away the `calloc` call entirely unless you add something beyond `free` that uses its result.) – T.C. Jul 24 '14 at 14:30
  • Personally I would use vector for all dynamic arrays unless a special case. It will set values to 0 by default. – Neil Kirk Jul 24 '14 at 14:30
  • I wish I could mark a comment as the answer to the question... Thanks for indulging my curiosity guys! – SyntaxTerror Jul 24 '14 at 14:33
  • OK I made an answer xD – Neil Kirk Jul 24 '14 at 14:35
  • Related: http://stackoverflow.com/questions/2688466/why-mallocmemset-is-slower-than-calloc – Mysticial Jul 24 '14 at 18:33

1 Answers1

2

The tests are not equivalent because using calloc and maybe value initialization, does not actually 0 the memory until it is touched. Whereas your manual setting of the malloc'd memory to 0 causes it to be touched and therefore allocated. Try reading each element of the value and calloc'd memory and (assuming optimizer doesn't eliminate read because value not used) you should get the same results.

It does depends on OS. A simpler OS may not do it this way. Often memory is divided into pages. Commonly a page is not actually allocated by the OS until it is touched by the program. It is only "reserved". This is to speed up programs which don't end up using all the memory they allocate. If you remove the code which modifies the malloc'd memory, maybe it will speed up.

To clarify - all this happens behind the scenes by the OS. Your program is totally ok to assume the values are ready at 0 at any time, from the value-initialization and calloc.

Personally I would use vector for all dynamic arrays unless a special case. It will set values to 0 by default.

Neil Kirk
  • 21,327
  • 9
  • 53
  • 91