Skip to content
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

WIP: Modified JEventProcessorPODIO::Process to acquire lock only when need… #1531

Draft
wants to merge 2 commits into
base: pr/JEventProcessorPODIO_avoid_fixing_collections
Choose a base branch
from

Conversation

RaiqaRasool
Copy link

Briefly, what does this PR introduce?

This PR introduces changes to the JEventProcessorPODIO::Process to limit the scope of locks, enabling the use of JANA's parallelism and improving the performance by avoiding unnecessary serialization of events.

What kind of change does this PR introduce?

  • Bug fix (issue #__)
  • New feature (issue #__)
  • Documentation update
  • Other: __

Does this PR introduce breaking changes? What changes might users need to make to their code?

No, this PR does not introduce breaking changes. Users do not need to make any changes to their existing code.

Does this PR change default behavior?

Yes, the PR changes the default behavior by enabling JANA's parallelism through the use of std::unique_lock with std::defer_lock, allowing sections of the code to run in parallel rather than in sequence. The main change is the introduction of std::unique_lock with std::defer_lock to manage the mutex locking more precisely, allowing for better parallelism by unlocking the mutex during non-critical sections of the code.

Copy link

sonarcloud bot commented Jul 22, 2024

Copy link

sonarcloud bot commented Jul 22, 2024

Please retry analysis of this Pull-Request directly on SonarCloud

@veprbl veprbl requested review from wdconinc and nathanwbrei and removed request for wdconinc July 22, 2024 16:18
Copy link
Contributor

@wdconinc wdconinc left a comment

Choose a reason for hiding this comment

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

Was that all that was needed? In transit but I thought it wasn't that easy...

Comment on lines +375 to +380
lock.lock();
if (m_is_first_event) {
FindCollectionsToWrite(event);
m_is_first_event = false;
}
lock.unlock();
Copy link
Contributor

@wdconinc wdconinc Jul 22, 2024

Choose a reason for hiding this comment

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

If I understand correctly (m_is_first_event monotonically changing from true to false), the lock can be inside the if, avoiding a lock/unlock after the first event. I'd want to avoid an unnecessary lock since it potentially introduces a wait for the write operation.

The (new) race condition to avoid then is m_is_first_event changing from true to false while the condition is evaluated, so we'd have to do a second locked if inside the unlocked if, but it would virtually never be used.

Copy link
Contributor

Choose a reason for hiding this comment

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

You're describing the ABA problem. I think std::call_once is the tool for this purpose. (Just make sure that any code inside call_once is exception free because we've been bitten by bad standard library implementations before)

Copy link
Contributor

Choose a reason for hiding this comment

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

any code inside call_once is exception free

The code inside is an entire event processing in EICrecon :=)

Copy link
Contributor

Choose a reason for hiding this comment

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

Explanation of double-checked locking and ABA problem for anyone who is interested: https://en.wikipedia.org/wiki/Double-checked_locking#Motivation_and_original_pattern

However, this is an optimization detail that I would avoid for now in favor of the simple, obvious solution. We'd like to verify:

  • Consistent results in the output file
  • A sensible cores vs throughput curve
  • No data races uncovered by valgrind/tsan/whatever

Copy link
Contributor

Choose a reason for hiding this comment

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

any code inside call_once is exception free

The code inside is an entire event processing in EICrecon :=)

Nope, just FindCollectionsToWrite() thankfully :)

Copy link
Contributor

Choose a reason for hiding this comment

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

Ok, I see. At some point this ran through the whole first event to figure out which output names were activated, right? Or do I remember that wrong?

Copy link
Contributor

Choose a reason for hiding this comment

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

It did some wild things in the past for sure. Right now it just returns all available collection names (ignoring whether the corresponding factories have been run or not) and applies inclusions and exclusions.

@nathanwbrei
Copy link
Contributor

Was that all that was needed? In transit but I thought it wasn't that easy...

The goal is to find out. I'm also resuscitating #1069 as part of this effort.

@nathanwbrei nathanwbrei marked this pull request as draft July 22, 2024 18:59
@nathanwbrei nathanwbrei changed the title Modified JEventProcessorPODIO::Process to acquire lock only when need… WIP: Modified JEventProcessorPODIO::Process to acquire lock only when need… Jul 22, 2024
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