t_clock_gettime.c revision 276478
154359Sroberto/* $NetBSD: t_clock_gettime.c,v 1.1 2011/10/15 06:42:16 jruoho Exp $ */
2132451Sroberto
382498Sroberto/*-
4200576Sroberto * Copyright (c) 2008 The NetBSD Foundation, Inc.
5132451Sroberto * All rights reserved.
682498Sroberto *
782498Sroberto * This code is derived from software contributed to The NetBSD Foundation
854359Sroberto * by Frank Kardel.
954359Sroberto *
1054359Sroberto * Redistribution and use in source and binary forms, with or without
1154359Sroberto * modification, are permitted provided that the following conditions
1254359Sroberto * are met:
1354359Sroberto * 1. Redistributions of source code must retain the above copyright
1454359Sroberto *    notice, this list of conditions and the following disclaimer.
1554359Sroberto * 2. Redistributions in binary form must reproduce the above copyright
1654359Sroberto *    notice, this list of conditions and the following disclaimer in the
1754359Sroberto *    documentation and/or other materials provided with the distribution.
1854359Sroberto *
1954359Sroberto * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20182007Sroberto * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2154359Sroberto * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22132451Sroberto * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2354359Sroberto * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2454359Sroberto * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2554359Sroberto * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2654359Sroberto * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2754359Sroberto * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2854359Sroberto * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2954359Sroberto * POSSIBILITY OF SUCH DAMAGE.
3054359Sroberto */
31182007Sroberto
3254359Sroberto/*-
3354359Sroberto * Copyright (c) 2006 Frank Kardel
3454359Sroberto * All rights reserved.
3554359Sroberto *
3654359Sroberto * Redistribution and use in source and binary forms, with or without
37132451Sroberto * modification, are permitted provided that the following conditions
3854359Sroberto * are met:
3954359Sroberto * 1. Redistributions of source code must retain the above copyright
4054359Sroberto *    notice, this list of conditions and the following disclaimer.
4154359Sroberto * 2. Redistributions in binary form must reproduce the above copyright
4254359Sroberto *    notice, this list of conditions and the following disclaimer in the
4354359Sroberto *    documentation and/or other materials provided with the distribution.
4454359Sroberto *
4554359Sroberto * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
4654359Sroberto * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
4754359Sroberto * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
4854359Sroberto * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
4954359Sroberto * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
5054359Sroberto * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
5154359Sroberto * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
5254359Sroberto * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
5354359Sroberto * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
5454359Sroberto * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
5554359Sroberto * POSSIBILITY OF SUCH DAMAGE.
5654359Sroberto */
5754359Sroberto
5854359Sroberto#include <sys/cdefs.h>
5954359Sroberto__COPYRIGHT("@(#) Copyright (c) 2008\
6054359Sroberto The NetBSD Foundation, inc. All rights reserved.");
6154359Sroberto__RCSID("$NetBSD: t_clock_gettime.c,v 1.1 2011/10/15 06:42:16 jruoho Exp $");
6254359Sroberto
6354359Sroberto#include <sys/param.h>
6454359Sroberto#include <sys/sysctl.h>
6554359Sroberto
6654359Sroberto#ifdef __NetBSD__
6754359Sroberto#include <machine/int_limits.h>
6854359Sroberto#endif
6954359Sroberto
7054359Sroberto#include <atf-c.h>
7154359Sroberto#include <errno.h>
7254359Sroberto#include <stdio.h>
7354359Sroberto#include <stdlib.h>
7454359Sroberto#include <string.h>
7554359Sroberto#include <time.h>
7654359Sroberto#include <unistd.h>
7754359Sroberto
7854359Sroberto#ifdef __NetBSD__
7954359Sroberto#include "../../../h_macros.h"
8054359Sroberto#else
81182007Sroberto#include <limits.h>
8254359Sroberto#include <stdint.h>
8354359Sroberto#include "h_macros.h"
8454359Sroberto#endif
8554359Sroberto
8654359Sroberto#define MINPOSDIFF	15000000	/* 15 ms for now */
8754359Sroberto#define TIMEOUT		5
8854359Sroberto
8954359Sroberto#define TC_HARDWARE	"kern.timecounter.hardware"
9054359Sroberto#define TC_CHOICE	"kern.timecounter.choice"
9154359Sroberto
9254359Srobertostatic void
9354359Srobertocheck_timecounter(void)
9454359Sroberto{
9554359Sroberto	struct timespec tsa, tsb, tsl, res;
9654359Sroberto	long long mindiff = INTMAX_MAX;
9754359Sroberto	time_t endlimit;
9854359Sroberto
9954359Sroberto#define CL(x) \
10054359Sroberto	do { \
10154359Sroberto		if ((x) != -1) \
10254359Sroberto			break; \
10354359Sroberto		atf_tc_fail_nonfatal("%s: %s", #x, strerror(errno)); \
10454359Sroberto		return; \
10554359Sroberto	} while (0)
10654359Sroberto
10754359Sroberto	CL(clock_gettime(CLOCK_REALTIME, &tsa));
10854359Sroberto	tsl = tsa;
10954359Sroberto
11054359Sroberto	CL(time(&endlimit));
11154359Sroberto	endlimit += TIMEOUT + 1;
11254359Sroberto
11354359Sroberto	while ((time_t)tsa.tv_sec < endlimit) {
11454359Sroberto		long long diff;
11554359Sroberto
11654359Sroberto		CL(clock_gettime(CLOCK_REALTIME, &tsb));
11754359Sroberto		diff = 1000000000LL * (tsb.tv_sec - tsa.tv_sec)
11854359Sroberto		    + tsb.tv_nsec - tsa.tv_nsec;
11954359Sroberto
12054359Sroberto		if (diff > 0 && mindiff > diff)
12154359Sroberto			mindiff = diff;
12254359Sroberto
12354359Sroberto		if (diff < 0 || diff > MINPOSDIFF) {
12454359Sroberto			long long elapsed;
12554359Sroberto			(void)printf("%stime TSA: 0x%jx.%08jx, TSB: 0x%jx.%08jx, "
12654359Sroberto			    "diff = %lld nsec, ", (diff < 0) ? "BAD " : "",
12754359Sroberto			    (uintmax_t)tsa.tv_sec, (uintmax_t)tsa.tv_nsec,
12854359Sroberto			    (uintmax_t)tsb.tv_sec, (uintmax_t)tsb.tv_nsec, diff);
12954359Sroberto
13054359Sroberto			elapsed = 1000000000LL * (tsb.tv_sec - tsl.tv_sec)
13154359Sroberto			    + tsb.tv_nsec - tsl.tv_nsec;
13254359Sroberto
13354359Sroberto
13454359Sroberto			(void)printf("%lld nsec\n", elapsed);
13554359Sroberto			tsl = tsb;
13654359Sroberto
13754359Sroberto			ATF_CHECK(diff >= 0);
13854359Sroberto			if (diff < 0)
13954359Sroberto				return;
14054359Sroberto		}
14154359Sroberto
14254359Sroberto		tsa.tv_sec = tsb.tv_sec;
14354359Sroberto		tsa.tv_nsec = tsb.tv_nsec;
14454359Sroberto	}
14554359Sroberto
14654359Sroberto	if (clock_getres(CLOCK_REALTIME, &res) == 0) {
14754359Sroberto		long long r = res.tv_sec * 1000000000 + res.tv_nsec;
14854359Sroberto
149		(void)printf("Claimed resolution: %lld nsec (%f Hz) or "
150		    "better\n", r, 1.0 / r * 1e9);
151		(void)printf("Observed minimum non zero delta: %lld "
152		    "nsec\n", mindiff);
153	}
154
155#undef CL
156}
157
158ATF_TC(clock_gettime_real);
159ATF_TC_HEAD(clock_gettime_real, tc)
160{
161	atf_tc_set_md_var(tc, "require.user", "root");
162	atf_tc_set_md_var(tc, "descr",
163	    "Checks the monotonicity of the CLOCK_REALTIME implementation");
164	atf_tc_set_md_var(tc, "timeout", "300");
165}
166
167ATF_TC_BODY(clock_gettime_real, tc)
168{
169	char name[128], cbuf[512], ctrbuf[10240];
170	size_t cbufsiz = sizeof(cbuf);
171	size_t ctrbufsiz = sizeof(ctrbuf);
172	const char *p;
173	char *save;
174	int quality, n;
175
176	if (sysctlbyname(TC_HARDWARE, cbuf, &cbufsiz, NULL, 0) != 0) {
177		(void)printf("\nChecking legacy time implementation "
178		    "for %d seconds\n", TIMEOUT);
179		check_timecounter();
180		return;
181		/* NOTREACHED */
182	}
183	(void)printf("%s = %s\n", TC_HARDWARE, cbuf);
184	REQUIRE_LIBC(save = strdup(cbuf), NULL);
185
186	RL(sysctlbyname(TC_CHOICE, ctrbuf, &ctrbufsiz, NULL, 0));
187	(void)printf("%s = %s\n", TC_CHOICE, ctrbuf);
188
189	for (p = ctrbuf, n = 0; sscanf(p, "%127[^(](q=%d, f=%*u Hz)%*[ ]%n",
190	    name, &quality, &n) == 2; p += n) {
191		struct timespec ts;
192		int ret;
193
194		if (quality < 0)
195			continue;
196
197		(void)printf("\nChecking %s for %d seconds\n", name, TIMEOUT);
198		CHECK_LIBC(ret = sysctlbyname(TC_HARDWARE, NULL, 0,
199		    name, strlen(name)), -1);
200		if (ret == -1)
201			continue;
202
203		/* wait a bit to select new counter in clockinterrupt */
204		ts.tv_sec = 0;
205		ts.tv_nsec = 100000000;
206		(void)nanosleep(&ts, NULL);
207
208		check_timecounter();
209	}
210
211	RL(sysctlbyname(TC_HARDWARE, NULL, 0, save, strlen(save)));
212}
213
214ATF_TP_ADD_TCS(tp)
215{
216
217	ATF_TP_ADD_TC(tp, clock_gettime_real);
218
219	return atf_no_error();
220}
221