<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/5bf5c9e06ffa55a8463f0d52c1a80034ea2748b2">https://github.com/macports/macports-legacy-support/commit/5bf5c9e06ffa55a8463f0d52c1a80034ea2748b2</a></p>
<pre style="white-space: pre; background: #F8F8F8"><span style='display:block; white-space:pre;color:#808000;'>commit 5bf5c9e06ffa55a8463f0d52c1a80034ea2748b2
</span>Author: Fred Wright <fw@fwright.net>
AuthorDate: Sat Feb 22 11:21:58 2025 -0800
<span style='display:block; white-space:pre;color:#404040;'> Add tool to report properties of mach time scale.
</span>---
tools/mach_time.c | 186 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 186 insertions(+)
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/tools/mach_time.c b/tools/mach_time.c
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 0000000..a0b4800
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/tools/mach_time.c
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,186 @@
</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;'>+/* This is a simple too to report info about mach_time scaling */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#include <limits.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 <stdio.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 <stdlib.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/sysctl.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#if defined(__ppc__)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define ARCH "ppc"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#elif defined(__ppc64__)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define ARCH "ppc64"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#elif defined(__i386__)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define ARCH "i386"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#elif defined(__x86_64__)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define ARCH "x86_64"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#elif defined(__arm__)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define ARCH "arm"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#elif defined(__arm64__) || defined(__aarch64__)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define ARCH "arm64"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define ARCH "unknown"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define SYSCTL_OSVER_CLASS CTL_KERN
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define SYSCTL_OSVER_ITEM KERN_OSRELEASE
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* sysctl to check whether we're running natively (not Rosetta 1) */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define SYSCTL_NATIVE "sysctl.proc_native"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* sysctl to check whether we're running in Rosetta 2 */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define SYSCTL_TRANSLATED "sysctl.proc_translated"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define EXTRA_SHIFT 2
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define HIGH_SHIFT (32 + EXTRA_SHIFT)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define HIGH_BITS (64 - HIGH_SHIFT)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+#define NUMERATOR_MASK (~0U << HIGH_BITS)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static char osver[256];
</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;'>+get_osver(void)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int mib[] = {SYSCTL_OSVER_CLASS, SYSCTL_OSVER_ITEM};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int miblen = sizeof(mib) / sizeof(mib[0]);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ size_t len = sizeof(osver);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (sysctl(mib, miblen, osver, &len, NULL, 0)) return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (len <= 0 || len >= (ssize_t) sizeof(osver)) return -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ osver[len] = '\0';
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (osver[len - 1] == '\n') osver[len - 1] = '\0';
</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;'>+/* Test whether running under Rosetta */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+/* -1 no, 1 Rosetta 1, 2 Rosetta 2 */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+static int
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+check_rosetta(void)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int native, translated;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ size_t native_sz = sizeof(native);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ size_t translated_sz = sizeof(translated);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Check for Rosetta 1 */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (sysctlbyname(SYSCTL_NATIVE, &native, &native_sz, NULL, 0) < 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* If sysctl failed, must be real ppc. */
</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 (!native) return 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* If "native", check for Rosetta 2 */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (sysctlbyname(SYSCTL_TRANSLATED, &translated, &translated_sz,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ NULL, 0) < 0) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* If sysctl failed, must be really native. */
</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;'>+ return translated ? 2 : -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;'>+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 err, tbinfo_err;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ const char *rosetta;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ unsigned long val;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ char *cp;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ mach_timebase_info_data_t tbinfo;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ double scale, dfscale;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ double limit;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ uint64_t scale_ns;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ double fscale_ns;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ double error_ns, dferror_ns, serror_ns;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ const char *approxstr, *err_units;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (argc >= 3) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ val = strtoul(argv[1], &cp, 0);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (*cp) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf("Bad numerator\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;'>+ tbinfo.numer = val;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ val = strtoul(argv[2], &cp, 0);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (*cp) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf("Bad denominator\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;'>+ tbinfo.denom = val;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ err = get_osver();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ switch (check_rosetta()) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ case -1: rosetta = "native"; break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ case 1: rosetta = "Rosetta 1"; break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ case 2: rosetta = "Rosetta 2"; break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ default: rosetta = "???"; break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf("OS is Darwin %s, CPU is %s (%s)\n",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ err ? "???" : osver, ARCH, rosetta);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ tbinfo_err = mach_timebase_info(&tbinfo);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (tbinfo_err != KERN_SUCCESS) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf("Unable to obtain timebase rate, err = %d\n", tbinfo_err);
</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;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ scale = (double) tbinfo.numer / tbinfo.denom;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ dfscale = (double) (tbinfo.numer / tbinfo.denom);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ approxstr = (tbinfo.numer % tbinfo.denom) ? "~" : "";
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ limit = ldexp(1.0, 64) / tbinfo.denom / 1E9;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (!(tbinfo.numer & NUMERATOR_MASK)) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ scale_ns = (((uint64_t) tbinfo.numer << HIGH_SHIFT) + (tbinfo.denom >> 1))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ / tbinfo.denom;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ scale_ns = ((((uint64_t) tbinfo.numer << 32) + (tbinfo.denom >> 1))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ / tbinfo.denom) << EXTRA_SHIFT;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ fscale_ns = (double) (scale_ns >> 32) + ldexp(scale_ns & 0xFFFFFFFF,-32);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ error_ns = (ldexp(fscale_ns, -EXTRA_SHIFT) - scale) / scale;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ dferror_ns = (dfscale - scale) / scale;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (fabs(error_ns) >=1E-6) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ serror_ns = error_ns * 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;'>+ serror_ns = error_ns * 1E9; err_units = "ppb";
</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;'>+ printf("Mach absolute time multiplier (%db/%db) = %u/%u %s= %f\n",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ (int) sizeof(tbinfo.numer) * CHAR_BIT,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ (int) sizeof(tbinfo.denom) * CHAR_BIT,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ tbinfo.numer, tbinfo.denom,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ approxstr, scale);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf("Mach absolute time frequency = %.3f MHz\n", 1000.0 / scale);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ if (limit >= 86400) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf("Mach multiply-first scaling overflow at %.1f days, %.2f years\n",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ limit / 86400, limit / (86400 * 365.25));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ } else {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf("Mach multiply-first scaling overflow at %.2f minutes, %.2f hours\n",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ limit / 60, limit / 3600);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf("Mach divide-first scaling error = %.3f ppm\n", dferror_ns * 1E6);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ printf("Nanosecond 64-bit 30b.34b multiplier = 0x%08X:%08X %s= %f,"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ " relative error = %.6f %s\n",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ (uint32_t) (scale_ns >> 32), (uint32_t) (scale_ns & 0xFFFFFFFF),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ approxstr, ldexp(fscale_ns, -EXTRA_SHIFT), serror_ns, err_units);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ return 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+}
</span></pre><pre style='margin:0'>
</pre>