204 lines
6.2 KiB
C++
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
|