diff --git a/codex/utils/asyncprofiler.nim b/codex/utils/asyncprofiler.nim index 5ed19e66..c3a43f5d 100644 --- a/codex/utils/asyncprofiler.nim +++ b/codex/utils/asyncprofiler.nim @@ -3,4 +3,6 @@ import ../conf when chronosFuturesInstrumentation: import ./asyncprofiler/asyncprofiler import ./asyncprofiler/serialization - export asyncprofiler, serialization + import ./asyncprofiler/metricscollector + + export asyncprofiler, serialization, metricscollector diff --git a/codex/utils/asyncprofiler/metricscollector.nim b/codex/utils/asyncprofiler/metricscollector.nim new file mode 100644 index 00000000..0d52e888 --- /dev/null +++ b/codex/utils/asyncprofiler/metricscollector.nim @@ -0,0 +1,54 @@ +import std/times + +import asyncprofiler +import metrics + +when defined(metrics): + type + ProfilingCollector* = ref object of Gauge + perfSampler: PerfSampler + + PerfSampler = proc (): MetricsSummary {.raises: [].} + + proc newCollector*( + ProfilingCollector: typedesc, + name: string, + help: string, + perfSampler: PerfSampler, + registry: Registry = defaultRegistry, + ): ProfilingCollector = + result = ProfilingCollector.newCollector( + name=name, help=help, registry=registry) + result.perfSampler = perfSampler + + + method collect*(self: ProfilingCollector): Metrics = + let now = times.getTime().toMilliseconds() + + var largestExecTime = low(timer.Duration) + var largestMaxExecTime = low(timer.Duration) + for (locationPtr, metric) in self.perfSampler().pairs: + if metric.maxSingleTime > largestMaxExecTime: + largestMaxExecTime = metric.maxSingleTime + + if metric.totalExecTime > largestExecTime: + largestExecTime = metric.totalExecTime + + result[newSeq[string]()] = @[ + Metric( + name: "largest_total_exec_time", + value: largestExecTime.nanoseconds.float64, + timestamp: now, + ), + Metric( + name: "largest_max_exec_time", + value: largestMaxExecTime.nanoseconds.float64, + timestamp: now, + ) + ] + + var profilingCollector = ProfilingCollector.newCollector( + name = "profiling", + help = "Profiling metrics", + perfSampler = getFutureSummaryMetrics + ) diff --git a/tests/codex/utils/asyncprofiler/testmetricscollector.nim b/tests/codex/utils/asyncprofiler/testmetricscollector.nim new file mode 100644 index 00000000..f5620f0e --- /dev/null +++ b/tests/codex/utils/asyncprofiler/testmetricscollector.nim @@ -0,0 +1,66 @@ +import std/unittest + +import pkg/metrics + +import codex/utils/asyncprofiler + +import ../../helpers + +checksuite "asyncprofiler metrics collector": + + var locations = @[ + SrcLoc(procedure: "start", file: "discovery.nim", line: 174), + SrcLoc(procedure: "start", file: "discovery.nim", line: 192), + SrcLoc(procedure: "query", file: "manager.nim", line: 323), + SrcLoc(procedure: "update", file: "sqliteds.nim", line: 107), + ] + + let sample = { + (addr locations[0]): OverallMetrics( + totalExecTime: 90062.nanoseconds, + totalRunTime: 113553.nanoseconds, + totalWallTime: 174567.nanoseconds, + minSingleTime: 80062.nanoseconds, + maxSingleTime: 80062.nanoseconds, + count: 1 + ), + (addr locations[1]): OverallMetrics( + totalExecTime: 91660.nanoseconds, + totalRunTime: 71660.nanoseconds, + totalWallTime: 72941.nanoseconds, + minSingleTime: 71660.nanoseconds, + maxSingleTime: 81660.nanoseconds, + count: 1 + ), + (addr locations[2]): OverallMetrics( + totalExecTime: 60529.nanoseconds, + totalRunTime: 60529.nanoseconds, + totalWallTime: 60784.nanoseconds, + minSingleTime: 60529.nanoseconds, + maxSingleTime: 60529.nanoseconds, + count: 1 + ), + (addr locations[3]): OverallMetrics( + totalExecTime: 60145.nanoseconds, + totalRunTime: 156214.nanoseconds, + totalWallTime: 60813.nanoseconds, + minSingleTime: 5333.nanoseconds, + maxSingleTime: 41257.nanoseconds, + count: 3 + ), + }.toTable + + test "should keep track of basic worst-case exec time stats": + var registry = newRegistry() + var collector = ProfilingCollector.newCollector( + name = "profiling_metrics", + help = "Metrics from the profiler", + registry = registry, perfSampler = proc (): MetricsSummary = sample + ) + + check collector.valueByName("largest_total_exec_time") == 91660 + check collector.valueByName("largest_max_exec_time") == 81660 + + + +