feat(profiling): instrument executeQuery/executeUpdate paths with nanosecond step timings + 100-thread open-loop benchmark#516
Conversation
…s and open-loop benchmark test Agent-Logs-Url: https://github.com/Open-J-Proxy/ojp/sessions/d969ea6a-97b9-4001-9fa9-41d0394edf22 Co-authored-by: rrobetti <7221783+rrobetti@users.noreply.github.com>
|
@copilot print out the total (sum of all means) at the end. |
…ing report Agent-Logs-Url: https://github.com/Open-J-Proxy/ojp/sessions/fa4fda8a-b0c0-4f5d-8ccf-51f13e842448 Co-authored-by: rrobetti <7221783+rrobetti@users.noreply.github.com>
Done in 0bbae43. A |
|
@copilot discount the time spent once control is given to the jdbc driver, for example when executeQuery is called in the H2 JDBC driver, that time is not OJP time, same for when getting a connection from HikariCP or creating the statement or reading next row in a result set, all those times need to be subtracted from the measurements. |
…w OJP-only overhead Agent-Logs-Url: https://github.com/Open-J-Proxy/ojp/sessions/ae46c7a0-3adb-4253-8466-cbd9526738bf Co-authored-by: rrobetti <7221783+rrobetti@users.noreply.github.com>
…ing in beginJdbcCall Agent-Logs-Url: https://github.com/Open-J-Proxy/ojp/sessions/ae46c7a0-3adb-4253-8466-cbd9526738bf Co-authored-by: rrobetti <7221783+rrobetti@users.noreply.github.com>
Done in commits 2454178 and 50e7da6. Added
All are no-ops in production (guarded by vs. the previous totals that included JDBC time (~666 µs query, ~364 µs update). The ~353 µs and ~274 µs differences are the actual H2 JDBC costs that are now discounted. Warning Firewall rules blocked me from connecting to one or more addresses (expand for details)I tried to connect to the following addresses, but was blocked by firewall rules:
If you need me to access, download, or install something from one of these locations, you can either:
|
|
@copilot merge main branch into this branch, add measurement steps if required. Document which main branch commit this branch is up to date with for future reference. |
…tation-for-query-paths Co-authored-by: rrobetti <7221783+rrobetti@users.noreply.github.com>
…it; verify new SessionConnectionHelper paths retain JDBC exclusion Agent-Logs-Url: https://github.com/Open-J-Proxy/ojp/sessions/b7032520-e5f1-4616-9ed0-df63436dd35e Co-authored-by: rrobetti <7221783+rrobetti@users.noreply.github.com>
|
Done in commit 595edb8. Main merged cleanly (no conflicts). The auto-merge correctly preserved all JDBC exclusion wrappers in
The benchmark test javadoc documents the sync point: main commit |
|
@copilot run the test again and plot the new results here. |
Results from a fresh run (H2 in-memory, 100 concurrent threads, OJP overhead only — JDBC time excluded): Key takeaways:
|



Assessment-only instrumentation to identify latency bottlenecks across the
executeQueryandexecuteUpdateserver action paths. Not intended for merge to main.Main branch sync: this branch is current with main as of commit
e59f4eb2(Merge PR #520 – throttle incoming requests, 2026-05-15).New infrastructure
ExecutionPathProfiler— per-thread recorder;mark(stepName)snapshots elapsed ns since the previous mark;excludeNs(long ns)subtracts external JDBC time from the current step windowExecutionPathProfilingContext—ThreadLocalholder;mark(),beginJdbcCall(), andendJdbcCall()are all guaranteed no-ops in production (zero allocation, zero branching cost when not activated)Instrumented steps
executeQuerysessionConnection→cacheCheck→sqlEnhancement→paramConversion→statementCreation→sqlExecution→resultSetHandlingexecuteUpdateaffinityCheck→sessionConnection→paramConversion→statementCreation→sqlExecution→buildResultJDBC time exclusion
Each step measures OJP-internal overhead only. Time spent inside JDBC driver calls is subtracted via
beginJdbcCall()/endJdbcCall()pairs placed at every JDBC boundary:SessionConnectionHelpergetMetaData().getURL(),isClosed(), HikariCP/DriverManager pool acquisitionExecuteQueryActionprepareStatement/createStatement,executeQueryExecuteUpdateActionprepareStatement/createStatement,executeUpdateResultSetHelpergetColumnCount, column label reads, URL resolution, everyrs.next()Note: the new
acquireSessionPermit()call introduced inSessionConnectionHelperby PR #520 is intentionally not excluded — it is OJP admission-control wait time, not a JDBC driver call, and should be counted as OJP overhead within thesessionConnectionstep.Benchmark test (
ExecutePathLatencyBenchmarkTest)Pre-creates 120 direct H2 sessions (no pool pressure), warms JIT with 20 sequential requests, then releases 100 threads simultaneously via
CountDownLatch(open loop). Collects per-step ns timings, computes medians, prints an ASCII bar chart with aTOTAL (sum of medians)row at the bottom.Latest results (H2 in-memory, 100 concurrent threads, OJP overhead only — JDBC time excluded)
Key findings (OJP overhead only):
executeQuerytotal: 227 µs —resultSetHandlingdominates (~129 µs, pure protoResultRowconstruction for 10 result rows).sessionConnection(~53 µs) is the second-largest cost (session map lookup).sqlExecution(~40 µs) captures only the OJP post-query work (registerResultSet + UUID generation).executeUpdatetotal: 66 µs —affinityCheck(~51 µs, regex parse) is the single largest cost. All other steps are sub-6 µs after JDBC is excluded.