From e90e569284133171f2fdf64e4eff880ad716fd6f Mon Sep 17 00:00:00 2001 From: inphi Date: Mon, 18 Aug 2025 17:18:42 -0400 Subject: [PATCH] cannon,op-challenger: Add metric to report i-cache misses --- cannon/mipsevm/debug.go | 12 ++++---- cannon/mipsevm/debug_test.go | 2 ++ cannon/mipsevm/multithreaded/mips.go | 1 + cannon/mipsevm/multithreaded/stats.go | 14 +++++++++ op-challenger/game/fault/trace/vm/executor.go | 2 ++ .../game/fault/trace/vm/executor_test.go | 23 ++++++++------ op-challenger/metrics/vm.go | 30 +++++++++++++------ 7 files changed, 61 insertions(+), 23 deletions(-) diff --git a/cannon/mipsevm/debug.go b/cannon/mipsevm/debug.go index 02c20ea248239..ffa6bfaaeb641 100644 --- a/cannon/mipsevm/debug.go +++ b/cannon/mipsevm/debug.go @@ -3,11 +3,13 @@ package mipsevm import "github.com/ethereum/go-ethereum/common/hexutil" type DebugInfo struct { - Pages int `json:"pages"` - MemoryUsed hexutil.Uint64 `json:"memory_used"` - NumPreimageRequests int `json:"num_preimage_requests"` - TotalPreimageSize int `json:"total_preimage_size"` - TotalSteps uint64 `json:"total_steps"` + Pages int `json:"pages"` + MemoryUsed hexutil.Uint64 `json:"memory_used"` + NumPreimageRequests int `json:"num_preimage_requests"` + TotalPreimageSize int `json:"total_preimage_size"` + TotalSteps uint64 `json:"total_steps"` + InstructionCacheMissCount uint64 `json:"instruction_cache_miss_count"` + HighestICacheMissPC hexutil.Uint64 `json:"highest_icache_miss_pc"` // Multithreading-related stats below RmwSuccessCount uint64 `json:"rmw_success_count"` RmwFailCount uint64 `json:"rmw_fail_count"` diff --git a/cannon/mipsevm/debug_test.go b/cannon/mipsevm/debug_test.go index e2b6b8e43ab69..df567b202bd2d 100644 --- a/cannon/mipsevm/debug_test.go +++ b/cannon/mipsevm/debug_test.go @@ -18,6 +18,8 @@ func TestDebugInfo_Serialization(t *testing.T) { NumPreimageRequests: 3, TotalPreimageSize: 4, TotalSteps: 123456, + InstructionCacheMissCount: 10, + HighestICacheMissPC: 11, RmwSuccessCount: 5, RmwFailCount: 6, MaxStepsBetweenLLAndSC: 7, diff --git a/cannon/mipsevm/multithreaded/mips.go b/cannon/mipsevm/multithreaded/mips.go index 9db3a234bde04..3a9b9ecfcffda 100644 --- a/cannon/mipsevm/multithreaded/mips.go +++ b/cannon/mipsevm/multithreaded/mips.go @@ -335,6 +335,7 @@ func (m *InstrumentedState) doMipsStep() error { insn, opcode, fun = decoded.insn, decoded.opcode, decoded.fun } else { // PC is outside eager region + m.statsTracker.trackInstructionCacheMiss(pc) insn, opcode, fun = exec.GetInstructionDetails(pc, m.state.Memory) } diff --git a/cannon/mipsevm/multithreaded/stats.go b/cannon/mipsevm/multithreaded/stats.go index 04de1516359bd..77185ea64c867 100644 --- a/cannon/mipsevm/multithreaded/stats.go +++ b/cannon/mipsevm/multithreaded/stats.go @@ -1,6 +1,7 @@ package multithreaded import ( + "github.com/ethereum/go-ethereum/common/hexutil" lru "github.com/hashicorp/golang-lru/v2/simplelru" "github.com/ethereum-optimism/optimism/cannon/mipsevm" @@ -14,6 +15,7 @@ type StatsTracker interface { trackReservationInvalidation() trackForcedPreemption() trackThreadActivated(tid Word, step uint64) + trackInstructionCacheMiss(pc Word) populateDebugInfo(debugInfo *mipsevm.DebugInfo) } @@ -31,6 +33,7 @@ func (s *noopStatsTracker) trackReservationInvalidation() {} func (s *noopStatsTracker) trackForcedPreemption() {} func (s *noopStatsTracker) trackThreadActivated(tid Word, step uint64) {} func (s *noopStatsTracker) populateDebugInfo(debugInfo *mipsevm.DebugInfo) {} +func (s *noopStatsTracker) trackInstructionCacheMiss(pc Word) {} var _ StatsTracker = (*noopStatsTracker)(nil) @@ -48,6 +51,8 @@ type statsTrackerImpl struct { reservationInvalidationCount uint64 forcedPreemptionCount uint64 idleStepCountThread0 uint64 + icacheMissCount uint64 + highestICacheMissPC Word } func (s *statsTrackerImpl) populateDebugInfo(debugInfo *mipsevm.DebugInfo) { @@ -57,6 +62,8 @@ func (s *statsTrackerImpl) populateDebugInfo(debugInfo *mipsevm.DebugInfo) { debugInfo.ReservationInvalidationCount = s.reservationInvalidationCount debugInfo.ForcedPreemptionCount = s.forcedPreemptionCount debugInfo.IdleStepCountThread0 = s.idleStepCountThread0 + debugInfo.InstructionCacheMissCount = s.icacheMissCount + debugInfo.HighestICacheMissPC = hexutil.Uint64(s.highestICacheMissPC) } func (s *statsTrackerImpl) trackLL(threadId Word, step uint64) { @@ -105,6 +112,13 @@ func (s *statsTrackerImpl) trackThreadActivated(tid Word, step uint64) { s.activeThreadId = tid } +func (s *statsTrackerImpl) trackInstructionCacheMiss(pc Word) { + s.icacheMissCount += 1 + if pc > s.highestICacheMissPC { + s.highestICacheMissPC = pc + } +} + func NewStatsTracker() StatsTracker { return newStatsTracker(5) } diff --git a/op-challenger/game/fault/trace/vm/executor.go b/op-challenger/game/fault/trace/vm/executor.go index c6339a6a723d0..d2047710e7ed9 100644 --- a/op-challenger/game/fault/trace/vm/executor.go +++ b/op-challenger/game/fault/trace/vm/executor.go @@ -200,6 +200,7 @@ func (e *Executor) DoGenerateProof(ctx context.Context, dir string, begin uint64 memoryUsed = fmt.Sprintf("%d", uint64(info.MemoryUsed)) e.metrics.RecordMemoryUsed(uint64(info.MemoryUsed)) e.metrics.RecordSteps(info.Steps) + e.metrics.RecordInstructionCacheMissCount(info.InstructionCacheMissCount) e.metrics.RecordRmwSuccessCount(info.RmwSuccessCount) e.metrics.RecordRmwFailCount(info.RmwFailCount) e.metrics.RecordMaxStepsBetweenLLAndSC(info.MaxStepsBetweenLLAndSC) @@ -215,6 +216,7 @@ func (e *Executor) DoGenerateProof(ctx context.Context, dir string, begin uint64 type debugInfo struct { MemoryUsed hexutil.Uint64 `json:"memory_used"` Steps uint64 `json:"total_steps"` + InstructionCacheMissCount uint64 `json:"instruction_cache_miss_count"` RmwSuccessCount uint64 `json:"rmw_success_count"` RmwFailCount uint64 `json:"rmw_fail_count"` MaxStepsBetweenLLAndSC uint64 `json:"max_steps_between_ll_and_sc"` diff --git a/op-challenger/game/fault/trace/vm/executor_test.go b/op-challenger/game/fault/trace/vm/executor_test.go index ba6c4f8a269db..55b7ab2403720 100644 --- a/op-challenger/game/fault/trace/vm/executor_test.go +++ b/op-challenger/game/fault/trace/vm/executor_test.go @@ -229,21 +229,26 @@ func newMetrics() *capturingVmMetrics { } type capturingVmMetrics struct { - executionTimeRecordCount int - memoryUsed hexutil.Uint64 - steps uint64 - rmwSuccessCount uint64 - rmwFailCount uint64 - maxStepsBetweenLLAndSC uint64 - reservationInvalidations uint64 - forcedPreemptions uint64 - idleStepsThread0 uint64 + executionTimeRecordCount int + memoryUsed hexutil.Uint64 + steps uint64 + instructionCacheMissCount uint64 + rmwSuccessCount uint64 + rmwFailCount uint64 + maxStepsBetweenLLAndSC uint64 + reservationInvalidations uint64 + forcedPreemptions uint64 + idleStepsThread0 uint64 } func (c *capturingVmMetrics) RecordSteps(val uint64) { c.steps = val } +func (c *capturingVmMetrics) RecordInstructionCacheMissCount(val uint64) { + c.instructionCacheMissCount = val +} + func (c *capturingVmMetrics) RecordExecutionTime(t time.Duration) { c.executionTimeRecordCount += 1 } diff --git a/op-challenger/metrics/vm.go b/op-challenger/metrics/vm.go index 132bd9e713eaf..96ab7abeae444 100644 --- a/op-challenger/metrics/vm.go +++ b/op-challenger/metrics/vm.go @@ -13,6 +13,7 @@ type VmMetricer interface { RecordVmMemoryUsed(vmType string, memoryUsed uint64) RecordVmRmwSuccessCount(vmType string, val uint64) RecordVmSteps(vmType string, val uint64) + RecordVmInstructionCacheMissCount(vmType string, val uint64) RecordVmRmwFailCount(vmType string, val uint64) RecordVmMaxStepsBetweenLLAndSC(vmType string, val uint64) RecordVmReservationInvalidationCount(vmType string, val uint64) @@ -25,6 +26,7 @@ type TypedVmMetricer interface { RecordExecutionTime(t time.Duration) RecordMemoryUsed(memoryUsed uint64) RecordSteps(val uint64) + RecordInstructionCacheMissCount(val uint64) RecordRmwSuccessCount(val uint64) RecordRmwFailCount(val uint64) RecordMaxStepsBetweenLLAndSC(val uint64) @@ -34,15 +36,16 @@ type TypedVmMetricer interface { } type VmMetrics struct { - vmExecutionTime *prometheus.HistogramVec - vmMemoryUsed *prometheus.HistogramVec - vmSteps *prometheus.GaugeVec - vmRmwSuccessCount *prometheus.GaugeVec - vmRmwFailCount *prometheus.GaugeVec - vmMaxStepsBetweenLLAndSC *prometheus.GaugeVec - vmReservationInvalidations *prometheus.GaugeVec - vmForcedPreemptions *prometheus.GaugeVec - vmIdleStepsThread0 *prometheus.GaugeVec + vmExecutionTime *prometheus.HistogramVec + vmMemoryUsed *prometheus.HistogramVec + vmSteps *prometheus.GaugeVec + vmInstructionCacheMissCount *prometheus.GaugeVec + vmRmwSuccessCount *prometheus.GaugeVec + vmRmwFailCount *prometheus.GaugeVec + vmMaxStepsBetweenLLAndSC *prometheus.GaugeVec + vmReservationInvalidations *prometheus.GaugeVec + vmForcedPreemptions *prometheus.GaugeVec + vmIdleStepsThread0 *prometheus.GaugeVec } var _ VmMetricer = (*VmMetrics)(nil) @@ -59,6 +62,10 @@ func (m *VmMetrics) RecordVmSteps(vmType string, val uint64) { m.vmSteps.WithLabelValues(vmType).Set(float64(val)) } +func (m *VmMetrics) RecordVmInstructionCacheMissCount(vmType string, val uint64) { + m.vmInstructionCacheMissCount.WithLabelValues(vmType).Set(float64(val)) +} + func (m *VmMetrics) RecordVmRmwSuccessCount(vmType string, val uint64) { m.vmRmwSuccessCount.WithLabelValues(vmType).Set(float64(val)) } @@ -145,6 +152,7 @@ var _ VmMetricer = NoopVmMetrics{} func (n NoopVmMetrics) RecordVmExecutionTime(vmType string, t time.Duration) {} func (n NoopVmMetrics) RecordVmMemoryUsed(vmType string, memoryUsed uint64) {} func (n NoopVmMetrics) RecordVmSteps(vmType string, val uint64) {} +func (n NoopVmMetrics) RecordVmInstructionCacheMissCount(vmType string, val uint64) {} func (n NoopVmMetrics) RecordVmRmwSuccessCount(vmType string, val uint64) {} func (n NoopVmMetrics) RecordVmRmwFailCount(vmType string, val uint64) {} func (n NoopVmMetrics) RecordVmMaxStepsBetweenLLAndSC(vmType string, val uint64) {} @@ -171,6 +179,10 @@ func (m *typedVmMetricsImpl) RecordSteps(val uint64) { m.m.RecordVmSteps(m.vmType, val) } +func (m *typedVmMetricsImpl) RecordInstructionCacheMissCount(val uint64) { + m.m.RecordVmInstructionCacheMissCount(m.vmType, val) +} + func (m *typedVmMetricsImpl) RecordRmwSuccessCount(val uint64) { m.m.RecordVmRmwSuccessCount(m.vmType, val) }