1 /******************************************************************************
2 *
3 * Copyright © International Business Machines Corp., 2006, 2008
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
13 * the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 *
19 * NAME
20 * gtod_infinite.c
21 *
22 * DESCRIPTION
23 * This 'test' is designed to run forever. It must manually be killed,
24 * so it is not ideally suited tobe part of a validation suite of tests.
25 * This test was initially designed to look for 'delays' between two
26 * calls to clock_gettime(), and helped locate SMI induced delays on
27 * several hardware platforms.
28 *
29 * As mentioned above, this test is designed to be run on a system for
30 * an unspecified period of time. It would not be unusual to let this
31 * test run for several days.
32 *
33 * During startup, the test will print out the 'maximum' delay between
34 * clock_gettime() calls. It starts with a predefined maximum of
35 * START_MAX(300ns) to eliminate noise during startup. In addition,
36 * it will print out every delay that exceeds REPORT_MIN (1000000ns).
37 *
38 * USAGE:
39 * Use run_auto.sh script in current directory to build and run test.
40 *
41 * AUTHOR
42 * Darren Hart <dvhltc@us.ibm.com>
43 *
44 * HISTORY
45 * 2006-Aug-17: Initial version by Darren Hart <dvhltc@us.ibm.com>
46 *
47 *****************************************************************************/
48
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <time.h>
52 #include <sched.h>
53 #include <librttest.h>
54 #include <sys/mman.h>
55 #include <unistd.h>
56 #include <signal.h>
57
58 #define CLOCK_TO_USE CLOCK_MONOTONIC
59
60 #define START_MAX 3000
61 #define REPORT_MIN 1000000
62
63 static unsigned int max_window = 0; /* infinite, don't use a window */
64 static unsigned int test_duration = 0; /* infinite duration */
65 static int test_stop = 0; /* 1 to stop */
66
usage(void)67 void usage(void)
68 {
69 rt_help();
70 printf("gtod_infinite specific options:\n");
71 printf
72 (" -wWINDOW iterations in max value window (default inf)\n");
73 printf(" -tDURATION test duration in finite hours (default inf)\n");
74 }
75
parse_args(int c,char * v)76 int parse_args(int c, char *v)
77 {
78 int handled = 1;
79 switch (c) {
80 case 'h':
81 usage();
82 exit(0);
83 case 'w':
84 max_window = atoi(v);
85 break;
86 case 't':
87 test_duration = atoi(v);
88 break;
89 default:
90 handled = 0;
91 break;
92 }
93 return handled;
94 }
95
alarm_handler(int sig)96 void alarm_handler(int sig)
97 {
98 /* Stop test execution */
99 test_stop = 1;
100 }
101
main(int argc,char * argv[])102 int main(int argc, char *argv[])
103 {
104 int /* i, */ rc;
105 struct timespec ts, p_ts;
106 nsec_t s_time, e_time, diff_time;
107 nsec_t max_time = START_MAX;
108 // cpu_set_t mask;
109 struct sched_param param;
110 time_t tt;
111 unsigned int wi;
112 struct sigaction sact;
113 setup();
114
115 /* Set signal handler for SIGALRM */
116 sigfillset(&sact.sa_mask);
117 sact.sa_handler = alarm_handler;
118 rc = sigaction(SIGALRM, &sact, NULL);
119 if (rc) {
120 perror("sigaction");
121 exit(1);
122 }
123 /*
124 CPU_ZERO(&mask);
125 CPU_SET(0, &mask);
126 rc = sched_setaffinity(0, sizeof(mask), &mask);
127 if (rc) {
128 perror("sched_setaffinity");
129 exit(1);
130 }
131 */
132 rt_init("hw:t:", parse_args, argc, argv);
133
134 mlockall(MCL_CURRENT | MCL_FUTURE);
135
136 if (max_window > 0) {
137 printf("%d iterations in max calculation window\n", max_window);
138 }
139
140 param.sched_priority = sched_get_priority_min(SCHED_FIFO) + 80;
141 rc = sched_setscheduler(0, SCHED_FIFO, ¶m);
142 if (rc) {
143 perror("sched_setscheduler");
144 exit(1);
145 }
146
147 rc = clock_gettime(CLOCK_TO_USE, &p_ts);
148 if (rc) {
149 perror("clock_gettime");
150 exit(1);
151 }
152
153 /* Set alarm for test duration, if specified */
154 if (test_duration > 0) {
155 rc = alarm(test_duration * 60 * 60);
156 if (rc) {
157 perror("alarm");
158 exit(1);
159 }
160 }
161
162 wi = 0;
163 while (test_stop != 1) {
164 rc = clock_gettime(CLOCK_TO_USE, &p_ts);
165 rc = clock_gettime(CLOCK_TO_USE, &ts);
166 if (rc) {
167 perror("clock_gettime");
168 exit(1);
169 }
170
171 ts_to_nsec(&p_ts, &s_time);
172 ts_to_nsec(&ts, &e_time);
173
174 diff_time = e_time - s_time;
175
176 if (max_window > 0 ||
177 ((diff_time > max_time) || (diff_time > REPORT_MIN))) {
178 if (diff_time > max_time)
179 max_time = diff_time;
180
181 if (max_window == 0 || ++wi == max_window) {
182 tt = (time_t) ts.tv_sec;
183 printf("Task delayed for %lld nsec!!! %s",
184 max_time, ctime(&tt));
185 fflush(stdout);
186
187 if (wi == max_window) {
188 max_time = 0;
189 wi = 0;
190 }
191 }
192
193 }
194 }
195
196 return 0;
197 }
198