1f08c3bdfSopenharmony_ci/****************************************************************************** 2f08c3bdfSopenharmony_ci * 3f08c3bdfSopenharmony_ci * Copyright © International Business Machines Corp., 2006-2008 4f08c3bdfSopenharmony_ci * 5f08c3bdfSopenharmony_ci * This program is free software; you can redistribute it and/or modify 6f08c3bdfSopenharmony_ci * it under the terms of the GNU General Public License as published by 7f08c3bdfSopenharmony_ci * the Free Software Foundation; either version 2 of the License, or 8f08c3bdfSopenharmony_ci * (at your option) any later version. 9f08c3bdfSopenharmony_ci * 10f08c3bdfSopenharmony_ci * This program is distributed in the hope that it will be useful, 11f08c3bdfSopenharmony_ci * but WITHOUT ANY WARRANTY; without even the implied warranty of 12f08c3bdfSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 13f08c3bdfSopenharmony_ci * the GNU General Public License for more details. 14f08c3bdfSopenharmony_ci * 15f08c3bdfSopenharmony_ci * You should have received a copy of the GNU General Public License 16f08c3bdfSopenharmony_ci * along with this program; if not, write to the Free Software 17f08c3bdfSopenharmony_ci * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18f08c3bdfSopenharmony_ci * 19f08c3bdfSopenharmony_ci * NAME 20f08c3bdfSopenharmony_ci * sched_latency.c 21f08c3bdfSopenharmony_ci * 22f08c3bdfSopenharmony_ci * DESCRIPTION 23f08c3bdfSopenharmony_ci * Measure the latency involved with periodic scheduling. 24f08c3bdfSopenharmony_ci * Steps: 25f08c3bdfSopenharmony_ci * - A thread is created at a priority of 89. 26f08c3bdfSopenharmony_ci * - It periodically sleeps for a specified duration(period). 27f08c3bdfSopenharmony_ci * - The delay is measured as 28f08c3bdfSopenharmony_ci * 29f08c3bdfSopenharmony_ci * delay = (now - start - i*period) converted to microseconds 30f08c3bdfSopenharmony_ci * 31f08c3bdfSopenharmony_ci * where, 32f08c3bdfSopenharmony_ci * now = CLOCK_MONOTONIC gettime in ns, start = CLOCK_MONOTONIC gettime 33f08c3bdfSopenharmony_ci * at the start of the test, i = iteration number, period = period chosen 34f08c3bdfSopenharmony_ci * 35f08c3bdfSopenharmony_ci * USAGE: 36f08c3bdfSopenharmony_ci * Use run_auto.sh script in current directory to build and run test. 37f08c3bdfSopenharmony_ci * 38f08c3bdfSopenharmony_ci * AUTHOR 39f08c3bdfSopenharmony_ci * Darren Hart <dvhltc@us.ibm.com> 40f08c3bdfSopenharmony_ci * 41f08c3bdfSopenharmony_ci * HISTORY 42f08c3bdfSopenharmony_ci * 2006-May-10: Initial version by Darren Hart <dvhltc@us.ibm.com> 43f08c3bdfSopenharmony_ci * 2007-Jul-11: Quantiles added by Josh Triplett <josh@kernel.org> 44f08c3bdfSopenharmony_ci * 2007-Jul-12: Latency tracing added by Josh Triplett <josh@kernel.org> 45f08c3bdfSopenharmony_ci * 46f08c3bdfSopenharmony_ci * This line has to be added to avoid a stupid CVS problem 47f08c3bdfSopenharmony_ci *****************************************************************************/ 48f08c3bdfSopenharmony_ci 49f08c3bdfSopenharmony_ci#include <stdio.h> 50f08c3bdfSopenharmony_ci#include <stdlib.h> 51f08c3bdfSopenharmony_ci#include <math.h> 52f08c3bdfSopenharmony_ci#include <librttest.h> 53f08c3bdfSopenharmony_ci#include <libstats.h> 54f08c3bdfSopenharmony_ci 55f08c3bdfSopenharmony_ci#define PRIO 89 56f08c3bdfSopenharmony_ci//#define PERIOD 17*NS_PER_MS 57f08c3bdfSopenharmony_ci//#define ITERATIONS 100 58f08c3bdfSopenharmony_ci#define MIN_ITERATIONS 100 59f08c3bdfSopenharmony_ci#define DEFAULT_ITERATIONS 10000 60f08c3bdfSopenharmony_ci#define DEF_PERIOD 5*NS_PER_MS 61f08c3bdfSopenharmony_ci#define DEF_LOAD_MS 1 62f08c3bdfSopenharmony_ci#define PASS_US 100 63f08c3bdfSopenharmony_ci#define HIST_BUCKETS 100 64f08c3bdfSopenharmony_ci#define OVERHEAD 50000 // allow for 50 us of periodic overhead (context switch, etc.) 65f08c3bdfSopenharmony_ci 66f08c3bdfSopenharmony_cinsec_t start; 67f08c3bdfSopenharmony_cinsec_t end; 68f08c3bdfSopenharmony_cistatic int ret = 0; 69f08c3bdfSopenharmony_cistatic int iterations = 0; 70f08c3bdfSopenharmony_cistatic unsigned long long latency_threshold = 0; 71f08c3bdfSopenharmony_cistatic nsec_t period = DEF_PERIOD; 72f08c3bdfSopenharmony_cistatic unsigned int load_ms = DEF_LOAD_MS; 73f08c3bdfSopenharmony_ci 74f08c3bdfSopenharmony_cistats_container_t dat; 75f08c3bdfSopenharmony_cistats_container_t hist; 76f08c3bdfSopenharmony_cistats_quantiles_t quantiles; 77f08c3bdfSopenharmony_cistats_record_t rec; 78f08c3bdfSopenharmony_ci 79f08c3bdfSopenharmony_civoid usage(void) 80f08c3bdfSopenharmony_ci{ 81f08c3bdfSopenharmony_ci rt_help(); 82f08c3bdfSopenharmony_ci printf("sched_latency specific options:\n"); 83f08c3bdfSopenharmony_ci printf(" -dLOAD periodic load in ms (default 1)\n"); 84f08c3bdfSopenharmony_ci printf(" -lTHRESHOLD trace latency, with given threshold in us\n"); 85f08c3bdfSopenharmony_ci printf(" -tPERIOD period in ms (default 5)\n"); 86f08c3bdfSopenharmony_ci printf(" -iITERATIONS number of iterations (default %d)\n", 87f08c3bdfSopenharmony_ci DEFAULT_ITERATIONS); 88f08c3bdfSopenharmony_ci} 89f08c3bdfSopenharmony_ci 90f08c3bdfSopenharmony_ciint parse_args(int c, char *v) 91f08c3bdfSopenharmony_ci{ 92f08c3bdfSopenharmony_ci 93f08c3bdfSopenharmony_ci int handled = 1; 94f08c3bdfSopenharmony_ci switch (c) { 95f08c3bdfSopenharmony_ci case 'h': 96f08c3bdfSopenharmony_ci usage(); 97f08c3bdfSopenharmony_ci exit(0); 98f08c3bdfSopenharmony_ci case 'd': 99f08c3bdfSopenharmony_ci load_ms = atoi(v); 100f08c3bdfSopenharmony_ci break; 101f08c3bdfSopenharmony_ci case 'i': 102f08c3bdfSopenharmony_ci iterations = atoi(v); 103f08c3bdfSopenharmony_ci break; 104f08c3bdfSopenharmony_ci case 'l': 105f08c3bdfSopenharmony_ci latency_threshold = strtoull(v, NULL, 0); 106f08c3bdfSopenharmony_ci break; 107f08c3bdfSopenharmony_ci case 't': 108f08c3bdfSopenharmony_ci period = strtoull(v, NULL, 0) * NS_PER_MS; 109f08c3bdfSopenharmony_ci break; 110f08c3bdfSopenharmony_ci default: 111f08c3bdfSopenharmony_ci handled = 0; 112f08c3bdfSopenharmony_ci break; 113f08c3bdfSopenharmony_ci } 114f08c3bdfSopenharmony_ci return handled; 115f08c3bdfSopenharmony_ci} 116f08c3bdfSopenharmony_ci 117f08c3bdfSopenharmony_civoid *periodic_thread(void *arg) 118f08c3bdfSopenharmony_ci{ 119f08c3bdfSopenharmony_ci int i; 120f08c3bdfSopenharmony_ci nsec_t delay, avg_delay = 0, start_delay, min_delay = -1ULL, max_delay = 121f08c3bdfSopenharmony_ci 0; 122f08c3bdfSopenharmony_ci int failures = 0; 123f08c3bdfSopenharmony_ci nsec_t next = 0, now = 0, sched_delta = 0, delta = 0, prev = 124f08c3bdfSopenharmony_ci 0, iter_start; 125f08c3bdfSopenharmony_ci 126f08c3bdfSopenharmony_ci /* wait for the specified start time */ 127f08c3bdfSopenharmony_ci rt_nanosleep_until(start); 128f08c3bdfSopenharmony_ci 129f08c3bdfSopenharmony_ci now = rt_gettime(); 130f08c3bdfSopenharmony_ci start_delay = (now - start) / NS_PER_US; 131f08c3bdfSopenharmony_ci iter_start = next = now; 132f08c3bdfSopenharmony_ci 133f08c3bdfSopenharmony_ci debug(DBG_INFO, "ITERATION DELAY(US) MAX_DELAY(US) FAILURES\n"); 134f08c3bdfSopenharmony_ci debug(DBG_INFO, "--------- --------- ------------- --------\n"); 135f08c3bdfSopenharmony_ci 136f08c3bdfSopenharmony_ci if (latency_threshold) { 137f08c3bdfSopenharmony_ci latency_trace_enable(); 138f08c3bdfSopenharmony_ci latency_trace_start(); 139f08c3bdfSopenharmony_ci } 140f08c3bdfSopenharmony_ci for (i = 0; i < iterations; i++) { 141f08c3bdfSopenharmony_ci /* wait for the period to start */ 142f08c3bdfSopenharmony_ci next += period; 143f08c3bdfSopenharmony_ci prev = now; 144f08c3bdfSopenharmony_ci now = rt_gettime(); 145f08c3bdfSopenharmony_ci 146f08c3bdfSopenharmony_ci if (next < now) { 147f08c3bdfSopenharmony_ci printf("\nPERIOD MISSED!\n"); 148f08c3bdfSopenharmony_ci printf(" scheduled delta: %8llu us\n", 149f08c3bdfSopenharmony_ci sched_delta / 1000); 150f08c3bdfSopenharmony_ci printf(" actual delta: %8llu us\n", 151f08c3bdfSopenharmony_ci delta / 1000); 152f08c3bdfSopenharmony_ci printf(" latency: %8llu us\n", 153f08c3bdfSopenharmony_ci (delta - sched_delta) / 1000); 154f08c3bdfSopenharmony_ci printf("---------------------------------------\n"); 155f08c3bdfSopenharmony_ci printf(" previous start: %8llu us\n", 156f08c3bdfSopenharmony_ci (prev - iter_start) / 1000); 157f08c3bdfSopenharmony_ci printf(" now: %8llu us\n", 158f08c3bdfSopenharmony_ci (now - iter_start) / 1000); 159f08c3bdfSopenharmony_ci printf(" scheduled start: %8llu us\n", 160f08c3bdfSopenharmony_ci (next - iter_start) / 1000); 161f08c3bdfSopenharmony_ci printf("next scheduled start is in the past!\n"); 162f08c3bdfSopenharmony_ci ret = 1; 163f08c3bdfSopenharmony_ci break; 164f08c3bdfSopenharmony_ci } 165f08c3bdfSopenharmony_ci 166f08c3bdfSopenharmony_ci sched_delta = next - now; /* how long we should sleep */ 167f08c3bdfSopenharmony_ci delta = 0; 168f08c3bdfSopenharmony_ci do { 169f08c3bdfSopenharmony_ci nsec_t new_now; 170f08c3bdfSopenharmony_ci 171f08c3bdfSopenharmony_ci rt_nanosleep(next - now); 172f08c3bdfSopenharmony_ci new_now = rt_gettime(); 173f08c3bdfSopenharmony_ci delta += new_now - now; /* how long we did sleep */ 174f08c3bdfSopenharmony_ci now = new_now; 175f08c3bdfSopenharmony_ci } while (now < next); 176f08c3bdfSopenharmony_ci 177f08c3bdfSopenharmony_ci /* start of period */ 178f08c3bdfSopenharmony_ci delay = 179f08c3bdfSopenharmony_ci (now - iter_start - (nsec_t) (i + 1) * period) / NS_PER_US; 180f08c3bdfSopenharmony_ci rec.x = i; 181f08c3bdfSopenharmony_ci rec.y = delay; 182f08c3bdfSopenharmony_ci stats_container_append(&dat, rec); 183f08c3bdfSopenharmony_ci 184f08c3bdfSopenharmony_ci if (delay < min_delay) 185f08c3bdfSopenharmony_ci min_delay = delay; 186f08c3bdfSopenharmony_ci if (delay > max_delay) 187f08c3bdfSopenharmony_ci max_delay = delay; 188f08c3bdfSopenharmony_ci if (delay > pass_criteria) { 189f08c3bdfSopenharmony_ci failures++; 190f08c3bdfSopenharmony_ci ret = 1; 191f08c3bdfSopenharmony_ci } 192f08c3bdfSopenharmony_ci avg_delay += delay; 193f08c3bdfSopenharmony_ci if (latency_threshold && delay > latency_threshold) 194f08c3bdfSopenharmony_ci break; 195f08c3bdfSopenharmony_ci 196f08c3bdfSopenharmony_ci /* continuous status ticker */ 197f08c3bdfSopenharmony_ci debug(DBG_INFO, "%9i %9llu %13llu %8i\r", i, delay, max_delay, 198f08c3bdfSopenharmony_ci failures); 199f08c3bdfSopenharmony_ci fflush(stdout); 200f08c3bdfSopenharmony_ci 201f08c3bdfSopenharmony_ci busy_work_ms(load_ms); 202f08c3bdfSopenharmony_ci } 203f08c3bdfSopenharmony_ci if (latency_threshold) { 204f08c3bdfSopenharmony_ci latency_trace_stop(); 205f08c3bdfSopenharmony_ci if (i != iterations) { 206f08c3bdfSopenharmony_ci printf 207f08c3bdfSopenharmony_ci ("Latency threshold (%lluus) exceeded at iteration %d\n", 208f08c3bdfSopenharmony_ci latency_threshold, i); 209f08c3bdfSopenharmony_ci latency_trace_print(); 210f08c3bdfSopenharmony_ci stats_container_resize(&dat, i + 1); 211f08c3bdfSopenharmony_ci } 212f08c3bdfSopenharmony_ci } 213f08c3bdfSopenharmony_ci 214f08c3bdfSopenharmony_ci /* save samples before the quantile calculation messes things up! */ 215f08c3bdfSopenharmony_ci stats_hist(&hist, &dat); 216f08c3bdfSopenharmony_ci stats_container_save("samples", 217f08c3bdfSopenharmony_ci "Periodic Scheduling Latency Scatter Plot", 218f08c3bdfSopenharmony_ci "Iteration", "Latency (us)", &dat, "points"); 219f08c3bdfSopenharmony_ci stats_container_save("hist", "Periodic Scheduling Latency Histogram", 220f08c3bdfSopenharmony_ci "Latency (us)", "Samples", &hist, "steps"); 221f08c3bdfSopenharmony_ci 222f08c3bdfSopenharmony_ci avg_delay /= i; 223f08c3bdfSopenharmony_ci printf("\n\n"); 224f08c3bdfSopenharmony_ci printf("Start: %4llu us: %s\n", start_delay, 225f08c3bdfSopenharmony_ci start_delay < pass_criteria ? "PASS" : "FAIL"); 226f08c3bdfSopenharmony_ci printf("Min: %4llu us: %s\n", min_delay, 227f08c3bdfSopenharmony_ci min_delay < pass_criteria ? "PASS" : "FAIL"); 228f08c3bdfSopenharmony_ci printf("Max: %4llu us: %s\n", max_delay, 229f08c3bdfSopenharmony_ci max_delay < pass_criteria ? "PASS" : "FAIL"); 230f08c3bdfSopenharmony_ci printf("Avg: %4llu us: %s\n", avg_delay, 231f08c3bdfSopenharmony_ci avg_delay < pass_criteria ? "PASS" : "FAIL"); 232f08c3bdfSopenharmony_ci printf("StdDev: %.4f us\n", stats_stddev(&dat)); 233f08c3bdfSopenharmony_ci printf("Quantiles:\n"); 234f08c3bdfSopenharmony_ci stats_quantiles_calc(&dat, &quantiles); 235f08c3bdfSopenharmony_ci stats_quantiles_print(&quantiles); 236f08c3bdfSopenharmony_ci printf("Failed Iterations: %d\n", failures); 237f08c3bdfSopenharmony_ci 238f08c3bdfSopenharmony_ci return NULL; 239f08c3bdfSopenharmony_ci} 240f08c3bdfSopenharmony_ci 241f08c3bdfSopenharmony_ciint main(int argc, char *argv[]) 242f08c3bdfSopenharmony_ci{ 243f08c3bdfSopenharmony_ci int per_id; 244f08c3bdfSopenharmony_ci setup(); 245f08c3bdfSopenharmony_ci 246f08c3bdfSopenharmony_ci pass_criteria = PASS_US; 247f08c3bdfSopenharmony_ci rt_init("d:l:ht:i:", parse_args, argc, argv); 248f08c3bdfSopenharmony_ci 249f08c3bdfSopenharmony_ci printf("-------------------------------\n"); 250f08c3bdfSopenharmony_ci printf("Scheduling Latency\n"); 251f08c3bdfSopenharmony_ci printf("-------------------------------\n\n"); 252f08c3bdfSopenharmony_ci 253f08c3bdfSopenharmony_ci if (load_ms * NS_PER_MS >= period - OVERHEAD) { 254f08c3bdfSopenharmony_ci printf("ERROR: load must be < period - %d us\n", 255f08c3bdfSopenharmony_ci OVERHEAD / NS_PER_US); 256f08c3bdfSopenharmony_ci exit(1); 257f08c3bdfSopenharmony_ci } 258f08c3bdfSopenharmony_ci 259f08c3bdfSopenharmony_ci if (iterations == 0) 260f08c3bdfSopenharmony_ci iterations = DEFAULT_ITERATIONS; 261f08c3bdfSopenharmony_ci if (iterations < MIN_ITERATIONS) { 262f08c3bdfSopenharmony_ci printf 263f08c3bdfSopenharmony_ci ("Too few iterations (%d), use min iteration instead (%d)\n", 264f08c3bdfSopenharmony_ci iterations, MIN_ITERATIONS); 265f08c3bdfSopenharmony_ci iterations = MIN_ITERATIONS; 266f08c3bdfSopenharmony_ci } 267f08c3bdfSopenharmony_ci 268f08c3bdfSopenharmony_ci printf("Running %d iterations with a period of %llu ms\n", iterations, 269f08c3bdfSopenharmony_ci period / NS_PER_MS); 270f08c3bdfSopenharmony_ci printf("Periodic load duration: %d ms\n", load_ms); 271f08c3bdfSopenharmony_ci printf("Expected running time: %d s\n", 272f08c3bdfSopenharmony_ci (int)(iterations * ((float)period / NS_PER_SEC))); 273f08c3bdfSopenharmony_ci 274f08c3bdfSopenharmony_ci if (stats_container_init(&dat, iterations)) 275f08c3bdfSopenharmony_ci exit(1); 276f08c3bdfSopenharmony_ci 277f08c3bdfSopenharmony_ci if (stats_container_init(&hist, HIST_BUCKETS)) { 278f08c3bdfSopenharmony_ci stats_container_free(&dat); 279f08c3bdfSopenharmony_ci exit(1); 280f08c3bdfSopenharmony_ci } 281f08c3bdfSopenharmony_ci 282f08c3bdfSopenharmony_ci /* use the highest value for the quantiles */ 283f08c3bdfSopenharmony_ci if (stats_quantiles_init(&quantiles, (int)log10(iterations))) { 284f08c3bdfSopenharmony_ci stats_container_free(&hist); 285f08c3bdfSopenharmony_ci stats_container_free(&dat); 286f08c3bdfSopenharmony_ci exit(1); 287f08c3bdfSopenharmony_ci } 288f08c3bdfSopenharmony_ci 289f08c3bdfSopenharmony_ci /* wait one quarter second to execute */ 290f08c3bdfSopenharmony_ci start = rt_gettime() + 250 * NS_PER_MS; 291f08c3bdfSopenharmony_ci per_id = create_fifo_thread(periodic_thread, NULL, PRIO); 292f08c3bdfSopenharmony_ci 293f08c3bdfSopenharmony_ci join_thread(per_id); 294f08c3bdfSopenharmony_ci join_threads(); 295f08c3bdfSopenharmony_ci 296f08c3bdfSopenharmony_ci printf("\nCriteria: latencies < %d us\n", (int)pass_criteria); 297f08c3bdfSopenharmony_ci printf("Result: %s\n", ret ? "FAIL" : "PASS"); 298f08c3bdfSopenharmony_ci 299f08c3bdfSopenharmony_ci stats_container_free(&dat); 300f08c3bdfSopenharmony_ci stats_container_free(&hist); 301f08c3bdfSopenharmony_ci stats_quantiles_free(&quantiles); 302f08c3bdfSopenharmony_ci 303f08c3bdfSopenharmony_ci return ret; 304f08c3bdfSopenharmony_ci} 305