Store graph callbacks in a structure
[lttv.git] / lttv / lttv / sync / event_matching_tcp.c
CommitLineData
70407e86
BP
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
08365995 23#include <errno.h>
70407e86
BP
24#include <stdlib.h>
25#include <string.h>
08365995 26#include <unistd.h>
70407e86
BP
27
28#include "event_analysis.h"
2bd4b3e4 29#include "sync_chain.h"
70407e86
BP
30
31#include "event_matching_tcp.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
40static void initMatchingTCP(SyncState* const syncState);
41static void destroyMatchingTCP(SyncState* const syncState);
42
10341d26 43static void matchEventTCP(SyncState* const syncState, Event* const event);
70407e86
BP
44static GArray* finalizeMatchingTCP(SyncState* const syncState);
45static void printMatchingStatsTCP(SyncState* const syncState);
8d7d16dd
BP
46static void writeMatchingGraphsPlotsTCP(SyncState* const syncState, const
47 unsigned int i, const unsigned int j);
70407e86
BP
48
49// Functions specific to this module
50static void registerMatchingTCP() __attribute__((constructor (101)));
51
10341d26 52static void matchEvents(SyncState* const syncState, Event* const event,
70407e86
BP
53 GHashTable* const unMatchedList, GHashTable* const
54 unMatchedOppositeList, const size_t fieldOffset, const size_t
55 oppositeFieldOffset);
56static void partialDestroyMatchingTCP(SyncState* const syncState);
57
10341d26
BP
58static bool isAck(const Message* const message);
59static bool needsAck(const Message* const message);
70407e86
BP
60static void buildReversedConnectionKey(ConnectionKey* const
61 reversedConnectionKey, const ConnectionKey* const connectionKey);
62
08365995
BP
63static void openGraphDataFiles(SyncState* const syncState);
64static void closeGraphDataFiles(SyncState* const syncState);
10341d26 65static void writeMessagePoint(FILE* stream, const Message* const message);
08365995 66
70407e86
BP
67
68static MatchingModule matchingModuleTCP = {
69 .name= "TCP",
f6691532
BP
70 .canMatch[TCP]= true,
71 .canMatch[UDP]= false,
70407e86
BP
72 .initMatching= &initMatchingTCP,
73 .destroyMatching= &destroyMatchingTCP,
74 .matchEvent= &matchEventTCP,
75 .finalizeMatching= &finalizeMatchingTCP,
76 .printMatchingStats= &printMatchingStatsTCP,
467066ee
BP
77 .graphFunctions= {
78 .writeTraceTracePlots= &writeMatchingGraphsPlotsTCP,
79 }
70407e86
BP
80};
81
82
83/*
84 * Matching module registering function
85 */
86static void registerMatchingTCP()
87{
88 g_queue_push_tail(&matchingModules, &matchingModuleTCP);
89}
90
91
92/*
93 * Matching init function
94 *
95 * This function is called at the beginning of a synchronization run for a set
96 * of traces.
97 *
98 * Allocate the matching specific data structures
99 *
100 * Args:
101 * syncState container for synchronization data.
102 * This function allocates these matchingData members:
103 * unMatchedInE
104 * unMatchedOutE
105 * unAcked
106 * stats
107 */
108static void initMatchingTCP(SyncState* const syncState)
109{
110 MatchingDataTCP* matchingData;
111
112 matchingData= malloc(sizeof(MatchingDataTCP));
113 syncState->matchingData= matchingData;
114
10341d26
BP
115 matchingData->unMatchedInE= g_hash_table_new_full(&ghfSegmentKeyHash,
116 &gefSegmentKeyEqual, NULL, &gdnDestroyEvent);
117 matchingData->unMatchedOutE= g_hash_table_new_full(&ghfSegmentKeyHash,
118 &gefSegmentKeyEqual, NULL, &gdnDestroyEvent);
70407e86
BP
119 matchingData->unAcked= g_hash_table_new_full(&ghfConnectionKeyHash,
120 &gefConnectionKeyEqual, &gdnConnectionKeyDestroy,
10341d26 121 &gdnTCPSegmentListDestroy);
70407e86
BP
122
123 if (syncState->stats)
124 {
08365995
BP
125 unsigned int i;
126
70407e86 127 matchingData->stats= calloc(1, sizeof(MatchingStatsTCP));
08365995
BP
128 matchingData->stats->totMessageArray= malloc(syncState->traceNb *
129 sizeof(unsigned int*));
130 for (i= 0; i < syncState->traceNb; i++)
131 {
132 matchingData->stats->totMessageArray[i]=
133 calloc(syncState->traceNb, sizeof(unsigned int));
134 }
70407e86
BP
135 }
136 else
137 {
138 matchingData->stats= NULL;
139 }
08365995 140
8d7d16dd 141 if (syncState->graphsStream)
08365995
BP
142 {
143 openGraphDataFiles(syncState);
144 }
145 else
146 {
147 matchingData->messagePoints= NULL;
148 }
70407e86
BP
149}
150
151
152/*
153 * Matching destroy function
154 *
155 * Free the matching specific data structures
156 *
157 * Args:
158 * syncState container for synchronization data.
159 * This function deallocates these matchingData members:
160 * stats
161 */
162static void destroyMatchingTCP(SyncState* const syncState)
163{
164 MatchingDataTCP* matchingData;
165
166 matchingData= (MatchingDataTCP*) syncState->matchingData;
167
168 if (matchingData == NULL)
169 {
170 return;
171 }
172
173 partialDestroyMatchingTCP(syncState);
174
175 if (syncState->stats)
176 {
08365995
BP
177 unsigned int i;
178
179 for (i= 0; i < syncState->traceNb; i++)
180 {
181 free(matchingData->stats->totMessageArray[i]);
182 }
183 free(matchingData->stats->totMessageArray);
70407e86
BP
184 free(matchingData->stats);
185 }
186
187 free(syncState->matchingData);
188 syncState->matchingData= NULL;
189}
190
191
192/*
193 * Free some of the matching specific data structures
194 *
195 * This function can be called right after the events have been processed to
196 * free some data structures that are not needed for finalization.
197 *
198 * Args:
199 * syncState container for synchronization data.
200 * This function deallocates these matchingData members:
201 * unMatchedInE
202 * unMatchedOut
203 * unAcked
204 */
205static void partialDestroyMatchingTCP(SyncState* const syncState)
206{
207 MatchingDataTCP* matchingData;
208
209 matchingData= (MatchingDataTCP*) syncState->matchingData;
210
211 if (matchingData == NULL || matchingData->unMatchedInE == NULL)
212 {
213 return;
214 }
215
70407e86
BP
216 g_hash_table_destroy(matchingData->unMatchedInE);
217 matchingData->unMatchedInE= NULL;
70407e86 218 g_hash_table_destroy(matchingData->unMatchedOutE);
70407e86 219 g_hash_table_destroy(matchingData->unAcked);
08365995 220
8d7d16dd 221 if (syncState->graphsStream && matchingData->messagePoints)
08365995
BP
222 {
223 closeGraphDataFiles(syncState);
224 }
70407e86
BP
225}
226
227
228/*
229 * Try to match one event from a trace with the corresponding event from
230 * another trace.
231 *
232 * Args:
233 * syncState container for synchronization data.
234 * event new event to match
70407e86 235 */
10341d26 236static void matchEventTCP(SyncState* const syncState, Event* const event)
70407e86
BP
237{
238 MatchingDataTCP* matchingData;
239
f6691532
BP
240 g_assert(event->type == TCP);
241
70407e86
BP
242 matchingData= (MatchingDataTCP*) syncState->matchingData;
243
10341d26 244 if (event->event.tcpEvent->direction == IN)
70407e86
BP
245 {
246 matchEvents(syncState, event, matchingData->unMatchedInE,
10341d26
BP
247 matchingData->unMatchedOutE, offsetof(Message, inE),
248 offsetof(Message, outE));
70407e86
BP
249 }
250 else
251 {
252 matchEvents(syncState, event, matchingData->unMatchedOutE,
10341d26
BP
253 matchingData->unMatchedInE, offsetof(Message, outE),
254 offsetof(Message, inE));
70407e86
BP
255 }
256}
257
258
259/*
260 * Call the partial matching destroyer and Obtain the factors from downstream
261 *
262 * Args:
263 * syncState container for synchronization data.
264 *
265 * Returns:
266 * Factors[traceNb] synchronization factors for each trace
267 */
268static GArray* finalizeMatchingTCP(SyncState* const syncState)
269{
270 partialDestroyMatchingTCP(syncState);
271
272 return syncState->analysisModule->finalizeAnalysis(syncState);
273}
274
275
276/*
d6ee5003
BP
277 * Print statistics related to matching. Must be called after
278 * finalizeMatching.
70407e86
BP
279 *
280 * Args:
281 * syncState container for synchronization data.
282 */
283static void printMatchingStatsTCP(SyncState* const syncState)
284{
08365995 285 unsigned int i, j;
70407e86
BP
286 MatchingDataTCP* matchingData;
287
288 if (!syncState->stats)
289 {
290 return;
291 }
292
293 matchingData= (MatchingDataTCP*) syncState->matchingData;
294
295 printf("TCP matching stats:\n");
08365995 296 printf("\ttotal input and output events matched together to form a packet: %u\n",
70407e86 297 matchingData->stats->totPacket);
08365995
BP
298
299 printf("\tMessage traffic:\n");
300
301 for (i= 0; i < syncState->traceNb; i++)
302 {
303 for (j= i + 1; j < syncState->traceNb; j++)
304 {
305 printf("\t\t%3d - %-3d: sent %-10u received %-10u\n", i, j,
306 matchingData->stats->totMessageArray[j][i],
307 matchingData->stats->totMessageArray[i][j]);
308 }
309 }
310
311 if (syncState->analysisModule->analyzeExchange != NULL)
312 {
313 printf("\ttotal packets identified needing an acknowledge: %u\n",
314 matchingData->stats->totPacketNeedAck);
315 printf("\ttotal exchanges (four events matched together): %u\n",
316 matchingData->stats->totExchangeEffective);
317 printf("\ttotal synchronization exchanges: %u\n",
318 matchingData->stats->totExchangeSync);
319 }
70407e86
BP
320}
321
322
323/*
324 * Implementation of a packet matching algorithm for TCP
325 *
326 * Args:
10341d26 327 * event: new event to match
70407e86 328 * unMatchedList: list of unmatched events of the same type (send or
10341d26 329 * receive) as event
70407e86 330 * unMatchedOppositeList: list of unmatched events of the opposite type of
10341d26
BP
331 * event
332 * fieldOffset: offset of the Event field in the Message struct for the
333 * field of the type of event
334 * oppositeFieldOffset: offset of the Event field in the Message struct
335 * for the field of the opposite type of event
70407e86 336 */
10341d26 337static void matchEvents(SyncState* const syncState, Event* const event,
70407e86
BP
338 GHashTable* const unMatchedList, GHashTable* const unMatchedOppositeList,
339 const size_t fieldOffset, const size_t oppositeFieldOffset)
340{
10341d26
BP
341 Event* companionEvent;
342 Message* packet;
70407e86
BP
343 MatchingDataTCP* matchingData;
344 GQueue* conUnAcked;
345
346 matchingData= (MatchingDataTCP*) syncState->matchingData;
347
10341d26 348 companionEvent= g_hash_table_lookup(unMatchedOppositeList, event->event.tcpEvent->segmentKey);
70407e86
BP
349 if (companionEvent != NULL)
350 {
351 g_debug("Found matching companion event, ");
352
10341d26
BP
353 // If it's there, remove it and create a Message
354 g_hash_table_steal(unMatchedOppositeList, event->event.tcpEvent->segmentKey);
355 packet= malloc(sizeof(Message));
356 *((Event**) ((void*) packet + fieldOffset))= event;
357 *((Event**) ((void*) packet + oppositeFieldOffset))= companionEvent;
358 packet->print= &printTCPSegment;
359 // Both events can now share the same segmentKey
360 free(packet->outE->event.tcpEvent->segmentKey);
361 packet->outE->event.tcpEvent->segmentKey= packet->inE->event.tcpEvent->segmentKey;
70407e86 362
08365995
BP
363 if (syncState->stats)
364 {
365 matchingData->stats->totPacket++;
366 matchingData->stats->totMessageArray[packet->inE->traceNum][packet->outE->traceNum]++;
367 }
368
70407e86
BP
369 // Discard loopback traffic
370 if (packet->inE->traceNum == packet->outE->traceNum)
371 {
10341d26 372 destroyTCPSegment(packet);
70407e86
BP
373 return;
374 }
375
8d7d16dd 376 if (syncState->graphsStream)
08365995
BP
377 {
378 writeMessagePoint(matchingData->messagePoints[packet->inE->traceNum][packet->outE->traceNum],
379 packet);
380 }
381
10341d26 382 if (syncState->analysisModule->analyzeMessage != NULL)
70407e86 383 {
10341d26 384 syncState->analysisModule->analyzeMessage(syncState, packet);
70407e86
BP
385 }
386
387 // We can skip the rest of the algorithm if the analysis module is not
388 // interested in exchanges
08365995 389 if (syncState->analysisModule->analyzeExchange == NULL)
70407e86 390 {
10341d26 391 destroyTCPSegment(packet);
70407e86
BP
392 return;
393 }
394
395 // If this packet acknowleges some data ...
396 if (isAck(packet))
397 {
398 ConnectionKey oppositeConnectionKey;
399
400 buildReversedConnectionKey(&oppositeConnectionKey,
10341d26 401 &event->event.tcpEvent->segmentKey->connectionKey);
70407e86
BP
402 conUnAcked= g_hash_table_lookup(matchingData->unAcked,
403 &oppositeConnectionKey);
404 if (conUnAcked != NULL)
405 {
10341d26 406 Message* ackedPacket;
70407e86 407 GList* result;
10341d26 408 Exchange* exchange;
70407e86 409
10341d26
BP
410 exchange= NULL;
411
412 result= g_queue_find_custom(conUnAcked, packet, &gcfTCPSegmentAckCompare);
70407e86
BP
413
414 while (result != NULL)
415 {
416 // Remove the acknowledged packet from the unAcked list
417 // and keep it for later offset calculations
418 g_debug("Found matching unAcked packet, ");
419
10341d26 420 ackedPacket= (Message*) result->data;
70407e86
BP
421 g_queue_delete_link(conUnAcked, result);
422
423 if (syncState->stats)
424 {
425 matchingData->stats->totExchangeEffective++;
426 }
427
10341d26 428 if (exchange == NULL)
70407e86 429 {
10341d26
BP
430 exchange= malloc(sizeof(Exchange));
431 exchange->message= packet;
432 exchange->acks= g_queue_new();
70407e86
BP
433 }
434
10341d26 435 g_queue_push_tail(exchange->acks, ackedPacket);
70407e86
BP
436
437 result= g_queue_find_custom(conUnAcked, packet,
10341d26 438 &gcfTCPSegmentAckCompare);
70407e86
BP
439 }
440
441 // It might be possible to do an offset calculation
10341d26 442 if (exchange != NULL)
70407e86 443 {
10341d26 444 ackedPacket= g_queue_peek_tail(exchange->acks);
70407e86
BP
445 if (ackedPacket->outE->traceNum != packet->inE->traceNum
446 || ackedPacket->inE->traceNum !=
447 packet->outE->traceNum || packet->inE->traceNum ==
448 packet->outE->traceNum)
449 {
10341d26
BP
450 ackedPacket->print(ackedPacket);
451 packet->print(packet);
70407e86
BP
452 g_error("Disorganized exchange encountered during "
453 "synchronization");
454 }
455 else
456 {
457 if (syncState->stats)
458 {
459 matchingData->stats->totExchangeSync++;
460 }
461
462 syncState->analysisModule->analyzeExchange(syncState,
10341d26 463 exchange);
70407e86 464 }
10341d26
BP
465
466 exchange->message= NULL;
467 destroyTCPExchange(exchange);
70407e86
BP
468 }
469 }
470 }
471
472 if (needsAck(packet))
473 {
474 if (syncState->stats)
475 {
476 matchingData->stats->totPacketNeedAck++;
477 }
478
479 // If this packet will generate an ack, add it to the unAcked list
480 g_debug("Adding to unAcked, ");
481 conUnAcked= g_hash_table_lookup(matchingData->unAcked,
10341d26 482 &event->event.tcpEvent->segmentKey->connectionKey);
70407e86
BP
483 if (conUnAcked == NULL)
484 {
485 ConnectionKey* connectionKey;
486
487 connectionKey= malloc(sizeof(ConnectionKey));
10341d26 488 memcpy(connectionKey, &event->event.tcpEvent->segmentKey->connectionKey,
70407e86
BP
489 sizeof(ConnectionKey));
490 g_hash_table_insert(matchingData->unAcked, connectionKey,
491 conUnAcked= g_queue_new());
492 }
493 g_queue_push_tail(conUnAcked, packet);
494 }
495 else
496 {
10341d26 497 destroyTCPSegment(packet);
70407e86
BP
498 }
499 }
500 else
501 {
502 // If there's no corresponding event, add the event to the unmatched
503 // list for this type of event
504 g_debug("Adding to unmatched event list, ");
10341d26 505 g_hash_table_replace(unMatchedList, event->event.tcpEvent->segmentKey, event);
70407e86
BP
506 }
507}
508
509
510/*
511 * Check if a packet is an acknowledge
512 *
10341d26
BP
513 * Args:
514 * packet TCP Message
515 *
70407e86
BP
516 * Returns:
517 * true if it is,
518 * false otherwise
519 */
10341d26 520static bool isAck(const Message* const packet)
70407e86 521{
10341d26 522 if (packet->inE->event.tcpEvent->segmentKey->ack == 1)
70407e86
BP
523 {
524 return true;
525 }
526 else
527 {
528 return false;
529 }
530}
531
532
533/*
534 * Check if a packet will increment the sequence number, thus needing an
535 * acknowledge
536 *
10341d26
BP
537 * Args:
538 * packet TCP Message
539 *
70407e86
BP
540 * Returns:
541 * true if the packet will need an acknowledge
542 * false otherwise
543 */
10341d26 544static bool needsAck(const Message* const packet)
70407e86 545{
10341d26
BP
546 if (packet->inE->event.tcpEvent->segmentKey->syn || packet->inE->event.tcpEvent->segmentKey->fin ||
547 packet->inE->event.tcpEvent->segmentKey->tot_len - packet->inE->event.tcpEvent->segmentKey->ihl * 4 -
548 packet->inE->event.tcpEvent->segmentKey->doff * 4 > 0)
70407e86
BP
549 {
550 return true;
551 }
552 else
553 {
554 return false;
555 }
556}
557
558
559/*
560 * Populate a connection key structure for the opposite direction of a
561 * connection
562 *
563 * Args:
564 * reversedConnectionKey the result, must be pre-allocated
565 * connectionKey the connection key to reverse
566 */
567static void buildReversedConnectionKey(ConnectionKey* const
568 reversedConnectionKey, const ConnectionKey* const connectionKey)
569{
570 reversedConnectionKey->saddr= connectionKey->daddr;
571 reversedConnectionKey->daddr= connectionKey->saddr;
572 reversedConnectionKey->source= connectionKey->dest;
573 reversedConnectionKey->dest= connectionKey->source;
574}
08365995
BP
575
576
577/*
578 * Create and open files used to store message points to genereate
579 * graphs. Allocate and populate array to store file pointers.
580 *
581 * Args:
582 * syncState: container for synchronization data
583 */
584static void openGraphDataFiles(SyncState* const syncState)
585{
586 unsigned int i, j;
587 int retval;
588 char* cwd;
589 char name[29];
590 MatchingDataTCP* matchingData;
591
592 matchingData= (MatchingDataTCP*) syncState->matchingData;
593
8d7d16dd 594 cwd= changeToGraphDir(syncState->graphsDir);
08365995
BP
595
596 matchingData->messagePoints= malloc(syncState->traceNb * sizeof(FILE**));
597 for (i= 0; i < syncState->traceNb; i++)
598 {
599 matchingData->messagePoints[i]= malloc(syncState->traceNb *
600 sizeof(FILE*));
601 for (j= 0; j < syncState->traceNb; j++)
602 {
603 if (i != j)
604 {
605 retval= snprintf(name, sizeof(name),
606 "matching_tcp-%03u_to_%03u.data", j, i);
607 if (retval > sizeof(name) - 1)
608 {
609 name[sizeof(name) - 1]= '\0';
610 }
611 if ((matchingData->messagePoints[i][j]= fopen(name, "w")) ==
612 NULL)
613 {
614 g_error(strerror(errno));
615 }
616 }
617 }
618 }
619
620 retval= chdir(cwd);
621 if (retval == -1)
622 {
623 g_error(strerror(errno));
624 }
625 free(cwd);
626}
627
628
629/*
630 * Write a message point to a file used to generate graphs
631 *
632 * Args:
10341d26 633 * stream: FILE*, file pointer where to write the point
8d7d16dd 634 * message: message for which to write the point
08365995 635 */
10341d26 636static void writeMessagePoint(FILE* stream, const Message* const message)
08365995 637{
e96ed88f 638 uint64_t x, y;
08365995 639
10341d26 640 if (message->inE->traceNum < message->outE->traceNum)
08365995
BP
641 {
642 // CA is inE->traceNum
76be6fc2
BP
643 x= message->inE->cpuTime;
644 y= message->outE->cpuTime;
08365995
BP
645 }
646 else
647 {
648 // CA is outE->traceNum
76be6fc2
BP
649 x= message->outE->cpuTime;
650 y= message->inE->cpuTime;
08365995
BP
651 }
652
653 fprintf(stream, "%20llu %20llu\n", x, y);
654}
655
656
657/*
658 * Close files used to store convex hull points to genereate graphs.
659 * Deallocate array to store file pointers.
660 *
661 * Args:
662 * syncState: container for synchronization data
663 */
664static void closeGraphDataFiles(SyncState* const syncState)
665{
666 unsigned int i, j;
667 MatchingDataTCP* matchingData;
668 int retval;
669
670 matchingData= (MatchingDataTCP*) syncState->matchingData;
671
672 if (matchingData->messagePoints == NULL)
673 {
674 return;
675 }
676
677 for (i= 0; i < syncState->traceNb; i++)
678 {
679 for (j= 0; j < syncState->traceNb; j++)
680 {
681 if (i != j)
682 {
683 retval= fclose(matchingData->messagePoints[i][j]);
684 if (retval != 0)
685 {
686 g_error(strerror(errno));
687 }
688 }
689 }
690 free(matchingData->messagePoints[i]);
691 }
692 free(matchingData->messagePoints);
693
694 matchingData->messagePoints= NULL;
695}
696
697
698/*
d6ee5003 699 * Write the matching-specific graph lines in the gnuplot script.
08365995
BP
700 *
701 * Args:
08365995
BP
702 * syncState: container for synchronization data
703 * i: first trace number
704 * j: second trace number, garanteed to be larger than i
705 */
8d7d16dd
BP
706static void writeMatchingGraphsPlotsTCP(SyncState* const syncState, const
707 unsigned int i, const unsigned int j)
08365995 708{
8d7d16dd 709 fprintf(syncState->graphsStream,
08365995
BP
710 "\t\"matching_tcp-%1$03d_to_%2$03d.data\" "
711 "title \"Sent messages\" with points linetype 4 "
712 "linecolor rgb \"#98fc66\" pointtype 9 pointsize 2, \\\n"
713 "\t\"matching_tcp-%2$03d_to_%1$03d.data\" "
714 "title \"Received messages\" with points linetype 4 "
715 "linecolor rgb \"#6699cc\" pointtype 11 pointsize 2, \\\n", i, j);
08365995 716}
This page took 0.053375 seconds and 4 git commands to generate.