Skip to content

Commit

Permalink
Add thread local caching to thread_stack_bounds
Browse files Browse the repository at this point in the history
Summary:
Original Author: [email protected]
Original Git: 4fc57f3
Original Reviewed By: tmikov
Original Revision: D66839832

To improve performance in situations where the runtime is repeatedly
called from different threads, add a second level of caching for the
stack bounds in a `thread_local` in OSCompat. Only if this cache fails
will we actually fall back to the platform-specific API calls.

The user-facing API doesn't change, we just split the
`thread_stack_bounds` code into a public function and an internal
`_impl` function.

Reviewed By: tmikov

Differential Revision: D66890656

fbshipit-source-id: 901c5484ed95d3ec0a8611aee87f4d4b9fbd6337
  • Loading branch information
avp authored and facebook-github-bot committed Dec 9, 2024
1 parent 33dfc8f commit 568b1c9
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 7 deletions.
11 changes: 11 additions & 0 deletions include/hermes/Support/OSCompat.h
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,17 @@ uint64_t global_thread_id();
/// stack bounds.
std::pair<const void *, size_t> thread_stack_bounds(unsigned gap = 0);

namespace detail {
/// Non-caching platform-specific implementation of thread_stack_bounds.
/// This is an internal implementation detail.
/// \return (higher stack bound, size) of the current thread.
/// The stack overflows when an address is no longer within
/// the bounds [high - size, high).
/// Will return (nullptr, 0) if the platform doesn't support checking the
/// stack bounds.
std::pair<const void *, size_t> thread_stack_bounds_impl();
} // namespace detail

/// Set the thread name for the current thread. This can be viewed in various
/// debuggers and profilers.
/// NOTE: Is a no-op on some platforms.
Expand Down
1 change: 1 addition & 0 deletions lib/Support/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ add_hermes_library(hermesSupport
ErrorHandling.cpp
InternalIdentifierMaker.cpp
JSONEmitter.cpp
OSCompatCommon.cpp
OSCompatEmscripten.cpp
OSCompatPosix.cpp
OSCompatWindows.cpp
Expand Down
32 changes: 32 additions & 0 deletions lib/Support/OSCompatCommon.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

#include "hermes/Support/OSCompat.h"

namespace hermes {
namespace oscompat {

std::pair<const void *, size_t> thread_stack_bounds(unsigned gap) {
// Avoid calling into the platform-specific code if we can cache the result
// on a per-thread basis.

// The cached result of thread_stack_bounds().
static thread_local std::pair<const void *, size_t> cachedBounds{nullptr, 0};

std::pair<const void *, size_t> bounds = cachedBounds;

if (LLVM_UNLIKELY(!bounds.first)) {
cachedBounds = bounds = detail::thread_stack_bounds_impl();
}

// Adjust for the gap here to allow caching with multiple gaps.
auto [high, size] = bounds;
return {high, gap < size ? size - gap : 0};
}

} // namespace oscompat
} // namespace hermes
6 changes: 5 additions & 1 deletion lib/Support/OSCompatEmscripten.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -216,13 +216,17 @@ uint64_t global_thread_id() {
return 0;
}

std::pair<const void *, size_t> thread_stack_bounds(unsigned gap) {
namespace detail {

std::pair<const void *, size_t> thread_stack_bounds_impl(unsigned gap) {
uintptr_t high = emscripten_stack_get_base();
uintptr_t low = emscripten_stack_get_end();
size_t sz = high - low - gap;
return {(void *)high, sz};
}

} // namespace detail

void set_thread_name(const char *name) {
// Intentionally does nothing
}
Expand Down
13 changes: 8 additions & 5 deletions lib/Support/OSCompatPosix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -612,9 +612,11 @@ uint64_t global_thread_id() {
#error "Thread ID not supported on this platform"
#endif

namespace detail {

#if defined(__APPLE__) && defined(__MACH__)

std::pair<const void *, size_t> thread_stack_bounds(unsigned gap) {
std::pair<const void *, size_t> thread_stack_bounds_impl() {
pthread_t tid = pthread_self();
void *origin = pthread_get_stackaddr_np(tid);
rlim_t size = 0;
Expand All @@ -630,12 +632,12 @@ std::pair<const void *, size_t> thread_stack_bounds(unsigned gap) {
size = pthread_get_stacksize_np(tid);
}

return {origin, gap < size ? size - gap : 0};
return {origin, size};
}

#else

std::pair<const void *, size_t> thread_stack_bounds(unsigned gap) {
std::pair<const void *, size_t> thread_stack_bounds_impl() {
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_getattr_np(pthread_self(), &attr);
Expand Down Expand Up @@ -664,12 +666,13 @@ std::pair<const void *, size_t> thread_stack_bounds(unsigned gap) {
pthread_attr_destroy(&attr);

// origin is now the lowest addressable byte.
unsigned adjustedSize = gap < size ? size - gap : 0;
return {(char *)origin + size, adjustedSize};
return {(char *)origin + size, size};
}

#endif

} // namespace detail

void set_thread_name(const char *name) {
// Set the thread name for TSAN. It doesn't share the same name mapping as the
// OS does. This macro expands to nothing if TSAN isn't on.
Expand Down
6 changes: 5 additions & 1 deletion lib/Support/OSCompatWindows.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -397,11 +397,15 @@ uint64_t global_thread_id() {
return GetCurrentThreadId();
}

std::pair<const void *, size_t> thread_stack_bounds(unsigned) {
namespace detail {

std::pair<const void *, size_t> thread_stack_bounds_impl() {
// Native stack checking unsupported on Windows.
return {nullptr, 0};
}

} // namespace detail

void set_thread_name(const char *name) {
// Set the thread name for TSAN. It doesn't share the same name mapping as the
// OS does. This macro expands to nothing if TSAN isn't on.
Expand Down

0 comments on commit 568b1c9

Please sign in to comment.