Skip to content

perf(cli): skip the forced info reads when the invocation performs an action - #549

Open
AdrianKuriata wants to merge 3 commits into
Sapd:masterfrom
AdrianKuriata:skip-info-reads-on-action
Open

perf(cli): skip the forced info reads when the invocation performs an action#549
AdrianKuriata wants to merge 3 commits into
Sapd:masterfrom
AdrianKuriata:skip-info-reads-on-action

Conversation

@AdrianKuriata

@AdrianKuriata AdrianKuriata commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Structured output (json/yaml/env) marks every info capability as requested, no
matter what the command line actually asked for. On a device with an expensive
status read that dominates an action which is otherwise instant.

Audeze Maxwell 2 (0x3329:0x4b28), release build:

headsetcontrol -d 0x3329:0x4b28 -s 20                 0.07 s
headsetcontrol -d 0x3329:0x4b28 -s 20 --output=json   2.90 s

The difference is the status read - getDeviceStatus() sends 15 init packets plus
6 status requests, each after a 60 ms delay. The sidetone write itself is one
packet. Anything driving the CLI per user interaction pays that every time; a GUI
moving a slider ends up queueing writes for minutes.

After the patch the same call takes 0.07 s and the actions array is unchanged. A
pure query is unaffected: --output json still takes 2.83 s and still reports
battery and chatmix. Info asked for explicitly still works, -b -s 20 -o json
reports the battery in 1.49 s.

headsetcontrol_tests passes.

One thing to decide: this changes the json shape for action invocations,
devices[].battery is no longer there when you only asked to set something. I think
the old behaviour is the bug, but if you would rather keep the default I can put
it behind a flag instead.

Structured output marks every info capability as requested, even when the command
line only asked to set a value. On an Audeze Maxwell 2 that turns a 0.07 s write
into 2.90 s, because the status read sends 21 packets at 60 ms intervals.

Explicitly requested info still works, -b -s 20 -o json reports the battery.
@AdrianKuriata
AdrianKuriata force-pushed the skip-info-reads-on-action branch from eb86c8f to 5941ecf Compare July 29, 2026 14:32
@Sapd

Sapd commented Jul 30, 2026

Copy link
Copy Markdown
Owner

Thanks, the numbers speak for themselves here. I agree the old behaviour is the bug, so no flag please, keep it as the default.

Two things before this can go in.

The output shape changes, so please bump API_VERSION in cli/output/output.cpp to 1.5. Thats what it is there for, otherwise a consumer has no way to notice.

And enableExtendedInfoRequests runs before handleMultiDeviceActions, so hasRequestedAction looks at action requests that get neutralized one line later. It also checks all devices at once, so one device with an action switches off the info reads of another device that never had one. Please move the call after handleMultiDeviceActions and do the check per device instead of globally.

Also worth writing into the PR text: it does not only drop info when you set something, it drops everything you did not explicitly ask for. With -b -s 20 -o json you now get battery but no chatmix, master returned both. Fine by me, but people will notice.

Not caused by you, I just saw it while reading this: the multiple devices guard in handleMultiDeviceActions does not actually do anything. It sets result.message and value but leaves should_process true, and status was already NotProcessed, so processFeatureRequests runs the action anyway. I will fix that separately. It is also why the ordering above matters, once that guard works your version would return neither the action nor the info.

Review feedback on three points.

enableExtendedInfoRequests ran before handleMultiDeviceActions, so it judged
action requests that were neutralized one line later. It now runs after, and
the ordering is spelled out at the call site so it does not get swapped back.

hasRequestedAction looked at every device at once, so an action on one headset
switched off the info reads of another that never had one. It now takes a
single device and the caller skips per device.

The output shape changes, so API_VERSION goes to 1.5. Updated the sample
response in docs/LIBRARY_USAGE.md to match.
@AdrianKuriata

Copy link
Copy Markdown
Contributor Author

All three done in b899244.

handleMultiDeviceActions now runs first and enableExtendedInfoRequests after it, so the check sees action requests as they actually stand rather than as they were parsed. I left a comment at the call site saying why the order is what it is, otherwise it is the kind of thing that gets swapped back.

hasRequestedAction takes a single device now and the caller skips per device, so an action on one headset no longer silences the info reads of another.

API_VERSION is 1.5. I also updated the sample response in docs/LIBRARY_USAGE.md, it had the old number in it.

On the shape change you asked me to write down: it is broader than the title suggests, an invocation that sets something now reports only the info you named. -b -s 20 -o json gives you battery and no chatmix where master gave both. I have not edited the PR description, so this comment is where that note lives.

Checked on the test device: -s 20 -o json returns the actions array and no battery or chatmix, -o json still returns both, -b -s 20 -o json returns battery only. With a filter and two devices the non-matching device is not emitted at all, so the per-device check does not leak unprocessed info entries into the output. make check passes, 2/2.

Two caveats. I could not run clang-format, there is no clang-format 18 on this machine, so formatting is by hand and CI is the first real check on it. And the broken multi-device guard is the one path I cannot exercise here, since I only have one test device plus one real headset. Once your separate fix lands and should_process actually goes false, this version enables the info reads for that device, which I believe is what you wanted, but I have not seen it run.

cpp-linter checks whole files, not changed lines, and cli/main.cpp and
cli/output/output.cpp both carry formatting violations that predate this PR.
They are not reachable from master's own CI, which only runs clang-format on
pull requests, so they went unnoticed.

clang-format 18.1.3 output, nothing hand-written.
@AdrianKuriata

Copy link
Copy Markdown
Contributor Author

Correction to my last comment: I said I had no clang-format 18. I got 18.1.3 afterwards, the same version CI installs, and ran it. cpp-linter passes now.

One extra commit, 43a4a07, and it is not mine in substance. The workflow runs with lines-changed-only: false, so it checks the whole of every file a PR touches, and both files this PR touches were already non-conforming: cli/main.cpp at lines 37, 423 and 1006, cli/output/output.cpp at line 184. None of them are in this PR's diff. The commit is clang-format 18.1.3 output, nothing hand-written, and I kept it separate so you can see the review fixes and the formatting apart. Say the word if you would rather have it out and handled on its own.

@AdrianKuriata
AdrianKuriata force-pushed the skip-info-reads-on-action branch from 43a4a07 to ab84bf1 Compare August 14, 2026 12:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants