<pre style='margin:0'>
Christopher Nielsen (mascguy) pushed a commit to branch master
in repository macports-legacy-support.
</pre>
<p><a href="https://github.com/macports/macports-legacy-support/commit/4b5ec68632bd20ef7e1ac3c7b6442e52f179d50b">https://github.com/macports/macports-legacy-support/commit/4b5ec68632bd20ef7e1ac3c7b6442e52f179d50b</a></p>
<pre style="white-space: pre; background: #F8F8F8"><span style='display:block; white-space:pre;color:#808000;'>commit 4b5ec68632bd20ef7e1ac3c7b6442e52f179d50b
</span>Author: Fred Wright <fw@fwright.net>
AuthorDate: Mon Mar 10 13:27:36 2025 -0700
<span style='display:block; white-space:pre;color:#404040;'> test_clocks: Initial new clock test.
</span><span style='display:block; white-space:pre;color:#404040;'>
</span><span style='display:block; white-space:pre;color:#404040;'> This test provides consistency checks and optional information reports
</span><span style='display:block; white-space:pre;color:#404040;'> on all clocks.
</span><span style='display:block; white-space:pre;color:#404040;'>
</span><span style='display:block; white-space:pre;color:#404040;'> TESTED:
</span><span style='display:block; white-space:pre;color:#404040;'> Passes and provides plausible info on all platforms, with both old and
</span><span style='display:block; white-space:pre;color:#404040;'> new clock implementations.
</span>---
test/test_clocks.c | 864 +++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 864 insertions(+)
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/test/test_clocks.c b/test/test_clocks.c
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 0000000..f95468a
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/test/test_clocks.c
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,864 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Copyright (c) 2025 Frederick H. G. Wright II <fw@fwright.net>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Permission to use, copy, modify, and distribute this software for any
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * purpose with or without fee is hereby granted, provided that the above
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * copyright notice and this permission notice appear in all copies.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * This provides tests of the various clock functions.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * In general, we represent most time values in 64-bit nanoseconds, which,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * even as a signed quantity, has a range of about 292 years. Intermediate
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * calculations may be done in floating-point, but its range may not be
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * sufficient for absolute (1970-relative) values in nanoseconds. We sometimes
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * use long doubles, but they're not always better than doubles.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <errno.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <libgen.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <math.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdint.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdio.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <stdlib.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <string.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <time.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <unistd.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <mach/mach_time.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/param.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <sys/time.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * To determine the number of samples we collect, we *very* generously
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * assume that we could collect one sample per CPU clock, and that the
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * clock rate is no more than 4GHz. With 10000 samples, that means
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * we get more than two microseconds of data as a minimum, which is
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * enough to see at least two transitions of a microsecond-resolution
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * clock. At the other extreme, if we assume that the lowest conceivable
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * collection rate is 5MHz, then the collection should take no more than
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * two milliseconds, which means we can do all our tests in well under a
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * second.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define MIN_READ_TIME_PS 250
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define MIN_CLOCK_RES_NS 10
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define NUM_DIFFS 10000
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define NUM_SAMPLES (NUM_DIFFS+1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+typedef uint64_t mach_time_t;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+typedef struct timeval timeval_t;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+typedef struct timespec timespec_t;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+typedef uint64_t ns_time_t;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+typedef int64_t sns_time_t;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define MILLION 1000000U
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define BILLION 1000000000U
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define BILLION64 1000000000ULL
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define BILLIONDBL 1000000000.0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Parameters for collection sequence */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define MAX_STEP_NS 700000 /* Maximum delta not considered a step */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define MAX_STEP_TRIES 50 /* Maximum tries to avoid a step */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define STD_SLEEP_US 1000 /* Standard sleep before collecting */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define MAX_SLEEP_US 100000 /* Maximum sleep when retrying */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define LL (long long)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define ULL (unsigned long long)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+typedef unsigned long pointer_int_t;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static mach_timebase_info_data_t tbinfo;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static long double mach2nanos, mach2usecs, mach2secs;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static ns_time_t mach_res;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Bit bucket for cache warmup calls */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static volatile union scratch_u {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ mach_time_t mach;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ timeval_t timeval;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ timespec_t timespec;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ns_time_t ns_time;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+} time_scratch;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Local errors */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* #define ONE_ERROR(name,text) */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define OUR_ERRORS \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ONE_ERROR(badmicros,"Bad tv_usec value") \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ONE_ERROR(badnanos,"Bad tv_nsec value") \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ONE_ERROR(resolution,"Bad clock resolution") \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ONE_ERROR(backstep,"Too many retries to avoid backstep") \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ONE_ERROR(illbackstep,"Clock illegally stepped backward") \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ONE_ERROR(zerostep,"Too many consecutive unchanged samples") \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ONE_ERROR(step,"Too many retries to avoid step") \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ONE_ERROR(noerrno,"Error with errno not set") \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define ONE_ERROR(name,text) err_##name,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+typedef enum errs { err_dummy, /* Avoid zero */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ OUR_ERRORS
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+} errs_t;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#undef ONE_ERROR
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define ONE_ERROR(name,text) text,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static const char * const errnames[] = { NULL,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ OUR_ERRORS
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#undef ONE_ERROR
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static const char *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+get_errstr(int err)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (err < 0) return errnames[-err];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return strerror(err);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Properties of various clocks
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Type of clock (mach, time-of-day, gettime, gettime_ns)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Maximum zero deltas allowed
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Step adjustments allowed
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Slewing from adjtime() allowed
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Approximate
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* List of clock types */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* #define CLOCK_TYPE(name,buf) */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define CLOCK_TYPES \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ CLOCK_TYPE(mach,mtnsbuf) \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ CLOCK_TYPE(timeofday,tvnsbuf) \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ CLOCK_TYPE(gettime,tsnsbuf) \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ CLOCK_TYPE(gettime_ns,tsnsbuf) \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define CLOCK_TYPE(name,buf) clock_type_##name,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+typedef enum clock_type {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ CLOCK_TYPES
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+} clock_type_t;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#undef CLOCK_TYPE
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* List of non-process-specific clocks */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* #define NP_CLOCK(name,type,okstep,okadj,approx) */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define NP_CLOCKS \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ NP_TOD_CLOCKS \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ NP_MACH_CLOCKS \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ NP_GETTIME_CLOCKS(gettime) \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ NP_GETTIME_CLOCKS(gettime_ns) \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Time of day clock */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define NP_TOD_CLOCKS \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ NP_CLOCK(timeofday,timeofday,1,1,0) \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Mach clocks */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define NP_MACH_CLOCKS \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ NP_CLOCK(absolute,mach,0,0,0) \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ NP_CLOCK(approximate,mach,0,0,1) \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ NP_CLOCK(continuous,mach,0,0,0) \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ NP_CLOCK(continuous_approximate,mach,0,0,1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Gettime clocks (for both flavors) */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define NP_GETTIME_CLOCKS(type) \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ NP_CLOCK(REALTIME,type,1,1,0) \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ NP_CLOCK(MONOTONIC,type,0,1,0) \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ NP_CLOCK(MONOTONIC_RAW,type,0,0,0) \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ NP_CLOCK(MONOTONIC_RAW_APPROX,type,0,0,1) \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ NP_CLOCK(UPTIME_RAW,type,0,0,0) \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ NP_CLOCK(UPTIME_RAW_APPROX,type,0,0,1) \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define CALLMAC(a,b,c) a##b(c)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define CONC(a,b) a##b
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Clock type codes */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define CLOCK_IDX_timeofday(name) clock_idx_##name
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define CLOCK_IDX_mach(name) clock_idx_mach_##name
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define CLOCK_IDX_gettime(name) clock_idx_gettime_##name
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define CLOCK_IDX_gettime_ns(name) clock_idx_gettime_ns_##name
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define NP_CLOCK(name,type,okstep,okadj,approx) \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ CALLMAC(CLOCK_IDX_,type,name),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+typedef enum clock_idx {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ NP_CLOCKS
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+} clock_idx_t;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#undef NP_CLOCK
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#undef CLOCK_IDX_timeofday
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#undef CLOCK_IDX_mach
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#undef CLOCK_IDX_gettime
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#undef CLOCK_IDX_gettime_ns
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Duplicate enum to get max value without "no default" switch() warnings.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Some compilers need this to be cast to clock_idx_t to avoid warnings
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * on comparisons.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define CLOCK_IDX_timeofday(name) clock_xidx_##name
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define CLOCK_IDX_mach(name) clock_xidx_mach_##name
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define CLOCK_IDX_gettime(name) clock_xidx_gettime_##name
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define CLOCK_IDX_gettime_ns(name) clock_xidx_gettime_ns_##name
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define NP_CLOCK(name,type,okstep,okadj,approx) \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ CALLMAC(CLOCK_IDX_,type,name),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+typedef enum clock_xidx {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ NP_CLOCKS
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ clock_idx_max,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+} clock_xidx_t;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#undef NP_CLOCK
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#undef CLOCK_IDX_timeofday
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#undef CLOCK_IDX_mach
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#undef CLOCK_IDX_gettime
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#undef CLOCK_IDX_gettime_ns
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define NP_CLOCK(name,type,okstep,okadj,approx) clock_type_##type,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static const clock_type_t clock_types[] = {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ NP_CLOCKS
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#undef NP_CLOCK
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define NP_CLOCK(name,type,okstep,okadj,approx) okstep,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static const int clock_okstep[] = {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ NP_CLOCKS
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#undef NP_CLOCK
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define NP_CLOCK(name,type,okstep,okadj,approx) approx,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static const int clock_approx[] = {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ NP_CLOCKS
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#undef NP_CLOCK
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Arguments for collector functions */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define CLOCK_ARG_timeofday(name) NULL
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define CLOCK_ARG_mach(name) mach_##name##_time
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define CLOCK_ARG_gettime(name) ((void *) CLOCK_##name)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define CLOCK_ARG_gettime_ns(name) ((void *) CLOCK_##name)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define NP_CLOCK(name,type,okstep,okadj,approx) \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ CALLMAC(CLOCK_ARG_,type,name),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static void * const clock_args[] = {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ NP_CLOCKS
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#undef NP_CLOCK
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#undef CLOCK_ARG_timeofday
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#undef CLOCK_ARG_mach
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#undef CLOCK_ARG_gettime
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#undef CLOCK_ARG_gettime_ns
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Names for messages */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define CLOCK_NAME_timeofday(name) "gettimeofday"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define CLOCK_NAME_mach(name) "mach_" #name "_time"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define CLOCK_NAME_gettime(name) "CLOCK_" #name
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define CLOCK_NAME_gettime_ns(name) "CLOCK_" #name "_ns"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define NP_CLOCK(name,type,okstep,okadj,approx) \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ CALLMAC(CLOCK_NAME_,type,name),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static const char * const clock_names[] = {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ NP_CLOCKS
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#undef NP_CLOCK
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#undef CLOCK_NAME_timeofday
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#undef CLOCK_NAME_mach
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#undef CLOCK_NAME_gettime
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#undef CLOCK_NAME_gettime_ns
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Struct for clock stats */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+typedef struct cstats_s {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ns_time_t min;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ns_time_t max;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ double mean;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ double stddev;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int maxsame;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+} cstats_t;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Struct for info on clock errors */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+typedef struct errinfo_s {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ns_time_t first;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ns_time_t last;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int index;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ns_time_t prev;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ns_time_t cur;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ns_time_t nzmin;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int badsame;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int maxsame;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int retries;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int errnum;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ timeval_t badtv;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ timespec_t badts;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+} errinfo_t;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Buffers for clock values */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static timeval_t tvbuf[NUM_SAMPLES];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static mach_time_t mtbuf[NUM_SAMPLES];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static timespec_t tsbuf[NUM_SAMPLES];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Buffers for nanosecondized versions */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static ns_time_t tvnsbuf[NUM_SAMPLES];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static ns_time_t mtnsbuf[NUM_SAMPLES];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static ns_time_t tsnsbuf[NUM_SAMPLES];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Pointers to buffers, by clock type */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define CLOCK_TYPE(name,buf) &buf[0],
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static ns_time_t * const nsbufp[] = {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ CLOCK_TYPES
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#undef CLOCK_TYPE
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static ns_time_t clock_res[clock_idx_max];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static char progname[PATH_MAX];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+setup(int verbose)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (mach_timebase_info(&tbinfo)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf("Can't get mach_time scale\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ mach2nanos = (long double) tbinfo.numer / tbinfo.denom;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ mach2usecs = mach2nanos / 1000.0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ mach2secs = mach2nanos / BILLIONDBL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ mach_res = (tbinfo.numer + tbinfo.denom - 1) / tbinfo.denom;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (verbose) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf(" Scale for mach_time (nanoseconds per unit) is %u/%u = %.3f\n",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ tbinfo.numer, tbinfo.denom, (double) mach2nanos);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Verify errors with bad clockid */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+check_invalid(void)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int ret = 0, err;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ timespec_t ts;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ns_time_t ns;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ errno = -err_noerrno;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if ((err = clock_getres(-1, &ts)) != -1 || errno != EINVAL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf(" *** clock_getres(-1, ...) = %d, errno = %d (%s)\n",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ err, errno, get_errstr(errno));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ret = 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ errno = -err_noerrno;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if ((err = clock_gettime(-1, &ts)) != -1 || errno != EINVAL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf(" *** clock_gettime(-1, ...) = %d, errno = %d (%s)\n",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ err, errno, get_errstr(errno));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ret = 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ errno = -err_noerrno;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if ((ns = clock_gettime_nsec_np(-1)) || errno != EINVAL) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf(" *** clock_gettime_nsec_np(-1) = %lld, errno = %d (%s)\n",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ (long long) ns, errno, get_errstr(errno));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ret = 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Conversions from different time formats to nanoseconds */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static ns_time_t
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+tv2nsec(timeval_t *tv)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return tv->tv_sec * BILLION64 + tv->tv_usec * 1000;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static ns_time_t
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+mt2nsec(mach_time_t mach_time)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return mach_time * mach2nanos;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static ns_time_t
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ts2nsec(timespec_t *ts)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return ts->tv_sec * BILLION64 + ts->tv_nsec;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Plus a microsecond conversion */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static useconds_t
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+mt2usec(mach_time_t mach_time)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return mach_time * mach2usecs;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Mach time in microseconds */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static useconds_t
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+mach_usec(void)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return mt2usec(mach_absolute_time());
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Version of usleep() that defends against signals */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static void
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+usleepx(useconds_t usecs)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ useconds_t now = mach_usec();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ useconds_t target = now + usecs;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ do {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ (void) usleep(target - now);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } while ((now = mach_usec()) < target);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Functions to collect samples of one clock
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * For best measurement accuracy, these first collect samples in their native
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * format, then convert to nanoseconds separately.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+typedef mach_time_t (mach_time_fn_t)(void);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+collect_mach(void *arg, errinfo_t *ei)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ mach_time_fn_t *func = (mach_time_fn_t *) arg;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ mach_time_t *mtp = &mtbuf[0];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ns_time_t *nsp = &mtnsbuf[0];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ (void) ei;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ time_scratch.mach = (*func)(); /* Warm up cache */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ while (mtp < &mtbuf[NUM_SAMPLES]) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *mtp++ = (*func)();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ mtp = &mtbuf[0];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ while (nsp < &mtnsbuf[NUM_SAMPLES]) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *nsp++ = mt2nsec(*mtp++);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+collect_timeofday(void *arg, errinfo_t *ei)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ (void) arg;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int ret = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ timeval_t *tvp = &tvbuf[0];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ns_time_t *nsp = &tvnsbuf[0];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ (void) gettimeofday(tvp, NULL); /* Warm up cache */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ while (tvp < &tvbuf[NUM_SAMPLES]) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if ((ret = gettimeofday(tvp++, NULL))) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ei->errnum = errno;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ tvp = &tvbuf[0];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ while (nsp < &tvnsbuf[NUM_SAMPLES]) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if ((unsigned int) tvp->tv_usec >= MILLION) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ei->errnum = -err_badmicros;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ei->badtv = *tvp;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ret = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *nsp++ = tv2nsec(tvp++);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+collect_gettime(void *arg, errinfo_t *ei)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ clockid_t clkid = (clockid_t) (pointer_int_t) arg;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int ret = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ timespec_t *tsp = &tsbuf[0];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ns_time_t *nsp = &tsnsbuf[0];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ (void) clock_gettime(clkid, tsp); /* Warm up cache */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ while (tsp < &tsbuf[NUM_SAMPLES]) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if ((ret = clock_gettime(clkid, tsp++))) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ei->errnum = errno;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ tsp = &tsbuf[0];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ while (nsp < &tsnsbuf[NUM_SAMPLES]) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if ((unsigned int) tsp->tv_nsec >= BILLION) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ei->errnum = -err_badnanos;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ei->badts = *tsp;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ret = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *nsp++ = ts2nsec(tsp++);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+collect_gettime_ns(void *arg, errinfo_t *ei)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ clockid_t clkid = (clockid_t) (pointer_int_t) arg;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ns_time_t *nsp = &tsnsbuf[0];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ time_scratch.ns_time = clock_gettime_nsec_np(clkid); /* Warm up cache */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ while (nsp < &tsnsbuf[NUM_SAMPLES]) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!(*nsp++ = clock_gettime_nsec_np(clkid))) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ei->errnum = errno;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+collect_samples(clock_idx_t clkidx, errinfo_t *ei)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int ret = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ei->errnum = errno = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define CLOCK_TYPE(name,buf) \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ case clock_type_##name: \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ret = collect_##name(clock_args[clkidx], ei); break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ switch (clock_types[clkidx]) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ CLOCK_TYPES
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#undef CLOCK_TYPE
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Resolution getters */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+getres_timeofday(void *arg, ns_time_t *np)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ (void) arg;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *np = 1000;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+getres_mach(void *arg, ns_time_t *np)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ (void) arg;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *np = mach_res;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+getres_gettime(void *arg, ns_time_t *np)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ timespec_t ts = {0, 0};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ret = clock_getres((clockid_t) (pointer_int_t) arg, &ts);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *np = ts2nsec(&ts);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Resolution must be 1-1000 ns */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!ret && (ts.tv_sec || ts.tv_nsec < 1 || ts.tv_nsec > 1000)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ret = -err_resolution;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+getres_gettime_ns(void *arg, ns_time_t *np)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return getres_gettime(arg, np);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+getres(clock_idx_t clkidx, ns_time_t *np)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define CLOCK_TYPE(name,buf) \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ case clock_type_##name: \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return getres_##name(clock_args[clkidx], np);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ switch (clock_types[clkidx]) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ CLOCK_TYPES
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#undef CLOCK_TYPE
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ abort(); /* Should be unreachable, but some dumb compilers complain */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* General sample collection, with checking and retries */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Check collected samples (nanosecond version) */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+check_samples(clock_idx_t clkidx, errinfo_t *ei)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int ret, maxsame, cursame = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ns_time_t last, cur = 0, res = 0, nzmin = ~0ULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ const ns_time_t *buf = nsbufp[clock_types[clkidx]];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ const ns_time_t *nsp = buf;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ sns_time_t diff;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Determine maximum consecutive repeated values */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if ((ret = getres(clkidx, &res))) return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ maxsame = MAX(res, MIN_CLOCK_RES_NS) * 1000 / MIN_READ_TIME_PS;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ei->errnum = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ last = *nsp++;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ while (nsp < &buf[NUM_SAMPLES]) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ cur = *nsp++;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ diff = cur - last;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (diff < 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (clock_okstep[clkidx]) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ei->errnum = -err_backstep; ret = 1; break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ei->errnum = -err_illbackstep; ret = -1; break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (diff > MAX_STEP_NS) { ei->errnum = -err_step; ret = 1; break; }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!diff) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (++cursame > maxsame && !clock_approx[clkidx]) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ei->errnum = -err_zerostep; ret = -1; break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (diff < nzmin) nzmin = diff;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ cursame = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ last = cur;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ei->first = buf[0]; ei->last = buf[NUM_SAMPLES - 1];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ei->index = ret ? nsp - buf : -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ei->prev = last; ei->cur = cur;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ei->nzmin = nzmin < ~0ULL ? nzmin : 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ei->badsame = cursame; ei->maxsame = maxsame;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ei->retries = -1; /* Will be updated */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Get stats on time differences */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static void
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+get_stats(clock_idx_t clkidx, cstats_t *sp)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ const ns_time_t *buf = nsbufp[clock_types[clkidx]];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ const ns_time_t *nsp = buf;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ns_time_t last, cur;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int64_t diff;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ long double mean, sqsum = 0.0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int cursame = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ sp->min = ~0ULL; sp->max = 0; sp->maxsame = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ last = *nsp++;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ sp->mean = mean = (buf[NUM_DIFFS] - buf[0]) / NUM_DIFFS;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ while (nsp < &buf[NUM_SAMPLES]) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ cur = *nsp++; diff = (int64_t) cur - (int64_t) last;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ last = cur;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (diff < sp->min) sp->min = diff;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (diff > sp->max) sp->max = diff;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ sqsum = (diff - mean) * (diff - mean);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!diff) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (++cursame > sp->maxsame) sp->maxsame = cursame;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ cursame =0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ sp->stddev = sqrt(sqsum / (NUM_DIFFS - 1));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Get and check one clock */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+check_clock(clock_idx_t clkidx, cstats_t *sp, errinfo_t *ei)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int ret, tries = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ useconds_t sleepus = STD_SLEEP_US;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ do {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ usleepx(sleepus);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if ((ret = collect_samples(clkidx, ei))) break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if ((ret = check_samples(clkidx, ei)) <= 0) break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ sleepus = MIN(sleepus * 2, MAX_SLEEP_US);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } while (++tries < MAX_STEP_TRIES);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ei->retries = tries;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!ret && sp) get_stats(clkidx, sp);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Report error getting time */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static void
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+report_clock_err(clock_idx_t clkidx, const errinfo_t *ei, int verbose)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ const char *indent = verbose ? " " : "";
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf("%s*** clock %s failed (%d): %s\n",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ indent, clock_names[clkidx],
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ei->errnum, get_errstr(ei->errnum));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!verbose) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf(" @%d: %llu->%llu(%llu), numsame = %d/%d, retries = %d\n",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ei->index, ULL ei->prev, ULL ei->cur, ULL (ei->cur - ei->prev),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ei->badsame, ei->maxsame, ei->retries);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf(" first/last = %llu/%llu, fail @%d: %llu->%llu(%llu)\n"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ " numsame = %d/%d, retries = %d\n",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ULL ei->first, ULL ei->last, ei->index,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ULL ei->prev, ULL ei->cur, ULL (ei->cur - ei->prev),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ei->badsame, ei->maxsame, ei->retries);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Print stats */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static void
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+print_stats(const cstats_t *sp, const errinfo_t *ei)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (sp->maxsame) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf(" clock diffs (maxsame min/nzmin/mean/max stddev) "
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ "= %d %llu/%llu/%.2f/%llu %.3f\n",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ sp->maxsame,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ULL sp->min, ULL ei->nzmin, sp->mean, ULL sp->max, sp->stddev);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf(" clock diffs (min/mean/max stddev) "
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ "= %llu/%.2f/%llu %.3f\n",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ULL sp->min, sp->mean, ULL sp->max, sp->stddev);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (ei->retries > 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf(" retries to avoid steps or excessive repeats = %d\n",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ei->retries);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Open logfile for writing */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static FILE *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+open_log(clock_idx_t clkidx, const char *extra, int quiet)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ FILE *fp;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ const char *name = clock_names[clkidx];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ char fname[PATH_MAX];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ snprintf(fname, sizeof(fname), TEST_TEMP "/%s-%s%s.log",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ progname, name, extra);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if(!(fp = fopen(fname, "w"))) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ fprintf(stderr, " Unable to open %s\n", fname);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!quiet) printf(" Logging to " TEST_TEMP "/\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return fp;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Dump all clock samples */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static void
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+clock_dump_ns(clock_idx_t clkidx, errinfo_t *ei, int verbose, int quiet)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int idx;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ns_time_t cur, *nsbuf = nsbufp[clock_types[clkidx]];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ sns_time_t last = nsbuf[0];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ FILE *fp;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!(fp = open_log(clkidx, "", quiet))) return;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (verbose >= 2) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ fprintf(fp, "# Capture of %d %s samples (%s), retries = %d\n",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ NUM_SAMPLES, clock_names[clkidx],
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ei->errnum ? "error" : "no error", ei->retries);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ fprintf(fp, "# Nonzero min delta = %d, max consecutive same = %d\n",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ (int) ei->nzmin, ei->badsame);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ fprintf(fp, "# First value = %llu, last = %llu, diff = %llu\n",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ULL ei->first, ULL ei->last, ULL (ei->last - ei->first));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ fprintf(fp, "# Average time per sample = %.1f ns\n",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ (double) (ei->last - ei->first) / (NUM_SAMPLES - 1));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (ei->errnum) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ fprintf(fp, "#\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ fprintf(fp, "# *** Error %d (%s)\n",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ei->errnum, get_errstr(ei->errnum));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ fprintf(fp, "# *** Failed @%d: %llu -> %llu (%lld)\n",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ei->index, ULL ei->prev, ULL ei->cur, LL ei->cur - LL ei->prev);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ fprintf(fp, "#\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (verbose) fprintf(fp, "# Index Value Delta\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ for (idx = 0; idx < NUM_SAMPLES; ++idx) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ cur = nsbuf[idx];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ fprintf(fp, "%7d %19llu %5d\n", idx, ULL cur, (int) (cur - last));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ last = cur;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ fclose(fp);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Report info about one clock */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+report_clock(clock_idx_t clkidx, int dump, int verbose, int quiet)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int err, ret = 0, vnq = verbose && !quiet;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ const char *name = clock_names[clkidx];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ cstats_t stats = {0};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ errinfo_t info = {0};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (vnq) printf(" Checking %s", name);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if ((err = getres(clkidx, &clock_res[clkidx]))) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!vnq) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf("*** Error getting resolution of clock %s (%d): %s\n",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ clock_names[clkidx], err, get_errstr(err));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf("\n *** Error getting resolution of clock %s (%d): %s\n",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ clock_names[clkidx], err, get_errstr(err));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (err < 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf(" *** Value = %lld\n", (long long) clock_res[clkidx]);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (vnq) printf(" (resolution = %d ns)\n", (int) clock_res[clkidx]);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if ((err = check_clock(clkidx, &stats, &info))) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ report_clock_err(clkidx, &info, verbose);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ret = 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (vnq && !ret) print_stats(&stats, &info);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if ((dump && ret) || dump > 1) clock_dump_ns(clkidx, &info, verbose, quiet);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Report info about all clocks (singly) */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+report_all_clocks(int dump, int verbose, int quiet)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int ret = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ clock_idx_t clkidx = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ while (clkidx < (clock_idx_t) clock_idx_max) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ret |= report_clock(clkidx, dump, verbose, quiet);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ++clkidx;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* Main function */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+int
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+main(int argc, char *argv[])
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int argn = 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int continuous = 0, dump = 0, quiet = 0, verbose = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int err = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ const char *cp;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ char chr;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ strncpy(progname, basename(argv[0]), sizeof(progname));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ while (argn < argc && argv[argn][0] == '-') {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ cp = argv[argn];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ while ((chr = *++cp)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ switch (chr) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ case 'C': ++continuous; break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ case 'd': ++dump; break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ case 'q': ++quiet; break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ case 'v': ++verbose; break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ++argn;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (verbose && !quiet) printf("%s starting.\n", progname);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ err = setup(verbose && !quiet);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ err |= check_invalid();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ while (!err) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ err |= report_all_clocks(dump, verbose, quiet);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!continuous) break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!quiet) printf("%s %s.\n", progname, err ? "failed" : "passed");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return err;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span></pre><pre style='margin:0'>
</pre>