pthread timing granularity with compat5x on FreeBSD 6.0

martin0406 at lispworks.com martin0406 at lispworks.com
Tue Apr 11 17:36:32 UTC 2006


Hi there,

Is there some known issue with the granularity of scheduling when running
FreeBSD 5.x executables on FreeBSD 6.0 with compat5x?  The sample code below,
describes the problem.  Any clues could be appreciated.

My config is as follows:
kern.osrelease: 6.0-RELEASE
kern.osrevision: 199506
kern.version: FreeBSD 6.0-RELEASE #0: Thu Nov  3 09:36:13 UTC 2005
    root at x64.samsco.home:/usr/obj/usr/src/sys/GENERIC
hw.model: AMD Athlon(tm) 64 X2 Dual Core Processor 4400+


------------------------------------------------------------------------------
/* This code demonstrate a problem with sleeping
   on FreeBSD 6.0 when running code that was compiled
   on FreeBSD 5.x, when another pthread is busy.

   The function LoopingSignaler tries to sleep for a fixed period of time.
   When this is compiled on FreeBSD 5 and run on FreeBSD 5, it sleeps for
   approximately the right time.  When it is compiled on FreeBSD 5 and
   run on FreeBSD 6 it seems to sleep in "granules" of ~157 ms when competing
   for CPU time with another thread.

   To test:
   compile on FreeBSD 5 by

          gcc -pthread we.c

   run on FreeBSD 6

          a.out [millseconds]

   The test starts a pthread that sleeps in a loop reporting the length of
   time it slept.  The main thread then calls usleep for a while, and finally
   starts to use the cpu heavily (empty while loop).

   As long it is usleeping, the sleep time of the other pthread
   is correct.  Once it starts using cpu, the sleep time increase
   to the granule boundary.

   The sleeping thread prints the time it slept in miliiseconds, first
   in cpu time (by times(2), and then elapsed time by gettimeofday(2)).

   By default it tries to sleep for 50 milliseocnds.

*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <pthread.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/times.h>
#include <unistd.h>
#include <signal.h>

void *LoopingSignaler(void *arg)
{
  long tick_per_second = sysconf(_SC_CLK_TCK);
  clock_t start_sleep;
  struct timeval tm;
  int count = 100;
  int millis = (int) arg;

  while(count--) {
    int use_select = count & 1;
    struct timeval in;
    struct timespec ain, aout;
    struct tms tmbuf;

    in.tv_sec  = 0; in.tv_usec  = millis * 1000;
    ain.tv_sec = 0; ain.tv_nsec = millis * 1000000;

    /* Record the start times */
    times(&tmbuf);
    gettimeofday(&tm, NULL);
    start_sleep = tmbuf.tms_utime;

    /* Sleep in two different ways. */
    if (use_select)
      select(1, NULL , NULL , NULL, &in);
    else
      nanosleep(&ain, &aout);

    /* Display time spent sleeping */
    {
      clock_t diff;
      long millis_sleep, millis_real;
      struct timeval etm;

      times(&tmbuf);
      gettimeofday(&etm, NULL);

      diff  = tmbuf.tms_utime - start_sleep;

      millis_sleep = (diff * 1000) / tick_per_second;

      {
	int secdiff  = etm.tv_sec - tm.tv_sec;
	int micsdiff = etm.tv_usec - tm.tv_usec;
	millis_real  = (micsdiff + secdiff * 1000000) / 1000;
      }

      printf("%s slept for %d / %d\n",
	     use_select ? "   select": "nanosleep",
	     millis_sleep, millis_real);
    }
  }

  exit(0);
}

int main(int argc,  char **argv)
{
  int millis = 50;
  pthread_t pt;
  pthread_attr_t attr;
  int res;

  if (argc > 1)
    millis = atoi(argv[1]);
  pthread_attr_init(&attr);

  res = pthread_create(&pt, &attr, &LoopingSignaler, (void *)millis);

  /* initial test with the main thread idle */
  usleep(millis * 1000 * 20);
  printf("\nfinished usleep\n\n");

  /* second test with the main thread busy */
  while(1) {};

  return 0;
}
------------------------------------------------------------------------------


__Martin


More information about the freebsd-threads mailing list