Nat! bio photo

Nat!

Senior Mull

Twitter Github Twitch

Measuring context switches :: a small expedition. Part II

Here is the main routine, that is used for testing. Can't really say more than what's in the comments. The program will wait until a number (currently 23) context switches have hit it. It then prints out the number of seconds elapsed and a list with the durations of said context switches.

#include <assert.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <time.h>


extern unsigned long long   _rdtsc();
extern unsigned int         _apicID();


typedef struct
{
   unsigned int   gap;
   unsigned int   apicID;
} context_switch_record;


static int   compare_context_switch_record( context_switch_record *a,
                                            context_switch_record *b)
{
   return( (int) a->gap - (int) b->gap);
}


int   main( int argc, char *argv[])
{
   context_switch_record   infos[ 23];
   unsigned long long  a, b;
   unsigned long long  normal;
   unsigned long long  diff;
   unsigned int        i;
   struct timeval      start;
   struct timeval      stop;
   struct timeval      elapsed;

   gettimeofday( &start, NULL);

   //
   // establish a "gap" between two rdtsc() calls, that
   // should be considered as normal (no interrupt)
   //
   a      = _rdtsc();
   b      = _rdtsc();
   normal = (b - a) * 20;
   printf( "(%qd -> %qd) ", b - a, normal);

   for( i = 0; i < sizeof( infos) / sizeof( context_switch_record); i++)
   {
      b  = _rdtsc();
      for(;;)
      {
         a    = b;
         b    = _rdtsc();
         diff = b - a;

         //
         // if the delay between a and b is to large
         // then record it
         //
         if( diff > normal)
            break;
      }
      assert( diff <= INT_MAX);

      //
      // record cycles spent and current cpuID
      //
      infos[ i].gap    = diff;
      infos[ i].apicID = _apicID();
   }

   gettimeofday( &stop, NULL);

   //
   // compute time spent waiting for n context switches
   //
   elapsed.tv_sec  = stop.tv_sec - start.tv_sec;
   elapsed.tv_usec = stop.tv_usec - start.tv_usec;
   if( stop.tv_usec < start.tv_usec)
   {
      elapsed.tv_sec -= 1;
      elapsed.tv_usec = 1000000L - start.tv_usec + stop.tv_usec;
   }
   printf( "%d.%06lds\n\n", (int) elapsed.tv_sec, (long) elapsed.tv_usec);

   //
   // output data and done
   //
   qsort( &infos, sizeof( infos) / sizeof( context_switch_record),
          sizeof( context_switch_record),
          (void *) compare_context_switch_record);

   for( i = 0; i < sizeof( infos) / sizeof( context_switch_record); i++)
      printf( "%u : %u\n", infos[ i].gap, infos[ i].apicID);

   return( 0);
}

Here is the Xcode Project.