├── Makefile.am ├── libdl ├── Makefile.am ├── dl_syscalls.c ├── Makefile.orig ├── README ├── dl_syscalls.h └── COPYING ├── doc ├── examples │ ├── merge │ │ ├── global.json │ │ ├── thread2.json │ │ ├── thread3.json │ │ ├── resources.json │ │ ├── thread1.json │ │ └── thread0.json │ ├── tutorial │ │ ├── example4.json │ │ ├── example3.json │ │ ├── example1.json │ │ ├── example2.json │ │ ├── example10.json │ │ ├── example6.json │ │ ├── example8.json │ │ ├── example11.json │ │ ├── example5.json │ │ ├── example9.json │ │ └── example7.json │ ├── cpufreq_governor_efficiency │ │ ├── calibration.json │ │ ├── calibration.sh │ │ ├── dvfs.json │ │ ├── dvfs.sh │ │ ├── README │ │ └── test.sh │ ├── custom-slice.json │ ├── template.json │ ├── spreading-tasks.json │ ├── mp3-long.json │ ├── mp3-short.json │ ├── browser-long.json │ ├── browser-short.json │ ├── video-long.json │ └── video-short.json ├── merge.py ├── workgen ├── tune_json.py └── tutorial.txt ├── autogen.sh ├── TODO ├── src ├── Makefile.am ├── rt-app_taskgroups.h ├── rt-app.h ├── rt-app_args.h ├── rt-app_parse_config.h ├── rt-app_args.c ├── rt-app_utils.h ├── rt-app_types.h ├── rt-app_utils.c └── rt-app_taskgroups.c ├── .gitignore ├── configure.ac ├── README.in └── COPYING.in /Makefile.am: -------------------------------------------------------------------------------- 1 | if SET_DLSCHED 2 | SUBDIRS = libdl src 3 | else 4 | SUBDIRS = src 5 | endif 6 | 7 | -------------------------------------------------------------------------------- /libdl/Makefile.am: -------------------------------------------------------------------------------- 1 | noinst_LIBRARIES = libdl.a 2 | libdl_a_SOURCES= dl_syscalls.c dl_syscalls.h 3 | -------------------------------------------------------------------------------- /doc/examples/merge/global.json: -------------------------------------------------------------------------------- 1 | { 2 | "global" : { 3 | "default_policy" : "SCHED_OTHER", 4 | "duration" : 5, 5 | "ftrace" : "main,task,loop,event", 6 | "gnuplot" : true, 7 | "logdir" : "/tmp/", 8 | "log_basename" : "rt-app", 9 | "lock_pages" : true, 10 | "frag" : 1 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /doc/examples/merge/thread2.json: -------------------------------------------------------------------------------- 1 | { 2 | "tasks" : { 3 | "thread2" : { 4 | "exec" : 1000, 5 | "period" : 1000, 6 | "deadline" : 1000, 7 | "lock_order" : ["wake"], 8 | "resources" : { 9 | "wake" : { "duration" : 0, "access": ["m1"] } 10 | } 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /doc/examples/merge/thread3.json: -------------------------------------------------------------------------------- 1 | { 2 | "tasks" : { 3 | "thread3" : { 4 | "exec" : 1000, 5 | "period" : 1000, 6 | "deadline" : 1000, 7 | "lock_order" : ["wake"], 8 | "resources" : { 9 | "wake" : { "duration" : 0, "access": ["m1"] } 10 | } 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | autoreconf --force --install --symlink || exit 1 4 | 5 | echo 6 | echo "----------------------------------------------------------------" 7 | echo "Initialized build system. For a common configuration please run:" 8 | echo "----------------------------------------------------------------" 9 | echo 10 | echo "./configure" 11 | echo 12 | -------------------------------------------------------------------------------- /doc/examples/merge/resources.json: -------------------------------------------------------------------------------- 1 | { 2 | "resources" : { 3 | "m0" : { "type" : "mutex" }, 4 | "sync_mutex" : { "type" : "mutex" }, 5 | "wait" : { "type" : "wait" }, 6 | "trig" : { "type" : "signal", "target" : "wait" }, 7 | "m1" : { "type" : "mutex" }, 8 | "wake" : { "type" : "wait" }, 9 | "broad" : { "type" : "broadcast", "target" : "wake" } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /doc/examples/merge/thread1.json: -------------------------------------------------------------------------------- 1 | { 2 | "tasks" : { 3 | "thread1" : { 4 | "exec" : 1000, 5 | "period" : 10000, 6 | "deadline" : 8000, 7 | "lock_order" : ["m0", "trig"], 8 | "resources" : { 9 | "m0" : { "duration" : 500 }, 10 | "trig" : { "duration" : 0, "access": ["sync_mutex"] } 11 | } 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | List of things to do for enhancing the synthetic workload generato 2 | * Use a .json file to create a file viewable on kernelshark 3 | * Use a record from trace-cmd and/or perf to generate a json file 4 | * simplify the grammar to descibe a pattern of a task 5 | * Add more details of the grammarin documentation 6 | * create different kind of busy loop : cpu intensive loop, memeory intensive 7 | * loop ... 8 | -------------------------------------------------------------------------------- /libdl/dl_syscalls.c: -------------------------------------------------------------------------------- 1 | #include "dl_syscalls.h" 2 | 3 | int sched_setattr(pid_t pid, 4 | const struct sched_attr *attr, 5 | unsigned int flags) 6 | { 7 | return syscall(__NR_sched_setattr, pid, attr, flags); 8 | } 9 | 10 | int sched_getattr(pid_t pid, 11 | struct sched_attr *attr, 12 | unsigned int size, 13 | unsigned int flags) 14 | { 15 | return syscall(__NR_sched_getattr, pid, attr, size, flags); 16 | } 17 | -------------------------------------------------------------------------------- /doc/examples/merge/thread0.json: -------------------------------------------------------------------------------- 1 | { 2 | "tasks" : { 3 | "thread0" : { 4 | "exec" : 5000, 5 | "period" : 5000, 6 | "deadline" : 5000, 7 | "lock_order" : ["wait", "m0", "broad"], 8 | "resources" : { 9 | "m0" : { "duration" : 1000 }, 10 | "wait" : { "duration" : 0, "access": ["sync_mutex"] }, 11 | "broad" : { "duration" : 0, "access": ["m1"] } 12 | } 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | ACLOCAL_AMFLAGS = -I m4 2 | AM_CPPFLAGS = -I$(srcdir)/../libdl/ 3 | bin_PROGRAMS = rt-app 4 | rt_app_SOURCES= rt-app_types.h rt-app_args.h rt-app_utils.h rt-app_utils.c rt-app_args.c rt-app.h rt-app.c 5 | rt_app_SOURCES += rt-app_parse_config.h rt-app_parse_config.c rt-app_taskgroups.h rt-app_taskgroups.c 6 | rt_app_LDADD = $(QRESLIB) 7 | if SET_DLSCHED 8 | rt_app_LDADD += ../libdl/libdl.a 9 | endif 10 | dist_bin_SCRIPTS = $(srcdir)/../doc/workgen 11 | -------------------------------------------------------------------------------- /src/rt-app_taskgroups.h: -------------------------------------------------------------------------------- 1 | #ifndef _RTAPP_TASKGROUPS_H 2 | #define _RTAPP_TASKGROUPS_H 3 | 4 | #include "rt-app_types.h" 5 | 6 | taskgroup_data_t *alloc_taskgroup(size_t size); 7 | taskgroup_data_t *find_taskgroup(char *name); 8 | void set_thread_taskgroup(thread_data_t *data, taskgroup_data_t *tg); 9 | void reset_thread_taskgroup(void); 10 | 11 | void initialize_cgroups(void); 12 | void add_cgroups(void); 13 | void remove_cgroups(void); 14 | 15 | #endif /* _RTAPP_TASKGROUPS_H */ 16 | -------------------------------------------------------------------------------- /doc/examples/tutorial/example4.json: -------------------------------------------------------------------------------- 1 | { 2 | /* 3 | * Simple use case with 2 threads that runs for 10 ms and wake up each 4 | * other until the use case is stopped with Ctrl+C 5 | */ 6 | "tasks" : { 7 | "thread0" : { 8 | "loop" : -1, 9 | "run" : 10000, 10 | "resume" : "thread1", 11 | "suspend" : "thread0" 12 | }, 13 | "thread1" : { 14 | "loop" : -1, 15 | "run" : 10000, 16 | "resume" : "thread0", 17 | "suspend" : "thread1" 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /doc/examples/cpufreq_governor_efficiency/calibration.json: -------------------------------------------------------------------------------- 1 | { 2 | "tasks" : { 3 | "thread" : { 4 | "instance" : 1, 5 | "loop" : 1, 6 | "phases" : { 7 | "run" : { 8 | "loop" : 1, 9 | "run" : 2000, 10 | }, 11 | "sleep" : { 12 | "loop" : 1, 13 | "sleep" : 2000, 14 | } 15 | } 16 | } 17 | }, 18 | "global" : { 19 | "default_policy" : "SCHED_FIFO", 20 | "calibration" : "CPU0", 21 | "lock_pages" : true, 22 | "logdir" : "./", 23 | } 24 | } 25 | 26 | -------------------------------------------------------------------------------- /doc/examples/cpufreq_governor_efficiency/calibration.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | if [ ! $1 ] ; then 6 | echo "Please input one cpu" 7 | exit 8 | fi 9 | 10 | echo performance > /sys/devices/system/cpu/cpu$1/cpufreq/scaling_governor 11 | 12 | sleep 1 13 | 14 | sed 's/"calibration" : "CPU.*",/"calibration" : "CPU'$1'",/' -i calibration.json 15 | pLoad=$(rt-app calibration.json 2>&1 |grep pLoad |sed 's/.*= \(.*\)ns.*/\1/') 16 | sed 's/"calibration" : .*,/"calibration" : '$pLoad',/' -i dvfs.json 17 | echo CPU$1\'s pLoad is $pLoad 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | COPYING 2 | Makefile 3 | Makefile.in 4 | README 5 | aclocal.m4 6 | *.txt 7 | *.swp 8 | *.patch 9 | cscope.out 10 | ID 11 | GPATH 12 | GRTAGS 13 | GTAGS 14 | TAGS.LST 15 | autom4te.cache/ 16 | build-aux/ 17 | config.log 18 | config.status 19 | configure 20 | libdl/.deps/ 21 | libdl/Makefile 22 | libdl/Makefile.in 23 | libdl/dl_syscalls.o 24 | libdl/libdl.a 25 | libtool 26 | m4/ 27 | src/.deps/ 28 | src/Makefile 29 | src/Makefile.in 30 | src/config.h 31 | src/config.h.in 32 | src/rt-app 33 | src/*.o 34 | src/*.txt 35 | src/*.swp 36 | src/stamp-h1 37 | 38 | -------------------------------------------------------------------------------- /doc/examples/tutorial/example3.json: -------------------------------------------------------------------------------- 1 | { 2 | /* 3 | * Simple use case which starts with a 10% load during 1sec (100 loops) 4 | * and then increase to 90% for the next sec (100 loops) 5 | */ 6 | "tasks" : { 7 | "thread0" : { 8 | "instance" : 12, 9 | "loop" : 1, 10 | "phases" : { 11 | "light" : { 12 | "loop" : 10, 13 | "run" : 3000, 14 | "timer" : { "ref" : "unique", "period" : 30000 } 15 | }, 16 | "heavy" : { 17 | "loop" : 10, 18 | "run" : 27000, 19 | "timer" : { "ref" : "unique", "period" : 30000 } 20 | } 21 | } 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /doc/examples/tutorial/example1.json: -------------------------------------------------------------------------------- 1 | { 2 | /* 3 | * Simple use case which creates a thread that run 2ms then sleep 8ms 4 | * until the use case is stopped with Ctrl+C 5 | */ 6 | "tasks" : { 7 | "thread0" : { 8 | "loop" : -1, 9 | "run" : 20000, 10 | "sleep" : 80000 11 | } 12 | }, 13 | "global" : { 14 | "duration" : 2, 15 | "calibration" : "CPU0", 16 | "default_policy" : "SCHED_OTHER", 17 | "pi_enabled" : false, 18 | "lock_pages" : false, 19 | "logdir" : "./", 20 | "log_basename" : "rt-app1", 21 | "ftrace" : "main,task,loop,event", 22 | "gnuplot" : true, 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /doc/examples/cpufreq_governor_efficiency/dvfs.json: -------------------------------------------------------------------------------- 1 | { 2 | "tasks" : { 3 | "thread" : { 4 | "instance" : 1, 5 | "policy" : "SCHED_FIFO", 6 | "cpus" : [1], 7 | "loop" : 10, 8 | "phases" : { 9 | "sleeping" : { 10 | "loop" : 1, 11 | "timer" : { "ref" : "tick", "period" : 1200000, } 12 | }, 13 | "running" : { 14 | "loop" : 1, 15 | "run" : 900000, 16 | } 17 | } 18 | } 19 | }, 20 | "global" : { 21 | "default_policy" : "SCHED_OTHER", 22 | "calibration" : 128, 23 | "lock_pages" : true, 24 | "logdir" : "./", 25 | "log_size" : 2, 26 | } 27 | } 28 | 29 | -------------------------------------------------------------------------------- /doc/examples/tutorial/example2.json: -------------------------------------------------------------------------------- 1 | { 2 | /* 3 | * Simple use case which creates 10% load 4 | * until the use case is stopped with Ctrl+C 5 | */ 6 | "tasks" : { 7 | "thread0" : { 8 | "instance" : 1, 9 | "loop" : -1, 10 | "run" : 10000, 11 | "timer" : { "ref" : "unique", "period" : 100000 } 12 | } 13 | }, 14 | "global" : { 15 | "duration" : 2, 16 | "calibration" : "CPU0", 17 | "default_policy" : "SCHED_OTHER", 18 | "pi_enabled" : false, 19 | "lock_pages" : false, 20 | "logdir" : "./", 21 | "log_basename" : "rt-app2", 22 | "ftrace" : "main,task,loop,event", 23 | "gnuplot" : true 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /doc/examples/tutorial/example10.json: -------------------------------------------------------------------------------- 1 | { 2 | /* 3 | * Use case which creates a thread that runs 2ms then sleep 8ms 4 | * in taskgroup /tg1. The use case runs for 2secs or until it 5 | * is stopped with Ctrl+C. 6 | */ 7 | "tasks" : { 8 | "thread0" : { 9 | "loop" : -1, 10 | "run" : 20000, 11 | "sleep" : 80000, 12 | "taskgroup" : "/tg1" 13 | } 14 | }, 15 | "global" : { 16 | "duration" : 2, 17 | "calibration" : "CPU0", 18 | "default_policy" : "SCHED_OTHER", 19 | "pi_enabled" : false, 20 | "lock_pages" : false, 21 | "logdir" : "./", 22 | "log_basename" : "rt-app1", 23 | "ftrace" : "main,task,loop,event", 24 | "gnuplot" : true 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /doc/examples/tutorial/example6.json: -------------------------------------------------------------------------------- 1 | { 2 | /* 3 | * Simple use case which creates CPU-, memory-, 4 | * and IO-bouned load for 2 seconds duration. 5 | */ 6 | "tasks" : { 7 | "thread0" : { 8 | "instance" : 1, 9 | "loop" : -1, 10 | "run" : 1000, 11 | "mem" : 1000, 12 | "sleep" : 5000, 13 | "iorun" : 100000 14 | } 15 | }, 16 | "global" : { 17 | "duration" : 2, 18 | "calibration" : "CPU0", 19 | "default_policy" : "SCHED_OTHER", 20 | "pi_enabled" : false, 21 | "lock_pages" : false, 22 | "logdir" : "./", 23 | "log_basename" : "rt-app2", 24 | "ftrace" : "main,task,loop,event", 25 | "gnuplot" : true, 26 | "io_device" : "/dev/null", 27 | "mem_buffer_size" : 1048576 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /doc/examples/custom-slice.json: -------------------------------------------------------------------------------- 1 | { 2 | /* 3 | * Simple use case setting the custom slice value on a SCHED_OTHER 4 | * task (thread0) via the runtime parameter. This runs alongside a 5 | * SCHED_DEADLINE task with its own sched_runtime value. 6 | * The workload runs for 2s until the use case is stopped with Ctrl+C 7 | */ 8 | "tasks" : { 9 | "thread0" : { 10 | "loop" : -1, 11 | "run" : 20000, 12 | "policy" : "SCHED_OTHER", 13 | "priority" : -19, /* This is actually the NICE value */ 14 | "dl-runtime" : 100000 15 | }, 16 | "thread1" : { 17 | "loop" : -1, 18 | "run" : 20000, 19 | "policy" : "SCHED_DEADLINE", 20 | "dl-runtime" : 200000 21 | } 22 | }, 23 | "global" : { 24 | "duration" : 2, 25 | "calibration" : "CPU0", 26 | "pi_enabled" : false, 27 | "lock_pages" : false, 28 | "logdir" : "./", 29 | "log_basename" : "rt-app1", 30 | "ftrace" : "main,task,loop,event", 31 | "gnuplot" : true, 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /doc/merge.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import os 4 | import sys 5 | import getopt 6 | import json 7 | 8 | outfile = "merged.json" 9 | 10 | try: 11 | opts, args = getopt.getopt(sys.argv[1:], "o:") 12 | 13 | except getopt.GetoptError as err: 14 | print str(err) # will print something like "option -a not recognized" 15 | sys.exit(2) 16 | for o, a in opts: 17 | if o == "-o": 18 | outfile = a 19 | 20 | merged = dict() 21 | for f in args: 22 | if not os.path.exists(f): 23 | print "WARN: %s does not exist", f 24 | 25 | fp = open(f, "r") 26 | d = json.load(fp) 27 | fp.close() 28 | 29 | for key in d: 30 | print key, 31 | if merged.has_key(key): 32 | print "WARNING: merged already has key", key 33 | merged[key].update(d[key]) 34 | else: 35 | merged[key] = d[key] 36 | 37 | print merged 38 | print 39 | 40 | fp = open(outfile, "w") 41 | json.dump(merged, fp, indent=4, sort_keys=True) 42 | fp.close() 43 | -------------------------------------------------------------------------------- /doc/examples/tutorial/example8.json: -------------------------------------------------------------------------------- 1 | { 2 | /* 3 | * Simple use case which creates a thread with 3 phases each running for 4 | * 1.5ms. In phase 1 the thread will be affined to CPU 0, in phase 2 it 5 | * will be affined to CPU 1 and in the third phase it will be affined to 6 | * CPUs 2 (inherit from "cpus" at task level). 7 | */ 8 | "tasks" : { 9 | "thread0" : { 10 | "cpus" : [2], 11 | "phases" : { 12 | "phase1" : { 13 | "cpus" : [0], 14 | "loop" : 1, 15 | "run" : 1500 16 | }, 17 | "phase2" : { 18 | "cpus" : [1], 19 | "loop" : 1, 20 | "run" : 1500 21 | }, 22 | "phase3" : { 23 | "loop" : 1, 24 | "run" : 1500 25 | } 26 | } 27 | } 28 | }, 29 | "global" : { 30 | "duration" : 2, 31 | "calibration" : "CPU0", 32 | "default_policy" : "SCHED_OTHER", 33 | "pi_enabled" : false, 34 | "lock_pages" : false, 35 | "logdir" : "./", 36 | "log_basename" : "rt-app1", 37 | "ftrace" : "main,task,loop,event", 38 | "gnuplot" : true 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/rt-app.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of rt-app - https://launchpad.net/rt-app 3 | Copyright (C) 2010 Giacomo Bagnoli 4 | Copyright (C) 2014 Juri Lelli 5 | Copyright (C) 2014 Vincent Guittot 6 | 7 | This program is free software; you can redistribute it and/or 8 | modify it under the terms of the GNU General Public License 9 | as published by the Free Software Foundation; either version 2 10 | of the License, or (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 | */ 21 | 22 | #ifndef _RT_APP_H_ 23 | #define _RT_APP_H_ 24 | 25 | void *thread_body(void *arg); 26 | 27 | #endif /* _RT_APP_H_ */ 28 | 29 | -------------------------------------------------------------------------------- /doc/examples/template.json: -------------------------------------------------------------------------------- 1 | { 2 | /* 3 | * Simple use case which creates 10% load 4 | * for 6 seconds. 5 | * A "sleep" : 0 has been added so the file can be used by tune_json.py to 6 | * use a sleep event instead of the timer. In this latter case, you need 7 | * to set the timer's period to 0 8 | */ 9 | "tasks" : { 10 | /* no 'loop' value at task level means loop indefinitely (-1) */ 11 | "thread0" : { 12 | "instance" : 1, /* number of threads to be created */ 13 | "loop" : -1, /* loop forever (see 'duration' below) */ 14 | 15 | "run" : 10000, /* create load [us]: when awaken, 16 | execute `floor (10000*1000 / pLoad[ns])` loops */ 17 | 18 | "sleep" : 0, /* sleep 0s - which is somewhat useless */ 19 | 20 | "timer" : { "ref" : "unique", "period" : 100000 } 21 | /* wake up thread every 100000 us */ 22 | } 23 | }, 24 | "global" : { 25 | "duration" : 6, /* run for a maximum of 6s total */ 26 | "calibration" : "CPU0", /* calibrate on CPU0 */ 27 | "default_policy" : "SCHED_OTHER", 28 | "pi_enabled" : false, 29 | "lock_pages" : false, 30 | "logdir" : "./", 31 | "log_basename" : "rt-app2", 32 | "gnuplot" : true 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /doc/examples/cpufreq_governor_efficiency/dvfs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # $1 $2 $3 $4 $5: governor cpu run sleep loops 4 | set -e 5 | 6 | echo $1 > /sys/devices/system/cpu/cpu$2/cpufreq/scaling_governor 7 | #echo $1 > /sys/devices/system/cpu/cpu1/cpufreq/scaling_governor 8 | sed 's/"cpus" : \[.*\],/"cpus" : \['$2'\],/' -i dvfs.json 9 | 10 | if [ $3 ] ; then 11 | sed 's/"run" : .*,/"run" : '$3',/' -i dvfs.json 12 | fi 13 | 14 | if [ $4 ] ; then 15 | sed 's/"period" : .*,/"period" : '$4',/' -i dvfs.json 16 | fi 17 | 18 | if [ $5 ] ; then 19 | sed '0,/"loop"/s/"loop" : .*,/"loop" : '$5',/' -i dvfs.json 20 | fi 21 | 22 | sync 23 | 24 | sleep 1 25 | 26 | rt-app dvfs.json 2> /dev/null 27 | 28 | if [ $1 ] ; then 29 | 30 | mv -f rt-app-thread-0.log rt-app_$1_run$3us_sleep$4us.log 31 | 32 | sum=0 33 | loop=0 34 | overrun=0 35 | for i in $(cat rt-app_$1_run$3us_sleep$4us.log | sed '1d;n;d' | sed '1d' | awk '{print $3}'); do 36 | loop=$(($loop + 1)) 37 | sum=$(($sum + $i)) 38 | if [ $4 -le $i ] ; then 39 | #echo $i"vs"$4 40 | overrun=$(($overrun + 1)) 41 | fi 42 | done 43 | 44 | sum=$(($sum / $loop)) 45 | echo $sum" "$overrun 46 | #rm -f rt-app_$1_run$3us_sleep$4us.log 47 | fi 48 | 49 | -------------------------------------------------------------------------------- /doc/examples/tutorial/example11.json: -------------------------------------------------------------------------------- 1 | { 2 | /* 3 | * Use case which creates a thread with 3 phases. In each phase the thread 4 | * runs for 2ms and then sleeps for 8ms. In phase0 the thread runs in 5 | * taskgroup /tg1/tg11. Phase1 does not specify a taskgroup so the thread 6 | * will continue to run in taskgroup /tg1/tg11. In phase2 the thread will 7 | * run in taskgroup / (the root taskgroup). The use case runs for 2secs or 8 | * until it is stopped with Ctrl+C. 9 | */ 10 | "tasks" : { 11 | "thread0" : { 12 | "loop" : -1, 13 | "phases" : { 14 | "phase0" : { 15 | "run" : 20000, 16 | "sleep" : 80000, 17 | "taskgroup" : "/tg1/tg11" 18 | }, 19 | "phase1" : { 20 | "run" : 20000, 21 | "sleep" : 80000 22 | }, 23 | "phase2" : { 24 | "run" : 20000, 25 | "sleep" : 80000, 26 | "taskgroup" : "/" 27 | } 28 | } 29 | } 30 | }, 31 | "global" : { 32 | "duration" : 2, 33 | "calibration" : "CPU0", 34 | "default_policy" : "SCHED_OTHER", 35 | "pi_enabled" : false, 36 | "lock_pages" : false, 37 | "logdir" : "./", 38 | "log_basename" : "rt-app1", 39 | "ftrace" : "main,task,loop,event", 40 | "gnuplot" : true 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /doc/examples/tutorial/example5.json: -------------------------------------------------------------------------------- 1 | { 2 | /* This example doesn't care of unique id constraint imposed for json 3 | * file and multiplies the used of the same key id at same object's level. 4 | * Removing this constraint makes the json file more readable and easier 5 | * to create. This file can't be used directly with rt-app but can be used 6 | * with workgen which parses and modifies it to match with json requirement 7 | */ 8 | "tasks": { 9 | "thread0": { 10 | "instance" : 1, 11 | "priority": -19, 12 | "cpus": [ 0 ], 13 | "loop" : 1, 14 | "phases" : { 15 | "p0" : { 16 | "sleep" : 10000, 17 | }, 18 | "p1" : { 19 | "loop" : 8, 20 | "lock": "mutex", 21 | "run" : 10000, 22 | "signal": "queue", 23 | "run" : 10000, 24 | "unlock": "mutex", 25 | "run": 100000, 26 | "resume" : "thread1", 27 | "timer": { "ref" : "tick", "period" : 200000} 28 | } 29 | } 30 | }, 31 | "thread1": { 32 | "priority": -19, 33 | "cpus": [ 1 ], 34 | "loop" : 3, 35 | "lock": "mutex", 36 | "wait": { "ref": "queue", "mutex": "mutex" }, 37 | "unlock": "mutex", 38 | "run": 10000, 39 | "suspend" : "thread1", 40 | "run": 10000, 41 | "suspend" : "thread1", 42 | "run": 10000 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/rt-app_args.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of rt-app - https://launchpad.net/rt-app 3 | Copyright (C) 2010 Giacomo Bagnoli 4 | Copyright (C) 2014 Juri Lelli 5 | Copyright (C) 2014 Vincent Guittot 6 | 7 | This program is free software; you can redistribute it and/or 8 | modify it under the terms of the GNU General Public License 9 | as published by the Free Software Foundation; either version 2 10 | of the License, or (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 | */ 21 | 22 | #ifndef _RTAPP_ARGS_H_ 23 | #define _RTAPP_ARGS_H_ 24 | 25 | #include "rt-app_types.h" 26 | 27 | void 28 | usage (const char* msg, int ex_code); 29 | 30 | void 31 | parse_command_line(int argc, char **argv, rtapp_options_t *opts); 32 | 33 | #endif // _RTAPP_ARGS_H_ 34 | -------------------------------------------------------------------------------- /src/rt-app_parse_config.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of rt-app - https://launchpad.net/rt-app 3 | Copyright (C) 2010 Giacomo Bagnoli 4 | Copyright (C) 2014 Juri Lelli 5 | Copyright (C) 2014 Vincent Guittot 6 | 7 | This program is free software; you can redistribute it and/or 8 | modify it under the terms of the GNU General Public License 9 | as published by the Free Software Foundation; either version 2 10 | of the License, or (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 | */ 21 | 22 | #ifndef _RTAPP_PARSE_CONFIG_H 23 | #define _RTAPP_PARSE_CONFIG_H 24 | 25 | #include "rt-app_types.h" 26 | 27 | void 28 | parse_config(const char *filename, rtapp_options_t *opts); 29 | void 30 | parse_config_stdin(rtapp_options_t *opts); 31 | 32 | #endif // _RTAPP_PARSE_CONFIG_H 33 | -------------------------------------------------------------------------------- /libdl/Makefile.orig: -------------------------------------------------------------------------------- 1 | # go on and adjust here if you don't like those flags 2 | CFLAGS=-Os -s -pipe -DDEBUG 3 | #CFLAGS=-Wall -Os -fomit-frame-pointer -s -pipe -DDEBUG 4 | CC=$(CROSS_COMPILE)gcc 5 | # likewise, if you want to change the destination prefix 6 | DESTPREFIX=/usr/local 7 | DESTDIR=lib 8 | TARGET=libdl 9 | DOCS=COPYING README 10 | RELEASE=$(shell basename `pwd`) 11 | 12 | all: static shared 13 | 14 | clean: 15 | rm -f *.o $(TARGET).so* $(TARGET).a 16 | 17 | distclean: clean 18 | rm -f *~ *.s 19 | 20 | install: all 21 | install -d $(DESTPREFIX)/$(DESTDIR) 22 | install -c $(TARGET) $(DESTPREFIX)/$(DESTDIR) 23 | 24 | install-doc: 25 | install -d $(DESTPREFIX)/share/doc/libdl 26 | install -c $(DOCS) $(DESTPREFIX)/share/doc/libdl 27 | 28 | release: distclean release_gz release_bz2 29 | @echo --- $(RELEASE) released --- 30 | 31 | release_gz: distclean 32 | @echo Building tar.gz 33 | ( cd .. ; tar czf $(RELEASE).tar.gz $(RELEASE) ) 34 | 35 | release_bz2: distclean 36 | @echo Building tar.bz2 37 | ( cd .. ; tar cjf $(RELEASE).tar.bz2 $(RELEASE) ) 38 | 39 | static: $(TARGET).o 40 | $(AR) rcs $(TARGET).a $(TARGET).o 41 | 42 | shared: $(TARGET).o 43 | $(CC) -shared -Wl,-soname,$(TARGET).so.1 -o $(TARGET).so.1.0.0 $(TARGET).o 44 | 45 | $(TARGET).o: dl_syscalls.h dl_syscalls.c 46 | $(CC) -fPIC $(CFLAGS) -c dl_syscalls.c -o $(TARGET).o 47 | 48 | -------------------------------------------------------------------------------- /doc/examples/tutorial/example9.json: -------------------------------------------------------------------------------- 1 | { 2 | /* 3 | * A simple example on using fork event. 4 | * 5 | * thread3 will fork thread1 and thread2 in each of its phases. 6 | * Note that thread2 will NOT be instantiated at start time and 7 | * will only run when thread3 forks it. Unlike thread1 which will 8 | * run at the start - since default value of instance property is 9 | * 1 - and will run again when thread3 forks ie: twice in total. 10 | */ 11 | "tasks" : { 12 | "thread1" : { 13 | "phases" : { 14 | "phase1" : { 15 | "run" : 10000, 16 | "sleep" : 10000 17 | } 18 | } 19 | }, 20 | "thread2" : { 21 | "instance": 0, 22 | "phases" : { 23 | "phase1" : { 24 | "run" : 20000, 25 | "sleep" : 20000 26 | } 27 | } 28 | }, 29 | "thread3" : { 30 | "phases" : { 31 | "phase1" : { 32 | "fork": "thread1", 33 | "run" : 10000, 34 | "sleep" : 10000 35 | }, 36 | "phase2" : { 37 | "fork": "thread2", 38 | "run" : 20000, 39 | "sleep" : 20000 40 | } 41 | }, 42 | "loop": 1 43 | } 44 | }, 45 | "global" : { 46 | "duration" : 2, 47 | "calibration" : "CPU0", 48 | "default_policy" : "SCHED_OTHER", 49 | "pi_enabled" : false, 50 | "lock_pages" : false, 51 | "logdir" : "./", 52 | "log_basename" : "rt-app1", 53 | "ftrace" : "none", 54 | "gnuplot" : false 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /doc/examples/spreading-tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "tasks" : { 3 | "thread1" : { 4 | "instance" : 1, 5 | "loop" : -1, 6 | "phases" : { 7 | "light" : { 8 | "loop" : 300, 9 | "run" : 1000, 10 | "timer" : { "ref" : "unique", "period" : 10000 } 11 | }, 12 | "heavy" : { 13 | "loop" : 300, 14 | "run" : 7000, 15 | "timer" : { "ref" : "unique", "period" : 10000 } 16 | } 17 | } 18 | }, 19 | "thread2" : { 20 | "instance" : 1, 21 | "loop" : -1, 22 | "phases" : { 23 | "light1" : { 24 | "loop" : 900, 25 | "run" : 1000, 26 | "timer" : { "ref" : "unique", "period" : 10000 } 27 | }, 28 | "heavy1" : { 29 | "loop" : 600, 30 | "run" : 7000, 31 | "timer" : { "ref" : "unique", "period" : 10000 } 32 | }, 33 | "light2" : { 34 | "loop" : 300, 35 | "run" : 1000, 36 | "timer" : { "ref" : "unique", "period" : 10000 } 37 | }, 38 | "heavy1" : { 39 | "loop" : 600, 40 | "run" : 7000, 41 | "timer" : { "ref" : "unique", "period" : 10000 } 42 | }, 43 | } 44 | } 45 | }, 46 | "global" : { 47 | "duration" : 60, 48 | "default_policy" : "SCHED_OTHER", 49 | "calibration" : "CPU0" 50 | } 51 | } 52 | 53 | -------------------------------------------------------------------------------- /libdl/README: -------------------------------------------------------------------------------- 1 | Libdl 2 | Copyright (C) 2009-2010 Dario Faggioli 3 | Release under GPL, version 2 (see COPYING) 4 | Use at your own risk. 5 | 6 | ABOUT 7 | ----- 8 | 9 | Libdl provides what is needed to use the SCHED_DEADLINE scheduling 10 | policy and all its features from an userspace program. 11 | This is needed since the new system calls, flags, etc. that make 12 | it possible are not (yet? :-P) included in the standard library. 13 | 14 | 15 | PREREQUISITES 16 | ------------- 17 | 18 | The new interface is only implemented by kernels patched to support 19 | the SCHED_DEADLINE schedulign policy. 20 | 21 | Instructions on how to download and compile such a kernel are available 22 | on the development Website of the project: 23 | 24 | http://gitorious.org/sched_deadline/pages/Home 25 | 26 | 27 | USAGE 28 | ----- 29 | 30 | To compile the library as a static or shared object: 31 | 32 | $> make static or $> make shared or just $> make 33 | 34 | To install in the default path (/usr/local/lib): 35 | 36 | #> make install 37 | 38 | To customize the install path change DESTPREFIX and DESTDIR 39 | in the Makefile. 40 | 41 | To statically include the files in your project: 42 | - copy dl_syscalls.h and dl_syscalls.c in your header and 43 | source folder; 44 | - edit your Makefile so that targets where the new interface 45 | is used depends on dl_syscall.c; 46 | - compile and install it as usual. 47 | 48 | 49 | CONTACT 50 | ------- 51 | 52 | For bug reporting, as well as for any other comment, feel free to 53 | contact me at raistlin@linux.it. 54 | 55 | -------------------------------------------------------------------------------- /doc/examples/mp3-long.json: -------------------------------------------------------------------------------- 1 | { 2 | "tasks" : { 3 | "AudioTick" : { 4 | "priority" : -19, 5 | "loop" : -1, 6 | "cpus" : [0], 7 | "phases" : { 8 | "p1" : { 9 | "loop" : 1, 10 | "resume" : "AudioOut", 11 | "timer" : { "ref" : "tick", "period": 6000 } 12 | }, 13 | "p2" : { 14 | "loop" : 4, 15 | "timer" : { "ref" : "tick", "period": 6000 } 16 | } 17 | } 18 | }, 19 | "AudioOut" : { 20 | "priority" : -19, 21 | "loop" : -1, 22 | "run" : 275, 23 | "resume" : "AudioTrack", 24 | "run" : 4725, 25 | "suspend" : "AudioOut" 26 | }, 27 | "AudioTrack" : { 28 | "priority" : -16, 29 | "loop" : -1, 30 | "suspend" : "AudioTrack", 31 | "run" : 300, 32 | "resume" : "mp3.decoder" 33 | }, 34 | "mp3.decoder" : { 35 | "priority" : -2, 36 | "loop" : -1, 37 | "suspend" : "mp3.decoder", 38 | "run" : 1000, 39 | "lock" : "mutex", 40 | "signal" : "queue", 41 | "wait" : { "ref" : "queue", "mutex": "mutex" }, 42 | "unlock" : "mutex", 43 | "run" : 150 44 | }, 45 | "OMXCall" : { 46 | "priority" : -2, 47 | "loop" : -1, 48 | "lock" : "mutex", 49 | "wait" : { "ref" : "queue", "mutex": "mutex" }, 50 | "unlock" : "mutex", 51 | "run" : 300, 52 | "lock" : "mutex", 53 | "signal" : "queue", 54 | "unlock" : "mutex" 55 | } 56 | }, 57 | "global" : { 58 | "default_policy" : "SCHED_OTHER", 59 | "duration" : 600, 60 | "gnuplot" : false, 61 | "logdir" : "./", 62 | "log_basename" : "mp3", 63 | "lock_pages" : true, 64 | "frag" : 1, 65 | "calibration" : "CPU0" 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /doc/examples/mp3-short.json: -------------------------------------------------------------------------------- 1 | { 2 | "tasks" : { 3 | "AudioTick" : { 4 | "priority" : -19, 5 | "loop" : -1, 6 | "cpus" : [0], 7 | "phases" : { 8 | "p1" : { 9 | "loop" : 1, 10 | "resume" : "AudioOut", 11 | "timer" : { "ref" : "tick", "period": 6000 } 12 | }, 13 | "p2" : { 14 | "loop" : 4, 15 | "timer" : { "ref" : "tick", "period": 6000 } 16 | } 17 | } 18 | }, 19 | "AudioOut" : { 20 | "priority" : -19, 21 | "loop" : -1, 22 | "run" : 275, 23 | "resume" : "AudioTrack", 24 | "run" : 4725, 25 | "suspend" : "AudioOut" 26 | }, 27 | "AudioTrack" : { 28 | "priority" : -16, 29 | "loop" : -1, 30 | "suspend" : "AudioTrack", 31 | "run" : 300, 32 | "resume" : "mp3.decoder" 33 | }, 34 | "mp3.decoder" : { 35 | "priority" : -2, 36 | "loop" : -1, 37 | "suspend" : "mp3.decoder", 38 | "run" : 1000, 39 | "lock" : "mutex", 40 | "signal" : "queue", 41 | "wait" : { "ref" : "queue", "mutex": "mutex" }, 42 | "unlock" : "mutex", 43 | "run" : 150 44 | }, 45 | "OMXCall" : { 46 | "priority" : -2, 47 | "loop" : -1, 48 | "lock" : "mutex", 49 | "wait" : { "ref" : "queue", "mutex": "mutex" }, 50 | "unlock" : "mutex", 51 | "run" : 300, 52 | "lock" : "mutex", 53 | "signal" : "queue", 54 | "unlock" : "mutex" 55 | } 56 | }, 57 | "global" : { 58 | "default_policy" : "SCHED_OTHER", 59 | "duration" : 6, 60 | "gnuplot" : false, 61 | "logdir" : "./", 62 | "log_basename" : "mp3", 63 | "lock_pages" : true, 64 | "frag" : 1, 65 | "calibration" : "CPU0" 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_INIT([rt-app], [m4_esyscmd_s([git describe --tags HEAD])], [juri.lelli@arm.com, vincent.guittot@linaro.org]) 2 | AC_COPYRIGHT([Copyright (C) 2009 Giacomo Bagnoli 3 | Copyright (C) 2016 Juri Lelli 4 | Copyright (C) 2016 Vincent Guittot ]) 5 | AC_CONFIG_AUX_DIR([build-aux]) 6 | AM_INIT_AUTOMAKE([-Wall -Werror foreign dist-bzip2]) 7 | m4_pattern_allow([AM_PROG_AR]) 8 | AM_PROG_AR 9 | AC_PROG_CC 10 | AC_PROG_LIBTOOL 11 | AC_CONFIG_MACRO_DIR([m4]) 12 | AC_CONFIG_SRCDIR([src/rt-app.c]) 13 | AC_HEADER_STDC 14 | 15 | AC_CHECK_LIB([pthread], [pthread_create]) 16 | AC_CHECK_LIB([m], [round]) 17 | AC_CHECK_LIB([rt], [clock_gettime]) 18 | AC_CHECK_LIB([numa], [numa_available]) 19 | AC_CHECK_LIB([json-c], [json_object_from_file], [], [AC_MSG_ERROR([json-c libraries required])]) 20 | AC_CHECK_FUNCS(sched_setattr, [have_sched_settattr=yes], [have_sched_settattr=no]) 21 | 22 | AM_CONDITIONAL([SET_DLSCHED], [test "x$have_sched_settattr" = xno]) 23 | 24 | AC_ARG_WITH([debugfs], AS_HELP_STRING([--with-debugfs], [use debugfs for tracing])) 25 | 26 | if test "x$with_debugfs" = "xyes"; then 27 | rtapp_tracefs_path="/sys/kernel/debug/tracing" 28 | elif test "x$cross_compiling" = "xyes"; then 29 | rtapp_tracefs_path="/sys/kernel/tracing" 30 | else 31 | if test -d "/sys/kernel/debug/tracing" && ! test -d "/sys/kernel/tracing"; then 32 | rtapp_tracefs_path="/sys/kernel/debug/tracing" 33 | else 34 | rtapp_tracefs_path="/sys/kernel/tracing" 35 | fi 36 | fi 37 | AC_DEFINE_UNQUOTED([TRACEFS_PATH], ["$rtapp_tracefs_path"], [Path to tracefs directory]) 38 | 39 | AC_ARG_VAR([LOGLVL], [verbosity level, from 0 to 100. 100 is very verbose]) 40 | 41 | if test -z "${LOGLVL}";then 42 | AC_DEFINE([LOG_LEVEL], [50], [Define log message verbosity]) 43 | else 44 | AC_DEFINE_UNQUOTED([LOG_LEVEL], [${LOGLVL}]) 45 | fi 46 | 47 | AC_DEFINE([BUILD_DATE], ["m4_esyscmd_s([date +"%Y-%m-%d %H:%M:%S %Z"])"], [Build date.]) 48 | 49 | AC_CONFIG_HEADERS([src/config.h]) 50 | AC_CONFIG_FILES([Makefile src/Makefile libdl/Makefile README COPYING]) 51 | AC_OUTPUT 52 | -------------------------------------------------------------------------------- /doc/examples/tutorial/example7.json: -------------------------------------------------------------------------------- 1 | { 2 | /* Simple use case with two tasks driving each other in 3 | turn. This demonstrates that the barrier event causes 4 | tasks to be synchronized no matter which task reaches 5 | the barrier first. The sequence which should be seen is: 6 | 7 | time task0 task1 8 | 0000: run run 9 | 1000: sleep run 10 | 2000: sleep wait FIRST 11 | 3000: wait FIRST, then run wait FIRST, then run 12 | 4000: run sleep 13 | 5000: wait SECOND sleep 14 | 6000: wait SECOND, then run wait SECOND, then run 15 | 16 | (These times will not be exactly reflected when you run 17 | the example as we don't account for any scheduling effects 18 | or run/sleep time variation in the explanation) 19 | 20 | At 2000, task1 is waiting for the FIRST barrier however 21 | task0 doesn't enter this barrier until the 2000-usec 22 | sleep event completes at 3000. In this first barrier, 23 | task1 waits for task0 to reach the synchronization point. 24 | 25 | At 5000, task0 is waiting for the SECOND barrier, however 26 | task1 does not enter this barrier until the 2000-usec 27 | sleep event completes at 6000. In this second barrier, 28 | task0 waits for task1 to reach the synchronization point. 29 | */ 30 | "tasks" : { 31 | "task0" : { 32 | "loop" : -1, 33 | "runtime1" : 1000, 34 | "sleep1" : 2000, 35 | "barrier1" : "FIRST", 36 | "runtime2" : 2000, 37 | "barrier2" : "SECOND", 38 | "runtime3" : 1000, 39 | "sleep3" : 2000, 40 | "barrier3" : "THIRD", 41 | }, 42 | "task1" : { 43 | "loop" : -1, 44 | "runtime1" : 2000, 45 | "barrier1" : "FIRST", 46 | "runtime2" : 1000, 47 | "sleep2" : 2000, 48 | "barrier2" : "SECOND", 49 | "runtime3" : 2000, 50 | "barrier3" : "THIRD", 51 | }, 52 | }, 53 | "global" : { 54 | "duration" : 5, 55 | "calibration" : "CPU0", 56 | "default_policy" : "SCHED_OTHER", 57 | "pi_enabled" : false, 58 | "lock_pages" : false, 59 | "logdir" : "./", 60 | "log_basename" : "rt-app1", 61 | "ftrace" : "main,task,loop,event", 62 | "gnuplot" : false, 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /doc/examples/cpufreq_governor_efficiency/README: -------------------------------------------------------------------------------- 1 | Measure the efficiency of cpufreq governors using rt-app 2 | 3 | BACKGROUND: 4 | DVFS adds a latency in the execution of task because of the time to 5 | decide to move at max freq. We need to measure this latency and check 6 | that the governor stays in an acceptable range. 7 | 8 | When rt-app runs a json file, a log file is created for each thread. 9 | This log file records the number of loop that has been executed and 10 | the duration for executing these loops (per phase). We can use these 11 | figures to evaluate to latency that is added by a cpufreq governor 12 | and its "performance efficiency". 13 | 14 | We use the run+sleep pattern to do the measurement, for the run time per 15 | loop, the performance governor should run the expected duration as the 16 | CPU stays a max freq. At the opposite, the powersave governor will give 17 | use the longest duration (as it stays at lowest OPP). Other governor will 18 | be somewhere between the 2 previous duration as they will use several OPP 19 | and will go back to max frequency after a defined duration which depends 20 | on its monitoring period. 21 | 22 | The formula: 23 | 24 | duration of powersave gov - duration of the gov 25 | -------------------------------------------------------- x 100% 26 | duration of powersave gov - duration of performance gov 27 | 28 | will give the efficiency of the governor. 100% means as efficient as 29 | the perf governor and 0% means as efficient as the powersave governor. 30 | 31 | This test offers json files and shell scripts to do the measurement. 32 | 33 | Usage: 34 | ./calibration.sh 35 | cpu: cpu number on which you want to run the test 36 | 37 | ./test.sh [] 38 | governor: target CPUFreq governor you want to test 39 | cpu: cpu number on which you want to run the test. Be the same 40 | as the one passing to "calibration.sh". 41 | runtime: running time in ms per loop of the workload pattern 42 | sleeptime: sleeping time in ms per loop of the workload pattern 43 | loops: repeat times of the workload pattern. default: 10 44 | 45 | Example: 46 | "./calibration.sh 0" means to calculate the computing capacity of CPU0 which 47 | will be used in the following test. 48 | 49 | "./test.sh ondemand 0 100 100 20" means to 50 | test "ondemand" on CPU0 with workload pattern "run 100ms + sleep 100ms"(20 loops). 51 | 52 | NOTE: 53 | - Make sure there are "sed", "cut", "grep", "rt-app", etc tools on 54 | your test machine, and run the scripts under root privilege. 55 | 56 | - Run the test while the system is idle. 57 | 58 | - You can change the target governor's parameters after running "calibration.sh", 59 | but before "test.sh". 60 | 61 | -------------------------------------------------------------------------------- /doc/workgen: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import os 4 | import sys 5 | import getopt 6 | import subprocess 7 | import signal 8 | 9 | def check_unikid_json(infile, outfile, verbose=0): 10 | if not os.path.exists(infile): 11 | print "WARN: %s does not exist", infile 12 | 13 | try: 14 | fi = open(infile, "r") 15 | except IOError: 16 | print "WARN: Unable to open %s", infile 17 | sys.exit(2) 18 | 19 | lines = fi.readlines() 20 | fi.close() 21 | 22 | try: 23 | fo = open(outfile, "w+") 24 | except IOError: 25 | print "WARN: Unable to open %s", f 26 | sys.exit(2) 27 | 28 | curid = 1 29 | refcount = 0 30 | idlist = {} 31 | myid = [] 32 | for myline in lines: 33 | 34 | if "{" in myline: 35 | refcount +=1 36 | myid.append(curid) 37 | curid = 1 38 | idlist[refcount] = {} 39 | 40 | if "}" in myline: 41 | del idlist[refcount] 42 | curid = myid.pop() 43 | refcount -=1 44 | 45 | try: 46 | key_id, value = myline.split(":", 1) 47 | except ValueError: 48 | fo.write(myline) 49 | continue 50 | 51 | key_id = key_id.strip('\"\t\n\r ') 52 | 53 | value = value.strip(',\"\t\n\r ') 54 | 55 | if key_id in idlist[refcount]: 56 | newkey_id = key_id + str(curid) 57 | while newkey_id in idlist[refcount]: 58 | curid +=1 59 | newkey_id = key_id + str(curid) 60 | 61 | if verbose: 62 | print "level ", refcount, " : key ", key_id, " changed into ", newkey_id 63 | 64 | myline = myline.replace(key_id, newkey_id, 1) 65 | key_id = newkey_id 66 | 67 | idlist[refcount][key_id] = value 68 | 69 | fo.write(myline) 70 | 71 | fo.close() 72 | 73 | return 74 | 75 | 76 | if __name__ == '__main__': 77 | 78 | def handleSigTERM(signum, frame): 79 | sys.exit 80 | 81 | signal.signal(signal.SIGTERM, handleSigTERM) 82 | signal.signal(signal.SIGINT, handleSigTERM) 83 | 84 | outfile = "unikid.json" 85 | selfupdate = 0 86 | verbose = 0 87 | dry_run = False 88 | 89 | try: 90 | opts, args = getopt.getopt(sys.argv[1:], "o:avd") 91 | except getopt.GetoptError as err: 92 | print str(err) # will print something like "option -a not recognized" 93 | sys.exit(2) 94 | 95 | for o, a in opts: 96 | if o == "-o": 97 | outfile = a 98 | if o == "-a": 99 | selfupate = 1 100 | if o == "-v": 101 | verbose = 1 102 | if o == "-d": 103 | dry_run = True 104 | 105 | for f in args: 106 | if selfupdate: 107 | outfile = f 108 | 109 | check_unikid_json(outfile, outfile) 110 | 111 | if not dry_run: 112 | subprocess.call(["rt-app", outfile]) 113 | -------------------------------------------------------------------------------- /doc/examples/browser-long.json: -------------------------------------------------------------------------------- 1 | { 2 | "tasks" : { 3 | "BrowserMain" : { 4 | "loop" : 3, 5 | "phases" : { 6 | "start" : { 7 | "loop" : 1, 8 | "sleep" : 400000, 9 | "run" : 15000, 10 | "resume" : "Browser", 11 | "run" : 7000, 12 | "sleep" : 8000 13 | }, 14 | "render1" : { 15 | "loop" : 50, 16 | "resume" : "BrowserSub", 17 | "run" : 3000 18 | }, 19 | "render2" : { 20 | "loop" : 1, 21 | "suspend" : "Browser", 22 | "run" : 10000, 23 | "resume" : "Browser", 24 | "run" : 5000 25 | }, 26 | "render3" : { 27 | "loop" : 20, 28 | "resume" : "BrowserSub", 29 | "run" : 3000 30 | }, 31 | "stop" : { 32 | "loop" : 1, 33 | "run" : 2000, 34 | "sleep" : 200000, 35 | "suspend" : "Browser", 36 | "sleep" : 600000 37 | }, 38 | "scroll" : { 39 | "loop" : 4, 40 | "resume" : "Browser", 41 | "suspend" : "BrowserNext", 42 | "run" : 1000 43 | }, 44 | "stop2" : { 45 | "loop" : 1, 46 | "suspend" : "Browser", 47 | "run" : 200, 48 | "sleep" : 800000 49 | } 50 | } 51 | }, 52 | "BrowserSub1" : { 53 | "priority" : -6, 54 | "loop" : -1, 55 | "suspend" : "BrowserSub", 56 | "run" : 100 57 | }, 58 | "BrowserSub2" : { 59 | "priority" : -6, 60 | "loop" : -1, 61 | "suspend" : "BrowserSub", 62 | "run" : 100 63 | }, 64 | "BrowserDisplay" : { 65 | "priority" : -6, 66 | "loop" : -1, 67 | "suspend" : "Browser", 68 | "run" : 300, 69 | "resume" : "BrowserNext", 70 | "run" : 12000, 71 | "lock" : "mutex11", 72 | "sync" : { "ref" : "queue11", "mutex": "mutex11" }, 73 | "unlock" : "mutex11", 74 | "run" : 300, 75 | "resume" : "Binder-display", 76 | "run" : 400 77 | }, 78 | "Binder-dummy" : { 79 | "priority" : -6, 80 | "loop" : -1, 81 | "lock" : "mutex11", 82 | "wait" : { "ref" : "queue11", "mutex": "mutex11" }, 83 | "unlock" : "mutex11", 84 | "run" : 200, 85 | "lock" : "mutex11", 86 | "signal" : "queue11", 87 | "unlock" : "mutex11", 88 | "run" : 100 89 | }, 90 | "Binder-display" : { 91 | "priority" : -6, 92 | "loop" : -1, 93 | "suspend" : "Binder-display", 94 | "run" : 300, 95 | "resume" : "Event-Browser", 96 | "resume" : "Event-Display" 97 | }, 98 | "Event-Browser" : { 99 | "priority" : -9, 100 | "loop" : -1, 101 | "suspend" : "Event-Browser", 102 | "run" : 50, 103 | "sleep" : 16000, 104 | "run" : 50, 105 | "resume" : "Browser" 106 | }, 107 | "Event-Display" : { 108 | "priority" : -9, 109 | "loop" : -1, 110 | "suspend" : "Event-Display", 111 | "run" : 50, 112 | "sleep" : 16000, 113 | "run" : 50, 114 | "resume" : "Display" 115 | }, 116 | "Display" : { 117 | "priority" : -8, 118 | "loop" : -1, 119 | "suspend" : "Display", 120 | "run" : 16000 121 | }, 122 | }, 123 | "global" : { 124 | "default_policy" : "SCHED_OTHER", 125 | "duration" : 600, 126 | "gnuplot" : false, 127 | "logdir" : "./", 128 | "log_basename" : "web", 129 | "lock_pages" : true, 130 | "frag" : 1, 131 | "calibration" : "CPU0" 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /doc/examples/browser-short.json: -------------------------------------------------------------------------------- 1 | { 2 | "tasks" : { 3 | "BrowserMain" : { 4 | "loop" : 3, 5 | "phases" : { 6 | "start" : { 7 | "loop" : 1, 8 | "sleep" : 400000, 9 | "run" : 15000, 10 | "resume" : "Browser", 11 | "run" : 7000, 12 | "sleep" : 8000 13 | }, 14 | "render1" : { 15 | "loop" : 50, 16 | "resume" : "BrowserSub", 17 | "run" : 3000 18 | }, 19 | "render2" : { 20 | "loop" : 1, 21 | "suspend" : "Browser", 22 | "run" : 10000, 23 | "resume" : "Browser", 24 | "run" : 5000 25 | }, 26 | "render3" : { 27 | "loop" : 20, 28 | "resume" : "BrowserSub", 29 | "run" : 3000 30 | }, 31 | "stop" : { 32 | "loop" : 1, 33 | "run" : 2000, 34 | "sleep" : 200000, 35 | "suspend" : "Browser", 36 | "sleep" : 600000 37 | }, 38 | "scroll" : { 39 | "loop" : 4, 40 | "resume" : "Browser", 41 | "suspend" : "BrowserNext", 42 | "run" : 1000 43 | }, 44 | "stop2" : { 45 | "loop" : 1, 46 | "suspend" : "Browser", 47 | "run" : 200, 48 | "sleep" : 800000 49 | } 50 | } 51 | }, 52 | "BrowserSub1" : { 53 | "priority" : -6, 54 | "loop" : -1, 55 | "suspend" : "BrowserSub", 56 | "run" : 100 57 | }, 58 | "BrowserSub2" : { 59 | "priority" : -6, 60 | "loop" : -1, 61 | "suspend" : "BrowserSub", 62 | "run" : 100 63 | }, 64 | "BrowserDisplay" : { 65 | "priority" : -6, 66 | "loop" : -1, 67 | "suspend" : "Browser", 68 | "run" : 300, 69 | "resume" : "BrowserNext", 70 | "run" : 12000, 71 | "lock" : "mutex11", 72 | "sync" : { "ref" : "queue11", "mutex": "mutex11" }, 73 | "unlock" : "mutex11", 74 | "run" : 300, 75 | "resume" : "Binder-display", 76 | "run" : 400 77 | }, 78 | "Binder-dummy" : { 79 | "priority" : -6, 80 | "loop" : -1, 81 | "lock" : "mutex11", 82 | "wait" : { "ref" : "queue11", "mutex": "mutex11" }, 83 | "unlock" : "mutex11", 84 | "run" : 200, 85 | "lock" : "mutex11", 86 | "signal" : "queue11", 87 | "unlock" : "mutex11", 88 | "run" : 100 89 | }, 90 | "Binder-display" : { 91 | "priority" : -6, 92 | "loop" : -1, 93 | "suspend" : "Binder-display", 94 | "run" : 300, 95 | "resume" : "Event-Browser", 96 | "resume" : "Event-Display" 97 | }, 98 | "Event-Browser" : { 99 | "priority" : -9, 100 | "loop" : -1, 101 | "suspend" : "Event-Browser", 102 | "run" : 50, 103 | "sleep" : 16000, 104 | "run" : 50, 105 | "resume" : "Browser" 106 | }, 107 | "Event-Display" : { 108 | "priority" : -9, 109 | "loop" : -1, 110 | "suspend" : "Event-Display", 111 | "run" : 50, 112 | "sleep" : 16000, 113 | "run" : 50, 114 | "resume" : "Display" 115 | }, 116 | "Display" : { 117 | "priority" : -8, 118 | "loop" : -1, 119 | "suspend" : "Display", 120 | "run" : 16000 121 | }, 122 | }, 123 | "global" : { 124 | "default_policy" : "SCHED_OTHER", 125 | "duration" : 6, 126 | "gnuplot" : false, 127 | "logdir" : "./", 128 | "log_basename" : "web", 129 | "lock_pages" : true, 130 | "frag" : 1, 131 | "calibration" : "CPU0" 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /doc/examples/cpufreq_governor_efficiency/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | test_efficiency() { 6 | 7 | FILENAME="results_$RANDOM$$.txt" 8 | 9 | if [ -e /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors ]; then 10 | for i in $(cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors); do 11 | if [ $i = $1 ] ; then 12 | gov_target=$i 13 | fi 14 | export gov_$i=$(echo $i) 15 | done 16 | else 17 | echo "cpufreq sysfs is not available!" 18 | exit 19 | fi 20 | 21 | if [ ! $gov_target ] ; then 22 | echo " Can't find $1 governor!" 23 | exit 24 | fi 25 | 26 | if [ ! $gov_performance ] ; then 27 | echo "Can't find performance governor!" 28 | exit 29 | fi 30 | 31 | if [ ! $gov_powersave ] ; then 32 | echo "Can't find powersave governor!" 33 | exit 34 | fi 35 | 36 | if [ $gov_target = $gov_performance ] || [ $gov_target = $gov_powersave ] ; then 37 | echo "Please input a governor other than \"performance\" or \"powersave\"" 38 | exit 39 | fi 40 | 41 | # Get target gov data first 42 | dvfs.sh $1 $2 $3 $4 $5 > $FILENAME 43 | target=$(cat $FILENAME |sed -n '$p' | cut -d " " -f 1) 44 | over_target=$(cat $FILENAME |sed -n '$p' | cut -d " " -f 2) 45 | # Get performance data 46 | dvfs.sh performance $2 $3 $4 $5 > $FILENAME 47 | performance=$(cat $FILENAME |sed -n '$p' | cut -d " " -f 1) 48 | over_perf=$(cat $FILENAME |sed -n '$p' | cut -d " " -f 2) 49 | # Get powersave data 50 | dvfs.sh powersave $2 $3 $4 $5 > $FILENAME 51 | powersave=$(cat $FILENAME |sed -n '$p' | cut -d " " -f 1) 52 | over_save=$(cat $FILENAME |sed -n '$p' | cut -d " " -f 2) 53 | if [ $performance -ge $powersave ] ; then 54 | echo "powersave: $powersave" 55 | echo "performance: $performance" 56 | echo "Error! performance spent more time than powersave!" 57 | exit 58 | fi 59 | 60 | echo "\"powersave\" efficiency: 0% overrun: "$over_save 61 | echo "\"performance\" efficiency: 100% overrun: "$over_perf 62 | 63 | denominator=$(($powersave - $performance)) 64 | 65 | if [ $powersave -le $target ]; then 66 | target=0 67 | else 68 | numerator=$(($powersave - $target)) 69 | numerator=$(($numerator * 100)) 70 | target=$(($numerator / $denominator)) 71 | if [ $target -gt 100 ]; then 72 | target=100 73 | fi 74 | fi 75 | 76 | echo "\"$gov_target\" efficiency: $target% overrun: "$over_target 77 | 78 | rm -f $FILENAME 79 | } 80 | 81 | if [ $# -lt 4 ]; then 82 | echo "Usage: ./test.sh []" 83 | echo "governor: target CPUFreq governor you want to test" 84 | echo "cpu: cpu number on which you want to run the test" 85 | echo "runtime: running time in ms per loop of the workload pattern" 86 | echo "sleeptime: sleeping time in ms per loop of the workload pattern" 87 | echo "loops: repeat times of the workload pattern. default: 10" 88 | echo "\nExample:\n\"./test.sh ondemand 0 100 100 20\" means\nTest \"ondemand\" on CPU0 with workload pattern \"run 100ms + sleep 100ms\"(20 loops).\n" 89 | exit 90 | fi 91 | 92 | if [ $# = 4 ]; then 93 | loops=10 94 | else 95 | loops=$5 96 | fi 97 | 98 | echo "Test \"$1\" on CPU$2 with workload pattern \"run $3ms + sleep $4ms\"($loops loops)." 99 | 100 | sleep 1 101 | PATH=$PATH:. 102 | 103 | test_efficiency $1 $2 $(($3 * 1000)) $(($4 * 1000)) $loops 104 | 105 | -------------------------------------------------------------------------------- /libdl/dl_syscalls.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Libdl 3 | * (C) Dario Faggioli , 2009, 2010 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 version 2 of the License. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License (COPYING file) for more details. 13 | * 14 | */ 15 | 16 | #ifndef __DL_SYSCALLS__ 17 | #define __DL_SYSCALLS__ 18 | 19 | #include 20 | #define _GNU_SOURCE 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #define SCHED_DEADLINE 6 27 | 28 | /* XXX use the proper syscall numbers */ 29 | 30 | /* __NR_sched_setattr number */ 31 | #ifndef __NR_sched_setattr 32 | #ifdef __x86_64__ 33 | #define __NR_sched_setattr 314 34 | #endif 35 | 36 | #ifdef __i386__ 37 | #define __NR_sched_setattr 351 38 | #endif 39 | 40 | #ifdef __arm__ 41 | #define __NR_sched_setattr 380 42 | #endif 43 | 44 | #ifdef __aarch64__ 45 | #define __NR_sched_setattr 274 46 | #endif 47 | #endif 48 | 49 | /* __NR_sched_getattr number */ 50 | #ifndef __NR_sched_getattr 51 | #ifdef __x86_64__ 52 | #define __NR_sched_getattr 315 53 | #endif 54 | 55 | #ifdef __i386__ 56 | #define __NR_sched_getattr 352 57 | #endif 58 | 59 | #ifdef __arm__ 60 | #define __NR_sched_getattr 381 61 | #endif 62 | 63 | #ifdef __aarch64__ 64 | #define __NR_sched_getattr 275 65 | #endif 66 | #endif 67 | 68 | #define SF_SIG_RORUN 2 69 | #define SF_SIG_DMISS 4 70 | #define SF_BWRECL_DL 8 71 | #define SF_BWRECL_RT 16 72 | #define SF_BWRECL_OTH 32 73 | 74 | #define RLIMIT_DLDLINE 16 75 | #define RLIMIT_DLRTIME 17 76 | 77 | /* 78 | * For the sched_{set,get}attr() calls 79 | */ 80 | #define SCHED_FLAG_RESET_ON_FORK 0x01 81 | #define SCHED_FLAG_RECLAIM 0x02 82 | #define SCHED_FLAG_DL_OVERRUN 0x04 83 | #define SCHED_FLAG_KEEP_POLICY 0x08 84 | #define SCHED_FLAG_KEEP_PARAMS 0x10 85 | #define SCHED_FLAG_UTIL_CLAMP_MIN 0x20 86 | #define SCHED_FLAG_UTIL_CLAMP_MAX 0x40 87 | 88 | #define SCHED_FLAG_KEEP_ALL (SCHED_FLAG_KEEP_POLICY | \ 89 | SCHED_FLAG_KEEP_PARAMS) 90 | 91 | #define SCHED_FLAG_UTIL_CLAMP (SCHED_FLAG_UTIL_CLAMP_MIN | \ 92 | SCHED_FLAG_UTIL_CLAMP_MAX) 93 | 94 | #define SCHED_FLAG_ALL (SCHED_FLAG_RESET_ON_FORK | \ 95 | SCHED_FLAG_RECLAIM | \ 96 | SCHED_FLAG_DL_OVERRUN | \ 97 | SCHED_FLAG_KEEP_ALL | \ 98 | SCHED_FLAG_UTIL_CLAMP) 99 | 100 | struct sched_attr { 101 | __u32 size; 102 | 103 | __u32 sched_policy; 104 | __u64 sched_flags; 105 | 106 | /* SCHED_NORMAL, SCHED_BATCH */ 107 | __s32 sched_nice; 108 | 109 | /* SCHED_FIFO, SCHED_RR */ 110 | __u32 sched_priority; 111 | 112 | /* SCHED_DEADLINE */ 113 | __u64 sched_runtime; 114 | __u64 sched_deadline; 115 | __u64 sched_period; 116 | 117 | /* Utilization hints */ 118 | __u32 sched_util_min; 119 | __u32 sched_util_max; 120 | }; 121 | 122 | int sched_setattr(pid_t pid, 123 | const struct sched_attr *attr, 124 | unsigned int flags); 125 | 126 | int sched_getattr(pid_t pid, 127 | struct sched_attr *attr, 128 | unsigned int size, 129 | unsigned int flags); 130 | 131 | #endif /* __DL_SYSCALLS__ */ 132 | 133 | -------------------------------------------------------------------------------- /src/rt-app_args.c: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of rt-app - https://launchpad.net/rt-app 3 | Copyright (C) 2010 Giacomo Bagnoli 4 | Copyright (C) 2014 Juri Lelli 5 | Copyright (C) 2014 Vincent Guittot 6 | 7 | This program is free software; you can redistribute it and/or 8 | modify it under the terms of the GNU General Public License 9 | as published by the Free Software Foundation; either version 2 10 | of the License, or (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 | */ 21 | 22 | #define _GNU_SOURCE 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include "rt-app_parse_config.h" 30 | #include "rt-app_utils.h" 31 | 32 | char help_usage[] = \ 33 | "Usage: rt-app [-l ] \n" 34 | "Try 'rt-app --help' for more information.\n"; 35 | 36 | char help_full[] = \ 37 | "Usage:\n" 38 | " rt-app [-l ] \n" 39 | " cat taskset.json | rt-app -\n\n" 40 | "taskset.json is a json file describing the workload that will be generated" 41 | "by rt-app.\n\n" 42 | "In the first example, the json file is opened and parsed by rt-app.\n" 43 | "In the second example, rt-app reads the workload description in json format\n" 44 | "through the standard input.\n\n" 45 | "Miscellaneous:\n" 46 | " -v, --version display version information and exit\n" 47 | " -l, --log set verbosity level (10: ERROR/CRITICAL, 50: NOTICE (default)\n" 48 | " 75: INFO, 100: DEBUG)\n" 49 | " -h, --help display this help text and exit\n"; 50 | 51 | void 52 | usage(const char* msg, int ex_code) 53 | { 54 | printf("%s", help_usage); 55 | 56 | if (msg != NULL) 57 | printf("\n%s\n", msg); 58 | exit(ex_code); 59 | } 60 | 61 | struct option long_args[] = { 62 | {"help", no_argument, 0, 'h'}, 63 | {"version", no_argument, 0, 'v'}, 64 | {"log", required_argument, 0, 'l'}, 65 | {0, 0, 0, 0} 66 | }; 67 | 68 | void 69 | parse_command_line(int argc, char **argv, rtapp_options_t *opts) 70 | { 71 | struct stat config_file_stat; 72 | int c; 73 | 74 | while (1) { 75 | c = getopt_long(argc, argv, "hvl:", long_args, 0); 76 | if (c == -1) 77 | break; 78 | 79 | switch (c) { 80 | case 'h': 81 | printf("%s", help_full); 82 | exit(0); 83 | break; 84 | case 'v': 85 | printf("%s %s (%s)\n", 86 | PACKAGE, 87 | VERSION, 88 | BUILD_DATE); 89 | exit(0); 90 | break; 91 | case 'l': 92 | if (!optarg) { 93 | usage(NULL, EXIT_INV_COMMANDLINE); 94 | } else { 95 | char *endptr; 96 | long int ll = strtol(optarg, &endptr, 10); 97 | if (*endptr) { 98 | usage(NULL, EXIT_INV_COMMANDLINE); 99 | break; 100 | } 101 | log_level = ll; 102 | } 103 | break; 104 | default: 105 | usage(NULL, EXIT_INV_COMMANDLINE); 106 | break; 107 | } 108 | } 109 | 110 | if (optind >= argc) 111 | usage(NULL, EXIT_INV_COMMANDLINE); 112 | 113 | if (stat(argv[optind], &config_file_stat) == 0) 114 | parse_config(argv[optind], opts); 115 | else if (strcmp(argv[optind], "-") == 0) 116 | parse_config_stdin(opts); 117 | else 118 | usage(NULL, EXIT_FAILURE); 119 | } 120 | -------------------------------------------------------------------------------- /README.in: -------------------------------------------------------------------------------- 1 | README for rt-app @VERSION@ 2 | 3 | ============== 4 | INTRODUCTION 5 | ============== 6 | 7 | rt-app is a test application that starts multiple periodic threads in order to 8 | simulate a real-time periodic load. 9 | 10 | Code is currently maintained on GitHub: 11 | 12 | http://github.com/scheduler-tools/rt-app 13 | 14 | 15 | ============== 16 | REQUIREMENTS 17 | ============== 18 | 19 | rt-app runs on GNU/Linux. It needs bash, autoconf, automake, libtool, 20 | libjson-c, GNU make and a recent compiler (tested on: gcc) for basic features. 21 | If your system has numactl (libnuma-dev) installed, numa features will be supported. 22 | 23 | 24 | ================= 25 | BUILDING json-c 26 | ================= 27 | 28 | If you are not happy using the version installed by your packaging system, 29 | if it does not provide static libraries and you need them, need to 30 | cross-compile, build it from source like this: 31 | 32 | retrieve source code available here: 33 | 34 | https://github.com/json-c/json-c 35 | 36 | cross-compile json-c and build both static and shared libraries for aarch64: 37 | 38 | export ac_cv_func_malloc_0_nonnull=yes 39 | export ac_cv_func_realloc_0_nonnull=yes 40 | ./autogen.sh 41 | ./configure --host=aarch64-linux-gnu --enable-shared --enable-static 42 | make 43 | 44 | 45 | ================= 46 | BUILDING numactl 47 | ================= 48 | 49 | If you are not happy using the version installed by your packaging system, 50 | if it does not provide static libraries and you need them, need to 51 | cross-compile, build it from source like this: 52 | 53 | retrieve source code available here: 54 | 55 | git clone https://github.com/numactl/numactl.git 56 | 57 | cross-compile numactl and build static libraries for aarch64: 58 | 59 | ./autogen.sh 60 | ./configure --host=aarch64-linux-gnu --disable-shared --enable-static 61 | make 62 | 63 | 64 | ================================ 65 | BUILDING AND INSTALLING rt-app 66 | ================================ 67 | 68 | VARIANT A) 69 | cross-compile a static rt-app for aarch64, using your own json-c and/or numactl build 70 | ---------------------------------------------------------------------- 71 | (...that wasn't installed (or not into the standard locations)) 72 | 73 | export ac_cv_lib_json_c_json_object_from_file=yes 74 | export ac_cv_lib_numa_numa_available=yes 75 | 76 | ./autogen.sh 77 | ./configure --host=aarch64-linux-gnu LDFLAGS="-L -L" CFLAGS="-I -I" 78 | AM_LDFLAGS="-all-static" make 79 | 80 | configure supports the usual flags, like `--help` and `--prefix`, there is an 81 | install target in the Makefile as well. 82 | 83 | 84 | EXAMPLE: with a directory structure like the following: 85 | 86 | $ tree -d -L 2 87 | . 88 | ├── json-c 89 | │   ├── autoconf-archive 90 | │   ├── cmake 91 | │   ├── fuzz 92 | │   └── tests 93 | ├── numactl 94 | │   ├── m4 95 | │   └── test 96 | └── rt-app 97 | ├── doc 98 | ├── libdl 99 | └── src 100 | 101 | 102 | you would run: 103 | 104 | cd rt-app 105 | export ac_cv_lib_json_c_json_object_from_file=yes 106 | export ac_cv_lib_numa_numa_available=yes 107 | ./autogen.sh 108 | ./configure --host=aarch64-linux-gnu LDFLAGS="-L$PWD/../json-c -L$PWD/../numactl" CFLAGS="-I$PWD/../" 109 | AM_LDFLAGS="-all-static" make 110 | 111 | and you should get a static rt-app executable in the src directory. 112 | 113 | 114 | VARIANT B) 115 | regular build of rt-app for your host against json-c in canonical locations 116 | --------------------------------------------------------------------------- 117 | (and installation with PREFIX=/usr/local) 118 | 119 | ./autogen.sh 120 | ./configure 121 | make 122 | make install 123 | 124 | 125 | ======= 126 | USAGE 127 | ======= 128 | 129 | $ rt-app [-l ] 130 | 131 | where config file is a full/relative path to a json file (look under 132 | doc/examples for examples) or "-" (without quotes) to read JSON data from 133 | stdin. 134 | 135 | Refer to file doc/tutorial.txt for information about how to write the json 136 | file. 137 | -------------------------------------------------------------------------------- /src/rt-app_utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of rt-app - https://launchpad.net/rt-app 3 | Copyright (C) 2010 Giacomo Bagnoli 4 | Copyright (C) 2014 Juri Lelli 5 | Copyright (C) 2014 Vincent Guittot 6 | 7 | This program is free software; you can redistribute it and/or 8 | modify it under the terms of the GNU General Public License 9 | as published by the Free Software Foundation; either version 2 10 | of the License, or (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 | */ 21 | 22 | #ifndef _TIMESPEC_UTILS_H_ 23 | #define _TIMESPEC_UTILS_H_ 24 | 25 | #include 26 | #include 27 | 28 | #include "config.h" 29 | #include "rt-app_types.h" 30 | 31 | #ifndef LOG_PREFIX 32 | #define LOG_PREFIX "[rt-app] " 33 | #endif 34 | 35 | #define LOG_LEVEL_DEBUG 100 36 | #define LOG_LEVEL_INFO 75 37 | #define LOG_LEVEL_NOTICE 50 38 | #define LOG_LEVEL_ERROR 10 39 | #define LOG_LEVEL_CRITICAL 10 40 | 41 | #define BUF_SIZE 100 42 | 43 | extern int log_level; 44 | extern int ftrace_level; 45 | 46 | /* This prepends a string to a message */ 47 | #define rtapp_log_to(where, level, level_pfx, msg, args...) \ 48 | do { \ 49 | if (level <= log_level) { \ 50 | fprintf(where, LOG_PREFIX level_pfx msg "\n", ##args); \ 51 | } \ 52 | } while (0) 53 | 54 | #define FTRACE_NONE 0x00 55 | #define FTRACE_MAIN 0x01 56 | #define FTRACE_TASK 0x02 57 | #define FTRACE_LOOP 0x04 58 | #define FTRACE_EVENT 0x08 59 | #define FTRACE_STATS 0x10 60 | #define FTRACE_ATTRS 0x20 61 | 62 | #define log_ftrace(mark_fd, level, msg, args...) \ 63 | do { \ 64 | if (level & ftrace_level) \ 65 | ftrace_write(mark_fd, msg, ##args); \ 66 | } while (0) 67 | 68 | #define log_notice(msg, args...) \ 69 | do { \ 70 | rtapp_log_to(stderr, LOG_LEVEL_NOTICE, " ", msg, ##args); \ 71 | } while (0) 72 | 73 | #define log_info(msg, args...) \ 74 | do { \ 75 | rtapp_log_to(stderr, LOG_LEVEL_INFO, " ", msg, ##args); \ 76 | } while (0) 77 | 78 | #define log_error(msg, args...) \ 79 | do { \ 80 | rtapp_log_to(stderr, LOG_LEVEL_ERROR, " ", msg, ##args); \ 81 | } while (0) 82 | 83 | #define log_debug(msg, args...) \ 84 | do { \ 85 | rtapp_log_to(stderr, LOG_LEVEL_DEBUG, " ", msg, ##args); \ 86 | } while (0) 87 | 88 | #define log_critical(msg, args...) \ 89 | do { \ 90 | rtapp_log_to(stderr, LOG_LEVEL_CRITICAL, " ", msg, ##args); \ 91 | } while (0) 92 | 93 | unsigned long 94 | timespec_to_usec(struct timespec *ts); 95 | 96 | unsigned long long 97 | timespec_to_usec_ull(struct timespec *ts); 98 | 99 | long 100 | timespec_to_usec_long(struct timespec *ts); 101 | 102 | struct timespec 103 | usec_to_timespec(unsigned long usec); 104 | 105 | struct timespec 106 | usec_to_timespec(unsigned long usec); 107 | 108 | struct timespec 109 | msec_to_timespec(unsigned int msec); 110 | 111 | struct timespec 112 | timespec_add(struct timespec *t1, struct timespec *t2); 113 | 114 | struct timespec 115 | timespec_sub(struct timespec *t1, struct timespec *t2); 116 | 117 | int 118 | timespec_lower(struct timespec *what, struct timespec *than); 119 | 120 | int64_t 121 | timespec_sub_to_ns(struct timespec *t1, struct timespec *t2); 122 | 123 | void 124 | log_timing(FILE *handler, timing_point_t *t); 125 | 126 | pid_t 127 | gettid(void); 128 | 129 | __u64 130 | timespec_to_nsec(struct timespec *ts); 131 | 132 | char * 133 | policy_to_string(policy_t policy); 134 | 135 | int 136 | string_to_policy(const char *policy_name, policy_t *policy); 137 | 138 | int 139 | string_to_resource(const char *name, resource_t *resource); 140 | 141 | int 142 | resource_to_string(resource_t resource, char *name); 143 | 144 | int 145 | ftrace_setup(char *categories); 146 | 147 | void 148 | ftrace_write(int mark_fd, const char *fmt, ...); 149 | 150 | #endif // _TIMESPEC_UTILS_H_ 151 | 152 | /* vim: set ts=8 noexpandtab shiftwidth=8: */ 153 | -------------------------------------------------------------------------------- /doc/tune_json.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import argparse 4 | import collections 5 | import json 6 | import os 7 | import re 8 | import shutil 9 | import sys 10 | import tempfile 11 | 12 | 13 | def find_dict_by_key(doc, key): 14 | if key in doc and type(doc[key]) is collections.OrderedDict: 15 | return doc[key] 16 | 17 | for k in doc: 18 | if type(doc[k]) is collections.OrderedDict: 19 | return find_dict_by_key(doc[k], key) 20 | 21 | 22 | def dict_find_and_replace_value(dic, key, val): 23 | for k in dic: 24 | if type(dic[k]) is collections.OrderedDict: 25 | dict_find_and_replace_value(dic[k], key, val) 26 | if k == key: 27 | dic[k] = val 28 | 29 | 30 | def dict_of_loading(dic): 31 | if not 'run' in dic: 32 | return False, None 33 | 34 | for k in dic: 35 | if 'timer' in k and 'period' in dic[k]: 36 | return True, k 37 | else: 38 | return False, None 39 | 40 | 41 | def calculate_and_update_loading(dic, loading): 42 | of_loading, timer_id = dict_of_loading(dic) 43 | 44 | if of_loading: 45 | period = dic[timer_id]['period'] 46 | run = period * loading / 100 47 | dic['run'] = run 48 | 49 | for k in dic: 50 | if type(dic[k]) is collections.OrderedDict: 51 | calculate_and_update_loading(dic[k], loading) 52 | 53 | 54 | # strip comments in json file and load the file as a dict 55 | def load_json_file(filename): 56 | try: 57 | f = open(filename, 'r') 58 | except: 59 | print 'ERROR: Unable to open %s' %filename 60 | sys.exit(2) 61 | 62 | comment_re = re.compile( 63 | '(^)?[^\S\n]*/(?:\*(.*?)\*/[^\S\n]*|/[^\n]*)($)?', 64 | re.DOTALL | re.MULTILINE) 65 | 66 | content = ''.join(f.readlines()) 67 | f.close() 68 | 69 | match = comment_re.search(content) 70 | while match: 71 | content = content[:match.start()] + content[match.end():] 72 | match = comment_re.search(content) 73 | 74 | return json.JSONDecoder(object_pairs_hook=collections.OrderedDict).decode(content) 75 | 76 | 77 | def dump_json_file(doc, outfile): 78 | tmp = tempfile.NamedTemporaryFile(delete=False) 79 | json.dump(doc, tmp, indent=4, sort_keys=False) 80 | tmp.close() 81 | 82 | shutil.move(tmp.name, outfile) 83 | 84 | 85 | if __name__ == '__main__': 86 | parser = argparse.ArgumentParser() 87 | 88 | parser.add_argument('-f', '--file', dest='infile', default='', help='input json filename') 89 | parser.add_argument('-o', '--out', dest='outfile', default='workload.json', help='output json filename'); 90 | parser.add_argument('--instance', default=0, type=int, help='number of thread instance') 91 | parser.add_argument('--period', default=0, type=int, help='period of each thread/phase (us)') 92 | parser.add_argument('--run', default=0, type=int, help='run time of each thread/phase (us)') 93 | parser.add_argument('--sleep', default=0, type=int, help='sleep time of each thread/phase (us)') 94 | parser.add_argument('--loop', default=0,type=int, help='loop count of each thread/phase (-1 as infinite loop)') 95 | parser.add_argument('--loading', default=0, type=int, help='loading of each thread (%%)') 96 | parser.add_argument('--key', type=str, help='the key id of thread/phase in which the parameters will be changed') 97 | parser.add_argument('--duration', default=0, type=int, help='max duration of the use case (s)') 98 | 99 | 100 | args = parser.parse_args() 101 | 102 | if not os.path.isfile(args.infile): 103 | print 'ERROR: input file %s does not exist\n' %args.infile 104 | parser.print_help() 105 | sys.exit(2) 106 | 107 | doc = target = load_json_file(args.infile) 108 | 109 | if args.key: 110 | target = find_dict_by_key(doc, args.key) 111 | if not target: 112 | print 'ERROR: key id %s is not found' %args.key 113 | sys.exit(2) 114 | 115 | if args.instance > 0: 116 | dict_find_and_replace_value(target, 'instance', args.instance) 117 | 118 | if args.period > 0: 119 | dict_find_and_replace_value(target, 'period', args.period) 120 | 121 | if args.duration > 0: 122 | dict_find_and_replace_value(target, 'duration', args.duration) 123 | 124 | if args.run > 0: 125 | dict_find_and_replace_value(target, 'run', args.run) 126 | 127 | if args.sleep > 0: 128 | dict_find_and_replace_value(target, 'sleep', args.sleep) 129 | 130 | if args.loop > 0 or args.loop == -1: 131 | dict_find_and_replace_value(target, 'loop', args.loop) 132 | 133 | if args.loading > 0: 134 | calculate_and_update_loading(target, args.loading); 135 | 136 | dump_json_file(doc, args.outfile) 137 | -------------------------------------------------------------------------------- /doc/examples/video-long.json: -------------------------------------------------------------------------------- 1 | { 2 | "tasks" : { 3 | "surfaceflinger" : { 4 | "priority" : -7, 5 | "loop" : -1, 6 | "suspend", 7 | "run" : 1500 8 | }, 9 | 10 | "DispSync" : { 11 | "priority" : -7, 12 | "loop" : -1, 13 | "phases" : { 14 | "p1" : { 15 | "suspend", 16 | "run" : 35, 17 | "resume" : "EventThread", 18 | "run" : 40, 19 | }, 20 | 21 | "p2" : { 22 | "loop" : 2, 23 | "suspend", 24 | "run" : 30 25 | } 26 | }, 27 | }, 28 | 29 | "hwc_eventmon" : { 30 | "priority" : -19, 31 | "loop" : -1, 32 | "resume" : "DispSync", 33 | "run" : 115, 34 | "timer" : { "ref" : "timerA", "period" : 16667 } 35 | }, 36 | 37 | "EventThread1" : { 38 | "priority" : -8, 39 | "loop" : -1, 40 | "phases" : { 41 | "p1" : { 42 | "suspend" : "EventThread", 43 | "run" : 25, 44 | "resume" : "DispSync", 45 | "sleep" : 9650, 46 | "run" : 70, 47 | "resume" : "DispSync", 48 | "run" : 80 49 | }, 50 | 51 | "p2" : { 52 | "suspend" : "EventThread", 53 | "run" : 90, 54 | "resume" : "DispSync" 55 | } 56 | } 57 | }, 58 | 59 | "EventThread2" : { 60 | "priority" : -8, 61 | "loop" : -1, 62 | "phases" : { 63 | "p1" : { 64 | "suspend" : "EventThread", 65 | "run" : 30, 66 | "resume" : "surfaceflinger" 67 | }, 68 | 69 | "p2" : { 70 | "suspend" : "EventThread", 71 | "run" : 35, 72 | "sleep" : 2000, 73 | "run" : 110, 74 | "resume" : "DispSync", 75 | "run" : 60 76 | } 77 | } 78 | }, 79 | 80 | "waker" : { 81 | "priority" : -19, 82 | "loop" : -1, 83 | "resume" : "NuPlayerRenderer", 84 | "timer" : { "ref" : "timerB", "period" : 33333 } 85 | }, 86 | 87 | "NuPlayerRenderer" : { 88 | "priority" : -15, 89 | "loop" : -1, 90 | "phases" : { 91 | "p1" : { 92 | "loop" : 3, 93 | "suspend" : "NuPlayerRenderer", 94 | "run" : 140, 95 | "resume" : "NuPlayerDriver1", 96 | "run" : 95 97 | }, 98 | 99 | "p2" : { 100 | "sleep" : 27000, 101 | "run" : 580, 102 | "resume" : "NPDecoder", 103 | "resume" : "NPDecoder-CL", 104 | "resume" : "gle.aac.decoder" 105 | } 106 | } 107 | }, 108 | 109 | "NuPlayerDriver1" : { 110 | "priority" : -15, 111 | "loop" : -1, 112 | "suspend", 113 | "run" : 100, 114 | "lock" : "NuPlayerDriver", 115 | "sync" : { "ref" : "NuPlayerDriver", "mutex" : "NuPlayerDriver" }, 116 | "unlock" : "NuPlayerDriver", 117 | "run" : 50, 118 | "suspend" : "NuPlayerDriver", 119 | "run" : 80, 120 | "lock" : "NuPlayerDriver", 121 | "sync" : { "ref" : "NuPlayerDriver", "mutex" : "NuPlayerDriver" }, 122 | "unlock" : "NuPlayerDriver", 123 | "run" : 370, 124 | "lock" : "NuPlayerDriver", 125 | "sync" : { "ref" : "NuPlayerDriver", "mutex" : "NuPlayerDriver" }, 126 | "unlock" : "NuPlayerDriver", 127 | "run" : 135, 128 | "resume" : "NuPlayerDriver" 129 | }, 130 | 131 | "NuPlayerDriver2" : { 132 | "priority" : -15, 133 | "loop" : -1, 134 | "suspend" : "NuPlayerDriver", 135 | "run" : 110, 136 | "resume" : "NuPlayerDriver", 137 | "resume" : "CodecLooper1", 138 | "sleep" : 2500, 139 | "run" : 80, 140 | "lock" : "NuPlayerDriver", 141 | "sync" : { "ref" : "NuPlayerDriver", "mutex" : "NuPlayerDriver" }, 142 | "unlock" : "NuPlayerDriver", 143 | "run" : 50, 144 | "lock" : "NuPlayerDriver", 145 | "sync" : { "ref" : "NuPlayerDriver", "mutex" : "NuPlayerDriver" }, 146 | "unlock" : "NuPlayerDriver", 147 | "run" : 70, 148 | "lock" : "NuPlayerDriver", 149 | "sync" : { "ref" : "NuPlayerDriver", "mutex" : "NuPlayerDriver" }, 150 | "unlock" : "NuPlayerDriver", 151 | "run" : 35 152 | }, 153 | 154 | "CodecLooper1" : { 155 | "priority" : -15, 156 | "loop" : -1, 157 | "suspend", 158 | "run" : 230, 159 | "sleep" : 80, 160 | "run" : 150, 161 | "sleep" : 210, 162 | "run" : 330, 163 | "resume" : "CodecLooper2", 164 | "sleep" : 900, 165 | "run" : 170, 166 | "sleep" : 670, 167 | "run" : 125, 168 | "resume" : "CodecLooper2" 169 | }, 170 | 171 | "CodecLooper2" : { 172 | "priority" : -1, 173 | "loop" : -1, 174 | "suspend", 175 | "run" : 160, 176 | "resume" : "CodecLooper3", 177 | "sleep" : 590, 178 | "resume" : "OMXCallbackDisp2", 179 | "run" : 75, 180 | "suspend", 181 | "run" : 260 182 | }, 183 | 184 | "OMXCallbackDisp2" : { 185 | "priority" : -1, 186 | "loop" : -1, 187 | "suspend", 188 | "run" : 180 189 | }, 190 | 191 | "CodecLooper3" : { 192 | "priority" : -1, 193 | "loop" : -1, 194 | "suspend", 195 | "run" : 1000 196 | }, 197 | 198 | "NPDecoder" : { 199 | "priority" : -15, 200 | "loop" : -1, 201 | "suspend", 202 | "run" : 500, 203 | "sleep" : 680, 204 | "resume" : "OMXCallbackDisp1", 205 | "run" : 2000 206 | }, 207 | 208 | "NPDecoder-CL" : { 209 | "priority" : -15, 210 | "loop" : -1, 211 | "suspend", 212 | "run" : 570, 213 | "sleep" : 570, 214 | "run" : 2100 215 | }, 216 | 217 | "gle.aac.decoder" : { 218 | "priority" : -1, 219 | "loop" : -1, 220 | "suspend", 221 | "run" : 2400, 222 | "sleep" : 430, 223 | "run" : 45 224 | }, 225 | 226 | "OMXCallbackDisp1" : { 227 | "priority" : -1, 228 | "loop" : -1, 229 | "suspend", 230 | "run" : 135, 231 | "sleep" : 230, 232 | "run" : 140, 233 | "sleep" : 330, 234 | "run" : 190, 235 | "sleep" : 550, 236 | "run" : 160 237 | } 238 | }, 239 | 240 | "global" : { 241 | "default_policy" : "SCHED_OTHER", 242 | "duration" : 600, 243 | "gnuplot" : false, 244 | "logdir" : "./", 245 | "log_basename" : "video", 246 | "lock_pages" : true, 247 | "frag" : 1, 248 | "calibration" : "CPU0" 249 | } 250 | } 251 | 252 | -------------------------------------------------------------------------------- /doc/examples/video-short.json: -------------------------------------------------------------------------------- 1 | { 2 | "tasks" : { 3 | "surfaceflinger" : { 4 | "priority" : -7, 5 | "loop" : -1, 6 | "suspend", 7 | "run" : 1500 8 | }, 9 | 10 | "DispSync" : { 11 | "priority" : -7, 12 | "loop" : -1, 13 | "phases" : { 14 | "p1" : { 15 | "suspend", 16 | "run" : 35, 17 | "resume" : "EventThread", 18 | "run" : 40, 19 | }, 20 | 21 | "p2" : { 22 | "loop" : 2, 23 | "suspend", 24 | "run" : 30 25 | } 26 | }, 27 | }, 28 | 29 | "hwc_eventmon" : { 30 | "priority" : -19, 31 | "loop" : -1, 32 | "resume" : "DispSync", 33 | "run" : 115, 34 | "timer" : { "ref" : "timerA", "period" : 16667 } 35 | }, 36 | 37 | "EventThread1" : { 38 | "priority" : -8, 39 | "loop" : -1, 40 | "phases" : { 41 | "p1" : { 42 | "suspend" : "EventThread", 43 | "run" : 25, 44 | "resume" : "DispSync", 45 | "sleep" : 9650, 46 | "run" : 70, 47 | "resume" : "DispSync", 48 | "run" : 80 49 | }, 50 | 51 | "p2" : { 52 | "suspend" : "EventThread", 53 | "run" : 90, 54 | "resume" : "DispSync" 55 | } 56 | } 57 | }, 58 | 59 | "EventThread2" : { 60 | "priority" : -8, 61 | "loop" : -1, 62 | "phases" : { 63 | "p1" : { 64 | "suspend" : "EventThread", 65 | "run" : 30, 66 | "resume" : "surfaceflinger" 67 | }, 68 | 69 | "p2" : { 70 | "suspend" : "EventThread", 71 | "run" : 35, 72 | "sleep" : 2000, 73 | "run" : 110, 74 | "resume" : "DispSync", 75 | "run" : 60 76 | } 77 | } 78 | }, 79 | 80 | "waker" : { 81 | "priority" : -19, 82 | "loop" : -1, 83 | "resume" : "NuPlayerRenderer", 84 | "timer" : { "ref" : "timerB", "period" : 33333 } 85 | }, 86 | 87 | "NuPlayerRenderer" : { 88 | "priority" : -15, 89 | "loop" : -1, 90 | "phases" : { 91 | "p1" : { 92 | "loop" : 3, 93 | "suspend" : "NuPlayerRenderer", 94 | "run" : 140, 95 | "resume" : "NuPlayerDriver1", 96 | "run" : 95 97 | }, 98 | 99 | "p2" : { 100 | "sleep" : 27000, 101 | "run" : 580, 102 | "resume" : "NPDecoder", 103 | "resume" : "NPDecoder-CL", 104 | "resume" : "gle.aac.decoder" 105 | } 106 | } 107 | }, 108 | 109 | "NuPlayerDriver1" : { 110 | "priority" : -15, 111 | "loop" : -1, 112 | "suspend", 113 | "run" : 100, 114 | "lock" : "NuPlayerDriver", 115 | "sync" : { "ref" : "NuPlayerDriver", "mutex" : "NuPlayerDriver" }, 116 | "unlock" : "NuPlayerDriver", 117 | "run" : 50, 118 | "suspend" : "NuPlayerDriver", 119 | "run" : 80, 120 | "lock" : "NuPlayerDriver", 121 | "sync" : { "ref" : "NuPlayerDriver", "mutex" : "NuPlayerDriver" }, 122 | "unlock" : "NuPlayerDriver", 123 | "run" : 370, 124 | "lock" : "NuPlayerDriver", 125 | "sync" : { "ref" : "NuPlayerDriver", "mutex" : "NuPlayerDriver" }, 126 | "unlock" : "NuPlayerDriver", 127 | "run" : 135, 128 | "resume" : "NuPlayerDriver" 129 | }, 130 | 131 | "NuPlayerDriver2" : { 132 | "priority" : -15, 133 | "loop" : -1, 134 | "suspend" : "NuPlayerDriver", 135 | "run" : 110, 136 | "resume" : "NuPlayerDriver", 137 | "resume" : "CodecLooper1", 138 | "sleep" : 2500, 139 | "run" : 80, 140 | "lock" : "NuPlayerDriver", 141 | "sync" : { "ref" : "NuPlayerDriver", "mutex" : "NuPlayerDriver" }, 142 | "unlock" : "NuPlayerDriver", 143 | "run" : 50, 144 | "lock" : "NuPlayerDriver", 145 | "sync" : { "ref" : "NuPlayerDriver", "mutex" : "NuPlayerDriver" }, 146 | "unlock" : "NuPlayerDriver", 147 | "run" : 70, 148 | "lock" : "NuPlayerDriver", 149 | "sync" : { "ref" : "NuPlayerDriver", "mutex" : "NuPlayerDriver" }, 150 | "unlock" : "NuPlayerDriver", 151 | "run" : 35 152 | }, 153 | 154 | "CodecLooper1" : { 155 | "priority" : -15, 156 | "loop" : -1, 157 | "suspend", 158 | "run" : 230, 159 | "sleep" : 80, 160 | "run" : 150, 161 | "sleep" : 210, 162 | "run" : 330, 163 | "resume" : "CodecLooper2", 164 | "sleep" : 900, 165 | "run" : 170, 166 | "sleep" : 670, 167 | "run" : 125, 168 | "resume" : "CodecLooper2" 169 | }, 170 | 171 | "CodecLooper2" : { 172 | "priority" : -1, 173 | "loop" : -1, 174 | "suspend", 175 | "run" : 160, 176 | "resume" : "CodecLooper3", 177 | "sleep" : 590, 178 | "resume" : "OMXCallbackDisp2", 179 | "run" : 75, 180 | "suspend", 181 | "run" : 260 182 | }, 183 | 184 | "OMXCallbackDisp2" : { 185 | "priority" : -1, 186 | "loop" : -1, 187 | "suspend", 188 | "run" : 180 189 | }, 190 | 191 | "CodecLooper3" : { 192 | "priority" : -1, 193 | "loop" : -1, 194 | "suspend", 195 | "run" : 1000 196 | }, 197 | 198 | "NPDecoder" : { 199 | "priority" : -15, 200 | "loop" : -1, 201 | "suspend", 202 | "run" : 500, 203 | "sleep" : 680, 204 | "resume" : "OMXCallbackDisp1", 205 | "run" : 2000 206 | }, 207 | 208 | "NPDecoder-CL" : { 209 | "priority" : -15, 210 | "loop" : -1, 211 | "suspend", 212 | "run" : 570, 213 | "sleep" : 570, 214 | "run" : 2100 215 | }, 216 | 217 | "gle.aac.decoder" : { 218 | "priority" : -1, 219 | "loop" : -1, 220 | "suspend", 221 | "run" : 2400, 222 | "sleep" : 430, 223 | "run" : 45 224 | }, 225 | 226 | "OMXCallbackDisp1" : { 227 | "priority" : -1, 228 | "loop" : -1, 229 | "suspend", 230 | "run" : 135, 231 | "sleep" : 230, 232 | "run" : 140, 233 | "sleep" : 330, 234 | "run" : 190, 235 | "sleep" : 550, 236 | "run" : 160 237 | } 238 | }, 239 | 240 | "global" : { 241 | "default_policy" : "SCHED_OTHER", 242 | "duration" : 6, 243 | "gnuplot" : false, 244 | "logdir" : "./", 245 | "log_basename" : "video", 246 | "lock_pages" : true, 247 | "frag" : 1, 248 | "calibration" : "CPU0" 249 | } 250 | } 251 | 252 | -------------------------------------------------------------------------------- /src/rt-app_types.h: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of rt-app - https://launchpad.net/rt-app 3 | Copyright (C) 2010 Giacomo Bagnoli 4 | Copyright (C) 2014 Juri Lelli 5 | Copyright (C) 2014 Vincent Guittot 6 | 7 | This program is free software; you can redistribute it and/or 8 | modify it under the terms of the GNU General Public License 9 | as published by the Free Software Foundation; either version 2 10 | of the License, or (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 | */ 21 | 22 | #ifndef _RTAPP_TYPES_H_ 23 | #define _RTAPP_TYPES_H_ 24 | 25 | /* For cpu_set_t type */ 26 | #define _GNU_SOURCE 27 | #include 28 | #include 29 | 30 | #include 31 | #include 32 | #include "config.h" 33 | 34 | #ifndef HAVE_SCHED_SETATTR 35 | #include "dl_syscalls.h" 36 | #endif 37 | 38 | #if HAVE_LIBNUMA 39 | #include 40 | #endif 41 | 42 | #define RTAPP_POLICY_DESCR_LENGTH 16 43 | #define RTAPP_RESOURCE_DESCR_LENGTH 16 44 | #define RTAPP_FTRACE_PATH_LENGTH 256 45 | 46 | #define DEFAULT_THREAD_PRIORITY 10 47 | #define DEFAULT_THREAD_NICE 0 48 | #define THREAD_PRIORITY_UNCHANGED INT_MAX 49 | 50 | #define PATH_LENGTH 256 51 | 52 | /* exit codes */ 53 | #define EXIT_SUCCESS 0 54 | #define EXIT_FAILURE 1 55 | #define EXIT_INV_CONFIG 2 56 | #define EXIT_INV_COMMANDLINE 3 57 | 58 | /* SCHED_IDLE is not available if __USE_GNU is not defined */ 59 | #ifndef __USE_GNU 60 | #define SCHED_IDLE 5 61 | #endif 62 | 63 | struct _thread_data_t; 64 | 65 | typedef enum policy_t 66 | { 67 | other = SCHED_OTHER, 68 | idle = SCHED_IDLE, 69 | rr = SCHED_RR, 70 | fifo = SCHED_FIFO, 71 | deadline = SCHED_DEADLINE, 72 | same = -1 73 | } policy_t; 74 | 75 | typedef enum resource_t 76 | { 77 | rtapp_unknown = 0, 78 | rtapp_mutex, 79 | rtapp_wait, 80 | rtapp_signal, 81 | rtapp_broadcast, 82 | rtapp_sleep, 83 | rtapp_run, 84 | rtapp_sig_and_wait, 85 | rtapp_lock, 86 | rtapp_unlock, 87 | rtapp_timer, 88 | rtapp_timer_unique, 89 | rtapp_suspend, 90 | rtapp_resume, 91 | rtapp_mem, 92 | rtapp_iorun, 93 | rtapp_runtime, 94 | rtapp_yield, 95 | rtapp_barrier, 96 | rtapp_fork 97 | } resource_t; 98 | 99 | struct _rtapp_mutex { 100 | pthread_mutex_t obj; 101 | pthread_mutexattr_t attr; 102 | } ; 103 | 104 | struct _rtapp_cond { 105 | pthread_cond_t obj; 106 | pthread_condattr_t attr; 107 | }; 108 | 109 | struct _rtapp_barrier_like { 110 | /* sync operation which works without ordering - everyone waits 111 | * until the last task arrives at the sync point. Conceptually 112 | * just like pthread_barrier except we don't have any cleanup 113 | * issues which barrier would impose */ 114 | /* mutex to guard read/write of the flag */ 115 | pthread_mutex_t m_obj; 116 | pthread_mutexattr_t m_attr; 117 | /* flag to indicate how many are waiting */ 118 | int waiting; 119 | /* condvar to wait/signal on */ 120 | pthread_cond_t c_obj; 121 | }; 122 | 123 | struct _rtapp_signal { 124 | pthread_cond_t *target; 125 | }; 126 | 127 | struct _rtapp_timer { 128 | struct timespec t_next; 129 | int init; 130 | int relative; 131 | }; 132 | 133 | struct _rtapp_iomem_buf { 134 | char *ptr; 135 | int size; 136 | }; 137 | 138 | struct _rtapp_iodev { 139 | int fd; 140 | }; 141 | 142 | struct _rtapp_fork { 143 | struct _thread_data_t *tdata; 144 | char *ref; 145 | int nforks; 146 | }; 147 | 148 | /* Shared resources */ 149 | typedef struct _rtapp_resource_t { 150 | union { 151 | struct _rtapp_mutex mtx; 152 | struct _rtapp_cond cond; 153 | struct _rtapp_signal signal; 154 | struct _rtapp_timer timer; 155 | struct _rtapp_iomem_buf buf; 156 | struct _rtapp_iodev dev; 157 | struct _rtapp_barrier_like barrier; 158 | struct _rtapp_fork fork; 159 | } res; 160 | int index; 161 | resource_t type; 162 | char *name; 163 | } rtapp_resource_t; 164 | 165 | typedef struct _rtapp_resources_t { 166 | int nresources; 167 | rtapp_resource_t resources[0]; 168 | } rtapp_resources_t; 169 | 170 | typedef struct _event_data_t { 171 | char name[48]; 172 | resource_t type; 173 | int res; 174 | int dep; 175 | int duration; 176 | int count; 177 | } event_data_t; 178 | 179 | typedef struct _cpuset_data_t { 180 | cpu_set_t *cpuset; 181 | char *cpuset_str; 182 | size_t cpusetsize; 183 | } cpuset_data_t; 184 | 185 | typedef struct _numaset_data_t { 186 | struct bitmask * numaset; 187 | char *numaset_str; 188 | } numaset_data_t; 189 | 190 | typedef struct _sched_data_t { 191 | policy_t policy; 192 | int prio; 193 | unsigned long runtime; 194 | unsigned long deadline; 195 | unsigned long period; 196 | int util_min; 197 | int util_max; 198 | } sched_data_t; 199 | 200 | typedef struct _taskgroup_data_t { 201 | char *name; 202 | int offset; 203 | } taskgroup_data_t; 204 | 205 | typedef struct _phase_data_t { 206 | int loop; 207 | event_data_t *events; 208 | int nbevents; 209 | cpuset_data_t cpu_data; 210 | numaset_data_t numa_data; 211 | sched_data_t *sched_data; 212 | taskgroup_data_t *taskgroup_data; 213 | } phase_data_t; 214 | 215 | typedef struct _thread_data_t { 216 | int ind; 217 | char *name; 218 | int lock_pages; 219 | int duration; 220 | 221 | cpuset_data_t cpu_data; /* cpu set information */ 222 | cpuset_data_t *curr_cpu_data; /* Current cpu set being used */ 223 | cpuset_data_t def_cpu_data; /* Default cpu set for task */ 224 | 225 | numaset_data_t numa_data; /* numa bind set mask */ 226 | numaset_data_t *curr_numa_data; /* Current numa bind set being used */ 227 | 228 | sched_data_t *sched_data; /* scheduler policy information */ 229 | sched_data_t *curr_sched_data; /* current scheduler policy */ 230 | 231 | taskgroup_data_t *taskgroup_data; /* taskgroup information */ 232 | taskgroup_data_t *curr_taskgroup_data; /* current taskgroup */ 233 | 234 | int loop; 235 | int nphases; 236 | phase_data_t *phases; 237 | 238 | struct timespec main_app_start; 239 | 240 | FILE *log_handler; 241 | 242 | unsigned long delay; 243 | 244 | int forked; 245 | int num_instances; 246 | 247 | rtapp_resources_t *local_resources; 248 | rtapp_resources_t **global_resources; 249 | } thread_data_t; 250 | 251 | typedef struct _pthread_data_t { 252 | thread_data_t *data; 253 | pthread_t thread; 254 | } pthread_data_t; 255 | 256 | typedef struct _ftrace_data_t { 257 | char *tracefs; 258 | int trace_fd; 259 | int marker_fd; 260 | } ftrace_data_t; 261 | 262 | typedef struct _log_data_t { 263 | unsigned long perf; 264 | unsigned long duration; 265 | unsigned long wu_latency; 266 | unsigned long c_duration; 267 | unsigned long c_period; 268 | long slack; 269 | } log_data_t; 270 | 271 | typedef struct _rtapp_options_t { 272 | int lock_pages; 273 | 274 | thread_data_t *threads_data; 275 | int nthreads; 276 | int num_tasks; 277 | 278 | policy_t policy; 279 | int duration; 280 | 281 | char *logdir; 282 | char *logbasename; 283 | int logsize; 284 | int gnuplot; 285 | int calib_cpu; 286 | int calib_ns_per_loop; 287 | 288 | rtapp_resources_t *resources; 289 | int pi_enabled; 290 | 291 | int die_on_dmiss; 292 | int mem_buffer_size; 293 | char *io_device; 294 | 295 | int cumulative_slack; 296 | } rtapp_options_t; 297 | 298 | typedef struct _timing_point_t { 299 | int ind; 300 | unsigned long perf; 301 | unsigned long duration; 302 | unsigned long period; 303 | unsigned long c_duration; 304 | unsigned long c_period; 305 | unsigned long wu_latency; 306 | long slack; 307 | __u64 start_time; 308 | __u64 end_time; 309 | __u64 rel_start_time; 310 | } timing_point_t; 311 | 312 | #endif // _RTAPP_TYPES_H_ 313 | -------------------------------------------------------------------------------- /src/rt-app_utils.c: -------------------------------------------------------------------------------- 1 | /* 2 | This file is part of rt-app - https://launchpad.net/rt-app 3 | Copyright (C) 2010 Giacomo Bagnoli 4 | Copyright (C) 2014 Juri Lelli 5 | Copyright (C) 2014 Vincent Guittot 6 | 7 | This program is free software; you can redistribute it and/or 8 | modify it under the terms of the GNU General Public License 9 | as published by the Free Software Foundation; either version 2 10 | of the License, or (at your option) any later version. 11 | 12 | This program is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | GNU General Public License for more details. 16 | 17 | You should have received a copy of the GNU General Public License 18 | along with this program; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 | */ 21 | 22 | #define _GNU_SOURCE 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #include "rt-app_utils.h" 33 | 34 | int log_level = 50; // default 35 | int ftrace_level; // no ftrace messages by default 36 | 37 | unsigned long 38 | timespec_to_usec(struct timespec *ts) 39 | { 40 | return lround((ts->tv_sec * 1E9 + ts->tv_nsec) / 1000.0); 41 | } 42 | 43 | unsigned long long 44 | timespec_to_usec_ull(struct timespec *ts) 45 | { 46 | return llround((ts->tv_sec * 1E9 + ts->tv_nsec) / 1000.0); 47 | } 48 | 49 | long 50 | timespec_to_usec_long(struct timespec *ts) 51 | { 52 | return round((ts->tv_sec * 1E9 + ts->tv_nsec) / 1000.0); 53 | } 54 | 55 | __u64 56 | timespec_to_nsec(struct timespec *ts) 57 | { 58 | return round(ts->tv_sec * 1E9 + ts->tv_nsec); 59 | } 60 | 61 | struct timespec 62 | usec_to_timespec(unsigned long usec) 63 | { 64 | struct timespec ts; 65 | 66 | ts.tv_sec = usec / 1000000; 67 | ts.tv_nsec = (usec % 1000000) * 1000; 68 | 69 | return ts; 70 | } 71 | 72 | struct timespec 73 | msec_to_timespec(unsigned int msec) 74 | { 75 | struct timespec ts; 76 | 77 | ts.tv_sec = msec / 1000; 78 | ts.tv_nsec = (msec % 1000) * 1000000; 79 | 80 | return ts; 81 | } 82 | 83 | struct timespec 84 | timespec_add(struct timespec *t1, struct timespec *t2) 85 | { 86 | struct timespec ts; 87 | 88 | ts.tv_sec = t1->tv_sec + t2->tv_sec; 89 | ts.tv_nsec = t1->tv_nsec + t2->tv_nsec; 90 | 91 | while (ts.tv_nsec >= 1E9) { 92 | ts.tv_nsec -= 1E9; 93 | ts.tv_sec++; 94 | } 95 | 96 | return ts; 97 | } 98 | 99 | struct timespec 100 | timespec_sub(struct timespec *t1, struct timespec *t2) 101 | { 102 | struct timespec ts; 103 | 104 | if (t1->tv_nsec < t2->tv_nsec) { 105 | ts.tv_sec = t1->tv_sec - t2->tv_sec -1; 106 | ts.tv_nsec = t1->tv_nsec + 1000000000 - t2->tv_nsec; 107 | } else { 108 | ts.tv_sec = t1->tv_sec - t2->tv_sec; 109 | ts.tv_nsec = t1->tv_nsec - t2->tv_nsec; 110 | } 111 | 112 | return ts; 113 | 114 | } 115 | 116 | int 117 | timespec_lower(struct timespec *what, struct timespec *than) 118 | { 119 | if (what->tv_sec > than->tv_sec) 120 | return 0; 121 | 122 | if (what->tv_sec < than->tv_sec) 123 | return 1; 124 | 125 | if (what->tv_nsec < than->tv_nsec) 126 | return 1; 127 | 128 | return 0; 129 | } 130 | 131 | int64_t 132 | timespec_sub_to_ns(struct timespec *t1, struct timespec *t2) 133 | { 134 | int64_t diff; 135 | 136 | if (t1->tv_nsec < t2->tv_nsec) { 137 | diff = 1E9 * (int64_t)((int) t1->tv_sec - 138 | (int) t2->tv_sec - 1); 139 | diff += ((int) t1->tv_nsec + 1E9 - (int) t2->tv_nsec); 140 | } else { 141 | diff = 1E9 * (int64_t)((int) t1->tv_sec - (int) t2->tv_sec); 142 | diff += ((int) t1->tv_nsec - (int) t2->tv_nsec); 143 | } 144 | return diff; 145 | } 146 | 147 | 148 | void 149 | log_timing(FILE *handler, timing_point_t *t) 150 | { 151 | fprintf(handler, 152 | "%4d %8lu %8lu %8lu %15llu %15llu %15llu %10ld %10lu %10lu %10lu", 153 | t->ind, 154 | t->perf, 155 | t->duration, 156 | t->period, 157 | t->start_time, 158 | t->end_time, 159 | t->rel_start_time, 160 | t->slack, 161 | t->c_duration, 162 | t->c_period, 163 | t->wu_latency 164 | ); 165 | fprintf(handler, "\n"); 166 | } 167 | 168 | pid_t 169 | gettid(void) 170 | { 171 | return syscall(__NR_gettid); 172 | } 173 | 174 | int 175 | string_to_policy(const char *policy_name, policy_t *policy) 176 | { 177 | if (strcmp(policy_name, "SCHED_OTHER") == 0) 178 | *policy = other; 179 | else if (strcmp(policy_name, "SCHED_IDLE") == 0) 180 | *policy = idle; 181 | else if (strcmp(policy_name, "SCHED_RR") == 0) 182 | *policy = rr; 183 | else if (strcmp(policy_name, "SCHED_FIFO") == 0) 184 | *policy = fifo; 185 | else if (strcmp(policy_name, "SCHED_DEADLINE") == 0) 186 | *policy = deadline; 187 | else 188 | return 1; 189 | return 0; 190 | } 191 | 192 | char * 193 | policy_to_string(policy_t policy) 194 | { 195 | switch (policy) { 196 | case other: 197 | return "SCHED_OTHER"; 198 | case idle: 199 | return "SCHED_IDLE"; 200 | case rr: 201 | return "SCHED_RR"; 202 | case fifo: 203 | return "SCHED_FIFO"; 204 | case deadline: 205 | return "SCHED_DEADLINE"; 206 | default: 207 | return NULL; 208 | } 209 | return NULL; 210 | } 211 | 212 | int 213 | string_to_resource(const char *name, resource_t *resource) 214 | { 215 | if (strcmp(name, "mutex") == 0) 216 | *resource = rtapp_mutex; 217 | else if (strcmp(name, "signal") == 0) 218 | *resource = rtapp_signal; 219 | else if (strcmp(name, "wait") == 0) 220 | *resource = rtapp_wait; 221 | else if (strcmp(name, "broadcast") == 0) 222 | *resource = rtapp_broadcast; 223 | else if (strcmp(name, "sync") == 0) 224 | *resource = rtapp_sig_and_wait; 225 | else if (strcmp(name, "sleep") == 0) 226 | *resource = rtapp_sleep; 227 | else if (strcmp(name, "run") == 0) 228 | *resource = rtapp_run; 229 | else if (strcmp(name, "timer") == 0) 230 | *resource = rtapp_timer; 231 | else 232 | return 1; 233 | return 0; 234 | } 235 | 236 | int 237 | resource_to_string(resource_t resource, char *resource_name) 238 | { 239 | switch (resource) { 240 | case rtapp_mutex: 241 | strcpy(resource_name, "mutex"); 242 | break; 243 | case rtapp_wait: 244 | strcpy(resource_name, "wait"); 245 | break; 246 | case rtapp_signal: 247 | strcpy(resource_name, "signal"); 248 | break; 249 | case rtapp_broadcast: 250 | strcpy(resource_name, "broadcast"); 251 | break; 252 | case rtapp_sig_and_wait: 253 | strcpy(resource_name, "sync"); 254 | break; 255 | case rtapp_sleep: 256 | strcpy(resource_name, "sleep"); 257 | break; 258 | case rtapp_run: 259 | strcpy(resource_name, "run"); 260 | break; 261 | case rtapp_timer: 262 | strcpy(resource_name, "timer"); 263 | break; 264 | case rtapp_barrier: 265 | strcpy(resource_name, "barrier"); 266 | break; 267 | default: 268 | return 1; 269 | } 270 | return 0; 271 | } 272 | 273 | int ftrace_setup(char *categories) 274 | { 275 | char *cat = strtok(categories, ","); 276 | 277 | ftrace_level = FTRACE_NONE; 278 | while (cat) { 279 | if (!strncasecmp("main", cat, 5)) 280 | ftrace_level |= FTRACE_MAIN; 281 | else if (!strncasecmp("task", cat, 5)) 282 | ftrace_level |= FTRACE_TASK; 283 | else if (!strncasecmp("loop", cat, 5)) 284 | ftrace_level |= FTRACE_LOOP; 285 | else if (!strncasecmp("event", cat, 6)) 286 | ftrace_level |= FTRACE_EVENT; 287 | else if (!strncasecmp("stats", cat, 6)) 288 | ftrace_level |= FTRACE_STATS; 289 | else if (!strncasecmp("none", cat, 5)) 290 | ftrace_level = FTRACE_NONE; 291 | else 292 | return 1; 293 | cat = strtok(NULL, ","); 294 | } 295 | 296 | return 0; 297 | } 298 | 299 | void ftrace_write(int mark_fd, const char *fmt, ...) 300 | { 301 | va_list ap; 302 | int n, size = BUF_SIZE, ret; 303 | char *tmp, *ntmp; 304 | 305 | if (mark_fd < 0) { 306 | log_error("invalid mark_fd"); 307 | exit(EXIT_FAILURE); 308 | } 309 | 310 | if ((tmp = malloc(size)) == NULL) { 311 | log_error("Cannot allocate ftrace buffer"); 312 | exit(EXIT_FAILURE); 313 | } 314 | 315 | while(1) { 316 | /* Try to print in the allocated space */ 317 | va_start(ap, fmt); 318 | n = vsnprintf(tmp, BUF_SIZE, fmt, ap); 319 | va_end(ap); 320 | 321 | /* If it worked return success */ 322 | if (n > -1 && n < size) { 323 | ret = write(mark_fd, tmp, n); 324 | free(tmp); 325 | if (ret < 0) { 326 | log_error("Cannot write mark_fd: %s\n", 327 | strerror(errno)); 328 | exit(EXIT_FAILURE); 329 | } else if (ret < n) { 330 | log_debug("Cannot write all bytes at once into mark_fd\n"); 331 | } 332 | return; 333 | } 334 | 335 | /* Else try again with more space */ 336 | if (n > -1) /* glibc 2.1 */ 337 | size = n+1; 338 | else /* glibc 2.0 */ 339 | size *= 2; 340 | 341 | if ((ntmp = realloc(tmp, size)) == NULL) { 342 | free(tmp); 343 | log_error("Cannot reallocate ftrace buffer"); 344 | exit(EXIT_FAILURE); 345 | } else { 346 | tmp = ntmp; 347 | } 348 | } 349 | 350 | } 351 | -------------------------------------------------------------------------------- /src/rt-app_taskgroups.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "config.h" 11 | #include "rt-app_utils.h" 12 | #include "rt-app_taskgroups.h" 13 | 14 | #define PIN "[tg] " 15 | 16 | typedef struct _taskgroup_ctrl_t 17 | { 18 | char *mount_point; 19 | taskgroup_data_t *tg_array; 20 | unsigned int nr_tgs; 21 | } taskgroup_ctrl_t; 22 | 23 | static taskgroup_ctrl_t ctrl; 24 | 25 | const static unsigned int max_nbr_tgs = 32; 26 | 27 | static void initialize_taskgroups(void) 28 | { 29 | size_t size = max_nbr_tgs * sizeof(taskgroup_data_t); 30 | 31 | ctrl.tg_array = malloc(size); 32 | if (!ctrl.tg_array) { 33 | perror("malloc"); 34 | exit(EXIT_FAILURE); 35 | } 36 | } 37 | 38 | taskgroup_data_t *alloc_taskgroup(size_t size) 39 | { 40 | taskgroup_data_t *tg; 41 | 42 | if (!ctrl.nr_tgs) 43 | initialize_taskgroups(); 44 | 45 | if (ctrl.nr_tgs >= max_nbr_tgs) { 46 | log_error(PIN "# taskgroups exceeds max # taskgroups [%u]", 47 | max_nbr_tgs); 48 | return NULL; 49 | } 50 | 51 | tg = &ctrl.tg_array[ctrl.nr_tgs++]; 52 | 53 | tg->name = malloc(size); 54 | if (!tg->name) { 55 | perror("malloc"); 56 | return NULL; 57 | } 58 | tg->offset = 0; 59 | 60 | log_debug(PIN "# taskgroups allocated [%u]", ctrl.nr_tgs); 61 | 62 | return tg; 63 | } 64 | 65 | taskgroup_data_t *find_taskgroup(char *name) 66 | { 67 | taskgroup_data_t *tg = ctrl.tg_array; 68 | unsigned int i; 69 | 70 | for (i = 0; i < ctrl.nr_tgs; i++, tg++) 71 | if (!strcmp(tg->name, name)) 72 | return tg; 73 | 74 | return NULL; 75 | } 76 | 77 | static int cgroup_attach_task(char *name); 78 | 79 | void set_thread_taskgroup(thread_data_t *data, taskgroup_data_t *tg) 80 | { 81 | if (!tg) 82 | return; 83 | 84 | if (data->curr_taskgroup_data == tg) 85 | return; 86 | 87 | log_debug("[%d] set task [%s] taskgroup [%s]", data->ind, data->name, tg->name); 88 | 89 | if (cgroup_attach_task(tg->name)) { 90 | log_critical(PIN "cannot attach task to taskgroup [%s]", tg->name); 91 | exit(EXIT_FAILURE); 92 | } 93 | 94 | data->curr_taskgroup_data = tg; 95 | } 96 | 97 | void reset_thread_taskgroup(void) 98 | { 99 | if (!ctrl.nr_tgs) 100 | return; 101 | 102 | cgroup_attach_task("/"); 103 | } 104 | 105 | static int cgroup_check_cpu_controller(void) 106 | { 107 | int dummy[2], enabled, ret = 0; 108 | FILE *cgroups; 109 | char buf[512]; 110 | 111 | cgroups = fopen("/proc/cgroups", "re"); 112 | 113 | if (!cgroups) { 114 | perror("fopen"); 115 | goto err; 116 | } 117 | 118 | /* Ignore the first line as it contains the header. */ 119 | if (!fgets(buf, sizeof(buf), cgroups)) { 120 | perror("fgets"); 121 | goto err; 122 | } 123 | 124 | while (!feof(cgroups)) { 125 | /* 126 | * Only interested in 'subsys_name' and 'enabled' column 127 | * of /proc/cgroups, not in 'hierarchy' or 'num_cgroups'. 128 | */ 129 | if (fscanf(cgroups, "%s %d %d %d", buf, &dummy[0], &dummy[1], 130 | &enabled) < 4) { 131 | perror("fscanf"); 132 | goto err; 133 | } 134 | 135 | if (!strcmp(buf, "cpu") && enabled == 1) 136 | goto done; 137 | } 138 | err: 139 | ret = -1; 140 | done: 141 | if (cgroups) 142 | fclose(cgroups); 143 | 144 | return ret; 145 | } 146 | 147 | static int cgroup_get_cpu_controller_mount_point(void) 148 | { 149 | struct mntent *ent; 150 | FILE *mounts; 151 | int ret = -1; 152 | 153 | mounts = setmntent("/proc/mounts", "re"); 154 | 155 | if (!mounts) { 156 | perror("setmntent"); 157 | return ret; 158 | } 159 | 160 | while (ent = getmntent(mounts)) { 161 | if (strcmp(ent->mnt_type, "cgroup")) 162 | continue; 163 | 164 | if (!hasmntopt(ent, "cpu")) 165 | continue; 166 | 167 | ctrl.mount_point = malloc(strlen(ent->mnt_dir) + 1); 168 | if (!ctrl.mount_point) { 169 | perror("malloc"); 170 | break; 171 | } 172 | 173 | strcpy(ctrl.mount_point, ent->mnt_dir); 174 | 175 | log_debug(PIN "cgroup cpu controller mountpoint [%s] found", ent->mnt_dir); 176 | ret = 0; 177 | break; 178 | } 179 | 180 | endmntent(mounts); 181 | return ret; 182 | } 183 | 184 | void initialize_cgroups(void) 185 | { 186 | if (!ctrl.nr_tgs) 187 | return; 188 | 189 | if (cgroup_check_cpu_controller()) { 190 | log_error(PIN "no cgroup cpu controller found"); 191 | exit(EXIT_FAILURE); 192 | } 193 | 194 | if (cgroup_get_cpu_controller_mount_point()) { 195 | log_error(PIN "no cgroup cpu controller mountpoint found"); 196 | exit(EXIT_FAILURE); 197 | } 198 | } 199 | 200 | static int cgroup_mkdir(const char *name, int *offset) 201 | { 202 | char *dir = NULL, *path = NULL, del; 203 | int i = 0, ret = 0, y; 204 | size_t size; 205 | 206 | *offset = -1; 207 | 208 | if (!name || !strcmp(name, "/")) 209 | goto error; 210 | 211 | dir = strdup(name); 212 | if (!dir) { 213 | log_error(PIN "cannot duplicate string [%s]", name); 214 | ret = -1; 215 | goto error; 216 | } 217 | 218 | size = strlen(ctrl.mount_point) + strlen(dir) + 1; 219 | path = malloc(size); 220 | if (!path) { 221 | perror("malloc"); 222 | ret = -1; 223 | goto error; 224 | } 225 | 226 | do { 227 | y = i; 228 | 229 | while (dir[i] == '/') 230 | i++; 231 | 232 | if (dir[i] == '\0') 233 | goto error; 234 | 235 | while (dir[i] != '\0' && dir[i] != '/') 236 | i++; 237 | 238 | del = dir[i]; 239 | dir[i] = '\0'; 240 | 241 | snprintf(path, size, "%s%s", ctrl.mount_point, dir); 242 | 243 | ret = mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); 244 | if (ret) { 245 | switch (errno) { 246 | case EEXIST: 247 | log_debug(PIN "cgroup [%s] exists, continue ...", dir); 248 | ret = 0; 249 | goto next; 250 | default: 251 | log_error(PIN "cgroup [%s] unhandled error (%s)", dir, strerror(errno)); 252 | goto error; 253 | } 254 | } else if (*offset == -1) { 255 | *offset = y; 256 | } 257 | next: 258 | dir[i] = del; 259 | } while (dir[i]); 260 | error: 261 | free(dir); 262 | free(path); 263 | return ret; 264 | } 265 | 266 | static int cgroup_rmdir(char *name, int offset) 267 | { 268 | char *dir = NULL, *path = NULL, *del; 269 | int ret = 0; 270 | size_t size, last; 271 | 272 | if (offset < 0) 273 | goto error; 274 | 275 | dir = strdup(name); 276 | if (!dir) { 277 | log_error(PIN "cannot duplicate string [%s]", name); 278 | ret = -1; 279 | goto error; 280 | } 281 | 282 | /* Remove trailing slashes. */ 283 | while (last = strlen(dir) - 1, dir[last] == '/') 284 | dir[last] = '\0'; 285 | 286 | size = strlen(ctrl.mount_point) + strlen(dir) + 1; 287 | path = malloc(size); 288 | if (!path) { 289 | perror("malloc"); 290 | ret = -1; 291 | goto error; 292 | } 293 | 294 | while (1) { 295 | snprintf(path, size, "%s%s", ctrl.mount_point, dir); 296 | 297 | ret = rmdir(path); 298 | if (ret) { 299 | switch (errno) { 300 | case ENOTEMPTY: 301 | log_debug(PIN "cgroup [%s] not empty, continue ...", dir); 302 | ret = 0; 303 | break; 304 | case EBUSY: 305 | log_debug(PIN "cgroup [%s] is busy, continue ...", dir); 306 | ret = 0; 307 | break; 308 | case ENOENT: 309 | log_debug(PIN "cgroup [%s] doesn't exist, continue ...", dir); 310 | ret = 0; 311 | break; 312 | default: 313 | log_error(PIN "cgroup [%s] unhandled error (%s)", dir, strerror(errno)); 314 | break; 315 | } 316 | break; 317 | } 318 | 319 | del = strrchr(dir, '/'); 320 | if (!del) 321 | break; 322 | *del = '\0'; 323 | 324 | /* Remove trailing slashes and adapt delimiter. */ 325 | while (last = strlen(dir) - 1, dir[last] == '/') { 326 | del = &dir[last]; 327 | *del = '\0'; 328 | } 329 | 330 | if (del <= dir + offset) 331 | break; 332 | } 333 | error: 334 | free(dir); 335 | free(path); 336 | return ret; 337 | } 338 | 339 | void add_cgroups(void) 340 | { 341 | taskgroup_data_t *tg = ctrl.tg_array; 342 | int i; 343 | 344 | for (i = 0; i < ctrl.nr_tgs; i++, tg++) { 345 | if (cgroup_mkdir(tg->name, &tg->offset)) { 346 | log_critical(PIN "cannot create cgroup [%s]", tg->name); 347 | exit(EXIT_FAILURE); 348 | } 349 | log_debug(PIN "cgroup [%s] added", tg->name); 350 | } 351 | } 352 | 353 | void remove_cgroups(void) 354 | { 355 | taskgroup_data_t *tg = &ctrl.tg_array[ctrl.nr_tgs - 1]; 356 | int i; 357 | 358 | if (!ctrl.mount_point) 359 | return; 360 | 361 | for (i = ctrl.nr_tgs - 1; i >= 0; i--, tg--) { 362 | if (cgroup_rmdir(tg->name, tg->offset)) { 363 | log_critical(PIN "cannot remove cgroup [%s]", tg->name); 364 | exit(EXIT_FAILURE); 365 | } 366 | log_debug(PIN "cgroup [%s] removed", tg->name); 367 | } 368 | } 369 | 370 | static int cgroup_attach_task(char *name) 371 | { 372 | char *file, *path; 373 | int ret = -1; 374 | FILE *tasks; 375 | size_t size; 376 | 377 | file = strcmp(name, "/") ? "/tasks" : "tasks"; 378 | size = strlen(ctrl.mount_point) + strlen(name) + strlen(file) + 1; 379 | path = malloc(size); 380 | if (!path) { 381 | perror("malloc"); 382 | goto error; 383 | } 384 | 385 | sprintf(path, "%s%s%s", ctrl.mount_point, name, file); 386 | tasks = fopen(path, "we"); 387 | if (!tasks) { 388 | perror("fopen"); 389 | goto error; 390 | } 391 | 392 | if (fprintf(tasks, "%d", gettid()) < 0) { 393 | perror("fprintf"); 394 | goto error; 395 | } 396 | 397 | if (fclose(tasks)) { 398 | perror("fclose"); 399 | goto error; 400 | } 401 | 402 | ret = 0; 403 | error: 404 | free(path); 405 | return ret; 406 | } 407 | -------------------------------------------------------------------------------- /COPYING.in: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1990, 1991, 1992 Free Software Foundation, Inc. 5 | 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Library General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | Appendix: How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 19yy 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License 307 | along with this program; if not, write to the Free Software 308 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) 19yy name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Library General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /libdl/COPYING: -------------------------------------------------------------------------------- 1 | The following is the original GNU GPL v2 under which schedtool is released. 2 | schedtool is (c) by Freek, 2004, 2005, 2006, 2007 3 | 4 | -- -- 5 | 6 | GNU GENERAL PUBLIC LICENSE 7 | Version 2, June 1991 8 | 9 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 10 | 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 11 | Everyone is permitted to copy and distribute verbatim copies 12 | of this license document, but changing it is not allowed. 13 | 14 | Preamble 15 | 16 | The licenses for most software are designed to take away your 17 | freedom to share and change it. By contrast, the GNU General Public 18 | License is intended to guarantee your freedom to share and change free 19 | software--to make sure the software is free for all its users. This 20 | General Public License applies to most of the Free Software 21 | Foundation's software and to any other program whose authors commit to 22 | using it. (Some other Free Software Foundation software is covered by 23 | the GNU Library General Public License instead.) You can apply it to 24 | your programs, too. 25 | 26 | When we speak of free software, we are referring to freedom, not 27 | price. Our General Public Licenses are designed to make sure that you 28 | have the freedom to distribute copies of free software (and charge for 29 | this service if you wish), that you receive source code or can get it 30 | if you want it, that you can change the software or use pieces of it 31 | in new free programs; and that you know you can do these things. 32 | 33 | To protect your rights, we need to make restrictions that forbid 34 | anyone to deny you these rights or to ask you to surrender the rights. 35 | These restrictions translate to certain responsibilities for you if you 36 | distribute copies of the software, or if you modify it. 37 | 38 | For example, if you distribute copies of such a program, whether 39 | gratis or for a fee, you must give the recipients all the rights that 40 | you have. You must make sure that they, too, receive or can get the 41 | source code. And you must show them these terms so they know their 42 | rights. 43 | 44 | We protect your rights with two steps: (1) copyright the software, and 45 | (2) offer you this license which gives you legal permission to copy, 46 | distribute and/or modify the software. 47 | 48 | Also, for each author's protection and ours, we want to make certain 49 | that everyone understands that there is no warranty for this free 50 | software. If the software is modified by someone else and passed on, we 51 | want its recipients to know that what they have is not the original, so 52 | that any problems introduced by others will not reflect on the original 53 | authors' reputations. 54 | 55 | Finally, any free program is threatened constantly by software 56 | patents. We wish to avoid the danger that redistributors of a free 57 | program will individually obtain patent licenses, in effect making the 58 | program proprietary. To prevent this, we have made it clear that any 59 | patent must be licensed for everyone's free use or not licensed at all. 60 | 61 | The precise terms and conditions for copying, distribution and 62 | modification follow. 63 | 64 | GNU GENERAL PUBLIC LICENSE 65 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 66 | 67 | 0. This License applies to any program or other work which contains 68 | a notice placed by the copyright holder saying it may be distributed 69 | under the terms of this General Public License. The "Program", below, 70 | refers to any such program or work, and a "work based on the Program" 71 | means either the Program or any derivative work under copyright law: 72 | that is to say, a work containing the Program or a portion of it, 73 | either verbatim or with modifications and/or translated into another 74 | language. (Hereinafter, translation is included without limitation in 75 | the term "modification".) Each licensee is addressed as "you". 76 | 77 | Activities other than copying, distribution and modification are not 78 | covered by this License; they are outside its scope. The act of 79 | running the Program is not restricted, and the output from the Program 80 | is covered only if its contents constitute a work based on the 81 | Program (independent of having been made by running the Program). 82 | Whether that is true depends on what the Program does. 83 | 84 | 1. You may copy and distribute verbatim copies of the Program's 85 | source code as you receive it, in any medium, provided that you 86 | conspicuously and appropriately publish on each copy an appropriate 87 | copyright notice and disclaimer of warranty; keep intact all the 88 | notices that refer to this License and to the absence of any warranty; 89 | and give any other recipients of the Program a copy of this License 90 | along with the Program. 91 | 92 | You may charge a fee for the physical act of transferring a copy, and 93 | you may at your option offer warranty protection in exchange for a fee. 94 | 95 | 2. You may modify your copy or copies of the Program or any portion 96 | of it, thus forming a work based on the Program, and copy and 97 | distribute such modifications or work under the terms of Section 1 98 | above, provided that you also meet all of these conditions: 99 | 100 | a) You must cause the modified files to carry prominent notices 101 | stating that you changed the files and the date of any change. 102 | 103 | b) You must cause any work that you distribute or publish, that in 104 | whole or in part contains or is derived from the Program or any 105 | part thereof, to be licensed as a whole at no charge to all third 106 | parties under the terms of this License. 107 | 108 | c) If the modified program normally reads commands interactively 109 | when run, you must cause it, when started running for such 110 | interactive use in the most ordinary way, to print or display an 111 | announcement including an appropriate copyright notice and a 112 | notice that there is no warranty (or else, saying that you provide 113 | a warranty) and that users may redistribute the program under 114 | these conditions, and telling the user how to view a copy of this 115 | License. (Exception: if the Program itself is interactive but 116 | does not normally print such an announcement, your work based on 117 | the Program is not required to print an announcement.) 118 | 119 | These requirements apply to the modified work as a whole. If 120 | identifiable sections of that work are not derived from the Program, 121 | and can be reasonably considered independent and separate works in 122 | themselves, then this License, and its terms, do not apply to those 123 | sections when you distribute them as separate works. But when you 124 | distribute the same sections as part of a whole which is a work based 125 | on the Program, the distribution of the whole must be on the terms of 126 | this License, whose permissions for other licensees extend to the 127 | entire whole, and thus to each and every part regardless of who wrote it. 128 | 129 | Thus, it is not the intent of this section to claim rights or contest 130 | your rights to work written entirely by you; rather, the intent is to 131 | exercise the right to control the distribution of derivative or 132 | collective works based on the Program. 133 | 134 | In addition, mere aggregation of another work not based on the Program 135 | with the Program (or with a work based on the Program) on a volume of 136 | a storage or distribution medium does not bring the other work under 137 | the scope of this License. 138 | 139 | 3. You may copy and distribute the Program (or a work based on it, 140 | under Section 2) in object code or executable form under the terms of 141 | Sections 1 and 2 above provided that you also do one of the following: 142 | 143 | a) Accompany it with the complete corresponding machine-readable 144 | source code, which must be distributed under the terms of Sections 145 | 1 and 2 above on a medium customarily used for software interchange; or, 146 | 147 | b) Accompany it with a written offer, valid for at least three 148 | years, to give any third party, for a charge no more than your 149 | cost of physically performing source distribution, a complete 150 | machine-readable copy of the corresponding source code, to be 151 | distributed under the terms of Sections 1 and 2 above on a medium 152 | customarily used for software interchange; or, 153 | 154 | c) Accompany it with the information you received as to the offer 155 | to distribute corresponding source code. (This alternative is 156 | allowed only for noncommercial distribution and only if you 157 | received the program in object code or executable form with such 158 | an offer, in accord with Subsection b above.) 159 | 160 | The source code for a work means the preferred form of the work for 161 | making modifications to it. For an executable work, complete source 162 | code means all the source code for all modules it contains, plus any 163 | associated interface definition files, plus the scripts used to 164 | control compilation and installation of the executable. However, as a 165 | special exception, the source code distributed need not include 166 | anything that is normally distributed (in either source or binary 167 | form) with the major components (compiler, kernel, and so on) of the 168 | operating system on which the executable runs, unless that component 169 | itself accompanies the executable. 170 | 171 | If distribution of executable or object code is made by offering 172 | access to copy from a designated place, then offering equivalent 173 | access to copy the source code from the same place counts as 174 | distribution of the source code, even though third parties are not 175 | compelled to copy the source along with the object code. 176 | 177 | 4. You may not copy, modify, sublicense, or distribute the Program 178 | except as expressly provided under this License. Any attempt 179 | otherwise to copy, modify, sublicense or distribute the Program is 180 | void, and will automatically terminate your rights under this License. 181 | However, parties who have received copies, or rights, from you under 182 | this License will not have their licenses terminated so long as such 183 | parties remain in full compliance. 184 | 185 | 5. You are not required to accept this License, since you have not 186 | signed it. However, nothing else grants you permission to modify or 187 | distribute the Program or its derivative works. These actions are 188 | prohibited by law if you do not accept this License. Therefore, by 189 | modifying or distributing the Program (or any work based on the 190 | Program), you indicate your acceptance of this License to do so, and 191 | all its terms and conditions for copying, distributing or modifying 192 | the Program or works based on it. 193 | 194 | 6. Each time you redistribute the Program (or any work based on the 195 | Program), the recipient automatically receives a license from the 196 | original licensor to copy, distribute or modify the Program subject to 197 | these terms and conditions. You may not impose any further 198 | restrictions on the recipients' exercise of the rights granted herein. 199 | You are not responsible for enforcing compliance by third parties to 200 | this License. 201 | 202 | 7. If, as a consequence of a court judgment or allegation of patent 203 | infringement or for any other reason (not limited to patent issues), 204 | conditions are imposed on you (whether by court order, agreement or 205 | otherwise) that contradict the conditions of this License, they do not 206 | excuse you from the conditions of this License. If you cannot 207 | distribute so as to satisfy simultaneously your obligations under this 208 | License and any other pertinent obligations, then as a consequence you 209 | may not distribute the Program at all. For example, if a patent 210 | license would not permit royalty-free redistribution of the Program by 211 | all those who receive copies directly or indirectly through you, then 212 | the only way you could satisfy both it and this License would be to 213 | refrain entirely from distribution of the Program. 214 | 215 | If any portion of this section is held invalid or unenforceable under 216 | any particular circumstance, the balance of the section is intended to 217 | apply and the section as a whole is intended to apply in other 218 | circumstances. 219 | 220 | It is not the purpose of this section to induce you to infringe any 221 | patents or other property right claims or to contest validity of any 222 | such claims; this section has the sole purpose of protecting the 223 | integrity of the free software distribution system, which is 224 | implemented by public license practices. Many people have made 225 | generous contributions to the wide range of software distributed 226 | through that system in reliance on consistent application of that 227 | system; it is up to the author/donor to decide if he or she is willing 228 | to distribute software through any other system and a licensee cannot 229 | impose that choice. 230 | 231 | This section is intended to make thoroughly clear what is believed to 232 | be a consequence of the rest of this License. 233 | 234 | 8. If the distribution and/or use of the Program is restricted in 235 | certain countries either by patents or by copyrighted interfaces, the 236 | original copyright holder who places the Program under this License 237 | may add an explicit geographical distribution limitation excluding 238 | those countries, so that distribution is permitted only in or among 239 | countries not thus excluded. In such case, this License incorporates 240 | the limitation as if written in the body of this License. 241 | 242 | 9. The Free Software Foundation may publish revised and/or new versions 243 | of the General Public License from time to time. Such new versions will 244 | be similar in spirit to the present version, but may differ in detail to 245 | address new problems or concerns. 246 | 247 | Each version is given a distinguishing version number. If the Program 248 | specifies a version number of this License which applies to it and "any 249 | later version", you have the option of following the terms and conditions 250 | either of that version or of any later version published by the Free 251 | Software Foundation. If the Program does not specify a version number of 252 | this License, you may choose any version ever published by the Free Software 253 | Foundation. 254 | 255 | 10. If you wish to incorporate parts of the Program into other free 256 | programs whose distribution conditions are different, write to the author 257 | to ask for permission. For software which is copyrighted by the Free 258 | Software Foundation, write to the Free Software Foundation; we sometimes 259 | make exceptions for this. Our decision will be guided by the two goals 260 | of preserving the free status of all derivatives of our free software and 261 | of promoting the sharing and reuse of software generally. 262 | 263 | NO WARRANTY 264 | 265 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 266 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 267 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 268 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 269 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 270 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 271 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 272 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 273 | REPAIR OR CORRECTION. 274 | 275 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 276 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 277 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 278 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 279 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 280 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 281 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 282 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 283 | POSSIBILITY OF SUCH DAMAGES. 284 | 285 | END OF TERMS AND CONDITIONS 286 | 287 | How to Apply These Terms to Your New Programs 288 | 289 | If you develop a new program, and you want it to be of the greatest 290 | possible use to the public, the best way to achieve this is to make it 291 | free software which everyone can redistribute and change under these terms. 292 | 293 | To do so, attach the following notices to the program. It is safest 294 | to attach them to the start of each source file to most effectively 295 | convey the exclusion of warranty; and each file should have at least 296 | the "copyright" line and a pointer to where the full notice is found. 297 | 298 | 299 | Copyright (C) 19yy 300 | 301 | This program is free software; you can redistribute it and/or modify 302 | it under the terms of the GNU General Public License as published by 303 | the Free Software Foundation; either version 2 of the License, or 304 | (at your option) any later version. 305 | 306 | This program is distributed in the hope that it will be useful, 307 | but WITHOUT ANY WARRANTY; without even the implied warranty of 308 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 309 | GNU General Public License for more details. 310 | 311 | You should have received a copy of the GNU General Public License 312 | along with this program; if not, write to the Free Software 313 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 314 | 315 | 316 | Also add information on how to contact you by electronic and paper mail. 317 | 318 | If the program is interactive, make it output a short notice like this 319 | when it starts in an interactive mode: 320 | 321 | Gnomovision version 69, Copyright (C) 19yy name of author 322 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 323 | This is free software, and you are welcome to redistribute it 324 | under certain conditions; type `show c' for details. 325 | 326 | The hypothetical commands `show w' and `show c' should show the appropriate 327 | parts of the General Public License. Of course, the commands you use may 328 | be called something other than `show w' and `show c'; they could even be 329 | mouse-clicks or menu items--whatever suits your program. 330 | 331 | You should also get your employer (if you work as a programmer) or your 332 | school, if any, to sign a "copyright disclaimer" for the program, if 333 | necessary. Here is a sample; alter the names: 334 | 335 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 336 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 337 | 338 | , 1 April 1989 339 | Ty Coon, President of Vice 340 | 341 | This General Public License does not permit incorporating your program into 342 | proprietary programs. If your program is a subroutine library, you may 343 | consider it more useful to permit linking proprietary applications with the 344 | library. If this is what you want to do, use the GNU Library General 345 | Public License instead of this License. 346 | -------------------------------------------------------------------------------- /doc/tutorial.txt: -------------------------------------------------------------------------------- 1 | HOW-TO use rt-app and workgen to emulate a workload ? 2 | 3 | **** rt-app and workgen **** 4 | rt-app/workgen is a tool that can be used to emulate a use case. Not only the 5 | sleep and run pattern can be emulated but also the dependency between tasks 6 | like accessing same critical resources, creating sequential wake up or syncing 7 | the wake up of threads. The use case is described in a json like file which is 8 | first parsed by workgen then rt-app. 9 | 10 | workgen is a python script that will parse, check and update the json like file 11 | in order to strictly match the json grammar before calling rt-app that will 12 | execute the sequence described in it. 13 | 14 | Even if the json protocol is used in rt-app, workgen enables some freedom 15 | compared to stricter json grammar rules. For examples, 16 | - You don't have to ensure uniqueness of key in json object, workgen will check 17 | the file and ensure that each key is unique by appending an index if necessary. 18 | The feature is quite useful when you describe a sequence made of same kind of 19 | events e.g. a sequence of multiple sleep and run events. 20 | - Some values can be omitted and workgen will add them when it parses the file 21 | before starting the use case. 22 | 23 | **** json file skeleton **** 24 | 25 | The json file that describes a workload is made on 3 main objects: tasks, 26 | resources and global objects. Only tasks object is mandatory; default value will 27 | be used if global object is not defined and resources object is kept for 28 | backward compatibility with old version of rt-app but it doesn't give any 29 | benefit to declare it as the resources are now dynamically created by rt-app 30 | when it parses the file. 31 | 32 | **** global object **** 33 | 34 | The global object defines parameters for the whole use case: 35 | 36 | * duration : Integer. Duration of the use case in seconds. All the threads will 37 | be killed once the duration has elapsed. if -1 has been set, the use case will 38 | run indefinitly until all threads kill themselves (as an example if a finite 39 | number of loop has been defined in their running pattern) or if a signal 40 | is received to stop the use case. 41 | 42 | * calibration : String or Integer: A String defines the CPU that will be used 43 | to calibrate the ns per loop value. "CPU0" is the default value (see run event 44 | section for details about ns per loop value). A integer skips the calibration 45 | step and uses the integer value as ns per loop. 46 | 47 | * default_policy : String. Default scheduling policy of threads. Default 48 | value is SCHED_OTHER. 49 | 50 | * pi_enabled: Boolean. Enable the priority inheritance of mutex. Default value 51 | is False. 52 | 53 | * lock_pages : Boolean. Lock the mem page in RAM. Locking the page in RAM 54 | ensures that your RT thread will not be stalled until a page is moved from swap 55 | to RAM. The lock of the page is only possible for non CFS tasks. Default value 56 | is True. 57 | 58 | * logdir : String. Path to store the various log files. The default path is 59 | the current directory (./). Directory must be already existing. 60 | 61 | * log_basename : String. Prefix used for all log files of the use case. 62 | "rt-app-" is used by default. 63 | 64 | * log_size : String or Integer. A Integer defines a fix size in MB of the 65 | temporary buffer (size per thread) that will be used to store the log data 66 | before saving them in a file. This temporary buffer is used as a circular 67 | buffer so the oldest data will be lost in case of overflow. A string is used 68 | to set a predefined behavior: 69 | - "file" will be used to store the log data directly in the file without 70 | using a temporary buffer. 71 | - "Disable" will disable the log mechanism. 72 | - "Auto" will let rt-app compute the buffer size to not overflow the latter 73 | during the use case. 74 | The use of a temporary buffer prevents the threads of unexpected wait during 75 | io access. The "Auto" mode is not implemented yet and fallback to "file" mode 76 | for the moment. 77 | 78 | * ftrace: String. If not "none", rt-app logs in ftrace the events corresponding 79 | to the requested categories, which can be specified as a comma separated list of 80 | names. 81 | 82 | NOTE: the usage of a "boolean" value for this attribute is DEPRECATED and will 83 | be removed soon. For the time being we map "True/False" to enable/disable all 84 | the supported category names. 85 | 86 | The category names currently supported are: 87 | - main : events generated by the main rt-app task 88 | - task : events generated by a task 89 | - run : events generated by the run of a task 90 | - loop : events generated by each loop of a task 91 | - stats : events reporting statistics on task's activation 92 | 93 | Default value is "none". 94 | 95 | * gnuplot : Boolean. If True, it will create a gnu plot compatible file for 96 | each threads (see gnuplot section for more details). Default value is False. 97 | 98 | "io_device" : Text. Path to the file which will be written to create IO-bounded 99 | busy loop. Specify it carefully since it might damage the specified file. 100 | Default value is "/dev/null". 101 | 102 | "mem_buffer_size" : Integer. The size of per-thread memory buffer in byte being 103 | used to create IO-bounded and memory-bounded busy loop. Default value is 104 | 4194304(4MB). 105 | 106 | * cumulative_slack : Boolean. Accumulate slack (see below) measured during 107 | successive timer events in a phase. Default value is False (time between the 108 | end of last event and the end of the phase). 109 | 110 | *** default global object: 111 | "global" : { 112 | "duration" : -1, 113 | "calibration" : "CPU0", 114 | "default_policy" : "SCHED_OTHER", 115 | "pi_enabled" : false, 116 | "lock_pages" : false, 117 | "logdir" : "./", 118 | "log_size" : "file", 119 | "log_basename" : "rt-app", 120 | "ftrace" : "none", 121 | "gnuplot" : false, 122 | "io_device" : "/dev/null" 123 | "mem_buffer_size" : 4194304, 124 | "cumulative_slack" : false 125 | } 126 | 127 | **** tasks object **** 128 | 129 | The tasks object is made of sub-objects that describe threads. No other kind 130 | of object than thread object is allowed. The key value of each object will be 131 | used as thread's name. 132 | 133 | "tasks" : { 134 | "thread_name1" : { 135 | ... 136 | }, 137 | "thread_name2" : { 138 | ... 139 | }, 140 | "thread_name3" : { 141 | ... 142 | }, 143 | ... 144 | } 145 | 146 | *** thread object *** 147 | 148 | Thread object describes the behavior of one kind of thread which means that 149 | several threads can be created with the same object (see instance parameter 150 | below). 151 | 152 | * instance : Integer. Define the number of threads that will be created with 153 | the properties of this thread object. Default value is 1. A value of 0 will 154 | create the structures of the task but will not create a pthread. 155 | 156 | * delay: Integer. Initial delay before a thread starts execution. The unit 157 | is usec. 158 | 159 | * phases: Object. The phases object describes the behavior of the thread. This 160 | behavior can be split in several distinct phases with their own events and 161 | properties. See phase object parameter below. 162 | 163 | *** phase object *** 164 | 165 | If there is only 1 phase, the sequence of events can be directly put in the 166 | thread object instead of creating a phases object. As an example, the 2 objects 167 | below are equals: 168 | 169 | "task" : { 170 | "thread1" : { 171 | "phases" : { 172 | "phase1" : { 173 | "run" : 10, 174 | "sleep" : 10 175 | } 176 | } 177 | } 178 | } 179 | 180 | "task" : { 181 | "thread1" : { 182 | "run" : 10, 183 | "sleep" : 10 184 | } 185 | } 186 | 187 | *** thread and phase object properties *** 188 | 189 | Several properties can be set at thread and/or phase levels. All these 190 | properties are optional and default value will be used if nothing is defined. 191 | 192 | * loop: Integer. Define the number of times the parent object must be run. The 193 | parent object can be a phase or a thread. For phase object, the loop defines 194 | the number of time the phase will be executed before starting the next phase. 195 | For thread object, the loop defines the number of times that the complete 196 | "phases" object will be executed. The default value is -1 for thread object and 197 | 1 for phases. 198 | 199 | *** scheduling policy 200 | 201 | The scheduling policy can be set at thread and phase levels. A default policy 202 | is set after the thread creation if nothing has been defined. Then, the 203 | scheduling properties can be changed at the beginning of each phase if it has 204 | been defined in the phase object. The behavior is quite similar to an event as 205 | a update happens only if one of the scheduling parameters has been set 206 | otherwise the scheduling parameters will stay unchanged 207 | 208 | * policy : String. Define the scheduling policy of the thread. default_policy 209 | is used if not defined. Accepted value are: 210 | - "SCHED_OTHER" 211 | - "SCHED_IDLE" 212 | - "SCHED_RR" 213 | - "SCHED_FIFO" 214 | - "SCHED_DEADLINE" 215 | 216 | * priority : Integer. Define the scheduling priority of the thread. The value 217 | must be aligned with the range allowed by the policy. The default priority is 218 | 0 for sched_other and sched_deadline class and 10 for rt classes 219 | 220 | * dl-runtime : Integer: Define the runtime budget for deadline scheduling class. 221 | Default value is 0. The unit is usec. For backward compatibility, the 222 | key "runtime" will also be checked in thread object but special must be taken 223 | as this can conflict with runtime event. 224 | 225 | Since Linux 6.12 this parameter also applies to the SCHED_OTHER scheduling 226 | class. It is used to request a custom slice length for the thread. 227 | 228 | * dl-period : Integer. Define the period duration for deadline scheduling class. 229 | Default value is runtime. The unit is usec. For backward compatibility, the 230 | key "period" will also be checked in thread object. 231 | 232 | * dl-deadline : Integer. Define the deadline parameter for deadline scheduling 233 | class. Default value is period. The unit is usec. For backward compatibility, 234 | the key "deadline" will also be checked in thread object. 235 | 236 | *** CPUs affinity 237 | 238 | * cpus: Array of Integer. Define the CPU affinity of the thread. Default 239 | value is all CPUs of the system. An example : "cpus" : [0, 2, 3] 240 | 241 | "cpus" can be specified at task level or phase level. As an example, below 242 | creates two threads. One thread will run with affinity of CPU 2 and 3. The 243 | second task will run first phase with affinity to CPU 0 and 1, second phase with 244 | affinity to CPU 2, and the third phase with affinity to CPU 4, 5, and 6 (it will 245 | inherit the affinity from the task level): 246 | 247 | "tasks" : { 248 | "thread1" : { 249 | "cpus" : [2,3], 250 | "phases" : { 251 | "phase1" : { 252 | "run" : 10, 253 | "sleep" : 10 254 | } 255 | } 256 | } 257 | "thread2" : { 258 | "cpus" : [4,5,6], 259 | "phases" : { 260 | "phase1" : { 261 | "cpus" : [0,1], 262 | "run" : 10, 263 | "sleep" : 10 264 | } 265 | "phase2" : { 266 | "cpus" : [2], 267 | "run" : 10, 268 | "sleep" : 10 269 | } 270 | "phase3" : { 271 | "run" : 10, 272 | "sleep" : 10 273 | } 274 | } 275 | } 276 | } 277 | 278 | *** Utilization Clamping 279 | 280 | util_min: Integer. Can be specified at task level or phase level. Sets the min 281 | utilization value the task can have; which helps boosting the task from 282 | scheduler point of view. 283 | 284 | util_max: Integer. Can be specified at task level or phase level. Sets the max 285 | utilization value the task can have; which helps capping the task from 286 | scheduler point of view. 287 | 288 | *** NUMA memory binding 289 | 290 | * nodes_membind: Array of Integer. Define the NUMA binding of the thread. 291 | Default value is all NUMA nodes of the system. 292 | An example : "nodes_membind" : [0, 2, 3] 293 | 294 | "nodes_membind" Can be specified at task level or phase level. 295 | As an example, below creates two threads. 296 | One thread will run with memory binding to nodes 2 and 3. 297 | The second task will run first phase with memory binding to nodes 0 and 1, 298 | second phase with memory binding to node 2. 299 | Please note, that we follow an "event based policy", which means that 300 | rt-app changes memory binding when there is a "nodes_membind" event 301 | and don't do anything otherwise. 302 | 303 | "tasks" : { 304 | "thread1" : { 305 | "nodes_membind" : [2,3], 306 | "phases" : { 307 | "phase1" : { 308 | "run" : 10, 309 | "sleep" : 10 310 | } 311 | } 312 | } 313 | "thread2" : { 314 | "phases" : { 315 | "phase1" : { 316 | "nodes_membind" : [0,1], 317 | "run" : 10, 318 | "sleep" : 10 319 | } 320 | "phase2" : { 321 | "nodes_membind" : [2], 322 | "run" : 10, 323 | "sleep" : 10 324 | } 325 | } 326 | } 327 | } 328 | 329 | *** taskgroups 330 | 331 | * taskgroup: String. Can be specified at task level or phase level. Currently 332 | only SCHED_OTHER and SCHED_IDLE tasks are supported to contain taskgroup data. 333 | Tasks with a different policy and without taskgroup data can coexist in the 334 | setup. An empty taskgroup ("") is allowed and is interpreted as if there is 335 | no taskgroup data given. Pre-existing parts of a taskgroup are preserved. 336 | They are not removed during rt-app teardown. 337 | The default build supports up to 32 different taskgroups. In case a 338 | configuration exceeds this limit the error message '[rt-app] [tg] # 339 | taskgroups exceeds max # taskgroups [32]' is issued before rt-app exits. The 340 | number of supported taskgroups can be increased by changing 'const static 341 | unsigned int max_nbr_tgs = 32' at compile time. 342 | 343 | *** events *** 344 | 345 | events are simple action that will be performed by the thread or on the 346 | thread. They have to be listed by execution order. 347 | 348 | * run : Integer. Emulate the execution of a load. The duration is defined in 349 | usec but the run event will effectively run a number of time a loop that waste 350 | cpu cycles. When the run event is executed with parameter t, the workload 351 | executed will be n loops of the calibration workload (pLoad in ns): 352 | n := floor (t * 1000 / pLoad) 353 | so, it might be running for a shorter amount of time. 354 | 355 | This way of working enables to emulate a fixed workload with a duration that 356 | will vary with the frequency or the compute capacity of the CPU. 357 | 358 | 359 | * runtime : Integer. The duration is define in usec. Similar to the 360 | run event, it emulates the execution of a load. Unlike run, runtime 361 | runs for a specific amount of time irrespective of the compute 362 | capacity of the CPU or the frequency. 363 | 364 | * sleep : Integer. Emulate the sleep of a task. The duration is defined in 365 | usec. 366 | 367 | * mem : Integer. Emulate the memory write operation. The value defines the size 368 | in byte to be written into the memory buffer. The size of the memory buffer is 369 | defined by "mem_buffer_size" in "global" object. 370 | 371 | * iorun : Integer. Emulate the IO write operation. The value defined the size 372 | in byte to be write into the IO device specified by "io_device" in "global" 373 | object. 374 | 375 | * timer : Object. Emulate the wake up of the thread by a timer. Timer differs 376 | from sleep event by the start time of the timer duration. Sleep duration starts 377 | at the beginning of the sleep event whereas timer duration starts at the end of 378 | the last use of the timer. So Timer event are immunized against preemption, 379 | frequency scaling and computing capacity of a CPU. The initial starting time of 380 | the timer is set during the 1st use of the latter. 381 | 382 | |<------19---------->|<------19---------->|<------19---------->| 383 | task A ...|run 5|timer 19 |------run 5|timer 19|run 5|timer 19 | 384 | task B |run 10 | 385 | 386 | 387 | As an example to point out the difference between sleep and timer, let consider 388 | a task A that run 5 and then sleep 10. The period of task A should be 15. 389 | Let's add a task B that runs 5 and use a timer to wakes up every 19. 390 | 391 | |<------15------>|<------15------>|<------19---------->|<------15------>|<------16------->|<------19---------->|<------19---------->|<------19---------->|<------19---------->|<------19---------->| 392 | taskA ...|run 5|sleep 10 |run 5|sleep 10 |----run 5|sleep 10 |run 5|sleep 10 |-run 5|sleep 10 |----run 5|sleep 10 |----run 5|sleep 10 |----run 5|sleep 10 |----run 5|sleep 10 |----run 5|sleep 10 | 393 | taskB ...|------run 5|timer 19|--run 5|timer 19 |run 5|timer 19 |run 5|timer 19 |run 5|timer 19 |run 5|timer 19 |run 5|timer 19 |run 5|timer 19 |run 5|timer 19 | 394 | |<------19---------->|<------19---------->|<------19---------->|<------19---------->|<------19---------->|<------19---------->|<------19---------->|<------19---------->|<------19---------->| 395 | 396 | We can see that task B period stays to 19 even if the run event is delayed 397 | because of scheduling preemption whereas the period of task A starts at 15 but 398 | increases to 19 because of the scheduling delay. 399 | 400 | "unique" timer device: When a thread that uses a timer is instantiated, the 401 | timer will be shared across the thread instance which disturbs the original 402 | sequence. In order to have 1 timer per instance, you can use the "unique" 403 | prefix so a new timer will be created for each instance. Uniqueness 404 | applies to the thread boundary which means that using the same unique 405 | name in the sequence of a thread will refer to the same timer like the example 406 | below: 407 | "phases" : { 408 | "light" : { 409 | "loop" : 10, 410 | "run" : 1000, 411 | "timer" : { "ref" : "unique", "period" : 30000 } 412 | }, 413 | "heavy" : { 414 | "loop" : 10, 415 | "run" : 4000, 416 | "timer" : { "ref" : "unique", "period" : 30000 } 417 | } 418 | } 419 | 420 | If you want to refer to different timer you must use different name like 421 | below: 422 | "phases" : { 423 | "light" : { 424 | "loop" : 10, 425 | "run" : 1000, 426 | "timer" : { "ref" : "uniqueA", "period" : 30000 } 427 | }, 428 | "heavy" : { 429 | "loop" : 10, 430 | "run" : 4000, 431 | "timer" : { "ref" : "uniqueB", "period" : 400000 } 432 | } 433 | } 434 | 435 | Timers can work with a "relative" or an "absolute" reference. By default they 436 | work in "relative" mode, but this mode can also be explicitly specified as the 437 | following: 438 | 439 | "phases" : { 440 | "phase0" : { 441 | "loop" : 10, 442 | "run0" : 10000, 443 | "timer0" : { "ref" : "unique", "period" : 20000, "mode" : "relative" }, 444 | } 445 | 446 | "relative" mode means that the reference for setting the next timer event is 447 | relative to the end of the current phase. This in turn means that if, for some 448 | reason (i.e., clock frequency was too low), events in a certain phase took too 449 | long to execute and the timer of that phase couldn't actually fire at all, the 450 | next phase won't be affected. For example: 451 | 452 | +---- + +-----+ +-------------------+-----+ +--- 453 | |r0 | |r0 | |r0 |r0 | |r0 454 | | | | | | | | | 455 | o-----------o-----------o-------------------o-----------o-------> 456 | 0 10 20 30 40 50 60 70 80 100 120 457 | ^ ^ ^ ^ 458 | | | | MISS! | 459 | + + + + 460 | Timer0 Timer0 Timer0 Timer0 461 | 462 | In this example character "o" denotes when phases finish/start. Third 463 | activation of Timer0 is missed, since r0 executed for more that 20ms. However 464 | the next phase is not affected as Timer0 was set considering the instant of 465 | time when the misbehaving r0 finished executing. 466 | 467 | "absolute" mode is specified as the following: 468 | 469 | "phases" : { 470 | "phase0" : { 471 | "loop" : 10, 472 | "run0" : 10000, 473 | "timer0" : { "ref" : "unique", "period" : 20000, "mode" : "absolute" }, 474 | } 475 | 476 | "absolute" mode means that the reference for setting the next timer event is 477 | fixed and always consider the starting time of the first phase. This means that 478 | if, for some reason (i.e., clock frequency was too low), events in a certain 479 | phase took too long to execute and the timer of that phase couldn't actually 480 | fire at all, the next phase (and potentially other subsequent phases) _will_ be 481 | affected. For example, considering again the example above: 482 | 483 | +---- + +-----+ +-------------------+-----+-----+ +--- 484 | |r0 | |r0 | |r0 |r0 |r0 | |r0 485 | | | | | | | | | | 486 | o-----------o-----------o-------------------o-----o---------o----> 487 | 0 10 20 30 40 50 60 70 80 100 120 488 | ^ ^ ^ ^ ^ 489 | | | | MISS! | MISS! | 490 | + + + + + 491 | Timer0 Timer0 Timer0 Timer0 Timer0 492 | 493 | Third activation of Timer0 is missed, since r0 executed for more that 20ms. 494 | Even if 4th activation of r0 executes for 10ms (as specified in the 495 | configuration), 4th Timer0 is still missed because the reference didn't change. 496 | In this example 5th activation of r0 then managed to recover, but in general it 497 | depends on how badly a certain phase misbehaves. 498 | 499 | * lock : String. Lock the mutex defined by the string value. 500 | 501 | * unlock : String. Unlock the mutex defined by the string value. 502 | 503 | * wait : Object {"ref" : String, "mutex" : String }. Block the calling thread 504 | until another thread sends a wake up signal to the resource defined by "ref". 505 | The mutex defined by "mutex" is used during the block sequence: See 506 | pthread_cond_wait() for more details about the sequence (especially regarding 507 | the use of the mutex). 508 | 509 | * signal : String. Send a wake up signal to the resource defined by the 510 | string. The 1st thread in the wait list will be wokn up. See 511 | pthread_cond_signal() for more details. 512 | 513 | * broad : String. Send a wake up signal to the resource defined by the 514 | string. All threads that are blocked on the resource wil wake up. See 515 | pthread_cond_broadcast() for more details. 516 | 517 | * sync : Object {"ref" : String, "mutex" : String }. Atomically wakes 518 | up a blocked thread and then blocks the calling thread on the condition. 519 | taskA ...|run 5|wait|------------|run 5| wait |---------------- 520 | taskB ...-------------------|sync|-------- 521 | 522 | The sync event "sync" : {"ref" : "CondA", "mutex" : "mutexA" } generates the 523 | following sequence: 524 | { 525 | "lock" : "mutexA", 526 | "signal" : "CondA", 527 | "wait" : { "ref" : "condA", "mutex" : "mutexA" }, 528 | "unlock" : "mutexA" 529 | } 530 | 531 | * barrier : String. Used as at least a pair where the name must match. 532 | Any number of matching uses will cause all threads hitting the barrier event 533 | to wait for a signal. The number of users is recorded, so that when the last user 534 | hits the barrier event, that thread will broadcast and continue to the next 535 | step. This is conceptually exactly the same as a pthread_barrier_wait operation 536 | however, using a pthread_barrier would impose some strict conditions on usage 537 | around thread cleanups - primarily that you cannot cancel an in-progress barrier 538 | operation which would mean that we have to restrict cleanup to only be possible 539 | at the end of a loop cycle (i.e. all phases are complete). This would be too 540 | restrictive for most uses so here we use an alternative. Finally, barrier can't 541 | be used with fork event because we must know how many threads will wait which 542 | is not possible with fork events. 543 | 544 | In this implementation, the barrier event manages its own mutex and uses a 545 | variable shared between users to track waiting tasks, protected by the mutex. 546 | 547 | You must use a unique name for each sync event since the number of users is 548 | taken from the number of references to the name in the input json. i.e. each 549 | name must represent a single sync point, and be shared amongst all threads 550 | which wish to synchronize at that point. 551 | 552 | The barrier event "barrier" : "SyncPointA" 553 | generates the following sequence: 554 | { 555 | "lock" : "SyncPointA" (internal mutex), 556 | If the shared variable is 0: 557 | "signal" : "SyncPointA" (internal condvar), 558 | Else: 559 | decrement the shared variable, 560 | "wait" : { "ref" : "SyncPointA" (internal condvar), 561 | "mutex" : "SyncPointA" (internal mutex) }, 562 | increment the shared variable, 563 | "unlock" : "SyncPointA" (internal mutex) 564 | } 565 | 566 | * suspend : String. Block the calling thread until another thread wakes it up 567 | with resume. String is ignored. 568 | 569 | * resume : String. Wake up the thread defined by the string. 570 | 571 | taskA ...|run 5|suspend |----------------|run 5|suspend |---------------- 572 | taskB ...-------------------|resume taskA|run 10 |-------------------- 573 | 574 | * yield: String. Calls pthread_yield(), freeing the CPU for other tasks. This has a 575 | special meaning for SCHED_DEADLINE tasks. String can be empty. 576 | 577 | * fork: String. Instead of creating all tasks at start time, you can fork one 578 | at any point of time using this event. The name of the forked task must match 579 | one of the defined tasks. 580 | 581 | **** Trace and Log **** 582 | 583 | Some traces and log hooks have been added to ease the debug and monitor various 584 | metrics of the use cases 585 | 586 | *** Trace *** 587 | 588 | A trace can be inserted into ftrace buffer for each event in order to sync 589 | kernel events like sched_switch with the use case's sequence. 590 | 591 | A simple example of ftrace log: 592 | 593 | rt-app-22165 [002] 105512.816244: print: tracking_mark_write: rtapp_main: event=start 594 | small_task-0-22166 [005] 105512.839499: print: tracking_mark_write: rtapp_main: event=clock_ref data=105512715874 595 | small_task-0-22166 [005] 105512.851733: print: tracking_mark_write: rtapp_task: event=start 596 | small_task-0-22166 [001] 105512.852153: print: tracking_mark_write: rtapp_loop: event=start thread_loop=0 phase=0 phase_loop=0 597 | small_task-0-22166 [001] 105512.852164: print: tracking_mark_write: rtapp_event: id=0 type=6 desc=run 598 | small_task-0-22166 [001] 105512.853565: print: tracking_mark_write: rtapp_event: id=1 type=10 desc=timer:small_task 599 | small_task-0-22166 [001] 105512.853585: print: tracking_mark_write: rtapp_loop: event=end thread_loop=0 phase=0 phase_loop=0 600 | small_task-0-22166 [001] 105512.853592: print: tracking_mark_write: rtapp_loop: event=start thread_loop=0 phase=0 phase_loop=1 601 | small_task-0-22166 [001] 105512.853600: print: tracking_mark_write: rtapp_event: id=0 type=6 desc=run 602 | small_task-0-22166 [001] 105512.854999: print: tracking_mark_write: rtapp_event: id=1 type=10 desc=timer:small_task 603 | big_task-1-22167 [000] 105512.855414: print: tracking_mark_write: rtapp_task: event=start 604 | big_task-1-22167 [001] 105512.855723: print: tracking_mark_write: rtapp_loop: event=start thread_loop=0 phase=0 phase_loop=0 605 | big_task-1-22167 [001] 105512.855732: print: tracking_mark_write: rtapp_event: id=0 type=6 desc=run 606 | big_task-1-22167 [001] 105512.862754: print: tracking_mark_write: rtapp_event: id=1 type=10 desc=timer:big_task 607 | big_task-1-22167 [001] 105512.862772: print: tracking_mark_write: rtapp_loop: event=end thread_loop=0 phase=0 phase_loop=0 608 | big_task-1-22167 [001] 105512.862779: print: tracking_mark_write: rtapp_loop: event=start thread_loop=0 phase=0 phase_loop=1 609 | big_task-1-22167 [001] 105512.862786: print: tracking_mark_write: rtapp_event: id=0 type=6 desc=run 610 | small_task-0-22166 [001] 105512.869674: print: tracking_mark_write: rtapp_loop: event=end thread_loop=0 phase=0 phase_loop=1 611 | [...] 612 | small_task-0-22166 [001] 105515.829685: print: tracking_mark_write: rtapp_task: event=end 613 | [...] 614 | big_task-1-22167 [001] 105515.838870: print: tracking_mark_write: rtapp_task: event=end 615 | rt-app-22165 [002] 105515.839357: print: tracking_mark_write: rtapp_main: event=end 616 | 617 | 618 | The rt-app task index is now encoded in the task name, which is reported at 619 | the beginning of each trace event following this template: 620 | 621 | -[-]- 622 | 623 | Where: 624 | - task_name : the name of a task as specified in the task definition 625 | - task_id : the ID of the task created by rt-app and matching its 626 | position into the JSON file 627 | - fork_id : the ID of the nth forked version of a task, this filed is optional 628 | and it's there only for forked tasks. 629 | - pid : the Linux assigned PID for this task 630 | 631 | The generated events are of these main categories: 632 | 633 | * Main task events, for example: 634 | 635 | - rtapp_main: event=start 636 | - rtapp_main: event=clock_ref data=105512715874 637 | - rtapp_main: event=end 638 | 639 | Reporting the start and end of the main thread. 640 | 641 | The additional "clock_ref" event back annotates in the trace the time 642 | reference used by the performance log entries generated by each task. 643 | 644 | * Workload tasks events, for example: 645 | 646 | - rtapp_task: event=start 647 | - rtapp_task: event=end 648 | 649 | Reporting the start end end of worker tasks. 650 | 651 | * Workload's loops events, for example: 652 | 653 | - rtapp_loop: event=start thread_loop=0 phase=0 phase_loop=0 654 | - rtapp_loop: event=end thread_loop=0 phase=0 phase_loop=0 655 | 656 | Reporting the start and end of workload's phases and loops. 657 | 658 | * Workload's events, for example: 659 | 660 | - rtapp_event: id=0 type=6 desc=run 661 | - rtapp_event: id=1 type=10 desc=timer:small_task 662 | 663 | Reporting the execution of the specified event type in the current phase/loop. 664 | 665 | * Workload's stats, for example: 666 | 667 | - rtapp_stats: period=3948 run=1378 wu_lat=95 slack=2454 c_run=16000 c_period=1600 668 | 669 | Reporting the major performance metrics measured after each workload 670 | activation. 671 | 672 | *** Log and gnuplot *** 673 | 674 | You can log some metrics for each phase that is executed by a thread. These 675 | metrics are: 676 | - perf: fixed amount of work performed during a phase (c_duration/calibration) 677 | (see events/run above) [number of 1000 loops, each pLoad] 678 | - run: time spent by the thread to execute the run events [us] 679 | - period: duration to execute the complete phase [us] 680 | - start/end : absolute start and end time of a phase. Same time base is used in 681 | ftrace 682 | - rel_st: start time of a phase relatively to the beg of the use case 683 | - slack: if global option "cumulative_slack" (see above) is false, time between 684 | the end of last event and the end of the phase, e.g. 685 | 686 | taskA ...|-- run5 --|- sleep5 -|-- run5--|..timer20.|-- run5 --|- sleep5 -|-- run6 --|.timer20.| 687 | <--------------- period 20 --------------> <--------------- period 20 --------------> 688 | <-slack5-> 689 | 690 | it can also be negative if the execution of a phases' events overshoots the 691 | current period, e.g. 692 | 693 | taskA ...|-- run5 --|- sleep5 -|------- run30 ------xxxxxxxxxx| 694 | <--------------- period 20 --------------> 695 | 696 | 697 | if global option "cumulative_slack" is true, all the intermediate slacks of a 698 | phase with multiple timers are accumulated and reported when the phase 699 | completes 700 | 701 | - c_duration: sum of the configured duration of run/runtime events [us] 702 | - c_period: sum of the timer(s) period(s) [us] 703 | - wu_lat: sum of wakeup latencies after timer events [us] 704 | 705 | Below is an extract of a log: 706 | 707 | # Policy : SCHED_OTHER priority : 0 708 | #idx perf run period start end rel_st slack c_duration c_period wu_lat 709 | 0 92164 19935 98965 504549567051 504549666016 2443 78701 20000 100000 266 710 | 0 92164 19408 99952 504549666063 504549766015 101455 80217 20000 100000 265 711 | 0 92164 19428 99952 504549766062 504549866014 201454 80199 20000 100000 264 712 | 0 92164 19438 99955 504549866060 504549966015 301452 80190 20000 100000 265 713 | 0 92164 19446 99952 504549966061 504550066013 401453 80093 20000 100000 264 714 | 0 92164 19415 99953 504550066060 504550166013 501452 80215 20000 100000 263 715 | 0 92164 19388 99954 504550166059 504550266013 601451 80242 20000 100000 264 716 | 0 92164 19444 99956 504550266060 504550366015 701452 80185 20000 100000 265 717 | 718 | Some gnuplot files are also created to generate charts based on the log files 719 | for each thread and for each kind of metrics. The format of the chart that 720 | will be generated by gnuplot is eps (text art has been used for the chart 721 | below) 722 | 723 | Measured thread0 Loop stats 724 | Load [nb loop] 725 | 120000 ++--+----+---+----+---+---+----+---+----+--++ 506000 load ****** 726 | + + + + + + + + + + + run ###### 727 | |$$ : : : : $$$ : : : : | period $$$$$$ 728 | 110000 ++.$$$........$$$$...$...$..........$$$.$$$$+ 729 | | : $$$$$$$$ $$ $: $ $$$$$$$$ $: $ 730 | | : : : : $ : :$ : : : ++ 504000 731 | | : : : : : : : : : | 732 | 100000 ++.........................................++ 733 | | : : : : : : : : : | 734 | | : : : : : : : : : | 735 | 90000 ++.........................................++ 736 | | : : : : : : : : : ++ 502000 737 | | : : : : : : : : : | 738 | 80000 ++.........................................++ 739 | | : : : : : : : : : | 740 | | : : : : : : : : : | 741 | 70000 +******************************************** 500000 742 | | : : : : : : : : : | 743 | | : : : : : : : : : | 744 | | : : : : : : : : : | 745 | 60000 ++.........................................++ 746 | | : : : : : : : : : | 747 | | : : : : : : : : : ++ 498000 748 | 50000 ++.........................................++ 749 | | : : : : : : : : : | 750 | | : : : : : : : : : | 751 | 40000 ++.........................................++ 752 | | : : : : : : : : : ++ 496000 753 | |# : : : : : : : : : | 754 | | # : : : : ### : : : : | 755 | 30000 ++.###.###....####...#...#..........###.####+ 756 | | : # :#### ### : # ######## #: # 757 | + + + + + + +# + + + + 758 | 20000 ++--+----+---+----+---+---+----+---+----+--++ 494000 759 | 17560556057560556057560656065606756065606756075607 760 | Loop start time [msec] 761 | 762 | 763 | --------------------------------------------------------------------------------