output bot metrics data in tidepool with "-M" flag
This commit is contained in:
parent
52d339747a
commit
9067459eb1
|
@ -42,12 +42,12 @@ pub struct CliArgs {
|
||||||
|
|
||||||
#[derive(Clone, Debug, Args)]
|
#[derive(Clone, Debug, Args)]
|
||||||
pub struct OutputDataArgs {
|
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.
|
/// Generate the full list of moves in the output.
|
||||||
#[arg(short = 'L', long)]
|
#[arg(short = 'L', long)]
|
||||||
pub list_moves: bool,
|
pub list_moves: bool,
|
||||||
|
/// Generate algorithm metrics in the output.
|
||||||
|
#[arg(short = 'M', long)]
|
||||||
|
pub metrics: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Args)]
|
#[derive(Clone, Debug, Args)]
|
||||||
|
|
|
@ -341,6 +341,7 @@ fn run_simulation(
|
||||||
exit_early: &atomic::AtomicBool,
|
exit_early: &atomic::AtomicBool,
|
||||||
) {
|
) {
|
||||||
let mut moves = data_args.list_moves.then(Vec::new);
|
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 seed = seed.unwrap_or_else(|| rand::thread_rng().next_u64());
|
||||||
let weights = eval::Weights::default();
|
let weights = eval::Weights::default();
|
||||||
|
|
||||||
|
@ -363,6 +364,9 @@ fn run_simulation(
|
||||||
sim.matrix(),
|
sim.matrix(),
|
||||||
mino::Queue::new(sim.queue().hold(), sim.queue().next()),
|
mino::Queue::new(sim.queue().hold(), sim.queue().next()),
|
||||||
);
|
);
|
||||||
|
if data_args.metrics {
|
||||||
|
bot.start_instrumenting();
|
||||||
|
}
|
||||||
|
|
||||||
while bot.iterations() < config.bot.iters {
|
while bot.iterations() < config.bot.iters {
|
||||||
let gas = std::cmp::min(50_000, config.bot.iters - bot.iterations());
|
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() {
|
if let Some(moves) = moves.as_mut() {
|
||||||
moves.push(output::Move { placement })
|
moves.push(output::Move { placement })
|
||||||
}
|
}
|
||||||
|
if let Some(metrics) = metrics.as_mut() {
|
||||||
|
metrics.push(bot.metrics().unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
let status = Status {
|
let status = Status {
|
||||||
lines_left: sim.lines_left(),
|
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 {
|
let output = output::Output {
|
||||||
seed,
|
seed,
|
||||||
cleared: config.game.goal - sim.lines_left(),
|
cleared: config.game.goal - sim.lines_left(),
|
||||||
pieces: sim.pieces(),
|
pieces: sim.pieces(),
|
||||||
config: config.game,
|
config: config.game,
|
||||||
moves,
|
moves,
|
||||||
profile,
|
metrics,
|
||||||
};
|
};
|
||||||
if tx.send(Msg::Output(id, output.into())).is_err() {
|
if tx.send(Msg::Output(id, output.into())).is_err() {
|
||||||
tracing::debug!("nobody received output id={id}");
|
tracing::debug!("nobody received output id={id}");
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
use fish::bot::Metrics;
|
||||||
use mino::srs::Piece;
|
use mino::srs::Piece;
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use std::time::Duration;
|
|
||||||
|
|
||||||
use crate::config::GameConfig;
|
use crate::config::GameConfig;
|
||||||
|
|
||||||
|
@ -11,10 +11,13 @@ pub struct Output {
|
||||||
pub config: GameConfig,
|
pub config: GameConfig,
|
||||||
pub pieces: usize,
|
pub pieces: usize,
|
||||||
pub cleared: usize,
|
pub cleared: usize,
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub moves: Option<Vec<Move>>,
|
pub moves: Option<Vec<Move>>,
|
||||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
#[serde(
|
||||||
pub profile: Option<Profile>,
|
serialize_with = "ser::metrics",
|
||||||
|
skip_serializing_if = "Option::is_none"
|
||||||
|
)]
|
||||||
|
pub metrics: Option<Vec<Metrics>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Output {
|
impl Output {
|
||||||
|
@ -30,16 +33,6 @@ pub struct Move {
|
||||||
// TODO: spin?
|
// 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)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct SummaryStats<T: Copy> {
|
pub struct SummaryStats<T: Copy> {
|
||||||
count: usize,
|
count: usize,
|
||||||
|
@ -167,11 +160,56 @@ mod ser {
|
||||||
.serialize(serializer)
|
.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
|
where
|
||||||
S: serde::Serializer,
|
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>
|
pub fn summary_stats<S, T>(stats: &SummaryStats<T>, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
|
Loading…
Reference in New Issue