Skip to content

Commit

Permalink
Report networking statistics along with GameReporter
Browse files Browse the repository at this point in the history
 - jitter max, mean, variance
  • Loading branch information
altf4 committed Mar 28, 2021
1 parent 4b354cf commit 710208a
Show file tree
Hide file tree
Showing 5 changed files with 66 additions and 5 deletions.
11 changes: 7 additions & 4 deletions Source/Core/Core/HW/EXI_DeviceSlippi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2206,8 +2206,8 @@ void CEXISlippi::prepareNewSeed()

void CEXISlippi::handleReportGame(u8 *payload)
{
SlippiGameReporter::GameReport r;
r.durationFrames = Common::swap32(&payload[0]);
SlippiGameReporter::GameReport report;
report.durationFrames = Common::swap32(&payload[0]);

//ERROR_LOG(SLIPPI_ONLINE, "Frames: %d", r.durationFrames);

Expand All @@ -2222,10 +2222,13 @@ void CEXISlippi::handleReportGame(u8 *payload)

//ERROR_LOG(SLIPPI_ONLINE, "Stocks: %d, DamageDone: %f", p.stocksRemaining, p.damageDone);

r.players.push_back(p);
report.players.push_back(p);
}

gameReporter->StartReport(r);
// Add network quality information to game report
slippi_netplay->GetNetworkingStats(&report);

gameReporter->StartReport(report);
}

void CEXISlippi::DMAWrite(u32 _uAddr, u32 _uSize)
Expand Down
5 changes: 4 additions & 1 deletion Source/Core/Core/Slippi/SlippiGameReporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,9 @@ void SlippiGameReporter::ReportThreadHandler()
request["playKey"] = userInfo.playKey;
request["gameIndex"] = gameIndex;
request["gameDurationFrames"] = report.durationFrames;
request["jitterMean"] = report.jitterMean;
request["jitterMax"] = report.jitterMax;
request["jitterVariance"] = report.jitterVariance;

json players = json::array();
for (int i = 0; i < report.players.size(); i++)
Expand Down Expand Up @@ -138,4 +141,4 @@ void SlippiGameReporter::ReportThreadHandler()
Common::SleepCurrentThread(0);
}
}
}
}
3 changes: 3 additions & 0 deletions Source/Core/Core/Slippi/SlippiGameReporter.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ class SlippiGameReporter
{
u32 durationFrames = 0;
std::vector<PlayerReport> players;
float jitterMean = 0;
float jitterMax = 0;
float jitterVariance = 0;
};

SlippiGameReporter(SlippiUser *user);
Expand Down
46 changes: 46 additions & 0 deletions Source/Core/Core/Slippi/SlippiNetplay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@
#include <SlippiGame.h>
#include <algorithm>
#include <fstream>
#include <math.h>
#include <mbedtls/md5.h>
#include <memory>
#include <numeric>
#include <thread>

static std::mutex pad_mutex;
Expand Down Expand Up @@ -148,6 +150,13 @@ unsigned int SlippiNetplayClient::OnData(sf::Packet &packet)

u64 curTime = Common::Timer::GetTimeUs();

// 120 frames to let the game settle before measuring network quality
if (frame > 120)
{
std::lock_guard<std::recursive_mutex> lkq(packetTimestampsMutex);
packetTimestamps.push_back(curTime);
}

auto timing = lastFrameTiming;
if (!hasGameStarted)
{
Expand Down Expand Up @@ -536,6 +545,10 @@ void SlippiNetplayClient::StartSlippiGame()

// Reset ack timers
ackTimers.Clear();
{
std::lock_guard<std::recursive_mutex> lkq(packetTimestampsMutex);
packetTimestamps.clear();
}
}

void SlippiNetplayClient::SendConnectionSelected()
Expand Down Expand Up @@ -714,3 +727,36 @@ s32 SlippiNetplayClient::CalcTimeOffsetUs()

return sum / count;
}

// C++ seriously doesn't have a variance built-in. So we have to make our own
float SlippiNetplayClient::ComputeSampleVariance(float mean, std::vector<u64>& numbers)
{
if (numbers.size() <= 1)
return 0;

float total = 0;
for(u64 i : numbers) {
total += pow((i - mean), 2);
}

return total / (numbers.size() - 1);
}

void SlippiNetplayClient::GetNetworkingStats(SlippiGameReporter::GameReport *report)
{
std::vector<u64> differences;
{
std::lock_guard<std::recursive_mutex> lkq(packetTimestampsMutex);
differences.resize(packetTimestamps.size()-1);
std::adjacent_difference(packetTimestamps.begin(), packetTimestamps.end(), differences.begin());
// For absolutely no reason that I can gather, adjacent_difference puts an exta element at the front of the result vector. Remove it
differences.erase(differences.begin());
}
float sum = 0;
for (u64 i : differences) {
sum += i;
}
report->jitterMean = sum / (float)differences.size();
report->jitterMax = (float)*std::max_element(differences.begin(), differences.end());
report->jitterVariance = ComputeSampleVariance(report->jitterMean, differences);
}
6 changes: 6 additions & 0 deletions Source/Core/Core/Slippi/SlippiNetplay.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "Common/TraversalClient.h"
#include "Core/NetPlayProto.h"
#include "Core/Slippi/SlippiPad.h"
#include "Core/Slippi/SlippiGameReporter.h"
#include "InputCommon/GCPadStatus.h"
#include <SFML/Network/Packet.hpp>
#include <array>
Expand Down Expand Up @@ -123,6 +124,7 @@ class SlippiNetplayClient
u64 GetSlippiPing();
int32_t GetSlippiLatestRemoteFrame();
s32 CalcTimeOffsetUs();
void GetNetworkingStats(SlippiGameReporter::GameReport *outReport);

protected:
struct
Expand Down Expand Up @@ -169,6 +171,9 @@ class SlippiNetplayClient

FrameTiming lastFrameTiming;
u64 pingUs;
std::vector<u64> packetTimestamps;
std::recursive_mutex packetTimestampsMutex;

std::deque<std::unique_ptr<SlippiPad>> localPadQueue; // most recent inputs at start of deque
std::deque<std::unique_ptr<SlippiPad>> remotePadQueue; // most recent inputs at start of deque
Common::FifoQueue<FrameTiming, false> ackTimers;
Expand All @@ -184,6 +189,7 @@ class SlippiNetplayClient
unsigned int OnData(sf::Packet &packet);
void Send(sf::Packet &packet);
void Disconnect();
float ComputeSampleVariance(float mean, std::vector<u64>& numbers);

bool m_is_connected = false;

Expand Down

0 comments on commit 710208a

Please sign in to comment.