Files
netcode-demo/common/include/common/metrics.hpp
2026-01-11 01:37:39 +04:00

204 lines
6.2 KiB
C++

#pragma once
#include "types.hpp"
#include "ring_buffer.hpp"
#include <cmath>
#include <algorithm>
#include <fstream>
#include <string>
#include <iomanip>
namespace netcode {
// Метрики позиции
struct PositionMetrics {
double mae = 0.0; // Mean Absolute Error
double mse = 0.0; // Mean Squared Error
double max_error = 0.0; // Максимальная ошибка
uint32_t sample_count = 0;
};
// Метрики сети
struct NetworkMetrics {
double rtt_ms = 0.0;
double jitter_ms = 0.0;
double packet_loss_percent = 0.0;
uint64_t bytes_sent = 0;
uint64_t bytes_received = 0;
uint64_t packets_sent = 0;
uint64_t packets_received = 0;
};
// Метрики алгоритмов компенсации
struct CompensationMetrics {
uint32_t predictions_per_second = 0;
uint32_t reconciliations_per_second = 0;
double avg_correction_distance = 0.0;
double max_correction_distance = 0.0;
uint32_t rollbacks_count = 0;
double input_delay_ms = 0.0;
};
// Накопитель метрик
class MetricsCollector {
public:
void add_position_error(float predicted_x, float predicted_y,
float actual_x, float actual_y) {
float dx = predicted_x - actual_x;
float dy = predicted_y - actual_y;
float error = std::sqrt(dx * dx + dy * dy);
position_errors_.push(error);
total_error_ += error;
total_squared_error_ += error * error;
max_error_ = (std::max)(max_error_, static_cast<double>(error));
error_count_++;
}
void add_correction(float distance) {
corrections_.push(distance);
correction_count_++;
total_correction_ += distance;
max_correction_ = (std::max)(max_correction_, static_cast<double>(distance));
}
void add_reconciliation() {
reconciliation_count_++;
}
void add_prediction() {
prediction_count_++;
}
void add_rollback() {
rollback_count_++;
}
PositionMetrics get_position_metrics() const {
PositionMetrics m;
m.sample_count = error_count_;
if (error_count_ > 0) {
m.mae = total_error_ / error_count_;
m.mse = total_squared_error_ / error_count_;
m.max_error = max_error_;
}
return m;
}
CompensationMetrics get_compensation_metrics(double elapsed_seconds) const {
CompensationMetrics m;
if (elapsed_seconds > 0) {
m.predictions_per_second = static_cast<uint32_t>(prediction_count_ / elapsed_seconds);
m.reconciliations_per_second = static_cast<uint32_t>(reconciliation_count_ / elapsed_seconds);
}
if (correction_count_ > 0) {
m.avg_correction_distance = total_correction_ / correction_count_;
}
m.max_correction_distance = max_correction_;
m.rollbacks_count = rollback_count_;
return m;
}
void reset_compensation_metrics() {
prediction_count_ = 0;
reconciliation_count_ = 0;
total_correction_ = 0.0;
max_correction_ = 0.0;
correction_count_ = 0;
}
void reset() {
position_errors_.clear();
corrections_.clear();
total_error_ = 0;
total_squared_error_ = 0;
max_error_ = 0;
error_count_ = 0;
total_correction_ = 0;
max_correction_ = 0;
correction_count_ = 0;
prediction_count_ = 0;
reconciliation_count_ = 0;
rollback_count_ = 0;
}
private:
RingBuffer<float, 1024> position_errors_;
RingBuffer<float, 256> corrections_;
double total_error_ = 0;
double total_squared_error_ = 0;
double max_error_ = 0;
uint32_t error_count_ = 0;
double total_correction_ = 0;
double max_correction_ = 0;
uint32_t correction_count_ = 0;
uint32_t prediction_count_ = 0;
uint32_t reconciliation_count_ = 0;
uint32_t rollback_count_ = 0;
};
class MetricsLogger {
public:
explicit MetricsLogger(const std::string& filename = "client_metrics.csv") {
file_.open(filename);
if (file_.is_open()) {
file_ << "timestamp_ms,preset,algorithm,rtt_ms,jitter_ms,packet_loss_percent,"
<< "packets_sent_per_sec,packets_delivered_per_sec,packets_lost_per_sec,packets_duplicated_per_sec,"
<< "fps,inputs_per_sec,snapshots_per_sec,"
<< "position_mae,position_mse,position_max_error,samples,"
<< "predictions_per_sec,reconciliations_per_sec,"
<< "avg_correction_distance,max_correction_distance\n";
file_.flush();
}
}
void log(uint64_t timestamp_ms,
const std::string& preset_name,
const std::string& algorithm_name,
double rtt_ms,
double jitter_ms,
double packet_loss_percent,
uint64_t packets_sent_ps,
uint64_t packets_delivered_ps,
uint64_t packets_lost_ps,
uint64_t packets_duplicated_ps,
float fps,
uint32_t inputs_per_sec,
uint32_t snapshots_per_sec,
const PositionMetrics& pos,
const CompensationMetrics& comp) {
if (!file_.is_open()) return;
file_ << timestamp_ms << ","
<< preset_name << ","
<< algorithm_name << ","
<< std::fixed << std::setprecision(3)
<< rtt_ms << ","
<< jitter_ms << ","
<< packet_loss_percent << ","
<< packets_sent_ps << ","
<< packets_delivered_ps << ","
<< packets_lost_ps << ","
<< packets_duplicated_ps << ","
<< fps << ","
<< inputs_per_sec << ","
<< snapshots_per_sec << ","
<< pos.mae << ","
<< pos.mse << ","
<< pos.max_error << ","
<< pos.sample_count << ","
<< comp.predictions_per_second << ","
<< comp.reconciliations_per_second << ","
<< comp.avg_correction_distance << ","
<< comp.max_correction_distance << "\n";
file_.flush();
}
private:
std::ofstream file_;
};
} // namespace netcode