Bladeren bron

added instrumentation

tristangurtler 3 jaren geleden
bovenliggende
commit
9254fdd76b

+ 2 - 2
prsona/Makefile

@@ -105,7 +105,7 @@ MG_OBJ += $(MG_OBJ_PATH)/civetweb.o
 MG_OBJ += $(MG_OBJ_PATH)/CivetServer.o
 
 $(MG_OBJ_PATH)/%.o: 
-	make -C ../civetweb WITH_WEBSOCKET=1 WITH_CPP=1 lib
+	make -C ../civetweb WITH_WEBSOCKET=1 WITH_CPP=1 WITH_SERVER_STATS=1 lib
 
 $(PRSONA_BIN_PATH)/localTest: $(PRSONA_OBJ_PATH)/localMain.o $(PRSONA_OBJ) $(BGN_OBJ_PATH)/bgn.a
 	$(CPP) $(CPPFLAGS) -no-pie -o $@ $^ $(LDFLAGS)
@@ -131,7 +131,7 @@ seemly:
 	-pkill server
 
 demolition:
-	scripts/bringDownTestServers.sh
+	-scripts/bringDownTestServers.sh
 
 prsona_clean: 
 	-rm $(PRSONA_BIN_PATH)/*

+ 18 - 3
prsona/inc/networkClient.hpp

@@ -30,7 +30,10 @@ void make_vote(
     const std::vector<int>& serverPorts,
     const std::string& target,
     int targetPort,
-    size_t numClients);
+    size_t numClients,
+    const CivetServer& civetServer,
+    std::mutex& outputMtx,
+    const std::string& outputFilename);
 
 bool make_reputation_proof(
     std::default_random_engine& rng,
@@ -39,7 +42,10 @@ bool make_reputation_proof(
     const std::vector<int>& serverPorts,
     const std::string& target,
     int targetPort,
-    size_t numClients);
+    size_t numClients,
+    const CivetServer& civetServer,
+    std::mutex& outputMtx,
+    const std::string& outputFilename);
 
 /* "PRIVATE" FUNCTIONS */
 
@@ -152,7 +158,9 @@ class PrsonaClientWebSocketHandler : public CivetWebSocketHandler {
             std::default_random_engine& rng,
             PrsonaClient *prsonaClient,
             const std::vector<std::string>& serverIPs,
-            const std::vector<int>& serverPorts);
+            const std::vector<int>& serverPorts,
+            std::mutex& outputMtx,
+            const std::string& outputFilename);
 
         // REQUIRED BY INHERITED CLASS
         virtual bool handleConnection(
@@ -176,17 +184,24 @@ class PrsonaClientWebSocketHandler : public CivetWebSocketHandler {
 
     private:
         std::default_random_engine &rng;
+        
         PrsonaClient *prsonaClient;
+
         const std::vector<std::string> serverIPs;
         const std::vector<int> serverPorts;
 
+        std::mutex& outputMtx;
+        const std::string outputFilename;
+
         // RESPONSE ROUTER FUNCTION
         void generate_response(
+            CivetServer *server,
             struct mg_connection *conn,
             const char *filename);
 
         // REPUTATION PROOF RESPONSE
         void verify_reputation_proof(
+            CivetServer *civetServer,
             struct mg_connection *conn,
             const char *filename);
 };

+ 48 - 7
prsona/inc/networkServer.hpp

@@ -42,7 +42,14 @@ void make_epoch(
     const std::string& selfIP,
     int selfPort,
     std::mutex& updateMtx,
-    std::atomic<size_t>& epochNum);
+    std::atomic<size_t>& epochNum,
+    const CivetServer& civetServer,
+    std::mutex& buildUpOutputMtx,
+    const std::string& buildUpOutputFilename,
+    std::mutex& breakDownOutputMtx,
+    const std::string& breakDownOutputFilename,
+    std::mutex& fullOutputMtx,
+    const std::string& fullOutputFilename);
 
 /* "PRIVATE" FUNCTIONS */
 
@@ -96,7 +103,10 @@ std::vector<Proof> epoch_build_up(
     const std::vector<int>& serverPorts,
     const std::string& selfIP,
     int selfPort,
-    Twistpoint& nextGenerator);
+    Twistpoint& nextGenerator,
+    const CivetServer& civetServer,
+    std::mutex& outputMtx,
+    const std::string& outputFilename);
 
 void epoch_break_down(
     std::default_random_engine& rng,
@@ -106,7 +116,10 @@ void epoch_break_down(
     const std::string& selfIP,
     int selfPort,
     const std::vector<Proof>& generatorProof,
-    const Twistpoint& nextGenerator);
+    const Twistpoint& nextGenerator,
+    const CivetServer& civetServer,
+    std::mutex& outputMtx,
+    const std::string& outputFilename);
 
 // HELPERS FOR EPOCH HELPERS
 Twistpoint initiate_epoch_updates(
@@ -161,7 +174,7 @@ std::string make_epoch_initiator_string(
     const std::vector<Proof>& generatorProof,
     const Twistpoint& nextGenerator);
 
-void read_epoch_initiator_string(
+ssize_t read_epoch_initiator_string(
     const char *filename,
     std::vector<Proof>& generatorProof,
     Twistpoint& nextGenerator);
@@ -180,7 +193,7 @@ std::string make_epoch_update_string(
     const Twistpoint& nextGenerator,
     bool doUserTallies);
 
-bool read_epoch_update_string(
+ssize_t read_epoch_update_string(
     const char *filename,
     std::vector<std::vector<Proof>>& pi,
     std::vector<std::vector<Twistpoint>>& permutationCommits,
@@ -192,7 +205,8 @@ bool read_epoch_update_string(
     std::vector<std::vector<Twistpoint>>& userTallyMaskCommits,
     std::vector<std::vector<Twistpoint>>& userTallyMessageCommits,
     std::vector<std::vector<Twistpoint>>& userTallySeedCommits,
-    Twistpoint& nextGenerator);
+    Twistpoint& nextGenerator,
+    bool& doUserTallies);
 
 /* OTHER SERVER-RELEVANT HANDLERS */
 
@@ -281,7 +295,15 @@ class PrsonaServerWebSocketHandler : public CivetWebSocketHandler  {
             const std::string& selfIP,
             int selfPort,
             std::mutex& updateMtx,
-            std::atomic<size_t>& epochNum);
+            std::atomic<size_t>& epochNum,
+            std::mutex& buildUpOutputMtx,
+            const std::string& buildUpOutputFilename,
+            std::mutex& breakDownOutputMtx,
+            const std::string& breakDownOutputFilename,
+            std::mutex& updateOutputMtx,
+            const std::string& updateOutputFilename,
+            std::mutex& voteOutputMtx,
+            const std::string& voteOutputFilename);
 
         // REQUIRED BY INHERITED CLASS
         bool handleConnection(
@@ -305,18 +327,33 @@ class PrsonaServerWebSocketHandler : public CivetWebSocketHandler  {
 
     private:
         std::default_random_engine& rng;
+        
         PrsonaServer *prsonaServer;
+        
         const std::vector<std::string> serverIPs;
         const std::vector<int> serverPorts;
+        
         const std::string selfIP;
         const int selfPort;
+        
         std::mutex& updateMtx;
+        
         std::atomic<size_t>& epochNum;
+        
+        std::mutex& buildUpOutputMtx;
+        const std::string buildUpOutputFilename;
+        std::mutex& breakDownOutputMtx;
+        const std::string breakDownOutputFilename;
+        std::mutex& updateOutputMtx;
+        const std::string updateOutputFilename;
+        std::mutex& voteOutputMtx;
+        const std::string voteOutputFilename;
 
         struct synchronization_tool updateSynch, distributeSynch;
 
         // RESPONSE ROUTER FUNCTION
         void generate_response(
+            CivetServer *server,
             struct mg_connection *conn,
             const char *filename);
 
@@ -393,6 +430,7 @@ class PrsonaServerWebSocketHandler : public CivetWebSocketHandler  {
         );
 
         void receive_vote(
+            CivetServer *civetServer,
             struct mg_connection *conn,
             const char *filename
         );
@@ -435,16 +473,19 @@ class PrsonaServerWebSocketHandler : public CivetWebSocketHandler  {
 
         // EPOCH ROUNDS
         void build_up_midway_pseudonyms(
+            CivetServer *civetServer,
             struct mg_connection *conn,
             const char *filename
         );
 
         void break_down_midway_pseudonyms(
+            CivetServer *civetServer,
             struct mg_connection *conn,
             const char *filename
         );
 
         void accept_epoch_updates(
+            CivetServer *civetServer,
             struct mg_connection *conn,
             const char *filename
         );

+ 19 - 1
prsona/inc/networking.hpp

@@ -1,6 +1,9 @@
 #ifndef __PRSONA_NETWORKING_HPP
 #define __PRSONA_NETWORKING_HPP
 
+#define USE_SERVER_STATS 1
+#define USE_SSL 0
+
 #include <mutex>
 #include <condition_variable>
 #include <random>
@@ -12,7 +15,6 @@
 
 #define MG_WEBSOCKET_OPCODE_DATACOMPLETE 0xb
 #define DEFAULT_PRSONA_PORT_STR "8080"
-#define USE_SSL 0
 
 #define TMP_FILE_SIZE 12
 #define TMP_DIR "./tmp/"
@@ -180,6 +182,17 @@ void load_single_instance_config(
     int& relevantPort,
     const char *filename);
 
+// Extracts relevant log data from server
+std::vector<size_t> get_log_data(
+    const struct mg_context *ctx);
+
+// Write log data to file
+void write_log_data(
+    std::mutex& outputMtx,
+    const std::string& outputFilename,
+    const std::vector<double>& timingData,
+    const std::vector<size_t>& bandwidthData);
+
 /* "PRIVATE" FUNCTIONS TO HELP THE GENERIC HELPERS */
 
 // Helper for set_temp_filename()
@@ -187,6 +200,11 @@ std::string random_string(
     std::default_random_engine& rng,
     size_t length);
 
+// Helper for get_log_data()
+size_t parse_log_for_data(
+    const char *input,
+    const char *key);
+
 /* WEBSOCKET HANDLER FUNCTIONS */
 
 // NULL

+ 13 - 3
prsona/src/clientMain.cpp

@@ -47,6 +47,16 @@ int main(int argc, char *argv[])
     if (argc > 2)
         output = argv[2];
 
+    string outputDir = "out/" + output + "/" + id;
+    int mkdirOut = system(("mkdir -p " + outputDir).c_str());
+
+    mutex voteOutputMtx;
+    string voteOutputFilename = outputDir + "/vote.out";
+    mutex repProofOutputMtx;
+    string repProofOutputFilename = outputDir + "/repProver.out";
+    mutex repVerifyOutputMtx;
+    string repVerifyOutputFilename = outputDir + "/repVerifier.out";
+
     // Default to malicious security if not specified
     bool maliciousServers = true;
     if (argc > 3)
@@ -116,7 +126,7 @@ int main(int argc, char *argv[])
     cout << "[" << seedStr << "] Setting up handlers for client." << endl;
 
     // Main handler (in clients, only used for verifying reputation proofs)
-    PrsonaClientWebSocketHandler wsHandler(rng, prsonaClient, serverIPs, serverPorts);
+    PrsonaClientWebSocketHandler wsHandler(rng, prsonaClient, serverIPs, serverPorts, repVerifyOutputMtx, repVerifyOutputFilename);
     server.addWebSocketHandler("/ws", wsHandler);
 
     // Exit handler (allows client to be brought down by making correct GET request)
@@ -159,7 +169,7 @@ int main(int argc, char *argv[])
             case CLIENT_MAKE_VOTE:
                 cout << "[" << seedStr << "] Making new vote row." << endl;
                 whichServer = distribution(rng);
-                make_vote(rng, prsonaClient, serverIPs, serverPorts, serverIPs[whichServer], serverPorts[whichServer], numClients);
+                make_vote(rng, prsonaClient, serverIPs, serverPorts, serverIPs[whichServer], serverPorts[whichServer], numClients, server, voteOutputMtx, voteOutputFilename);
                 cout << "[" << seedStr << "] New vote row complete." << endl;
                 break;
 
@@ -171,7 +181,7 @@ int main(int argc, char *argv[])
                 targetPort = stoi(fullQuery.substr(colonLocation + 1));
 
                 cout << "[" << seedStr << "] Making new reputation proof." << endl;
-                make_reputation_proof(rng, prsonaClient, serverIPs, serverPorts, target, targetPort, numClients);
+                make_reputation_proof(rng, prsonaClient, serverIPs, serverPorts, target, targetPort, numClients, server, repProofOutputMtx, repProofOutputFilename);
                 cout << "[" << seedStr << "] New reputation proof complete." << endl;
                 break;
 

+ 78 - 7
prsona/src/networkClient.cpp

@@ -58,7 +58,10 @@ void make_vote(
     const std::vector<int>& serverPorts,
     const std::string& target,
     int targetPort,
-    size_t numClients)
+    size_t numClients,
+    const CivetServer& civetServer,
+    std::mutex& outputMtx,
+    const std::string& outputFilename)
 {
     std::uniform_int_distribution<int> voteDistribution(0, PrsonaBase::get_max_allowed_vote());
     std::uniform_int_distribution<int> numVoteDistribution(0, numClients);
@@ -74,6 +77,10 @@ void make_vote(
     }
     shuffle(replaces.begin(), replaces.end(), rng);
 
+    std::vector<size_t> bandwidthDataBefore = get_log_data(civetServer.getContext());
+    std::chrono::high_resolution_clock::time_point wallTimeBefore = std::chrono::high_resolution_clock::now();
+    clock_t cpuTimeBefore = clock();
+
     // Get current fresh generator (it's not guaranteed we've done this in the current epoch)
     std::vector<Proof> generatorProof;
     Twistpoint freshGenerator = get_generator(rng, serverIPs, serverPorts, true, generatorProof);
@@ -97,6 +104,20 @@ void make_vote(
 
     // Send the new votes (and their proof) to the chosen server
     send_item(rng, target, targetPort, SUBMIT_VOTE_URI, data, false);
+
+    clock_t cpuTimeAfter = clock();
+    std::chrono::high_resolution_clock::time_point wallTimeAfter = std::chrono::high_resolution_clock::now();
+    std::vector<size_t> bandwidthDataAfter = get_log_data(civetServer.getContext());
+
+    std::vector<double> timingData(2);
+    timingData[0] = std::chrono::duration_cast<std::chrono::duration<double>>(wallTimeAfter - wallTimeBefore).count();
+    timingData[1] = ((double)(cpuTimeAfter - cpuTimeBefore)) / CLOCKS_PER_SEC;
+
+    std::vector<size_t> bandwidthData(2);
+    bandwidthData[0] = bandwidthDataAfter[0] - bandwidthDataBefore[0];
+    bandwidthData[1] = bandwidthDataAfter[1] - bandwidthDataBefore[1];
+
+    write_log_data(outputMtx, outputFilename, timingData, bandwidthData);
 }
 
 bool make_reputation_proof(
@@ -106,8 +127,15 @@ bool make_reputation_proof(
     const std::vector<int>& serverPorts,
     const std::string& target,
     int targetPort,
-    size_t numClients)
+    size_t numClients,
+    const CivetServer& civetServer,
+    std::mutex& outputMtx,
+    const std::string& outputFilename)
 {
+    std::vector<size_t> bandwidthDataBefore = get_log_data(civetServer.getContext());
+    std::chrono::high_resolution_clock::time_point wallTimeBefore = std::chrono::high_resolution_clock::now();
+    clock_t cpuTimeBefore = clock();
+
     // Get current fresh generator (it's not guaranteed we've done this in the current epoch)
     std::vector<Proof> generatorProof;
     Twistpoint freshGenerator = get_generator(rng, serverIPs, serverPorts, true, generatorProof);
@@ -142,6 +170,20 @@ bool make_reputation_proof(
     // Send that proof to a chosen client (and set up a file to receive whether or not the client accepted the proof)
     char *responseFile = send_item(rng, target, targetPort, VERIFY_REPUTATION_PROOF_URI, data, true);
 
+    clock_t cpuTimeAfter = clock();
+    std::chrono::high_resolution_clock::time_point wallTimeAfter = std::chrono::high_resolution_clock::now();
+    std::vector<size_t> bandwidthDataAfter = get_log_data(civetServer.getContext());
+
+    std::vector<double> timingData(2);
+    timingData[0] = std::chrono::duration_cast<std::chrono::duration<double>>(wallTimeAfter - wallTimeBefore).count();
+    timingData[1] = ((double)(cpuTimeAfter - cpuTimeBefore)) / CLOCKS_PER_SEC;
+
+    std::vector<size_t> bandwidthData(2);
+    bandwidthData[0] = bandwidthDataAfter[0] - bandwidthDataBefore[0];
+    bandwidthData[1] = bandwidthDataAfter[1] - bandwidthDataBefore[1];
+
+    write_log_data(outputMtx, outputFilename, timingData, bandwidthData);
+
     // The other client will give one byte back, containing whether or not it accepted the proof
     std::ifstream response(responseFile);
     char passed = response.get();
@@ -809,8 +851,10 @@ PrsonaClientWebSocketHandler::PrsonaClientWebSocketHandler(
     std::default_random_engine& rng,
     PrsonaClient *prsonaClient,
     const std::vector<std::string>& serverIPs,
-    const std::vector<int>& serverPorts)
-: rng(rng), prsonaClient(prsonaClient), serverIPs(serverIPs), serverPorts(serverPorts)
+    const std::vector<int>& serverPorts,
+    std::mutex& outputMtx,
+    const std::string& outputFilename)
+: rng(rng), prsonaClient(prsonaClient), serverIPs(serverIPs), serverPorts(serverPorts), outputMtx(outputMtx), outputFilename(outputFilename)
 { /* */ }
 
 /*
@@ -862,7 +906,7 @@ bool PrsonaClientWebSocketHandler::handleData(
         // Requester has indicated they have sent all relevant data
         case MG_WEBSOCKET_OPCODE_CONNECTION_CLOSE:
         case MG_WEBSOCKET_OPCODE_DATACOMPLETE:
-            generate_response(conn, filename);
+            generate_response(server, conn, filename);
             break;
 
         // Requester has sent more data (which may theoretically be broken up into multiple packets)
@@ -902,6 +946,7 @@ void PrsonaClientWebSocketHandler::handleClose(
  */
 
 void PrsonaClientWebSocketHandler::generate_response(
+    CivetServer *server,
     struct mg_connection *conn,
     const char *filename)
 {
@@ -911,7 +956,7 @@ void PrsonaClientWebSocketHandler::generate_response(
     switch (info->query_string[0])
     {
         case PRSONA_VERIFY_REPUTATION_PROOF:
-            verify_reputation_proof(conn, filename);
+            verify_reputation_proof(server, conn, filename);
             break;
 
         default:
@@ -924,7 +969,9 @@ void PrsonaClientWebSocketHandler::generate_response(
  */
 
 void PrsonaClientWebSocketHandler::verify_reputation_proof(
-    struct mg_connection *conn, const char *filename)
+    CivetServer *civetServer,
+    struct mg_connection *conn,
+    const char *filename)
 {
     std::vector<Proof> pi;
     Twistpoint shortTermPublicKey;
@@ -932,6 +979,12 @@ void PrsonaClientWebSocketHandler::verify_reputation_proof(
 
     // Un-serialize the reputation proof
     std::ifstream file(filename);
+
+    file.ignore(std::numeric_limits<std::streamsize>::max());
+    std::streamsize bandwidthRcv = file.gcount();
+    file.clear();
+    file.seekg(0, std::ios_base::beg);
+
     BinarySizeT sizeOfVector;
     file >> sizeOfVector;
     for (size_t i = 0; i < sizeOfVector.val(); i++)
@@ -944,6 +997,10 @@ void PrsonaClientWebSocketHandler::verify_reputation_proof(
     file >> shortTermPublicKey;
     file >> threshold;
 
+    std::vector<size_t> bandwidthDataBefore = get_log_data(civetServer->getContext());
+    std::chrono::high_resolution_clock::time_point wallTimeBefore = std::chrono::high_resolution_clock::now();
+    clock_t cpuTimeBefore = clock();
+
     // Get current fresh generator (it's not guaranteed we've done this in the current epoch)
     std::vector<Proof> generatorProof;
     Twistpoint freshGenerator = get_generator(rng, serverIPs, serverPorts, true, generatorProof);
@@ -958,6 +1015,20 @@ void PrsonaClientWebSocketHandler::verify_reputation_proof(
     // Check if the proof verifies correctly
     bool flag = prsonaClient->verify_reputation_proof(pi, shortTermPublicKey, threshold, encryptedScoreProof, encryptedScore);
 
+    clock_t cpuTimeAfter = clock();
+    std::chrono::high_resolution_clock::time_point wallTimeAfter = std::chrono::high_resolution_clock::now();
+    std::vector<size_t> bandwidthDataAfter = get_log_data(civetServer->getContext());
+
+    std::vector<double> timingData(2);
+    timingData[0] = std::chrono::duration_cast<std::chrono::duration<double>>(wallTimeAfter - wallTimeBefore).count();
+    timingData[1] = ((double)(cpuTimeAfter - cpuTimeBefore)) / CLOCKS_PER_SEC;
+
+    std::vector<size_t> bandwidthData(2);
+    bandwidthData[0] = bandwidthDataAfter[0] - bandwidthDataBefore[0] + bandwidthRcv;
+    bandwidthData[1] = bandwidthDataAfter[1] - bandwidthDataBefore[1] + 1;
+
+    write_log_data(outputMtx, outputFilename, timingData, bandwidthData);
+
     // Tell the prover whether or not we accept the proof
     std::string data = flag ? "\x01" : "\x00";
     mg_websocket_write(conn, MG_WEBSOCKET_OPCODE_BINARY, data.c_str(), 1);

+ 199 - 22
prsona/src/networkServer.cpp

@@ -1,6 +1,8 @@
 #include <iostream>
 #include <fstream>
 #include <sstream>
+#include <ctime>
+#include <chrono>
 
 #include "networkServer.hpp"
 
@@ -94,17 +96,29 @@ void make_epoch(
     const std::string& selfIP,
     int selfPort,
     std::mutex& updateMtx,
-    std::atomic<size_t>& epochNum)
+    std::atomic<size_t>& epochNum,
+    const CivetServer& civetServer,
+    std::mutex& buildUpOutputMtx,
+    const std::string& buildUpOutputFilename,
+    std::mutex& breakDownOutputMtx,
+    const std::string& breakDownOutputFilename,
+    std::mutex& fullOutputMtx,
+    const std::string& fullOutputFilename)
 {
     // As before, the fresh generator always starts from the same G
     Twistpoint nextGenerator = PrsonaServer::EL_GAMAL_GENERATOR;
 
-    // Take update locks on every machine
     std::unique_lock<std::mutex> updateLock(updateMtx, std::defer_lock);
+
+    std::vector<size_t> bandwidthDataBefore = get_log_data(civetServer.getContext());
+    std::chrono::high_resolution_clock::time_point wallTimeBefore = std::chrono::high_resolution_clock::now();
+    clock_t cpuTimeBefore = clock();
+
+    // Take update locks on every machine
     obtain_update_locks(updateLock, serverIPs, serverPorts, selfIP, selfPort);
 
     // Do the first half of the epoch calculations (building up the intermediary values)
-    std::vector<Proof> generatorProof = epoch_build_up(rng, prsonaServer, serverIPs, serverPorts, selfIP, selfPort, nextGenerator);
+    std::vector<Proof> generatorProof = epoch_build_up(rng, prsonaServer, serverIPs, serverPorts, selfIP, selfPort, nextGenerator, civetServer, buildUpOutputMtx, buildUpOutputFilename);
 
     // Tally up the current scores at the end of the epoch for the users
     std::vector<EGCiphertext> currentUserEncryptedTallies;
@@ -115,13 +129,27 @@ void make_epoch(
     distribute_tallied_scores(prsonaServer, serverIPs, serverPorts, selfIP, selfPort, nextGenerator, currentUserEncryptedTallies, currentServerEncryptedTallies);
 
     // Do the second half of the epoch calculations (breaking down values to their final values, to be given to users)
-    epoch_break_down(rng, prsonaServer, serverIPs, serverPorts, selfIP, selfPort, generatorProof, nextGenerator);
+    epoch_break_down(rng, prsonaServer, serverIPs, serverPorts, selfIP, selfPort, generatorProof, nextGenerator, civetServer, breakDownOutputMtx, breakDownOutputFilename);
 
     // Indicate we are in a new epoch
     epochNum.fetch_add(1);
 
     // Release the update locks from every machine
     release_update_locks(updateLock, serverIPs, serverPorts, selfIP, selfPort);
+    
+    clock_t cpuTimeAfter = clock();
+    std::chrono::high_resolution_clock::time_point wallTimeAfter = std::chrono::high_resolution_clock::now();
+    std::vector<size_t> bandwidthDataAfter = get_log_data(civetServer.getContext());
+
+    std::vector<double> timingData(2);
+    timingData[0] = std::chrono::duration_cast<std::chrono::duration<double>>(wallTimeAfter - wallTimeBefore).count();
+    timingData[1] = ((double)(cpuTimeAfter - cpuTimeBefore)) / CLOCKS_PER_SEC;
+
+    std::vector<size_t> bandwidthData(2);
+    bandwidthData[0] = bandwidthDataAfter[0] - bandwidthDataBefore[0];
+    bandwidthData[1] = bandwidthDataAfter[1] - bandwidthDataBefore[1];
+
+    write_log_data(fullOutputMtx, fullOutputFilename, timingData, bandwidthData);
 }
 
 /*********************************************************
@@ -430,7 +458,10 @@ std::vector<Proof> epoch_build_up(
     const std::vector<int>& serverPorts,
     const std::string& selfIP,
     int selfPort,
-    Twistpoint& nextGenerator)
+    Twistpoint& nextGenerator,
+    const CivetServer& civetServer,
+    std::mutex& outputMtx,
+    const std::string& outputFilename)
 {
     std::vector<std::vector<std::vector<Proof>>> pi;
     std::vector<std::vector<std::vector<Twistpoint>>> permutationCommits;
@@ -456,6 +487,10 @@ std::vector<Proof> epoch_build_up(
             serverTallyCommits.clear();
             partwayVoteMatrixCommits.clear();
             finalVoteMatrixCommits.clear();
+
+            std::vector<size_t> bandwidthDataBefore = get_log_data(civetServer.getContext());
+            std::chrono::high_resolution_clock::time_point wallTimeBefore = std::chrono::high_resolution_clock::now();
+            clock_t cpuTimeBefore = clock();
             
             // Perform the actual calculation
             prsonaServer->build_up_midway_pseudonyms(pi, permutationCommits, freshPseudonymCommits, freshPseudonymSeedCommits, serverTallyCommits, partwayVoteMatrixCommits, finalVoteMatrixCommits, nextGenerator);
@@ -493,6 +528,20 @@ std::vector<Proof> epoch_build_up(
             for (size_t j = 0; j < conns.size(); j++)
                 mg_close_connection(conns[j]);
 
+            clock_t cpuTimeAfter = clock();
+            std::chrono::high_resolution_clock::time_point wallTimeAfter = std::chrono::high_resolution_clock::now();
+            std::vector<size_t> bandwidthDataAfter = get_log_data(civetServer.getContext());
+
+            std::vector<double> timingData(2);
+            timingData[0] = std::chrono::duration_cast<std::chrono::duration<double>>(wallTimeAfter - wallTimeBefore).count();
+            timingData[1] = ((double)(cpuTimeAfter - cpuTimeBefore)) / CLOCKS_PER_SEC;
+
+            std::vector<size_t> bandwidthData(2);
+            bandwidthData[0] = bandwidthDataAfter[0] - bandwidthDataBefore[0];
+            bandwidthData[1] = bandwidthDataAfter[1] - bandwidthDataBefore[1];
+
+            write_log_data(outputMtx, outputFilename, timingData, bandwidthData);
+
             // Keep an up-to-date version of the proof of the new fresh generator
             generatorProofHolder = pi[0];
         }
@@ -518,7 +567,10 @@ void epoch_break_down(
     const std::string& selfIP,
     int selfPort,
     const std::vector<Proof>& generatorProof,
-    const Twistpoint& nextGenerator)
+    const Twistpoint& nextGenerator,
+    const CivetServer& civetServer,
+    std::mutex& outputMtx,
+    const std::string& outputFilename)
 {
     std::vector<std::vector<std::vector<Proof>>> pi;
     std::vector<std::vector<std::vector<Twistpoint>>> permutationCommits;
@@ -548,6 +600,10 @@ void epoch_break_down(
             userTallyMessageCommits.clear();
             userTallySeedCommits.clear();
 
+            std::vector<size_t> bandwidthDataBefore = get_log_data(civetServer.getContext());
+            std::chrono::high_resolution_clock::time_point wallTimeBefore = std::chrono::high_resolution_clock::now();
+            clock_t cpuTimeBefore = clock();
+
             // Perform the actual calculation
             prsonaServer->break_down_midway_pseudonyms(generatorProof, pi, permutationCommits, freshPseudonymCommits, freshPseudonymSeedCommits, serverTallyCommits, partwayVoteMatrixCommits, finalVoteMatrixCommits, userTallyMaskCommits, userTallyMessageCommits, userTallySeedCommits, nextGenerator);
 
@@ -579,6 +635,18 @@ void epoch_break_down(
 
             for (size_t j = 0; j < conns.size(); j++)
                 mg_close_connection(conns[j]);
+
+            clock_t cpuTimeAfter = clock();
+            std::chrono::high_resolution_clock::time_point wallTimeAfter = std::chrono::high_resolution_clock::now();
+            std::vector<size_t> bandwidthDataAfter = get_log_data(civetServer.getContext());
+
+            std::vector<double> timingData(2);
+            timingData[0] = std::chrono::duration_cast<std::chrono::duration<double>>(wallTimeAfter - wallTimeBefore).count();
+            timingData[1] = ((double)(cpuTimeAfter - cpuTimeBefore)) / CLOCKS_PER_SEC;
+
+            std::vector<size_t> bandwidthData(2);
+            bandwidthData[0] = bandwidthDataAfter[0] - bandwidthDataBefore[0];
+            bandwidthData[1] = bandwidthDataAfter[1] - bandwidthDataBefore[1];
         }
         else    // When it's another server's turn, tell them to do their part
         {
@@ -900,12 +968,18 @@ std::string make_epoch_initiator_string(
     return buffer.str();
 }
 
-void read_epoch_initiator_string(
+ssize_t read_epoch_initiator_string(
     const char *filename,
     std::vector<Proof>& generatorProof,
     Twistpoint& nextGenerator)
 {
     std::ifstream file(filename);
+
+    file.ignore(std::numeric_limits<std::streamsize>::max());
+    std::streamsize retval = file.gcount();
+    file.clear();
+    file.seekg(0, std::ios_base::beg);
+
     BinarySizeT sizeOfVector;
 
     generatorProof.clear();
@@ -920,6 +994,8 @@ void read_epoch_initiator_string(
     }
     
     file >> nextGenerator;
+
+    return retval;
 }
 
 std::string make_epoch_update_string(
@@ -1015,7 +1091,7 @@ std::string make_epoch_update_string(
     return buffer.str();
 }
 
-bool read_epoch_update_string(
+ssize_t read_epoch_update_string(
     const char *filename,
     std::vector<std::vector<Proof>>& pi,
     std::vector<std::vector<Twistpoint>>& permutationCommits,
@@ -1027,9 +1103,16 @@ bool read_epoch_update_string(
     std::vector<std::vector<Twistpoint>>& userTallyMaskCommits,
     std::vector<std::vector<Twistpoint>>& userTallyMessageCommits,
     std::vector<std::vector<Twistpoint>>& userTallySeedCommits,
-    Twistpoint& nextGenerator)
+    Twistpoint& nextGenerator,
+    bool& doUserTallies)
 {
     std::ifstream file(filename);
+
+    file.ignore(std::numeric_limits<std::streamsize>::max());
+    std::streamsize retval = file.gcount();
+    file.clear();
+    file.seekg(0, std::ios_base::beg);
+
     BinarySizeT sizeOfVectorI, sizeOfVectorJ;
     
     pi.clear();
@@ -1198,10 +1281,12 @@ bool read_epoch_update_string(
 
     file >> nextGenerator;
     
-    BinaryBool doUserTallies;
-    file >> doUserTallies;
+    BinaryBool binaryDoUserTallies;
+    file >> binaryDoUserTallies;
+
+    doUserTallies = binaryDoUserTallies.val();
 
-    return doUserTallies.val();
+    return retval;
 }
 
 /**********************************************************
@@ -1379,8 +1464,16 @@ PrsonaServerWebSocketHandler::PrsonaServerWebSocketHandler(
     const std::string& selfIP,
     int selfPort,
     std::mutex& updateMtx,
-    std::atomic<size_t>& epochNum)
-: rng(rng), prsonaServer(prsonaServer), serverIPs(serverIPs), serverPorts(serverPorts), selfIP(selfIP), selfPort(selfPort), updateMtx(updateMtx), epochNum(epochNum)
+    std::atomic<size_t>& epochNum,
+    std::mutex& buildUpOutputMtx,
+    const std::string& buildUpOutputFilename,
+    std::mutex& breakDownOutputMtx,
+    const std::string& breakDownOutputFilename,
+    std::mutex& updateOutputMtx,
+    const std::string& updateOutputFilename,
+    std::mutex& voteOutputMtx,
+    const std::string& voteOutputFilename)
+: rng(rng), prsonaServer(prsonaServer), serverIPs(serverIPs), serverPorts(serverPorts), selfIP(selfIP), selfPort(selfPort), updateMtx(updateMtx), epochNum(epochNum), buildUpOutputMtx(buildUpOutputMtx), buildUpOutputFilename(buildUpOutputFilename), breakDownOutputMtx(breakDownOutputMtx), breakDownOutputFilename(breakDownOutputFilename), updateOutputMtx(updateOutputMtx), updateOutputFilename(updateOutputFilename), voteOutputMtx(voteOutputMtx), voteOutputFilename(voteOutputFilename)
 { /* */ }
 
 /*
@@ -1461,7 +1554,7 @@ bool PrsonaServerWebSocketHandler::handleData(
         // Requester has indicated they have sent all relevant data
         case MG_WEBSOCKET_OPCODE_CONNECTION_CLOSE:
         case MG_WEBSOCKET_OPCODE_DATACOMPLETE:
-            generate_response(conn, filename);
+            generate_response(server, conn, filename);
             break;
 
         // Requester has sent more data (which may theoretically be broken up into multiple packets)
@@ -1501,6 +1594,7 @@ void PrsonaServerWebSocketHandler::handleClose(
  */
 
 void PrsonaServerWebSocketHandler::generate_response(
+    CivetServer *server,
     struct mg_connection *conn,
     const char *filename)
 {
@@ -1578,7 +1672,7 @@ void PrsonaServerWebSocketHandler::generate_response(
             break;
 
         case PRSONA_RECEIVE_VOTE:
-            receive_vote(conn, filename);
+            receive_vote(server, conn, filename);
             break;
 
         // CLIENT INTERACTION HELPER
@@ -1609,15 +1703,15 @@ void PrsonaServerWebSocketHandler::generate_response(
 
         // EPOCH ROUNDS
         case PRSONA_PERFORM_EPOCH_BUILD_UP:
-            build_up_midway_pseudonyms(conn, filename);
+            build_up_midway_pseudonyms(server, conn, filename);
             break;
 
         case PRSONA_PERFORM_EPOCH_BREAK_DOWN:
-            break_down_midway_pseudonyms(conn, filename);
+            break_down_midway_pseudonyms(server, conn, filename);
             break;
 
         case PRSONA_RECEIVE_EPOCH_UPDATE:
-            accept_epoch_updates(conn, filename);
+            accept_epoch_updates(server, conn, filename);
             break;
 
         // DISTRIBUTED BGN
@@ -1992,11 +2086,17 @@ void PrsonaServerWebSocketHandler::add_new_client(
 }
 
 void PrsonaServerWebSocketHandler::receive_vote(
+    CivetServer *civetServer,
     struct mg_connection *conn,
     const char *filename)
 {
     std::ifstream file(filename);
 
+    file.ignore(std::numeric_limits<std::streamsize>::max());
+    std::streamsize bandwidthRcv = file.gcount();
+    file.clear();
+    file.seekg(0, std::ios_base::beg);
+
     // Un-serialize request
     BinarySizeT sizeOfVector;
     file >> sizeOfVector;
@@ -2029,6 +2129,11 @@ void PrsonaServerWebSocketHandler::receive_vote(
 
     // If we're dealing this update to the other servers, obtain global update lock
     std::unique_lock<std::mutex> updateLock(updateMtx, std::defer_lock);
+
+    std::vector<size_t> bandwidthDataBefore = get_log_data(civetServer->getContext());
+    std::chrono::high_resolution_clock::time_point wallTimeBefore = std::chrono::high_resolution_clock::now();
+    clock_t cpuTimeBefore = clock();
+
     if (shouldDeal.val())
         obtain_update_locks(updateLock, serverIPs, serverPorts, selfIP, selfPort);
 
@@ -2044,6 +2149,20 @@ void PrsonaServerWebSocketHandler::receive_vote(
         release_update_locks(updateLock, serverIPs, serverPorts, selfIP, selfPort);
     }
 
+    clock_t cpuTimeAfter = clock();
+    std::chrono::high_resolution_clock::time_point wallTimeAfter = std::chrono::high_resolution_clock::now();
+    std::vector<size_t> bandwidthDataAfter = get_log_data(civetServer->getContext());
+
+    std::vector<double> timingData(2);
+    timingData[0] = std::chrono::duration_cast<std::chrono::duration<double>>(wallTimeAfter - wallTimeBefore).count();
+    timingData[1] = ((double)(cpuTimeAfter - cpuTimeBefore)) / CLOCKS_PER_SEC;
+
+    std::vector<size_t> bandwidthData(2);
+    bandwidthData[0] = bandwidthDataAfter[0] - bandwidthDataBefore[0] + bandwidthRcv;
+    bandwidthData[1] = bandwidthDataAfter[1] - bandwidthDataBefore[1];
+
+    write_log_data(voteOutputMtx, voteOutputFilename, timingData, bandwidthData);
+
     // Notify client their request has been completed
     mg_websocket_write(conn, MG_WEBSOCKET_OPCODE_DATACOMPLETE, "", 0);
 }
@@ -2356,6 +2475,7 @@ void PrsonaServerWebSocketHandler::set_generator(
  */
 
 void PrsonaServerWebSocketHandler::build_up_midway_pseudonyms(
+    CivetServer *civetServer,
     struct mg_connection *conn,
     const char *filename)
 {
@@ -2364,7 +2484,7 @@ void PrsonaServerWebSocketHandler::build_up_midway_pseudonyms(
     Twistpoint nextGenerator;
 
     // Un-serialize request
-    read_epoch_initiator_string(filename, generatorProof, nextGenerator);
+    ssize_t bandwidthRcv = read_epoch_initiator_string(filename, generatorProof, nextGenerator);
     generatorProofHolder.push_back(generatorProof);
 
     std::vector<std::vector<std::vector<Proof>>> pi;
@@ -2376,6 +2496,10 @@ void PrsonaServerWebSocketHandler::build_up_midway_pseudonyms(
     std::vector<std::vector<std::vector<std::vector<TwistBipoint>>>> partwayVoteMatrixCommits;
     std::vector<std::vector<std::vector<std::vector<TwistBipoint>>>> finalVoteMatrixCommits;
 
+    std::vector<size_t> bandwidthDataBefore = get_log_data(civetServer->getContext());
+    std::chrono::high_resolution_clock::time_point wallTimeBefore = std::chrono::high_resolution_clock::now();
+    clock_t cpuTimeBefore = clock();
+
     // Do actual epoch calculation
     prsonaServer->build_up_midway_pseudonyms(pi, permutationCommits, freshPseudonymCommits, freshPseudonymSeedCommits, serverTallyCommits, partwayVoteMatrixCommits, finalVoteMatrixCommits, nextGenerator);
 
@@ -2408,6 +2532,20 @@ void PrsonaServerWebSocketHandler::build_up_midway_pseudonyms(
     // Close connections
     for (size_t i = 0; i < conns.size(); i++)
         mg_close_connection(conns[i]);
+
+    clock_t cpuTimeAfter = clock();
+    std::chrono::high_resolution_clock::time_point wallTimeAfter = std::chrono::high_resolution_clock::now();
+    std::vector<size_t> bandwidthDataAfter = get_log_data(civetServer->getContext());
+
+    std::vector<double> timingData(2);
+    timingData[0] = std::chrono::duration_cast<std::chrono::duration<double>>(wallTimeAfter - wallTimeBefore).count();
+    timingData[1] = ((double)(cpuTimeAfter - cpuTimeBefore)) / CLOCKS_PER_SEC;
+
+    std::vector<size_t> bandwidthData(2);
+    bandwidthData[0] = bandwidthDataAfter[0] - bandwidthDataBefore[0] + bandwidthRcv;
+    bandwidthData[1] = bandwidthDataAfter[1] - bandwidthDataBefore[1];
+
+    write_log_data(buildUpOutputMtx, buildUpOutputFilename, timingData, bandwidthData);
     
     // Serialize response
     data = make_epoch_initiator_string(pi[0][0], nextGenerator);
@@ -2418,6 +2556,7 @@ void PrsonaServerWebSocketHandler::build_up_midway_pseudonyms(
 }
 
 void PrsonaServerWebSocketHandler::break_down_midway_pseudonyms(
+    CivetServer *civetServer,
     struct mg_connection *conn,
     const char *filename)
 {
@@ -2425,7 +2564,7 @@ void PrsonaServerWebSocketHandler::break_down_midway_pseudonyms(
     Twistpoint nextGenerator;
 
     // Un-serialize request
-    read_epoch_initiator_string(filename, generatorProof, nextGenerator);
+    ssize_t bandwidthRcv = read_epoch_initiator_string(filename, generatorProof, nextGenerator);
     
     std::vector<std::vector<std::vector<Proof>>> pi;
     std::vector<std::vector<std::vector<Twistpoint>>> permutationCommits;
@@ -2438,6 +2577,10 @@ void PrsonaServerWebSocketHandler::break_down_midway_pseudonyms(
     std::vector<std::vector<std::vector<Twistpoint>>> userTallyMessageCommits;
     std::vector<std::vector<std::vector<Twistpoint>>> userTallySeedCommits;
 
+    std::vector<size_t> bandwidthDataBefore = get_log_data(civetServer->getContext());
+    std::chrono::high_resolution_clock::time_point wallTimeBefore = std::chrono::high_resolution_clock::now();
+    clock_t cpuTimeBefore = clock();
+
     // Do actual epoch calculation
     prsonaServer->break_down_midway_pseudonyms(generatorProof, pi, permutationCommits, freshPseudonymCommits, freshPseudonymSeedCommits, serverTallyCommits, partwayVoteMatrixCommits, finalVoteMatrixCommits, userTallyMaskCommits, userTallyMessageCommits, userTallySeedCommits, nextGenerator);
 
@@ -2469,6 +2612,20 @@ void PrsonaServerWebSocketHandler::break_down_midway_pseudonyms(
     for (size_t i = 0; i < conns.size(); i++)
         mg_close_connection(conns[i]);
 
+    clock_t cpuTimeAfter = clock();
+    std::chrono::high_resolution_clock::time_point wallTimeAfter = std::chrono::high_resolution_clock::now();
+    std::vector<size_t> bandwidthDataAfter = get_log_data(civetServer->getContext());
+
+    std::vector<double> timingData(2);
+    timingData[0] = std::chrono::duration_cast<std::chrono::duration<double>>(wallTimeAfter - wallTimeBefore).count();
+    timingData[1] = ((double)(cpuTimeAfter - cpuTimeBefore)) / CLOCKS_PER_SEC;
+
+    std::vector<size_t> bandwidthData(2);
+    bandwidthData[0] = bandwidthDataAfter[0] - bandwidthDataBefore[0] + bandwidthRcv;
+    bandwidthData[1] = bandwidthDataAfter[1] - bandwidthDataBefore[1];
+
+    write_log_data(breakDownOutputMtx, breakDownOutputFilename, timingData, bandwidthData);
+
     // Keep our epoch value up-to-date
     epochNum.fetch_add(1);
 
@@ -2477,6 +2634,7 @@ void PrsonaServerWebSocketHandler::break_down_midway_pseudonyms(
 }
 
 void PrsonaServerWebSocketHandler::accept_epoch_updates(
+    CivetServer *civetServer,
     struct mg_connection *conn,
     const char *filename)
 {
@@ -2491,13 +2649,32 @@ void PrsonaServerWebSocketHandler::accept_epoch_updates(
     std::vector<std::vector<Twistpoint>> userTallyMessageCommits;
     std::vector<std::vector<Twistpoint>> userTallySeedCommits;
     Twistpoint nextGenerator;
+    bool doUserTallies;
 
     // Un-serialize request
-    bool doUserTallies = read_epoch_update_string(filename, pi, permutationCommits, freshPseudonymCommits, freshPseudonymSeedCommits, serverTallyCommits, partwayVoteMatrixCommits, finalVoteMatrixCommits, userTallyMaskCommits, userTallyMessageCommits, userTallySeedCommits, nextGenerator);
+    ssize_t bandwidthRcv = read_epoch_update_string(filename, pi, permutationCommits, freshPseudonymCommits, freshPseudonymSeedCommits, serverTallyCommits, partwayVoteMatrixCommits, finalVoteMatrixCommits, userTallyMaskCommits, userTallyMessageCommits, userTallySeedCommits, nextGenerator, doUserTallies);
+
+    std::vector<size_t> bandwidthDataBefore = get_log_data(civetServer->getContext());
+    std::chrono::high_resolution_clock::time_point wallTimeBefore = std::chrono::high_resolution_clock::now();
+    clock_t cpuTimeBefore = clock();
 
     // Load data into server object
     prsonaServer->accept_epoch_updates(pi, permutationCommits, freshPseudonymCommits, freshPseudonymSeedCommits, serverTallyCommits, partwayVoteMatrixCommits, finalVoteMatrixCommits, userTallyMaskCommits, userTallyMessageCommits, userTallySeedCommits, nextGenerator, doUserTallies);
 
+    clock_t cpuTimeAfter = clock();
+    std::chrono::high_resolution_clock::time_point wallTimeAfter = std::chrono::high_resolution_clock::now();
+    std::vector<size_t> bandwidthDataAfter = get_log_data(civetServer->getContext());
+
+    std::vector<double> timingData(2);
+    timingData[0] = std::chrono::duration_cast<std::chrono::duration<double>>(wallTimeAfter - wallTimeBefore).count();
+    timingData[1] = ((double)(cpuTimeAfter - cpuTimeBefore)) / CLOCKS_PER_SEC;
+
+    std::vector<size_t> bandwidthData(2);
+    bandwidthData[0] = bandwidthDataAfter[0] - bandwidthDataBefore[0] + bandwidthRcv;
+    bandwidthData[1] = bandwidthDataAfter[1] - bandwidthDataBefore[1];
+
+    write_log_data(breakDownOutputMtx, breakDownOutputFilename, timingData, bandwidthData);
+
     // Acknowledge receipt of request
     mg_websocket_write(conn, MG_WEBSOCKET_OPCODE_DATACOMPLETE, "", 0);
 }

+ 44 - 0
prsona/src/networking.cpp

@@ -108,6 +108,33 @@ void load_single_instance_config(
     }
 }
 
+std::vector<size_t> get_log_data(
+    const struct mg_context *ctx)
+{
+    std::vector<size_t> retval;
+    char buffer[4096];
+
+    mg_get_context_info(ctx, buffer, 4096);
+
+    retval.push_back(parse_log_for_data(buffer, "read"));
+    retval.push_back(parse_log_for_data(buffer, "written"));
+
+    return retval;
+}
+
+void write_log_data(
+    std::mutex& outputMtx,
+    const std::string& outputFilename,
+    const std::vector<double>& timingData,
+    const std::vector<size_t>& bandwidthData)
+{
+    std::unique_lock<std::mutex> lck(outputMtx);
+
+    FILE *outputFile = fopen(outputFilename.c_str(), "a");
+    fprintf(outputFile, "%f,%f,%zu,%zu\n", timingData[0], timingData[1], bandwidthData[0], bandwidthData[1]);
+    fclose(outputFile);
+}
+
 /***********************************************************
  ****                                                   ****
  ****  "private" functions to help the generic helpers  ****
@@ -138,6 +165,23 @@ std::string random_string(
     return retval;
 }
 
+size_t parse_log_for_data(const char *input, const char *key)
+{
+    size_t length = strlen(input);
+    char *copy = new char[length + 1];
+    strncpy(copy, input, length);
+    copy[length] = 0;
+
+    char *pos = strstr(copy, key) + strlen(key);
+    pos = strtok(pos, "{}:,\" \n");
+
+    size_t retval = strtoul(pos, NULL, 10);
+
+    delete [] copy;
+
+    return retval;
+}
+
 /***************************************
  ****                               ****
  ****  websocket handler functions  ****

+ 16 - 2
prsona/src/serverMain.cpp

@@ -47,6 +47,20 @@ int main(int argc, char *argv[])
     if (argc > 2)
         output = argv[2];
 
+    string outputDir = "out/" + output + "/" + id;
+    int mkdirOut = system(("mkdir -p " + outputDir).c_str());
+
+    mutex epochBuildUpOutputMtx;
+    string epochBuildUpOutputFilename = outputDir + "/epochUp.out";
+    mutex epochBreakDownOutputMtx;
+    string epochBreakDownOutputFilename = outputDir + "/epochDown.out";
+    mutex epochUpdateOutputMtx;
+    string epochUpdateOutputFilename = outputDir + "/epochUpdate.out";
+    mutex voteUpdateOutputMtx;
+    string voteUpdateOutputFilename = outputDir + "/voteUpdate.out";
+    mutex fullEpochOutputMtx;
+    string fullEpochOutputFilename = outputDir + "/overallEpoch.out";
+
     // Default to malicious security if not specified
     bool maliciousServers = true;
     if (argc > 3)
@@ -120,7 +134,7 @@ int main(int argc, char *argv[])
     cout << "[" << seedStr << "] Setting up handlers for server." << endl;
 
     // Main handler
-    PrsonaServerWebSocketHandler wsHandler(rng, prsonaServer, serverIPs, serverPorts, selfIP, selfPort, updateMtx, epochNum);
+    PrsonaServerWebSocketHandler wsHandler(rng, prsonaServer, serverIPs, serverPorts, selfIP, selfPort, updateMtx, epochNum, epochBuildUpOutputMtx, epochBuildUpOutputFilename, epochBreakDownOutputMtx, epochBreakDownOutputFilename, epochUpdateOutputMtx, epochUpdateOutputFilename, voteUpdateOutputMtx, voteUpdateOutputFilename);
     server.addWebSocketHandler("/ws", wsHandler);
 
     // Exit handler (allows server to be brought down by making correct GET request)
@@ -195,7 +209,7 @@ int main(int argc, char *argv[])
             {
                 size_t currEpoch = epochNum.load();
                 cout << "[" << seedStr << "] Executing epoch calculations (going from t = " << currEpoch << " to " << currEpoch + 1 << ")." << endl;
-                make_epoch(rng, prsonaServer, serverIPs, serverPorts, selfIP, selfPort, updateMtx, epochNum);
+                make_epoch(rng, prsonaServer, serverIPs, serverPorts, selfIP, selfPort, updateMtx, epochNum, server, epochBuildUpOutputMtx, epochBuildUpOutputFilename, epochBreakDownOutputMtx, epochBreakDownOutputFilename, fullEpochOutputMtx, fullEpochOutputFilename);
                 currEpoch = epochNum.load();
                 cout << "[" << seedStr << "] Epoch calculations complete (now in t = " << currEpoch << ")." << endl;
             }