output bot metrics data in tidepool with "-M" flag

This commit is contained in:
tali 2023-04-16 19:07:16 -04:00
parent 52d339747a
commit 9067459eb1
3 changed files with 65 additions and 24 deletions

View File

@ -42,12 +42,12 @@ pub struct CliArgs {
#[derive(Clone, Debug, Args)]
pub struct OutputDataArgs {
/// Generate profiling data in the output.
#[arg(short = 'P', long)]
pub profile: bool,
/// Generate the full list of moves in the output.
#[arg(short = 'L', long)]
pub list_moves: bool,
/// Generate algorithm metrics in the output.
#[arg(short = 'M', long)]
pub metrics: bool,
}
#[derive(Clone, Debug, Args)]

View File

@ -341,6 +341,7 @@ fn run_simulation(
exit_early: &atomic::AtomicBool,
) {
let mut moves = data_args.list_moves.then(Vec::new);
let mut metrics = data_args.metrics.then(Vec::new);
let seed = seed.unwrap_or_else(|| rand::thread_rng().next_u64());
let weights = eval::Weights::default();
@ -363,6 +364,9 @@ fn run_simulation(
sim.matrix(),
mino::Queue::new(sim.queue().hold(), sim.queue().next()),
);
if data_args.metrics {
bot.start_instrumenting();
}
while bot.iterations() < config.bot.iters {
let gas = std::cmp::min(50_000, config.bot.iters - bot.iterations());
@ -385,6 +389,9 @@ fn run_simulation(
if let Some(moves) = moves.as_mut() {
moves.push(output::Move { placement })
}
if let Some(metrics) = metrics.as_mut() {
metrics.push(bot.metrics().unwrap());
}
let status = Status {
lines_left: sim.lines_left(),
@ -396,17 +403,13 @@ fn run_simulation(
}
}
let profile = data_args.profile.then(|| output::Profile {
time: Instant::now() - time_start,
});
let output = output::Output {
seed,
cleared: config.game.goal - sim.lines_left(),
pieces: sim.pieces(),
config: config.game,
moves,
profile,
metrics,
};
if tx.send(Msg::Output(id, output.into())).is_err() {
tracing::debug!("nobody received output id={id}");

View File

@ -1,6 +1,6 @@
use fish::bot::Metrics;
use mino::srs::Piece;
use serde::Serialize;
use std::time::Duration;
use crate::config::GameConfig;
@ -11,10 +11,13 @@ pub struct Output {
pub config: GameConfig,
pub pieces: usize,
pub cleared: usize,
#[serde(default, skip_serializing_if = "Option::is_none")]
#[serde(skip_serializing_if = "Option::is_none")]
pub moves: Option<Vec<Move>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub profile: Option<Profile>,
#[serde(
serialize_with = "ser::metrics",
skip_serializing_if = "Option::is_none"
)]
pub metrics: Option<Vec<Metrics>>,
}
impl Output {
@ -30,16 +33,6 @@ pub struct Move {
// TODO: spin?
}
#[derive(Serialize, Debug)]
pub struct Profile {
#[serde(serialize_with = "ser::seconds")]
pub time: Duration,
// TODO: pps mean/variance
// TODO: timing stats for specific functions/routines
// TODO: stats info about top <N> evaluations
// TODO: histograms about selected nodes
}
#[derive(Copy, Clone, Debug)]
pub struct SummaryStats<T: Copy> {
count: usize,
@ -167,11 +160,56 @@ mod ser {
.serialize(serializer)
}
pub fn seconds<S>(dur: &Duration, serializer: S) -> Result<S::Ok, S::Error>
pub fn metrics<S>(metrics: &Option<Vec<Metrics>>, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
dur.as_secs_f64().serialize(serializer)
#[derive(Serialize)]
struct MoveMetrics {
start: NodeMetrics,
end: NodeMetrics,
}
#[derive(Serialize)]
struct NodeMetrics {
features: Vec<i32>,
heuristic: i32,
#[serde(flatten)]
rating: RatingVariant,
#[serde(skip_serializing_if = "Option::is_none")]
iteration: Option<u32>,
}
#[derive(Serialize)]
#[serde(untagged)]
enum RatingVariant {
NotApplicable,
Rating { rating: i32 },
Solution { solution: i32 },
}
metrics
.iter()
.flat_map(|m| m.iter())
.map(|m| MoveMetrics {
start: NodeMetrics {
features: m.start_features.1.to_vec(),
heuristic: m.start_heuristic,
rating: RatingVariant::NotApplicable,
iteration: None,
},
end: NodeMetrics {
features: m.end_features.1.to_vec(),
heuristic: m.end_heuristic,
rating: match m.end_rating {
(false, v) => RatingVariant::Rating { rating: v },
(true, v) => RatingVariant::Solution { solution: -v },
},
iteration: Some(m.end_iteration),
},
})
.collect::<Vec<_>>()
.serialize(serializer)
}
pub fn summary_stats<S, T>(stats: &SummaryStats<T>, serializer: S) -> Result<S::Ok, S::Error>