-
Notifications
You must be signed in to change notification settings - Fork 341
[lldb] Defer checking CFA memory region #7877
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
[lldb] Defer checking CFA memory region #7877
Conversation
@swift-ci test |
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.
The change looks good, but most of it should be possible on llvm.org main?
@@ -57,15 +57,17 @@ class StackID { | |||
return *this; | |||
} | |||
|
|||
bool IsCFAOnStack() const { return m_cfa_on_stack; } | |||
/// Check if the CFA is on the stack, or elsewhere in the process, such as on | |||
/// the heap. |
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 we comment that the caller is now expected to check for Heap frames?
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.
Was this meant to be on the IsYounger
function? If so, I moved the heap check into IsYounger
to avoid having to put that requirement onto callers.
I was thinking of making the change here first, with the thought that I could get a commit sooner, and then opening a PR to llvm.org. Thoughts? |
lldb/include/lldb/Target/StackID.h
Outdated
bool IsCFAOnStack(Process &process) const; | ||
|
||
/// Determine if the first StackID is "younger" than the second. | ||
static bool IsYounger(const StackID &lhs, const StackID &rhs); |
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.
Prob just me, but I'm not completely clear on what "younger" means here. If foo()
calls bar()
and we do a backtrace, is the bar()
stack frame younger than the foo()
stack frame. Younger meaning most recently created stack frame.
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.
Yes, that's correct.
I don't find the term "younger" entirely intuitive either, but I followed the existing use of the term. Do you have an alternative suggestion?
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.
Not offhand. Maybe we can stick a definition like above in the comment.
I've been trying to use "younger" and "older" rather than above and below or other spatial words because stack frames have a temporal order (one was pushed, then the next) but they don't really have a spatial order. A frame "younger" than the current frame was either pushed by this frame or by one of the ones it pushed - it's younger because it was created after the frames that pushed it. An "older" frame is in the sequence that pushed this frame so it had to exist before this frame, and so is older than it.
Jim
… On Dec 13, 2023, at 4:13 PM, Jason Molenda ***@***.***> wrote:
@jasonmolenda commented on this pull request.
In lldb/include/lldb/Target/StackID.h <#7877 (comment)>:
> @@ -57,15 +57,17 @@ class StackID {
return *this;
}
- bool IsCFAOnStack() const { return m_cfa_on_stack; }
+ /// Check if the CFA is on the stack, or elsewhere in the process, such as on
+ /// the heap.
+ bool IsCFAOnStack(Process &process) const;
+
+ /// Determine if the first StackID is "younger" than the second.
+ static bool IsYounger(const StackID &lhs, const StackID &rhs);
Not offhand. Maybe we can stick a definition like above in the comment.
—
Reply to this email directly, view it on GitHub <#7877 (comment)>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/ADUPVW2RNJ2YRTO6OUIYIP3YJJADRAVCNFSM6AAAAABATZZ4WCVHI2DSMVQWIX3LMV43YUDVNRWFEZLROVSXG5CSMV3GSZLXHMYTOOBQGY4DQOBUGE>.
You are receiving this because your review was requested.
|
Yeah I don't have a problem with the term "younger", but a casual reader who hasn't thought about it (OK IT'S ME) will look at that and say wait, which is younger? I think "younger" meaning "the stack frame most recently created in time" is a clear way of thinking about it. |
@swift-ci test |
@swift-ci test macOS |
@swift-ci test windows |
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.
Looks good now. However, it would still be great to upstream this?
To support stepping in Swift async code, LLDB uses the memory region (ie stack vs heap) of the Canonical Frame Address (CFA) to identify when an async function calls a synchronous function. But this has resulted in a performance regression, as determining the memory region of the CFA is not free, and eagerly performing this query for every `StackID`, particularly during backtracing/unwinding – when stepping is not yet occurring, is wasteful. This change proposes a solution that defers the memory region query until required to perform stepping logic. The logic that checks heaps vs stacks was moved into `ThreadPlan`, the only place that currently needs to make that determination. Performing this check in `ThreadPlan` provides access to the process, allowing stack/heap determination to happen as needed. Previously, the stack/heap determination was made eagerly when the `StackID` was constructed. rdar://117505613 (cherry-picked from commit c58c369)
To support stepping in Swift async code, LLDB uses the memory region (ie stack vs heap) of the Canonical Frame Address (CFA) to identify when an async function calls a synchronous function. But this has resulted in a performance regression, as determining the memory region of the CFA is not free, and eagerly performing this query for every `StackID`, particularly during backtracing/unwinding – when stepping is not yet occurring, is wasteful. This change proposes a solution that defers the memory region query until required to perform stepping logic. The logic that checks heaps vs stacks was moved into `ThreadPlan`, the only place that currently needs to make that determination. Performing this check in `ThreadPlan` provides access to the process, allowing stack/heap determination to happen as needed. Previously, the stack/heap determination was made eagerly when the `StackID` was constructed. rdar://117505613 (cherry-picked from commit c58c369)
The optimization in swiftlang#7877 accidentally changed the default answer for this function. It's important to default to "On Stack" when we don't know, because that's where most CFAs live, and because we don't want to trigger the expensive heap comparisons unless we're absolutely sure the CFA is on the heap.
The optimization in swiftlang#7877 accidentally changed the default answer for this function. It's important to default to "On Stack" when we don't know, because that's where most CFAs live, and because we don't want to trigger the expensive heap comparisons unless we're absolutely sure the CFA is on the heap.
The optimization in swiftlang#7877 accidentally changed the default answer for this function. It's important to default to "On Stack" when we don't know, because that's where most CFAs live, and because we don't want to trigger the expensive heap comparisons unless we're absolutely sure the CFA is on the heap. (cherry picked from commit 57757e9)
To support stepping in Swift async code, LLDB uses the memory region (ie stack vs heap) of the Canonical Frame Address (CFA) to identify when an async function calls a synchronous function.
But this has resulted in a performance regression, as determining the memory region of the CFA is not free, and eagerly performing this query for every
StackID
, particularly during backtracing/unwinding – when stepping is not yet occurring, is wasteful.This change proposes a solution that defers the memory region query until required to perform stepping logic. The logic that checks heaps vs stacks was moved into
ThreadPlan
, the only place that currently needs to make that determination. Performing this check inThreadPlan
provides access to the process, allowing stack/heap determination to happen as needed. Previously, the stack/heap determination was made eagerly when theStackID
was constructed.rdar://117505613