From 0d8af5c194e6800325a49d88568d21188083ae32 Mon Sep 17 00:00:00 2001 From: Stella Laurenzo Date: Thu, 12 Jan 2017 16:19:24 -0800 Subject: [PATCH] Add WTF_TASK as a temporary zone that is not bound permanently to a thread. --- bindings/cpp/include/wtf/macros.h | 13 +++++++ bindings/cpp/include/wtf/runtime.h | 50 +++++++++++++++++++++++++++ bindings/cpp/runtime.cc | 45 +++++++++++++++++++++++- bindings/cpp/threaded_torture_test.cc | 8 ++--- 4 files changed, 109 insertions(+), 7 deletions(-) diff --git a/bindings/cpp/include/wtf/macros.h b/bindings/cpp/include/wtf/macros.h index bda11edd..8e9e43c6 100644 --- a/bindings/cpp/include/wtf/macros.h +++ b/bindings/cpp/include/wtf/macros.h @@ -117,4 +117,17 @@ __WTF_INTERNAL_UNIQUE(__wtf_scope_eventn_)}; \ __WTF_INTERNAL_UNIQUE(__wtf_scopen_).Enter +// Creates a scoped "Task" zone that will be in effect until scope exit. +// This is ideal for thread pools and such which execute many workers where +// you want a specific zone for each type of task the worker is performing +// (versus a zone for each worker thread). +#define WTF_TASK_IF(cond, name) \ + __INTERNAL_WTF_NAMESPACE::ScopedTaskIf __WTF_INTERNAL_UNIQUE( \ + __wtf_taskn_) { \ + name \ + } + +// Same as WTF_TASK_IF conditioned on the current namespace. +#define WTF_TASK(name) WTF_TASK_IF(kWtfEnabledForNamespace, name) + #endif // TRACING_FRAMEWORK_BINDINGS_CPP_INCLUDE_WTF_MACROS_H_ diff --git a/bindings/cpp/include/wtf/runtime.h b/bindings/cpp/include/wtf/runtime.h index 351b4095..55511cb1 100644 --- a/bindings/cpp/include/wtf/runtime.h +++ b/bindings/cpp/include/wtf/runtime.h @@ -176,7 +176,18 @@ class Runtime { // or cause crashes if called when asynchronous logging is not quiesced. void ResetForTesting(); + // Pops an idle EventBuffer for the given task and then returns it when + // done. Typically used via the ScopedTask class. + EventBuffer* PopTaskEventBuffer(const std::string& name); + void PushTaskEventBuffer(const std::string& name, EventBuffer* event_buffer); + private: + // Each named task has an info descriptor with the idle event buffers. + struct TaskDefinition { + int next_instance_id = 0; + std::deque idle_event_buffers; + }; + Runtime(); Runtime(const Runtime&) = delete; void operator=(const Runtime&) = delete; @@ -187,9 +198,48 @@ class Runtime { platform::mutex mu_; std::vector> thread_event_buffers_; + std::unordered_map tasks_; int uniquifier_ = 0; }; +// Represents a temporary assignment of an EventBuffer to a thread. +// The previous state is restored when the ScopedTask goes out of +// scope. +template +class ScopedTaskIf { + public: + explicit ScopedTaskIf(std::string name) + : name_(std::move(name)), + previous_event_buffer_(PlatformGetThreadLocalEventBuffer()) { + PlatformSetThreadLocalEventBuffer( + Runtime::GetInstance()->PopTaskEventBuffer(name_)); + } + ~ScopedTaskIf() { + Runtime::GetInstance()->PushTaskEventBuffer( + name_, PlatformGetThreadLocalEventBuffer()); + PlatformSetThreadLocalEventBuffer(previous_event_buffer_); + } + ScopedTaskIf(const ScopedTaskIf&) = delete; + void operator=(const ScopedTaskIf&) = delete; + + private: + std::string name_; + EventBuffer* previous_event_buffer_; +}; + +// Explicit disabled instantiation of ScopedTaskIf. +template <> +class ScopedTaskIf { + public: + explicit ScopedTaskIf(std::string name) {} + ~ScopedTaskIf() = default; + ScopedTaskIf(const ScopedTaskIf&) = delete; + void operator=(const ScopedTaskIf&) = delete; +}; + +using ScopedTask = ScopedTaskIf; +using ScopedTaskEnabled = ScopedTaskIf; + } // namespace wtf #endif // TRACING_FRAMEWORK_BINDINGS_CPP_INCLUDE_WTF_RUNTIME_H_ diff --git a/bindings/cpp/runtime.cc b/bindings/cpp/runtime.cc index 64f70f73..2996c506 100644 --- a/bindings/cpp/runtime.cc +++ b/bindings/cpp/runtime.cc @@ -103,7 +103,50 @@ Runtime* Runtime::GetInstance() { return &runtime; } -void Runtime::ResetForTesting() { thread_event_buffers_.clear(); } +void Runtime::ResetForTesting() { + platform::lock_guard lock{mu_}; + thread_event_buffers_.clear(); + tasks_.clear(); +} + +EventBuffer* Runtime::PopTaskEventBuffer(const std::string& name) { + int unique_id; + EventBuffer* created; + { + platform::lock_guard lock{mu_}; + auto& task = tasks_[name]; + if (!task.idle_event_buffers.empty()) { + EventBuffer* existing = task.idle_event_buffers.front(); + task.idle_event_buffers.pop_front(); + return existing; + } + unique_id = task.next_instance_id++; + created = CreateThreadEventBuffer(); + } + + // Add uniquifier to the provided task name to make sure that + // different threads don't get attributed to the same zone. + std::ostringstream ss; + ss << name << ":" << unique_id; + std::string unique_name = ss.str(); + int zone_id = + ZoneRegistry::GetInstance()->CreateZone(unique_name.c_str(), "TASK", ""); + StandardEvents::SetZone(created, zone_id); + created->FreezePrefixSlots(); + + return created; +} + +void Runtime::PushTaskEventBuffer(const std::string& name, + EventBuffer* event_buffer) { + if (!event_buffer) { + return; + } + + platform::lock_guard lock{mu_}; + auto& task = tasks_[name]; + task.idle_event_buffers.push_front(event_buffer); +} EventBuffer* Runtime::CreateThreadEventBuffer() { EventBuffer* r; diff --git a/bindings/cpp/threaded_torture_test.cc b/bindings/cpp/threaded_torture_test.cc index 2e851d40..04f9d29a 100644 --- a/bindings/cpp/threaded_torture_test.cc +++ b/bindings/cpp/threaded_torture_test.cc @@ -12,8 +12,6 @@ std::atomic had_error; std::atomic stop; -std::vector thread_names; - void SaveThread() { WTF_AUTO_THREAD_ENABLE(); wtf::Runtime::SaveCheckpoint checkpoint; @@ -46,8 +44,9 @@ void SaveThread() { } void NoiseMaker1(int thread_number) { - WTF_THREAD_ENABLE(thread_names[thread_number].c_str()); for (int i = 0;; i++) { + WTF_TASK("NoiseMaker"); + WTF_EVENT("NoiseMaker1#Loop: thread_number, i", int32_t, int32_t) (thread_number, i); std::this_thread::sleep_for(std::chrono::microseconds(5)); @@ -82,9 +81,6 @@ extern "C" int main(int argc, char** argv) { } std::cerr << "Running with " << thread_count << " threads." << std::endl; for (int i = 0; i < thread_count; i++) { - std::stringstream thread_name; - thread_name << "NoiseMaker" << i; - thread_names.push_back(thread_name.str()); threads.emplace_back(NoiseMaker1, i); }