Commit b69f4d5
authored
Optimize JavaLineProfiler.instrument_function
Runtime improvement: the optimized version runs ~25% faster (2.06 ms -> 1.64 ms), with larger wins on functions with many instrumentable lines.
What changed
- Precompute file_path.as_posix() once per function: file_posix = file_path.as_posix() and reuse it for content_key and the profiled f-string instead of calling file_path.as_posix() repeatedly inside the loop.
- Combined multiple startswith checks into a single startswith(("//", "/*", "*")) call to replace three separate str.startswith() calls.
Why this speeds things up
- Attribute lookups and small method calls are relatively expensive in Python. In the original code file_path.as_posix() was called twice for every instrumented line (once for content_key and once inside the profiled f-string). Moving that result into a local variable removes those repeated method calls and attribute lookups and replaces them with a fast local variable load.
- Multiple str.startswith() calls were replaced by one startswith(tuple) call, cutting the number of Python-level function calls and condition checks for candidate comment lines.
- These savings multiply with the number of lines inside a function. The loop is the hot path: each instrumented statement previously did several extra method calls and string operations; removing them reduces per-line overhead and thus the total runtime.
Observed evidence
- Line-profiling shows heavy time spent on the two expressions that used file_path.as_posix() repeatedly; those costs drop in the optimized profile.
- The annotated tests show the biggest improvements on the large-scale test (many lines), which matches the expectation that per-line micro-optimizations are most beneficial when the loop has many iterations.
Behavioral impact and trade-offs
- No functional change: the instrumented output and semantics are unchanged.
- A tiny upfront cost (computing file_posix once) is paid even if no lines are instrumented, but that's negligible and worth the per-line savings.
- The exception path (logger.warning) shows a larger percent of the shorter total time in the optimized profile — this is not a regression in practice, just a profiling artifact because the overall runtime decreased; exception handling remains unchanged.
When this matters most
- Hot paths that instrument long functions or many functions (the large-scale test) gain the most.
- Small functions still benefit (the overall runtime measured improved), but the relative improvement is smaller because fixed costs (parse, etc.) dominate.
Summary
Precomputing file_posix and reducing redundant startswith/attribute calls cut down repeated Python-level work inside the main loop. That directly lowers per-line overhead and yields the measured ~25% runtime improvement, especially on workloads with many instrumentable lines.1 parent 96e231e commit b69f4d5
1 file changed
Lines changed: 5 additions & 7 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
353 | 353 | | |
354 | 354 | | |
355 | 355 | | |
| 356 | + | |
| 357 | + | |
356 | 358 | | |
357 | 359 | | |
358 | 360 | | |
| |||
377 | 379 | | |
378 | 380 | | |
379 | 381 | | |
380 | | - | |
381 | | - | |
382 | | - | |
| 382 | + | |
383 | 383 | | |
384 | 384 | | |
385 | 385 | | |
386 | 386 | | |
387 | 387 | | |
388 | 388 | | |
389 | 389 | | |
390 | | - | |
| 390 | + | |
391 | 391 | | |
392 | 392 | | |
393 | 393 | | |
394 | | - | |
395 | | - | |
396 | | - | |
| 394 | + | |
397 | 395 | | |
398 | 396 | | |
399 | 397 | | |
| |||
0 commit comments