Skip to content

Commit 7276e5e

Browse files
feat: Add per-backend execution timing instrumentation (issue #56) (#57)
* feat: Add per-backend execution timing instrumentation (issue #56) This change adds execution timing to backend results to improve visibility into backend performance. This makes it easier to identify slow backends, diagnose performance regressions, and validate caching optimizations. Changes: - Added execution_time_ms field to BackendResult model - Implemented timing tracking at dispatcher level using perf_counter - Display timing in verbose CLI output (e.g., "1567.84ms") - Timing included in JSON output format - All existing tests pass (239 tests) Part of epic #52 - Performance: Optimize caching to eliminate redundant API calls [AI-assisted] * fix: Use actual backend response_time instead of wall-clock time The previous implementation measured wall-clock time from task start to finish, which showed similar times for all backends (~1.3s) because they run concurrently. This was not useful for identifying slow backends. Now using the existing response_time field (which each backend already tracks internally) and converting it to milliseconds. This shows the actual work time for each backend: - Fast cached backends: 0-85ms - Slow backends with API calls: 275-1641ms This correctly identifies which backends are actually slow vs fast. [AI-assisted] --------- Co-authored-by: florath-ai-assistant[bot] <Andreas.Florath@telekom.de>
1 parent e004552 commit 7276e5e

File tree

3 files changed

+30
-3
lines changed

3 files changed

+30
-3
lines changed

src/aletheia_probe/cli.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -393,8 +393,11 @@ async def _async_assess_publication(
393393
)
394394
)
395395
cache_indicator = " [cached]" if backend_result.cached else ""
396+
timing_info = ""
397+
if backend_result.execution_time_ms is not None:
398+
timing_info = f" ({backend_result.execution_time_ms:.2f}ms)"
396399
print(
397-
f" {status_emoji} {backend_result.backend_name}: {backend_result.status}{cache_indicator}"
400+
f" {status_emoji} {backend_result.backend_name}: {backend_result.status}{cache_indicator}{timing_info}"
398401
)
399402
if backend_result.assessment:
400403
print(

src/aletheia_probe/dispatcher.py

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,9 +173,9 @@ async def _query_backends(
173173
backend_config = self.config_manager.get_backend_config(backend_name)
174174
timeout = backend_config.timeout if backend_config else 15
175175

176-
# Create task with timeout
176+
# Create task with timeout and timing wrapper
177177
task = asyncio.create_task(
178-
backend.query_with_timeout(query_input, timeout),
178+
self._query_backend_with_timing(backend, query_input, timeout),
179179
name=f"backend_{backend_name}",
180180
)
181181
tasks.append((backend_name, task))
@@ -232,6 +232,27 @@ async def _query_backends(
232232

233233
return backend_results
234234

235+
async def _query_backend_with_timing(
236+
self, backend: Backend, query_input: QueryInput, timeout: int
237+
) -> BackendResult:
238+
"""Query a backend and add execution timing information.
239+
240+
Args:
241+
backend: The backend to query
242+
query_input: The query input
243+
timeout: Timeout in seconds
244+
245+
Returns:
246+
BackendResult with execution_time_ms populated
247+
"""
248+
result = await backend.query_with_timeout(query_input, timeout)
249+
250+
# Convert response_time (seconds) to execution_time_ms (milliseconds)
251+
# response_time already contains the actual backend execution time
252+
result_dict = result.model_dump()
253+
result_dict["execution_time_ms"] = result.response_time * 1000
254+
return BackendResult(**result_dict)
255+
235256
def _calculate_assessment(
236257
self,
237258
query_input: QueryInput,

src/aletheia_probe/models.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ class BackendResult(BaseModel):
5252
)
5353
response_time: float = Field(..., description="Query response time in seconds")
5454
cached: bool = Field(False, description="Whether result was retrieved from cache")
55+
execution_time_ms: float | None = Field(
56+
None, description="Backend execution time in milliseconds"
57+
)
5558

5659

5760
class JournalMetadata(BaseModel):

0 commit comments

Comments
 (0)