Fix deadlock in Optimize1qGatesDecomposition#16592
Conversation
|
One or more of the following people are relevant to this code:
|
|
I want to add another test that looks at doing a full path transpilation with each optimization level using a target involving only custom 1q and 2q gates. Just to make sure we have sufficient coverage of this path moving forward. I didn't have enough time to do it tonight, but if someone is feeling inspired they can feel free to push it up to my PR branch. Otherwise I'll circle back to it later. |
jakelishman
left a comment
There was a problem hiding this comment.
Without having looked in any detail, a couple of questions:
- For a backport, this looks like a very invasive change to a core pass. Is this smaller than it looks? Very approximately: is it possible to factor the
process_runclosure out in one commit, then do the other changes in a second, if not only for review ease to separate "code movement" from "code change" logic for the backport? - Is the backport going to be a nuisance, given this PR just rebased/merged in a non-backportable change?
Functionally I'm not sure how reducible it will be. The crux of the issue is we need a Python-only path that is GIL aware and can manage the detach for only the parallel portion which requires some re-organization, both to explicitly split Python path from the non-Python path, and then also split the parallel and serial parts. I tried to minimize the code migration which resulted in a bit more duplication than is strictly necessary (thinking mostly the serial path). That being said with #[pyfunction]
pub fn py_run_pass(py, ...) {
py.detach(|| {
run_pass()
})
}
pub fn run_pass() {...}but given the panic bug we had in 2.4 I'm not 100% confident in doing that here, especially for a backport fix. That seems riskier to me, especially since we have places that can still do I can split this up into two PRs if you want, it realistically won't make the annoying to code movement part any easier to review. The second change that fixes the bug would be basically what I outlined above as the "minimal" riskier change once the reorg is done.
I'm not worried about the backport mechanics. The rebase diff for that changes was just: - let sequence = unitary_to_gate_sequence_inner(
- aview2(&operator),
- target_basis_set,
- qubit.index(),
- None,
- true,
- None,
- );
- let Some(sequence) = sequence else {
+ let Some((sequence, new_error)) = resynthesize_run_min_error(aview2(&operator), target_basis_set, qubit, target) else {
+ return Ok(None);
+ };
- let new_error = compute_error_from_target_one_qubit_sequence(&sequence, qubit, target);
+so reversing that it will apply cleanly on |
|
Oh yeah, I wasn't meaning we need 2 PRs necessarily. The point of splitting wasn't to make the code motion easier to review, it was to make the bit that actually changes the logic easier to review, because at the moment it's harder to pick that out of the diff. That's based on assumption that this was done by a simple move of the For backport: that's good, thanks. |
54c99e6 to
d3b45de
Compare
|
I split out the process_runs code move into #16595 as suggested. The diff for this PR becomes just this now: mtreinish/qiskit-core@split-out-process-runs...mtreinish:qiskit-core:fix-deadlock-o1qgd I've marked this as on hold until #16595 merges. |
…skit#16595) This commit splits out the internal closure `process_runs` that is internally used by the Optimize1qGatesDecomposition pass to process and synthesize a 1q run found in the circuit. This is just a mechanical change that is setting the stage for fixing the deadlock reported in issue Qiskit#16591 that is being fixed by Qiskit#16592. This change was originally part of Qiskit#16592 but was split out to make the logic change made in Qiskit#16592 more clear. This is just the mechanical pre-work needed for that, however while not strictly a fix this PR will need to backported to also backport Qiskit#16592.
This commit fixes an oversight in the new multithreaded Optimize1qGatesDecomposition pass introduced in Qiskit#15667 that could cause a deadlock with the Python GIL when using custom 1q gates. If there are custom gates defined in Python then we need Python to get the matrix of that custom gate. However, when running in a multithreaded context Python only allows one thread to interact with the interpreter at a time via the GIL. When operating in parallel the pass was not releasing the GIL from the parent thread running the pass. This meant that the children threads would wait to acquire the GIL to call Python but never be able to get the lock because the parent thread that spawned it never released the GIL. This commit fixes that issue by adding a dedicate entrypoint for calling the pass via Python and having that entrypoint release the GIL prior to launching an parallel threads. It then reacquires the GIL before modifying the output DAG which might need Python for working with the custom gates. This mirrors the pattern used in the other parallel passes that work in a similar way such as `UnitarySynthesis` and `TwoQubitPeepholeOptimization`. Fixes Qiskit#16591
d3b45de to
aa34625
Compare
|
Now that #16595 has merged I've rebased this on main and removed the |
This commit fixes an oversight in the new multithreaded Optimize1qGatesDecomposition pass introduced in #15667 that could cause a deadlock with the Python GIL when using custom 1q gates. If there are custom gates defined in Python then we need Python to get the matrix of that custom gate. However, when running in a multithreaded context Python only allows one thread to interact with the interpreter at a time via the GIL. When operating in parallel the pass was not releasing the GIL from the parent thread running the pass. This meant that the children threads would wait to acquire the GIL to call Python but never be able to get the lock because the parent thread that spawned it never released the GIL.
This commit fixes that issue by adding a dedicate entrypoint for calling the pass via Python and having that entrypoint release the GIL prior to launching an parallel threads. It then reacquires the GIL before modifying the output DAG which might need Python for working with the custom gates. This mirrors the pattern used in the other parallel passes that work in a similar way such as
UnitarySynthesisandTwoQubitPeepholeOptimization.Fixes #16591
AI/LLM disclosure