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