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, ¶m); 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