Skip to content
This repository has been archived by the owner on Dec 29, 2022. It is now read-only.

Commit

Permalink
Add WTF_TASK as a temporary zone that is not bound permanently to a t…
Browse files Browse the repository at this point in the history
…hread.
  • Loading branch information
Stella Laurenzo committed Jan 13, 2017
1 parent 7b3567a commit 0d8af5c
Show file tree
Hide file tree
Showing 4 changed files with 109 additions and 7 deletions.
13 changes: 13 additions & 0 deletions bindings/cpp/include/wtf/macros.h
Expand Up @@ -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<cond> __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_
50 changes: 50 additions & 0 deletions bindings/cpp/include/wtf/runtime.h
Expand Up @@ -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<EventBuffer*> idle_event_buffers;
};

Runtime();
Runtime(const Runtime&) = delete;
void operator=(const Runtime&) = delete;
Expand All @@ -187,9 +198,48 @@ class Runtime {

platform::mutex mu_;
std::vector<std::unique_ptr<EventBuffer>> thread_event_buffers_;
std::unordered_map<std::string, TaskDefinition> 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 <bool kEnable>
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<false> {
public:
explicit ScopedTaskIf(std::string name) {}
~ScopedTaskIf() = default;
ScopedTaskIf(const ScopedTaskIf&) = delete;
void operator=(const ScopedTaskIf&) = delete;
};

using ScopedTask = ScopedTaskIf<kMasterEnable>;
using ScopedTaskEnabled = ScopedTaskIf<true>;

} // namespace wtf

#endif // TRACING_FRAMEWORK_BINDINGS_CPP_INCLUDE_WTF_RUNTIME_H_
45 changes: 44 additions & 1 deletion bindings/cpp/runtime.cc
Expand Up @@ -103,7 +103,50 @@ Runtime* Runtime::GetInstance() {
return &runtime;
}

void Runtime::ResetForTesting() { thread_event_buffers_.clear(); }
void Runtime::ResetForTesting() {
platform::lock_guard<platform::mutex> lock{mu_};
thread_event_buffers_.clear();
tasks_.clear();
}

EventBuffer* Runtime::PopTaskEventBuffer(const std::string& name) {
int unique_id;
EventBuffer* created;
{
platform::lock_guard<platform::mutex> 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<platform::mutex> lock{mu_};
auto& task = tasks_[name];
task.idle_event_buffers.push_front(event_buffer);
}

EventBuffer* Runtime::CreateThreadEventBuffer() {
EventBuffer* r;
Expand Down
8 changes: 2 additions & 6 deletions bindings/cpp/threaded_torture_test.cc
Expand Up @@ -12,8 +12,6 @@
std::atomic<bool> had_error;
std::atomic<bool> stop;

std::vector<std::string> thread_names;

void SaveThread() {
WTF_AUTO_THREAD_ENABLE();
wtf::Runtime::SaveCheckpoint checkpoint;
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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);
}

Expand Down

0 comments on commit 0d8af5c

Please sign in to comment.