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