Home | History | Annotate | Line # | Download | only in sys
t_clock_gettime.c revision 1.6.2.1
      1  1.6.2.1  perseant /* $NetBSD: t_clock_gettime.c,v 1.6.2.1 2025/08/02 05:58:06 perseant Exp $ */
      2      1.1    jruoho 
      3      1.1    jruoho /*-
      4      1.1    jruoho  * Copyright (c) 2008 The NetBSD Foundation, Inc.
      5      1.1    jruoho  * All rights reserved.
      6      1.1    jruoho  *
      7      1.1    jruoho  * This code is derived from software contributed to The NetBSD Foundation
      8      1.1    jruoho  * by Frank Kardel.
      9      1.1    jruoho  *
     10      1.1    jruoho  * Redistribution and use in source and binary forms, with or without
     11      1.1    jruoho  * modification, are permitted provided that the following conditions
     12      1.1    jruoho  * are met:
     13      1.1    jruoho  * 1. Redistributions of source code must retain the above copyright
     14      1.1    jruoho  *    notice, this list of conditions and the following disclaimer.
     15      1.1    jruoho  * 2. Redistributions in binary form must reproduce the above copyright
     16      1.1    jruoho  *    notice, this list of conditions and the following disclaimer in the
     17      1.1    jruoho  *    documentation and/or other materials provided with the distribution.
     18      1.1    jruoho  *
     19      1.1    jruoho  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20      1.1    jruoho  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21      1.1    jruoho  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22      1.1    jruoho  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23      1.1    jruoho  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24      1.1    jruoho  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25      1.1    jruoho  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26      1.1    jruoho  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27      1.1    jruoho  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28      1.1    jruoho  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29      1.1    jruoho  * POSSIBILITY OF SUCH DAMAGE.
     30      1.1    jruoho  */
     31      1.1    jruoho 
     32      1.1    jruoho /*-
     33      1.1    jruoho  * Copyright (c) 2006 Frank Kardel
     34      1.1    jruoho  * All rights reserved.
     35      1.1    jruoho  *
     36      1.1    jruoho  * Redistribution and use in source and binary forms, with or without
     37      1.1    jruoho  * modification, are permitted provided that the following conditions
     38      1.1    jruoho  * are met:
     39      1.1    jruoho  * 1. Redistributions of source code must retain the above copyright
     40      1.1    jruoho  *    notice, this list of conditions and the following disclaimer.
     41      1.1    jruoho  * 2. Redistributions in binary form must reproduce the above copyright
     42      1.1    jruoho  *    notice, this list of conditions and the following disclaimer in the
     43      1.1    jruoho  *    documentation and/or other materials provided with the distribution.
     44      1.1    jruoho  *
     45      1.1    jruoho  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     46      1.1    jruoho  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     47      1.1    jruoho  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     48      1.1    jruoho  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     49      1.1    jruoho  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     50      1.1    jruoho  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     51      1.1    jruoho  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     52      1.1    jruoho  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     53      1.1    jruoho  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     54      1.1    jruoho  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     55      1.1    jruoho  * POSSIBILITY OF SUCH DAMAGE.
     56      1.1    jruoho  */
     57      1.1    jruoho 
     58      1.1    jruoho #include <sys/cdefs.h>
     59      1.1    jruoho __COPYRIGHT("@(#) Copyright (c) 2008\
     60      1.1    jruoho  The NetBSD Foundation, inc. All rights reserved.");
     61  1.6.2.1  perseant __RCSID("$NetBSD: t_clock_gettime.c,v 1.6.2.1 2025/08/02 05:58:06 perseant Exp $");
     62      1.1    jruoho 
     63      1.1    jruoho #include <sys/param.h>
     64      1.4  riastrad 
     65      1.4  riastrad #include <sys/ioctl.h>
     66      1.1    jruoho #include <sys/sysctl.h>
     67      1.1    jruoho 
     68      1.1    jruoho #include <atf-c.h>
     69      1.1    jruoho #include <errno.h>
     70      1.4  riastrad #include <fcntl.h>
     71      1.2  christos #include <limits.h>
     72      1.4  riastrad #include <stdint.h>
     73      1.1    jruoho #include <stdio.h>
     74      1.1    jruoho #include <stdlib.h>
     75      1.1    jruoho #include <string.h>
     76      1.1    jruoho #include <time.h>
     77      1.1    jruoho #include <unistd.h>
     78      1.1    jruoho 
     79      1.3  christos #include "h_macros.h"
     80      1.1    jruoho 
     81      1.1    jruoho #define MINPOSDIFF	15000000	/* 15 ms for now */
     82      1.1    jruoho #define TIMEOUT		5
     83      1.1    jruoho 
     84      1.1    jruoho #define TC_HARDWARE	"kern.timecounter.hardware"
     85      1.1    jruoho #define TC_CHOICE	"kern.timecounter.choice"
     86      1.1    jruoho 
     87      1.1    jruoho static void
     88      1.1    jruoho check_timecounter(void)
     89      1.1    jruoho {
     90      1.1    jruoho 	struct timespec tsa, tsb, tsl, res;
     91      1.1    jruoho 	long long mindiff = INTMAX_MAX;
     92      1.1    jruoho 	time_t endlimit;
     93      1.1    jruoho 
     94      1.1    jruoho #define CL(x) \
     95      1.1    jruoho 	do { \
     96      1.1    jruoho 		if ((x) != -1) \
     97      1.1    jruoho 			break; \
     98      1.1    jruoho 		atf_tc_fail_nonfatal("%s: %s", #x, strerror(errno)); \
     99      1.1    jruoho 		return; \
    100      1.1    jruoho 	} while (0)
    101      1.1    jruoho 
    102      1.1    jruoho 	CL(clock_gettime(CLOCK_REALTIME, &tsa));
    103      1.1    jruoho 	tsl = tsa;
    104      1.1    jruoho 
    105      1.1    jruoho 	CL(time(&endlimit));
    106      1.1    jruoho 	endlimit += TIMEOUT + 1;
    107      1.1    jruoho 
    108      1.1    jruoho 	while ((time_t)tsa.tv_sec < endlimit) {
    109      1.1    jruoho 		long long diff;
    110      1.1    jruoho 
    111      1.1    jruoho 		CL(clock_gettime(CLOCK_REALTIME, &tsb));
    112      1.1    jruoho 		diff = 1000000000LL * (tsb.tv_sec - tsa.tv_sec)
    113      1.1    jruoho 		    + tsb.tv_nsec - tsa.tv_nsec;
    114      1.1    jruoho 
    115      1.1    jruoho 		if (diff > 0 && mindiff > diff)
    116      1.1    jruoho 			mindiff = diff;
    117      1.1    jruoho 
    118      1.1    jruoho 		if (diff < 0 || diff > MINPOSDIFF) {
    119      1.1    jruoho 			long long elapsed;
    120  1.6.2.1  perseant 			(void)printf("%stime"
    121  1.6.2.1  perseant 			    " TSA: 0x%jx.%08jx, TSB: 0x%jx.%08jx, "
    122      1.1    jruoho 			    "diff = %lld nsec, ", (diff < 0) ? "BAD " : "",
    123      1.1    jruoho 			    (uintmax_t)tsa.tv_sec, (uintmax_t)tsa.tv_nsec,
    124  1.6.2.1  perseant 			    (uintmax_t)tsb.tv_sec, (uintmax_t)tsb.tv_nsec,
    125  1.6.2.1  perseant 			    diff);
    126      1.1    jruoho 
    127      1.1    jruoho 			elapsed = 1000000000LL * (tsb.tv_sec - tsl.tv_sec)
    128      1.1    jruoho 			    + tsb.tv_nsec - tsl.tv_nsec;
    129      1.1    jruoho 
    130      1.1    jruoho 
    131      1.1    jruoho 			(void)printf("%lld nsec\n", elapsed);
    132      1.1    jruoho 			tsl = tsb;
    133      1.1    jruoho 
    134      1.1    jruoho 			ATF_CHECK(diff >= 0);
    135      1.1    jruoho 			if (diff < 0)
    136      1.1    jruoho 				return;
    137      1.1    jruoho 		}
    138      1.1    jruoho 
    139      1.1    jruoho 		tsa.tv_sec = tsb.tv_sec;
    140      1.1    jruoho 		tsa.tv_nsec = tsb.tv_nsec;
    141      1.1    jruoho 	}
    142      1.1    jruoho 
    143      1.1    jruoho 	if (clock_getres(CLOCK_REALTIME, &res) == 0) {
    144      1.1    jruoho 		long long r = res.tv_sec * 1000000000 + res.tv_nsec;
    145      1.1    jruoho 
    146      1.1    jruoho 		(void)printf("Claimed resolution: %lld nsec (%f Hz) or "
    147      1.1    jruoho 		    "better\n", r, 1.0 / r * 1e9);
    148      1.1    jruoho 		(void)printf("Observed minimum non zero delta: %lld "
    149      1.1    jruoho 		    "nsec\n", mindiff);
    150      1.1    jruoho 	}
    151      1.1    jruoho 
    152      1.1    jruoho #undef CL
    153      1.1    jruoho }
    154      1.1    jruoho 
    155      1.1    jruoho ATF_TC(clock_gettime_real);
    156      1.1    jruoho ATF_TC_HEAD(clock_gettime_real, tc)
    157      1.1    jruoho {
    158      1.1    jruoho 	atf_tc_set_md_var(tc, "require.user", "root");
    159      1.1    jruoho 	atf_tc_set_md_var(tc, "descr",
    160      1.1    jruoho 	    "Checks the monotonicity of the CLOCK_REALTIME implementation");
    161      1.1    jruoho 	atf_tc_set_md_var(tc, "timeout", "300");
    162      1.1    jruoho }
    163      1.1    jruoho 
    164      1.1    jruoho ATF_TC_BODY(clock_gettime_real, tc)
    165      1.1    jruoho {
    166      1.1    jruoho 	char name[128], cbuf[512], ctrbuf[10240];
    167      1.1    jruoho 	size_t cbufsiz = sizeof(cbuf);
    168      1.1    jruoho 	size_t ctrbufsiz = sizeof(ctrbuf);
    169      1.1    jruoho 	const char *p;
    170      1.1    jruoho 	char *save;
    171      1.1    jruoho 	int quality, n;
    172      1.1    jruoho 
    173      1.1    jruoho 	if (sysctlbyname(TC_HARDWARE, cbuf, &cbufsiz, NULL, 0) != 0) {
    174      1.1    jruoho 		(void)printf("\nChecking legacy time implementation "
    175      1.1    jruoho 		    "for %d seconds\n", TIMEOUT);
    176      1.1    jruoho 		check_timecounter();
    177      1.1    jruoho 		return;
    178      1.1    jruoho 		/* NOTREACHED */
    179      1.1    jruoho 	}
    180      1.1    jruoho 	(void)printf("%s = %s\n", TC_HARDWARE, cbuf);
    181      1.1    jruoho 	REQUIRE_LIBC(save = strdup(cbuf), NULL);
    182      1.1    jruoho 
    183      1.1    jruoho 	RL(sysctlbyname(TC_CHOICE, ctrbuf, &ctrbufsiz, NULL, 0));
    184      1.1    jruoho 	(void)printf("%s = %s\n", TC_CHOICE, ctrbuf);
    185      1.1    jruoho 
    186      1.1    jruoho 	for (p = ctrbuf, n = 0; sscanf(p, "%127[^(](q=%d, f=%*u Hz)%*[ ]%n",
    187      1.1    jruoho 	    name, &quality, &n) == 2; p += n) {
    188      1.1    jruoho 		struct timespec ts;
    189      1.1    jruoho 		int ret;
    190      1.1    jruoho 
    191      1.1    jruoho 		if (quality < 0)
    192      1.1    jruoho 			continue;
    193      1.1    jruoho 
    194      1.1    jruoho 		(void)printf("\nChecking %s for %d seconds\n", name, TIMEOUT);
    195      1.1    jruoho 		CHECK_LIBC(ret = sysctlbyname(TC_HARDWARE, NULL, 0,
    196      1.1    jruoho 		    name, strlen(name)), -1);
    197      1.1    jruoho 		if (ret == -1)
    198      1.1    jruoho 			continue;
    199      1.1    jruoho 
    200      1.1    jruoho 		/* wait a bit to select new counter in clockinterrupt */
    201      1.1    jruoho 		ts.tv_sec = 0;
    202      1.1    jruoho 		ts.tv_nsec = 100000000;
    203      1.1    jruoho 		(void)nanosleep(&ts, NULL);
    204      1.1    jruoho 
    205      1.1    jruoho 		check_timecounter();
    206      1.1    jruoho 	}
    207      1.1    jruoho 
    208      1.1    jruoho 	RL(sysctlbyname(TC_HARDWARE, NULL, 0, save, strlen(save)));
    209      1.1    jruoho }
    210      1.1    jruoho 
    211      1.4  riastrad static void
    212      1.4  riastrad waste_user_time(void)
    213      1.4  riastrad {
    214      1.4  riastrad 	static char buf[4*4096];
    215      1.4  riastrad 
    216      1.4  riastrad 	arc4random_buf(buf, sizeof(buf));
    217      1.4  riastrad }
    218      1.4  riastrad 
    219      1.4  riastrad static void __unused
    220      1.4  riastrad waste_system_time(void)
    221      1.4  riastrad {
    222      1.4  riastrad 	static char buf[4*4096];
    223      1.4  riastrad 	int fd[2];
    224      1.4  riastrad 	int i, n;
    225      1.4  riastrad 
    226      1.4  riastrad 	RL(pipe2(fd, O_NONBLOCK));
    227      1.4  riastrad 	RL(n = ioctl(fd[1], FIONSPACE));
    228      1.6  riastrad 	n = MIN((unsigned)MAX(0, n), sizeof(buf));
    229      1.4  riastrad 	for (i = 0; i < 16; i++) {
    230      1.4  riastrad 		RL(write(fd[1], buf, n));
    231      1.4  riastrad 		RL(read(fd[0], buf, n));
    232      1.4  riastrad 	}
    233      1.4  riastrad 	RL(close(fd[0]));
    234      1.4  riastrad 	RL(close(fd[1]));
    235      1.4  riastrad }
    236      1.4  riastrad 
    237      1.4  riastrad static void
    238      1.4  riastrad check_monotonicity(const char *clockname, clockid_t clockid,
    239      1.4  riastrad     void (*waste_time)(void))
    240      1.4  riastrad {
    241      1.4  riastrad 	static const struct timespec maxtime = {5, 0};
    242      1.4  riastrad 	struct timespec mono_t0, t0, mono_d;
    243      1.4  riastrad 
    244      1.4  riastrad 	RL(clock_gettime(CLOCK_MONOTONIC, &mono_t0));
    245      1.4  riastrad 	RL(clock_gettime(clockid, &t0));
    246      1.4  riastrad 
    247      1.4  riastrad 	do {
    248      1.4  riastrad 		struct timespec t1, mono_t1;
    249      1.4  riastrad 
    250      1.4  riastrad 		(*waste_time)();
    251      1.4  riastrad 
    252      1.4  riastrad 		RL(clock_gettime(clockid, &t1));
    253      1.4  riastrad 		ATF_CHECK_MSG(timespeccmp(&t0, &t1, <=),
    254      1.4  riastrad 		    "clock %s=0x%jx went backwards t0=%jd.%09ld t1=%jd.%09ld",
    255      1.4  riastrad 		    clockname, (uintmax_t)clockid,
    256      1.4  riastrad 		    (intmax_t)t0.tv_sec, t0.tv_nsec,
    257      1.4  riastrad 		    (intmax_t)t1.tv_sec, t1.tv_nsec);
    258      1.4  riastrad 
    259      1.4  riastrad 		t0 = t1;
    260      1.4  riastrad 
    261      1.4  riastrad 		RL(clock_gettime(CLOCK_MONOTONIC, &mono_t1));
    262      1.4  riastrad 		timespecsub(&mono_t1, &mono_t0, &mono_d);
    263      1.4  riastrad 	} while (timespeccmp(&mono_d, &maxtime, <));
    264      1.4  riastrad }
    265      1.4  riastrad 
    266      1.4  riastrad ATF_TC(clock_gettime_process_cputime_is_monotonic);
    267      1.4  riastrad ATF_TC_HEAD(clock_gettime_process_cputime_is_monotonic, tc)
    268      1.4  riastrad {
    269      1.4  riastrad 	atf_tc_set_md_var(tc, "descr",
    270      1.4  riastrad 	    "Checks that CLOCK_PROCESS_CPUTIME_ID is monotonic");
    271      1.4  riastrad }
    272      1.4  riastrad ATF_TC_BODY(clock_gettime_process_cputime_is_monotonic, tc)
    273      1.4  riastrad {
    274      1.4  riastrad 	check_monotonicity("CLOCK_PROCESS_CPUTIME_ID",
    275      1.4  riastrad 	    CLOCK_PROCESS_CPUTIME_ID, &waste_user_time);
    276      1.4  riastrad }
    277      1.4  riastrad 
    278      1.4  riastrad ATF_TC(clock_gettime_thread_cputime_is_monotonic);
    279      1.4  riastrad ATF_TC_HEAD(clock_gettime_thread_cputime_is_monotonic, tc)
    280      1.4  riastrad {
    281      1.4  riastrad 	atf_tc_set_md_var(tc, "descr",
    282      1.4  riastrad 	    "Checks that CLOCK_THREAD_CPUTIME_ID is monotonic");
    283      1.4  riastrad }
    284      1.4  riastrad ATF_TC_BODY(clock_gettime_thread_cputime_is_monotonic, tc)
    285      1.4  riastrad {
    286      1.4  riastrad 	check_monotonicity("CLOCK_THREAD_CPUTIME_ID",
    287      1.4  riastrad 	    CLOCK_THREAD_CPUTIME_ID, &waste_user_time);
    288      1.4  riastrad }
    289      1.4  riastrad 
    290  1.6.2.1  perseant static void
    291  1.6.2.1  perseant check_resolution(const char *clockname, clockid_t clockid)
    292  1.6.2.1  perseant {
    293  1.6.2.1  perseant 	struct timespec ts;
    294  1.6.2.1  perseant 	int rv;
    295  1.6.2.1  perseant 
    296  1.6.2.1  perseant 	RLF(rv = clock_getres(clockid, &ts), "%s", clockname);
    297  1.6.2.1  perseant 	if (rv != -1) {
    298  1.6.2.1  perseant 		ATF_CHECK_MSG(ts.tv_sec == 0,
    299  1.6.2.1  perseant 		    "The resolution of the clock %s is reported as %jd.%09ld"
    300  1.6.2.1  perseant 		    " which is lower than a second; most likely a wrong value",
    301  1.6.2.1  perseant 		    clockname, ts.tv_sec, ts.tv_nsec);
    302  1.6.2.1  perseant 	}
    303  1.6.2.1  perseant }
    304  1.6.2.1  perseant 
    305  1.6.2.1  perseant ATF_TC(clock_getres);
    306  1.6.2.1  perseant ATF_TC_HEAD(clock_getres, tc)
    307  1.6.2.1  perseant {
    308  1.6.2.1  perseant 	atf_tc_set_md_var(tc, "descr",
    309  1.6.2.1  perseant 	    "Checks that clock_getres(2) returns some reasonable resolution"
    310  1.6.2.1  perseant 	    " for all supported clocks");
    311  1.6.2.1  perseant }
    312  1.6.2.1  perseant ATF_TC_BODY(clock_getres, tc)
    313  1.6.2.1  perseant {
    314  1.6.2.1  perseant 	check_resolution("CLOCK_REALTIME", CLOCK_REALTIME);
    315  1.6.2.1  perseant 	check_resolution("CLOCK_MONOTONIC", CLOCK_MONOTONIC);
    316  1.6.2.1  perseant 	atf_tc_expect_fail("These clocks aren't supported but are documented"
    317  1.6.2.1  perseant 	    " in clock_gettime(2) for some reason");
    318  1.6.2.1  perseant 	check_resolution("CLOCK_VIRTUAL", CLOCK_VIRTUAL);
    319  1.6.2.1  perseant 	check_resolution("CLOCK_PROF", CLOCK_PROF);
    320  1.6.2.1  perseant 	atf_tc_expect_pass();
    321  1.6.2.1  perseant 	check_resolution("CLOCK_PROCESS_CPUTIME_ID", CLOCK_PROCESS_CPUTIME_ID);
    322  1.6.2.1  perseant 	check_resolution("CLOCK_THREAD_CPUTIME_ID", CLOCK_THREAD_CPUTIME_ID);
    323  1.6.2.1  perseant }
    324  1.6.2.1  perseant 
    325      1.1    jruoho ATF_TP_ADD_TCS(tp)
    326      1.1    jruoho {
    327      1.1    jruoho 
    328      1.1    jruoho 	ATF_TP_ADD_TC(tp, clock_gettime_real);
    329      1.4  riastrad 	ATF_TP_ADD_TC(tp, clock_gettime_process_cputime_is_monotonic);
    330      1.4  riastrad 	ATF_TP_ADD_TC(tp, clock_gettime_thread_cputime_is_monotonic);
    331  1.6.2.1  perseant 	ATF_TP_ADD_TC(tp, clock_getres);
    332      1.1    jruoho 
    333      1.1    jruoho 	return atf_no_error();
    334      1.1    jruoho }
    335