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