1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2009, 2010 Benjamin Poirier <benjamin.poirier@polymtl.ca>
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation, either version 2.1 of the License, or (at
7 * your option) any later version.
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
12 * License for more details.
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
28 #include "event_analysis.h"
29 #include "sync_chain.h"
31 #include "event_matching_tcp.h"
34 // Functions common to all matching modules
35 static void initMatchingTCP(SyncState
* const syncState
);
36 static void destroyMatchingTCP(SyncState
* const syncState
);
38 static void matchEventTCP(SyncState
* const syncState
, Event
* const event
);
39 static AllFactors
* finalizeMatchingTCP(SyncState
* const syncState
);
40 static void printMatchingStatsTCP(SyncState
* const syncState
);
41 static void writeMatchingGraphsPlotsTCPMessages(SyncState
* const syncState
,
42 const unsigned int i
, const unsigned int j
);
44 // Functions specific to this module
45 static void matchEvents(SyncState
* const syncState
, Event
* const event
,
46 GHashTable
* const unMatchedList
, GHashTable
* const
47 unMatchedOppositeList
, const size_t fieldOffset
, const size_t
49 static void partialDestroyMatchingTCP(SyncState
* const syncState
);
51 static bool isAck(const Message
* const message
);
52 static bool needsAck(const Message
* const message
);
53 static void buildReversedConnectionKey(ConnectionKey
* const
54 reversedConnectionKey
, const ConnectionKey
* const connectionKey
);
56 static void openGraphDataFiles(SyncState
* const syncState
);
57 static void closeGraphDataFiles(SyncState
* const syncState
);
58 static void writeMessagePoint(FILE* stream
, const Message
* const message
);
61 static MatchingModule matchingModuleTCP
= {
64 .canMatch
[UDP
]= false,
65 .initMatching
= &initMatchingTCP
,
66 .destroyMatching
= &destroyMatchingTCP
,
67 .matchEvent
= &matchEventTCP
,
68 .finalizeMatching
= &finalizeMatchingTCP
,
69 .printMatchingStats
= &printMatchingStatsTCP
,
71 .writeTraceTraceForePlots
= &writeMatchingGraphsPlotsTCPMessages
,
77 * Matching module registering function
79 void registerMatchingTCP()
81 g_queue_push_tail(&matchingModules
, &matchingModuleTCP
);
86 * Matching init function
88 * This function is called at the beginning of a synchronization run for a set
91 * Allocate the matching specific data structures
94 * syncState container for synchronization data.
95 * This function allocates these matchingData members:
101 static void initMatchingTCP(SyncState
* const syncState
)
103 MatchingDataTCP
* matchingData
;
105 matchingData
= malloc(sizeof(MatchingDataTCP
));
106 syncState
->matchingData
= matchingData
;
108 matchingData
->unMatchedInE
= g_hash_table_new_full(&ghfSegmentKeyHash
,
109 &gefSegmentKeyEqual
, NULL
, &gdnDestroyEvent
);
110 matchingData
->unMatchedOutE
= g_hash_table_new_full(&ghfSegmentKeyHash
,
111 &gefSegmentKeyEqual
, NULL
, &gdnDestroyEvent
);
112 matchingData
->unAcked
= g_hash_table_new_full(&ghfConnectionKeyHash
,
113 &gefConnectionKeyEqual
, &gdnConnectionKeyDestroy
,
114 &gdnTCPSegmentListDestroy
);
116 if (syncState
->stats
)
120 matchingData
->stats
= calloc(1, sizeof(MatchingStatsTCP
));
121 matchingData
->stats
->totMessageArray
= malloc(syncState
->traceNb
*
122 sizeof(unsigned int*));
123 for (i
= 0; i
< syncState
->traceNb
; i
++)
125 matchingData
->stats
->totMessageArray
[i
]=
126 calloc(syncState
->traceNb
, sizeof(unsigned int));
131 matchingData
->stats
= NULL
;
134 if (syncState
->graphsStream
)
136 openGraphDataFiles(syncState
);
140 matchingData
->messagePoints
= NULL
;
146 * Matching destroy function
148 * Free the matching specific data structures
151 * syncState container for synchronization data.
152 * This function deallocates these matchingData members:
155 static void destroyMatchingTCP(SyncState
* const syncState
)
157 MatchingDataTCP
* matchingData
;
159 matchingData
= (MatchingDataTCP
*) syncState
->matchingData
;
161 if (matchingData
== NULL
)
166 partialDestroyMatchingTCP(syncState
);
168 if (syncState
->stats
)
172 for (i
= 0; i
< syncState
->traceNb
; i
++)
174 free(matchingData
->stats
->totMessageArray
[i
]);
176 free(matchingData
->stats
->totMessageArray
);
177 free(matchingData
->stats
);
180 free(syncState
->matchingData
);
181 syncState
->matchingData
= NULL
;
186 * Free some of the matching specific data structures
188 * This function can be called right after the events have been processed to
189 * free some data structures that are not needed for finalization.
192 * syncState container for synchronization data.
193 * This function deallocates these matchingData members:
198 static void partialDestroyMatchingTCP(SyncState
* const syncState
)
200 MatchingDataTCP
* matchingData
;
202 matchingData
= (MatchingDataTCP
*) syncState
->matchingData
;
204 if (matchingData
== NULL
|| matchingData
->unMatchedInE
== NULL
)
209 g_hash_table_destroy(matchingData
->unMatchedInE
);
210 matchingData
->unMatchedInE
= NULL
;
211 g_hash_table_destroy(matchingData
->unMatchedOutE
);
212 g_hash_table_destroy(matchingData
->unAcked
);
214 if (syncState
->graphsStream
&& matchingData
->messagePoints
)
216 closeGraphDataFiles(syncState
);
222 * Try to match one event from a trace with the corresponding event from
226 * syncState container for synchronization data.
227 * event new event to match
229 static void matchEventTCP(SyncState
* const syncState
, Event
* const event
)
231 MatchingDataTCP
* matchingData
;
233 g_assert(event
->type
== TCP
);
235 matchingData
= (MatchingDataTCP
*) syncState
->matchingData
;
237 if (event
->event
.tcpEvent
->direction
== IN
)
239 matchEvents(syncState
, event
, matchingData
->unMatchedInE
,
240 matchingData
->unMatchedOutE
, offsetof(Message
, inE
),
241 offsetof(Message
, outE
));
245 matchEvents(syncState
, event
, matchingData
->unMatchedOutE
,
246 matchingData
->unMatchedInE
, offsetof(Message
, outE
),
247 offsetof(Message
, inE
));
253 * Call the partial matching destroyer and obtain the factors from downstream
256 * syncState container for synchronization data.
259 * AllFactors* synchronization factors for each trace pair
261 static AllFactors
* finalizeMatchingTCP(SyncState
* const syncState
)
263 partialDestroyMatchingTCP(syncState
);
265 return syncState
->analysisModule
->finalizeAnalysis(syncState
);
270 * Print statistics related to matching. Must be called after
274 * syncState container for synchronization data.
276 static void printMatchingStatsTCP(SyncState
* const syncState
)
279 MatchingDataTCP
* matchingData
;
281 if (!syncState
->stats
)
286 matchingData
= (MatchingDataTCP
*) syncState
->matchingData
;
288 printf("TCP matching stats:\n");
289 printf("\ttotal input and output events matched together to form a packet: %u\n",
290 matchingData
->stats
->totPacket
);
292 printf("\tMessage traffic:\n");
294 for (i
= 0; i
< syncState
->traceNb
; i
++)
296 for (j
= i
+ 1; j
< syncState
->traceNb
; j
++)
298 printf("\t\t%3d - %-3d: sent %-10u received %-10u\n", i
, j
,
299 matchingData
->stats
->totMessageArray
[j
][i
],
300 matchingData
->stats
->totMessageArray
[i
][j
]);
304 if (syncState
->analysisModule
->analyzeExchange
!= NULL
)
306 printf("\ttotal packets identified needing an acknowledge: %u\n",
307 matchingData
->stats
->totPacketNeedAck
);
308 printf("\ttotal exchanges (four events matched together): %u\n",
309 matchingData
->stats
->totExchangeEffective
);
310 printf("\ttotal synchronization exchanges: %u\n",
311 matchingData
->stats
->totExchangeSync
);
317 * Implementation of a packet matching algorithm for TCP
320 * event: new event to match
321 * unMatchedList: list of unmatched events of the same type (send or
323 * unMatchedOppositeList: list of unmatched events of the opposite type of
325 * fieldOffset: offset of the Event field in the Message struct for the
326 * field of the type of event
327 * oppositeFieldOffset: offset of the Event field in the Message struct
328 * for the field of the opposite type of event
330 static void matchEvents(SyncState
* const syncState
, Event
* const event
,
331 GHashTable
* const unMatchedList
, GHashTable
* const unMatchedOppositeList
,
332 const size_t fieldOffset
, const size_t oppositeFieldOffset
)
334 Event
* companionEvent
;
336 MatchingDataTCP
* matchingData
;
339 matchingData
= (MatchingDataTCP
*) syncState
->matchingData
;
341 companionEvent
= g_hash_table_lookup(unMatchedOppositeList
, event
->event
.tcpEvent
->segmentKey
);
342 if (companionEvent
!= NULL
)
344 g_debug("Found matching companion event, ");
346 // If it's there, remove it and create a Message
347 g_hash_table_steal(unMatchedOppositeList
, event
->event
.tcpEvent
->segmentKey
);
348 packet
= malloc(sizeof(Message
));
349 *((Event
**) ((void*) packet
+ fieldOffset
))= event
;
350 *((Event
**) ((void*) packet
+ oppositeFieldOffset
))= companionEvent
;
351 packet
->print
= &printTCPSegment
;
352 // Both events can now share the same segmentKey
353 free(packet
->outE
->event
.tcpEvent
->segmentKey
);
354 packet
->outE
->event
.tcpEvent
->segmentKey
= packet
->inE
->event
.tcpEvent
->segmentKey
;
356 if (syncState
->stats
)
358 matchingData
->stats
->totPacket
++;
359 matchingData
->stats
->totMessageArray
[packet
->inE
->traceNum
][packet
->outE
->traceNum
]++;
362 // Discard loopback traffic
363 if (packet
->inE
->traceNum
== packet
->outE
->traceNum
)
365 destroyTCPSegment(packet
);
369 if (syncState
->graphsStream
)
371 writeMessagePoint(matchingData
->messagePoints
[packet
->inE
->traceNum
][packet
->outE
->traceNum
],
375 if (syncState
->analysisModule
->analyzeMessage
!= NULL
)
377 syncState
->analysisModule
->analyzeMessage(syncState
, packet
);
380 // We can skip the rest of the algorithm if the analysis module is not
381 // interested in exchanges
382 if (syncState
->analysisModule
->analyzeExchange
== NULL
)
384 destroyTCPSegment(packet
);
388 // If this packet acknowleges some data ...
391 ConnectionKey oppositeConnectionKey
;
393 buildReversedConnectionKey(&oppositeConnectionKey
,
394 &event
->event
.tcpEvent
->segmentKey
->connectionKey
);
395 conUnAcked
= g_hash_table_lookup(matchingData
->unAcked
,
396 &oppositeConnectionKey
);
397 if (conUnAcked
!= NULL
)
399 Message
* ackedPacket
;
405 result
= g_queue_find_custom(conUnAcked
, packet
, &gcfTCPSegmentAckCompare
);
407 while (result
!= NULL
)
409 // Remove the acknowledged packet from the unAcked list
410 // and keep it for later offset calculations
411 g_debug("Found matching unAcked packet, ");
413 ackedPacket
= (Message
*) result
->data
;
414 g_queue_delete_link(conUnAcked
, result
);
416 if (syncState
->stats
)
418 matchingData
->stats
->totExchangeEffective
++;
421 if (exchange
== NULL
)
423 exchange
= malloc(sizeof(Exchange
));
424 exchange
->message
= packet
;
425 exchange
->acks
= g_queue_new();
428 g_queue_push_tail(exchange
->acks
, ackedPacket
);
430 result
= g_queue_find_custom(conUnAcked
, packet
,
431 &gcfTCPSegmentAckCompare
);
434 // It might be possible to do an offset calculation
435 if (exchange
!= NULL
)
437 ackedPacket
= g_queue_peek_tail(exchange
->acks
);
438 if (ackedPacket
->outE
->traceNum
!= packet
->inE
->traceNum
439 || ackedPacket
->inE
->traceNum
!=
440 packet
->outE
->traceNum
|| packet
->inE
->traceNum
==
441 packet
->outE
->traceNum
)
443 ackedPacket
->print(ackedPacket
);
444 packet
->print(packet
);
445 g_error("Disorganized exchange encountered during "
450 if (syncState
->stats
)
452 matchingData
->stats
->totExchangeSync
++;
455 syncState
->analysisModule
->analyzeExchange(syncState
,
459 exchange
->message
= NULL
;
460 destroyTCPExchange(exchange
);
465 if (needsAck(packet
))
467 if (syncState
->stats
)
469 matchingData
->stats
->totPacketNeedAck
++;
472 // If this packet will generate an ack, add it to the unAcked list
473 g_debug("Adding to unAcked, ");
474 conUnAcked
= g_hash_table_lookup(matchingData
->unAcked
,
475 &event
->event
.tcpEvent
->segmentKey
->connectionKey
);
476 if (conUnAcked
== NULL
)
478 ConnectionKey
* connectionKey
;
480 connectionKey
= malloc(sizeof(ConnectionKey
));
481 memcpy(connectionKey
, &event
->event
.tcpEvent
->segmentKey
->connectionKey
,
482 sizeof(ConnectionKey
));
483 g_hash_table_insert(matchingData
->unAcked
, connectionKey
,
484 conUnAcked
= g_queue_new());
486 g_queue_push_tail(conUnAcked
, packet
);
490 destroyTCPSegment(packet
);
495 // If there's no corresponding event, add the event to the unmatched
496 // list for this type of event
497 g_debug("Adding to unmatched event list, ");
498 g_hash_table_replace(unMatchedList
, event
->event
.tcpEvent
->segmentKey
, event
);
504 * Check if a packet is an acknowledge
513 static bool isAck(const Message
* const packet
)
515 if (packet
->inE
->event
.tcpEvent
->segmentKey
->ack
== 1)
527 * Check if a packet will increment the sequence number, thus needing an
534 * true if the packet will need an acknowledge
537 static bool needsAck(const Message
* const packet
)
539 if (packet
->inE
->event
.tcpEvent
->segmentKey
->syn
|| packet
->inE
->event
.tcpEvent
->segmentKey
->fin
||
540 packet
->inE
->event
.tcpEvent
->segmentKey
->tot_len
- packet
->inE
->event
.tcpEvent
->segmentKey
->ihl
* 4 -
541 packet
->inE
->event
.tcpEvent
->segmentKey
->doff
* 4 > 0)
553 * Populate a connection key structure for the opposite direction of a
557 * reversedConnectionKey the result, must be pre-allocated
558 * connectionKey the connection key to reverse
560 static void buildReversedConnectionKey(ConnectionKey
* const
561 reversedConnectionKey
, const ConnectionKey
* const connectionKey
)
563 reversedConnectionKey
->saddr
= connectionKey
->daddr
;
564 reversedConnectionKey
->daddr
= connectionKey
->saddr
;
565 reversedConnectionKey
->source
= connectionKey
->dest
;
566 reversedConnectionKey
->dest
= connectionKey
->source
;
571 * Create and open files used to store message points to genereate
572 * graphs. Allocate and populate array to store file pointers.
575 * syncState: container for synchronization data
577 static void openGraphDataFiles(SyncState
* const syncState
)
583 MatchingDataTCP
* matchingData
;
585 matchingData
= (MatchingDataTCP
*) syncState
->matchingData
;
587 cwd
= changeToGraphsDir(syncState
->graphsDir
);
589 matchingData
->messagePoints
= malloc(syncState
->traceNb
* sizeof(FILE**));
590 for (i
= 0; i
< syncState
->traceNb
; i
++)
592 matchingData
->messagePoints
[i
]= malloc(syncState
->traceNb
*
594 for (j
= 0; j
< syncState
->traceNb
; j
++)
598 retval
= snprintf(name
, sizeof(name
),
599 "matching_tcp-%03u_to_%03u.data", j
, i
);
600 if (retval
> sizeof(name
) - 1)
602 name
[sizeof(name
) - 1]= '\0';
604 if ((matchingData
->messagePoints
[i
][j
]= fopen(name
, "w")) ==
607 g_error("%s", strerror(errno
));
616 g_error("%s", strerror(errno
));
623 * Write a message point to a file used to generate graphs
626 * stream: FILE*, file pointer where to write the point
627 * message: message for which to write the point
629 static void writeMessagePoint(FILE* stream
, const Message
* const message
)
633 if (message
->inE
->traceNum
< message
->outE
->traceNum
)
635 // CA is inE->traceNum
636 x
= message
->inE
->cpuTime
;
637 y
= message
->outE
->cpuTime
;
641 // CA is outE->traceNum
642 x
= message
->outE
->cpuTime
;
643 y
= message
->inE
->cpuTime
;
646 fprintf(stream
, "%20" PRIu64
" %20" PRIu64
"\n", x
, y
);
651 * Close files used to store convex hull points to genereate graphs.
652 * Deallocate array to store file pointers.
655 * syncState: container for synchronization data
657 static void closeGraphDataFiles(SyncState
* const syncState
)
660 MatchingDataTCP
* matchingData
;
663 matchingData
= (MatchingDataTCP
*) syncState
->matchingData
;
665 if (matchingData
->messagePoints
== NULL
)
670 for (i
= 0; i
< syncState
->traceNb
; i
++)
672 for (j
= 0; j
< syncState
->traceNb
; j
++)
676 retval
= fclose(matchingData
->messagePoints
[i
][j
]);
679 g_error("%s", strerror(errno
));
683 free(matchingData
->messagePoints
[i
]);
685 free(matchingData
->messagePoints
);
687 matchingData
->messagePoints
= NULL
;
692 * Write the matching-specific graph lines in the gnuplot script.
695 * syncState: container for synchronization data
696 * i: first trace number
697 * j: second trace number, garanteed to be larger than i
699 static void writeMatchingGraphsPlotsTCPMessages(SyncState
* const syncState
,
700 const unsigned int i
, const unsigned int j
)
702 fprintf(syncState
->graphsStream
,
703 "\t\"matching_tcp-%1$03d_to_%2$03d.data\" "
704 "title \"Sent messages\" with points linetype 4 "
705 "linecolor rgb \"#98fc66\" pointtype 9 pointsize 2, \\\n"
706 "\t\"matching_tcp-%2$03d_to_%1$03d.data\" "
707 "title \"Received messages\" with points linetype 4 "
708 "linecolor rgb \"#6699cc\" pointtype 11 pointsize 2, \\\n", i
, j
);