Make the synchronization module interfaces more generic
[lttv.git] / lttv / lttv / sync / event_matching_tcp.c
index 892dc7af127ab1fa40c0dfcc94f03a12618cf968..25e39858fb8b36c76c19c11bcd0efe5d64a5ba09 100644 (file)
 #include <config.h>
 #endif
 
+#include <errno.h>
 #include <stdlib.h>
 #include <string.h>
+#include <unistd.h>
 
 #include "event_analysis.h"
-#include "sync_chain.h"
+#include "sync_chain_lttv.h"
 
 #include "event_matching_tcp.h"
 
 static void initMatchingTCP(SyncState* const syncState);
 static void destroyMatchingTCP(SyncState* const syncState);
 
-static void matchEventTCP(SyncState* const syncState, NetEvent* const event,
-       EventType eventType);
+static void matchEventTCP(SyncState* const syncState, Event* const event);
 static GArray* finalizeMatchingTCP(SyncState* const syncState);
 static void printMatchingStatsTCP(SyncState* const syncState);
+static void writeMatchingGraphsPlotsTCP(FILE* stream, SyncState* const
+       syncState, const unsigned int i, const unsigned int j);
+static void writeMatchingGraphsOptionsTCP(FILE* stream, SyncState* const
+       syncState, const unsigned int i, const unsigned int j);
 
 // Functions specific to this module
 static void registerMatchingTCP() __attribute__((constructor (101)));
 
-static void matchEvents(SyncState* const syncState, NetEvent* const event,
+static void matchEvents(SyncState* const syncState, Event* const event,
        GHashTable* const unMatchedList, GHashTable* const
        unMatchedOppositeList, const size_t fieldOffset, const size_t
        oppositeFieldOffset);
 static void partialDestroyMatchingTCP(SyncState* const syncState);
 
-static bool isAck(const Packet* const packet);
-static bool needsAck(const Packet* const packet);
+static bool isAck(const Message* const message);
+static bool needsAck(const Message* const message);
 static void buildReversedConnectionKey(ConnectionKey* const
        reversedConnectionKey, const ConnectionKey* const connectionKey);
 
+static void openGraphDataFiles(SyncState* const syncState);
+static void closeGraphDataFiles(SyncState* const syncState);
+static void writeMessagePoint(FILE* stream, const Message* const message);
+
 
 static MatchingModule matchingModuleTCP = {
        .name= "TCP",
@@ -65,6 +74,8 @@ static MatchingModule matchingModuleTCP = {
        .matchEvent= &matchEventTCP,
        .finalizeMatching= &finalizeMatchingTCP,
        .printMatchingStats= &printMatchingStatsTCP,
+       .writeMatchingGraphsPlots= &writeMatchingGraphsPlotsTCP,
+       .writeMatchingGraphsOptions= &writeMatchingGraphsOptionsTCP,
 };
 
 
@@ -100,22 +111,40 @@ static void initMatchingTCP(SyncState* const syncState)
        matchingData= malloc(sizeof(MatchingDataTCP));
        syncState->matchingData= matchingData;
 
-       matchingData->unMatchedInE= g_hash_table_new_full(&ghfPacketKeyHash,
-               &gefPacketKeyEqual, NULL, &gdnDestroyNetEvent);
-       matchingData->unMatchedOutE= g_hash_table_new_full(&ghfPacketKeyHash,
-               &gefPacketKeyEqual, NULL, &gdnDestroyNetEvent);
+       matchingData->unMatchedInE= g_hash_table_new_full(&ghfSegmentKeyHash,
+               &gefSegmentKeyEqual, NULL, &gdnDestroyEvent);
+       matchingData->unMatchedOutE= g_hash_table_new_full(&ghfSegmentKeyHash,
+               &gefSegmentKeyEqual, NULL, &gdnDestroyEvent);
        matchingData->unAcked= g_hash_table_new_full(&ghfConnectionKeyHash,
                &gefConnectionKeyEqual, &gdnConnectionKeyDestroy,
-               &gdnPacketListDestroy);
+               &gdnTCPSegmentListDestroy);
 
        if (syncState->stats)
        {
+               unsigned int i;
+
                matchingData->stats= calloc(1, sizeof(MatchingStatsTCP));
+               matchingData->stats->totMessageArray= malloc(syncState->traceNb *
+                       sizeof(unsigned int*));
+               for (i= 0; i < syncState->traceNb; i++)
+               {
+                       matchingData->stats->totMessageArray[i]=
+                               calloc(syncState->traceNb, sizeof(unsigned int));
+               }
        }
        else
        {
                matchingData->stats= NULL;
        }
+
+       if (syncState->graphs)
+       {
+               openGraphDataFiles(syncState);
+       }
+       else
+       {
+               matchingData->messagePoints= NULL;
+       }
 }
 
 
@@ -144,6 +173,13 @@ static void destroyMatchingTCP(SyncState* const syncState)
 
        if (syncState->stats)
        {
+               unsigned int i;
+
+               for (i= 0; i < syncState->traceNb; i++)
+               {
+                       free(matchingData->stats->totMessageArray[i]);
+               }
+               free(matchingData->stats->totMessageArray);
                free(matchingData->stats);
        }
 
@@ -176,13 +212,15 @@ static void partialDestroyMatchingTCP(SyncState* const syncState)
                return;
        }
 
-       g_debug("Cleaning up unMatchedInE list\n");
        g_hash_table_destroy(matchingData->unMatchedInE);
        matchingData->unMatchedInE= NULL;
-       g_debug("Cleaning up unMatchedOutE list\n");
        g_hash_table_destroy(matchingData->unMatchedOutE);
-       g_debug("Cleaning up unAcked list\n");
        g_hash_table_destroy(matchingData->unAcked);
+
+       if (syncState->graphs && matchingData->messagePoints)
+       {
+               closeGraphDataFiles(syncState);
+       }
 }
 
 
@@ -195,23 +233,23 @@ static void partialDestroyMatchingTCP(SyncState* const syncState)
  *   event         new event to match
  *   eventType     type of event to match
  */
-static void matchEventTCP(SyncState* const syncState, NetEvent* const event, EventType eventType)
+static void matchEventTCP(SyncState* const syncState, Event* const event)
 {
        MatchingDataTCP* matchingData;
 
        matchingData= (MatchingDataTCP*) syncState->matchingData;
 
-       if (eventType == IN)
+       if (event->event.tcpEvent->direction == IN)
        {
                matchEvents(syncState, event, matchingData->unMatchedInE,
-                       matchingData->unMatchedOutE, offsetof(Packet, inE),
-                       offsetof(Packet, outE));
+                       matchingData->unMatchedOutE, offsetof(Message, inE),
+                       offsetof(Message, outE));
        }
        else
        {
                matchEvents(syncState, event, matchingData->unMatchedOutE,
-                       matchingData->unMatchedInE, offsetof(Packet, outE),
-                       offsetof(Packet, inE));
+                       matchingData->unMatchedInE, offsetof(Message, outE),
+                       offsetof(Message, inE));
        }
 }
 
@@ -242,6 +280,7 @@ static GArray* finalizeMatchingTCP(SyncState* const syncState)
  */
 static void printMatchingStatsTCP(SyncState* const syncState)
 {
+       unsigned int i, j;
        MatchingDataTCP* matchingData;
 
        if (!syncState->stats)
@@ -252,14 +291,30 @@ static void printMatchingStatsTCP(SyncState* const syncState)
        matchingData= (MatchingDataTCP*) syncState->matchingData;
 
        printf("TCP matching stats:\n");
-       printf("\ttotal input and output events matched together to form a packet: %d\n",
+       printf("\ttotal input and output events matched together to form a packet: %u\n",
                matchingData->stats->totPacket);
-       printf("\ttotal packets identified needing an acknowledge: %d\n",
-               matchingData->stats->totPacketNeedAck);
-       printf("\ttotal exchanges (four events matched together): %d\n",
-               matchingData->stats->totExchangeEffective);
-       printf("\ttotal synchronization exchanges: %d\n",
-               matchingData->stats->totExchangeSync);
+
+       printf("\tMessage traffic:\n");
+
+       for (i= 0; i < syncState->traceNb; i++)
+       {
+               for (j= i + 1; j < syncState->traceNb; j++)
+               {
+                       printf("\t\t%3d - %-3d: sent %-10u received %-10u\n", i, j,
+                               matchingData->stats->totMessageArray[j][i],
+                               matchingData->stats->totMessageArray[i][j]);
+               }
+       }
+
+       if (syncState->analysisModule->analyzeExchange != NULL)
+       {
+               printf("\ttotal packets identified needing an acknowledge: %u\n",
+                       matchingData->stats->totPacketNeedAck);
+               printf("\ttotal exchanges (four events matched together): %u\n",
+                       matchingData->stats->totExchangeEffective);
+               printf("\ttotal synchronization exchanges: %u\n",
+                       matchingData->stats->totExchangeSync);
+       }
 
        if (syncState->analysisModule->printAnalysisStats != NULL)
        {
@@ -272,64 +327,71 @@ static void printMatchingStatsTCP(SyncState* const syncState)
  * Implementation of a packet matching algorithm for TCP
  *
  * Args:
- *   netEvent:     new event to match
+ *   event:        new event to match
  *   unMatchedList: list of unmatched events of the same type (send or
- *                 receive) as netEvent
+ *                 receive) as event
  *   unMatchedOppositeList: list of unmatched events of the opposite type of
- *                 netEvent
- *   fieldOffset:  offset of the NetEvent field in the Packet struct for the
- *                 field of the type of netEvent
- *   oppositeFieldOffset: offset of the NetEvent field in the Packet struct
- *                 for the field of the opposite type of netEvent
+ *                 event
+ *   fieldOffset:  offset of the Event field in the Message struct for the
+ *                 field of the type of event
+ *   oppositeFieldOffset: offset of the Event field in the Message struct
+ *                 for the field of the opposite type of event
  */
-static void matchEvents(SyncState* const syncState, NetEvent* const event,
+static void matchEvents(SyncState* const syncState, Event* const event,
        GHashTable* const unMatchedList, GHashTable* const unMatchedOppositeList,
        const size_t fieldOffset, const size_t oppositeFieldOffset)
 {
-       NetEvent* companionEvent;
-       Packet* packet;
+       Event* companionEvent;
+       Message* packet;
        MatchingDataTCP* matchingData;
        GQueue* conUnAcked;
 
        matchingData= (MatchingDataTCP*) syncState->matchingData;
 
-       companionEvent= g_hash_table_lookup(unMatchedOppositeList, event->packetKey);
+       companionEvent= g_hash_table_lookup(unMatchedOppositeList, event->event.tcpEvent->segmentKey);
        if (companionEvent != NULL)
        {
                g_debug("Found matching companion event, ");
 
+               // If it's there, remove it and create a Message
+               g_hash_table_steal(unMatchedOppositeList, event->event.tcpEvent->segmentKey);
+               packet= malloc(sizeof(Message));
+               *((Event**) ((void*) packet + fieldOffset))= event;
+               *((Event**) ((void*) packet + oppositeFieldOffset))= companionEvent;
+               packet->print= &printTCPSegment;
+               // Both events can now share the same segmentKey
+               free(packet->outE->event.tcpEvent->segmentKey);
+               packet->outE->event.tcpEvent->segmentKey= packet->inE->event.tcpEvent->segmentKey;
+
                if (syncState->stats)
                {
                        matchingData->stats->totPacket++;
+                       matchingData->stats->totMessageArray[packet->inE->traceNum][packet->outE->traceNum]++;
                }
 
-               // If it's there, remove it and create a Packet
-               g_hash_table_steal(unMatchedOppositeList, event->packetKey);
-               packet= malloc(sizeof(Packet));
-               *((NetEvent**) ((void*) packet + fieldOffset))= event;
-               *((NetEvent**) ((void*) packet + oppositeFieldOffset))= companionEvent;
-               // Both events can now share the same packetKey
-               free(packet->outE->packetKey);
-               packet->outE->packetKey= packet->inE->packetKey;
-               packet->acks= NULL;
-
                // Discard loopback traffic
                if (packet->inE->traceNum == packet->outE->traceNum)
                {
-                       destroyPacket(packet);
+                       destroyTCPSegment(packet);
                        return;
                }
 
-               if (syncState->analysisModule->analyzePacket)
+               if (syncState->graphs)
                {
-                       syncState->analysisModule->analyzePacket(syncState, packet);
+                       writeMessagePoint(matchingData->messagePoints[packet->inE->traceNum][packet->outE->traceNum],
+                               packet);
+               }
+
+               if (syncState->analysisModule->analyzeMessage != NULL)
+               {
+                       syncState->analysisModule->analyzeMessage(syncState, packet);
                }
 
                // We can skip the rest of the algorithm if the analysis module is not
                // interested in exchanges
-               if (!syncState->analysisModule->analyzeExchange)
+               if (syncState->analysisModule->analyzeExchange == NULL)
                {
-                       destroyPacket(packet);
+                       destroyTCPSegment(packet);
                        return;
                }
 
@@ -339,15 +401,18 @@ static void matchEvents(SyncState* const syncState, NetEvent* const event,
                        ConnectionKey oppositeConnectionKey;
 
                        buildReversedConnectionKey(&oppositeConnectionKey,
-                               &event->packetKey->connectionKey);
+                               &event->event.tcpEvent->segmentKey->connectionKey);
                        conUnAcked= g_hash_table_lookup(matchingData->unAcked,
                                &oppositeConnectionKey);
                        if (conUnAcked != NULL)
                        {
-                               Packet* ackedPacket;
+                               Message* ackedPacket;
                                GList* result;
+                               Exchange* exchange;
+
+                               exchange= NULL;
 
-                               result= g_queue_find_custom(conUnAcked, packet, &gcfPacketAckCompare);
+                               result= g_queue_find_custom(conUnAcked, packet, &gcfTCPSegmentAckCompare);
 
                                while (result != NULL)
                                {
@@ -355,7 +420,7 @@ static void matchEvents(SyncState* const syncState, NetEvent* const event,
                                        // and keep it for later offset calculations
                                        g_debug("Found matching unAcked packet, ");
 
-                                       ackedPacket= (Packet*) result->data;
+                                       ackedPacket= (Message*) result->data;
                                        g_queue_delete_link(conUnAcked, result);
 
                                        if (syncState->stats)
@@ -363,28 +428,30 @@ static void matchEvents(SyncState* const syncState, NetEvent* const event,
                                                matchingData->stats->totExchangeEffective++;
                                        }
 
-                                       if (packet->acks == NULL)
+                                       if (exchange == NULL)
                                        {
-                                               packet->acks= g_queue_new();
+                                               exchange= malloc(sizeof(Exchange));
+                                               exchange->message= packet;
+                                               exchange->acks= g_queue_new();
                                        }
 
-                                       g_queue_push_tail(packet->acks, ackedPacket);
+                                       g_queue_push_tail(exchange->acks, ackedPacket);
 
                                        result= g_queue_find_custom(conUnAcked, packet,
-                                               &gcfPacketAckCompare);
+                                               &gcfTCPSegmentAckCompare);
                                }
 
                                // It might be possible to do an offset calculation
-                               if (packet->acks != NULL)
+                               if (exchange != NULL)
                                {
-                                       ackedPacket= g_queue_peek_tail(packet->acks);
+                                       ackedPacket= g_queue_peek_tail(exchange->acks);
                                        if (ackedPacket->outE->traceNum != packet->inE->traceNum
                                                || ackedPacket->inE->traceNum !=
                                                packet->outE->traceNum || packet->inE->traceNum ==
                                                packet->outE->traceNum)
                                        {
-                                               printPacket(ackedPacket);
-                                               printPacket(packet);
+                                               ackedPacket->print(ackedPacket);
+                                               packet->print(packet);
                                                g_error("Disorganized exchange encountered during "
                                                        "synchronization");
                                        }
@@ -396,8 +463,11 @@ static void matchEvents(SyncState* const syncState, NetEvent* const event,
                                                }
 
                                                syncState->analysisModule->analyzeExchange(syncState,
-                                                       packet);
+                                                       exchange);
                                        }
+
+                                       exchange->message= NULL;
+                                       destroyTCPExchange(exchange);
                                }
                        }
                }
@@ -412,13 +482,13 @@ static void matchEvents(SyncState* const syncState, NetEvent* const event,
                        // If this packet will generate an ack, add it to the unAcked list
                        g_debug("Adding to unAcked, ");
                        conUnAcked= g_hash_table_lookup(matchingData->unAcked,
-                               &event->packetKey->connectionKey);
+                               &event->event.tcpEvent->segmentKey->connectionKey);
                        if (conUnAcked == NULL)
                        {
                                ConnectionKey* connectionKey;
 
                                connectionKey= malloc(sizeof(ConnectionKey));
-                               memcpy(connectionKey, &event->packetKey->connectionKey,
+                               memcpy(connectionKey, &event->event.tcpEvent->segmentKey->connectionKey,
                                        sizeof(ConnectionKey));
                                g_hash_table_insert(matchingData->unAcked, connectionKey,
                                        conUnAcked= g_queue_new());
@@ -427,7 +497,7 @@ static void matchEvents(SyncState* const syncState, NetEvent* const event,
                }
                else
                {
-                       destroyPacket(packet);
+                       destroyTCPSegment(packet);
                }
        }
        else
@@ -435,7 +505,7 @@ static void matchEvents(SyncState* const syncState, NetEvent* const event,
                // If there's no corresponding event, add the event to the unmatched
                // list for this type of event
                g_debug("Adding to unmatched event list, ");
-               g_hash_table_replace(unMatchedList, event->packetKey, event);
+               g_hash_table_replace(unMatchedList, event->event.tcpEvent->segmentKey, event);
        }
 }
 
@@ -443,13 +513,16 @@ static void matchEvents(SyncState* const syncState, NetEvent* const event,
 /*
  * Check if a packet is an acknowledge
  *
+ * Args:
+ *   packet        TCP Message
+ *
  * Returns:
  *   true if it is,
  *   false otherwise
  */
-static bool isAck(const Packet* const packet)
+static bool isAck(const Message* const packet)
 {
-       if (packet->inE->packetKey->ack == 1)
+       if (packet->inE->event.tcpEvent->segmentKey->ack == 1)
        {
                return true;
        }
@@ -464,15 +537,18 @@ static bool isAck(const Packet* const packet)
  * Check if a packet will increment the sequence number, thus needing an
  * acknowledge
  *
+ * Args:
+ *   packet        TCP Message
+ *
  * Returns:
  *   true if the packet will need an acknowledge
  *   false otherwise
  */
-static bool needsAck(const Packet* const packet)
+static bool needsAck(const Message* const packet)
 {
-       if (packet->inE->packetKey->syn || packet->inE->packetKey->fin ||
-               packet->inE->packetKey->tot_len - packet->inE->packetKey->ihl * 4 -
-               packet->inE->packetKey->doff * 4 > 0)
+       if (packet->inE->event.tcpEvent->segmentKey->syn || packet->inE->event.tcpEvent->segmentKey->fin ||
+               packet->inE->event.tcpEvent->segmentKey->tot_len - packet->inE->event.tcpEvent->segmentKey->ihl * 4 -
+               packet->inE->event.tcpEvent->segmentKey->doff * 4 > 0)
        {
                return true;
        }
@@ -499,3 +575,174 @@ static void buildReversedConnectionKey(ConnectionKey* const
        reversedConnectionKey->source= connectionKey->dest;
        reversedConnectionKey->dest= connectionKey->source;
 }
+
+
+/*
+ * Create and open files used to store message points to genereate
+ * graphs. Allocate and populate array to store file pointers.
+ *
+ * Args:
+ *   syncState:    container for synchronization data
+ */
+static void openGraphDataFiles(SyncState* const syncState)
+{
+       unsigned int i, j;
+       int retval;
+       char* cwd;
+       char name[29];
+       MatchingDataTCP* matchingData;
+
+       matchingData= (MatchingDataTCP*) syncState->matchingData;
+
+       cwd= changeToGraphDir(syncState->graphs);
+
+       matchingData->messagePoints= malloc(syncState->traceNb * sizeof(FILE**));
+       for (i= 0; i < syncState->traceNb; i++)
+       {
+               matchingData->messagePoints[i]= malloc(syncState->traceNb *
+                       sizeof(FILE*));
+               for (j= 0; j < syncState->traceNb; j++)
+               {
+                       if (i != j)
+                       {
+                               retval= snprintf(name, sizeof(name),
+                                       "matching_tcp-%03u_to_%03u.data", j, i);
+                               if (retval > sizeof(name) - 1)
+                               {
+                                       name[sizeof(name) - 1]= '\0';
+                               }
+                               if ((matchingData->messagePoints[i][j]= fopen(name, "w")) ==
+                                       NULL)
+                               {
+                                       g_error(strerror(errno));
+                               }
+                       }
+               }
+       }
+
+       retval= chdir(cwd);
+       if (retval == -1)
+       {
+               g_error(strerror(errno));
+       }
+       free(cwd);
+}
+
+
+/*
+ * Write a message point to a file used to generate graphs
+ *
+ * Args:
+ *   stream:       FILE*, file pointer where to write the point
+ *   message:       message for which to write the point
+ */
+static void writeMessagePoint(FILE* stream, const Message* const message)
+{
+       LttCycleCount x, y;
+
+       if (message->inE->traceNum < message->outE->traceNum)
+       {
+               // CA is inE->traceNum
+               x= message->inE->time;
+               y= message->outE->time;
+       }
+       else
+       {
+               // CA is outE->traceNum
+               x= message->outE->time;
+               y= message->inE->time;
+       }
+
+       fprintf(stream, "%20llu %20llu\n", x, y);
+}
+
+
+/*
+ * Close files used to store convex hull points to genereate graphs.
+ * Deallocate array to store file pointers.
+ *
+ * Args:
+ *   syncState:    container for synchronization data
+ */
+static void closeGraphDataFiles(SyncState* const syncState)
+{
+       unsigned int i, j;
+       MatchingDataTCP* matchingData;
+       int retval;
+
+       matchingData= (MatchingDataTCP*) syncState->matchingData;
+
+       if (matchingData->messagePoints == NULL)
+       {
+               return;
+       }
+
+       for (i= 0; i < syncState->traceNb; i++)
+       {
+               for (j= 0; j < syncState->traceNb; j++)
+               {
+                       if (i != j)
+                       {
+                               retval= fclose(matchingData->messagePoints[i][j]);
+                               if (retval != 0)
+                               {
+                                       g_error(strerror(errno));
+                               }
+                       }
+               }
+               free(matchingData->messagePoints[i]);
+       }
+       free(matchingData->messagePoints);
+
+       matchingData->messagePoints= NULL;
+}
+
+
+/*
+ * Write the matching-specific graph lines in the gnuplot script. Call the
+ * downstream module's graph function.
+ *
+ * Args:
+ *   stream:       stream where to write the data
+ *   syncState:    container for synchronization data
+ *   i:            first trace number
+ *   j:            second trace number, garanteed to be larger than i
+ */
+static void writeMatchingGraphsPlotsTCP(FILE* stream, SyncState* const
+       syncState, const unsigned int i, const unsigned int j)
+{
+       fprintf(stream,
+               "\t\"matching_tcp-%1$03d_to_%2$03d.data\" "
+                       "title \"Sent messages\" with points linetype 4 "
+                       "linecolor rgb \"#98fc66\" pointtype 9 pointsize 2, \\\n"
+               "\t\"matching_tcp-%2$03d_to_%1$03d.data\" "
+                       "title \"Received messages\" with points linetype 4 "
+                       "linecolor rgb \"#6699cc\" pointtype 11 pointsize 2, \\\n", i, j);
+
+       if (syncState->analysisModule->writeAnalysisGraphsPlots != NULL)
+       {
+               syncState->analysisModule->writeAnalysisGraphsPlots(stream, syncState,
+                       i, j);
+       }
+}
+
+
+/*
+ * Write the matching-specific options in the gnuplot script (none). Call the
+ * downstream module's options function.
+ *
+ * Args:
+ *   stream:       stream where to write the data
+ *   syncState:    container for synchronization data
+ *   i:            first trace number
+ *   j:            second trace number, garanteed to be larger than i
+ */
+static void writeMatchingGraphsOptionsTCP(FILE* stream, SyncState* const
+       syncState, const unsigned int i, const unsigned int j)
+{
+       if (syncState->analysisModule->writeAnalysisGraphsOptions != NULL)
+       {
+               syncState->analysisModule->writeAnalysisGraphsOptions(stream,
+                       syncState, i, j);
+       }
+}
This page took 0.043015 seconds and 4 git commands to generate.