Mercurial > cgi-bin > hgwebdir.cgi > PR > Applications > pthread > pthread__k_tuple__async
comparison src/Application/main.c @ 0:9cf9b2091eeb
working condition variable version
| author | Sean Halle <seanhalle@yahoo.com> |
|---|---|
| date | Wed, 10 Jul 2013 14:13:46 -0700 |
| parents | |
| children | 88db7b62b961 |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:7ea6d049150f |
|---|---|
| 1 /* | |
| 2 * | |
| 3 */ | |
| 4 | |
| 5 #include "main.h" | |
| 6 | |
| 7 //========== Global Vars =========== | |
| 8 | |
| 9 const char *usage = | |
| 10 { | |
| 11 "Usage: k_tuple_async [options]\n" | |
| 12 " Creates a number of workers, and one consumer that packages productions " | |
| 13 " into a tuple.\n\n" | |
| 14 "Options:\n" | |
| 15 " -p <num> The number of producer threads to create.\n" | |
| 16 " -t <num> the number of tuples to create\n" | |
| 17 " -h this help screen\n\n" | |
| 18 }; | |
| 19 | |
| 20 char __ProgrammName[] = "K-tuple_async"; | |
| 21 char __DataSet[255]; | |
| 22 | |
| 23 #ifdef MEASURE_PERF | |
| 24 int cycles_counter_fd[NUM_CORES]; | |
| 25 int instrs_counter_fd[NUM_CORES]; | |
| 26 int cycles_counter_main_fd; | |
| 27 #endif | |
| 28 | |
| 29 pthread_mutex_t waitForAllDoneLock; | |
| 30 pthread_cond_t waitForAllDoneCond; | |
| 31 | |
| 32 | |
| 33 //=================================== | |
| 34 /* provide a millisecond-resolution timer for each system */ | |
| 35 #if defined(unix) || defined(__unix__) | |
| 36 #include <time.h> | |
| 37 #include <sys/time.h> | |
| 38 unsigned long get_msec(void) { | |
| 39 static struct timeval timeval, first_timeval; | |
| 40 | |
| 41 gettimeofday(&timeval, 0); | |
| 42 if(first_timeval.tv_sec == 0) { | |
| 43 first_timeval = timeval; | |
| 44 return 0; | |
| 45 } | |
| 46 return (timeval.tv_sec - first_timeval.tv_sec) * 1000 + (timeval.tv_usec - first_timeval.tv_usec) / 1000; | |
| 47 } | |
| 48 #elif defined(__WIN32__) || defined(WIN32) | |
| 49 #include <windows.h> | |
| 50 unsigned long get_msec(void) { | |
| 51 return GetTickCount(); | |
| 52 } | |
| 53 #else | |
| 54 #error "I don't know how to measure time on your platform" | |
| 55 #endif | |
| 56 | |
| 57 /*Initializes the performance counters, and opens the file descriptors used | |
| 58 * to read from the performance counters | |
| 59 */ | |
| 60 void | |
| 61 set_up_performance_counters() | |
| 62 { int i; | |
| 63 | |
| 64 #ifdef MEASURE_PERF | |
| 65 //setup performance counters | |
| 66 struct perf_event_attr hw_event; | |
| 67 memset(&hw_event,0,sizeof(hw_event)); | |
| 68 hw_event.type = PERF_TYPE_HARDWARE; | |
| 69 hw_event.size = sizeof(hw_event); | |
| 70 hw_event.disabled = 0; | |
| 71 hw_event.freq = 0; | |
| 72 hw_event.inherit = 1; /* children inherit it */ | |
| 73 hw_event.pinned = 1; /* must always be on PMU */ | |
| 74 hw_event.exclusive = 0; /* only group on PMU */ | |
| 75 hw_event.exclude_user = 0; /* don't count user */ | |
| 76 hw_event.exclude_kernel = 1; /* ditto kernel */ | |
| 77 hw_event.exclude_hv = 1; /* ditto hypervisor */ | |
| 78 hw_event.exclude_idle = 1; /* don't count when idle */ | |
| 79 hw_event.mmap = 0; /* include mmap data */ | |
| 80 hw_event.comm = 0; /* include comm data */ | |
| 81 | |
| 82 | |
| 83 for( i = 0; i < NUM_CORES; i++ ) | |
| 84 { | |
| 85 hw_event.config = PERF_COUNT_HW_CPU_CYCLES; //cycles | |
| 86 cycles_counter_fd[i] = syscall(__NR_perf_event_open, &hw_event, | |
| 87 0,//pid_t pid, | |
| 88 i,//int cpu, | |
| 89 -1,//int group_fd, | |
| 90 0//unsigned long flags | |
| 91 ); | |
| 92 if (cycles_counter_fd[i]<0){ | |
| 93 fprintf(stderr,"On core %d: ",i); | |
| 94 perror("Failed to open cycles counter"); | |
| 95 } | |
| 96 } | |
| 97 | |
| 98 int cycles_counter_main_fd; | |
| 99 hw_event.config = PERF_COUNT_HW_CPU_CYCLES; //cycles | |
| 100 hw_event.exclude_kernel=0; | |
| 101 cycles_counter_main_fd = syscall(__NR_perf_event_open, &hw_event, | |
| 102 0,//pid_t pid, | |
| 103 -1,//int cpu, | |
| 104 -1,//int group_fd, | |
| 105 0//unsigned long flags | |
| 106 ); | |
| 107 if (cycles_counter_main_fd<0){ | |
| 108 perror("Failed to open main cycles counter"); | |
| 109 } | |
| 110 | |
| 111 #endif | |
| 112 } | |
| 113 | |
| 114 | |
| 115 void | |
| 116 init_stuff() | |
| 117 { | |
| 118 pthread_mutex_init(&tupleIterLock, NULL); | |
| 119 pthread_cond_init( &tupleIterCond, NULL ); | |
| 120 tupleIter = 0; | |
| 121 | |
| 122 pthread_mutex_init(&producerAccessMutex, NULL); | |
| 123 pthread_mutex_init(&productionReadyLock, NULL); | |
| 124 pthread_cond_init( &productionReadyCond, NULL ); | |
| 125 currProductionNum = 0; | |
| 126 | |
| 127 pthread_mutex_init(&consumerReceivedAckLock, NULL); | |
| 128 pthread_cond_init( &consumerReceivedAckCond, NULL ); | |
| 129 currConsumerReceivedACKNum = 0; | |
| 130 } | |
| 131 | |
| 132 | |
| 133 typedef struct | |
| 134 { | |
| 135 int numProducers; | |
| 136 int numTuplesToCreate; | |
| 137 } | |
| 138 ParsedArgs; | |
| 139 | |
| 140 /*The benchmark Fn creates the producers and the consumer, then gives the | |
| 141 * "go" signal. It measures time from go until the consumer produces the | |
| 142 * last tuple as output. | |
| 143 */ | |
| 144 void | |
| 145 benchmark( ParsedArgs *args ) | |
| 146 { | |
| 147 int i; | |
| 148 ProducerParams producerParams[args->numProducers]; | |
| 149 pthread_t producerThds[args->numProducers]; | |
| 150 pthread_t consumerThd; | |
| 151 | |
| 152 ConsumerParams consumerParams; | |
| 153 | |
| 154 //Set up the param structs for producers.. gives them the mutex and cond var | |
| 155 // to communicate with consumer | |
| 156 //Also the core the producer should pin its thread to | |
| 157 for(i=0; i < args->numProducers; i++) | |
| 158 { | |
| 159 producerParams[i].producerID = i + 1; //no ID of 0, a fact used in handshake | |
| 160 producerParams[i].numTuplesToCreate = args->numTuplesToCreate; | |
| 161 producerParams[i].coreID = i % NUM_CORES; | |
| 162 } | |
| 163 | |
| 164 consumerParams.numProducers = args->numProducers; | |
| 165 consumerParams.numTuplesToCreate = args->numTuplesToCreate; | |
| 166 | |
| 167 //take measurement before creation of threads, to get total exetime | |
| 168 MeasStruct benchStartMeas, benchEndMeas; | |
| 169 | |
| 170 takeAMeas(0, benchStartMeas); | |
| 171 | |
| 172 for(i=0; i < args->numProducers; i++) | |
| 173 { pthread_create( &producerThds[i], NULL, &producer_birthFn, (void*)&producerParams[i]); | |
| 174 } | |
| 175 | |
| 176 pthread_create( &consumerThd, NULL, &consumer_birthFn, (void*)&consumerParams ); | |
| 177 | |
| 178 for(i=0; i<args->numProducers; i++) | |
| 179 { pthread_join( producerThds[i], NULL ); | |
| 180 } | |
| 181 pthread_join( consumerThd, NULL ); | |
| 182 | |
| 183 //work is all done, so take a measurement snapshot at end | |
| 184 takeAMeas(0, benchEndMeas); | |
| 185 | |
| 186 | |
| 187 #ifdef MEASURE_PERF | |
| 188 uint64_t totalExeCycles = ( benchEndMeas.cycles - benchStartMeas.cycles); | |
| 189 printf("Total Execution: %lu\n", totalExeCycles); | |
| 190 #else | |
| 191 uint64_t totalExeCycles = ( benchEndMeas.total - benchStartMeas.total); | |
| 192 printf("Total Cycles of Execution: %lu\n", totalExeCycles); | |
| 193 #endif | |
| 194 | |
| 195 //====================================================== | |
| 196 } | |
| 197 | |
| 198 | |
| 199 /*This parsed the command line arguments and returns the values in a struct | |
| 200 * Command line args should be a '-' followed by a single letter, then a value | |
| 201 */ | |
| 202 ParsedArgs * | |
| 203 parse_arguments( int argc, char **argv ) | |
| 204 { ParsedArgs *parsedArgs; | |
| 205 int i; | |
| 206 | |
| 207 parsedArgs = malloc(sizeof(ParsedArgs)); | |
| 208 if(argc < 2) | |
| 209 { fprintf(stdout, "must give arguments"); | |
| 210 fputs(usage, stdout); | |
| 211 return EXIT_FAILURE; | |
| 212 } | |
| 213 for( i=1; i < argc; i++ ) | |
| 214 { if(argv[i][0] == '-' && argv[i][2] == 0) | |
| 215 { switch(argv[i][1]) | |
| 216 { case 'p': | |
| 217 { if(!isdigit(argv[++i][0])) | |
| 218 { fprintf(stderr, "-p must be followed by the number of producer threads to spawn\n"); | |
| 219 return EXIT_FAILURE; | |
| 220 } | |
| 221 parsedArgs->numProducers = atoi(argv[i]); | |
| 222 if( parsedArgs->numProducers == 0 ) | |
| 223 { fprintf(stderr, "invalid number of producers specified: %d\n", parsedArgs->numProducers); | |
| 224 return EXIT_FAILURE; | |
| 225 } | |
| 226 else | |
| 227 { DEBUG__printf1("num producers: %d\n", parsedArgs->numProducers ); | |
| 228 } | |
| 229 } | |
| 230 break; | |
| 231 case 't': | |
| 232 { if( !isdigit( argv[++i][0] ) ) | |
| 233 { fputs("-t must be followed by a number\n", stderr); | |
| 234 return EXIT_FAILURE; | |
| 235 } | |
| 236 parsedArgs->numTuplesToCreate = atoi(argv[i]); | |
| 237 DEBUG__printf1("num tuples to produce: %d\n", parsedArgs->numTuplesToCreate ); | |
| 238 } | |
| 239 break; | |
| 240 case 'h': | |
| 241 { fputs(usage, stdout); | |
| 242 return 0; | |
| 243 } | |
| 244 default: | |
| 245 { fprintf(stderr, "unrecognized argument: %s\n", argv[i]); | |
| 246 fputs(usage, stderr); | |
| 247 return EXIT_FAILURE; | |
| 248 } | |
| 249 } | |
| 250 } | |
| 251 else | |
| 252 { fprintf(stdout, "unrecognized argument: %s\n", argv[i]); | |
| 253 fputs(usage, stdout); | |
| 254 return EXIT_FAILURE; | |
| 255 } | |
| 256 }//for | |
| 257 return parsedArgs; | |
| 258 } | |
| 259 | |
| 260 int main(int argc, char **argv) | |
| 261 { ParsedArgs *args; | |
| 262 int i; | |
| 263 | |
| 264 | |
| 265 set_up_performance_counters(); | |
| 266 | |
| 267 init_stuff(); | |
| 268 | |
| 269 args = parse_arguments( argc, argv); | |
| 270 | |
| 271 if( args < 10 ) return args +1; //non-zero exit when parsing went wrong | |
| 272 | |
| 273 benchmark( args ); | |
| 274 | |
| 275 return 0; | |
| 276 } | |
| 277 |
