+ graphs->bounds[i]= malloc(i * sizeof(Bounds));
+ for (j= 0; j < i; j++)
+ {
+ graphs->bounds[i][j].min= UINT64_MAX;
+ graphs->bounds[i][j].max= 0;
+ }
+ }
+
+ graphs->chullSS= (SyncState*) malloc(sizeof(SyncState));
+ memcpy(graphs->chullSS, syncState, sizeof(SyncState));
+ graphs->chullSS->analysisData= NULL;
+ result= g_queue_find_custom(&analysisModules, "chull", &gcfCompareAnalysis);
+ g_assert(result != NULL);
+ graphs->chullSS->analysisModule= (AnalysisModule*) result->data;
+ graphs->chullSS->analysisModule->initAnalysis(graphs->chullSS);
+ }
+}
+
+
+/*
+ * Create and open files used to store histogram points to generate graphs.
+ * Create data structures to store histogram points during analysis.
+ *
+ * Args:
+ * graphsDir: folder where to write files
+ * rttKey: host pair, make sure saddr < daddr
+ */
+static AnalysisHistogramEval* constructAnalysisHistogramEval(const char* const
+ graphsDir, const struct RttKey* const rttKey)
+{
+ int retval;
+ unsigned int i;
+ char* cwd;
+ char name[60], saddr[16], daddr[16];
+ AnalysisHistogramEval* histogram= calloc(1, sizeof(*histogram));
+ const struct {
+ size_t pointsOffset;
+ const char* fileName;
+ const char* host1, *host2;
+ } loopValues[]= {
+ {offsetof(AnalysisHistogramEval, ttSendPoints),
+ "analysis_eval_tt-%s_to_%s.data", saddr, daddr},
+ {offsetof(AnalysisHistogramEval, ttRecvPoints),
+ "analysis_eval_tt-%s_to_%s.data", daddr, saddr},
+ {offsetof(AnalysisHistogramEval, hrttPoints),
+ "analysis_eval_hrtt-%s_and_%s.data", saddr, daddr},
+ };
+
+ histogram->ttSendBins.min= BIN_NB - 1;
+ histogram->ttRecvBins.min= BIN_NB - 1;
+ histogram->hrttBins.min= BIN_NB - 1;
+
+ convertIP(saddr, rttKey->saddr);
+ convertIP(daddr, rttKey->daddr);
+
+ cwd= changeToGraphsDir(graphsDir);
+
+ for (i= 0; i < sizeof(loopValues) / sizeof(*loopValues); i++)
+ {
+ retval= snprintf(name, sizeof(name), loopValues[i].fileName,
+ loopValues[i].host1, loopValues[i].host2);
+ if (retval > sizeof(name) - 1)
+ {
+ name[sizeof(name) - 1]= '\0';
+ }
+ if ((*(FILE**)((void*) histogram + loopValues[i].pointsOffset)=
+ fopen(name, "w")) == NULL)
+ {
+ g_error(strerror(errno));
+ }
+ }
+
+ retval= chdir(cwd);
+ if (retval == -1)
+ {
+ g_error(strerror(errno));
+ }
+ free(cwd);
+
+ return histogram;
+}
+
+
+/*
+ * Close files used to store histogram points to generate graphs.
+ *
+ * Args:
+ * graphsDir: folder where to write files
+ * rttKey: host pair, make sure saddr < daddr
+ */
+static void destroyAnalysisHistogramEval(AnalysisHistogramEval* const
+ histogram)
+{
+ unsigned int i;
+ int retval;
+ const struct {
+ size_t pointsOffset;
+ } loopValues[]= {
+ {offsetof(AnalysisHistogramEval, ttSendPoints)},
+ {offsetof(AnalysisHistogramEval, ttRecvPoints)},
+ {offsetof(AnalysisHistogramEval, hrttPoints)},
+ };
+
+ for (i= 0; i < sizeof(loopValues) / sizeof(*loopValues); i++)
+ {
+ retval= fclose(*(FILE**)((void*) histogram + loopValues[i].pointsOffset));
+ if (retval != 0)
+ {
+ g_error(strerror(errno));
+ }
+ }
+
+ free(histogram);
+}
+
+
+/*
+ * A GDestroyNotify function for g_hash_table_new_full()
+ *
+ * Args:
+ * data: AnalysisHistogramEval*
+ */
+static void gdnDestroyAnalysisHistogramEval(gpointer data)
+{
+ destroyAnalysisHistogramEval(data);
+}
+
+
+/*
+ * A GHFunc for g_hash_table_foreach()
+ *
+ * Args:
+ * key: RttKey* where saddr < daddr
+ * value: AnalysisHistogramEval*
+ * user_data struct WriteHistogramInfo*
+ */
+static void ghfWriteHistogram(gpointer key, gpointer value, gpointer user_data)
+{
+ double* rtt1, * rtt2;
+ struct RttKey* rttKey= key;
+ struct RttKey oppositeRttKey= {.saddr= rttKey->daddr, .daddr=
+ rttKey->saddr};
+ AnalysisHistogramEval* histogram= value;
+ struct WriteHistogramInfo* info= user_data;
+
+ rtt1= g_hash_table_lookup(info->rttInfo, rttKey);
+ rtt2= g_hash_table_lookup(info->rttInfo, &oppositeRttKey);
+
+ if (rtt1 == NULL)
+ {
+ rtt1= rtt2;
+ }
+ else if (rtt2 != NULL)
+ {
+ rtt1= MIN(rtt1, rtt2);
+ }
+
+ dumpBinToFile(&histogram->ttSendBins, histogram->ttSendPoints);
+ dumpBinToFile(&histogram->ttRecvBins, histogram->ttRecvPoints);
+ dumpBinToFile(&histogram->hrttBins, histogram->hrttPoints);
+ writeHistogram(info->graphsStream, rttKey, rtt1, histogram);
+}
+
+
+/*
+ * Write the content of one bin in a histogram point file
+ *
+ * Args:
+ * bin: array of values that make up a histogram
+ * file: FILE*, write to this file
+ */
+static void dumpBinToFile(const struct Bins* const bins, FILE* const file)
+{
+ unsigned int i;
+
+ // The first and last bins are skipped, see struct Bins
+ for (i= 1; i < BIN_NB - 1; i++)
+ {
+ if (bins->bin[i] > 0)
+ {
+ fprintf(file, "%20.9f %20.9f %20.9f\n", (binStart(i) + binEnd(i))
+ / 2., (double) bins->bin[i] / ((binEnd(i) - binStart(i)) *
+ bins->total), binEnd(i) - binStart(i));
+ }
+ }
+}
+
+
+/*
+ * Write the analysis-specific plot in the gnuplot script.
+ *
+ * Args:
+ * graphsStream: write to this file
+ * rttKey: must be sorted such that saddr < daddr
+ * minRtt: if available, else NULL
+ * histogram: struct that contains the bins for the pair of traces
+ * identified by rttKey
+ */
+static void writeHistogram(FILE* graphsStream, const struct RttKey* rttKey,
+ double* minRtt, AnalysisHistogramEval* const histogram)
+{
+ char saddr[16], daddr[16];
+
+ convertIP(saddr, rttKey->saddr);
+ convertIP(daddr, rttKey->daddr);
+
+ fprintf(graphsStream,
+ "\nreset\n"
+ "set output \"histogram-%s-%s.eps\"\n"
+ "set title \"\"\n"
+ "set xlabel \"Message Latency (s)\"\n"
+ "set ylabel \"Proportion of messages per second\"\n", saddr, daddr);
+
+ if (minRtt != NULL)
+ {
+ fprintf(graphsStream,
+ "set arrow from %.9f, 0 rto 0, graph 1 "
+ "nohead linetype 3 linewidth 3 linecolor rgb \"black\"\n", *minRtt
+ / 2);
+ }
+
+ if (normalTotal(&histogram->ttSendBins) ||
+ normalTotal(&histogram->ttRecvBins) ||
+ normalTotal(&histogram->hrttBins))
+ {
+ fprintf(graphsStream, "plot \\\n");
+
+ if (normalTotal(&histogram->hrttBins))
+ {
+ fprintf(graphsStream,
+ "\t\"analysis_eval_hrtt-%s_and_%s.data\" "
+ "title \"RTT/2\" with linespoints linetype 1 linewidth 2 "
+ "linecolor rgb \"black\" pointtype 6 pointsize 1,\\\n",
+ saddr, daddr);
+ }
+
+ if (normalTotal(&histogram->ttSendBins))
+ {
+ fprintf(graphsStream,
+ "\t\"analysis_eval_tt-%1$s_to_%2$s.data\" "
+ "title \"%1$s to %2$s\" with linespoints linetype 4 linewidth 2 "
+ "linecolor rgb \"gray60\" pointtype 6 pointsize 1,\\\n",
+ saddr, daddr);
+ }
+
+ if (normalTotal(&histogram->ttRecvBins))
+ {
+ fprintf(graphsStream,
+ "\t\"analysis_eval_tt-%1$s_to_%2$s.data\" "
+ "title \"%1$s to %2$s\" with linespoints linetype 4 linewidth 2 "
+ "linecolor rgb \"gray30\" pointtype 6 pointsize 1,\\\n",
+ daddr, saddr);
+ }
+
+ // Remove the ",\\\n" from the last graph plot line
+ if (ftruncate(fileno(graphsStream), ftell(graphsStream) - 3) == -1)
+ {
+ g_error(strerror(errno));
+ }
+ if (fseek(graphsStream, 0, SEEK_END) == -1)
+ {
+ g_error(strerror(errno));