Commit 155c242f authored by Chris Hamilton's avatar Chris Hamilton Committed by Commit Bot

TaskAnnotator: Remove use of ThreadLocalOwnedPointer.

The overhead introduced by using an owned TLS pointer caused a performance
regression of 0.5% at the median, as this is a hot code path executed for
every single task that is evaluated.

This CL reverts to using a plain TLS pointer as before, and repurposes the
inline |ipc_program_counter| storage in PendingTask to store the current
IPC message context.

BUG=957693

Change-Id: I32ddf9a28b924b5a45301d4855dc08d8b914fbbd
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1590247
Commit-Queue: Chris Hamilton <chrisha@chromium.org>
Reviewed-by: default avatarFrançois Doray <fdoray@chromium.org>
Cr-Commit-Position: refs/heads/master@{#656299}
parent d3654d8f
...@@ -8,9 +8,7 @@ ...@@ -8,9 +8,7 @@
#include "base/debug/activity_tracker.h" #include "base/debug/activity_tracker.h"
#include "base/debug/alias.h" #include "base/debug/alias.h"
#include "base/memory/ptr_util.h"
#include "base/no_destructor.h" #include "base/no_destructor.h"
#include "base/pending_task.h"
#include "base/threading/thread_local.h" #include "base/threading/thread_local.h"
#include "base/trace_event/trace_event.h" #include "base/trace_event/trace_event.h"
...@@ -20,36 +18,40 @@ namespace { ...@@ -20,36 +18,40 @@ namespace {
TaskAnnotator::ObserverForTesting* g_task_annotator_observer = nullptr; TaskAnnotator::ObserverForTesting* g_task_annotator_observer = nullptr;
// Information about the context in which a PendingTask is currently being // Used as a sentinel to determine if a TLS-stored PendingTask is a dummy one.
// executed. static constexpr int kSentinelSequenceNum =
struct TaskAnnotatorThreadInfo { static_cast<int>(0xF00DBAADF00DBAAD);
// The pending task currently being executed.
const PendingTask* pending_task = nullptr;
// The pending task that was being executed when the |ipc_program_counter|
// was set. This is used to detect a nested message loop, in which case the
// global IPC decoration should not be applied.
const PendingTask* ipc_message_handler_task = nullptr;
// The program counter of the currently executing IPC message handler, if
// there is one.
const void* ipc_program_counter = nullptr;
};
// Returns the TLS slot that stores the PendingTask currently in progress on // Returns the TLS slot that stores the PendingTask currently in progress on
// each thread. Used to allow creating a breadcrumb of program counters on the // each thread. Used to allow creating a breadcrumb of program counters on the
// stack to help identify a task's origin in crashes. // stack to help identify a task's origin in crashes.
TaskAnnotatorThreadInfo* GetTLSForCurrentPendingTask() { ThreadLocalPointer<PendingTask>* GetTLSForCurrentPendingTask() {
static NoDestructor<ThreadLocalOwnedPointer<TaskAnnotatorThreadInfo>> static NoDestructor<ThreadLocalPointer<PendingTask>> instance;
instance; return instance.get();
if (!instance->Get()) }
instance->Set(WrapUnique(new TaskAnnotatorThreadInfo));
auto* tls_info = instance->Get(); // Determines whether or not the given |task| is a dummy pending task that has
return tls_info; // been injected by ScopedSetIpcProgramCounter solely for the purposes of
// tracking IPC context.
bool IsDummyPendingTask(const PendingTask* task) {
if (task->sequence_num == kSentinelSequenceNum &&
!task->posted_from.has_source_info() &&
!task->posted_from.program_counter()) {
return true;
}
return false;
} }
} // namespace } // namespace
const PendingTask* TaskAnnotator::CurrentTaskForThread() { const PendingTask* TaskAnnotator::CurrentTaskForThread() {
return GetTLSForCurrentPendingTask()->pending_task; auto* current_task = GetTLSForCurrentPendingTask()->Get();
// Don't return "dummy" current tasks that are only used for storing IPC
// context.
if (current_task && IsDummyPendingTask(current_task))
return nullptr;
return current_task;
} }
TaskAnnotator::TaskAnnotator() = default; TaskAnnotator::TaskAnnotator() = default;
...@@ -73,21 +75,11 @@ void TaskAnnotator::WillQueueTask(const char* trace_event_name, ...@@ -73,21 +75,11 @@ void TaskAnnotator::WillQueueTask(const char* trace_event_name,
if (pending_task->task_backtrace[0]) if (pending_task->task_backtrace[0])
return; return;
// Inherit the currently executing IPC handler context only if not in a nested const auto* parent_task = CurrentTaskForThread();
// message loop.
const auto* tls_info = GetTLSForCurrentPendingTask();
if (tls_info->ipc_message_handler_task == tls_info->pending_task)
pending_task->ipc_program_counter = tls_info->ipc_program_counter;
const auto* parent_task = tls_info->pending_task;
if (!parent_task) if (!parent_task)
return; return;
// If an IPC message handler context wasn't explicitly set, then inherit the pending_task->ipc_program_counter = parent_task->ipc_program_counter;
// context from the parent task.
if (!pending_task->ipc_program_counter)
pending_task->ipc_program_counter = parent_task->ipc_program_counter;
pending_task->task_backtrace[0] = parent_task->posted_from.program_counter(); pending_task->task_backtrace[0] = parent_task->posted_from.program_counter();
std::copy(parent_task->task_backtrace.begin(), std::copy(parent_task->task_backtrace.begin(),
parent_task->task_backtrace.end() - 1, parent_task->task_backtrace.end() - 1,
...@@ -139,15 +131,15 @@ void TaskAnnotator::RunTask(const char* trace_event_name, ...@@ -139,15 +131,15 @@ void TaskAnnotator::RunTask(const char* trace_event_name,
pending_task->ipc_program_counter; pending_task->ipc_program_counter;
debug::Alias(&task_backtrace); debug::Alias(&task_backtrace);
auto* tls_info = GetTLSForCurrentPendingTask(); auto* tls = GetTLSForCurrentPendingTask();
const auto* previous_pending_task = tls_info->pending_task; auto* previous_pending_task = tls->Get();
tls_info->pending_task = pending_task; tls->Set(pending_task);
if (g_task_annotator_observer) if (g_task_annotator_observer)
g_task_annotator_observer->BeforeRunTask(pending_task); g_task_annotator_observer->BeforeRunTask(pending_task);
std::move(pending_task->task).Run(); std::move(pending_task->task).Run();
tls_info->pending_task = previous_pending_task; tls->Set(previous_pending_task);
} }
uint64_t TaskAnnotator::GetTaskTraceID(const PendingTask& task) const { uint64_t TaskAnnotator::GetTaskTraceID(const PendingTask& task) const {
...@@ -169,17 +161,30 @@ void TaskAnnotator::ClearObserverForTesting() { ...@@ -169,17 +161,30 @@ void TaskAnnotator::ClearObserverForTesting() {
TaskAnnotator::ScopedSetIpcProgramCounter::ScopedSetIpcProgramCounter( TaskAnnotator::ScopedSetIpcProgramCounter::ScopedSetIpcProgramCounter(
const void* program_counter) { const void* program_counter) {
auto* tls_info = GetTLSForCurrentPendingTask(); // We store the IPC context in the currently running task. If there is none
old_ipc_message_handler_task_ = tls_info->ipc_message_handler_task; // then introduce a dummy task.
old_ipc_program_counter_ = tls_info->ipc_program_counter; auto* tls = GetTLSForCurrentPendingTask();
tls_info->ipc_message_handler_task = tls_info->pending_task; auto* current_task = tls->Get();
tls_info->ipc_program_counter = program_counter; if (!current_task) {
dummy_pending_task_ = std::make_unique<PendingTask>();
dummy_pending_task_->sequence_num = kSentinelSequenceNum;
current_task = dummy_pending_task_.get();
tls->Set(current_task);
}
old_ipc_program_counter_ = current_task->ipc_program_counter;
current_task->ipc_program_counter = program_counter;
} }
TaskAnnotator::ScopedSetIpcProgramCounter::~ScopedSetIpcProgramCounter() { TaskAnnotator::ScopedSetIpcProgramCounter::~ScopedSetIpcProgramCounter() {
auto* tls_info = GetTLSForCurrentPendingTask(); auto* tls = GetTLSForCurrentPendingTask();
tls_info->ipc_message_handler_task = old_ipc_message_handler_task_; auto* current_task = tls->Get();
tls_info->ipc_program_counter = old_ipc_program_counter_; DCHECK(current_task);
if (current_task == dummy_pending_task_.get()) {
tls->Set(nullptr);
} else {
current_task->ipc_program_counter = old_ipc_program_counter_;
}
} }
} // namespace base } // namespace base
...@@ -7,11 +7,13 @@ ...@@ -7,11 +7,13 @@
#include <stdint.h> #include <stdint.h>
#include <memory>
#include "base/base_export.h" #include "base/base_export.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/pending_task.h"
namespace base { namespace base {
struct PendingTask;
// Implements common debug annotations for posted tasks. This includes data // Implements common debug annotations for posted tasks. This includes data
// such as task origins, IPC message contexts, queueing durations and memory // such as task origins, IPC message contexts, queueing durations and memory
...@@ -70,7 +72,7 @@ class BASE_EXPORT TaskAnnotator::ScopedSetIpcProgramCounter { ...@@ -70,7 +72,7 @@ class BASE_EXPORT TaskAnnotator::ScopedSetIpcProgramCounter {
~ScopedSetIpcProgramCounter(); ~ScopedSetIpcProgramCounter();
private: private:
const PendingTask* old_ipc_message_handler_task_ = nullptr; std::unique_ptr<PendingTask> dummy_pending_task_;
const void* old_ipc_program_counter_ = nullptr; const void* old_ipc_program_counter_ = nullptr;
DISALLOW_COPY_AND_ASSIGN(ScopedSetIpcProgramCounter); DISALLOW_COPY_AND_ASSIGN(ScopedSetIpcProgramCounter);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment