Monday, 9 March 2015

... and it was such a great idea... :(

tldr: 

Lesson 1: You cannot cheat your way around strlen() by using sizeof(s)/sizeof(s[0]) because you cannot stuff a char *s into a char s[] for free.
Lesson 2: Don't use the clock mechanism in the proggy below, because it's unreliable on hyper-threaded CPUs.
Lesson 3: Don't use floats.

The full story:

I am currently reading the book Modern C.  In it, I came across the advice that you can compute the size of an array by doing  sizeof(s)/sizeof(s[0]).  Hmm, maybe I could use that instead of strlen, because surely this is much quicker!

So... hackety-hack, I made this[1] and got that output:

A: Time spent:           0.045580  count = 35
B: Time spent:           0.180489  count = 34

Then after some fiddling around, I realised that I of course cannot assign a char *s to a char s[] (without paying the full price), despite either form working in strlen().

I mailed my guru about this unsuccess for his entertainment (and that of his colleagues :-) , and the message coming back informed me that clock is considered harmful, and floats are also bad.  Being curious I asked why clock is dodgy (since time.h surely should be sound), and was informed that on a hyper-threaded CPU, it's unreliable, which of course is no good if you're trying to profile anything. Apparently it's better to use this little creation.

So, how to do find out if your cpu is hyper-threaded?  You do cat /proc/cpuinfo and look up the spec. (mine isn't ht but that's no excuse).

[1]
#define _GNU_SOURCE         /* See feature_test_macros(7) */
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <time.h>

int main (int argc, char *argv[])
{
  clock_t begin, end;
  double time_spent;

  // sadly I can't assign ss to s :(
  // char *ss = "supercalifragilisticexpialidocious";                                
  char s[] = "supercalifragilisticexpialidocious";
  size_t max = 10000000;
  int count;

  begin = clock();

  for (size_t i = 0; i < max; i++)
      count = sizeof(s)/sizeof(s[0]);

  end = clock();
  time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
  printf("A: Time spent:  \t %f  count = %d\n",time_spent, count);

  begin = clock();

  for (size_t i = 0; i < max; i++)
      count = strlen(s);

  end = clock();
  time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
  printf("B: Time spent:  \t %f  count = %d\n",time_spent, count);

  exit(EXIT_SUCCESS);
}