Commits

Bendik R. Opstad  committed 27bc1ca

Implemented writing itt and packet size to file

  • Participants
  • Parent commits be02da0

Comments (0)

Files changed (10)

File ByteRange.cc

 	timeval tmp;
 	ulong ms = 0;
 	for (ulong i = 0; i < sent_tstamp_pcap.size(); i++) {
-		timersub(&ackTime, &sent_tstamp_pcap[i], &tmp);
+		timersub(&ackTime, &sent_tstamp_pcap[i].first, &tmp);
 		ms = (tmp.tv_sec * 1000) + (tmp.tv_usec / 1000);
 
 		ulong ts = 0;
-		if (sent_tstamp_pcap[i].tv_sec > 0) {
-			ts += sent_tstamp_pcap[i].tv_sec * 1000000;
+		if (sent_tstamp_pcap[i].first.tv_sec > 0) {
+			ts += sent_tstamp_pcap[i].first.tv_sec * 1000000;
 		}
-		ts += (sent_tstamp_pcap[i].tv_usec);
+		ts += (sent_tstamp_pcap[i].first.tv_usec);
 		printf("     timestamp: %lu, diff: %lu\n", ts, ms);
 	}
 }
 	struct timeval tv;
 	int ms = 0;
 
-	if (sent_tstamp_pcap.empty() || (sent_tstamp_pcap[0].tv_sec == 0 && sent_tstamp_pcap[0].tv_usec == 0)) {
+	if (sent_tstamp_pcap.empty() || (sent_tstamp_pcap[0].first.tv_sec == 0 && sent_tstamp_pcap[0].first.tv_usec == 0)) {
 #ifdef DEBUG
 		cerr << "Range without a send time. Skipping: " << endl;
 #endif
 
 	/* since ackTime will always be bigger than sent_tstamp_pcap,
 	   (directly comparable timers) timerSub can be used here */
-	timersub(&ackTime, &sent_tstamp_pcap[0], &tv);
+	timersub(&ackTime, &sent_tstamp_pcap[0].first, &tv);
 
 	if (tv.tv_sec > 0) {
 		ms += tv.tv_sec * 1000;
 			cerr << "Strange latency: " << ms << "ms." << endl;
 			//cerr << "Start seq: " << rm->relative_seq(startSeq) << " End seq: " << rm->relative_seq(endSeq) << endl;
 			cerr << "Size of range: " << endSeq - startSeq << endl;
-			cerr << "sent_tstamp_pcap.tv_sec: " << sent_tstamp_pcap[0].tv_sec << " - sent_tstamp_pcap.tv_usec: "
-				 << sent_tstamp_pcap[0].tv_usec << endl;
+			cerr << "sent_tstamp_pcap.tv_sec: " << sent_tstamp_pcap[0].first.tv_sec << " - sent_tstamp_pcap.tv_usec: "
+				 << sent_tstamp_pcap[0].first.tv_usec << endl;
 			cerr << "ackTime.tv_sec : " << ackTime.tv_sec << "  - ackTime.tv_usec : "
 				 << ackTime.tv_usec << endl;
 			cerr << "Number of retransmissions: " << packet_retrans_count << endl;
 		recv_tstamp = &received_tstamp_pcap;
 	}
 	/* Use own macro in order to handle negative diffs */
-	negtimersub(recv_tstamp, &sent_tstamp_pcap[send_tcp_stamp_recv_index], &tv);
+	negtimersub(recv_tstamp, &sent_tstamp_pcap[send_tcp_stamp_recv_index].first, &tv);
 
 	ms += tv.tv_sec * 1000;
 	if(ms >= 0)
 }
 
 timeval* ByteRange::getSendTime() {
-	if (sent_tstamp_pcap[0].tv_sec == 0 && sent_tstamp_pcap[0].tv_usec == 0)
+	if (sent_tstamp_pcap[0].first.tv_sec == 0 && sent_tstamp_pcap[0].first.tv_usec == 0)
 		return NULL;
 	else
-		return &sent_tstamp_pcap[0];
+		return &sent_tstamp_pcap[0].first;
 }
 
 timeval* ByteRange::getAckTime() {
 	uint8_t rdb_byte_hits;
 
 	timeval received_tstamp_pcap;
-	vector<timeval> sent_tstamp_pcap;  // pcap tstamp for regular packet and retrans
+	//vector<timeval> sent_tstamp_pcap;  // pcap tstamp for regular packet and retrans
+	vector< pair<timeval, uint8_t> > sent_tstamp_pcap;
 
 	uint8_t send_tcp_stamp_recv_index; // The index of the element in the tstamps_tcp vector that matches the received tcp time stamp
 	uint32_t received_tstamp_tcp;
 		send_tcp_stamp_recv_index = 0;
 		update_byte_count();
 		original_payload_size = byte_count;
-		packet_sent_count = 1;
+		packet_sent_count = 0;
 		packet_received_count = 0;
 		packet_retrans_count = 0;
 		data_retrans_count = 0;
 		}
 	}
 
-	inline void increase_sent(uint32_t tstamp_tcp, timeval tstamp_pcap, bool rdb) {
+	inline void increase_sent(uint32_t tstamp_tcp, timeval tstamp_pcap, bool rdb, bool packet_sent=true) {
 		if (rdb) {
 			rdb_tstamps_tcp.push_back(tstamp_tcp);
 		}
 		else {
 			tstamps_tcp.push_back(tstamp_tcp);
 		}
+		if (packet_sent)
+			packet_sent_count++;
+
 		sent_count++;
-		sent_tstamp_pcap.push_back(tstamp_pcap);
+		sent_tstamp_pcap.push_back(pair<timeval, uint8_t>(tstamp_pcap, packet_sent));
 		lost_tstamps_tcp.push_back(pair<uint32_t,timeval>(tstamp_tcp, tstamp_pcap));
 	}
 

File CMakeLists.txt

 SET (CMAKE_CXX_FLAGS "-O3 -lm -Wall -Wno-long-long -Wno-variadic-macros") # -Werror?
 
 # Add NDEBUG only for release version
-# To activate: cmake -DCMAKE_BUILD_TYPE=Release .
+# To activate: cmake -DCMAKE_BUILD_TYPE=Release ..
 SET (CMAKE_CXX_FLAGS_RELEASE "-DNDEBUG")
 
 # Set debug compiler flags

File Connection.cc

 	rm->analyse_time_sec_start = GlobOpts::analyse_start;
 
 	struct timeval tv;
-	timersub(&(rm->ranges.rbegin()->second->sent_tstamp_pcap[0]), &rm->analyse_range_start->second->sent_tstamp_pcap[0], &tv);
+	timersub(&(rm->ranges.rbegin()->second->sent_tstamp_pcap[0].first), &rm->analyse_range_start->second->sent_tstamp_pcap[0].first, &tv);
 	rm->analyse_time_sec_end = tv.tv_sec;
 
 	if (GlobOpts::analyse_start) {
 		map<ulong, ByteRange*>::iterator it, it_end;
 		it = rm->ranges.begin();
-		timeval first_pcap_tstamp = it->second->sent_tstamp_pcap[0];
+		timeval first_pcap_tstamp = it->second->sent_tstamp_pcap[0].first;
 		it_end = rm->ranges.end();
 		for (; it != it_end; it++) {
-			timersub(&(it->second->sent_tstamp_pcap[0]), &first_pcap_tstamp, &tv);
+			timersub(&(it->second->sent_tstamp_pcap[0].first), &first_pcap_tstamp, &tv);
 			if (tv.tv_sec >= GlobOpts::analyse_start) {
 				rm->analyse_range_start = it;
 				rm->analyse_time_sec_start = tv.tv_sec;
 	if (GlobOpts::analyse_end) {
 		multimap<ulong, ByteRange*>::reverse_iterator rit, rit_end = rm->ranges.rend();
 		rit = rm->ranges.rbegin();
-		timeval last_pcap_tstamp = rit->second->sent_tstamp_pcap[0];
+		timeval last_pcap_tstamp = rit->second->sent_tstamp_pcap[0].first;
 		rit_end = rm->ranges.rend();
 		for (; rit != rit_end; rit++) {
-			timersub(&last_pcap_tstamp, &(rit->second->sent_tstamp_pcap[0]), &tv);
+			timersub(&last_pcap_tstamp, &(rit->second->sent_tstamp_pcap[0].first), &tv);
 			if (tv.tv_sec >= GlobOpts::analyse_end) {
 				rm->analyse_range_last = rm->analyse_range_end = rit.base();
 				rm->analyse_range_end++;
-				timersub(&(rit->second->sent_tstamp_pcap[0]), &rm->ranges.begin()->second->sent_tstamp_pcap[0], &tv);
+				timersub(&(rit->second->sent_tstamp_pcap[0].first), &rm->ranges.begin()->second->sent_tstamp_pcap[0].first, &tv);
 				rm->analyse_time_sec_end = tv.tv_sec;
 				break;
 			}
 	}
 	else if (GlobOpts::analyse_duration) {
 		ulong end_index = rm->ranges.size();
-		timeval begin_tv = rm->analyse_range_start->second->sent_tstamp_pcap[0];
+		timeval begin_tv = rm->analyse_range_start->second->sent_tstamp_pcap[0].first;
 		map<ulong, ByteRange*>::iterator begin_it, end_it, tmp_it;
 		begin_it = rm->analyse_range_start;
 		end_it = rm->ranges.end();
 			if (!advance) {
 				rm->analyse_range_end = rm->analyse_range_last = begin_it;
 				rm->analyse_range_end++;
-				timersub(&(begin_it->second->sent_tstamp_pcap[0]), &begin_tv, &tv);
+				timersub(&(begin_it->second->sent_tstamp_pcap[0].first), &begin_tv, &tv);
 				rm->analyse_time_sec_end = rm->analyse_time_sec_start + GlobOpts::analyse_duration;
 				break;
 			}
 			tmp_it = begin_it;
 			std::advance(tmp_it, advance);
 
-			timersub(&(tmp_it->second->sent_tstamp_pcap[0]), &begin_tv, &tv);
+			timersub(&(tmp_it->second->sent_tstamp_pcap[0].first), &begin_tv, &tv);
 			// Compares seconds, does not take into account milliseconds
 			// Shorter than the requested length
 			if (tv.tv_sec <= GlobOpts::analyse_duration) {
 void Connection::genBytesLatencyStats(struct byteStats* bs){
 	/* Iterate through vector and gather data */
 	rm->genStats(bs);
-	if (bs->nrRanges > 0)
-		bs->avgLat = bs->cumLat / bs->nrRanges;
 }
 
 
 
 	packetSizes[sent_time_bucket_idx].push_back(pair<timeval,uint64_t>(ts, ps));
 }
+
+void Connection::writePacketByteCountAndITT(ofstream* all_stream, ofstream* conn_stream) {
+	vector<vector<pair<timeval,uint64_t> > >::iterator i;
+	vector<pair<timeval,uint64_t> >::iterator j;
+
+	if (conn_stream) {
+		*conn_stream << "itt,packet_size" << endl;
+	}
+
+	uint64_t k = 0;
+	while (packetSizes[k].empty()) k++;
+
+	uint64_t prev = TV_TO_MS(packetSizes[k][0].first);
+	uint64_t itt, tmp;
+	for (i = packetSizes.begin(); i != packetSizes.end(); ++i) {
+		for (j = i->begin(); j != i->end(); ++j) {
+			if (!j->second)
+				continue;
+
+			tmp = TV_TO_MS(j->first);
+			itt = tmp - prev;
+			prev = tmp;
+
+			if (all_stream) {
+				*all_stream << itt << "," << j->second << endl;
+			}
+			if (conn_stream) {
+				*conn_stream << itt << "," << j->second << endl;
+			}
+		}
+	}
+}
+

File Connection.h

 	uint32_t getDuration(bool analyse_range_duration);
 
 	void registerPacketSize(const timeval& first_tstamp_in_dump, const timeval& pkt_tstamp, const uint64_t pkt_size);
+	void writePacketByteCountAndITT(ofstream* all_stream, ofstream* conn_stream);
 };
 #endif /* CONNECTION_H */
 int GlobStats::totNumBytes;
 
 /* Methods for class Dump */
-Dump::Dump(string src_ip, string dst_ip, string src_port, string dst_port, string fn) 
+Dump::Dump(string src_ip, string dst_ip, string src_port, string dst_port, string fn)
 {
 	timerclear(&first_sent_time);
 	srcIp = src_ip;
 	}
 }
 
+void print_stats_separator(bool final) {
+	if (final)
+		cout << "===============================================================" << endl << endl;
+	else
+		cout << "---------------------------------------------------------------" << endl;
+}
+
+// Update minimum values
+void updateMinStats(struct BaseStats& aggStats, struct BaseStats& stats) {
+	if (stats.min != -1 && stats.min < aggStats.min)
+		aggStats.min = stats.min;
+	if (stats.max != -1 && stats.max < aggStats.max)
+		aggStats.max = stats.max;
+	if (stats.avg != -1 && stats.avg  < aggStats.avg)
+		aggStats.avg = stats.avg;
+}
+
+// Update minimum values
+void updateMaxStats(struct BaseStats& aggStats, struct BaseStats& stats) {
+	if (stats.min != -1 && stats.min > aggStats.min)
+		aggStats.min = stats.min;
+	if (stats.max != -1 && stats.max > aggStats.max)
+		aggStats.max = stats.max;
+	if (stats.avg != -1 && stats.avg > aggStats.avg)
+		aggStats.avg = stats.avg;
+}
+
+
 /* Traverse the pcap dump and call methods for processing the packets
    This generates initial one-pass statistics from sender-side dump. */
 void Dump::printStatistics() {
-
 	/* Initiate struct for aggregate stats */
 	struct connStats cs, csAggregated;
 	memset(&cs, 0, sizeof(struct connStats));
 	memset(&csAggregated, 0, sizeof(struct connStats));
 
 	struct byteStats bsAggregated, bsAggregatedMin, bsAggregatedMax;
-	bsAggregatedMin.minLat = bsAggregatedMin.avgLat = bsAggregatedMin.maxLat = (numeric_limits<int>::max)();
-	bsAggregatedMin.minLength = bsAggregatedMin.avgLength = bsAggregatedMin.maxLength = (numeric_limits<int>::max)();
+	bsAggregatedMin.latency.min = bsAggregatedMin.latency.avg = bsAggregatedMin.latency.max = (numeric_limits<int64_t>::max)();
+	bsAggregatedMin.packet_length.min = bsAggregatedMin.packet_length.avg = bsAggregatedMin.packet_length.max = (numeric_limits<int64_t>::max)();
+	bsAggregatedMin.itt.min = bsAggregatedMin.itt.avg = bsAggregatedMin.itt.max = (numeric_limits<int64_t>::max)();
 
 	csAggregated.rdb_byte_hits = 0;
 	csAggregated.rdb_byte_misses = 0;
 	csAggregated.rdb_bytes_sent = 0;
 
-	int max_value = (numeric_limits<int>::max)();
+	int64_t max_value = (numeric_limits<int64_t>::max)();
 
 	// Print stats for each connection or aggregated
 	map<ConnectionMapKey*, Connection*, SortedConnectionKeyComparator> sortedConns;
 		if (!(GlobOpts::aggOnly)) {
 			bs.percentiles_lengths.init();
 			bs.percentiles_latencies.init();
+			bs.percentiles_itt.init();
 		}
 
 		cIt->second->genBytesLatencyStats(&bs);
 		}
 
 		if (GlobOpts::aggregate) {
-
-			bsAggregated.minLat += bs.minLat;
-			bsAggregated.maxLat += bs.maxLat;
-			bsAggregated.avgLat += bs.avgLat;
-			bsAggregated.cumLat += bs.cumLat;
-
-			// Get minimum values
-			if (bs.minLat && bs.minLat < bsAggregatedMin.minLat) {
-				bsAggregatedMin.minLat = bs.minLat;
-			}
-			if (bs.maxLat && bs.maxLat < bsAggregatedMin.maxLat) {
-				bsAggregatedMin.maxLat = bs.maxLat;
-			}
-			if (bs.avgLat && bs.avgLat < bsAggregatedMin.avgLat) {
-				bsAggregatedMin.avgLat = bs.avgLat;
-			}
-
-			// Get maximum values
-			if (bs.minLat && bs.minLat > bsAggregatedMax.minLat) {
-				bsAggregatedMax.minLat = bs.minLat;
-			}
-			if (bs.maxLat && bs.maxLat > bsAggregatedMax.maxLat)
-				bsAggregatedMax.maxLat = bs.maxLat;
-			if (bs.avgLat && bs.avgLat > bsAggregatedMax.avgLat)
-				bsAggregatedMax.avgLat = bs.avgLat;
-
-			if (bs.maxLat < 10) {
-				printf("bs.maxLat: %d\n", bs.maxLat);
-			}
+			// Latency
+			bsAggregated.latency += bs.latency;
+			updateMinStats(bsAggregatedMin.latency, bs.latency);
+			updateMaxStats(bsAggregatedMax.latency, bs.latency);
 
 			// Add the latency values
 			bsAggregated.latencies.insert(bsAggregated.latencies.end(), bs.latencies.begin(), bs.latencies.end());
 
-			if (bs.minLength != max_value) {
-				bsAggregated.minLength += bs.minLength;
-				bsAggregated.maxLength += bs.maxLength;
-				bsAggregated.avgLength += bs.avgLength;
-				bsAggregated.cumLength += bs.cumLength;
-
-				// Get minimum values
-				if (bsAggregatedMin.minLength > bs.minLength && bs.minLength > 0)
-					bsAggregatedMin.minLength = bs.minLength;
-				if (bsAggregatedMin.maxLength > bs.maxLength && bs.maxLength > 0)
-					bsAggregatedMin.maxLength = bs.maxLength;
-				if (bsAggregatedMin.avgLength > bs.avgLength && bs.avgLength > 0)
-					bsAggregatedMin.avgLength = bs.avgLength;
-
-				// Get maximum values
-				if (bsAggregatedMax.minLength < bs.minLength && bs.minLength > 0)
-					bsAggregatedMax.minLength = bs.minLength;
-				if (bsAggregatedMax.maxLength < bs.maxLength && bs.maxLength > 0)
-					bsAggregatedMax.maxLength = bs.maxLength;
-				if (bsAggregatedMax.avgLength < bs.avgLength && bs.avgLength > 0)
-					bsAggregatedMax.avgLength = bs.avgLength;
+			if (bs.packet_length.min != max_value) {
+				bsAggregated.packet_length += bs.packet_length;
+				updateMinStats(bsAggregatedMin.packet_length, bs.packet_length);
+				updateMaxStats(bsAggregatedMax.packet_length, bs.packet_length);
 
 				// Add the payload values
 				bsAggregated.payload_lengths.insert(bsAggregated.payload_lengths.end(), bs.payload_lengths.begin(), bs.payload_lengths.end());
 			}
 
+			if (bs.itt.min != max_value) {
+				// ITT
+				bsAggregated.itt += bs.itt;
+				updateMinStats(bsAggregatedMin.itt, bs.itt);
+				updateMaxStats(bsAggregatedMax.itt, bs.itt);
+				// Add the itt values
+				bsAggregated.intertransmission_times.insert(bsAggregated.intertransmission_times.end(), bs.intertransmission_times.begin(), bs.intertransmission_times.end());
+			}
+
 			// Add retrans stats
 			if ((ulong) bs.retrans.size() > bsAggregated.retrans.size()) {
 				for (ulong i = bsAggregated.retrans.size(); i < bs.retrans.size(); i++) {
 
 	if (GlobOpts::aggregate) {
 		if (csAggregated.nrPacketsSent) { /* To avoid division by 0 */
-			bsAggregated.avgLat /= sortedConns.size();
-			bsAggregated.avgLength /= sortedConns.size();
 			csAggregated.duration /= sortedConns.size();
-			bsAggregated.minLength /= sortedConns.size();
-			bsAggregated.maxLength /= sortedConns.size();
-			bsAggregated.minLat /= sortedConns.size();
-			bsAggregated.maxLat /= sortedConns.size();
+
+			bsAggregated.packet_length.min /= sortedConns.size();
+			bsAggregated.packet_length.avg /= sortedConns.size();
+			bsAggregated.packet_length.max /= sortedConns.size();
+
+			bsAggregated.latency.min /= sortedConns.size();
+			bsAggregated.latency.avg /= sortedConns.size();
+			bsAggregated.latency.max /= sortedConns.size();
+
+			bsAggregated.itt.min /= sortedConns.size();
+			bsAggregated.itt.avg /= sortedConns.size();
+			bsAggregated.itt.max /= sortedConns.size();
+
 			bsAggregated.percentiles_lengths.init();
 			bsAggregated.percentiles_latencies.init();
+			bsAggregated.percentiles_itt.init();
 
 			std::sort(bsAggregated.latencies.begin(), bsAggregated.latencies.end());
 			percentiles(&bsAggregated.latencies, &bsAggregated.percentiles_latencies);
 			std::sort(bsAggregated.payload_lengths.begin(), bsAggregated.payload_lengths.end());
 			percentiles(&bsAggregated.payload_lengths, &bsAggregated.percentiles_lengths);
+			std::sort(bsAggregated.intertransmission_times.begin(), bsAggregated.intertransmission_times.end());
+			percentiles(&bsAggregated.intertransmission_times, &bsAggregated.percentiles_itt);
 
 			cout << "\nAggregated Statistics for " << sortedConns.size() << " connections:" << endl;
 			printPacketStats(&csAggregated, &bsAggregated, true, &bsAggregatedMin, &bsAggregatedMax);
 
 			/* Print Aggregate bytewise latency */
 			printBytesLatencyStats(&csAggregated, &bsAggregated, true, &bsAggregatedMin, &bsAggregatedMax);
+
+			// ITT stats
+			printPacketITTStats(&csAggregated, &bsAggregated, true, &bsAggregatedMin, &bsAggregatedMax);
+			print_stats_separator(true);
 		}
 	}
+	itt_stream.close();
 }
 
-void print_stats_separator(bool final) {
-	if (final)
-		cout << "===============================================================" << endl << endl;
-	else
-		cout << "---------------------------------------------------------------" << endl;
-}
 
 /* Generate statistics for each connection.
    update aggregate stats if requested */
 	if (aggregated) {
 		printf("  Average of all packets in all connections     : %10d\n",
 		       (int) floorf((double) (cs->totBytesSent / cs->nrDataPacketsSent)));
-		printf("  Average of the average for each connection    : %10lld\n", bs->avgLength);
+		printf("  Average of the average for each connection    : %10d\n", (int) bs->packet_length.avg);
 	}
 	else {
-		printf("  Average                                       : %10lld\n", bs->avgLength);
+		printf("  Average                                       : %10d\n", (int) bs->packet_length.avg);
 	}
 
 	if (bs != NULL) {
 		if (aggregated) {
-			printf("  Minimum payload (min, avg, max)               :    %7lld, %7lld, %7lld bytes\n", aggregatedMin->minLength, bs->minLength, aggregatedMax->minLength);
-			printf("  Average payload (min, avg, max)               :    %7lld, %7lld, %7lld bytes\n", aggregatedMin->avgLength, bs->avgLength, aggregatedMax->avgLength);
-			printf("  Maximum payload (min, avg, max)               :    %7lld, %7lld, %7lld bytes\n", aggregatedMin->maxLength, bs->maxLength, aggregatedMax->maxLength);
-			printf("  Average for all packets in all all conns      : %10lld bytes\n", bs->cumLength / cs->nrPacketsSent);
+			printAggStats("payload", "bytes", cs, bs->packet_length, aggregatedMin->packet_length, aggregatedMax->packet_length);
 		}
 		else {
-			printf("  Minimum                                       : %10lld\n" \
-			       "  Maximum                                       : %10lld\n",
-			       bs->minLength, bs->maxLength);
+			printStats("payload", "bytes", bs->packet_length);
 		}
 
 		if (bs->percentiles_lengths.percentiles.size()) {
 				   cs->rdb_byte_misses, ((double) cs->rdb_byte_misses / cs->rdb_bytes_sent) * 100, ((double) cs->rdb_byte_misses / cs->totBytesSent) * 100);
 		}
 	}
+}
+
+
+/* Generate statistics for bytewise latency */
+void Dump::printPacketITTStats(struct connStats *cs, struct byteStats* bs, bool aggregated, struct byteStats* aggregatedMin, struct byteStats* aggregatedMax) {
 	print_stats_separator(false);
+	printf("ITT stats");
+
+ 	if (aggregated) {
+		printf(" (Average for all the connections)\n");
+	}
+	else
+		printf(":\n");
+
+	if (aggregated) {
+		printAggStats("ITT", "ms", cs, bs->itt, aggregatedMin->itt, aggregatedMax->itt);
+	}
+	else {
+		printStats("itt", "ms", bs->itt);
+	}
+
+	if (bs->percentiles_itt.percentiles.size()) {
+		bs->percentiles_itt.print("  %*sth percentile %-26s    : %10.0f ms\n", true);
+	}
+}
+
+
+void Dump::printStats(string prefix, string unit, struct BaseStats& bs) {
+	printf("  Minimum %s                                      : %7lu %s\n", prefix.c_str(), bs.min, unit.c_str());
+	printf("  Average %s                                      : %7.1f %s\n", prefix.c_str(), bs.avg, unit.c_str());
+	printf("  Maximum %s                                      : %7lu %s\n", prefix.c_str(), bs.max, unit.c_str());
+}
+
+void Dump::printAggStats(string prefix, string unit, struct connStats *cs, struct BaseStats& bs, struct BaseStats& aggregatedMin, struct BaseStats& aggregatedMax) {
+	printf("  Minimum %10s (min, avg, max)            :    %7lu, %7lu, %7lu %s\n", prefix.c_str(), aggregatedMin.min, bs.min, aggregatedMax.min, unit.c_str());
+	printf("  Average %10s (min, avg, max)            :    %7.0f, %7.0f, %7.0f %s\n", prefix.c_str(), aggregatedMin.avg, bs.avg, aggregatedMax.avg, unit.c_str());
+	printf("  Maximum %10s (min, avg, max)            :    %7lu, %7lu, %7lu %s\n", prefix.c_str(), aggregatedMin.max, bs.max, aggregatedMax.max, unit.c_str());
+	printf("  Average for all packets in all conns          : %10lu ms\n", bs.cum / cs->nrPacketsSent);
 }
 
 
 /* Generate statistics for bytewise latency */
 void Dump::printBytesLatencyStats(struct connStats *cs, struct byteStats* bs, bool aggregated, struct byteStats* aggregatedMin, struct byteStats* aggregatedMax) {
+	print_stats_separator(false);
 	printf("Latency stats");
 
 	if (aggregated) {
 		printf(":\n");
 
 	if (aggregated) {
-		printf("  Minimum latencies (min, avg, max)             :    %7d, %7d, %7d ms\n", aggregatedMin->minLat, bs->minLat, aggregatedMax->minLat);
-		printf("  Average latencies (min, avg, max)             :    %7lld, %7lld, %7lld ms\n", aggregatedMin->avgLat, bs->avgLat, aggregatedMax->avgLat);
-		printf("  Maximum latencies (min, avg, max)             :    %7d, %7d, %7d ms\n", aggregatedMin->maxLat, bs->maxLat, aggregatedMax->maxLat);
-		printf("  Average for all packets in all all conns      : %10lld ms\n", bs->cumLat / cs->nrPacketsSent);
+		printAggStats("latencies", "ms", cs, bs->latency, aggregatedMin->latency, aggregatedMax->latency);
 
 		if (GlobOpts::verbose) {
 			printf("\nAggregated latency values explained:\n"
 		}
 	}
 	else {
-		printf("  Minimum                                       : %7d ms\n", bs->minLat);
-		printf("  Average                                       : %7lld ms\n", bs->avgLat);
-		printf("  Maximum                                       : %7d ms\n", bs->maxLat);
+		printStats("latency", "ms", bs->latency);
 	}
 
 	if (bs->percentiles_latencies.percentiles.size()) {
 			//printf("  Occurrences of %2lu. dupacks                   : %d\n", i + 1, bs->dupacks[i]);
 		}
 	}
-	print_stats_separator(true);
 }
 
 void Dump::findTCPTimeStamp(struct DataSeg* data, uint8_t* opts, int option_length) {
 	}
 
 	printf("\nConnections in sender dump: %lu\n\n", conns.size());
-	printf("        %-30s   %-17s %-12s   %12s   %12s   %12s   %12s\n", "Conn key", "Duration (sec)", "Packets sent", "Packets recv", "Packet loss", "Byte loss", "Range loss");
+	printf("        %-30s   %-17s %-12s   %12s", "Conn key", "Duration (sec)", "Packets sent", "Loss (est)");
+
+	if (GlobOpts::withRecv) {
+		printf("%12s   %12s   %12s   %12s", "Packets recv", "Packet loss", "Byte loss", "Range loss");
+	}
+	printf("\n");
+
+	char loss_estimated[50];
+
 	for (cIt = sortedConns.begin(); cIt != sortedConns.end(); cIt++) {
 		memset(&cs, 0, sizeof(struct connStats));
 		cIt->second->addPacketStats(&cs);
 		cIt->second->addPacketStats(&csAggregated);
-		printf("   %-40s   %-17d  %-11d   %-11d %8.2f %%    %8.2f %%    %8.2f %%\n", cIt->second->getConnKey().c_str(), cs.duration,
-		       cs.nrPacketsSentFoundInDump, cs.nrPacketsReceivedFoundInDump,
-			   (((double) ((cs.nrPacketsSentFoundInDump - cs.nrPacketsReceivedFoundInDump)) / cs.nrPacketsSentFoundInDump) * 100),
-			   (cs.bytes_lost / (double) cs.totBytesSent) * 100,
-			   (cs.ranges_lost / (double) cs.ranges_sent) * 100);
+
+		if (cs.nrPacketsSent != cs.nrPacketsSentFoundInDump) {
+			sprintf(loss_estimated, "%.1f/%.1f", ((double) cs.nrRetrans / cs.nrPacketsSent) * 100, ((double) cs.nrRetrans / cs.nrPacketsSentFoundInDump) * 100);
+		}
+		else {
+			sprintf(loss_estimated, "%.1f", ((double) cs.nrRetrans / cs.nrPacketsSent) * 100);
+		}
+		printf("   %-40s   %-15d %-11d    %-11s", cIt->second->getConnKey().c_str(), cs.duration, cs.nrPacketsSentFoundInDump, loss_estimated);
+
+		if (GlobOpts::withRecv) {
+			printf("  %-11d %8.2f %%    %8.2f %%    %8.2f %%\n",
+				   cs.nrPacketsReceivedFoundInDump,
+				   (((double) ((cs.nrPacketsSentFoundInDump - cs.nrPacketsReceivedFoundInDump)) / cs.nrPacketsSentFoundInDump) * 100),
+				   (cs.bytes_lost / (double) cs.totBytesSent) * 100,
+				   (cs.ranges_lost / (double) cs.ranges_sent) * 100);
+		}
+		printf("\n");
 	}
+
 	if (GlobOpts::verbose >= 3) {
 		printf("\n   %-40s   %-17d   %-11d   %4.1f %%        %4.1f %%\n", "Average", 0,
 			   csAggregated.nrPacketsSentFoundInDump/(int)sortedConns.size(), (csAggregated.bytes_lost / (double) csAggregated.totBytesSent) * 100,
     s << v.all_bytes << ",";
 	s << (v.all_bytes - v.new_bytes) << ",";
 	s << v.new_bytes << ",";
-	
+
 	// total lost relative to sent within interval
 	if (v.tot_cnt_bytes != 0)
 		s << (v.cnt_bytes / v.tot_cnt_bytes) << ",";
 	double total_count = 0, total_bytes = 0;
 
 	const char* headers[] = {
-		"interval", 
+		"interval",
 		"ranges_sent", "all_bytes_sent", "old_bytes_sent", "new_bytes_sent",
 		"ranges_lost", "all_bytes_lost", "old_bytes_lost", "new_bytes_lost",
 		"ranges_lost_relative_to_interval", "all_bytes_lost_relative_to_interval", "old_bytes_lost_relative_to_interval", "new_bytes_lost_relative_to_interval",
-		"old_bytes_lost_relative_to_all_bytes_lost", "new_bytes_lost_relative_to_all_bytes_lost", 
+		"old_bytes_lost_relative_to_all_bytes_lost", "new_bytes_lost_relative_to_all_bytes_lost",
 		"ranges_lost_relative_to_total", "all_bytes_lost_relative_to_total"
 	};
 
 	}
 }
 
-/*
-  Writes packet loss to file aggregated of GlobOpts::lossAggrSeconds in CSV format.
-  loss-retr uses loss based on retransmissions.
-  With receiver side dump, the actual loss is used in loss-lost.
-*/
-/*void Dump::write_loss_to_file() {
-	FILE *loss_retr_file, *loss_lost_file = NULL;
-	stringstream loss_retr_fn, loss_lost_fn;
-	loss_retr_fn << GlobOpts::prefix << "loss-retr" << ".dat";
-	loss_lost_fn << GlobOpts::prefix << "loss-lost" << ".dat";
-	loss_retr_file = fopen(loss_retr_fn.str().c_str(), "w");
-
-	if (GlobOpts::withRecv) {
-		loss_lost_file = fopen(loss_lost_fn.str().c_str(), "w");
-		if (loss_lost_file == NULL) {
-			printf("Failed to open loss file for writing '%s'\n", loss_lost_fn.str().c_str());
-			return;
-		}
-	}
-	if (loss_retr_file == NULL) {
-		printf("Failed to open loss file for writing '%s'\n", loss_retr_fn.str().c_str());
-		return;
-	}
-
-	uint32_t timeslice_count = 0;
-
-	map<ConnectionMapKey*, Connection*>::iterator cIt, cItEnd;
-	for (cIt = conns.begin(); cIt != conns.end(); cIt++) {
-		timeslice_count = std::max(timeslice_count, cIt->second->getDuration(true));
-	}
-
-	unsigned timeslice = GlobOpts::lossAggrSeconds;
-
-	timeslice_count /= timeslice;
-	fprintf(loss_retr_file, "%45s %10u", " ", 0);
-	if (GlobOpts::withRecv)
-		fprintf(loss_lost_file, "%45s %10u", " ", 0);
-
-	// print columns
-	for (unsigned i = 1; i < timeslice_count; i++) {
-		fprintf(loss_retr_file, ",%10u", i);
-		if (GlobOpts::withRecv)
-			fprintf(loss_lost_file, ",%10u", i);
-	}
-	fprintf(loss_retr_file, "\n");
-	if (GlobOpts::withRecv)
-		fprintf(loss_lost_file, "\n");
-
-
-	for (cIt = conns.begin(); cIt != conns.end(); cIt++) {
-		cIt->second->rm->write_loss_over_time(timeslice, timeslice_count, loss_retr_file, loss_lost_file);
-	}
-
-	fclose(loss_retr_file);
-	if (GlobOpts::withRecv)
-		fclose(loss_lost_file);
-}*/
-
 
 void Dump::calculateLatencyVariation() {
 	map<ConnectionMapKey*, Connection*>::iterator it;
 	all_stream.open((GlobOpts::prefix + "queueing-delay-all.dat").c_str(), ios::out);
 
 	for (it = conns.begin(); it != conns.end(); ++it) {
-			it->second->writeSentTimesAndQueueingDelayVariance(first_tstamp, all_stream);
-
-			string filename;
-			filename = GlobOpts::prefix + "queueing-delay-" + it->second->getConnKey() + ".dat";
+		it->second->writeSentTimesAndQueueingDelayVariance(first_tstamp, all_stream);
 
-			ofstream stream;
-			stream.open(filename.c_str(), ios::out);
-			it->second->writeSentTimesAndQueueingDelayVariance(first_tstamp, stream);
-			stream.close();
+		string filename;
+		filename = GlobOpts::prefix + "queueing-delay-" + it->second->getConnKey() + ".dat";
 
+		ofstream stream;
+		stream.open(filename.c_str(), ios::out);
+		it->second->writeSentTimesAndQueueingDelayVariance(first_tstamp, stream);
+		stream.close();
 	}
-
 	all_stream.close();
 }
 
 	i++;
 }
 
+void Dump::writePacketByteCountAndITT() {
+	map<ConnectionMapKey*, Connection*>::iterator it;
+
+	ofstream* all_stream = NULL;
+	ofstream* conn_stream = NULL;
+
+	if (GlobOpts::aggregate) {
+		all_stream = new ofstream;
+		all_stream->open((GlobOpts::prefix + "packet-byte-count-and-itt-all.dat").c_str(), ios::out);
+		*all_stream << "itt,packet_size" << endl;
+	}
+
+	for (it = conns.begin(); it != conns.end(); ++it) {
+
+		if (!GlobOpts::aggOnly) {
+			string filename (GlobOpts::prefix + "packet-byte-count-and-itt-" + it->second->getConnKey() + ".dat");
+			conn_stream = new ofstream;
+			conn_stream->open(filename.c_str(), ios::out);
+		}
+
+		it->second->writePacketByteCountAndITT(all_stream, conn_stream);
+
+		if (!GlobOpts::aggOnly) {
+			conn_stream->close();
+			delete conn_stream;
+		}
+	}
+
+	if (GlobOpts::aggregate) {
+		all_stream->close();
+		delete all_stream;
+	}
+}
+
+
 void Dump::free_resources() {
 	map<ConnectionMapKey*, Connection*>::iterator cIt, cItEnd;
 	for (cIt = conns.begin(); cIt != conns.end(); cIt++) {
 	void processRecvd(const struct pcap_pkthdr* header, const u_char *data);
 	void processAcks(const struct pcap_pkthdr* header, const u_char *data);
 	void registerRecvd(const struct pcap_pkthdr* header, const u_char *data);
+	void printAggStats(string prefix, string unit, struct connStats *cs, struct BaseStats& bs, struct BaseStats& aggregatedMin, struct BaseStats& aggregatedMax);
+	void printStats(string prefix, string unit, struct BaseStats& bs);
 	void printPacketStats(struct connStats *cs, struct byteStats *bs, bool aggregated, struct byteStats* aggregatedMin, struct byteStats* aggregatedMax);
 	void printBytesLatencyStats(struct connStats *cs, struct byteStats* bs, bool aggregated, struct byteStats* aggregatedMin, struct byteStats* aggregatedMax);
+	void printPacketITTStats(struct connStats *cs, struct byteStats* bs, bool aggregated, struct byteStats* aggregatedMin, struct byteStats* aggregatedMax);
 public:
 	Dump(string src_ip, string dst_ip, string src_port, string dst_port, string fn);
 	uint64_t get_relative_sequence_number(uint32_t ack, uint32_t firstSeq, ulong largestAckSeq, uint32_t largestAckSeqAbsolute, Connection *conn);
 	void printConns();
 	void printStatistics();
 	void genAckLatencyFiles();
+	void writePacketByteCountAndITT();
 	void write_loss_to_file();
 	void calculateLatencyVariation();
 	void makeByteLatencyVariationCDF();

File RangeManager.cc

 
 #ifdef DEBUG
 	int debug_print = 0;//GlobOpts::debugLevel == 6;
-	if (TV_TO_MS(data_seg->tstamp_pcap) == 1396710194676) {
-		printf("\n\nHEEEEEEI sent:%d level:%d\n\n", sent, level);
-		printf("%s\n", conn->getConnKey().c_str());
-		debug_print = 1;
-	}
+	//if (TV_TO_MS(data_seg->tstamp_pcap) == 1396710194676) {
+	//	printf("\n\nHEEEEEEI sent:%d level:%d\n\n", sent, level);
+	//	printf("%s\n", conn->getConnKey().c_str());
+	//	debug_print = 1;
+	//}
 	//debug_print = 1;
 
 
 					ByteRange *new_br;
 					if (start_matches) {
 						new_br = cur_br->split_end(end_seq + 1, cur_br->endSeq);
-						cur_br->packet_sent_count++;
+						//cur_br->packet_sent_count++;
 						if (data_seg->flags & TH_FIN) {
 							cur_br->fin += 1;
 						}
 					}
 					else if (end_matches) {
 						new_br = cur_br->split_end(start_seq, cur_br->endSeq);
-						new_br->packet_sent_count++;
+						//new_br->packet_sent_count++;
 						if (data_seg->flags & TH_FIN) {
 							new_br->fin = 1;
 						}
 					else if (end_seq < cur_br->endSeq) {
 						// Split in the middle
 						new_br = cur_br->split_end(start_seq, cur_br->endSeq);
-						new_br->packet_sent_count++;
+						//new_br->packet_sent_count++;
 						if (data_seg->flags & TH_FIN) {
 							new_br->fin = 1;
 						}
 					// New data reaches beyond current range
 					else {
 						new_br = cur_br->split_end(start_seq, cur_br->endSeq);
-						new_br->packet_sent_count++;
+						//new_br->packet_sent_count++;
 						range_received = new_br;
 						insert_more_recursively = 1;
 					}
 			//printf("ByteRange size: %lu\n", sizeof(*last_br));
 
 			last_br->original_payload_size = data_seg->payloadSize;
+			last_br->original_packet_is_rdb = data_seg->is_rdb;
 			if (data_seg->is_rdb) {
-				last_br->original_packet_is_rdb = true;
 				// Packet sent is already counted on previous range
-				last_br->packet_sent_count = 0;
+				//last_br->packet_sent_count = 0;
 			}
 
-			last_br->increase_sent(data_seg->tstamp_tcp, data_seg->tstamp_pcap, this_is_rdb_data);
+			last_br->increase_sent(data_seg->tstamp_tcp, data_seg->tstamp_pcap, this_is_rdb_data, !data_seg->is_rdb);
 			if (data_seg->flags & TH_SYN) {
 				assert("SYN" && 0);
 				last_br->syn = 1;
 						//colored_printf(RED, "SYN: %d, FIN: %d\n", !!(data_seg->flags & TH_SYN), data_seg->flags & TH_FIN);
 						brIt->second->syn += !!(data_seg->flags & TH_SYN);
 						brIt->second->fin += !!(data_seg->flags & TH_FIN);
-						brIt->second->increase_sent(data_seg->tstamp_tcp, data_seg->tstamp_pcap, this_is_rdb_data);
+						brIt->second->increase_sent(data_seg->tstamp_tcp, data_seg->tstamp_pcap, this_is_rdb_data, false);
 						brIt->second->packet_retrans_count += 1;
 					}
 					else if (data_seg->flags & TH_RST) {
 				if (sent) {
 					assert("sent_count is 0!" && brIt->second->sent_count > 0);
 
-					brIt->second->increase_sent(data_seg->tstamp_tcp, data_seg->tstamp_pcap, this_is_rdb_data);
+					brIt->second->increase_sent(data_seg->tstamp_tcp, data_seg->tstamp_pcap, this_is_rdb_data, !level);
 
 					if (!level) {
 						brIt->second->packet_retrans_count += data_seg->retrans;
-						brIt->second->packet_sent_count++;
+						//brIt->second->packet_sent_count++;
 						if (data_seg->flags & TH_FIN) {
 							brIt->second->fin += 1;
 						}
 				if (sent) {
 					if (!level) {
 						brIt->second->packet_retrans_count += data_seg->retrans;
-						brIt->second->packet_sent_count++;
+						//brIt->second->packet_sent_count++;
 						if (data_seg->flags & TH_FIN) {
 							brIt->second->fin += 1;
 						}
 					}
 					brIt->second->data_retrans_count += data_seg->retrans;
 					brIt->second->rdb_count += data_seg->is_rdb;
-					brIt->second->increase_sent(data_seg->tstamp_tcp, data_seg->tstamp_pcap, this_is_rdb_data);
+					brIt->second->increase_sent(data_seg->tstamp_tcp, data_seg->tstamp_pcap, this_is_rdb_data, !level);
 #ifdef DEBUG
 					if (this_is_rdb_data) {
 						assert(data_seg->retrans != 0 && "Should not be retrans!\n");
 		else {
 			// The end_seq of the new range correspond to the end-seq of the entry in the map, so it's a duplicate
 			if (sent) {
-				brIt->second->increase_sent(data_seg->tstamp_tcp, data_seg->tstamp_pcap, this_is_rdb_data);
+				brIt->second->increase_sent(data_seg->tstamp_tcp, data_seg->tstamp_pcap, this_is_rdb_data, !level);
 				if (!level) {
 					brIt->second->packet_retrans_count += data_seg->retrans;
-					brIt->second->packet_sent_count++;
+					//brIt->second->packet_sent_count++;
 					if (data_seg->flags & TH_FIN) {
 						brIt->second->fin += 1;
 					}
 				printf("  Covers more than Range(%lu, %lu)\n", relative_seq(tmpRange->getStartSeq()), relative_seq(tmpRange->getEndSeq()));
 
 
-			if (timercmp(&seg->tstamp_pcap, &(tmpRange->sent_tstamp_pcap[0]), <)) {
+			if (timercmp(&seg->tstamp_pcap, &(tmpRange->sent_tstamp_pcap[0].first), <)) {
 				printf("ACK TIME IS EARLIER THAN SEND TIME!\n");
 				return false;
 			}
 	}
 }
 
+struct SentTime {
+	int64_t time;
+	uint16_t size;
+	SentTime(int t, uint16_t s) : time(t), size(s) {}
+
+	bool operator < (const SentTime& other) const {
+        return (time < other.time);
+    }
+};
+
+
 void RangeManager::genStats(struct byteStats *bs) {
-	int latency;
 	map<ulong, ByteRange*>::iterator it, it_end;
 	it = analyse_range_start;
 	it_end = analyse_range_end;
 
-	int tmp_byte_count = 0;
-	bs->minLat = bs->minLength = (numeric_limits<int>::max)();
+	vector<struct SentTime> sent_times;
+	int64_t latency, tmp_byte_count, itt;
+	bs->latency.min = bs->packet_length.min = bs->itt.min = (numeric_limits<int64_t>::max)();
 	int dupack_count;
 
 	for (; it != it_end; it++) {
 		// Skip if invalid (negative) latency
 		tmp_byte_count = it->second->getOrinalPayloadSize();
 		bs->payload_lengths.push_back(tmp_byte_count);
-		bs->cumLength += tmp_byte_count;
+		bs->latency.cum += tmp_byte_count;
 		for (int i = 0; i < it->second->getNumRetrans(); i++) {
 			bs->payload_lengths.push_back(tmp_byte_count);
-			bs->cumLength += tmp_byte_count;
+			bs->latency.cum += tmp_byte_count;
+		}
+
+		for (size_t i = 0; i < it->second->sent_tstamp_pcap.size(); i++) {
+			if (it->second->sent_tstamp_pcap[i].second)
+				sent_times.push_back(SentTime(TV_TO_MS(it->second->sent_tstamp_pcap[i].first), tmp_byte_count));
 		}
 
 		dupack_count = it->second->dupack_count;
 		}
 
 		if (tmp_byte_count) {
-			if (tmp_byte_count > bs->maxLength)
-				bs->maxLength = tmp_byte_count;
-			if (tmp_byte_count < bs->minLength) {
-				bs->minLength = tmp_byte_count;
+			if (tmp_byte_count > bs->packet_length.max)
+				bs->packet_length.max = tmp_byte_count;
+			if (tmp_byte_count < bs->packet_length.min) {
+				bs->packet_length.min = tmp_byte_count;
 			}
 		}
 
 		if ((latency = it->second->getSendAckTimeDiff(this))) {
 			bs->latencies.push_back(latency);
-			bs->cumLat += latency;
-			if (latency > bs->maxLat) {
-				bs->maxLat = latency;
+			bs->latency.cum += latency;
+			if (latency > bs->latency.max) {
+				bs->latency.max = latency;
 			}
-			if (latency < bs->minLat) {
-				bs->minLat = latency;
+			if (latency < bs->latency.min) {
+				bs->latency.min = latency;
 			}
 			bs->nrRanges++;
 		} else {
 		}
 	}
 
+	std::sort(sent_times.begin(), sent_times.end());
+
+	SentTime prev = sent_times[0];
+	for (size_t i = 1; i < sent_times.size(); i++) {
+		itt = sent_times[i].time - prev.time;
+		bs->intertransmission_times.push_back(itt);
+		prev = sent_times[i];
+		bs->itt.cum += itt;
+
+		if (itt > bs->itt.max)
+			bs->itt.max = itt;
+
+		if (itt < bs->itt.min) {
+			bs->itt.min = itt;
+		}
+	}
+
 	double temp;
 	double stdev;
 	if (bs->latencies.size()) {
-		double sumLat = bs->cumLat;
+		double sumLat = bs->latency.cum;
 		double mean =  sumLat / bs->latencies.size();
 		temp = 0;
 
 		}
 
 		std::sort(bs->latencies.begin(), bs->latencies.end());
-
 		stdev = sqrt(temp / (bs->latencies.size()));
 		bs->stdevLat = stdev;
+		bs->latency.avg = mean;
 		percentiles(&bs->latencies, &bs->percentiles_latencies);
 	}
 	else
-		bs->minLat = 0;
+		bs->latency.min = bs->latency.avg = bs->latency.max = -1;
 
 	if (bs->payload_lengths.size()) {
 		// Payload size stats
 		double sumLen = analysed_bytes_sent;
-		double meanLen =  sumLen / bs->payload_lengths.size();
-		bs->avgLength = meanLen;
+		double meanLen = sumLen / bs->payload_lengths.size();
+		bs->packet_length.avg = meanLen;
 		temp = 0;
 		for (unsigned int i = 0; i < bs->payload_lengths.size(); i++) {
 			temp += (bs->payload_lengths[i] - meanLen) * (bs->payload_lengths[i] - meanLen);
 		percentiles(&bs->payload_lengths, &bs->percentiles_lengths);
 	}
 	else
-		bs->minLength = 0;
+		bs->packet_length.min = bs->packet_length.avg = bs->packet_length.max = -1;
+
+	if (bs->intertransmission_times.size()) {
+		// Payload size stats
+		//double sumLen = analysed_bytes_sent;
+		//double meanLen =  sumLen / bs->payload_lengths.size();
+		//bs->avgLength = meanLen;
+		//temp = 0;
+		//for (unsigned int i = 0; i < bs->payload_lengths.size(); i++) {
+		//	temp += (bs->payload_lengths[i] - meanLen) * (bs->payload_lengths[i] - meanLen);
+		//}
+
+		//std::sort(bs->payload_lengths.begin(), bs->payload_lengths.end());
+		//stdev = sqrt(temp / (bs->payload_lengths.size()));
+		//bs->stdevLength = stdev;
+		bs->itt.avg = (double) bs->itt.cum / sent_times.size();
+		percentiles(&bs->intertransmission_times, &bs->percentiles_lengths);
+	}
+	else
+		bs->itt.min = bs->itt.avg = bs->itt.max = -1;
 }
 
 /* Check that every byte from firstSeq to lastSeq is present.
 
 	for (; it != it_end; it++) {
 		long diff = it->second->getRecvDiff() - lowestRecvDiff;
-		int64_t ts = TV_TO_MS(it->second->sent_tstamp_pcap[it->second->send_tcp_stamp_recv_index]);
+		int64_t ts = TV_TO_MS(it->second->sent_tstamp_pcap[it->second->send_tcp_stamp_recv_index].first);
 
 		assert(diff >= 0 && "Negative diff, this shouldn't happen!");
 
 	assert(GlobOpts::withRecv && "Writing loss grouped by interval requires receiver trace");
 
 	vector< pair<uint32_t, timeval> >::iterator lossIt, lossEnd;
-	vector<timeval>::iterator sentIt, sentEnd;
+	vector<pair<timeval, uint8_t> >::iterator sentIt, sentEnd;
 	map<ulong, ByteRange*>::iterator range;
 
 	// Extract total values from ranges
 		sentEnd = range->second->sent_tstamp_pcap.end();
 
 		if (sentIt != sentEnd && range->second->packet_sent_count > 0) {
-			uint64_t bucket_idx = interval_idx(*sentIt, first);
+			uint64_t bucket_idx = interval_idx((*sentIt).first, first);
 
 			while (bucket_idx >= tc.size()) {
 				tc.push_back(0);
 		// Place sent counts and byte counts in the right bucket
 		for (; sentIt != sentEnd; ++sentIt)
 		{
-			uint64_t bucket_idx = interval_idx(*sentIt, first);
+			uint64_t bucket_idx = interval_idx((*sentIt).first, first);
 
 			while (bucket_idx >= tc.size()) {
 				tc.push_back(0);
 		lossIt = range->second->lost_tstamps_tcp.begin();
 		lossEnd = range->second->lost_tstamps_tcp.end();
 
-		if (lossIt != lossEnd && 
-				range->second->packet_sent_count > 0 &&
-				lossIt->second == range->second->sent_tstamp_pcap[0]) {
-			uint64_t bucket_idx = interval_idx(range->second->sent_tstamp_pcap[0], first);
+		if (lossIt != lossEnd &&
+			range->second->packet_sent_count > 0 &&
+			lossIt->second == range->second->sent_tstamp_pcap[0].first) {
+			uint64_t bucket_idx = interval_idx(range->second->sent_tstamp_pcap[0].first, first);
 
 			while (bucket_idx >= loss.size()) {
 				loss.push_back(LossInterval(0, 0, 0));
 		if (diff_tmp > 0) {
 			num_retr_tmp = it->second->getNumRetrans();
 
-			send_time_ms = TV_TO_MS(it->second->sent_tstamp_pcap[0]);
-			//printf("%lu.%lu -> %lu\n", it->second->sent_tstamp_pcap[0].tv_sec, it->second->sent_tstamp_pcap[0].tv_usec, send_time_ms);
+			send_time_ms = TV_TO_MS(it->second->sent_tstamp_pcap[0].first);
+			//printf("%lu.%lu -> %lu\n", it->second->sent_tstamp_pcap[0].first.tv_sec, it->second->sent_tstamp_pcap[0].first.tv_usec, send_time_ms);
 
 			send_time_ms -= first_tstamp;
 

File analyseTCP.cc

 	if (GlobOpts::genAckLatencyFiles)
 		senderDump->genAckLatencyFiles();
 
-	if (GlobOpts::withThroughput)
+	if (GlobOpts::withThroughput) {
 		senderDump->writeByteCountGroupedByInterval();
+		senderDump->writePacketByteCountAndITT();
+	}
 
 	if (GlobOpts::withLoss)
 		senderDump->write_loss_to_file();
 	}
 
 	senderDump->printStatistics();
-
 	senderDump->printDumpStats();
 	senderDump->free_resources();
 

File analyseTCP.h

 	}
 };
 
+struct BaseStats {
+	int64_t min;
+	double avg;
+	int64_t max;
+	int64_t cum;
+	BaseStats() : min(0), avg(0), max(0), cum(0) {}
+
+	BaseStats& operator+=(const BaseStats &rhs) {
+		min += rhs.min;
+		avg += rhs.avg;
+		max += rhs.max;
+		cum += rhs.cum;
+		return *this;
+	}
+};
+
 /* Struct used to keep track of bytewise latency stats */
 struct byteStats {
-	int maxLat;     /* Maximum Latency */
-	int minLat;     /* Minimum Latency */
-	long long int cumLat;     /* Cumulative latency */
-	Percentiles percentiles_latencies;
-	double stdevLat;
 	int nrRanges;   /* Number of ranges in conn */
-	long long int avgLat;   /* Average latency */
-	vector<int> retrans;
-	vector<int> dupacks;
-	long long int maxLength;
-	long long int minLength;
-	long long int cumLength;
-	long long int avgLength;
+
+	struct BaseStats latency;
+	struct BaseStats packet_length;
+	struct BaseStats itt;
+
+	double stdevLat;
 	double stdevLength;
+
+	Percentiles percentiles_latencies;
 	Percentiles percentiles_lengths;
+	Percentiles percentiles_itt;
+
 	vector<double> latencies;
 	vector<double> payload_lengths;
 	vector<double> intertransmission_times;
-	byteStats() : maxLat(0), minLat(0), cumLat(0), stdevLat(0), nrRanges(0), avgLat(0),
-				  maxLength(0), minLength(0), cumLength(0), avgLength(0), stdevLength(0) {
+
+	vector<int> retrans;
+	vector<int> dupacks;
+	byteStats() : nrRanges(0), stdevLength(0) {
 	}
 };