Skip to content

Commit

Permalink
complete overhaul of live mode
Browse files Browse the repository at this point in the history
  • Loading branch information
AP-Frank committed Sep 21, 2018
1 parent f51afda commit ec4dacf
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 212 deletions.
15 changes: 3 additions & 12 deletions examples/moonsniff/sniffer.lua
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ local ffi = require "ffi"
local C = ffi.C

local MS_TYPE = 0b01010101
local LIVE_MODE_FILE_TYPE = C.ms_text -- alternative: C.ms_binary

function configure(parser)
parser:description("Demonstrate and test hardware latency induced by a device under test.\nThe ideal test setup is to use 2 taps, one should be connected to the ingress cable, the other one to the egress one.\n\n For more detailed information on possible setups and usage of this script have a look at moonsniff.md.")
Expand Down Expand Up @@ -44,7 +43,6 @@ function master(args)
local dev1rx = args.dev[2]:getRxQueue(0)

if args.live then
C.ms_init(args.output .. ".csv", LIVE_MODE_FILE_TYPE)
stats.startStatsTask{rxDevices = {args.dev[1], args.dev[2]}}
else
-- if we are not live we want to print the stats to a seperate file so they are easily
Expand All @@ -71,8 +69,6 @@ function master(args)
receiver1:wait()
lm.stop()

if args.live then C.ms_finish() end

log:info("Finished all capturing/writing operations")

if args.live then printStats(args) end
Expand Down Expand Up @@ -200,23 +196,18 @@ function printStats(args)
lm.sleepMillis(500)
print()

stats = C.ms_post_process(args.output .. ".csv", LIVE_MODE_FILE_TYPE)
stats = C.ms_fetch_stats()
hits = stats.hits
misses = stats.misses
cold = stats.cold_misses
invalidTS = stats.inval_ts
overwrites = stats.overwrites
print("Received: " .. hits + misses)
print("\tHits: " .. hits)
print("\tHits with invalid timestamps: " .. invalidTS)
print("\tMisses: " .. misses)
print("\tCold Misses: " .. cold)
print("\tOverwrites: " .. overwrites)
print("\tCold Overwrites: " .. stats.cold_overwrites)
print("\tLoss by misses: " .. (misses/(misses + hits)) * 100 .. "%")
print("\tTotal loss: " .. ((misses + invalidTS)/(misses + hits)) * 100 .. "%")
print("Average Latency: " .. tostring(tonumber(stats.average_latency)/10^3) .. " us")

print("Average latency: " .. tostring(tonumber(stats.average_latency)/10^3) .. " us")
print("Variance of latency: " .. tostring(tonumber(stats.variance_latency)/10^3) .. " us")
end

function iodebug(args)
Expand Down
12 changes: 3 additions & 9 deletions lua/moonsniff-io.lua
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,16 @@ local C = ffi.C
ffi.cdef[[
//----------------Moonsniff Live IO------------------------
struct ms_stats {
uint64_t average_latency;
int64_t average_latency;
int64_t variance_latency;
uint32_t hits;
uint32_t misses;
uint32_t cold_misses;
uint32_t inval_ts;
uint32_t overwrites;
uint32_t cold_overwrites;
};

enum ms_mode { ms_text, ms_binary };

void ms_add_entry(uint32_t identification, uint64_t timestamp);
void ms_test_for(uint32_t identification, uint64_t timestamp);
void ms_init(const char* fileName, enum ms_mode mode);
void ms_finish();
struct ms_stats ms_post_process(const char* fileName, enum ms_mode mode);
struct ms_stats ms_fetch_stats();

//---------------MSCAP Writer/Reader-------------------------
struct mscap {
Expand Down
226 changes: 35 additions & 191 deletions src/moonsniff.cpp
Original file line number Diff line number Diff line change
@@ -1,20 +1,12 @@
#include <cstdint>
#include <string>
#include <deque>
#include <iostream>
#include <fstream>
#include <mutex>
#include <cstring>
#include <thread>
#include <unordered_map>
#include <rte_mbuf.h>
#include <rte_mempool.h>
#include <rte_ether.h>
#include <rte_ip.h>
#include <rte_byteorder.h>

#define UINT24_MAX 16777215
#define INDEX_MASK (uint32_t) 0x00FFFFFF
#define NEGATIVE_THRESH -100 // Latencies smaller than this threshold are ignored


/*
* This namespace holds functions which are used by MoonSniff's Live Mode
Expand All @@ -23,167 +15,27 @@
*/
namespace moonsniff {

struct ms_timestamps {
uint64_t pre; // timestamp of packet before entering DUT
uint64_t post; // timestamp of packet after leaving DUT
};
// vars for live average computation
uint64_t count = 0;
double m2 = 0;
double mean = 0;
double variance = 0;

/**
* Base class for all file-writers
*
* The writers are responsible to write pre/post timestamp pairs
*/
class Writer {
protected:
std::ofstream file;
public:
virtual void write_to_file(uint64_t old_ts, uint64_t new_ts) = 0;
void finish(){
file.close();
}
void check_stream(const char* fileName){
if( file.fail() ){
std::cerr << "Failed to open file < " << fileName << " >\nMake sure this file exists.\n\n";
exit(EXIT_FAILURE);
}
}

};

class Text_Writer: public Writer {
public:
void write_to_file(uint64_t old_ts, uint64_t new_ts){
file << old_ts << " " << new_ts << "\n";
}

Text_Writer(const char* fileName){
file.open(fileName);
check_stream(fileName);
}
};

class Binary_Writer: public Writer {
public:
void write_to_file(uint64_t old_ts, uint64_t new_ts){
file.write(reinterpret_cast<const char*>(&old_ts), sizeof(uint64_t));
file.write(reinterpret_cast<const char*>(&new_ts), sizeof(uint64_t));
}

Binary_Writer(const char* fileName){
file.open(fileName, std::ios::binary);
check_stream(fileName);
}
};

/**
* Base class for all file-readers
*
* Reads pre/post timestamp pairs from a file
* Statistics which are exposed to applications
*/
class Reader {
protected:
std::ifstream file;
ms_timestamps ts;
public:
virtual ms_timestamps read_from_file() = 0;
virtual bool has_next() = 0;
void finish(){
file.close();
}
void check_stream(const char* fileName){
if( file.fail() ){
std::cerr << "Failed to open file < " << fileName << " >\nMake sure this file exists.\n\n";
exit(EXIT_FAILURE);
}
}
};

class Text_Reader: public Reader {
public:
bool has_next(){
return file >> ts.pre >> ts.post ? true : false;
}

ms_timestamps read_from_file(){
return ts;
}

Text_Reader(const char* fileName){
file.open(fileName);
check_stream(fileName);
}
};

class Binary_Reader: public Reader {
private:
std::streampos end;
public:
bool has_next(){
return end > file.tellg();
}

ms_timestamps read_from_file(){
file.read(reinterpret_cast<char*>(&ts.pre), sizeof(uint64_t));
file.read(reinterpret_cast<char*>(&ts.post), sizeof(uint64_t));

return ts;
}

Binary_Reader(const char* fileName){
file.open(fileName, std::ios::binary | std::ios::ate);
check_stream(fileName);
end = file.tellg();
file.seekg(0, std::ios::beg);

if ( (end - file.tellg()) % 16 != 0 ){
std::cerr << "Invalid binary file detected. Are you sure it was created in ms_binary mode?" << "\n";
exit(EXIT_FAILURE);
}
}
};


struct ms_stats {
uint64_t average_latency = 0;
int64_t average_latency = 0;
int64_t variance_latency = 0;
uint32_t hits = 0;
uint32_t misses = 0;
uint32_t inval_ts = 0;
} stats;

/**
* Enum to change the reading/writing mode
*/
enum ms_mode { ms_text, ms_binary };

std::ofstream file;

// initialize array and as many mutexes to ensure memory order
uint64_t hit_list[UINT24_MAX + 1] = { 0 };
std::mutex mtx[UINT24_MAX + 1];

Writer* writer;

/**
* Initializes the writers for the output file. Should be called before calling other functions.
*
* @param fileName Name of the output file
* @param mode The type of the Writer which shall be created
*/
static void init(const char* fileName, ms_mode mode){
if( mode == ms_binary ){
writer = new Binary_Writer(fileName);
} else {
writer = new Text_Writer(fileName);
}
}

/**
* Call when finished writing operations. Closes underlying writers.
*/
static void finish(){
writer -> finish();
}

/**
* Add a pre DUT timestamp to the array.
*
Expand All @@ -199,7 +51,7 @@ namespace moonsniff {

/**
* Check if there exists an entry in the array for the given identifier.
* Retrieves the pre DUT timestamp (if existing) and writes timestamp pair into a file.
* Updates current mean and variance estimation..
*
* @param identification Identifier for which an entry is searched
* @param timestamp The post timestamp
Expand All @@ -212,40 +64,35 @@ namespace moonsniff {
mtx[index].unlock();
if( old_ts != 0 ){
++stats.hits;
writer -> write_to_file(old_ts, timestamp);
// diff overflow improbable (latency > 290 years)
int64_t diff = timestamp - old_ts;
if (diff < -NEGATIVE_THRESH){
std::cerr << "Measured latency below " << NEGATIVE_THRESH
<< " (Threshold). Ignoring...\n";
}
++count;
double delta = diff - mean;
mean = mean + delta / count;
double delta2 = diff - mean;
m2 = m2 + delta * delta2;
} else {
++stats.misses;
}
}

/**
* Reads the output file which contains timestamp pairs.
* Computes the average latency from all pairs.
*
* @param fileName The name of the file generated during the sniffing phase
* @param mode The mode in which the file was written (ms_text, ms_binary)
* Fetch statistics. Finalizes variance computation..
*/
static ms_stats post_process(const char* fileName, ms_mode mode){
Reader* reader;
if( mode == ms_binary ){
reader = new Binary_Reader(fileName);
} else {
reader = new Text_Reader(fileName);
}
uint64_t size = 0, sum = 0;

while( reader -> has_next() ){
ms_timestamps ts = reader -> read_from_file();
if( ts.pre < ts.post && ts.post - ts.pre < 1e9 ){
sum += ts.post - ts.pre;
++size;
} else {
++stats.inval_ts;
}
}
std::cout << size << ", " << sum << "\n";
stats.average_latency = size != 0 ? sum/size : 0;
reader -> finish();
static ms_stats fetch_stats(){
if (count < 2) {
std::cerr << "Not enough members to calculate mean and variance\n";
} else {
variance = m2 / (count - 1);
}

// Implicit cast from double to int64_t -> sub-nanosecond parts are discarded
stats.average_latency = mean;
stats.variance_latency = variance;
return stats;
}
}
Expand All @@ -259,10 +106,7 @@ extern "C" {
moonsniff::test_for(identification, timestamp);
}

moonsniff::ms_stats ms_post_process(const char* fileName, moonsniff::ms_mode mode){
return moonsniff::post_process(fileName, mode);
moonsniff::ms_stats ms_fetch_stats(){
return moonsniff::fetch_stats();
}

void ms_init(const char* fileName, moonsniff::ms_mode mode){ moonsniff::init(fileName, mode); }
void ms_finish(){ moonsniff::finish(); }
}

0 comments on commit ec4dacf

Please sign in to comment.