GCC Code Coverage Report
Directory: ../ Exec Total Coverage
File: /home/iojs/build/workspace/node-test-commit-linux-coverage/nodes/benchmark/out/../src/node_trace_events.cc Lines: 64 64 100.0 %
Date: 2017-12-18 Branches: 37 64 57.8 %

Line Branch Exec Source
1
#include "node_internals.h"
2
#include "tracing/agent.h"
3
4
namespace node {
5
6
using v8::Context;
7
using v8::FunctionCallbackInfo;
8
using v8::Int32;
9
using v8::Local;
10
using v8::Object;
11
using v8::Value;
12
13
// The tracing APIs require category groups to be pointers to long-lived
14
// strings. Those strings are stored here.
15
3391
static std::unordered_set<std::string> categoryGroups;
16
17
// Gets a pointer to the category-enabled flags for a tracing category group,
18
// if tracing is enabled for it.
19
3366
static const uint8_t* GetCategoryGroupEnabled(const char* category_group) {
20
3366
    if (category_group == nullptr) return nullptr;
21
22
3366
    return TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(category_group);
23
}
24
25
3366
static const char* GetCategoryGroup(Environment* env,
26
                                    const Local<Value> categoryValue) {
27
6732
  CHECK(categoryValue->IsString());
28
29
3366
  Utf8Value category(env->isolate(), categoryValue);
30
  // If the value already exists in the set, insertion.first will point
31
  // to the existing value. Thus, this will maintain a long lived pointer
32
  // to the category c-string.
33
3366
  auto insertion = categoryGroups.insert(category.out());
34
35
  // The returned insertion is a pair whose first item is the object that was
36
  // inserted or that blocked the insertion and second item is a boolean
37
  // indicating whether it was inserted.
38
3366
  return insertion.first->c_str();
39
}
40
41
16
static void Emit(const FunctionCallbackInfo<Value>& args) {
42
16
  Environment* env = Environment::GetCurrent(args);
43
16
  Local<Context> context = env->context();
44
45
  // Args: [type, category, name, id, argName, argValue]
46
16
  CHECK_GE(args.Length(), 3);
47
48
  // Check the category group first, to avoid doing more work if it's not
49
  // enabled.
50
16
  const char* category_group = GetCategoryGroup(env, args[1]);
51
  const uint8_t* category_group_enabled =
52
16
    GetCategoryGroupEnabled(category_group);
53
32
  if (*category_group_enabled == 0) return;
54
55
  // get trace_event phase
56
30
  CHECK(args[0]->IsNumber());
57
45
  char phase = static_cast<char>(args[0]->Int32Value(context).ToChecked());
58
59
  // get trace_event name
60
45
  CHECK(args[2]->IsString());
61
15
  Utf8Value nameValue(env->isolate(), args[2]);
62
15
  const char* name = nameValue.out();
63
64
  // get trace_event id
65
15
  int64_t id = 0;
66
15
  bool has_id = false;
67



120
  if (args.Length() >= 4 && !args[3]->IsUndefined() && !args[3]->IsNull()) {
68
15
    has_id = true;
69
30
    CHECK(args[3]->IsNumber());
70
45
    id = args[3]->IntegerValue(context).ToChecked();
71
  }
72
73
  // TODO(AndreasMadsen): String values are not supported.
74
15
  int32_t num_args = 0;
75
  const char* arg_names[2];
76
  uint8_t arg_types[2];
77
  uint64_t arg_values[2];
78
79
  // Create Utf8Value in the function scope to prevent deallocation.
80
  // The c-string will be copied by TRACE_EVENT_API_ADD_TRACE_EVENT at the end.
81
30
  Utf8Value arg1NameValue(env->isolate(), args[4]);
82
30
  Utf8Value arg2NameValue(env->isolate(), args[6]);
83
84

70
  if (args.Length() >= 6 &&
85

35
      (!args[4]->IsUndefined() || !args[5]->IsUndefined())) {
86
5
    num_args = 1;
87
5
    arg_types[0] = TRACE_VALUE_TYPE_INT;
88
89
15
    CHECK(args[4]->IsString());
90
5
    arg_names[0] = arg1NameValue.out();
91
92
10
    CHECK(args[5]->IsNumber());
93
15
    arg_values[0] = args[5]->IntegerValue(context).ToChecked();
94
  }
95
96

68
  if (args.Length() >= 8 &&
97

31
      (!args[6]->IsUndefined() || !args[7]->IsUndefined())) {
98
4
    num_args = 2;
99
4
    arg_types[1] = TRACE_VALUE_TYPE_INT;
100
101
12
    CHECK(args[6]->IsString());
102
4
    arg_names[1] = arg2NameValue.out();
103
104
8
    CHECK(args[7]->IsNumber());
105
12
    arg_values[1] = args[7]->IntegerValue(context).ToChecked();
106
  }
107
108
  // The TRACE_EVENT_FLAG_COPY flag indicates that the name and argument
109
  // name should be copied thus they don't need to long-lived pointers.
110
  // The category name still won't be copied and thus need to be a long-lived
111
  // pointer.
112
15
  uint32_t flags = TRACE_EVENT_FLAG_COPY;
113
15
  if (has_id) {
114
15
    flags |= TRACE_EVENT_FLAG_HAS_ID;
115
  }
116
117
15
  const char* scope = node::tracing::kGlobalScope;
118
15
  uint64_t bind_id = node::tracing::kNoId;
119
120
  TRACE_EVENT_API_ADD_TRACE_EVENT(
121
    phase, category_group_enabled, name, scope, id, bind_id,
122
    num_args, arg_names, arg_types, arg_values,
123
30
    flags);
124
}
125
126
3350
static void CategoryGroupEnabled(const FunctionCallbackInfo<Value>& args) {
127
3350
  Environment* env = Environment::GetCurrent(args);
128
129
3350
  const char* category_group = GetCategoryGroup(env, args[0]);
130
  const uint8_t* category_group_enabled =
131
3350
    GetCategoryGroupEnabled(category_group);
132
10050
  args.GetReturnValue().Set(*category_group_enabled > 0);
133
3350
}
134
135
3348
void InitializeTraceEvents(Local<Object> target,
136
                           Local<Value> unused,
137
                           Local<Context> context,
138
                           void* priv) {
139
3348
  Environment* env = Environment::GetCurrent(context);
140
141
3348
  env->SetMethod(target, "emit", Emit);
142
3348
  env->SetMethod(target, "categoryGroupEnabled", CategoryGroupEnabled);
143
3348
}
144
145
}  // namespace node
146
147

13564
NODE_BUILTIN_MODULE_CONTEXT_AWARE(trace_events, node::InitializeTraceEvents)