1f08c3bdfSopenharmony_ci/****************************************************************************** 2f08c3bdfSopenharmony_ci * 3f08c3bdfSopenharmony_ci * Copyright © International Business Machines Corp., 2005-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 * pthread_cond_many.c 21f08c3bdfSopenharmony_ci * 22f08c3bdfSopenharmony_ci * DESCRIPTION 23f08c3bdfSopenharmony_ci * Measure pthread_cond_t latencies , but in presence of many processes. 24f08c3bdfSopenharmony_ci * 25f08c3bdfSopenharmony_ci * USAGE: 26f08c3bdfSopenharmony_ci * Use run_auto.sh script in current directory to build and run test. 27f08c3bdfSopenharmony_ci * 28f08c3bdfSopenharmony_ci * AUTHOR 29f08c3bdfSopenharmony_ci * Paul E. McKenney <paulmck@us.ibm.com> 30f08c3bdfSopenharmony_ci * 31f08c3bdfSopenharmony_ci * HISTORY 32f08c3bdfSopenharmony_ci * librttest parsing, threading, and mutex initialization - Darren Hart 33f08c3bdfSopenharmony_ci * 34f08c3bdfSopenharmony_ci * 35f08c3bdfSopenharmony_ci * This line has to be added to avoid a stupid CVS problem 36f08c3bdfSopenharmony_ci *****************************************************************************/ 37f08c3bdfSopenharmony_ci 38f08c3bdfSopenharmony_ci#include <stdio.h> 39f08c3bdfSopenharmony_ci#include <stdlib.h> 40f08c3bdfSopenharmony_ci#include <pthread.h> 41f08c3bdfSopenharmony_ci#include <sys/time.h> 42f08c3bdfSopenharmony_ci#include <sched.h> 43f08c3bdfSopenharmony_ci#include <string.h> 44f08c3bdfSopenharmony_ci#include <sys/poll.h> 45f08c3bdfSopenharmony_ci#include <sys/types.h> 46f08c3bdfSopenharmony_ci#include <unistd.h> 47f08c3bdfSopenharmony_ci#include <librttest.h> 48f08c3bdfSopenharmony_ci#include <libstats.h> 49f08c3bdfSopenharmony_ci#define PASS_US 100 50f08c3bdfSopenharmony_cipthread_mutex_t child_mutex; 51f08c3bdfSopenharmony_civolatile int *child_waiting = NULL; 52f08c3bdfSopenharmony_cidouble endtime; 53f08c3bdfSopenharmony_cipthread_cond_t *condlist = NULL; 54f08c3bdfSopenharmony_ciint iterations = 0; 55f08c3bdfSopenharmony_ciint nthreads = 0; 56f08c3bdfSopenharmony_ciint realtime = 0; 57f08c3bdfSopenharmony_ciint broadcast_flag = 0; 58f08c3bdfSopenharmony_ciunsigned long latency = 0; 59f08c3bdfSopenharmony_ciint fail = 0; 60f08c3bdfSopenharmony_ci/* 61f08c3bdfSopenharmony_ci * Return time as a floating-point number rather than struct timeval. 62f08c3bdfSopenharmony_ci */ 63f08c3bdfSopenharmony_ci 64f08c3bdfSopenharmony_cidouble d_gettimeofday(void) 65f08c3bdfSopenharmony_ci{ 66f08c3bdfSopenharmony_ci int retval; 67f08c3bdfSopenharmony_ci struct timeval tv; 68f08c3bdfSopenharmony_ci 69f08c3bdfSopenharmony_ci retval = gettimeofday(&tv, NULL); 70f08c3bdfSopenharmony_ci if (retval != 0) { 71f08c3bdfSopenharmony_ci perror("gettimeofday"); 72f08c3bdfSopenharmony_ci exit(-1); 73f08c3bdfSopenharmony_ci } 74f08c3bdfSopenharmony_ci return (tv.tv_sec + ((double)tv.tv_usec) / 1000000.); 75f08c3bdfSopenharmony_ci} 76f08c3bdfSopenharmony_ci 77f08c3bdfSopenharmony_civoid *childfunc(void *arg) 78f08c3bdfSopenharmony_ci{ 79f08c3bdfSopenharmony_ci int myid = (intptr_t) arg; 80f08c3bdfSopenharmony_ci pthread_cond_t *cp; 81f08c3bdfSopenharmony_ci volatile int *cw; 82f08c3bdfSopenharmony_ci 83f08c3bdfSopenharmony_ci cp = &condlist[myid]; 84f08c3bdfSopenharmony_ci cw = &child_waiting[myid]; 85f08c3bdfSopenharmony_ci while (*cw == 0) { 86f08c3bdfSopenharmony_ci pthread_mutex_lock(&child_mutex); 87f08c3bdfSopenharmony_ci *cw = 1; 88f08c3bdfSopenharmony_ci if (pthread_cond_wait(cp, &child_mutex) != 0) { 89f08c3bdfSopenharmony_ci perror("pthread_cond_wait"); 90f08c3bdfSopenharmony_ci exit(-1); 91f08c3bdfSopenharmony_ci } 92f08c3bdfSopenharmony_ci endtime = d_gettimeofday(); 93f08c3bdfSopenharmony_ci *cw = 2; 94f08c3bdfSopenharmony_ci pthread_mutex_unlock(&child_mutex); 95f08c3bdfSopenharmony_ci while (*cw == 2) { 96f08c3bdfSopenharmony_ci poll(NULL, 0, 10); 97f08c3bdfSopenharmony_ci } 98f08c3bdfSopenharmony_ci } 99f08c3bdfSopenharmony_ci pthread_exit(NULL); 100f08c3bdfSopenharmony_ci} 101f08c3bdfSopenharmony_ci 102f08c3bdfSopenharmony_cipthread_t create_thread_(int itsid) 103f08c3bdfSopenharmony_ci{ 104f08c3bdfSopenharmony_ci pthread_attr_t attr; 105f08c3bdfSopenharmony_ci pthread_t childid; 106f08c3bdfSopenharmony_ci int prio; 107f08c3bdfSopenharmony_ci struct sched_param schparm; 108f08c3bdfSopenharmony_ci 109f08c3bdfSopenharmony_ci if (pthread_attr_init(&attr) != 0) { 110f08c3bdfSopenharmony_ci perror("pthread_attr_init"); 111f08c3bdfSopenharmony_ci exit(-1); 112f08c3bdfSopenharmony_ci } 113f08c3bdfSopenharmony_ci if (realtime) { 114f08c3bdfSopenharmony_ci prio = sched_get_priority_max(SCHED_FIFO); 115f08c3bdfSopenharmony_ci if (prio == -1) { 116f08c3bdfSopenharmony_ci perror("sched_get_priority_max"); 117f08c3bdfSopenharmony_ci exit(-1); 118f08c3bdfSopenharmony_ci } 119f08c3bdfSopenharmony_ci schparm.sched_priority = prio; 120f08c3bdfSopenharmony_ci if (sched_setscheduler(getpid(), SCHED_FIFO, &schparm) != 0) { 121f08c3bdfSopenharmony_ci perror("sched_setscheduler"); 122f08c3bdfSopenharmony_ci exit(-1); 123f08c3bdfSopenharmony_ci } 124f08c3bdfSopenharmony_ci 125f08c3bdfSopenharmony_ci if (pthread_attr_setschedpolicy(&attr, SCHED_FIFO) != 0) { 126f08c3bdfSopenharmony_ci perror("pthread_attr_setschedpolicy"); 127f08c3bdfSopenharmony_ci exit(-1); 128f08c3bdfSopenharmony_ci } 129f08c3bdfSopenharmony_ci if (pthread_attr_setschedparam(&attr, &schparm) != 0) { 130f08c3bdfSopenharmony_ci perror("pthread_attr_setschedparam"); 131f08c3bdfSopenharmony_ci exit(-1); 132f08c3bdfSopenharmony_ci } 133f08c3bdfSopenharmony_ci } 134f08c3bdfSopenharmony_ci if (pthread_attr_setstacksize(&attr, (size_t) (32 * 1024)) != 0) { 135f08c3bdfSopenharmony_ci perror("pthread_attr_setstacksize"); 136f08c3bdfSopenharmony_ci exit(-1); 137f08c3bdfSopenharmony_ci } 138f08c3bdfSopenharmony_ci if (pthread_cond_init(&condlist[itsid], NULL) != 0) { 139f08c3bdfSopenharmony_ci perror("pthread_cond_init"); 140f08c3bdfSopenharmony_ci exit(-1); 141f08c3bdfSopenharmony_ci } 142f08c3bdfSopenharmony_ci if (pthread_create(&childid, &attr, childfunc, (void *)(intptr_t) itsid) 143f08c3bdfSopenharmony_ci != 0) { 144f08c3bdfSopenharmony_ci perror("pthread_create"); 145f08c3bdfSopenharmony_ci exit(-1); 146f08c3bdfSopenharmony_ci } 147f08c3bdfSopenharmony_ci return (childid); 148f08c3bdfSopenharmony_ci} 149f08c3bdfSopenharmony_ci 150f08c3bdfSopenharmony_civoid wake_child(int itsid, int broadcast_flag) 151f08c3bdfSopenharmony_ci{ 152f08c3bdfSopenharmony_ci double starttime; 153f08c3bdfSopenharmony_ci 154f08c3bdfSopenharmony_ci pthread_mutex_lock(&child_mutex); 155f08c3bdfSopenharmony_ci while (child_waiting[itsid] == 0) { 156f08c3bdfSopenharmony_ci pthread_mutex_unlock(&child_mutex); 157f08c3bdfSopenharmony_ci sched_yield(); 158f08c3bdfSopenharmony_ci pthread_mutex_lock(&child_mutex); 159f08c3bdfSopenharmony_ci } 160f08c3bdfSopenharmony_ci pthread_mutex_unlock(&child_mutex); 161f08c3bdfSopenharmony_ci if (broadcast_flag) { 162f08c3bdfSopenharmony_ci starttime = d_gettimeofday(); 163f08c3bdfSopenharmony_ci if (pthread_cond_broadcast(&condlist[itsid]) != 0) { 164f08c3bdfSopenharmony_ci perror("pthread_cond_broadcast"); 165f08c3bdfSopenharmony_ci exit(-1); 166f08c3bdfSopenharmony_ci } 167f08c3bdfSopenharmony_ci } else { 168f08c3bdfSopenharmony_ci starttime = d_gettimeofday(); 169f08c3bdfSopenharmony_ci if (pthread_cond_signal(&condlist[itsid]) != 0) { 170f08c3bdfSopenharmony_ci perror("pthread_cond_signal"); 171f08c3bdfSopenharmony_ci exit(-1); 172f08c3bdfSopenharmony_ci } 173f08c3bdfSopenharmony_ci } 174f08c3bdfSopenharmony_ci for (;;) { 175f08c3bdfSopenharmony_ci pthread_mutex_lock(&child_mutex); 176f08c3bdfSopenharmony_ci if (child_waiting[itsid] == 2) { 177f08c3bdfSopenharmony_ci break; 178f08c3bdfSopenharmony_ci } 179f08c3bdfSopenharmony_ci pthread_mutex_unlock(&child_mutex); 180f08c3bdfSopenharmony_ci poll(NULL, 0, 10); 181f08c3bdfSopenharmony_ci } 182f08c3bdfSopenharmony_ci latency = (unsigned long)((endtime - starttime) * 1000000.); 183f08c3bdfSopenharmony_ci pthread_mutex_unlock(&child_mutex); 184f08c3bdfSopenharmony_ci} 185f08c3bdfSopenharmony_ci 186f08c3bdfSopenharmony_civoid test_signal(long iter, long nthreads) 187f08c3bdfSopenharmony_ci{ 188f08c3bdfSopenharmony_ci int i; 189f08c3bdfSopenharmony_ci int j; 190f08c3bdfSopenharmony_ci int k; 191f08c3bdfSopenharmony_ci pthread_t *pt; 192f08c3bdfSopenharmony_ci unsigned long max = 0; 193f08c3bdfSopenharmony_ci unsigned long min = 0; 194f08c3bdfSopenharmony_ci stats_container_t dat; 195f08c3bdfSopenharmony_ci stats_record_t rec; 196f08c3bdfSopenharmony_ci 197f08c3bdfSopenharmony_ci stats_container_init(&dat, iter * nthreads); 198f08c3bdfSopenharmony_ci 199f08c3bdfSopenharmony_ci pt = malloc(sizeof(*pt) * nthreads); 200f08c3bdfSopenharmony_ci if (pt == NULL) { 201f08c3bdfSopenharmony_ci fprintf(stderr, "Out of memory\n"); 202f08c3bdfSopenharmony_ci exit(-1); 203f08c3bdfSopenharmony_ci } 204f08c3bdfSopenharmony_ci for (j = 0; j < nthreads; j++) { 205f08c3bdfSopenharmony_ci child_waiting[j] = 0; 206f08c3bdfSopenharmony_ci pt[j] = create_thread_(j); 207f08c3bdfSopenharmony_ci } 208f08c3bdfSopenharmony_ci for (i = 0; i < (iter - 1) * nthreads; i += nthreads) { 209f08c3bdfSopenharmony_ci for (j = 0, k = i; j < nthreads; j++, k++) { 210f08c3bdfSopenharmony_ci wake_child(j, broadcast_flag); 211f08c3bdfSopenharmony_ci rec.x = k; 212f08c3bdfSopenharmony_ci rec.y = latency; 213f08c3bdfSopenharmony_ci stats_container_append(&dat, rec); 214f08c3bdfSopenharmony_ci pthread_mutex_lock(&child_mutex); 215f08c3bdfSopenharmony_ci child_waiting[j] = 0; 216f08c3bdfSopenharmony_ci pthread_mutex_unlock(&child_mutex); 217f08c3bdfSopenharmony_ci } 218f08c3bdfSopenharmony_ci } 219f08c3bdfSopenharmony_ci for (j = 0; j < nthreads; j++) { 220f08c3bdfSopenharmony_ci wake_child(j, broadcast_flag); 221f08c3bdfSopenharmony_ci pthread_mutex_lock(&child_mutex); 222f08c3bdfSopenharmony_ci child_waiting[j] = 3; 223f08c3bdfSopenharmony_ci pthread_mutex_unlock(&child_mutex); 224f08c3bdfSopenharmony_ci if (pthread_join(pt[j], NULL) != 0) { 225f08c3bdfSopenharmony_ci fprintf(stderr, "%d: ", j); 226f08c3bdfSopenharmony_ci perror("pthread_join"); 227f08c3bdfSopenharmony_ci exit(-1); 228f08c3bdfSopenharmony_ci } 229f08c3bdfSopenharmony_ci } 230f08c3bdfSopenharmony_ci min = (unsigned long)-1; 231f08c3bdfSopenharmony_ci for (i = 0; i < iter * nthreads; i++) { 232f08c3bdfSopenharmony_ci latency = dat.records[i].y; 233f08c3bdfSopenharmony_ci if (latency > PASS_US) 234f08c3bdfSopenharmony_ci fail = 1; 235f08c3bdfSopenharmony_ci min = MIN(min, latency); 236f08c3bdfSopenharmony_ci max = MAX(max, latency); 237f08c3bdfSopenharmony_ci } 238f08c3bdfSopenharmony_ci printf("Recording statistics...\n"); 239f08c3bdfSopenharmony_ci printf("Minimum: %lu us\n", min); 240f08c3bdfSopenharmony_ci printf("Maximum: %lu us\n", max); 241f08c3bdfSopenharmony_ci printf("Average: %f us\n", stats_avg(&dat)); 242f08c3bdfSopenharmony_ci printf("Standard Deviation: %f\n", stats_stddev(&dat)); 243f08c3bdfSopenharmony_ci} 244f08c3bdfSopenharmony_ci 245f08c3bdfSopenharmony_civoid usage(void) 246f08c3bdfSopenharmony_ci{ 247f08c3bdfSopenharmony_ci rt_help(); 248f08c3bdfSopenharmony_ci printf("pthread_cond_many specific options:\n"); 249f08c3bdfSopenharmony_ci printf(" -r,--realtime run with realtime priority\n"); 250f08c3bdfSopenharmony_ci printf(" -b,--broadcast use cond_broadcast instead of cond_signal\n"); 251f08c3bdfSopenharmony_ci printf(" -iITERATIONS iterations (required)\n"); 252f08c3bdfSopenharmony_ci printf(" -nNTHREADS number of threads (required)\n"); 253f08c3bdfSopenharmony_ci printf("deprecated unnamed arguments:\n"); 254f08c3bdfSopenharmony_ci printf(" pthread_cond_many [options] iterations nthreads\n"); 255f08c3bdfSopenharmony_ci} 256f08c3bdfSopenharmony_ci 257f08c3bdfSopenharmony_ciint parse_args(int c, char *v) 258f08c3bdfSopenharmony_ci{ 259f08c3bdfSopenharmony_ci int handled = 1; 260f08c3bdfSopenharmony_ci switch (c) { 261f08c3bdfSopenharmony_ci case 'h': 262f08c3bdfSopenharmony_ci usage(); 263f08c3bdfSopenharmony_ci exit(0); 264f08c3bdfSopenharmony_ci case 'a': 265f08c3bdfSopenharmony_ci broadcast_flag = 1; 266f08c3bdfSopenharmony_ci break; 267f08c3bdfSopenharmony_ci case 'i': 268f08c3bdfSopenharmony_ci iterations = atoi(v); 269f08c3bdfSopenharmony_ci break; 270f08c3bdfSopenharmony_ci case 'n': 271f08c3bdfSopenharmony_ci nthreads = atoi(v); 272f08c3bdfSopenharmony_ci break; 273f08c3bdfSopenharmony_ci case 'r': 274f08c3bdfSopenharmony_ci realtime = 1; 275f08c3bdfSopenharmony_ci break; 276f08c3bdfSopenharmony_ci default: 277f08c3bdfSopenharmony_ci handled = 0; 278f08c3bdfSopenharmony_ci break; 279f08c3bdfSopenharmony_ci } 280f08c3bdfSopenharmony_ci return handled; 281f08c3bdfSopenharmony_ci} 282f08c3bdfSopenharmony_ci 283f08c3bdfSopenharmony_ciint main(int argc, char *argv[]) 284f08c3bdfSopenharmony_ci{ 285f08c3bdfSopenharmony_ci struct option longopts[] = { 286f08c3bdfSopenharmony_ci {"broadcast", 0, NULL, 'a'}, 287f08c3bdfSopenharmony_ci {"realtime", 0, NULL, 'r'}, 288f08c3bdfSopenharmony_ci {NULL, 0, NULL, 0}, 289f08c3bdfSopenharmony_ci }; 290f08c3bdfSopenharmony_ci setup(); 291f08c3bdfSopenharmony_ci 292f08c3bdfSopenharmony_ci init_pi_mutex(&child_mutex); 293f08c3bdfSopenharmony_ci rt_init_long("ahi:n:r", longopts, parse_args, argc, argv); 294f08c3bdfSopenharmony_ci 295f08c3bdfSopenharmony_ci /* Legacy command line arguments support, overrides getopt args. */ 296f08c3bdfSopenharmony_ci if (optind < argc) 297f08c3bdfSopenharmony_ci iterations = strtol(argv[optind++], NULL, 0); 298f08c3bdfSopenharmony_ci if (optind < argc) 299f08c3bdfSopenharmony_ci nthreads = strtol(argv[optind++], NULL, 0); 300f08c3bdfSopenharmony_ci 301f08c3bdfSopenharmony_ci /* Ensure we have the required arguments. */ 302f08c3bdfSopenharmony_ci if (iterations == 0 || nthreads == 0) { 303f08c3bdfSopenharmony_ci usage(); 304f08c3bdfSopenharmony_ci exit(1); 305f08c3bdfSopenharmony_ci } 306f08c3bdfSopenharmony_ci 307f08c3bdfSopenharmony_ci child_waiting = malloc(sizeof(*child_waiting) * nthreads); 308f08c3bdfSopenharmony_ci condlist = malloc(sizeof(*condlist) * nthreads); 309f08c3bdfSopenharmony_ci if ((child_waiting == NULL) || (condlist == NULL)) { 310f08c3bdfSopenharmony_ci fprintf(stderr, "Out of memory\n"); 311f08c3bdfSopenharmony_ci exit(-1); 312f08c3bdfSopenharmony_ci } 313f08c3bdfSopenharmony_ci test_signal(iterations, nthreads); 314f08c3bdfSopenharmony_ci printf("\nCriteria: latencies < %d us\n", PASS_US); 315f08c3bdfSopenharmony_ci printf("Result: %s\n", fail ? "FAIL" : "PASS"); 316f08c3bdfSopenharmony_ci 317f08c3bdfSopenharmony_ci return 0; 318f08c3bdfSopenharmony_ci} 319