Do not use __attribute__((constructor))
[lttv.git] / lttv / lttv / sync / event_matching_broadcast.c
1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2009 Benjamin Poirier <benjamin.poirier@polymtl.ca>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License Version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
16 * MA 02111-1307, USA.
17 */
18
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
22
23 #include <errno.h>
24 #include <inttypes.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
28
29 #include "event_analysis.h"
30 #include "sync_chain.h"
31
32 #include "event_matching_broadcast.h"
33
34
35 // Functions common to all matching modules
36 static void initMatchingBroadcast(SyncState* const syncState);
37 static void destroyMatchingBroadcast(SyncState* const syncState);
38
39 static void matchEventBroadcast(SyncState* const syncState, Event* const event);
40 static GArray* finalizeMatchingBroadcast(SyncState* const syncState);
41 static void printMatchingStatsBroadcast(SyncState* const syncState);
42 static void writeMatchingGraphsPlotsBroadcast(SyncState* const syncState, const
43 unsigned int i, const unsigned int j);
44
45 // Functions specific to this module
46 static void partialDestroyMatchingBroadcast(SyncState* const syncState);
47
48 static void openGraphDataFiles(SyncState* const syncState);
49 static void writeAccuracyPoints(MatchingGraphsBroadcast* graphs, const
50 Broadcast* const broadcast);
51 static void closeGraphDataFiles(SyncState* const syncState);
52
53
54 static MatchingModule matchingModuleBroadcast = {
55 .name= "broadcast",
56 .canMatch[TCP]= false,
57 .canMatch[UDP]= true,
58 .initMatching= &initMatchingBroadcast,
59 .destroyMatching= &destroyMatchingBroadcast,
60 .matchEvent= &matchEventBroadcast,
61 .finalizeMatching= &finalizeMatchingBroadcast,
62 .printMatchingStats= &printMatchingStatsBroadcast,
63 .graphFunctions= {
64 .writeTraceTimeForePlots= &writeMatchingGraphsPlotsBroadcast,
65 }
66 };
67
68
69 /*
70 * Matching module registering function
71 */
72 void registerMatchingBroadcast()
73 {
74 g_queue_push_tail(&matchingModules, &matchingModuleBroadcast);
75 }
76
77
78 /*
79 * Matching init function
80 *
81 * This function is called at the beginning of a synchronization run for a set
82 * of traces.
83 *
84 * Allocate the matching specific data structures
85 *
86 * Args:
87 * syncState container for synchronization data.
88 * This function allocates these matchingData members:
89 * pendingBroadcasts
90 * stats
91 */
92 static void initMatchingBroadcast(SyncState* const syncState)
93 {
94 MatchingDataBroadcast* matchingData;
95
96 matchingData= malloc(sizeof(MatchingDataBroadcast));
97 syncState->matchingData= matchingData;
98
99 matchingData->pendingBroadcasts= g_hash_table_new_full(&ghfDatagramKeyHash,
100 &gefDatagramKeyEqual, &gdnDestroyDatagramKey, &gdnDestroyBroadcast);
101
102 if (syncState->stats)
103 {
104 matchingData->stats= calloc(1, sizeof(MatchingStatsBroadcast));
105 }
106 else
107 {
108 matchingData->stats= NULL;
109 }
110
111 if (syncState->graphsStream)
112 {
113 matchingData->graphs= malloc(sizeof(MatchingGraphsBroadcast));
114 openGraphDataFiles(syncState);
115 }
116 else
117 {
118 matchingData->graphs= NULL;
119 }
120 }
121
122
123 /*
124 * Matching destroy function
125 *
126 * Free the matching specific data structures
127 *
128 * Args:
129 * syncState container for synchronization data.
130 * This function deallocates these matchingData members:
131 * stats
132 */
133 static void destroyMatchingBroadcast(SyncState* const syncState)
134 {
135 MatchingDataBroadcast* matchingData= syncState->matchingData;
136 unsigned int i;
137
138 if (matchingData == NULL)
139 {
140 return;
141 }
142
143 partialDestroyMatchingBroadcast(syncState);
144
145 if (syncState->stats)
146 {
147 free(matchingData->stats);
148 }
149
150 if (syncState->graphsStream)
151 {
152 for (i= 0; i < syncState->traceNb; i++)
153 {
154 free(matchingData->graphs->pointsNb[i]);
155 }
156 free(matchingData->graphs->pointsNb);
157 free(matchingData->graphs);
158 }
159
160 free(syncState->matchingData);
161 syncState->matchingData= NULL;
162 }
163
164
165 /*
166 * Free some of the matching specific data structures
167 *
168 * This function can be called right after the events have been processed to
169 * free some data structures that are not needed for finalization.
170 *
171 * Args:
172 * syncState container for synchronization data.
173 * This function deallocates these matchingData members:
174 * pendingBroadcasts
175 */
176 static void partialDestroyMatchingBroadcast(SyncState* const syncState)
177 {
178 MatchingDataBroadcast* matchingData;
179
180 matchingData= (MatchingDataBroadcast*) syncState->matchingData;
181
182 if (matchingData == NULL || matchingData->pendingBroadcasts == NULL)
183 {
184 return;
185 }
186
187 g_hash_table_destroy(matchingData->pendingBroadcasts);
188 matchingData->pendingBroadcasts= NULL;
189
190 if (syncState->graphsStream && matchingData->graphs->accuracyPoints)
191 {
192 closeGraphDataFiles(syncState);
193 }
194 }
195
196
197 /*
198 * Try to match one broadcast with previously received broadcasts (based on
199 * the addresses and the fist bytes of data they contain). Deliver them to the
200 * analysis module once traceNb events have been accumulated for a broadcast.
201 *
202 * Args:
203 * syncState container for synchronization data.
204 * event new event to match
205 */
206 static void matchEventBroadcast(SyncState* const syncState, Event* const event)
207 {
208 MatchingDataBroadcast* matchingData;
209
210 g_assert(event->type == UDP);
211
212 matchingData= (MatchingDataBroadcast*) syncState->matchingData;
213
214 if (!event->event.udpEvent->unicast)
215 {
216 if (event->event.udpEvent->direction == IN)
217 {
218 Broadcast* broadcast;
219 DatagramKey* datagramKey;
220 gboolean result;
221
222 if (matchingData->stats)
223 {
224 matchingData->stats->totReceive++;
225 }
226
227 /* if event in pendingBroadcasts:
228 * add it to its broadcast
229 * if this broadcast has traceNb events:
230 * remove it from pending and deliver it to analysis
231 * destroy the broadcast (and its elements)
232 * else:
233 * create a broadcast and add it to pending
234 */
235
236 result=
237 g_hash_table_lookup_extended(matchingData->pendingBroadcasts,
238 event->event.udpEvent->datagramKey, (gpointer)
239 &datagramKey, (gpointer) &broadcast);
240 if (result)
241 {
242 g_queue_push_tail(broadcast->events, event);
243 if (broadcast->events->length == syncState->traceNb)
244 {
245 if (matchingData->stats)
246 {
247 matchingData->stats->totComplete++;
248 }
249
250 g_hash_table_steal(matchingData->pendingBroadcasts, datagramKey);
251 free(datagramKey);
252 syncState->analysisModule->analyzeBroadcast(syncState, broadcast);
253
254 if (syncState->graphsStream)
255 {
256 writeAccuracyPoints(matchingData->graphs, broadcast);
257 }
258 destroyBroadcast(broadcast);
259 }
260 }
261 else
262 {
263 broadcast= malloc(sizeof(Broadcast));
264 broadcast->events= g_queue_new();
265 g_queue_push_tail(broadcast->events, event);
266
267 datagramKey= malloc(sizeof(DatagramKey));
268 *datagramKey= *event->event.udpEvent->datagramKey;
269
270 g_hash_table_insert(matchingData->pendingBroadcasts,
271 datagramKey, broadcast);
272 }
273 }
274 else
275 {
276 if (matchingData->stats)
277 {
278 matchingData->stats->totTransmit++;
279 }
280
281 event->destroy(event);
282 }
283 }
284 else
285 {
286 event->destroy(event);
287 }
288
289 }
290
291
292 /*
293 * Call the partial matching destroyer and Obtain the factors from downstream
294 *
295 * Args:
296 * syncState container for synchronization data.
297 *
298 * Returns:
299 * Factors[traceNb] synchronization factors for each trace
300 */
301 static GArray* finalizeMatchingBroadcast(SyncState* const syncState)
302 {
303 MatchingDataBroadcast* matchingData;
304
305 matchingData= (MatchingDataBroadcast*) syncState->matchingData;
306
307 if (matchingData->stats)
308 {
309 matchingData->stats->totIncomplete=
310 g_hash_table_size(matchingData->pendingBroadcasts);
311 }
312
313 partialDestroyMatchingBroadcast(syncState);
314
315 return syncState->analysisModule->finalizeAnalysis(syncState);
316 }
317
318
319 /*
320 * Print statistics related to matching. Must be called after
321 * finalizeMatching.
322 *
323 * Args:
324 * syncState container for synchronization data.
325 */
326 static void printMatchingStatsBroadcast(SyncState* const syncState)
327 {
328 MatchingDataBroadcast* matchingData;
329
330 if (!syncState->stats)
331 {
332 return;
333 }
334 matchingData= (MatchingDataBroadcast*) syncState->matchingData;
335
336 printf("Broadcast matching stats:\n");
337 printf("\ttotal broadcasts datagrams emitted: %u\n",
338 matchingData->stats->totTransmit);
339 printf("\ttotal broadcasts datagrams received: %u\n",
340 matchingData->stats->totReceive);
341 printf("\ttotal broadcast groups for which all receptions were identified: %u\n",
342 matchingData->stats->totComplete);
343 printf("\ttotal broadcast groups missing some receptions: %u\n",
344 matchingData->stats->totIncomplete);
345 if (matchingData->stats->totIncomplete > 0)
346 {
347 printf("\taverage number of broadcast datagrams received in incomplete groups: %f\n",
348 (double) (matchingData->stats->totReceive -
349 matchingData->stats->totComplete * syncState->traceNb) /
350 matchingData->stats->totIncomplete);
351 }
352 }
353
354
355 /*
356 * Create and open files used to store accuracy points to genereate graphs.
357 * Allocate and populate array to store file pointers and counters.
358 *
359 * Args:
360 * syncState: container for synchronization data
361 */
362 static void openGraphDataFiles(SyncState* const syncState)
363 {
364 unsigned int i, j;
365 int retval;
366 char* cwd;
367 char name[36];
368 MatchingGraphsBroadcast* graphs= ((MatchingDataBroadcast*)
369 syncState->matchingData)->graphs;
370
371 cwd= changeToGraphsDir(syncState->graphsDir);
372
373 graphs->accuracyPoints= malloc(syncState->traceNb * sizeof(FILE**));
374 graphs->pointsNb= malloc(syncState->traceNb * sizeof(unsigned int*));
375 for (i= 0; i < syncState->traceNb; i++)
376 {
377 graphs->accuracyPoints[i]= malloc(i * sizeof(FILE*));
378 graphs->pointsNb[i]= calloc(i, sizeof(unsigned int));
379 for (j= 0; j < i; j++)
380 {
381 retval= snprintf(name, sizeof(name),
382 "matching_broadcast-%03u_and_%03u.data", j, i);
383 g_assert_cmpint(retval, <=, sizeof(name) - 1);
384 if ((graphs->accuracyPoints[i][j]= fopen(name, "w")) == NULL)
385 {
386 g_error(strerror(errno));
387 }
388 }
389 }
390
391 retval= chdir(cwd);
392 if (retval == -1)
393 {
394 g_error(strerror(errno));
395 }
396 free(cwd);
397 }
398
399
400 /*
401 * Calculate and write points used to generate graphs
402 *
403 * Args:
404 * graphs: structure containing array of file pointers and counters
405 * broadcast: broadcast for which to write the points
406 */
407 static void writeAccuracyPoints(MatchingGraphsBroadcast* graphs, const
408 Broadcast* const broadcast)
409 {
410 unsigned int i, j;
411 GArray* events;
412 unsigned int eventNb= broadcast->events->length;
413
414 events= g_array_sized_new(FALSE, FALSE, sizeof(Event*), eventNb);
415 g_queue_foreach(broadcast->events, &gfAddEventToArray, events);
416
417 for (i= 0; i < eventNb; i++)
418 {
419 for (j= 0; j < eventNb; j++)
420 {
421 Event* eventI= g_array_index(events, Event*, i), * eventJ=
422 g_array_index(events, Event*, j);
423
424 if (eventI->traceNum < eventJ->traceNum)
425 {
426 fprintf(graphs->accuracyPoints[eventJ->traceNum][eventI->traceNum],
427 "%20" PRIu64 " %20.9f\n", eventI->cpuTime,
428 wallTimeSub(&eventJ->wallTime, &eventI->wallTime));
429 graphs->pointsNb[eventJ->traceNum][eventI->traceNum]++;
430 }
431 }
432 }
433
434 g_array_free(events, TRUE);
435 }
436
437
438 /*
439 * Close files used to store accuracy points to genereate graphs. Deallocate
440 * array to store file pointers (but not array for counters).
441 *
442 * Args:
443 * syncState: container for synchronization data
444 */
445 static void closeGraphDataFiles(SyncState* const syncState)
446 {
447 unsigned int i, j;
448 MatchingGraphsBroadcast* graphs= ((MatchingDataBroadcast*)
449 syncState->matchingData)->graphs;
450 int retval;
451
452 if (graphs->accuracyPoints == NULL)
453 {
454 return;
455 }
456
457 for (i= 0; i < syncState->traceNb; i++)
458 {
459 for (j= 0; j < i; j++)
460 {
461 retval= fclose(graphs->accuracyPoints[i][j]);
462 if (retval != 0)
463 {
464 g_error(strerror(errno));
465 }
466 }
467 free(graphs->accuracyPoints[i]);
468 }
469 free(graphs->accuracyPoints);
470
471 graphs->accuracyPoints= NULL;
472 }
473
474
475 /*
476 * Write the matching-specific graph lines in the gnuplot script.
477 *
478 * Args:
479 * syncState: container for synchronization data
480 * i: first trace number
481 * j: second trace number, garanteed to be larger than i
482 */
483 static void writeMatchingGraphsPlotsBroadcast(SyncState* const syncState, const
484 unsigned int i, const unsigned int j)
485 {
486 if (((MatchingDataBroadcast*)
487 syncState->matchingData)->graphs->pointsNb[j][i])
488 {
489 fprintf(syncState->graphsStream,
490 "\t\"matching_broadcast-%03d_and_%03d.data\" "
491 "title \"Broadcast differential delays\" with points "
492 "linecolor rgb \"black\" pointtype 6 pointsize 2, \\\n", i,
493 j);
494 }
495 }
This page took 0.03941 seconds and 4 git commands to generate.