Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[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

Merged

Conversation

kastiglione
Copy link

@kastiglione kastiglione commented Dec 13, 2023

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

@kastiglione
Copy link
Author

@swift-ci test

Copy link

@adrian-prantl adrian-prantl left a 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.

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?

Copy link
Author

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.

@kastiglione
Copy link
Author

kastiglione commented Dec 13, 2023

The change looks good, but most of it should be possible on llvm.org main?

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?

bool IsCFAOnStack(Process &process) const;

/// Determine if the first StackID is "younger" than the second.
static bool IsYounger(const StackID &lhs, const StackID &rhs);

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.

Copy link
Author

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?

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.

@jimingham
Copy link

jimingham commented Dec 14, 2023 via email

@jasonmolenda
Copy link

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.

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.

@kastiglione
Copy link
Author

@swift-ci test

@kastiglione
Copy link
Author

@swift-ci test macOS

@kastiglione
Copy link
Author

@swift-ci test windows

Copy link

@adrian-prantl adrian-prantl left a 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?

@kastiglione kastiglione merged commit c58c369 into stable/20230725 Jan 8, 2024
@kastiglione kastiglione deleted the dl/lldb-Defer-checking-CFA-memory-region branch January 8, 2024 19:51
kastiglione added a commit that referenced this pull request Jan 24, 2024
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)
kastiglione added a commit that referenced this pull request Jan 24, 2024
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)
felipepiovezan added a commit to felipepiovezan/llvm-project that referenced this pull request Aug 23, 2024
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.
felipepiovezan added a commit to felipepiovezan/llvm-project that referenced this pull request Aug 23, 2024
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.
felipepiovezan added a commit to felipepiovezan/llvm-project that referenced this pull request Sep 4, 2024
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)
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.

4 participants