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