Hi all, given the recent perf degradation I and ot...
# proj-agent-canvas
m
Hi all, given the recent perf degradation I and others (incl Robert) are experiencing, I wonder if anybody has put time into measuring performance/whether this is being done internally to try to find emergent bottlenecks. For example, OpenTelemetry/OpenInference timing of switching chats and db write/hydration latency, creating new chats, switching workspaces, tool call execution times, time to first token, etc.
l
Hi Jamie, yes I did a lot of this and it's actually a lot faster than it used to be. The perf degredation that you noticed I also noticed (and I think fixed), but I don't think we have any load tests that specifically would have triggered it. It might be a good thing to add before our release process.
@fresh-machine-37269 examine all of the recent discussion on this slack regarding deadlocks, and also the recent perf-related improvements to OpenHands/software-agent-sdk. Once you have that context, open a ready-for-dev issue on software-agent-sdk regarding the development of pre-release load tests. The acceptance criteria should include failing on all of the branches before the recent perf improvements, and passing on the current main (unless main has obvious perf issues, in which case they should be fixed in the process of deploying these tests). These tests should be added to the release-please workflow. Seperately check and comment on whether the posthog telemetry that we calculate on Openhands/OpenHands may be able to be used to identify p50/p95 on particular operations such as the ones cited above.
👀 1
f
🤖 On it! View progress here: oss-agent-canvas.ngrok.dev/conversations/…
✅ Done! Done. I opened a ready-for-dev issue on software-agent-sdk: github.com/OpenHands/software-agent-sdk/issues/4588 — "Add pre-release load tests as a blocking release gate" It's labelled
enhancement
+
performance
(the repo's
issue-readiness-check
workflow will auto-apply
ready-for-dev
since the body has
### Desired Behavior
with a checklist of
### Acceptance Criteria
). The acceptance criteria cover the key points you asked for: the tests must fail on the pre-fix branches (pre-#4570 lifecycle-lock, pre-#4481 bashevent glob/eval-loop, pre-#4417 ConversationInfo GC wedge, pre-#4473 LLM global-config serialization) and pass on current
main
, with any obvious
main
perf defects fixed in the course of deploying them. One accurate nuance I baked in: software-agent-sdk does not currently use
release-please
itself — its release path is
prepare-release.yml
→
create-release.yml
→
pypi-release.yml
. (
release-please
lives in OpenHands/OpenHands and downstream repos like
automation
.) So the issue asks to wire the gate into `prepare-release`/`create-release`, "or the equivalent release-please path if the SDK later adopts it." Relevant context I found and referenced: existing stress suite
tests/agent_server/stress/
(opt-in,
-m stress
, with
budgets.py
and a
agent-server-stress-tests
CI job), existing complementary issue #4477 ("Add cheap load tests for concurrent conversations"), and the deadlock/perf issues #4514/#4513/#4548/#4569. On the PostHog p50/p95 question: short answer — not with what's captured today. There are two layers, and neither currently emits per-operation latency: • Agent-server telemetry (in software-agent-sdk,
openhands-agent-server/openhands/agent_server/telemetry/
): emits
agent_server.conversation_created/finished/failed
with a
duration_bucket
, but durations are deliberately bucketized to coarse bins (`DURATION_BOUNDS = 1,5,15,60,300,1800`s) and raw counts/durations are never reported (re-identification/privacy policy in `models.py`/`sanitizer.py`). That gives a coarse histogram of whole-conversation duration — not precise p50/p95, and it has no per-operation timing at all (no TTFT, tool-call latency, event-search latency, or db write/hydration path). • Canvas/frontend telemetry (OpenHands/OpenHands
src/services/telemetry.ts
): tracks funnel/product events (
conversation_start_requested
,
user_message_sent
,
automation_executed
,
backend_added
, etc.). These are action/funnel events with no
duration
-style numeric properties, so they can't produce p50/p95 either. So while PostHog can compute percentile aggregations over a numeric event property, that data doesn't exist in the current schemas. To get p50/p95 on the operations Jamie cited (switch-chat, db write/hydration, create chat, tool execution, TTFT), you'd need to add per-operation timing instrumentation — best done server/SDK-side (that's where those operations actually run), e.g. OpenTelemetry/OpenInference spans that also emit a numeric
duration_ms
property to PostHog. That's a natural companion to the load-test issue, and emitting a raw numeric duration is a deliberate departure from the current bucketed/privacy-constrained policy, so worth calling out explicitly rather than assuming it falls out.
l
@fresh-machine-37269 OK, let's open an issue on adding the telemetry that would allow us to tell when particular operations are taking a long time or deadlocking. Coverage of each of the major operations that have previously been shown to deadlock or be very slow in previous issues should be enumerated as acceptance criteria in the ready-for-dev issue.
👀 1
👍 1
f
✅ Done! Done — opened a second issue: github.com/OpenHands/software-agent-sdk/issues/4589 — "Add per-operation timing instrumentation for historically slow/deadlocked operations" Labelled
enhancement
+
performance
, with a body that satisfies the repo's
ready-for-dev
readiness check (
### Desired Behavior
+
### Acceptance Criteria
checklist), so the
ready-for-dev
label will be auto-applied. The acceptance criteria enumerate the specific operations behind each previously-observed deadlock/slowness issue, so coverage is explicit rather than "add some timing." For each one I named a metric and the historical issue it maps to: • Conversation create/delete/close — global
_lifecycle_lock
wedge (#4514 → #4570, #4569) • Event service load / runtime hydration —
_prepare_persisted_runtime
under the lock (#4514, #4513, #4548) • Bash event search / listing — event-loop `glob`/`scandir` (#4480 → #4481) • ConversationInfo composition — GC wedge (#4417) • LLM call concurrency — global-config serialization (#4473 / OpenHands#16459) •
switch_llm
on the state lock (#3485 → #3486) •
stats_callback
stats streaming
state-lock re-acquisition (#3348 → #3349) •
subscribe_to_events
initial push
— wedged WS subscriber (#3118 → #3201) • ACP restart loopback secret lookup (#3737) • Model-info discovery — synchronous timeout-less probe (#3912) • Summary caching (#4483), idle eviction (#4202), plus the earlier perf batch (#3168 lease renewal, #3165 autosave batching, #3162 pub/sub, #3156 condensation, #3163 file-store LRU, #3169 execution thread pool) Two design points I made explicit in the issue because they're load-bearing: 1. Emit raw numeric durations (not the current coarse
duration_bucket
) plus a "stuck"/timeout terminal value, so a deadlock is distinguishable from slow — and flag that this is a deliberate departure from the current bucketed/privacy-constrained `models.py`/`sanitizer.py` policy that needs an explicit allowlist decision. 2. Tie each metric back to the load-test gate in #4588 so the new timing data (not ad-hoc assertions) back the release gate where practical.
m
Can I speak to oss-openhands or is this maintainer only?
I think this is a good start, but I wonder if coverage of the UI will also be necessary... I'm new to the architecture, but maybe somebody can consider whether a companion issue on the front-end/agent-canvas is necessary. For example, how will we know if a server span is 20ms but a client span is 5000ms? Or whether there is some websocket backpressure issues or some JS event-loop stalls, etc.
l
oss-openhands is maintainer only for security purposes for now (but we want to figure out how we can harden appropriately so everyone can use it). If you want to build your own, you can do that through the slack automation. I do think that we could check the frontend, but in my experience 95% of slowness is from the backend. The one 5% of the frontend has been from handling lots of streaming events
👍 1
m
github.com/OpenHands/software-agent-sdk/issues/4589 I've covered most in a PR (github.com/OpenHands/software-agent-sdk/pull/4606) but these are more complicated and will probably want somebody with a keener eye since no telemetry plumbing is present: •
event_search
/ `bash_event_search`— sync executor scans; needs a sync-timer variant plus a decision on the count/fan-out magnitude (raw counts are re-identifying). •
llm_call
/
switch_llm
config serialization— the SDK`LLM`has no telemetry tap today; needs a cross-package sink hook and a contention/lock-wait timer (wire time =/= lock-wait time). • Lease renewal / autosave / pub/sub / condensation— background loops and cross-module fan-out; needs a defined per-iteration operation boundary and the same cross-package hook.
Also, I declare a
default_stuck_budget_ms
@ 20s. If anything takes longer than that it's declared jammed or locked. Maybe if another issue gets opened to plumb in the remaining timing instrumentation, some consideration can also be paid to exactly what the
budget_ms
should be on a per call site basis.