• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  *       librttest.c
21  *
22  * DESCRIPTION
23  *      A set of commonly used convenience functions for writing
24  *      threaded realtime test cases.
25  *
26  * USAGE:
27  *       To be included in testcases.
28  *
29  * AUTHOR
30  *	Darren Hart <dvhltc@us.ibm.com>
31  *
32  * HISTORY
33  *      2006-Apr-26: Initial version by Darren Hart
34  *      2006-May-08: Added atomic_{inc,set,get}, thread struct, debug function,
35  *		      rt_init, buffered printing -- Vernon Mauery
36  *      2006-May-09: improved command line argument handling
37  *      2007-Jul-12: Added latency tracing functions and I/O helper functions
38  *					      -- Josh triplett
39  *	2008-Jan-10: Added RR thread support to tests -- Chirag Jog
40  *
41  *****************************************************************************/
42 
43 #include <librttest.h>
44 #include <libstats.h>
45 
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <signal.h>
49 #include <time.h>
50 #include <string.h>
51 #include <pthread.h>
52 #include <sched.h>
53 #include <errno.h>
54 #include <unistd.h>
55 #include <getopt.h>
56 #include <sys/prctl.h>
57 #include <sys/stat.h>
58 #include <sys/syscall.h>
59 #include <sys/types.h>
60 #include <sys/mman.h>
61 #include <fcntl.h>
62 #include <math.h>
63 
64 static LIST_HEAD(_threads);
65 static atomic_t _thread_count = { -1 };
66 
67 pthread_mutex_t _buffer_mutex;
68 char *_print_buffer = NULL;
69 int _print_buffer_offset = 0;
70 int _dbg_lvl = 0;
71 double pass_criteria;
72 
73 static int _use_pi = 1;
74 
75 /* function implementations */
rt_help(void)76 void rt_help(void)
77 {
78 	printf("librt standard options:\n");
79 	printf
80 	    ("  -b(0,1)	1:enable buffered output, 0:diable buffered output\n");
81 	printf("  -p(0,1)	0:don't use pi mutexes, 1:use pi mutexes\n");
82 	printf("  -m		use mlockall\n");
83 	printf
84 	    ("  -v[0-4]	0:no debug, 1:DBG_ERR, 2:DBG_WARN, 3:DBG_INFO, 4:DBG_DEBUG\n");
85 	printf("  -s		Enable saving stats data (default disabled)\n");
86 	printf("  -c		Set pass criteria\n");
87 }
88 
89 /* Calibrate the busy work loop */
calibrate_busyloop(void)90 void calibrate_busyloop(void)
91 {
92 	volatile int i = CALIBRATE_LOOPS;
93 	nsec_t start, end;
94 
95 	start = rt_gettime();
96 	while (--i > 0) {
97 		continue;
98 	}
99 	end = rt_gettime();
100 
101 	iters_per_us = (CALIBRATE_LOOPS * NS_PER_US) / (end - start);
102 }
103 
rt_init_long(const char * options,const struct option * longopts,int (* parse_arg)(int option,char * value),int argc,char * argv[])104 int rt_init_long(const char *options, const struct option *longopts,
105 		 int (*parse_arg) (int option, char *value), int argc,
106 		 char *argv[])
107 {
108 	const struct option *cur_opt;
109 	int use_buffer = 1;
110 	char *longopt_vals;
111 	size_t i;
112 	int c;
113 	opterr = 0;
114 	int mlock = 0;
115 	char *all_options;
116 
117 	if (asprintf(&all_options, ":b:mp:v:sc:%s", options) == -1) {
118 		fprintf(stderr,
119 			"Failed to allocate string for option string\n");
120 		exit(1);
121 	}
122 
123 	/* Check for duplicate options in optstring */
124 	for (i = 0; i < strlen(all_options); i++) {
125 		char opt = all_options[i];
126 
127 		if (opt == ':')
128 			continue;
129 
130 		/* Search ahead */
131 		if (strchr(&all_options[i + 1], opt)) {
132 			fprintf(stderr,
133 				"Programmer error -- argument -%c already used at least twice\n",
134 				opt);
135 			exit(1);
136 		}
137 	}
138 
139 	/* Ensure each long options has a known unique short option in val. */
140 	longopt_vals = "";
141 	cur_opt = longopts;
142 	while (cur_opt && cur_opt->name) {
143 		if (cur_opt->flag) {
144 			fprintf(stderr, "Programmer error -- argument --%s flag"
145 				" is non-null\n", cur_opt->name);
146 			exit(1);
147 		}
148 		if (!strchr(all_options, cur_opt->val)) {
149 			fprintf(stderr, "Programmer error -- argument --%s "
150 				"shortopt -%c wasn't listed in options (%s)\n",
151 				cur_opt->name, cur_opt->val, all_options);
152 			exit(1);
153 		}
154 		if (strchr(longopt_vals, cur_opt->val)) {
155 			fprintf(stderr, "Programmer error -- argument --%s "
156 				"shortopt -%c is used more than once\n",
157 				cur_opt->name, cur_opt->val);
158 			exit(1);
159 		}
160 		if (asprintf(&longopt_vals, "%s%c", longopt_vals, cur_opt->val)
161 		    < 0) {
162 			perror("asprintf");
163 			exit(2);
164 		}
165 		cur_opt++;
166 	}
167 
168 	while ((c = getopt_long(argc, argv, all_options, longopts, NULL)) != -1) {
169 		switch (c) {
170 		case 'c':
171 			pass_criteria = atof(optarg);
172 			break;
173 		case 'b':
174 			use_buffer = atoi(optarg);
175 			break;
176 		case 'p':
177 			_use_pi = atoi(optarg);
178 			break;
179 		case 'm':
180 			mlock = 1;
181 			break;
182 		case 'v':
183 			_dbg_lvl = atoi(optarg);
184 			break;
185 		case 's':
186 			save_stats = 1;
187 			break;
188 		case ':':
189 			if (optopt == '-')
190 				fprintf(stderr, "long option missing arg\n");
191 			else
192 				fprintf(stderr, "option -%c: missing arg\n",
193 					optopt);
194 			parse_arg('h', optarg);	/* Just to display usage */
195 			exit(1);	/* Just in case. (should normally be done by usage()) */
196 		case '?':
197 			if (optopt == '-')
198 				fprintf(stderr, "unrecognized long option\n");
199 			else
200 				fprintf(stderr, "option -%c not recognized\n",
201 					optopt);
202 			parse_arg('h', optarg);	/* Just to display usage */
203 			exit(1);	/* Just in case. (should normally be done by usage()) */
204 		default:
205 			if (parse_arg && parse_arg(c, optarg))
206 				break;	/* Application option */
207 
208 			fprintf(stderr,
209 				"Programmer error -- option -%c defined but not handled\n",
210 				c);
211 			exit(1);
212 		}
213 	}
214 	if (!_use_pi)
215 		printf
216 		    ("Priority Inheritance has been disabled for this run.\n");
217 	if (use_buffer)
218 		buffer_init();
219 	if (mlock) {
220 		if (mlockall(MCL_CURRENT | MCL_FUTURE)) {
221 			perror("failed to lock memory\n");
222 			exit(1);
223 		}
224 	}
225 
226 	calibrate_busyloop();
227 
228 	/*
229 	 * atexit() order matters here - buffer_print() will be called before
230 	 * buffer_fini().
231 	 */
232 	atexit(buffer_fini);
233 	atexit(buffer_print);
234 	return 0;
235 }
236 
rt_init(const char * options,int (* parse_arg)(int option,char * value),int argc,char * argv[])237 int rt_init(const char *options, int (*parse_arg) (int option, char *value),
238 	    int argc, char *argv[])
239 {
240 	return rt_init_long(options, NULL, parse_arg, argc, argv);
241 }
242 
buffer_init(void)243 void buffer_init(void)
244 {
245 	_print_buffer = malloc(PRINT_BUFFER_SIZE);
246 	if (!_print_buffer)
247 		fprintf(stderr,
248 			"insufficient memory for print buffer - printing directly to stderr\n");
249 	else
250 		memset(_print_buffer, 0, PRINT_BUFFER_SIZE);
251 }
252 
buffer_print(void)253 void buffer_print(void)
254 {
255 	if (_print_buffer) {
256 		fprintf(stderr, "%s", _print_buffer);
257 		memset(_print_buffer, 0, PRINT_BUFFER_SIZE);
258 		_print_buffer_offset = 0;
259 	}
260 }
261 
buffer_fini(void)262 void buffer_fini(void)
263 {
264 	if (_print_buffer)
265 		free(_print_buffer);
266 	_print_buffer = NULL;
267 }
268 
cleanup(int i)269 void cleanup(int i)
270 {
271 	printf("Test terminated with asynchronous signal\n");
272 	buffer_print();
273 	buffer_fini();
274 	if (i)
275 		exit(i);
276 }
277 
setup()278 void setup()
279 {
280 	signal(SIGINT, cleanup);
281 	signal(SIGQUIT, cleanup);
282 	signal(SIGTERM, cleanup);
283 }
284 
create_thread(void * (* func)(void *),void * arg,int prio,int policy)285 int create_thread(void *(*func) (void *), void *arg, int prio, int policy)
286 {
287 	struct sched_param param;
288 	int id, ret;
289 	struct thread *thread;
290 
291 	id = atomic_inc(&_thread_count);
292 
293 	thread = malloc(sizeof(struct thread));
294 	if (!thread)
295 		return -1;
296 
297 	list_add_tail(&thread->_threads, &_threads);
298 	pthread_cond_init(&thread->cond, NULL);	// Accept the defaults
299 	init_pi_mutex(&thread->mutex);
300 	thread->id = id;
301 	thread->priority = prio;
302 	thread->policy = policy;
303 	thread->flags = 0;
304 	thread->arg = arg;
305 	thread->func = func;
306 	param.sched_priority = prio;
307 
308 	pthread_attr_init(&thread->attr);
309 	pthread_attr_setinheritsched(&thread->attr, PTHREAD_EXPLICIT_SCHED);
310 	pthread_attr_setschedpolicy(&thread->attr, thread->policy);
311 	pthread_attr_setschedparam(&thread->attr, &param);
312 
313 	if ((ret =
314 	     pthread_create(&thread->pthread, &thread->attr, func,
315 			    (void *)thread))) {
316 		printf("pthread_create failed: %d (%s)\n", ret, strerror(ret));
317 		list_del(&thread->_threads);
318 		pthread_attr_destroy(&thread->attr);
319 		free(thread);
320 		return -1;
321 	}
322 	pthread_attr_destroy(&thread->attr);
323 
324 	return id;
325 }
326 
create_fifo_thread(void * (* func)(void *),void * arg,int prio)327 int create_fifo_thread(void *(*func) (void *), void *arg, int prio)
328 {
329 	return create_thread(func, arg, prio, SCHED_FIFO);
330 }
331 
create_rr_thread(void * (* func)(void *),void * arg,int prio)332 int create_rr_thread(void *(*func) (void *), void *arg, int prio)
333 {
334 	return create_thread(func, arg, prio, SCHED_RR);
335 }
336 
create_other_thread(void * (* func)(void *),void * arg)337 int create_other_thread(void *(*func) (void *), void *arg)
338 {
339 	return create_thread(func, arg, 0, SCHED_OTHER);
340 }
341 
set_thread_priority(pthread_t pthread,int prio)342 int set_thread_priority(pthread_t pthread, int prio)
343 {
344 	struct sched_param sched_param;
345 	sched_param.sched_priority = prio;
346 	int policy;
347 
348 	policy = (prio > 0) ? SCHED_FIFO : SCHED_OTHER;
349 
350 	return pthread_setschedparam(pthread, policy, &sched_param);
351 }
352 
set_priority(int prio)353 int set_priority(int prio)
354 {
355 	struct sched_param sp;
356 	int ret = 0;
357 
358 	sp.sched_priority = prio;
359 	if (sched_setscheduler(0, SCHED_FIFO, &sp) != 0) {
360 		perror("sched_setscheduler");
361 		ret = -1;
362 	}
363 	return ret;
364 }
365 
join_thread(int i)366 void join_thread(int i)
367 {
368 	struct thread *p, *t = NULL;
369 	list_for_each_entry(p, &_threads, _threads) {
370 		if (p->id == i) {
371 			t = p;
372 			break;
373 		}
374 	}
375 	if (t) {
376 		t->flags |= THREAD_QUIT;
377 		if (t->pthread)
378 			pthread_join(t->pthread, NULL);
379 		list_del(&t->_threads);
380 	}
381 }
382 
all_threads_quit(void)383 void all_threads_quit(void)
384 {
385 	struct thread *p;
386 	list_for_each_entry(p, &_threads, _threads) {
387 		p->flags |= THREAD_QUIT;
388 	}
389 }
390 
join_threads(void)391 void join_threads(void)
392 {
393 	all_threads_quit();
394 	struct thread *p, *t;
395 	list_for_each_entry_safe(p, t, &_threads, _threads) {
396 		if (p->pthread)
397 			pthread_join(p->pthread, NULL);
398 		list_del(&p->_threads);
399 	}
400 }
401 
get_thread(int i)402 struct thread *get_thread(int i)
403 {
404 	struct thread *p;
405 	list_for_each_entry(p, &_threads, _threads) {
406 		if (p->id == i) {
407 			return p;
408 		}
409 	}
410 	return NULL;
411 }
412 
ts_minus(struct timespec * ts_end,struct timespec * ts_start,struct timespec * ts_delta)413 void ts_minus(struct timespec *ts_end, struct timespec *ts_start,
414 	      struct timespec *ts_delta)
415 {
416 	if (ts_end == NULL || ts_start == NULL || ts_delta == NULL) {
417 		printf("ERROR in %s: one or more of the timespecs is NULL",
418 		       __FUNCTION__);
419 		return;
420 	}
421 
422 	ts_delta->tv_sec = ts_end->tv_sec - ts_start->tv_sec;
423 	ts_delta->tv_nsec = ts_end->tv_nsec - ts_start->tv_nsec;
424 	ts_normalize(ts_delta);
425 }
426 
ts_plus(struct timespec * ts_a,struct timespec * ts_b,struct timespec * ts_sum)427 void ts_plus(struct timespec *ts_a, struct timespec *ts_b,
428 	     struct timespec *ts_sum)
429 {
430 	if (ts_a == NULL || ts_b == NULL || ts_sum == NULL) {
431 		printf("ERROR in %s: one or more of the timespecs is NULL",
432 		       __FUNCTION__);
433 		return;
434 	}
435 
436 	ts_sum->tv_sec = ts_a->tv_sec + ts_b->tv_sec;
437 	ts_sum->tv_nsec = ts_a->tv_nsec + ts_b->tv_nsec;
438 	ts_normalize(ts_sum);
439 }
440 
ts_normalize(struct timespec * ts)441 void ts_normalize(struct timespec *ts)
442 {
443 	if (ts == NULL) {
444 		/* FIXME: write a real error logging system */
445 		printf("ERROR in %s: ts is NULL\n", __FUNCTION__);
446 		return;
447 	}
448 
449 	/* get the abs(nsec) < NS_PER_SEC */
450 	while (ts->tv_nsec > NS_PER_SEC) {
451 		ts->tv_sec++;
452 		ts->tv_nsec -= NS_PER_SEC;
453 	}
454 	while (ts->tv_nsec < -NS_PER_SEC) {
455 		ts->tv_sec--;
456 		ts->tv_nsec += NS_PER_SEC;
457 	}
458 
459 	/* get the values to the same polarity */
460 	if (ts->tv_sec > 0 && ts->tv_nsec < 0) {
461 		ts->tv_sec--;
462 		ts->tv_nsec += NS_PER_SEC;
463 	}
464 	if (ts->tv_sec < 0 && ts->tv_nsec > 0) {
465 		ts->tv_sec++;
466 		ts->tv_nsec -= NS_PER_SEC;
467 	}
468 }
469 
ts_to_nsec(struct timespec * ts,nsec_t * ns)470 int ts_to_nsec(struct timespec *ts, nsec_t * ns)
471 {
472 	struct timespec t;
473 	if (ts == NULL) {
474 		/* FIXME: write a real error logging system */
475 		printf("ERROR in %s: ts is NULL\n", __FUNCTION__);
476 		return -1;
477 	}
478 	t.tv_sec = ts->tv_sec;
479 	t.tv_nsec = ts->tv_nsec;
480 	ts_normalize(&t);
481 
482 	if (t.tv_sec <= 0 && t.tv_nsec < 0) {
483 		printf("ERROR in %s: ts is negative\n", __FUNCTION__);
484 		return -1;
485 	}
486 
487 	*ns = (nsec_t) ts->tv_sec * NS_PER_SEC + ts->tv_nsec;
488 	return 0;
489 }
490 
nsec_to_ts(nsec_t ns,struct timespec * ts)491 void nsec_to_ts(nsec_t ns, struct timespec *ts)
492 {
493 	if (ts == NULL) {
494 		/* FIXME: write a real error logging system */
495 		printf("ERROR in %s: ts is NULL\n", __FUNCTION__);
496 		return;
497 	}
498 	ts->tv_sec = ns / NS_PER_SEC;
499 	ts->tv_nsec = ns % NS_PER_SEC;
500 }
501 
502 /* return difference in microseconds */
tsc_minus(unsigned long long tsc_start,unsigned long long tsc_end)503 unsigned long long tsc_minus(unsigned long long tsc_start,
504 			     unsigned long long tsc_end)
505 {
506 	unsigned long long delta;
507 	if (tsc_start <= tsc_end)
508 		delta = tsc_end - tsc_start;
509 	else {
510 		delta = ULL_MAX - (tsc_end - tsc_start) + 1;
511 		printf("TSC wrapped, delta=%llu\n", delta);
512 	}
513 	return delta;
514 }
515 
rt_nanosleep_until(nsec_t ns)516 void rt_nanosleep_until(nsec_t ns)
517 {
518 	struct timespec ts_sleep, ts_rem;
519 	int rc;
520 	nsec_to_ts(ns, &ts_sleep);
521 	rc = clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &ts_sleep,
522 			     &ts_rem);
523 	/* FIXME: when should we display the remainder ? */
524 	if (rc != 0) {
525 		printf("WARNING: rt_nanosleep() returned early by %d s %d ns\n",
526 		       (int)ts_rem.tv_sec, (int)ts_rem.tv_nsec);
527 	}
528 }
529 
rt_nanosleep(nsec_t ns)530 void rt_nanosleep(nsec_t ns)
531 {
532 	struct timespec ts_sleep, ts_rem;
533 	int rc;
534 	nsec_to_ts(ns, &ts_sleep);
535 	rc = clock_nanosleep(CLOCK_MONOTONIC, 0, &ts_sleep, &ts_rem);
536 	/* FIXME: when should we display the remainder ? */
537 	if (rc != 0) {
538 		printf("WARNING: rt_nanosleep() returned early by %d s %d ns\n",
539 		       (int)ts_rem.tv_sec, (int)ts_rem.tv_nsec);
540 	}
541 }
542 
rt_gettime(void)543 nsec_t rt_gettime(void)
544 {
545 	struct timespec ts;
546 	nsec_t ns;
547 	int rc;
548 
549 	rc = clock_gettime(CLOCK_MONOTONIC, &ts);
550 	if (rc != 0) {
551 		printf("ERROR in %s: clock_gettime() returned %d\n",
552 		       __FUNCTION__, rc);
553 		perror("clock_gettime() failed");
554 		return 0;
555 	}
556 
557 	ts_to_nsec(&ts, &ns);
558 	return ns;
559 }
560 
busy_work_ms(int ms)561 void *busy_work_ms(int ms)
562 {
563 	busy_work_us(ms * US_PER_MS);
564 	return NULL;
565 }
566 
busy_work_us(int us)567 void *busy_work_us(int us)
568 {
569 	volatile int i;
570 	nsec_t start, now;
571 	int delta;		/* time in us */
572 
573 	i = us * iters_per_us;
574 
575 	start = rt_gettime();
576 	while (--i > 0) {
577 		continue;
578 	}
579 	now = rt_gettime();
580 
581 	delta = (now - start) / NS_PER_US;
582 	/* uncomment to tune to your machine */
583 	/* printf("busy_work_us requested: %dus  actual: %dus\n", us, delta); */
584 	return NULL;
585 }
586 
init_pi_mutex(pthread_mutex_t * m)587 void init_pi_mutex(pthread_mutex_t * m)
588 {
589 #if HAS_PRIORITY_INHERIT
590 	pthread_mutexattr_t attr;
591 	int ret;
592 	int protocol;
593 
594 	if ((ret = pthread_mutexattr_init(&attr)) != 0) {
595 		printf("Failed to init mutexattr: %d (%s)\n", ret,
596 		       strerror(ret));
597 	};
598 	if (_use_pi
599 	    && (ret =
600 		pthread_mutexattr_setprotocol(&attr,
601 					      PTHREAD_PRIO_INHERIT)) != 0) {
602 		printf("Can't set protocol prio inherit: %d (%s)\n", ret,
603 		       strerror(ret));
604 	}
605 	if ((ret = pthread_mutexattr_getprotocol(&attr, &protocol)) != 0) {
606 		printf("Can't get mutexattr protocol: %d (%s)\n", ret,
607 		       strerror(ret));
608 	}
609 	if ((ret = pthread_mutex_init(m, &attr)) != 0) {
610 		printf("Failed to init mutex: %d (%s)\n", ret, strerror(ret));
611 	}
612 #endif
613 
614 	/* FIXME: does any of this need to be destroyed ? */
615 }
616 
617 /* Write the entirety of data.  Complain if unable to do so. */
write_or_complain(int fd,const void * data,size_t len)618 static void write_or_complain(int fd, const void *data, size_t len)
619 {
620 	const char *remaining = data;
621 
622 	while (len > 0) {
623 		ssize_t ret = write(fd, remaining, len);
624 		if (ret <= 0) {
625 			if (errno != EAGAIN && errno != EINTR) {
626 				perror("write");
627 				return;
628 			}
629 		} else {
630 			remaining += ret;
631 			len -= ret;
632 		}
633 	}
634 }
635 
636 /* Write the given data to the existing file specified by pathname.  Complain
637  * if unable to do so. */
write_file(const char * pathname,const void * data,size_t len)638 static void write_file(const char *pathname, const void *data, size_t len)
639 {
640 	int fd = open(pathname, O_WRONLY);
641 	if (fd < 0) {
642 		printf("Failed to open file \"%s\": %d (%s)\n",
643 		       pathname, errno, strerror(errno));
644 		return;
645 	}
646 
647 	write_or_complain(fd, data, len);
648 
649 	if (close(fd) < 0) {
650 		printf("Failed to close file \"%s\": %d (%s)\n",
651 		       pathname, errno, strerror(errno));
652 	}
653 }
654 
655 /* Write the given '\0'-terminated string to the existing file specified by
656  * pathname.  Complain if unable to do so. */
write_string_to_file(const char * pathname,const char * string)657 static void write_string_to_file(const char *pathname, const char *string)
658 {
659 	write_file(pathname, string, strlen(string));
660 }
661 
read_and_print(const char * pathname,int output_fd)662 static void read_and_print(const char *pathname, int output_fd)
663 {
664 	char data[4096];
665 	int fd = open(pathname, O_RDONLY);
666 	if (fd < 0) {
667 		printf("Failed to open file \"%s\": %d (%s)\n",
668 		       pathname, errno, strerror(errno));
669 		return;
670 	}
671 
672 	while (1) {
673 		ssize_t ret = read(fd, data, sizeof(data));
674 		if (ret < 0) {
675 			if (errno != EAGAIN && errno != EINTR) {
676 				printf
677 				    ("Failed to read from file \"%s\": %d (%s)\n",
678 				     pathname, errno, strerror(errno));
679 				break;
680 			}
681 		} else if (ret == 0)
682 			break;
683 		else
684 			write_or_complain(output_fd, data, ret);
685 	}
686 
687 	if (close(fd) < 0) {
688 		printf("Failed to close file \"%s\": %d (%s)\n",
689 		       pathname, errno, strerror(errno));
690 	}
691 }
692 
latency_trace_enable(void)693 void latency_trace_enable(void)
694 {
695 	printf("Enabling latency tracer.\n");
696 	write_string_to_file("/proc/sys/kernel/trace_use_raw_cycles", "1");
697 	write_string_to_file("/proc/sys/kernel/trace_all_cpus", "1");
698 	write_string_to_file("/proc/sys/kernel/trace_enabled", "1");
699 	write_string_to_file("/proc/sys/kernel/trace_freerunning", "1");
700 	write_string_to_file("/proc/sys/kernel/trace_print_on_crash", "0");
701 	write_string_to_file("/proc/sys/kernel/trace_user_triggered", "1");
702 	write_string_to_file("/proc/sys/kernel/trace_user_trigger_irq", "-1");
703 	write_string_to_file("/proc/sys/kernel/trace_verbose", "0");
704 	write_string_to_file("/proc/sys/kernel/preempt_thresh", "0");
705 	write_string_to_file("/proc/sys/kernel/wakeup_timing", "0");
706 	write_string_to_file("/proc/sys/kernel/mcount_enabled", "1");
707 	write_string_to_file("/proc/sys/kernel/preempt_max_latency", "0");
708 }
709 
710 #ifndef PR_SET_TRACING
711 #define PR_SET_TRACING 0
712 #endif
713 
latency_trace_start(void)714 void latency_trace_start(void)
715 {
716 	if (prctl(PR_SET_TRACING, 1) < 0)
717 		perror("Failed to start tracing");
718 }
719 
latency_trace_stop(void)720 void latency_trace_stop(void)
721 {
722 	if (prctl(PR_SET_TRACING, 0) < 0)
723 		perror("Failed to stop tracing");
724 }
725 
latency_trace_print(void)726 void latency_trace_print(void)
727 {
728 	read_and_print("/proc/latency_trace", STDOUT_FILENO);
729 }
730