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