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