<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/24117c0e5b06bf660c95e257c61bcb1bc20328e0">https://github.com/macports/macports-legacy-support/commit/24117c0e5b06bf660c95e257c61bcb1bc20328e0</a></p>
<pre style="white-space: pre; background: #F8F8F8"><span style='display:block; white-space:pre;color:#808000;'>commit 24117c0e5b06bf660c95e257c61bcb1bc20328e0
</span>Author: Fred Wright <fw@fwright.net>
AuthorDate: Fri Apr 11 14:04:56 2025 -0700
<span style='display:block; white-space:pre;color:#404040;'> test_clocks: Add mach_time scaling check.
</span><span style='display:block; white-space:pre;color:#404040;'>
</span><span style='display:block; white-space:pre;color:#404040;'> This adds reporting and checking of mach_time scaling.
</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;'> Reports plausibly, and detects both forms of bad scaling on PPC.
</span>---
test/test_clocks.c | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++---
1 file changed, 83 insertions(+), 4 deletions(-)
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/test/test_clocks.c b/test/test_clocks.c
</span><span style='display:block; white-space:pre;color:#808080;'>index 58cd4af..9010dfe 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/test/test_clocks.c
</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;'>@@ -67,10 +67,13 @@ typedef int64_t sns_time_t;
</span> #define BILLION64 1000000000ULL
/* Parameters for collection sequence */
<span style='display:block; white-space:pre;background:#ffe0e0;'>-#define MAX_STEP_NS 700000 /* Maximum delta not considered a step */
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-#define MAX_STEP_TRIES 50 /* Maximum tries to avoid a step */
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-#define STD_SLEEP_US 1000 /* Standard sleep before collecting */
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-#define MAX_SLEEP_US 100000 /* Maximum sleep when retrying */
</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;'>+/* Mach_time scaling tolerance */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define MACH_SCALE_TOLER 10E-6
</span>
#ifndef TEST_TEMP
#define TEST_TEMP "/dev/null"
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -1297,6 +1300,81 @@ report_all_clock_compares(int dump, int verbose, int quiet)
</span> return ret;
}
<span style='display:block; white-space:pre;background:#e0ffe0;'>+/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * Check mach_time scaling
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * This checks the computation that scales mach_time to nanoseconds. It
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * only checks the accuracy of applying the scale factor reported by the OS;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * it does *not* check the scale factor itself. See the comment titled
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * "Mach timebase scaling" in src/time.c for details of right and wrong ways
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * to do this.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * The basic approach is to grab a "sandwich" of CLOCK_UPTIME_RAW (ns)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * between samples of mach_absolute_time(), and check the ratio of values.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * With any uptime of more than about a second, the inaccuracy of the
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * "divide first" approach on PowerPC is reliably observable, and with any
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * uptime of more than about 7.4 minutes, the overflow and wraparound of the
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * "multiply first" approach on PowerPC can be observed.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * If and when the overflow occurs from using the "multiply first" approach
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * on PowrerPC, the computed nanosecond value wraps around, after which its
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * value is never more than half the correct value. Thus, it can be detected
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ * on the basis of a very large negative error in the scale (at least 0.5).
</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;'>+check_mach_scaling(int verbose)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int ret = 0, idx, best = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ mach_time_t mt[4];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ns_time_t nst[3];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ double nslo, nshi, nsmean, nstoler, nscur, nserr, err_mult;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ const char *err_units, *msg;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (verbose) printf(" Checking mach_time scaling\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Get tightest "sandwich" out of 4/3 */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ mt[0] = mach_absolute_time();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ nst[0] = clock_gettime_nsec_np(CLOCK_UPTIME_RAW);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ mt[1] = mach_absolute_time();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ nst[1] = clock_gettime_nsec_np(CLOCK_UPTIME_RAW);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ mt[2] = mach_absolute_time();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ nst[2] = clock_gettime_nsec_np(CLOCK_UPTIME_RAW);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ mt[3] = mach_absolute_time();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ for(idx = 1; idx < 3; ++idx) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (mt[idx+1] - mt[idx] < mt[best+1] - mt[best]) best = idx;
</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;'>+ nslo = mt[best] * mach2nanos; nshi = mt[best+1] * mach2nanos;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ nscur = nst[best];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ nsmean = (nslo + nshi) / 2.0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ nstoler = (nshi - nslo) / 2.0 / nsmean;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ nserr = (nscur - nsmean) / nsmean;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (nserr < -0.499) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf(" *** Mach scaling wraparound, mach = %llu->%llu, ns = %llu\n",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ ULL mt[best], ULL mt[best+1], ULL nst[best]);
</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;'>+ if (fabs(nserr) >= 1E-6) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ err_mult = 1E6; err_units = "ppm";
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ err_mult = 1E9; err_units = "ppb";
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (fabs(nserr) >= MACH_SCALE_TOLER) ret = 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (verbose || ret) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ msg = ret ? "*** Excessive mach scaling error"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ : "Measured mach scaling error";
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf(" %s = %+.6f %s +/- %.6f %s\n", msg,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ nserr * err_mult, err_units, nstoler * err_mult, err_units);
</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 ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span> /* Main function */
int
main(int argc, char *argv[])
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -1329,6 +1407,7 @@ main(int argc, char *argv[])
</span> while (!err) {
err |= report_all_clocks(dump, verbose, quiet);
err |= report_all_clock_compares(dump, verbose, quiet);
<span style='display:block; white-space:pre;background:#e0ffe0;'>+ err |= check_mach_scaling(verbose && !quiet);
</span> if (!continuous) break;
}
</pre><pre style='margin:0'>
</pre>