LCOV - code coverage report
Current view: directory - src/shared/platform - nacl_clock_test.c (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 165 62 37.6 %
Date: 2014-09-25 Functions: 0 0 -

       1                 : /*
       2                 :  * Copyright (c) 2012 The Native Client Authors. All rights reserved.
       3                 :  * Use of this source code is governed by a BSD-style license that can be
       4                 :  * found in the LICENSE file.
       5                 :  */
       6                 : 
       7                 : #include <stdio.h>
       8                 : #include <string.h>
       9                 : 
      10                 : #include "native_client/src/shared/platform/nacl_clock.h"
      11                 : 
      12                 : #include "native_client/src/shared/platform/platform_init.h"
      13                 : 
      14                 : #include "native_client/src/include/nacl_macros.h"
      15                 : #include "native_client/src/include/portability.h"
      16                 : #include "native_client/src/shared/platform/nacl_time.h"
      17                 : #include "native_client/src/shared/platform/nacl_threads.h"
      18                 : #include "native_client/src/trusted/service_runtime/include/sys/errno.h"
      19                 : 
      20                 : /*
      21                 :  * Very basic sanity check.  With clock functionality, tests are a
      22                 :  * pain without a set of globally consistent dependency injection for
      23                 :  * syscalls, since faking out time-related syscalls in the test
      24                 :  * without faking out the same syscalls used by other modules is
      25                 :  * difficult.  Furthermore, this test is trying to verify basic
      26                 :  * functionality -- and testing against a mock interface that works
      27                 :  * according to our expectations of what the syscalls will do isn't
      28                 :  * the same: our assumptions might be wrong, and we ought to have a
      29                 :  * test that verifies end-to-end functionality.  Here, we just compare
      30                 :  * clock_gettime of the realtime clock against gettimeofday, and do
      31                 :  * two monotonic clock samples between a nanosleep to verify that the
      32                 :  * monotonic clock *approximately* measured the sleep duration -- with
      33                 :  * great fuzziness.
      34                 :  *
      35                 :  * On an unloaded i7, 1ms with a 1.25 fuzziness factor and a 100,000
      36                 :  * ns constant syscall overhead works fine.  On bots, we have to be
      37                 :  * much more generous.  (This is especially true for qemu-based
      38                 :  * testing.)
      39                 :  */
      40                 : #define DEFAULT_NANOSLEEP_EXTRA_OVERHEAD  (10 * NACL_NANOS_PER_MILLI)
      41                 : #define DEFAULT_NANOSLEEP_EXTRA_FACTOR    (100.0)
      42                 : #define DEFAULT_NANOSLEEP_TIME            (10 * NACL_NANOS_PER_MILLI)
      43                 : 
      44                 : #define THREAD_CYCLES     100000000
      45                 : 
      46                 : /*
      47                 :  * Global testing parameters -- fuzziness coefficients in determining
      48                 :  * what is considered accurate.
      49                 :  */
      50                 : int      g_cputime = 0;
      51                 : double   g_fuzzy_factor = DEFAULT_NANOSLEEP_EXTRA_FACTOR;
      52                 : uint64_t g_syscall_overhead = DEFAULT_NANOSLEEP_EXTRA_OVERHEAD;
      53                 : uint64_t g_slop_ms = 0;
      54                 : 
      55                 : /*
      56                 :  * ClockMonotonicAccuracyTest samples the NACL_ABI_CLOCK_MONOTONIC
      57                 :  * clock before and after invoking NaClNanosleep and computes the time
      58                 :  * delta.  The test is considered to pass if the time delta is close
      59                 :  * to the requested value.  "Close" is a per-host-OS attribute, thus
      60                 :  * the above testing parameters.
      61                 :  */
      62               1 : static int ClockMonotonicAccuracyTest(uint64_t sleep_nanos) {
      63               1 :   int                       num_failures = 0;
      64                 : 
      65                 :   int                       err;
      66                 :   struct nacl_abi_timespec  t_start;
      67                 :   struct nacl_abi_timespec  t_sleep;
      68                 :   struct nacl_abi_timespec  t_end;
      69                 : 
      70                 :   uint64_t                  elapsed_nanos;
      71                 :   uint64_t                  elapsed_lower_bound;
      72                 :   uint64_t                  elapsed_upper_bound;
      73                 : 
      74               1 :   t_sleep.tv_sec  = sleep_nanos / NACL_NANOS_PER_UNIT;
      75               1 :   t_sleep.tv_nsec = sleep_nanos % NACL_NANOS_PER_UNIT;
      76                 : 
      77               1 :   printf("\nCLOCK_MONOTONIC accuracy test:\n");
      78                 : 
      79               1 :   if (0 != (err = NaClClockGetTime(NACL_ABI_CLOCK_MONOTONIC, &t_start))) {
      80                 :     fprintf(stderr,
      81                 :             "nacl_clock_test: NaClClockGetTime (start) failed, error %d\n",
      82               0 :             err);
      83               0 :     ++num_failures;
      84               0 :     goto done;
      85                 :   }
      86                 :   for (;;) {
      87               1 :     err = NaClNanosleep(&t_sleep, &t_sleep);
      88               1 :     if (0 == err) {
      89               1 :       break;
      90                 :     }
      91               0 :     if (-NACL_ABI_EINTR == err) {
      92                 :       /* interrupted syscall: sleep some more */
      93               0 :       continue;
      94                 :     }
      95                 :     fprintf(stderr,
      96               0 :             "nacl_clock_test: NaClNanoSleep failed, error %d\n", err);
      97               0 :     num_failures++;
      98               0 :     goto done;
      99                 :   }
     100               1 :   if (0 != (err = NaClClockGetTime(NACL_ABI_CLOCK_MONOTONIC, &t_end))) {
     101                 :     fprintf(stderr,
     102                 :             "nacl_clock_test: NaClClockGetTime (end) failed, error %d\n",
     103               0 :             err);
     104               0 :     return 1;
     105                 :   }
     106                 : 
     107                 :   elapsed_nanos = (t_end.tv_sec - t_start.tv_sec) * NACL_NANOS_PER_UNIT +
     108               1 :       (t_end.tv_nsec - t_start.tv_nsec) + g_slop_ms * NACL_NANOS_PER_MILLI;
     109                 : 
     110               1 :   elapsed_lower_bound = sleep_nanos;
     111                 :   elapsed_upper_bound = (uint64_t) (sleep_nanos * g_fuzzy_factor +
     112               1 :                                     g_syscall_overhead);
     113                 : 
     114               1 :   printf("requested sleep:      %20"NACL_PRIu64" nS\n", sleep_nanos);
     115               1 :   printf("actual elapsed sleep: %20"NACL_PRIu64" nS\n", elapsed_nanos);
     116               1 :   printf("sleep lower bound:    %20"NACL_PRIu64" nS\n", elapsed_lower_bound);
     117               1 :   printf("sleep upper bound:    %20"NACL_PRIu64" nS\n", elapsed_upper_bound);
     118                 : 
     119                 :   if (elapsed_nanos < elapsed_lower_bound ||
     120               1 :       elapsed_upper_bound < elapsed_nanos) {
     121               0 :     printf("discrepancy too large\n");
     122               0 :     num_failures++;
     123                 :   }
     124                 :  done:
     125               1 :   printf((0 == num_failures) ? "PASSED\n" : "FAILED\n");
     126               1 :   return num_failures;
     127               1 : }
     128                 : 
     129                 : /*
     130                 :  * ClockRealtimeAccuracyTest compares the time returned by
     131                 :  * NACL_ABI_CLOCK_REALTIME against that returned by NaClGetTimeOfDay.
     132                 :  */
     133               1 : static int ClockRealtimeAccuracyTest(void) {
     134               1 :   int                       num_failures = 0;
     135                 : 
     136                 :   int                       err;
     137                 :   struct nacl_abi_timespec  t_now_ts;
     138                 :   struct nacl_abi_timeval   t_now_tv;
     139                 : 
     140                 :   uint64_t                  t_now_ts_nanos;
     141                 :   uint64_t                  t_now_tv_nanos;
     142                 :   int64_t                   t_now_diff_nanos;
     143                 : 
     144               1 :   printf("\nCLOCK_REALTIME accuracy test:\n");
     145                 : 
     146               1 :   if (0 != (err = NaClClockGetTime(NACL_ABI_CLOCK_REALTIME, &t_now_ts))) {
     147                 :     fprintf(stderr,
     148                 :             "nacl_clock_test: NaClClockGetTime (now) failed, error %d\n",
     149               0 :             err);
     150               0 :     num_failures++;
     151               0 :     goto done;
     152                 :   }
     153               1 :   if (0 != (err = NaClGetTimeOfDay(&t_now_tv))) {
     154                 :     fprintf(stderr,
     155                 :             "nacl_clock_test: NaClGetTimeOfDay (now) failed, error %d\n",
     156               0 :             err);
     157               0 :     num_failures++;
     158               0 :     goto done;
     159                 :   }
     160                 : 
     161               1 :   t_now_ts_nanos = t_now_ts.tv_sec * NACL_NANOS_PER_UNIT + t_now_ts.tv_nsec;
     162                 :   t_now_tv_nanos = t_now_tv.nacl_abi_tv_sec * NACL_NANOS_PER_UNIT +
     163               1 :       t_now_tv.nacl_abi_tv_usec * NACL_NANOS_PER_MICRO;
     164                 : 
     165               1 :   printf("clock_gettime:   %20"NACL_PRIu64" nS\n", t_now_ts_nanos);
     166               1 :   printf("gettimeofday:    %20"NACL_PRIu64" nS\n", t_now_tv_nanos);
     167                 : 
     168               1 :   t_now_diff_nanos = t_now_ts_nanos - t_now_tv_nanos;
     169               1 :   if (t_now_diff_nanos < 0) {
     170               0 :     t_now_diff_nanos = -t_now_diff_nanos;
     171                 :   }
     172               1 :   printf("time difference: %20"NACL_PRId64" nS\n", t_now_diff_nanos);
     173                 : 
     174               1 :   if (t_now_ts_nanos < g_syscall_overhead) {
     175               0 :     printf("discrepancy too large\n");
     176               0 :     num_failures++;
     177                 :   }
     178                 :  done:
     179               1 :   printf((0 == num_failures) ? "PASSED\n" : "FAILED\n");
     180               1 :   return num_failures;
     181               1 : }
     182                 : 
     183                 : #ifndef NACL_NO_CPUTIME_TEST
     184                 : struct ThreadInfo {
     185                 :   size_t                    cycles;
     186                 :   struct nacl_abi_timespec  thread_time;
     187                 :   struct nacl_abi_timespec  process_time;
     188                 :   int                       num_failures;
     189                 : };
     190                 : 
     191               0 : void WINAPI ThreadFunction(void *ptr) {
     192                 :   int                       err;
     193                 : 
     194                 :   size_t                    i;
     195               0 :   struct ThreadInfo         *info = (struct ThreadInfo *) ptr;
     196                 : 
     197               0 :   for (i = 1; i < info->cycles; i++) {
     198                 : #if defined(__GNUC__)
     199                 :     __asm__ volatile("" ::: "memory");
     200                 : #elif NACL_WINDOWS
     201                 :     _ReadWriteBarrier();
     202                 : #else
     203                 : # error Unsupported platform
     204                 : #endif
     205               0 :   }
     206                 : 
     207                 :   if (0 != (err = NaClClockGetTime(NACL_ABI_CLOCK_THREAD_CPUTIME_ID,
     208               0 :                                    &info->thread_time))) {
     209                 :     fprintf(stderr,
     210                 :             "nacl_clock_test: NaClClockGetTime (now) failed, error %d\n",
     211               0 :             err);
     212               0 :     info->num_failures++;
     213               0 :     return;
     214                 :   }
     215                 : 
     216                 :   if (0 != (err = NaClClockGetTime(NACL_ABI_CLOCK_PROCESS_CPUTIME_ID,
     217               0 :                                    &info->process_time))) {
     218                 :     fprintf(stderr,
     219                 :             "nacl_clock_test: NaClClockGetTime (now) failed, error %d\n",
     220               0 :             err);
     221               0 :     info->num_failures++;
     222                 :     return;
     223                 :   }
     224               0 : }
     225                 : 
     226               0 : static int ClockCpuTimeAccuracyTest(void) {
     227               0 :   int                       num_failures = 0;
     228                 : 
     229                 :   int                       err;
     230                 :   struct nacl_abi_timespec  t_process_start;
     231                 :   struct nacl_abi_timespec  t_process_end;
     232                 :   struct nacl_abi_timespec  t_thread_start;
     233                 :   struct nacl_abi_timespec  t_thread_end;
     234                 : 
     235               0 :   uint64_t                  thread_elapsed = 0;
     236               0 :   uint64_t                  process_elapsed = 0;
     237               0 :   uint64_t                  child_thread_elapsed = 0;
     238                 :   uint64_t                  elapsed_lower_bound;
     239                 :   uint64_t                  elapsed_upper_bound;
     240                 : 
     241                 :   size_t                    i;
     242                 :   struct ThreadInfo         info[10];
     243                 :   struct NaClThread         thread[10];
     244                 : 
     245               0 :   printf("\nCLOCK_PROCESS/THREAD_CPUTIME_ID accuracy test:\n");
     246                 : 
     247                 :   if (0 != (err = NaClClockGetTime(NACL_ABI_CLOCK_THREAD_CPUTIME_ID,
     248               0 :                                    &t_thread_start))) {
     249                 :     fprintf(stderr,
     250                 :             "nacl_clock_test: NaClClockGetTime (now) failed, error %d\n",
     251               0 :             err);
     252               0 :     num_failures++;
     253               0 :     goto done;
     254                 :   }
     255                 : 
     256                 :   if (0 != (err = NaClClockGetTime(NACL_ABI_CLOCK_PROCESS_CPUTIME_ID,
     257               0 :                                    &t_process_start))) {
     258                 :     fprintf(stderr,
     259                 :             "nacl_clock_test: NaClClockGetTime (now) failed, error %d\n",
     260               0 :             err);
     261               0 :     num_failures++;
     262               0 :     goto done;
     263                 :   }
     264                 : 
     265               0 :   for (i = 0; i < NACL_ARRAY_SIZE(thread); i++) {
     266               0 :     memset(&info[i], 0, sizeof info[i]);
     267               0 :     info[i].cycles = i * THREAD_CYCLES;
     268                 :     if (!NaClThreadCreateJoinable(&thread[i], ThreadFunction, &info[i],
     269               0 :                                   65536)) {
     270                 :       fprintf(stderr,
     271               0 :               "nacl_clock_test: NaClThreadCreateJoinable failed\n");
     272               0 :       num_failures++;
     273               0 :       goto done;
     274                 :     }
     275               0 :   }
     276                 : 
     277               0 :   for (i = 0; i < NACL_ARRAY_SIZE(thread); i++) {
     278               0 :     NaClThreadJoin(&thread[i]);
     279               0 :   }
     280                 : 
     281                 :   if (0 != (err = NaClClockGetTime(NACL_ABI_CLOCK_PROCESS_CPUTIME_ID,
     282               0 :                                    &t_process_end))) {
     283                 :     fprintf(stderr,
     284                 :             "nacl_clock_test: NaClClockGetTime (now) failed, error %d\n",
     285               0 :             err);
     286               0 :     num_failures++;
     287               0 :     goto done;
     288                 :   }
     289                 : 
     290                 :   if (0 != (err = NaClClockGetTime(NACL_ABI_CLOCK_THREAD_CPUTIME_ID,
     291               0 :                                    &t_thread_end))) {
     292                 :     fprintf(stderr,
     293                 :             "nacl_clock_test: NaClClockGetTime (now) failed, error %d\n",
     294               0 :             err);
     295               0 :     num_failures++;
     296               0 :     goto done;
     297                 :   }
     298                 : 
     299                 :   thread_elapsed =
     300                 :       (t_thread_end.tv_sec - t_thread_start.tv_sec) * NACL_NANOS_PER_UNIT +
     301               0 :       (t_thread_end.tv_nsec - t_thread_start.tv_nsec);
     302                 : 
     303                 :   process_elapsed =
     304                 :       (t_process_end.tv_sec - t_process_start.tv_sec) * NACL_NANOS_PER_UNIT +
     305               0 :       (t_process_end.tv_nsec - t_process_start.tv_nsec);
     306                 : 
     307               0 :   for (i = 0; i < NACL_ARRAY_SIZE(thread); i++) {
     308                 :     uint64_t thread_elapsed_nanos;
     309                 :     uint64_t process_elapsed_nanos;
     310               0 :     if (info[i].num_failures > 0) {
     311               0 :       num_failures += info[i].num_failures;
     312               0 :       goto done;
     313                 :     }
     314                 :     thread_elapsed_nanos = info[i].thread_time.tv_sec * NACL_NANOS_PER_UNIT +
     315               0 :         info[i].thread_time.tv_nsec;
     316                 :     process_elapsed_nanos = info[i].process_time.tv_sec * NACL_NANOS_PER_UNIT +
     317               0 :         info[i].process_time.tv_nsec;
     318                 :     printf("%"NACL_PRIdS": thread=%20"NACL_PRIu64" nS, process=%20"
     319                 :            NACL_PRIu64" nS\n",
     320               0 :            i, thread_elapsed_nanos, process_elapsed_nanos);
     321               0 :     child_thread_elapsed += thread_elapsed_nanos;
     322               0 :   }
     323                 : 
     324               0 :   elapsed_lower_bound = thread_elapsed + child_thread_elapsed;
     325                 :   elapsed_upper_bound = (uint64_t) (thread_elapsed +
     326               0 :       child_thread_elapsed * g_fuzzy_factor + g_syscall_overhead);
     327                 : 
     328               0 :   printf("thread time:         %20"NACL_PRIu64" nS\n", thread_elapsed);
     329               0 :   printf("process time:        %20"NACL_PRIu64" nS\n", process_elapsed);
     330               0 :   printf("child thread time:   %20"NACL_PRIu64" nS\n", child_thread_elapsed);
     331               0 :   printf("elapsed lower bound: %20"NACL_PRIu64" nS\n", elapsed_lower_bound);
     332               0 :   printf("elapsed upper bound: %20"NACL_PRIu64" nS\n", elapsed_upper_bound);
     333                 : 
     334                 :   if (process_elapsed < elapsed_lower_bound ||
     335               0 :       elapsed_upper_bound < process_elapsed) {
     336               0 :     printf("discrepancy too large\n");
     337               0 :     num_failures++;
     338                 :   }
     339                 :  done:
     340               0 :   printf((0 == num_failures) ? "PASSED\n" : "FAILED\n");
     341               0 :   return num_failures;
     342               0 : }
     343                 : #endif
     344                 : 
     345               1 : int main(int ac, char **av) {
     346               1 :   uint64_t                  sleep_nanos = DEFAULT_NANOSLEEP_TIME;
     347                 : 
     348                 :   int                       opt;
     349               1 :   uint32_t                  num_failures = 0;
     350                 : 
     351               1 :   puts("This is a basic functionality test being repurposed as an");
     352               1 :   puts(" unit/regression test.  The test parameters default to values that");
     353               1 :   puts("are more appropriate for heavily loaded continuous-testing robots.");
     354                 :   printf("\nThe default values are:\n -S %"NACL_PRIu64
     355                 :          " -f %f -o %"NACL_PRIu64" -s %"NACL_PRIu64"\n\n",
     356               1 :          sleep_nanos, g_fuzzy_factor, g_syscall_overhead, g_slop_ms);
     357               1 :   puts("For testing functionality, this test should be run with a different");
     358               1 :   puts("set of parameters.  On an unloaded i7, a sleep duration (-S) of");
     359               1 :   puts("1000000 ns (one millisecond), with a fuzziness factor (-f) of 1.25,");
     360               1 :   puts("a constant test overhead of 100000 ns (100 us), and a");
     361               1 :   puts("sleep duration \"slop\" (-s) of 0 is fine. The CPU time tests has to");
     362               1 :   puts("be explicitly enabled (-c) its run time is significant.");
     363                 : 
     364               1 :   while (-1 != (opt = getopt(ac, av, "cf:o:s:S:"))) {
     365               1 :     switch (opt) {
     366                 :       case 'c':
     367               0 :         g_cputime = 1;
     368               0 :         break;
     369                 :       case 'f':
     370               0 :         g_fuzzy_factor = strtod(optarg, (char **) NULL);
     371               0 :         break;
     372                 :       case 'o':
     373               0 :         g_syscall_overhead = strtoul(optarg, (char **) NULL, 0);
     374               0 :         break;
     375                 :       case 's':
     376               1 :         g_slop_ms = strtoul(optarg, (char **) NULL, 0);
     377               1 :         break;
     378                 :       case 'S':
     379               0 :         sleep_nanos = strtoul(optarg, (char **) NULL, 0);
     380               0 :         break;
     381                 :       default:
     382                 :         fprintf(stderr, "nacl_clock_test: unrecognized option `%c'.\n",
     383               0 :                 opt);
     384                 :         fprintf(stderr,
     385                 :                 "Usage: nacl_clock_test [-c] [-f fuzz_factor]\n"
     386               0 :                 "       [-s sleep_nanos] [-o syscall_overhead_nanos]\n");
     387               0 :         return -1;
     388                 :     }
     389               1 :   }
     390                 : 
     391               1 :   NaClPlatformInit();
     392                 : 
     393               1 :   if (g_cputime) {
     394               0 :     num_failures += ClockCpuTimeAccuracyTest();
     395               0 :   } else {
     396               1 :     num_failures += ClockMonotonicAccuracyTest(sleep_nanos);
     397               1 :     num_failures += ClockRealtimeAccuracyTest();
     398                 :   }
     399                 : 
     400               1 :   NaClPlatformFini();
     401                 : 
     402               1 :   return num_failures;
     403               1 : }

Generated by: LCOV version 1.7