mirror of
https://github.com/SikongJueluo/Mini-Nav.git
synced 2026-07-12 20:15:31 +08:00
feat: add hardware retrieval cycle performance measurement
Add cycle-level performance measurement for hardware CAM retrieval benchmarks to complement existing quality metrics. - Add query_topk_once_with_latency with accept→first/last cycle timing - Add QueryTiming dataclass and summarize_query_timings helper - Integrate cycle performance into benchmark outputs (CSV + Markdown) - Log RETRIEVAL_PERF_RESULT with cycles/query and queries/cycle - Update experiment docs with hardware cycle performance section - Add unit tests for summarize_query_timings and output writers
This commit is contained in:
@@ -15,7 +15,7 @@ CAM 顶层测试的共享辅助函数。
|
||||
from __future__ import annotations
|
||||
|
||||
import numpy as np
|
||||
from cocotb.triggers import RisingEdge
|
||||
from cocotb.triggers import ReadOnly, RisingEdge, Timer
|
||||
from model.ref_model import ( # noqa: E402
|
||||
match_top1,
|
||||
unpack_score_debug_flat,
|
||||
@@ -202,28 +202,73 @@ async def query_topk_once(dut, query, timeout_cycles=None):
|
||||
- beats: [(rank, row, score, last), ...]
|
||||
- score_debug: np.ndarray 或 None(SIM_DEBUG 模式)
|
||||
"""
|
||||
beats, top1_index, top1_score, score_debug, _ = await query_topk_once_with_latency(
|
||||
dut, query, timeout_cycles=timeout_cycles,
|
||||
)
|
||||
return beats, top1_index, top1_score, score_debug
|
||||
|
||||
|
||||
async def query_topk_once_with_latency(dut, query, timeout_cycles=None):
|
||||
"""发起一次查询、收集完整 Top-K 结果流,并返回周期计数。
|
||||
|
||||
返回:(beats, top1_index, top1_score, score_debug, timing)
|
||||
|
||||
``timing`` 字段:
|
||||
- accept_to_first_result_cycles: query 接受到首个 result_valid beat
|
||||
- accept_to_last_result_cycles: query 接受到 result_last beat(Top-K 完成)
|
||||
- total_query_cycles: 从拉高 query_valid 到 Top-K 完成的总上升沿数
|
||||
|
||||
``query_ready`` 是组合信号,握手周期在上升沿前采样;结果信号在
|
||||
ReadOnly settled phase 采样,避免重新引入 query_ready 采样时序问题。
|
||||
"""
|
||||
await wait_idle(dut)
|
||||
|
||||
dut.query_hash.value = int(query)
|
||||
|
||||
# 等待 query_ready 为高(DUT 已就绪),避免组合逻辑下降沿导致的
|
||||
# valid&&ready 握手丢失问题
|
||||
# valid&&ready 握手丢失问题。
|
||||
while not int(dut.query_ready.value):
|
||||
await RisingEdge(dut.clk)
|
||||
|
||||
# assert query_valid 覆盖一个上升沿完成握手
|
||||
edge_count = 0
|
||||
dut.query_valid.value = 1
|
||||
dut.result_ready.value = 1
|
||||
|
||||
await RisingEdge(dut.clk)
|
||||
edge_count += 1
|
||||
q_ready = int(dut.query_ready.value)
|
||||
assert q_ready, "Query accept handshake was missed despite query_ready pre-wait"
|
||||
accept_edge = edge_count
|
||||
dut.query_valid.value = 0
|
||||
|
||||
# 若调用者未指定超时,根据 DUT 参数动态估算
|
||||
if timeout_cycles is None:
|
||||
timeout_cycles = dut_query_timeout_cycles(dut)
|
||||
|
||||
# 消费完整串行结果流
|
||||
beats = await collect_topk(dut, timeout_cycles=timeout_cycles)
|
||||
beats = []
|
||||
first_result_edge = None
|
||||
last_result_edge = None
|
||||
|
||||
for _ in range(timeout_cycles):
|
||||
await RisingEdge(dut.clk)
|
||||
edge_count += 1
|
||||
await ReadOnly()
|
||||
if int(dut.result_valid.value):
|
||||
if first_result_edge is None:
|
||||
first_result_edge = edge_count
|
||||
rank = int(dut.result_rank.value)
|
||||
row = int(dut.result_row.value)
|
||||
score = int(dut.result_score.value)
|
||||
last = int(dut.result_last.value)
|
||||
beats.append((rank, row, score, last))
|
||||
if last:
|
||||
last_result_edge = edge_count
|
||||
await Timer(1, units="step")
|
||||
break
|
||||
await Timer(1, units="step")
|
||||
|
||||
if first_result_edge is None or last_result_edge is None:
|
||||
raise AssertionError("Top-K result stream did not finish")
|
||||
|
||||
# score_debug 在查询完成后可用(需 SIM_DEBUG 编译)
|
||||
num_rows = dut_num_rows(dut)
|
||||
score_bits = dut_score_bits(dut)
|
||||
score_debug = None
|
||||
@@ -234,7 +279,12 @@ async def query_topk_once(dut, query, timeout_cycles=None):
|
||||
score_bits,
|
||||
)
|
||||
|
||||
return beats, beats[0][1], beats[0][2], score_debug
|
||||
timing = {
|
||||
"accept_to_first_result_cycles": int(first_result_edge - accept_edge),
|
||||
"accept_to_last_result_cycles": int(last_result_edge - accept_edge),
|
||||
"total_query_cycles": int(edge_count),
|
||||
}
|
||||
return beats, beats[0][1], beats[0][2], score_debug, timing
|
||||
|
||||
|
||||
async def query_once(dut, query, timeout_cycles=None):
|
||||
|
||||
Reference in New Issue
Block a user