GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage-daily/nodes/benchmark/out/../src/tracing/agent.cc Lines: 133 133 100.0 %
Date: 2019-09-26 22:31:05 Branches: 40 50 80.0 %

Line Branch Exec Source
1
#include "tracing/agent.h"
2
3
#include <string>
4
#include "trace_event.h"
5
#include "tracing/node_trace_buffer.h"
6
#include "debug_utils.h"
7
#include "env-inl.h"
8
9
namespace node {
10
namespace tracing {
11
12
class Agent::ScopedSuspendTracing {
13
 public:
14
170
  ScopedSuspendTracing(TracingController* controller, Agent* agent,
15
                       bool do_suspend = true)
16
170
    : controller_(controller), agent_(do_suspend ? agent : nullptr) {
17
170
    if (do_suspend) {
18
170
      CHECK(agent_->started_);
19
170
      controller->StopTracing();
20
    }
21
170
  }
22
23
170
  ~ScopedSuspendTracing() {
24
170
    if (agent_ == nullptr) return;
25
170
    TraceConfig* config = agent_->CreateTraceConfig();
26
170
    if (config != nullptr) {
27
168
      controller_->StartTracing(config);
28
    }
29
340
  }
30
31
 private:
32
  TracingController* controller_;
33
  Agent* agent_;
34
};
35
36
namespace {
37
38
185
std::set<std::string> flatten(
39
    const std::unordered_map<int, std::multiset<std::string>>& map) {
40
185
  std::set<std::string> result;
41
475
  for (const auto& id_value : map)
42
290
    result.insert(id_value.second.begin(), id_value.second.end());
43
185
  return result;
44
}
45
46
}  // namespace
47
48
using v8::platform::tracing::TraceConfig;
49
using v8::platform::tracing::TraceWriter;
50
using std::string;
51
52
4895
Agent::Agent() : tracing_controller_(new TracingController()) {
53
4895
  tracing_controller_->Initialize(nullptr);
54
55
4895
  CHECK_EQ(uv_loop_init(&tracing_loop_), 0);
56
9934
  CHECK_EQ(uv_async_init(&tracing_loop_,
57
                         &initialize_writer_async_,
58
                         [](uv_async_t* async) {
59
    Agent* agent = ContainerOf(&Agent::initialize_writer_async_, async);
60
    agent->InitializeWritersOnThread();
61
  }), 0);
62
4895
  uv_unref(reinterpret_cast<uv_handle_t*>(&initialize_writer_async_));
63
4895
}
64
65
72
void Agent::InitializeWritersOnThread() {
66
72
  Mutex::ScopedLock lock(initialize_writer_mutex_);
67
216
  while (!to_be_initialized_.empty()) {
68
72
    AsyncTraceWriter* head = *to_be_initialized_.begin();
69
72
    head->InitializeOnThread(&tracing_loop_);
70
72
    to_be_initialized_.erase(head);
71
  }
72
72
  initialize_writer_condvar_.Broadcast(lock);
73
72
}
74
75
9790
Agent::~Agent() {
76
4895
  categories_.clear();
77
4895
  writers_.clear();
78
79
4895
  StopTracing();
80
81
4895
  uv_close(reinterpret_cast<uv_handle_t*>(&initialize_writer_async_), nullptr);
82
4895
  uv_run(&tracing_loop_, UV_RUN_ONCE);
83
4895
  CheckedUvLoopClose(&tracing_loop_);
84
4895
}
85
86
72
void Agent::Start() {
87
72
  if (started_)
88
72
    return;
89
90
  NodeTraceBuffer* trace_buffer_ = new NodeTraceBuffer(
91
72
      NodeTraceBuffer::kBufferChunks, this, &tracing_loop_);
92
72
  tracing_controller_->Initialize(trace_buffer_);
93
94
  // This thread should be created *after* async handles are created
95
  // (within NodeTraceWriter and NodeTraceBuffer constructors).
96
  // Otherwise the thread could shut down prematurely.
97
288
  CHECK_EQ(0, uv_thread_create(&thread_, [](void* arg) {
98
    Agent* agent = static_cast<Agent*>(arg);
99
    uv_run(&agent->tracing_loop_, UV_RUN_DEFAULT);
100
  }, this));
101
72
  started_ = true;
102
}
103
104
72
AgentWriterHandle Agent::AddClient(
105
    const std::set<std::string>& categories,
106
    std::unique_ptr<AsyncTraceWriter> writer,
107
    enum UseDefaultCategoryMode mode) {
108
72
  Start();
109
110
72
  const std::set<std::string>* use_categories = &categories;
111
112
72
  std::set<std::string> categories_with_default;
113
72
  if (mode == kUseDefaultCategories) {
114
70
    categories_with_default.insert(categories.begin(), categories.end());
115
140
    categories_with_default.insert(categories_[kDefaultHandleId].begin(),
116
210
                                   categories_[kDefaultHandleId].end());
117
70
    use_categories = &categories_with_default;
118
  }
119
120
144
  ScopedSuspendTracing suspend(tracing_controller_.get(), this);
121
72
  int id = next_writer_id_++;
122
72
  AsyncTraceWriter* raw = writer.get();
123
72
  writers_[id] = std::move(writer);
124
72
  categories_[id] = { use_categories->begin(), use_categories->end() };
125
126
  {
127
72
    Mutex::ScopedLock lock(initialize_writer_mutex_);
128
72
    to_be_initialized_.insert(raw);
129
72
    uv_async_send(&initialize_writer_async_);
130
216
    while (to_be_initialized_.count(raw) > 0)
131
144
      initialize_writer_condvar_.Wait(lock);
132
  }
133
134
144
  return AgentWriterHandle(this, id);
135
}
136
137
4895
AgentWriterHandle Agent::DefaultHandle() {
138
4895
  return AgentWriterHandle(this, kDefaultHandleId);
139
}
140
141
4895
void Agent::StopTracing() {
142
4895
  if (!started_)
143
9718
    return;
144
  // Perform final Flush on TraceBuffer. We don't want the tracing controller
145
  // to flush the buffer again on destruction of the V8::Platform.
146
72
  tracing_controller_->StopTracing();
147
72
  tracing_controller_->Initialize(nullptr);
148
72
  started_ = false;
149
150
  // Thread should finish when the tracing loop is stopped.
151
72
  uv_thread_join(&thread_);
152
}
153
154
4967
void Agent::Disconnect(int client) {
155
9934
  if (client == kDefaultHandleId) return;
156
  {
157
72
    Mutex::ScopedLock lock(initialize_writer_mutex_);
158
72
    to_be_initialized_.erase(writers_[client].get());
159
  }
160
72
  ScopedSuspendTracing suspend(tracing_controller_.get(), this);
161
72
  writers_.erase(client);
162
72
  categories_.erase(client);
163
}
164
165
20
void Agent::Enable(int id, const std::set<std::string>& categories) {
166
20
  if (categories.empty())
167
20
    return;
168
169
  ScopedSuspendTracing suspend(tracing_controller_.get(), this,
170
20
                               id != kDefaultHandleId);
171
20
  categories_[id].insert(categories.begin(), categories.end());
172
}
173
174
6
void Agent::Disable(int id, const std::set<std::string>& categories) {
175
  ScopedSuspendTracing suspend(tracing_controller_.get(), this,
176
6
                               id != kDefaultHandleId);
177
6
  std::multiset<std::string>& writer_categories = categories_[id];
178
12
  for (const std::string& category : categories) {
179
6
    auto it = writer_categories.find(category);
180
6
    if (it != writer_categories.end())
181
6
      writer_categories.erase(it);
182
6
  }
183
6
}
184
185
170
TraceConfig* Agent::CreateTraceConfig() const {
186
170
  if (categories_.empty())
187
2
    return nullptr;
188
168
  TraceConfig* trace_config = new TraceConfig();
189
324
  for (const auto& category : flatten(categories_)) {
190
156
    trace_config->AddIncludedCategory(category.c_str());
191
168
  }
192
168
  return trace_config;
193
}
194
195
17
std::string Agent::GetEnabledCategories() const {
196
17
  std::string categories;
197
29
  for (const std::string& category : flatten(categories_)) {
198
12
    if (!categories.empty())
199
1
      categories += ',';
200
12
    categories += category;
201
17
  }
202
17
  return categories;
203
}
204
205
4757
void Agent::AppendTraceEvent(TraceObject* trace_event) {
206
8282
  for (const auto& id_writer : writers_)
207
3525
    id_writer.second->AppendTraceEvent(trace_event);
208
4757
}
209
210
623
void Agent::AddMetadataEvent(std::unique_ptr<TraceObject> event) {
211
623
  Mutex::ScopedLock lock(metadata_events_mutex_);
212
624
  metadata_events_.push_back(std::move(event));
213
624
}
214
215
336
void Agent::Flush(bool blocking) {
216
  {
217
336
    Mutex::ScopedLock lock(metadata_events_mutex_);
218
3074
    for (const auto& event : metadata_events_)
219
3074
      AppendTraceEvent(event.get());
220
  }
221
222
532
  for (const auto& id_writer : writers_)
223
196
    id_writer.second->Flush(blocking);
224
336
}
225
226
622
void TracingController::AddMetadataEvent(
227
    const unsigned char* category_group_enabled,
228
    const char* name,
229
    int num_args,
230
    const char** arg_names,
231
    const unsigned char* arg_types,
232
    const uint64_t* arg_values,
233
    std::unique_ptr<v8::ConvertableToTraceFormat>* convertable_values,
234
    unsigned int flags) {
235
622
  std::unique_ptr<TraceObject> trace_event(new TraceObject);
236
  trace_event->Initialize(
237
      TRACE_EVENT_PHASE_METADATA, category_group_enabled, name,
238
      node::tracing::kGlobalScope,  // scope
239
      node::tracing::kNoId,         // id
240
      node::tracing::kNoId,         // bind_id
241
      num_args, arg_names, arg_types, arg_values, convertable_values,
242
      TRACE_EVENT_FLAG_NONE,
243
624
      CurrentTimestampMicroseconds(),
244
1248
      CurrentCpuTimestampMicroseconds());
245
  node::tracing::TraceEventHelper::GetAgent()->AddMetadataEvent(
246
624
      std::move(trace_event));
247
624
}
248
249
}  // namespace tracing
250
}  // namespace node