1f08c3bdfSopenharmony_ci/****************************************************************************** 2f08c3bdfSopenharmony_ci * 3f08c3bdfSopenharmony_ci * Copyright © International Business Machines Corp., 2007, 2008 4f08c3bdfSopenharmony_ci * 5f08c3bdfSopenharmony_ci * This program is free software; you can redistribute it and/or modify 6f08c3bdfSopenharmony_ci * it under the terms of the GNU General Public License as published by 7f08c3bdfSopenharmony_ci * the Free Software Foundation; either version 2 of the License, or 8f08c3bdfSopenharmony_ci * (at your option) any later version. 9f08c3bdfSopenharmony_ci * 10f08c3bdfSopenharmony_ci * This program is distributed in the hope that it will be useful, 11f08c3bdfSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 12f08c3bdfSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 13f08c3bdfSopenharmony_ci * the GNU General Public License for more details. 14f08c3bdfSopenharmony_ci * 15f08c3bdfSopenharmony_ci * You should have received a copy of the GNU General Public License 16f08c3bdfSopenharmony_ci * along with this program; if not, write to the Free Software 17f08c3bdfSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18f08c3bdfSopenharmony_ci * 19f08c3bdfSopenharmony_ci * NAME 20f08c3bdfSopenharmony_ci * hrtimer-prio.c 21f08c3bdfSopenharmony_ci * 22f08c3bdfSopenharmony_ci * DESCRIPTION 23f08c3bdfSopenharmony_ci * Test the latency of hrtimers under rt load. 24f08c3bdfSopenharmony_ci * The busy_threads should run at a priority higher than the system 25f08c3bdfSopenharmony_ci * softirq_hrtimer, but lower than the timer_thread. The timer_thread 26f08c3bdfSopenharmony_ci * measure the time it takes to return from a nanosleep call. If the 27f08c3bdfSopenharmony_ci * lower priority threads can increase the latency of the higher 28f08c3bdfSopenharmony_ci * priority thread, it is considered a failure. 29f08c3bdfSopenharmony_ci * 30f08c3bdfSopenharmony_ci * USAGE: 31f08c3bdfSopenharmony_ci * Use run_auto.sh script in current directory to build and run test. 32f08c3bdfSopenharmony_ci * 33f08c3bdfSopenharmony_ci * AUTHOR 34f08c3bdfSopenharmony_ci * Darren Hart <dvhltc@us.ibm.com> 35f08c3bdfSopenharmony_ci * 36f08c3bdfSopenharmony_ci * HISTORY 37f08c3bdfSopenharmony_ci * 2007-Aug-08: Initial version by Darren Hart <dvhltc@us.ibm.com> 38f08c3bdfSopenharmony_ci * 39f08c3bdfSopenharmony_ci * This line has to be added to avoid a stupid CVS problem 40f08c3bdfSopenharmony_ci *****************************************************************************/ 41f08c3bdfSopenharmony_ci 42f08c3bdfSopenharmony_ci#include <stdio.h> 43f08c3bdfSopenharmony_ci#include <stdlib.h> 44f08c3bdfSopenharmony_ci#include <math.h> 45f08c3bdfSopenharmony_ci#include <librttest.h> 46f08c3bdfSopenharmony_ci#include <libstats.h> 47f08c3bdfSopenharmony_ci 48f08c3bdfSopenharmony_ci#define DEF_MED_PRIO 60 // (softirqd-hrtimer,98) 49f08c3bdfSopenharmony_ci#define DEF_ITERATIONS 10000 50f08c3bdfSopenharmony_ci#define HIST_BUCKETS 100 51f08c3bdfSopenharmony_ci#define DEF_BUSY_TIME 10 // Duration of busy work in milliseconds 52f08c3bdfSopenharmony_ci#define DEF_SLEEP_TIME 10000 // Duration of nanosleep in nanoseconds 53f08c3bdfSopenharmony_ci#define DEF_CRITERIA 10 // maximum timer latency in microseconds 54f08c3bdfSopenharmony_ci 55f08c3bdfSopenharmony_cistatic int med_prio = DEF_MED_PRIO; 56f08c3bdfSopenharmony_cistatic int high_prio; 57f08c3bdfSopenharmony_cistatic int busy_time = DEF_BUSY_TIME; 58f08c3bdfSopenharmony_cistatic int iterations = DEF_ITERATIONS; 59f08c3bdfSopenharmony_cistatic int busy_threads; 60f08c3bdfSopenharmony_ci 61f08c3bdfSopenharmony_cistatic stats_container_t dat; 62f08c3bdfSopenharmony_cistatic stats_record_t rec; 63f08c3bdfSopenharmony_cistatic atomic_t busy_threads_started; 64f08c3bdfSopenharmony_cistatic unsigned long min_delta; 65f08c3bdfSopenharmony_cistatic unsigned long max_delta; 66f08c3bdfSopenharmony_ci 67f08c3bdfSopenharmony_civoid usage(void) 68f08c3bdfSopenharmony_ci{ 69f08c3bdfSopenharmony_ci rt_help(); 70f08c3bdfSopenharmony_ci printf("hrtimer-prio specific options:\n"); 71f08c3bdfSopenharmony_ci printf(" -t# #:busy work time in ms, defaults to %d ms\n", 72f08c3bdfSopenharmony_ci DEF_BUSY_TIME); 73f08c3bdfSopenharmony_ci printf(" -i# #:number of iterations, defaults to %d\n", 74f08c3bdfSopenharmony_ci DEF_ITERATIONS); 75f08c3bdfSopenharmony_ci printf(" -n# #:number of busy threads, defaults to NR_CPUS*2\n"); 76f08c3bdfSopenharmony_ci printf 77f08c3bdfSopenharmony_ci (" -f# #:rt fifo priority of busy threads (1,98), defaults to %d\n", 78f08c3bdfSopenharmony_ci DEF_MED_PRIO); 79f08c3bdfSopenharmony_ci} 80f08c3bdfSopenharmony_ci 81f08c3bdfSopenharmony_ciint parse_args(int c, char *v) 82f08c3bdfSopenharmony_ci{ 83f08c3bdfSopenharmony_ci 84f08c3bdfSopenharmony_ci int handled = 1; 85f08c3bdfSopenharmony_ci switch (c) { 86f08c3bdfSopenharmony_ci case 'h': 87f08c3bdfSopenharmony_ci usage(); 88f08c3bdfSopenharmony_ci exit(0); 89f08c3bdfSopenharmony_ci case 't': 90f08c3bdfSopenharmony_ci busy_time = atoi(v); 91f08c3bdfSopenharmony_ci break; 92f08c3bdfSopenharmony_ci case 'n': 93f08c3bdfSopenharmony_ci busy_threads = atoi(v); 94f08c3bdfSopenharmony_ci break; 95f08c3bdfSopenharmony_ci case 'f': 96f08c3bdfSopenharmony_ci med_prio = MIN(atoi(v), 98); 97f08c3bdfSopenharmony_ci break; 98f08c3bdfSopenharmony_ci case 'i': 99f08c3bdfSopenharmony_ci iterations = atoi(v); 100f08c3bdfSopenharmony_ci if (iterations < 100) { 101f08c3bdfSopenharmony_ci fprintf(stderr, 102f08c3bdfSopenharmony_ci "Number of iterations cannot be less than 100.\n"); 103f08c3bdfSopenharmony_ci exit(1); 104f08c3bdfSopenharmony_ci } 105f08c3bdfSopenharmony_ci break; 106f08c3bdfSopenharmony_ci default: 107f08c3bdfSopenharmony_ci handled = 0; 108f08c3bdfSopenharmony_ci break; 109f08c3bdfSopenharmony_ci } 110f08c3bdfSopenharmony_ci return handled; 111f08c3bdfSopenharmony_ci} 112f08c3bdfSopenharmony_ci 113f08c3bdfSopenharmony_civoid *busy_thread(void *thread) 114f08c3bdfSopenharmony_ci{ 115f08c3bdfSopenharmony_ci atomic_inc(&busy_threads_started); 116f08c3bdfSopenharmony_ci while (1) { 117f08c3bdfSopenharmony_ci busy_work_ms(busy_time); 118f08c3bdfSopenharmony_ci sched_yield(); 119f08c3bdfSopenharmony_ci } 120f08c3bdfSopenharmony_ci return NULL; 121f08c3bdfSopenharmony_ci} 122f08c3bdfSopenharmony_ci 123f08c3bdfSopenharmony_civoid *timer_thread(void *thread) 124f08c3bdfSopenharmony_ci{ 125f08c3bdfSopenharmony_ci int i; 126f08c3bdfSopenharmony_ci nsec_t start, end; 127f08c3bdfSopenharmony_ci unsigned long delta_us; 128f08c3bdfSopenharmony_ci while (atomic_get(&busy_threads_started) < busy_threads) { 129f08c3bdfSopenharmony_ci rt_nanosleep(10000); 130f08c3bdfSopenharmony_ci } 131f08c3bdfSopenharmony_ci printf("All Busy Threads started, commencing test\n"); // FIXME: use debug infrastructure 132f08c3bdfSopenharmony_ci max_delta = 0; 133f08c3bdfSopenharmony_ci for (i = 0; i < iterations; i++) { 134f08c3bdfSopenharmony_ci start = rt_gettime(); 135f08c3bdfSopenharmony_ci rt_nanosleep(DEF_SLEEP_TIME); 136f08c3bdfSopenharmony_ci end = rt_gettime(); 137f08c3bdfSopenharmony_ci delta_us = 138f08c3bdfSopenharmony_ci ((unsigned long)(end - start) - DEF_SLEEP_TIME) / NS_PER_US; 139f08c3bdfSopenharmony_ci rec.x = i; 140f08c3bdfSopenharmony_ci rec.y = delta_us; 141f08c3bdfSopenharmony_ci stats_container_append(&dat, rec); 142f08c3bdfSopenharmony_ci max_delta = MAX(max_delta, delta_us); 143f08c3bdfSopenharmony_ci min_delta = (i == 0) ? delta_us : MIN(min_delta, delta_us); 144f08c3bdfSopenharmony_ci } 145f08c3bdfSopenharmony_ci return NULL; 146f08c3bdfSopenharmony_ci} 147f08c3bdfSopenharmony_ci 148f08c3bdfSopenharmony_ciint main(int argc, char *argv[]) 149f08c3bdfSopenharmony_ci{ 150f08c3bdfSopenharmony_ci int ret = 1; 151f08c3bdfSopenharmony_ci int b; 152f08c3bdfSopenharmony_ci float avg_delta; 153f08c3bdfSopenharmony_ci int t_id; 154f08c3bdfSopenharmony_ci setup(); 155f08c3bdfSopenharmony_ci busy_threads = 2 * sysconf(_SC_NPROCESSORS_ONLN); // default busy_threads 156f08c3bdfSopenharmony_ci pass_criteria = DEF_CRITERIA; 157f08c3bdfSopenharmony_ci rt_init("f:i:jhn:t:", parse_args, argc, argv); 158f08c3bdfSopenharmony_ci high_prio = med_prio + 1; 159f08c3bdfSopenharmony_ci 160f08c3bdfSopenharmony_ci // Set main()'s prio to one above the timer_thread so it is sure to not 161f08c3bdfSopenharmony_ci // be starved 162f08c3bdfSopenharmony_ci if (set_priority(high_prio + 1) < 0) { 163f08c3bdfSopenharmony_ci printf("Failed to set main()'s priority to %d\n", 164f08c3bdfSopenharmony_ci high_prio + 1); 165f08c3bdfSopenharmony_ci exit(1); 166f08c3bdfSopenharmony_ci } 167f08c3bdfSopenharmony_ci 168f08c3bdfSopenharmony_ci printf("\n-------------------------------------------\n"); 169f08c3bdfSopenharmony_ci printf("High Resolution Timer Priority (Starvation)\n"); 170f08c3bdfSopenharmony_ci printf("-------------------------------------------\n\n"); 171f08c3bdfSopenharmony_ci printf("Running %d iterations\n", iterations); 172f08c3bdfSopenharmony_ci printf("Running with %d busy threads\n", busy_threads); 173f08c3bdfSopenharmony_ci printf("Busy thread work time: %d\n", busy_time); 174f08c3bdfSopenharmony_ci printf("Busy thread priority: %d\n", med_prio); 175f08c3bdfSopenharmony_ci printf("Timer thread priority: %d\n", high_prio); 176f08c3bdfSopenharmony_ci 177f08c3bdfSopenharmony_ci stats_container_t hist; 178f08c3bdfSopenharmony_ci stats_quantiles_t quantiles; 179f08c3bdfSopenharmony_ci if (stats_container_init(&dat, iterations)) { 180f08c3bdfSopenharmony_ci printf("Cannot init stat containers for dat\n"); 181f08c3bdfSopenharmony_ci exit(1); 182f08c3bdfSopenharmony_ci } 183f08c3bdfSopenharmony_ci if (stats_container_init(&hist, HIST_BUCKETS)) { 184f08c3bdfSopenharmony_ci printf("Cannot init stat containers for hist\n"); 185f08c3bdfSopenharmony_ci exit(1); 186f08c3bdfSopenharmony_ci } 187f08c3bdfSopenharmony_ci if (stats_quantiles_init(&quantiles, (int)log10(iterations))) { 188f08c3bdfSopenharmony_ci printf("Cannot init stat quantiles\n"); 189f08c3bdfSopenharmony_ci exit(1); 190f08c3bdfSopenharmony_ci } 191f08c3bdfSopenharmony_ci 192f08c3bdfSopenharmony_ci t_id = create_fifo_thread(timer_thread, NULL, high_prio); 193f08c3bdfSopenharmony_ci if (t_id == -1) { 194f08c3bdfSopenharmony_ci printf("Failed to create timer thread\n"); 195f08c3bdfSopenharmony_ci exit(1); 196f08c3bdfSopenharmony_ci } 197f08c3bdfSopenharmony_ci for (b = 0; b < busy_threads; b++) { 198f08c3bdfSopenharmony_ci if (create_fifo_thread(busy_thread, NULL, med_prio) < 0) { 199f08c3bdfSopenharmony_ci printf("Failed to create a busy thread\n"); 200f08c3bdfSopenharmony_ci exit(1); 201f08c3bdfSopenharmony_ci } 202f08c3bdfSopenharmony_ci } 203f08c3bdfSopenharmony_ci join_thread(t_id); 204f08c3bdfSopenharmony_ci 205f08c3bdfSopenharmony_ci avg_delta = stats_avg(&dat); 206f08c3bdfSopenharmony_ci stats_hist(&hist, &dat); 207f08c3bdfSopenharmony_ci stats_container_save("samples", 208f08c3bdfSopenharmony_ci "High Resolution Timer Latency Scatter Plot", 209f08c3bdfSopenharmony_ci "Iteration", "Latency (us)", &dat, "points"); 210f08c3bdfSopenharmony_ci stats_container_save("hist", "High Resolution Timer Latency Histogram", 211f08c3bdfSopenharmony_ci "Latency (us)", "Samples", &hist, "steps"); 212f08c3bdfSopenharmony_ci 213f08c3bdfSopenharmony_ci if (max_delta <= pass_criteria) 214f08c3bdfSopenharmony_ci ret = 0; 215f08c3bdfSopenharmony_ci 216f08c3bdfSopenharmony_ci printf("Minimum: %ld us\n", min_delta); 217f08c3bdfSopenharmony_ci printf("Maximum: %ld us\n", max_delta); 218f08c3bdfSopenharmony_ci printf("Average: %f us\n", avg_delta); 219f08c3bdfSopenharmony_ci printf("Standard Deviation: %f\n", stats_stddev(&dat)); 220f08c3bdfSopenharmony_ci printf("Quantiles:\n"); 221f08c3bdfSopenharmony_ci stats_quantiles_calc(&dat, &quantiles); 222f08c3bdfSopenharmony_ci stats_quantiles_print(&quantiles); 223f08c3bdfSopenharmony_ci printf("\nCriteria: Maximum wakeup latency < %lu us\n", 224f08c3bdfSopenharmony_ci (unsigned long)pass_criteria); 225f08c3bdfSopenharmony_ci printf("Result: %s\n", ret ? "FAIL" : "PASS"); 226f08c3bdfSopenharmony_ci 227f08c3bdfSopenharmony_ci return ret; 228f08c3bdfSopenharmony_ci} 229