1f08c3bdfSopenharmony_ci/****************************************************************************** 2f08c3bdfSopenharmony_ci * 3f08c3bdfSopenharmony_ci * Copyright © International Business Machines Corp., 2007, 2008, 2009 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 * pi_perf.c 21f08c3bdfSopenharmony_ci * 22f08c3bdfSopenharmony_ci * DESCRIPTION 23f08c3bdfSopenharmony_ci * Create a scenario with one high, one low and several 24f08c3bdfSopenharmony_ci * medium priority threads. Low priority thread holds a PI lock, high 25f08c3bdfSopenharmony_ci * priority thread later tries to grab it. The test measures the maximum 26f08c3bdfSopenharmony_ci * amount of time the high priority thread has to wait before it gets 27f08c3bdfSopenharmony_ci * the lock. This time should be bound by the duration for which low 28f08c3bdfSopenharmony_ci * priority thread holds the lock 29f08c3bdfSopenharmony_ci * 30f08c3bdfSopenharmony_ci * USAGE: 31f08c3bdfSopenharmony_ci * Use run_auto.sh script in current directory to build and run test. 32f08c3bdfSopenharmony_ci * Use "-j" to enable jvm simulator. 33f08c3bdfSopenharmony_ci * 34f08c3bdfSopenharmony_ci * AUTHOR 35f08c3bdfSopenharmony_ci * Author: Sripathi Kodi <sripathik@in.ibm.com> 36f08c3bdfSopenharmony_ci * 37f08c3bdfSopenharmony_ci * HISTORY 38f08c3bdfSopenharmony_ci * 2007-Nov-20: Initial version by Sripathi Kodi <sripathik@in.ibm.com> 39f08c3bdfSopenharmony_ci * 2009-Jul-03: Pass criteria corrected by Sripathi Kodi 40f08c3bdfSopenharmony_ci * <sripathik@in.ibm.com> 41f08c3bdfSopenharmony_ci * 42f08c3bdfSopenharmony_ci *****************************************************************************/ 43f08c3bdfSopenharmony_ci 44f08c3bdfSopenharmony_ci#include <stdio.h> 45f08c3bdfSopenharmony_ci#include <stdlib.h> 46f08c3bdfSopenharmony_ci#include <limits.h> 47f08c3bdfSopenharmony_ci#include <unistd.h> 48f08c3bdfSopenharmony_ci#include <string.h> 49f08c3bdfSopenharmony_ci#include <math.h> 50f08c3bdfSopenharmony_ci#include <librttest.h> 51f08c3bdfSopenharmony_ci#include <libstats.h> 52f08c3bdfSopenharmony_ci 53f08c3bdfSopenharmony_ci#define LOWPRIO 30 54f08c3bdfSopenharmony_ci#define HIGHPRIO 40 55f08c3bdfSopenharmony_ci#define BUSYPRIO 35 56f08c3bdfSopenharmony_ci 57f08c3bdfSopenharmony_ci#define DEF_LOW_WORK_MS 6 58f08c3bdfSopenharmony_ci#define DEF_HIGH_WORK_MS 1 59f08c3bdfSopenharmony_ci#define DEF_BUSY_WORK_MS 6 60f08c3bdfSopenharmony_ci#define DEF_ITERATIONS 100 61f08c3bdfSopenharmony_ci 62f08c3bdfSopenharmony_ci#define HIST_BUCKETS 100 63f08c3bdfSopenharmony_ci#define THRESHOLD 200 /* microseconds */ 64f08c3bdfSopenharmony_ci 65f08c3bdfSopenharmony_cipthread_barrier_t bar1, bar2; 66f08c3bdfSopenharmony_cipthread_mutex_t lock; 67f08c3bdfSopenharmony_ci 68f08c3bdfSopenharmony_cistatic int end = 0; 69f08c3bdfSopenharmony_ci 70f08c3bdfSopenharmony_cistatic unsigned int iterations = DEF_ITERATIONS; 71f08c3bdfSopenharmony_cistatic unsigned int low_work_time = DEF_LOW_WORK_MS; 72f08c3bdfSopenharmony_cistatic unsigned int high_work_time = DEF_HIGH_WORK_MS; 73f08c3bdfSopenharmony_cistatic unsigned int busy_work_time; 74f08c3bdfSopenharmony_cistatic int num_busy = -1; 75f08c3bdfSopenharmony_ci 76f08c3bdfSopenharmony_cinsec_t low_unlock, max_pi_delay; 77f08c3bdfSopenharmony_ci 78f08c3bdfSopenharmony_cistats_container_t low_dat, cpu_delay_dat; 79f08c3bdfSopenharmony_cistats_container_t cpu_delay_hist; 80f08c3bdfSopenharmony_cistats_quantiles_t cpu_delay_quantiles; 81f08c3bdfSopenharmony_cistats_record_t rec; 82f08c3bdfSopenharmony_ci 83f08c3bdfSopenharmony_civoid usage(void) 84f08c3bdfSopenharmony_ci{ 85f08c3bdfSopenharmony_ci rt_help(); 86f08c3bdfSopenharmony_ci printf("pi_perf_test specific options:\n"); 87f08c3bdfSopenharmony_ci printf 88f08c3bdfSopenharmony_ci (" -nNUMBER Number of busy threads. Default = number of cpus\n"); 89f08c3bdfSopenharmony_ci printf(" -iNUMBER Number of iterations. Default = %d\n", 90f08c3bdfSopenharmony_ci DEF_ITERATIONS); 91f08c3bdfSopenharmony_ci printf(" -tPERIOD Duration of work. Number of ms.\n"); 92f08c3bdfSopenharmony_ci} 93f08c3bdfSopenharmony_ci 94f08c3bdfSopenharmony_ciint parse_args(int c, char *v) 95f08c3bdfSopenharmony_ci{ 96f08c3bdfSopenharmony_ci int handled = 1; 97f08c3bdfSopenharmony_ci switch (c) { 98f08c3bdfSopenharmony_ci case 'h': 99f08c3bdfSopenharmony_ci usage(); 100f08c3bdfSopenharmony_ci exit(0); 101f08c3bdfSopenharmony_ci case 'i': 102f08c3bdfSopenharmony_ci iterations = atoi(v); 103f08c3bdfSopenharmony_ci break; 104f08c3bdfSopenharmony_ci case 'n': 105f08c3bdfSopenharmony_ci num_busy = atoi(v); 106f08c3bdfSopenharmony_ci break; 107f08c3bdfSopenharmony_ci case 'w': 108f08c3bdfSopenharmony_ci low_work_time = atoi(v); 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 *busy_thread(void *arg) 118f08c3bdfSopenharmony_ci{ 119f08c3bdfSopenharmony_ci struct thread *thr = (struct thread *)arg; 120f08c3bdfSopenharmony_ci 121f08c3bdfSopenharmony_ci printf("Busy %ld started\n", (long)thr->arg); 122f08c3bdfSopenharmony_ci 123f08c3bdfSopenharmony_ci while (!end) { 124f08c3bdfSopenharmony_ci /* Wait for all threads to reach barrier wait */ 125f08c3bdfSopenharmony_ci pthread_barrier_wait(&bar1); 126f08c3bdfSopenharmony_ci busy_work_ms(busy_work_time); 127f08c3bdfSopenharmony_ci /* Wait for all threads to finish this iteration */ 128f08c3bdfSopenharmony_ci pthread_barrier_wait(&bar2); 129f08c3bdfSopenharmony_ci } 130f08c3bdfSopenharmony_ci return NULL; 131f08c3bdfSopenharmony_ci} 132f08c3bdfSopenharmony_ci 133f08c3bdfSopenharmony_civoid *low_prio_thread(void *arg) 134f08c3bdfSopenharmony_ci{ 135f08c3bdfSopenharmony_ci nsec_t low_start, low_hold; 136f08c3bdfSopenharmony_ci unsigned int i; 137f08c3bdfSopenharmony_ci 138f08c3bdfSopenharmony_ci stats_container_init(&low_dat, iterations); 139f08c3bdfSopenharmony_ci 140f08c3bdfSopenharmony_ci printf("Low prio thread started\n"); 141f08c3bdfSopenharmony_ci 142f08c3bdfSopenharmony_ci for (i = 0; i < iterations; i++) { 143f08c3bdfSopenharmony_ci pthread_mutex_lock(&lock); 144f08c3bdfSopenharmony_ci /* Wait for all threads to reach barrier wait. 145f08c3bdfSopenharmony_ci Since we already own the mutex, high prio 146f08c3bdfSopenharmony_ci thread will boost our priority. 147f08c3bdfSopenharmony_ci */ 148f08c3bdfSopenharmony_ci pthread_barrier_wait(&bar1); 149f08c3bdfSopenharmony_ci 150f08c3bdfSopenharmony_ci low_start = rt_gettime(); 151f08c3bdfSopenharmony_ci busy_work_ms(low_work_time); 152f08c3bdfSopenharmony_ci low_unlock = rt_gettime(); 153f08c3bdfSopenharmony_ci low_hold = low_unlock - low_start; 154f08c3bdfSopenharmony_ci 155f08c3bdfSopenharmony_ci pthread_mutex_unlock(&lock); 156f08c3bdfSopenharmony_ci 157f08c3bdfSopenharmony_ci rec.x = i; 158f08c3bdfSopenharmony_ci rec.y = low_hold / NS_PER_US; 159f08c3bdfSopenharmony_ci stats_container_append(&low_dat, rec); 160f08c3bdfSopenharmony_ci 161f08c3bdfSopenharmony_ci if (i == iterations - 1) 162f08c3bdfSopenharmony_ci end = 1; 163f08c3bdfSopenharmony_ci 164f08c3bdfSopenharmony_ci /* Wait for all threads to finish this iteration */ 165f08c3bdfSopenharmony_ci pthread_barrier_wait(&bar2); 166f08c3bdfSopenharmony_ci } 167f08c3bdfSopenharmony_ci 168f08c3bdfSopenharmony_ci return NULL; 169f08c3bdfSopenharmony_ci} 170f08c3bdfSopenharmony_ci 171f08c3bdfSopenharmony_civoid *high_prio_thread(void *arg) 172f08c3bdfSopenharmony_ci{ 173f08c3bdfSopenharmony_ci nsec_t high_start, high_end, high_get_lock; 174f08c3bdfSopenharmony_ci unsigned int i; 175f08c3bdfSopenharmony_ci 176f08c3bdfSopenharmony_ci stats_container_init(&cpu_delay_dat, iterations); 177f08c3bdfSopenharmony_ci stats_container_init(&cpu_delay_hist, HIST_BUCKETS); 178f08c3bdfSopenharmony_ci stats_quantiles_init(&cpu_delay_quantiles, (int)log10(iterations)); 179f08c3bdfSopenharmony_ci 180f08c3bdfSopenharmony_ci printf("High prio thread started\n"); 181f08c3bdfSopenharmony_ci 182f08c3bdfSopenharmony_ci for (i = 0; i < iterations; i++) { 183f08c3bdfSopenharmony_ci /* Wait for all threads to reach barrier wait. When 184f08c3bdfSopenharmony_ci woken up, low prio thread will own the mutex 185f08c3bdfSopenharmony_ci */ 186f08c3bdfSopenharmony_ci pthread_barrier_wait(&bar1); 187f08c3bdfSopenharmony_ci 188f08c3bdfSopenharmony_ci high_start = rt_gettime(); 189f08c3bdfSopenharmony_ci pthread_mutex_lock(&lock); 190f08c3bdfSopenharmony_ci high_end = rt_gettime(); 191f08c3bdfSopenharmony_ci high_get_lock = high_end - low_unlock; 192f08c3bdfSopenharmony_ci 193f08c3bdfSopenharmony_ci busy_work_ms(high_work_time); 194f08c3bdfSopenharmony_ci pthread_mutex_unlock(&lock); 195f08c3bdfSopenharmony_ci 196f08c3bdfSopenharmony_ci rec.x = i; 197f08c3bdfSopenharmony_ci rec.y = high_get_lock / NS_PER_US; 198f08c3bdfSopenharmony_ci stats_container_append(&cpu_delay_dat, rec); 199f08c3bdfSopenharmony_ci 200f08c3bdfSopenharmony_ci /* Wait for all threads to finish this iteration */ 201f08c3bdfSopenharmony_ci pthread_barrier_wait(&bar2); 202f08c3bdfSopenharmony_ci } 203f08c3bdfSopenharmony_ci 204f08c3bdfSopenharmony_ci stats_hist(&cpu_delay_hist, &cpu_delay_dat); 205f08c3bdfSopenharmony_ci stats_container_save("samples", "pi_perf Latency Scatter Plot", 206f08c3bdfSopenharmony_ci "Iteration", "Latency (us)", &cpu_delay_dat, 207f08c3bdfSopenharmony_ci "points"); 208f08c3bdfSopenharmony_ci stats_container_save("hist", "pi_perf Latency Histogram", 209f08c3bdfSopenharmony_ci "Latency (us)", "Samples", &cpu_delay_hist, 210f08c3bdfSopenharmony_ci "steps"); 211f08c3bdfSopenharmony_ci 212f08c3bdfSopenharmony_ci printf 213f08c3bdfSopenharmony_ci ("Time taken for high prio thread to get the lock once released by low prio thread\n"); 214f08c3bdfSopenharmony_ci printf("Min delay = %ld us\n", stats_min(&cpu_delay_dat)); 215f08c3bdfSopenharmony_ci printf("Max delay = %ld us\n", stats_max(&cpu_delay_dat)); 216f08c3bdfSopenharmony_ci printf("Average delay = %4.2f us\n", stats_avg(&cpu_delay_dat)); 217f08c3bdfSopenharmony_ci printf("Standard Deviation = %4.2f us\n", stats_stddev(&cpu_delay_dat)); 218f08c3bdfSopenharmony_ci printf("Quantiles:\n"); 219f08c3bdfSopenharmony_ci stats_quantiles_calc(&cpu_delay_dat, &cpu_delay_quantiles); 220f08c3bdfSopenharmony_ci stats_quantiles_print(&cpu_delay_quantiles); 221f08c3bdfSopenharmony_ci 222f08c3bdfSopenharmony_ci max_pi_delay = stats_max(&cpu_delay_dat); 223f08c3bdfSopenharmony_ci 224f08c3bdfSopenharmony_ci return NULL; 225f08c3bdfSopenharmony_ci} 226f08c3bdfSopenharmony_ci 227f08c3bdfSopenharmony_ciint main(int argc, char *argv[]) 228f08c3bdfSopenharmony_ci{ 229f08c3bdfSopenharmony_ci long i; 230f08c3bdfSopenharmony_ci int ret; 231f08c3bdfSopenharmony_ci setup(); 232f08c3bdfSopenharmony_ci 233f08c3bdfSopenharmony_ci pass_criteria = THRESHOLD; 234f08c3bdfSopenharmony_ci rt_init("hi:n:w:", parse_args, argc, argv); 235f08c3bdfSopenharmony_ci 236f08c3bdfSopenharmony_ci if (iterations < 100) { 237f08c3bdfSopenharmony_ci printf("Number of iterations cannot be less than 100\n"); 238f08c3bdfSopenharmony_ci exit(1); 239f08c3bdfSopenharmony_ci } 240f08c3bdfSopenharmony_ci 241f08c3bdfSopenharmony_ci busy_work_time = low_work_time; 242f08c3bdfSopenharmony_ci if (num_busy == -1) { 243f08c3bdfSopenharmony_ci /* Number of busy threads = No. of CPUs */ 244f08c3bdfSopenharmony_ci num_busy = sysconf(_SC_NPROCESSORS_ONLN); 245f08c3bdfSopenharmony_ci } 246f08c3bdfSopenharmony_ci 247f08c3bdfSopenharmony_ci if ((ret = pthread_barrier_init(&bar1, NULL, (num_busy + 2)))) { 248f08c3bdfSopenharmony_ci printf("pthread_barrier_init failed: %s\n", strerror(ret)); 249f08c3bdfSopenharmony_ci exit(ret); 250f08c3bdfSopenharmony_ci } 251f08c3bdfSopenharmony_ci if ((ret = pthread_barrier_init(&bar2, NULL, (num_busy + 2)))) { 252f08c3bdfSopenharmony_ci printf("pthread_barrier_init failed: %s\n", strerror(ret)); 253f08c3bdfSopenharmony_ci exit(ret); 254f08c3bdfSopenharmony_ci } 255f08c3bdfSopenharmony_ci 256f08c3bdfSopenharmony_ci init_pi_mutex(&lock); 257f08c3bdfSopenharmony_ci 258f08c3bdfSopenharmony_ci if ((ret = create_fifo_thread(low_prio_thread, NULL, LOWPRIO)) < 0) 259f08c3bdfSopenharmony_ci exit(ret); 260f08c3bdfSopenharmony_ci if ((ret = 261f08c3bdfSopenharmony_ci create_fifo_thread(high_prio_thread, NULL, HIGHPRIO)) < 0) 262f08c3bdfSopenharmony_ci exit(ret); 263f08c3bdfSopenharmony_ci 264f08c3bdfSopenharmony_ci for (i = 0; i < num_busy; i++) { 265f08c3bdfSopenharmony_ci if ((ret = 266f08c3bdfSopenharmony_ci create_fifo_thread(busy_thread, (void *)i, BUSYPRIO)) < 0) 267f08c3bdfSopenharmony_ci exit(ret); 268f08c3bdfSopenharmony_ci } 269f08c3bdfSopenharmony_ci 270f08c3bdfSopenharmony_ci join_threads(); 271f08c3bdfSopenharmony_ci printf("Criteria: High prio lock wait time < " 272f08c3bdfSopenharmony_ci "(Low prio lock held time + %d us)\n", (int)pass_criteria); 273f08c3bdfSopenharmony_ci 274f08c3bdfSopenharmony_ci ret = 0; 275f08c3bdfSopenharmony_ci if (max_pi_delay > pass_criteria) 276f08c3bdfSopenharmony_ci ret = 1; 277f08c3bdfSopenharmony_ci 278f08c3bdfSopenharmony_ci printf("Result: %s\n", ret ? "FAIL" : "PASS"); 279f08c3bdfSopenharmony_ci return ret; 280f08c3bdfSopenharmony_ci} 281