Blame rt/tst-cpuclock2.c

Packit Service 82fcde
/* Test program for process and thread CPU clocks.
Packit Service 82fcde
   Copyright (C) 2005-2018 Free Software Foundation, Inc.
Packit Service 82fcde
   This file is part of the GNU C Library.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is free software; you can redistribute it and/or
Packit Service 82fcde
   modify it under the terms of the GNU Lesser General Public
Packit Service 82fcde
   License as published by the Free Software Foundation; either
Packit Service 82fcde
   version 2.1 of the License, or (at your option) any later version.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is distributed in the hope that it will be useful,
Packit Service 82fcde
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 82fcde
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 82fcde
   Lesser General Public License for more details.
Packit Service 82fcde
Packit Service 82fcde
   You should have received a copy of the GNU Lesser General Public
Packit Service 82fcde
   License along with the GNU C Library; if not, see
Packit Service 82fcde
   <http://www.gnu.org/licenses/>.  */
Packit Service 82fcde
Packit Service 82fcde
#include <unistd.h>
Packit Service 82fcde
#include <stdint.h>
Packit Service 82fcde
Packit Service 82fcde
#if (_POSIX_THREADS - 0) <= 0
Packit Service 82fcde
Packit Service 82fcde
# define TEST_FUNCTION 0
Packit Service 82fcde
Packit Service 82fcde
#else
Packit Service 82fcde
Packit Service 82fcde
#include <stdio.h>
Packit Service 82fcde
#include <stdlib.h>
Packit Service 82fcde
#include <time.h>
Packit Service 82fcde
#include <fcntl.h>
Packit Service 82fcde
#include <string.h>
Packit Service 82fcde
#include <errno.h>
Packit Service 82fcde
#include <pthread.h>
Packit Service 82fcde
Packit Service 82fcde
static pthread_barrier_t barrier;
Packit Service 82fcde
Packit Service 82fcde
/* This function is intended to rack up both user and system time.  */
Packit Service 82fcde
static void *
Packit Service 82fcde
chew_cpu (void *arg)
Packit Service 82fcde
{
Packit Service 82fcde
  pthread_barrier_wait (&barrier);
Packit Service 82fcde
Packit Service 82fcde
  while (1)
Packit Service 82fcde
    {
Packit Service 82fcde
      static volatile char buf[4096];
Packit Service 82fcde
      for (int i = 0; i < 100; ++i)
Packit Service 82fcde
	for (size_t j = 0; j < sizeof buf; ++j)
Packit Service 82fcde
	  buf[j] = 0xaa;
Packit Service 82fcde
      int nullfd = open ("/dev/null", O_WRONLY);
Packit Service 82fcde
      for (int i = 0; i < 100; ++i)
Packit Service 82fcde
	for (size_t j = 0; j < sizeof buf; ++j)
Packit Service 82fcde
	  buf[j] = 0xbb;
Packit Service 82fcde
      write (nullfd, (char *) buf, sizeof buf);
Packit Service 82fcde
      close (nullfd);
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  return NULL;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
static unsigned long long int
Packit Service 82fcde
tsdiff (const struct timespec *before, const struct timespec *after)
Packit Service 82fcde
{
Packit Service 82fcde
  struct timespec diff = { .tv_sec = after->tv_sec - before->tv_sec,
Packit Service 82fcde
			   .tv_nsec = after->tv_nsec - before->tv_nsec };
Packit Service 82fcde
  while (diff.tv_nsec < 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      --diff.tv_sec;
Packit Service 82fcde
      diff.tv_nsec += 1000000000;
Packit Service 82fcde
    }
Packit Service 82fcde
  return diff.tv_sec * 1000000000ULL + diff.tv_nsec;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
static unsigned long long int
Packit Service 82fcde
test_nanosleep (clockid_t clock, const char *which,
Packit Service 82fcde
		const struct timespec *before, int *bad)
Packit Service 82fcde
{
Packit Service 82fcde
  const struct timespec sleeptime = { .tv_nsec = 100000000 };
Packit Service 82fcde
  int e = clock_nanosleep (clock, 0, &sleeptime, NULL);
Packit Service 82fcde
  if (e == EINVAL || e == ENOTSUP || e == ENOSYS)
Packit Service 82fcde
    {
Packit Service 82fcde
      printf ("clock_nanosleep not supported for %s CPU clock: %s\n",
Packit Service 82fcde
	      which, strerror (e));
Packit Service 82fcde
      return 0;
Packit Service 82fcde
    }
Packit Service 82fcde
  if (e != 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      printf ("clock_nanosleep on %s CPU clock: %s\n", which, strerror (e));
Packit Service 82fcde
      *bad = 1;
Packit Service 82fcde
      return 0;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  struct timespec after;
Packit Service 82fcde
  if (clock_gettime (clock, &after) < 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      printf ("clock_gettime on %s CPU clock %lx => %s\n",
Packit Service 82fcde
	      which, (unsigned long int) clock, strerror (errno));
Packit Service 82fcde
      *bad = 1;
Packit Service 82fcde
      return 0;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  unsigned long long int diff = tsdiff (before, &after);
Packit Service 82fcde
  if (diff < sleeptime.tv_nsec || diff > sleeptime.tv_nsec * 2)
Packit Service 82fcde
    {
Packit Service 82fcde
      printf ("clock_nanosleep on %s slept %llu (outside reasonable range)\n",
Packit Service 82fcde
	      which, diff);
Packit Service 82fcde
      *bad = 1;
Packit Service 82fcde
      return diff;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  struct timespec sleeptimeabs = sleeptime;
Packit Service 82fcde
  sleeptimeabs.tv_sec += after.tv_sec;
Packit Service 82fcde
  sleeptimeabs.tv_nsec += after.tv_nsec;
Packit Service 82fcde
  while (sleeptimeabs.tv_nsec >= 1000000000)
Packit Service 82fcde
    {
Packit Service 82fcde
      ++sleeptimeabs.tv_sec;
Packit Service 82fcde
      sleeptimeabs.tv_nsec -= 1000000000;
Packit Service 82fcde
    }
Packit Service 82fcde
  e = clock_nanosleep (clock, TIMER_ABSTIME, &sleeptimeabs, NULL);
Packit Service 82fcde
  if (e != 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      printf ("absolute clock_nanosleep on %s CPU clock: %s\n",
Packit Service 82fcde
	      which, strerror (e));
Packit Service 82fcde
      *bad = 1;
Packit Service 82fcde
      return diff;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  struct timespec afterabs;
Packit Service 82fcde
  if (clock_gettime (clock, &afterabs) < 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      printf ("clock_gettime on %s CPU clock %lx => %s\n",
Packit Service 82fcde
	      which, (unsigned long int) clock, strerror (errno));
Packit Service 82fcde
      *bad = 1;
Packit Service 82fcde
      return diff;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  unsigned long long int sleepdiff = tsdiff (&sleeptimeabs, &afterabs);
Packit Service 82fcde
  if (sleepdiff > sleeptime.tv_nsec)
Packit Service 82fcde
    {
Packit Service 82fcde
      printf ("\
Packit Service 82fcde
absolute clock_nanosleep on %s %llu past target (outside reasonable range)\n",
Packit Service 82fcde
	      which, sleepdiff);
Packit Service 82fcde
      *bad = 1;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  unsigned long long int diffabs = tsdiff (&after, &afterabs);
Packit Service 82fcde
  if (diffabs < sleeptime.tv_nsec || diffabs > sleeptime.tv_nsec * 2)
Packit Service 82fcde
    {
Packit Service 82fcde
      printf ("\
Packit Service 82fcde
absolute clock_nanosleep on %s slept %llu (outside reasonable range)\n",
Packit Service 82fcde
	      which, diffabs);
Packit Service 82fcde
      *bad = 1;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  return diff + diffabs;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
static int
Packit Service 82fcde
do_test (void)
Packit Service 82fcde
{
Packit Service 82fcde
  int result = 0;
Packit Service 82fcde
  clockid_t process_clock, th_clock, my_thread_clock;
Packit Service 82fcde
  int e;
Packit Service 82fcde
  pthread_t th;
Packit Service 82fcde
Packit Service 82fcde
  e = clock_getcpuclockid (0, &process_clock);
Packit Service 82fcde
  if (e != 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      printf ("clock_getcpuclockid on self => %s\n", strerror (e));
Packit Service 82fcde
      return 1;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  e = pthread_getcpuclockid (pthread_self (), &my_thread_clock);
Packit Service 82fcde
  if (e != 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      printf ("pthread_getcpuclockid on self => %s\n", strerror (e));
Packit Service 82fcde
      return 1;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  /* This is a kludge.  This test fails if the semantics of thread and
Packit Service 82fcde
     process clocks are wrong.  The old code using hp-timing without kernel
Packit Service 82fcde
     support has bogus semantics if there are context switches.  We don't
Packit Service 82fcde
     fail to report failure when the proper functionality is not available
Packit Service 82fcde
     in the kernel.  It so happens that Linux kernels without correct CPU
Packit Service 82fcde
     clock support also lack CPU timer support, so we use use that to guess
Packit Service 82fcde
     that we are using the bogus code and not test it.  */
Packit Service 82fcde
  timer_t t;
Packit Service 82fcde
  if (timer_create (my_thread_clock, NULL, &t) != 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      printf ("timer_create: %m\n");
Packit Service 82fcde
      puts ("No support for CPU clocks with good semantics, skipping test");
Packit Service 82fcde
      return 0;
Packit Service 82fcde
    }
Packit Service 82fcde
  timer_delete (t);
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
  pthread_barrier_init (&barrier, NULL, 2);
Packit Service 82fcde
Packit Service 82fcde
  e = pthread_create (&th, NULL, chew_cpu, NULL);
Packit Service 82fcde
  if (e != 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      printf ("pthread_create: %s\n", strerror (e));
Packit Service 82fcde
      return 1;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  e = pthread_getcpuclockid (th, &th_clock);
Packit Service 82fcde
  if (e == ENOENT || e == ENOSYS || e == ENOTSUP)
Packit Service 82fcde
    {
Packit Service 82fcde
      puts ("pthread_getcpuclockid does not support other threads");
Packit Service 82fcde
      return 1;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  pthread_barrier_wait (&barrier);
Packit Service 82fcde
Packit Service 82fcde
  struct timespec res;
Packit Service 82fcde
  if (clock_getres (th_clock, &res) < 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      printf ("clock_getres on live thread clock %lx => %s\n",
Packit Service 82fcde
	      (unsigned long int) th_clock, strerror (errno));
Packit Service 82fcde
      result = 1;
Packit Service 82fcde
      return 1;
Packit Service 82fcde
    }
Packit Service 82fcde
  printf ("live thread clock %lx resolution %ju.%.9ju\n",
Packit Service 82fcde
	  (unsigned long int) th_clock,
Packit Service 82fcde
	  (uintmax_t) res.tv_sec, (uintmax_t) res.tv_nsec);
Packit Service 82fcde
Packit Service 82fcde
  struct timespec process_before, process_after;
Packit Service 82fcde
  if (clock_gettime (process_clock, &process_before) < 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      printf ("clock_gettime on process clock %lx => %s\n",
Packit Service 82fcde
	      (unsigned long int) process_clock, strerror (errno));
Packit Service 82fcde
      return 1;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  struct timespec before, after;
Packit Service 82fcde
  if (clock_gettime (th_clock, &before) < 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      printf ("clock_gettime on live thread clock %lx => %s\n",
Packit Service 82fcde
	      (unsigned long int) th_clock, strerror (errno));
Packit Service 82fcde
      return 1;
Packit Service 82fcde
    }
Packit Service 82fcde
  printf ("live thread before sleep => %ju.%.9ju\n",
Packit Service 82fcde
	  (uintmax_t) before.tv_sec, (uintmax_t) before.tv_nsec);
Packit Service 82fcde
Packit Service 82fcde
  struct timespec me_before, me_after;
Packit Service 82fcde
  if (clock_gettime (my_thread_clock, &me_before) < 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      printf ("clock_gettime on self thread clock %lx => %s\n",
Packit Service 82fcde
	      (unsigned long int) my_thread_clock, strerror (errno));
Packit Service 82fcde
      return 1;
Packit Service 82fcde
    }
Packit Service 82fcde
  printf ("self thread before sleep => %ju.%.9ju\n",
Packit Service 82fcde
	  (uintmax_t) me_before.tv_sec, (uintmax_t) me_before.tv_nsec);
Packit Service 82fcde
Packit Service 82fcde
  struct timespec sleeptime = { .tv_nsec = 500000000 };
Packit Service 82fcde
  if (nanosleep (&sleeptime, NULL) != 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      perror ("nanosleep");
Packit Service 82fcde
      return 1;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  if (clock_gettime (th_clock, &after) < 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      printf ("clock_gettime on live thread clock %lx => %s\n",
Packit Service 82fcde
	      (unsigned long int) th_clock, strerror (errno));
Packit Service 82fcde
      return 1;
Packit Service 82fcde
    }
Packit Service 82fcde
  printf ("live thread after sleep => %ju.%.9ju\n",
Packit Service 82fcde
	  (uintmax_t) after.tv_sec, (uintmax_t) after.tv_nsec);
Packit Service 82fcde
Packit Service 82fcde
  if (clock_gettime (process_clock, &process_after) < 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      printf ("clock_gettime on process clock %lx => %s\n",
Packit Service 82fcde
	      (unsigned long int) process_clock, strerror (errno));
Packit Service 82fcde
      return 1;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  if (clock_gettime (my_thread_clock, &me_after) < 0)
Packit Service 82fcde
    {
Packit Service 82fcde
      printf ("clock_gettime on self thread clock %lx => %s\n",
Packit Service 82fcde
	      (unsigned long int) my_thread_clock, strerror (errno));
Packit Service 82fcde
      return 1;
Packit Service 82fcde
    }
Packit Service 82fcde
  printf ("self thread after sleep => %ju.%.9ju\n",
Packit Service 82fcde
	  (uintmax_t) me_after.tv_sec, (uintmax_t) me_after.tv_nsec);
Packit Service 82fcde
Packit Service 82fcde
  unsigned long long int th_diff = tsdiff (&before, &after);
Packit Service 82fcde
  unsigned long long int pdiff = tsdiff (&process_before, &process_after);
Packit Service 82fcde
  unsigned long long int my_diff = tsdiff (&me_before, &me_after);
Packit Service 82fcde
Packit Service 82fcde
  if (th_diff < 100000000 || th_diff > 600000000)
Packit Service 82fcde
    {
Packit Service 82fcde
      printf ("live thread before - after %llu outside reasonable range\n",
Packit Service 82fcde
	      th_diff);
Packit Service 82fcde
      result = 1;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  if (my_diff > 100000000)
Packit Service 82fcde
    {
Packit Service 82fcde
      printf ("self thread before - after %llu outside reasonable range\n",
Packit Service 82fcde
	      my_diff);
Packit Service 82fcde
      result = 1;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  if (pdiff < th_diff)
Packit Service 82fcde
    {
Packit Service 82fcde
      printf ("process before - after %llu outside reasonable range (%llu)\n",
Packit Service 82fcde
	      pdiff, th_diff);
Packit Service 82fcde
      result = 1;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  process_after.tv_nsec += test_nanosleep (th_clock, "live thread",
Packit Service 82fcde
					   &after, &result);
Packit Service 82fcde
  process_after.tv_nsec += test_nanosleep (process_clock, "process",
Packit Service 82fcde
					   &process_after, &result);
Packit Service 82fcde
  test_nanosleep (CLOCK_PROCESS_CPUTIME_ID,
Packit Service 82fcde
		  "PROCESS_CPUTIME_ID", &process_after, &result);
Packit Service 82fcde
Packit Service 82fcde
  pthread_cancel (th);
Packit Service 82fcde
Packit Service 82fcde
  e = clock_nanosleep (CLOCK_THREAD_CPUTIME_ID, 0, &sleeptime, NULL);
Packit Service 82fcde
  if (e != EINVAL)
Packit Service 82fcde
    {
Packit Service 82fcde
      printf ("clock_nanosleep CLOCK_THREAD_CPUTIME_ID: %s\n",
Packit Service 82fcde
	      strerror (e));
Packit Service 82fcde
      result = 1;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  return result;
Packit Service 82fcde
}
Packit Service 82fcde
# define TIMEOUT 8
Packit Service 82fcde
# define TEST_FUNCTION do_test ()
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
#include "../test-skeleton.c"