| /****************************************************************************** |
| * |
| * Copyright © International Business Machines Corp., 2005, 2008 |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See |
| * the GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
| * |
| * NAME |
| * pthread_cond_latency.c |
| * |
| * DESCRIPTION |
| * measure pthread_cond_t latencies |
| * |
| * USAGE: |
| * Use run_auto.sh script in current directory to build and run test. |
| * |
| * AUTHOR |
| * Paul E. McKenney <paulmck@us.ibm.com> |
| * |
| * HISTORY |
| * |
| * |
| *****************************************************************************/ |
| |
| #include <stdio.h> |
| #include <pthread.h> |
| #include <sys/time.h> |
| #include <sched.h> |
| #include <sys/poll.h> |
| #include <sys/types.h> |
| #include <unistd.h> |
| #include <stdlib.h> |
| #include <librttest.h> |
| |
| pthread_mutex_t child_mutex = PTHREAD_MUTEX_INITIALIZER; |
| volatile int child_waiting = 0; |
| double endtime; |
| |
| void usage(void) |
| { |
| rt_help(); |
| printf("testpi-1 specific options:\n"); |
| } |
| |
| int parse_args(int c, char *v) |
| { |
| |
| int handled = 1; |
| switch (c) { |
| case 'h': |
| usage(); |
| exit(0); |
| default: |
| handled = 0; |
| break; |
| } |
| return handled; |
| } |
| |
| /* |
| * Return time as a floating-point number rather than struct timeval. |
| */ |
| |
| double d_gettimeofday(void) |
| { |
| int retval; |
| struct timeval tv; |
| |
| retval = gettimeofday(&tv, NULL); |
| if (retval != 0) { |
| perror("gettimeofday"); |
| exit(-1); |
| } |
| return (tv.tv_sec + ((double)tv.tv_usec) / 1000000.); |
| } |
| |
| void * |
| childfunc(void *arg) |
| { |
| pthread_cond_t *cp = (pthread_cond_t *)arg; |
| |
| while (child_waiting == 0) { |
| pthread_mutex_lock(&child_mutex); |
| child_waiting = 1; |
| if (pthread_cond_wait(cp, &child_mutex) != 0) { |
| perror("pthread_cond_wait"); |
| exit(-1); |
| } |
| endtime = d_gettimeofday(); |
| child_waiting = 2; |
| pthread_mutex_unlock(&child_mutex); |
| while (child_waiting == 2) { |
| poll(NULL, 0, 10); |
| } |
| } |
| pthread_exit(NULL); |
| } |
| |
| void |
| test_signal(int broadcast_flag, int iter) |
| { |
| pthread_attr_t attr; |
| pthread_t childid; |
| pthread_cond_t cond = PTHREAD_COND_INITIALIZER; |
| int i; |
| int prio; |
| struct sched_param schparm; |
| double starttime; |
| |
| prio = sched_get_priority_max(SCHED_FIFO); |
| if (prio == -1) { |
| perror("sched_get_priority_max"); |
| exit(-1); |
| } |
| schparm.sched_priority = prio; |
| if (sched_setscheduler(getpid(), SCHED_FIFO, &schparm) != 0) { |
| perror("sched_setscheduler"); |
| exit(-1); |
| } |
| |
| if (pthread_attr_init(&attr) != 0) { |
| perror("pthread_attr_init"); |
| exit(-1); |
| } |
| if (pthread_attr_setschedpolicy(&attr, SCHED_FIFO) != 0) { |
| perror("pthread_attr_setschedpolicy"); |
| exit(-1); |
| } |
| if (pthread_attr_setschedparam(&attr, &schparm) != 0) { |
| perror("pthread_attr_setschedparam"); |
| exit(-1); |
| } |
| if (pthread_create(&childid, &attr, childfunc, (void *)&cond) != 0) { |
| perror("pthread_create"); |
| exit(-1); |
| } |
| for (i = 0; i < iter; i++) { |
| pthread_mutex_lock(&child_mutex); |
| child_waiting = 0; |
| while (child_waiting == 0) { |
| pthread_mutex_unlock(&child_mutex); |
| sched_yield(); |
| pthread_mutex_lock(&child_mutex); |
| } |
| pthread_mutex_unlock(&child_mutex); |
| if (broadcast_flag) { |
| starttime = d_gettimeofday(); |
| if (pthread_cond_broadcast(&cond) != 0) { |
| perror("pthread_cond_broadcast"); |
| exit(-1); |
| } |
| } else { |
| starttime = d_gettimeofday(); |
| if (pthread_cond_signal(&cond) != 0) { |
| perror("pthread_cond_signal"); |
| exit(-1); |
| } |
| } |
| for (;;) { |
| pthread_mutex_lock(&child_mutex); |
| if (child_waiting == 2) { |
| break; |
| } |
| pthread_mutex_unlock(&child_mutex); |
| poll(NULL, 0, 10); |
| } |
| printf("%s() latency: %d microseconds\n", |
| (broadcast_flag |
| ? "pthread_cond_broadcast" |
| : "pthread_cond_signal"), |
| (int)((endtime - starttime) * 1000000.)); |
| pthread_mutex_unlock(&child_mutex); |
| } |
| pthread_mutex_lock(&child_mutex); |
| child_waiting = 3; |
| pthread_mutex_unlock(&child_mutex); |
| if (pthread_join(childid, NULL) != 0) { |
| perror("pthread_join"); |
| exit(-1); |
| } |
| } |
| |
| int |
| main(int argc, char *argv[]) |
| { |
| struct sched_param sp; |
| long iter; |
| setup(); |
| |
| rt_init("h", parse_args, argc, argv); |
| |
| sp.sched_priority = sched_get_priority_max(SCHED_FIFO); |
| if (sp.sched_priority == -1) { |
| perror("sched_get_priority_max"); |
| exit(-1); |
| } |
| if (sched_setscheduler(0, SCHED_FIFO, &sp) != 0) { |
| perror("sched_setscheduler"); |
| exit(-1); |
| } |
| |
| if (argc == 1) { |
| fprintf(stderr, "Usage: %s iterations [unicast]\n", argv[0]); |
| exit(-1); |
| } |
| iter = strtol(argv[1], NULL, 0); |
| test_signal(argc == 2, iter); |
| |
| return 0; |
| } |