Skip to content

Thread filter optim #238

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 8 commits into
base: main
Choose a base branch
from
Draft

Thread filter optim #238

wants to merge 8 commits into from

Conversation

r1viollet
Copy link
Collaborator

@r1viollet r1viollet commented Jul 7, 2025

What does this PR do?:

  • Reserve padded slots
  • Introduce a register / unregister to retrieve slots
  • manage a free list

Motivation:

Improve throughput of applications that run on many threads with many context updates.

Additional Notes:

How to test the change?:

For Datadog employees:

  • If this PR touches code that signs or publishes builds or packages, or handles
    credentials of any kind, I've requested a review from @DataDog/security-design-and-guidance.
  • This PR doesn't touch any of that.
  • JIRA: [JIRA-XXXX]

Unsure? Have a question? Request a review!

Copy link

github-actions bot commented Jul 7, 2025

🔧 Report generated by pr-comment-cppcheck

CppCheck Report

Errors (2)

Warnings (8)

Style Violations (306)

Copy link

github-actions bot commented Jul 7, 2025

🔧 Report generated by pr-comment-scanbuild

@r1viollet r1viollet force-pushed the r1viollet/thread_filter_squash branch 3 times, most recently from e5bce28 to 0918008 Compare July 7, 2025 11:45
@r1viollet
Copy link
Collaborator Author

I have reasonable performance on most runs:

Benchmark                                                       (command)  (skipResults)  (workload)  Mode  Cnt    Score   Error  Units
ThreadFilterBenchmark.threadFilterStress01  cpu=100us,wall=100us,filter=1           true           0  avgt         0.039          us/op
ThreadFilterBenchmark.threadFilterStress01  cpu=100us,wall=100us,filter=1           true           7  avgt         0.041          us/op
ThreadFilterBenchmark.threadFilterStress01  cpu=100us,wall=100us,filter=1           true       70000  avgt       111.094          us/op
ThreadFilterBenchmark.threadFilterStress02  cpu=100us,wall=100us,filter=1           true           0  avgt         0.132          us/op
ThreadFilterBenchmark.threadFilterStress02  cpu=100us,wall=100us,filter=1           true           7  avgt         0.139          us/op
ThreadFilterBenchmark.threadFilterStress02  cpu=100us,wall=100us,filter=1           true       70000  avgt       108.666          us/op
ThreadFilterBenchmark.threadFilterStress04  cpu=100us,wall=100us,filter=1           true           0  avgt         0.258          us/op
ThreadFilterBenchmark.threadFilterStress04  cpu=100us,wall=100us,filter=1           true           7  avgt         0.278          us/op
ThreadFilterBenchmark.threadFilterStress04  cpu=100us,wall=100us,filter=1           true       70000  avgt       118.940          us/op
ThreadFilterBenchmark.threadFilterStress08  cpu=100us,wall=100us,filter=1           true           0  avgt         0.624          us/op
ThreadFilterBenchmark.threadFilterStress08  cpu=100us,wall=100us,filter=1           true           7  avgt         0.646          us/op
ThreadFilterBenchmark.threadFilterStress08  cpu=100us,wall=100us,filter=1           true       70000  avgt       160.170          us/op
ThreadFilterBenchmark.threadFilterStress16  cpu=100us,wall=100us,filter=1           true           0  avgt         1.780          us/op
ThreadFilterBenchmark.threadFilterStress16  cpu=100us,wall=100us,filter=1           true           7  avgt         2.288          us/op
ThreadFilterBenchmark.threadFilterStress16  cpu=100us,wall=100us,filter=1           true       70000  avgt       221.987          us/op

I'm not sure why some runs still blow up for higher numbers of threads.

@r1viollet r1viollet mentioned this pull request Jul 7, 2025
3 tasks
@jbachorik jbachorik force-pushed the r1viollet/thread_filter_squash branch 2 times, most recently from e0ac246 to 2421ba9 Compare July 10, 2025 12:48
@r1viollet
Copy link
Collaborator Author

r1viollet commented Jul 10, 2025

CppCheck Report

Errors (2)

Warnings (8)

Style Violations (306)

@jbachorik jbachorik force-pushed the r1viollet/thread_filter_squash branch from 2421ba9 to 50a8d5f Compare July 21, 2025 14:57
@jbachorik
Copy link
Collaborator

I did run some comparison of native memory usage with different thread filter implementations - data is in the notebook

TL;DR there is no observable increase in the native memory usage (the UNDEFINED category). Anyway, it would be useful to have an extra counter for the ThreadIDTable utilization.

jbachorik and others added 3 commits July 24, 2025 21:43
If the TLS cleanup fires before the JVMTI hook, we want to
ensure that we don't crash while retrieving the ProfiledThread
- Add a check on validity of ProfiledThread

// Allocate a new slot
SlotID index = _next_index.fetch_add(1, std::memory_order_relaxed);
if (index >= kMaxThreads) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if it is important, but it can race unregisterThread, you may want to check return value of fetch_sub to determinate if it is really full.


_enabled = true;
// Ensure the chunk is initialized (lock-free)
if (chunk_idx >= _num_chunks.load(std::memory_order_acquire)) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't quite understand, are index and chunk_idx 1-to-1 matched?

ChunkStorage* expected = nullptr;
if (_chunks[chunk_idx].compare_exchange_strong(expected, new_chunk, std::memory_order_acq_rel)) {
// Successfully installed - initialize all slots
for (auto& slot : new_chunk->slots) {
Copy link
Contributor

@zhengyu123 zhengyu123 Aug 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe that initializing new_chunk can be done before compare_exchange_strong. Then you don't need initialized flag, which can result an awkward situation, e.g. you found chunk, but it is not initialized.

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.

3 participants