report API
Luna-Flow/mare_mark/report は JSONL イベントストリームを Plot IR ドキュメントに変換し、そのドキュメントを mmks_1 JSON、単独の SVG、または自己完結型の HTML ページとして描画します。4 つの関数はすべて純粋で、文字列と値を受け取り文字列を返します。ファイルの読み書きは cli の役割です。射影の規則は report の設計で説明しています。
ソース: src/report/report.mbt。
import {
"Luna-Flow/mare_mark/ir_model",
"Luna-Flow/mare_mark/report",
}
イベントの解析
document_from_jsonl
document_from_jsonl は JSONL イベントストリームを解析して PlotDocument にします。
pub fn document_from_jsonl(String, target? : String) -> Result[@ir_model.PlotDocument, String]
target(既定値 "unknown")はドキュメントにコピーされます。イベント自体はこれを持ちません。空行は読み飛ばされます。それ以外の各行は JSON オブジェクトでなければならず、その artifact_version は、存在する場合は文字列 "mmka_1" でなければなりません。各行はその "type" によって解釈されます:
type | 必須フィールド | 動作 |
|---|---|---|
observation | implementation(文字列)、dataset_id、elapsed_us(数値) | プロット点(x = dataset_id、y = elapsed_us、series = implementation)。ただし valid が false の場合や batch_sink が "kept" でない場合を除きます |
validation | なし | ケイパビリティ行列で implementation と actual_kind(存在しない場合は "unclassified")ごとに数えます。ステータスが invalid または infrastructure_failure の場合は不一致の行を追加し、case と dataset_id が存在すれば、そのケースとデータセットにおけるその実装の点を取り除きます |
validation_failure | なし | 反例の行(最小入力、最小フィンガープリント、縮小パス、リプレイコマンド) |
summary | なし | run_id とコーパス件数を設定します。最後の要約が優先されます |
| それ以外 | calibration を含め、無視されます |
ドキュメントは、タイトル "Benchmark observations"、単位 "µs/op"、区間の種類 "raw" の Scaling プロットを 1 つ持ちます。残る点が 1 つもない場合はプロットを持ちません。探索的な観測と確認的な観測は一緒にプロットされます。コーパスの合計は要約の 4 つの件数の和です。
エラーは 1 始まりの行番号を伴うメッセージです。不正な JSON、オブジェクトでない行、サポートされないまたは文字列でないアーティファクトバージョン、implementation、dataset_id、elapsed_us のいずれかを欠く観測、そして点も不一致も反例も含まないストリームがエラーになります。
test "parse a small event stream" {
let source =
#|{"type":"observation","case":"add","implementation":"a","dataset_id":0,"elapsed_us":12.5}
#|{"type":"observation","case":"add","implementation":"b","dataset_id":0,"elapsed_us":10.0}
#|{"type":"observation","case":"add","implementation":"b","dataset_id":1,"elapsed_us":30.0,"valid":false}
#|{"type":"summary","run_id":"demo","passed_count":2}
let document = @report.document_from_jsonl(source, target="native").unwrap()
inspect(document.run_id, content="demo")
inspect(document.plots[0].points.length(), content="2")
inspect(document.differential.corpus.total, content="2")
let bad = @report.document_from_jsonl("{\"artifact_version\":\"mmka_9\"}")
inspect(bad is Err("unsupported artifact version 'mmka_9' at line 1"), content="true")
}
描画
plot_json
plot_json はドキュメントを mmks_1 JSON としてシリアライズします。
pub fn plot_json(@ir_model.PlotDocument) -> String
オブジェクトはキー schema_version、run_id、target、plots(それぞれ kind、title、unit、interval_kind と、x、y、series からなる points を持つ)、および differential(mismatches、capabilities、counterexamples、corpus)を持ちます。プロットの種類はスネークケース(scaling、raw_distribution、block_order、interval、outlier、change_point、heatmap、pareto)で書かれます。出力はコンパクトで、文字列は JSON エンコーダによってエスケープされます。
test "plot JSON" {
let point = @ir_model.PlotPoint::new("0", 1.0, "a")
let plot = @ir_model.Plot::new(@ir_model.PlotKind::Scaling, "t", "µs/op", "raw", [point])
let document = @ir_model.PlotDocument::new("r", "native", [plot])
let json = @report.plot_json(document)
inspect(json.has_prefix("{\"schema_version\":\"mmks_1\",\"run_id\":\"r\""), content="true")
inspect(json.contains("\"points\":[{\"x\":\"0\",\"y\":1,\"series\":\"a\"}]"), content="true")
}
plot_svg
plot_svg は 1 つのプロットを単独の SVG 要素として描画します。
pub fn plot_svg(@ir_model.Plot) -> String
SVG は 960 × 420 の view box、アクセシブルな <title> と <desc>、インラインスタイル、目盛り値付きの 5 本の水平グリッド線、最大でおよそ 10 個の x ラベル、および凡例を持ちます。各点はツールチップ series — x: y unit 付きの円として描かれます。Scaling、Interval、ChangePoint のプロットでは、さらに系列ごとに各 x カテゴリにおける点の平均を線で結びます。Heatmap のプロットは系列と x カテゴリごとに 1 つのセルを描き、その不透明度は平均値とともに大きくなります。空のプロットには “No observations” と表示されます。すべてのテキストは XML エスケープされます。
test "plot SVG" {
let points = [
@ir_model.PlotPoint::new("64", 2.0, "scalar"),
@ir_model.PlotPoint::new("128", 4.5, "scalar"),
]
let plot = @ir_model.Plot::new(@ir_model.PlotKind::Scaling, "a < b", "µs/op", "raw", points)
let svg = @report.plot_svg(plot)
inspect(svg.has_prefix("<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 960 420\""), content="true")
inspect(svg.contains("<title id=\"plot-title\">a < b</title>"), content="true")
inspect(svg.contains("<polyline"), content="true")
}
html
html はドキュメント全体を 1 つの自己完結型 HTML ページとして描画します。
pub fn html(@ir_model.PlotDocument) -> String
ページには、実行 ID、ターゲット、スキーマバージョンを含むヘッダー、続いて差分レポート(コーパスの結果、不一致、ケイパビリティのカバレッジ行列、最小反例)、さらにプロットごとに 1 つの図が含まれます。CSS はインライン、プロットはインライン SVG で、スクリプトも外部リソースもないため、ファイルをそのままアーカイブしたり添付したりできます。出力はドキュメントだけに依存します。
test "self-contained HTML" {
let source =
#|{"type":"observation","case":"add","implementation":"a","dataset_id":0,"elapsed_us":12.5}
#|{"type":"summary","run_id":"demo"}
let page = @report.html(@report.document_from_jsonl(source).unwrap())
inspect(page.has_prefix("<!doctype html>"), content="true")
inspect(page.contains("<title>mare_mark · demo</title>"), content="true")
inspect(page.contains("<script"), content="false")
}