-
Notifications
You must be signed in to change notification settings - Fork 16
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
loading the pulse calibrations #137
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
clang-tidy made some suggestions
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
clang-tidy made some suggestions
clang-tidy review says "All clean, LGTM! 👍" |
clang-tidy review says "All clean, LGTM! 👍" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
clang-tidy made some suggestions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is coming along really nicely.
There are a couple github checks that I've never seen before, but are good to fix.
I have a couple other general comments, which I flagged in a couple places but I think it would be good to change throughout this patch:
- Error handling in the case that the pulse cals cannot be loaded (bad path, no file, etc).
- Use of
if (condition) assert(false && "message");
. I think it is better to sink the condition into the assert. It improves readability (in my opinion) and makes things a bit easier to reason about in the case when asserts are disabled.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
clang-tidy made some suggestions
@kitbarton gentle reminder that this PR is ready for a second review |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few changes would improve things. I'm also concerned by the OwningRef release semantics.
if (pulseCalsNameToSequenceMap.find(gateMangledName) != | ||
pulseCalsNameToSequenceMap.end()) { | ||
// found a pulse calibration for the barrier gate | ||
addPulseCalToModule(funcOp, pulseCalsNameToSequenceMap[gateMangledName]); | ||
} else { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here, return early and drop the else.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addressed in
036e5b1
if (pulseCalsNameToSequenceMap.find(gateMangledName) != | ||
pulseCalsNameToSequenceMap.end()) { | ||
// found a pulse calibration for the barrier gate | ||
addPulseCalToModule(funcOp, pulseCalsNameToSequenceMap[gateMangledName]); | ||
} else { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addressed in
036e5b1
if (pulseCalsNameToSequenceMap.find(gateMangledName) != | ||
pulseCalsNameToSequenceMap.end()) { | ||
// found a pulse calibration for the gate | ||
addPulseCalToModule(funcOp, pulseCalsNameToSequenceMap[gateMangledName]); | ||
} else { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addressed in
036e5b1
if (pulseCalsAddedToIR.find(sequenceOp.sym_name().str()) == | ||
pulseCalsAddedToIR.end()) { | ||
OpBuilder builder(funcOp.body()); | ||
auto *clonedPulseCalOp = builder.clone(*sequenceOp); | ||
auto clonedPulseCalSequenceOp = dyn_cast<SequenceOp>(clonedPulseCalOp); | ||
clonedPulseCalSequenceOp->moveBefore(funcOp); | ||
pulseCalsAddedToIR.insert(sequenceOp.sym_name().str()); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be useful to add an else here with a debug message?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added in
80ddf0f
mlir::OwningOpRef<ModuleOp> pulseCalsModule( | ||
mlir::parseSourceFile(sourceMgr, &getContext())); | ||
if (!pulseCalsModule) | ||
return llvm::createStringError(llvm::inconvertibleErrorCode(), | ||
"Failed to parse pulse calibrations file: " + | ||
pulseCalsPath); | ||
auto pulseCalsModuleRelease = pulseCalsModule.release(); | ||
pulseCalsModuleRelease->walk([&](mlir::pulse::SequenceOp sequenceOp) { | ||
auto sequenceName = sequenceOp.sym_name().str(); | ||
pulseCalsNameToSequenceMap[sequenceName] = sequenceOp; | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This whole section worries me. You parse in a module into an owning ref, then release it and store the name in a map. I'm worried this is only working currently because the memory is hanging around and not allocated for something else. Am I misunderstanding? It seems like there should be a copy of the contents of the parsed module into the existing top-level module for the translation unit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This whole section worries me. You parse in a module into an owning ref, then release it and store the name in a map. I'm worried this is only working currently because the memory is hanging around and not allocated for something else. Am I misunderstanding? It seems like there should be a copy of the contents of the parsed module into the existing top-level module for the translation unit.
Doesn't this depend on whether the copy constructor for the sequenceOp performs a deep copy or shallow copy?
I couldn't find the definition of sequenceOp quickly, so I don't know for sure.
Since this is a map of string to sequenceOp (and not sequenceOp reference or pointer) I would assume each sequence op is being copied as part of adding it to the map.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so pulseCalsModule
is of type mlir::OwningOpRef<ModuleOp>
, and pulseCalsModule.release()
returns the corresponding ModuleOp
, and its result (i.e., pulseCalsModuleRelease
) is of type ModuleOp
which I then do further processing on. In other words, I used release
function to obtain the ModuleOp
. Please let me know what you think
Another example of this in the codebase is https://github.com/Qiskit/qss-compiler/blob/6528f4e7a7feeec7f72f784a4784151fb83b7a7c/lib/API/api.cpp#L611
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@mbhealy @kitbarton was my answer related to your comment? or your concern is that maybe only a reference to sequenceOp is copied to the map, instead of the whole object?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
From looking at the definition of owningOpRef it looks like the destructor only erases the memory if the op contains something, and release()
should swap the memory from the owning ref to the moduleOp it's released to. Kit's point also about the copy for the map seems relevant. I'm still a bit worried because I'm not clear on exactly how Ops interact with the map constructs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
|
||
// clone the body of the original sequence ops | ||
for (std::size_t seqNum = 1; seqNum < sequenceOps.size(); seqNum++) { | ||
builder.setInsertionPointAfter(&mergedSequenceOp.back().back()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does insertion point setting have to be done inside the loop? Or can it be done once before the loop only?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addressed in
80ddf0f
sequenceOp->setAttr("pulse.args", builder.getArrayAttr(argAttrVec)); | ||
} | ||
|
||
bool LoadPulseCalsPass::areAllSequenceOpsHasSameDuration( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Slightly more grammatical function name
bool LoadPulseCalsPass::areAllSequenceOpsHasSameDuration( | |
bool LoadPulseCalsPass::doAllSequenceOpsHaveSameDuration( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
addressed in
80ddf0f
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this looks good.
I have a few non-blocking comments/questions.
@mbhealy had a good question about dangling memory for the sequenceOps that should get resolved before this is merged though.
|
||
void addPulseCalToModule(FuncOp funcOp, mlir::pulse::SequenceOp sequenceOp); | ||
|
||
// parse the pulse cals and add them to pulseCalsNameToSequenceMap |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are standard comments, not doxygen comments.
Is that intentional or an oversight?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is just standard comment
else if (auto castOp = dyn_cast<mlir::quir::DelayOp>(op)) | ||
loadPulseCals(castOp, callCircuitOp, funcOp); | ||
else if (auto castOp = dyn_cast<mlir::quir::ResetQubitOp>(op)) | ||
loadPulseCals(castOp, callCircuitOp, funcOp); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should there be a final else
here if nothing matches? Or is that acceptable behaviour?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if nothing matches we need to make sure it's not a quantum gate/measure, that needs calibration loading. Added in
80ddf0f
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added assert condition
instead of assert false
in 567e7fb
mlir::OwningOpRef<ModuleOp> pulseCalsModule( | ||
mlir::parseSourceFile(sourceMgr, &getContext())); | ||
if (!pulseCalsModule) | ||
return llvm::createStringError(llvm::inconvertibleErrorCode(), | ||
"Failed to parse pulse calibrations file: " + | ||
pulseCalsPath); | ||
auto pulseCalsModuleRelease = pulseCalsModule.release(); | ||
pulseCalsModuleRelease->walk([&](mlir::pulse::SequenceOp sequenceOp) { | ||
auto sequenceName = sequenceOp.sym_name().str(); | ||
pulseCalsNameToSequenceMap[sequenceName] = sequenceOp; | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This whole section worries me. You parse in a module into an owning ref, then release it and store the name in a map. I'm worried this is only working currently because the memory is hanging around and not allocated for something else. Am I misunderstanding? It seems like there should be a copy of the contents of the parsed module into the existing top-level module for the translation unit.
Doesn't this depend on whether the copy constructor for the sequenceOp performs a deep copy or shallow copy?
I couldn't find the definition of sequenceOp quickly, so I don't know for sure.
Since this is a map of string to sequenceOp (and not sequenceOp reference or pointer) I would assume each sequence op is being copied as part of adding it to the map.
Co-authored-by: mbhealy <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
clang-tidy made some suggestions
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
clang-tidy review says "All clean, LGTM! 👍" |
This PR adds a pass that loads the pulse calibrations, mark the quir operations with their pulse calibration name, and add the pulse calibrations to the module