YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/yb/util/trace-test.cc
Line
Count
Source (jump to first uncovered line)
1
// Licensed to the Apache Software Foundation (ASF) under one
2
// or more contributor license agreements.  See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership.  The ASF licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License.  You may obtain a copy of the License at
8
//
9
//   http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied.  See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
//
18
// The following only applies to changes made to this file as part of YugaByte development.
19
//
20
// Portions Copyright (c) YugaByte, Inc.
21
//
22
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
23
// in compliance with the License.  You may obtain a copy of the License at
24
//
25
// http://www.apache.org/licenses/LICENSE-2.0
26
//
27
// Unless required by applicable law or agreed to in writing, software distributed under the License
28
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
29
// or implied.  See the License for the specific language governing permissions and limitations
30
// under the License.
31
//
32
33
#include <string>
34
35
#include <gtest/gtest.h>
36
#include <rapidjson/document.h>
37
#include <rapidjson/rapidjson.h>  // NOLINT
38
39
#include "yb/gutil/casts.h"
40
41
#include "yb/util/debug/trace_event.h"
42
#include "yb/util/debug/trace_event_synthetic_delay.h"
43
#include "yb/util/debug/trace_logging.h"
44
#include "yb/util/status_log.h"
45
#include "yb/util/stopwatch.h"
46
#include "yb/util/test_macros.h"
47
#include "yb/util/test_util.h"
48
#include "yb/util/thread.h"
49
#include "yb/util/trace.h"
50
51
// Need to add rapidjson.h to the list of recognized third-party libraries in our linter.
52
53
54
using yb::debug::TraceLog;
55
using yb::debug::TraceResultBuffer;
56
using yb::debug::CategoryFilter;
57
using rapidjson::Document;
58
using rapidjson::Value;
59
using std::string;
60
using std::vector;
61
62
namespace yb {
63
64
class TraceTest : public YBTest {
65
};
66
67
// Replace all digits in 's' with the character 'X'.
68
4
static string XOutDigits(const string& s) {
69
4
  string ret;
70
4
  ret.reserve(s.size());
71
379
  for (char c : s) {
72
379
    if (isdigit(c)) {
73
122
      ret.push_back('X');
74
257
    } else {
75
257
      ret.push_back(c);
76
257
    }
77
379
  }
78
4
  return ret;
79
4
}
80
81
1
TEST_F(TraceTest, TestBasic) {
82
1
  scoped_refptr<Trace> t(new Trace);
83
1
  TRACE_TO(t, "hello $0, $1", "world", 12345);
84
1
  TRACE_TO(t, "goodbye $0, $1", "cruel world", 54321);
85
86
1
  string result = XOutDigits(t->DumpToString(false));
87
1
  ASSERT_EQ("XXXX XX:XX:XX.XXXXXX trace-test.cc:XX] hello world, XXXXX\n"
88
1
            "XXXX XX:XX:XX.XXXXXX trace-test.cc:XX] goodbye cruel world, XXXXX\n",
89
1
            result);
90
1
}
91
92
1
TEST_F(TraceTest, TestAttach) {
93
1
  scoped_refptr<Trace> traceA(new Trace);
94
1
  scoped_refptr<Trace> traceB(new Trace);
95
1
  {
96
1
    ADOPT_TRACE(traceA.get());
97
1
    EXPECT_EQ(traceA.get(), Trace::CurrentTrace());
98
1
    {
99
1
      ADOPT_TRACE(traceB.get());
100
1
      EXPECT_EQ(traceB.get(), Trace::CurrentTrace());
101
1
      TRACE("hello from traceB");
102
1
    }
103
1
    EXPECT_EQ(traceA.get(), Trace::CurrentTrace());
104
1
    TRACE("hello from traceA");
105
1
  }
106
1
  EXPECT_TRUE(Trace::CurrentTrace() == nullptr);
107
1
  TRACE("this goes nowhere");
108
109
1
  EXPECT_EQ(XOutDigits(traceA->DumpToString(false)),
110
1
            "XXXX XX:XX:XX.XXXXXX trace-test.cc:XXX] hello from traceA\n");
111
1
  EXPECT_EQ(XOutDigits(traceB->DumpToString(false)),
112
1
            "XXXX XX:XX:XX.XXXXXX trace-test.cc:XXX] hello from traceB\n");
113
1
}
114
115
1
TEST_F(TraceTest, TestChildTrace) {
116
1
  scoped_refptr<Trace> traceA(new Trace);
117
1
  scoped_refptr<Trace> traceB(new Trace);
118
1
  ADOPT_TRACE(traceA.get());
119
1
  traceA->AddChildTrace(traceB.get());
120
1
  TRACE("hello from traceA");
121
1
  {
122
1
    ADOPT_TRACE(traceB.get());
123
1
    TRACE("hello from traceB");
124
1
  }
125
1
  EXPECT_EQ("XXXX XX:XX:XX.XXXXXX trace-test.cc:XXX] hello from traceA\n"
126
1
            "..  Related trace:\n"
127
1
            "..  XXXX XX:XX:XX.XXXXXX trace-test.cc:XXX] hello from traceB\n",
128
1
            XOutDigits(traceA->DumpToString(false)));
129
1
}
130
131
static void GenerateTraceEvents(int thread_id,
132
5
                                int num_events) {
133
33.8k
  for (int i = 0; i < num_events; i++) {
134
33.8k
    TRACE_EVENT1("test", "foo", "thread_id", thread_id);
135
33.8k
  }
136
5
}
137
138
// Parse the dumped trace data and return the number of events
139
// found within, including only those with the "test" category.
140
8
int ParseAndReturnEventCount(const string& trace_json) {
141
8
  Document d;
142
8
  d.Parse<0>(trace_json.c_str());
143
0
  CHECK(d.IsObject()) << "bad json: " << trace_json;
144
8
  const Value& events_json = d["traceEvents"];
145
0
  CHECK(events_json.IsArray()) << "bad json: " << trace_json;
146
147
  // Count how many of our events were seen. We have to filter out
148
  // the metadata events.
149
8
  int seen_real_events = 0;
150
58.0k
  for (rapidjson::SizeType i = 0; i < events_json.Size(); i++) {
151
58.0k
    if (events_json[i]["cat"].GetString() == string("test")) {
152
58.0k
      seen_real_events++;
153
58.0k
    }
154
58.0k
  }
155
156
8
  return seen_real_events;
157
8
}
158
159
1
TEST_F(TraceTest, TestChromeTracing) {
160
1
  const int kNumThreads = 4;
161
1
  const int kEventsPerThread = AllowSlowTests() ? 1000000 : 10000;
162
163
1
  TraceLog* tl = TraceLog::GetInstance();
164
1
  tl->SetEnabled(CategoryFilter(CategoryFilter::kDefaultCategoryFilterString),
165
1
                 TraceLog::RECORDING_MODE,
166
1
                 TraceLog::RECORD_CONTINUOUSLY);
167
168
1
  vector<scoped_refptr<Thread> > threads(kNumThreads);
169
170
1
  Stopwatch s;
171
1
  s.start();
172
5
  for (int i = 0; i < kNumThreads; i++) {
173
4
    CHECK_OK(Thread::Create("test", "gen-traces", &GenerateTraceEvents, i, kEventsPerThread,
174
4
                            &threads[i]));
175
4
  }
176
177
5
  for (int i = 0; i < kNumThreads; i++) {
178
4
    threads[i]->Join();
179
4
  }
180
1
  tl->SetDisabled();
181
182
1
  int total_events = kNumThreads * kEventsPerThread;
183
1
  double elapsed = s.elapsed().wall_seconds();
184
185
1
  LOG(INFO) << "Trace performance: " << static_cast<int>(total_events / elapsed) << " traces/sec";
186
187
1
  string trace_json = TraceResultBuffer::FlushTraceLogToString();
188
189
  // Verify that the JSON contains events. It won't have exactly
190
  // kEventsPerThread * kNumThreads because the trace buffer isn't large enough
191
  // for that.
192
1
  ASSERT_GE(ParseAndReturnEventCount(trace_json), 100);
193
1
}
194
195
// Test that, if a thread exits before filling a full trace buffer, we still
196
// see its results. This is a regression test for a bug in the earlier integration
197
// of Chromium tracing into YB.
198
1
TEST_F(TraceTest, TestTraceFromExitedThread) {
199
1
  TraceLog* tl = TraceLog::GetInstance();
200
1
  tl->SetEnabled(CategoryFilter(CategoryFilter::kDefaultCategoryFilterString),
201
1
                 TraceLog::RECORDING_MODE,
202
1
                 TraceLog::RECORD_CONTINUOUSLY);
203
204
  // Generate 10 trace events in a separate thread.
205
1
  int kNumEvents = 10;
206
1
  scoped_refptr<Thread> t;
207
1
  CHECK_OK(Thread::Create("test", "gen-traces", &GenerateTraceEvents, 1, kNumEvents,
208
1
                          &t));
209
1
  t->Join();
210
1
  tl->SetDisabled();
211
1
  string trace_json = TraceResultBuffer::FlushTraceLogToString();
212
1
  LOG(INFO) << trace_json;
213
214
  // Verify that the buffer contains 10 trace events
215
1
  ASSERT_EQ(10, ParseAndReturnEventCount(trace_json));
216
1
}
217
218
1
static void GenerateWideSpan() {
219
1
  TRACE_EVENT0("test", "GenerateWideSpan");
220
1.00k
  for (int i = 0; i < 1000; i++) {
221
1.00k
    TRACE_EVENT0("test", "InnerLoop");
222
1.00k
  }
223
1
}
224
225
// Test creating a trace event which contains many other trace events.
226
// This ensures that we can go back and update a TraceEvent which fell in
227
// a different trace chunk.
228
1
TEST_F(TraceTest, TestWideSpan) {
229
1
  TraceLog* tl = TraceLog::GetInstance();
230
1
  tl->SetEnabled(CategoryFilter(CategoryFilter::kDefaultCategoryFilterString),
231
1
                 TraceLog::RECORDING_MODE,
232
1
                 TraceLog::RECORD_CONTINUOUSLY);
233
234
1
  scoped_refptr<Thread> t;
235
1
  CHECK_OK(Thread::Create("test", "gen-traces", &GenerateWideSpan, &t));
236
1
  t->Join();
237
1
  tl->SetDisabled();
238
239
1
  string trace_json = TraceResultBuffer::FlushTraceLogToString();
240
1
  ASSERT_EQ(1001, ParseAndReturnEventCount(trace_json));
241
1
}
242
243
// Regression test for KUDU-753: faulty JSON escaping when dealing with
244
// single quote characters.
245
1
TEST_F(TraceTest, TestJsonEncodingString) {
246
1
  TraceLog* tl = TraceLog::GetInstance();
247
1
  tl->SetEnabled(CategoryFilter(CategoryFilter::kDefaultCategoryFilterString),
248
1
                 TraceLog::RECORDING_MODE,
249
1
                 TraceLog::RECORD_CONTINUOUSLY);
250
1
  {
251
1
    TRACE_EVENT1("test", "test", "arg", "this is a test with \"'\"' and characters\nand new lines");
252
1
  }
253
1
  tl->SetDisabled();
254
1
  string trace_json = TraceResultBuffer::FlushTraceLogToString();
255
1
  ASSERT_EQ(1, ParseAndReturnEventCount(trace_json));
256
1
}
257
258
// Generate trace events continuously until 'latch' fires.
259
// Increment *num_events_generated for each event generated.
260
void GenerateTracesUntilLatch(AtomicInt<int64_t>* num_events_generated,
261
1
                              CountDownLatch* latch) {
262
4.16M
  while (latch->count()) {
263
4.16M
    {
264
      // This goes in its own scope so that the event is fully generated (with
265
      // both its START and END times) before we do the counter increment below.
266
4.16M
      TRACE_EVENT0("test", "GenerateTracesUntilLatch");
267
4.16M
    }
268
4.16M
    num_events_generated->Increment();
269
4.16M
  }
270
1
}
271
272
// Test starting and stopping tracing while a thread is running.
273
// This is a regression test for bugs in earlier versions of the imported
274
// trace code.
275
1
TEST_F(TraceTest, TestStartAndStopCollection) {
276
1
  TraceLog* tl = TraceLog::GetInstance();
277
278
1
  CountDownLatch latch(1);
279
1
  AtomicInt<int64_t> num_events_generated(0);
280
1
  scoped_refptr<Thread> t;
281
1
  CHECK_OK(Thread::Create("test", "gen-traces", &GenerateTracesUntilLatch,
282
1
                          &num_events_generated, &latch, &t));
283
284
1
  const int num_flushes = AllowSlowTests() ? 50 : 3;
285
4
  for (int i = 0; i < num_flushes; i++) {
286
3
    tl->SetEnabled(CategoryFilter(CategoryFilter::kDefaultCategoryFilterString),
287
3
                   TraceLog::RECORDING_MODE,
288
3
                   TraceLog::RECORD_CONTINUOUSLY);
289
290
3
    const int64_t num_events_before = num_events_generated.Load();
291
3
    SleepFor(MonoDelta::FromMilliseconds(10));
292
3
    const int64_t num_events_after = num_events_generated.Load();
293
3
    tl->SetDisabled();
294
295
3
    string trace_json = TraceResultBuffer::FlushTraceLogToString();
296
    // We might under-count the number of events, since we only measure the sleep,
297
    // and tracing is enabled before and disabled after we start counting.
298
    // We might also over-count by at most 1, because we could enable tracing
299
    // right in between creating a trace event and incrementing the counter.
300
    // But, we should never over-count by more than 1.
301
3
    auto expected_events_lowerbound = num_events_after - num_events_before - 1;
302
3
    int captured_events = ParseAndReturnEventCount(trace_json);
303
3
    ASSERT_GE(captured_events, expected_events_lowerbound);
304
3
  }
305
306
1
  latch.CountDown();
307
1
  t->Join();
308
1
}
309
310
1
TEST_F(TraceTest, TestChromeSampling) {
311
1
  TraceLog* tl = TraceLog::GetInstance();
312
1
  tl->SetEnabled(CategoryFilter(CategoryFilter::kDefaultCategoryFilterString),
313
1
                 TraceLog::RECORDING_MODE,
314
1
                 static_cast<TraceLog::Options>(TraceLog::RECORD_CONTINUOUSLY |
315
1
                                                TraceLog::ENABLE_SAMPLING));
316
317
101
  for (int i = 0; i < 100; i++) {
318
100
    switch (i % 3) {
319
34
      case 0:
320
34
        TRACE_EVENT_SET_SAMPLING_STATE("test", "state-0");
321
34
        break;
322
33
      case 1:
323
33
        TRACE_EVENT_SET_SAMPLING_STATE("test", "state-1");
324
33
        break;
325
33
      case 2:
326
33
        TRACE_EVENT_SET_SAMPLING_STATE("test", "state-2");
327
33
        break;
328
100
    }
329
100
    SleepFor(MonoDelta::FromMilliseconds(1));
330
100
  }
331
1
  tl->SetDisabled();
332
1
  string trace_json = TraceResultBuffer::FlushTraceLogToString();
333
1
  ASSERT_GT(ParseAndReturnEventCount(trace_json), 0);
334
1
}
335
336
class TraceEventCallbackTest : public YBTest {
337
 public:
338
7
  void SetUp() override {
339
7
    YBTest::SetUp();
340
7
    ASSERT_EQ(nullptr, s_instance);
341
7
    s_instance = this;
342
7
  }
343
7
  void TearDown() override {
344
7
    TraceLog::GetInstance()->SetDisabled();
345
346
    // Flush the buffer so that one test doesn't end up leaving any
347
    // extra results for the next test.
348
7
    TraceResultBuffer::FlushTraceLogToString();
349
350
7
    ASSERT_TRUE(!!s_instance);
351
7
    s_instance = nullptr;
352
7
    YBTest::TearDown();
353
354
7
  }
355
356
 protected:
357
5
  void EndTraceAndFlush() {
358
5
    TraceLog::GetInstance()->SetDisabled();
359
5
    string trace_json = TraceResultBuffer::FlushTraceLogToString();
360
5
    trace_doc_.Parse<0>(trace_json.c_str());
361
5
    LOG(INFO) << trace_json;
362
5
    ASSERT_TRUE(trace_doc_.IsObject());
363
5
    trace_parsed_ = trace_doc_["traceEvents"];
364
5
    ASSERT_TRUE(trace_parsed_.IsArray());
365
5
  }
366
367
4
  void DropTracedMetadataRecords() {
368
    // NB: rapidjson has move-semantics, like auto_ptr.
369
4
    Value old_trace_parsed;
370
4
    old_trace_parsed = trace_parsed_;
371
4
    trace_parsed_.SetArray();
372
4
    auto old_trace_parsed_size = old_trace_parsed.Size();
373
374
16
    for (rapidjson::SizeType i = 0; i < old_trace_parsed_size; i++) {
375
12
      Value value;
376
12
      value = old_trace_parsed[i];
377
12
      if (value.GetType() != rapidjson::kObjectType) {
378
0
        trace_parsed_.PushBack(value, trace_doc_.GetAllocator());
379
0
        continue;
380
0
      }
381
12
      string tmp;
382
12
      if (value.HasMember("ph") && strcmp(value["ph"].GetString(), "M") == 0) {
383
4
        continue;
384
4
      }
385
386
8
      trace_parsed_.PushBack(value, trace_doc_.GetAllocator());
387
8
    }
388
4
  }
389
390
  // Search through the given array for any dictionary which has a key
391
  // or value which has 'string_to_match' as a substring.
392
  // Returns the matching dictionary, or NULL.
393
  static const Value* FindTraceEntry(
394
    const Value& trace_parsed,
395
16
    const char* string_to_match) {
396
    // Scan all items
397
16
    auto trace_parsed_count = trace_parsed.Size();
398
32
    for (rapidjson::SizeType i = 0; i < trace_parsed_count; i++) {
399
24
      const Value& value = trace_parsed[i];
400
24
      if (value.GetType() != rapidjson::kObjectType) {
401
0
        continue;
402
0
      }
403
404
24
      for (Value::ConstMemberIterator it = value.MemberBegin();
405
188
           it != value.MemberEnd();
406
172
           ++it) {
407
172
        if (it->name.IsString() && strstr(it->name.GetString(), string_to_match) != nullptr) {
408
0
          return &value;
409
0
        }
410
172
        if (it->value.IsString() && strstr(it->value.GetString(), string_to_match) != nullptr) {
411
8
          return &value;
412
8
        }
413
172
      }
414
24
    }
415
8
    return nullptr;
416
16
  }
417
418
  // For TraceEventCallbackAndRecordingX tests.
419
  void VerifyCallbackAndRecordedEvents(size_t expected_callback_count,
420
4
                                       size_t expected_recorded_count) {
421
    // Callback events.
422
4
    EXPECT_EQ(expected_callback_count, collected_events_names_.size());
423
12
    for (size_t i = 0; i < collected_events_names_.size(); ++i) {
424
8
      EXPECT_EQ("callback", collected_events_categories_[i]);
425
8
      EXPECT_EQ("yes", collected_events_names_[i]);
426
8
    }
427
428
    // Recorded events.
429
4
    EXPECT_EQ(expected_recorded_count, trace_parsed_.Size());
430
4
    EXPECT_TRUE(FindTraceEntry(trace_parsed_, "recording"));
431
4
    EXPECT_FALSE(FindTraceEntry(trace_parsed_, "callback"));
432
4
    EXPECT_TRUE(FindTraceEntry(trace_parsed_, "yes"));
433
4
    EXPECT_FALSE(FindTraceEntry(trace_parsed_, "no"));
434
4
  }
435
436
  void VerifyCollectedEvent(size_t i,
437
                            unsigned phase,
438
                            const string& category,
439
6
                            const string& name) {
440
6
    EXPECT_EQ(phase, collected_events_phases_[i]);
441
6
    EXPECT_EQ(category, collected_events_categories_[i]);
442
6
    EXPECT_EQ(name, collected_events_names_[i]);
443
6
  }
444
445
  Document trace_doc_;
446
  Value trace_parsed_;
447
448
  vector<string> collected_events_categories_;
449
  vector<string> collected_events_names_;
450
  vector<unsigned char> collected_events_phases_;
451
  vector<MicrosecondsInt64> collected_events_timestamps_;
452
453
  static TraceEventCallbackTest* s_instance;
454
  static void Callback(MicrosecondsInt64 timestamp,
455
                       char phase,
456
                       const unsigned char* category_group_enabled,
457
                       const char* name,
458
                       uint64_t id,
459
                       int num_args,
460
                       const char* const arg_names[],
461
                       const unsigned char arg_types[],
462
                       const uint64_t arg_values[],
463
20
                       unsigned char flags) {
464
20
    s_instance->collected_events_phases_.push_back(phase);
465
20
    s_instance->collected_events_categories_.push_back(
466
20
        TraceLog::GetCategoryGroupName(category_group_enabled));
467
20
    s_instance->collected_events_names_.push_back(name);
468
20
    s_instance->collected_events_timestamps_.push_back(timestamp);
469
20
  }
470
};
471
472
TraceEventCallbackTest* TraceEventCallbackTest::s_instance;
473
474
1
TEST_F(TraceEventCallbackTest, TraceEventCallback) {
475
1
  TRACE_EVENT_INSTANT0("all", "before enable", TRACE_EVENT_SCOPE_THREAD);
476
1
  TraceLog::GetInstance()->SetEventCallbackEnabled(
477
1
      CategoryFilter("*"), Callback);
478
1
  TRACE_EVENT_INSTANT0("all", "event1", TRACE_EVENT_SCOPE_GLOBAL);
479
1
  TRACE_EVENT_INSTANT0("all", "event2", TRACE_EVENT_SCOPE_GLOBAL);
480
1
  {
481
1
    TRACE_EVENT0("all", "duration");
482
1
    TRACE_EVENT_INSTANT0("all", "event3", TRACE_EVENT_SCOPE_GLOBAL);
483
1
  }
484
1
  TraceLog::GetInstance()->SetEventCallbackDisabled();
485
1
  TRACE_EVENT_INSTANT0("all", "after callback removed",
486
1
                       TRACE_EVENT_SCOPE_GLOBAL);
487
1
  const auto n = std::min(collected_events_names_.size(), collected_events_phases_.size());
488
6
  for (size_t i = 0; i < n; ++i) {
489
5
    const auto& name = collected_events_names_[i];
490
5
    const auto phase = collected_events_phases_[i];
491
5
    LOG(INFO) << "Collected event #" << i << ": name=" << name << ", phase=" << phase;
492
5
  }
493
494
1
  ASSERT_EQ(5u, collected_events_names_.size());
495
496
1
  EXPECT_EQ("event1", collected_events_names_[0]);
497
1
  EXPECT_EQ(TRACE_EVENT_PHASE_INSTANT, collected_events_phases_[0]);
498
499
1
  EXPECT_EQ("event2", collected_events_names_[1]);
500
1
  EXPECT_EQ(TRACE_EVENT_PHASE_INSTANT, collected_events_phases_[1]);
501
502
1
  EXPECT_EQ("duration", collected_events_names_[2]);
503
1
  EXPECT_EQ(TRACE_EVENT_PHASE_BEGIN, collected_events_phases_[2]);
504
505
1
  EXPECT_EQ("event3", collected_events_names_[3]);
506
1
  EXPECT_EQ(TRACE_EVENT_PHASE_INSTANT, collected_events_phases_[3]);
507
508
1
  EXPECT_EQ("duration", collected_events_names_[4]);
509
1
  EXPECT_EQ(TRACE_EVENT_PHASE_END, collected_events_phases_[4]);
510
511
5
  for (size_t i = 1; i < collected_events_timestamps_.size(); i++) {
512
4
    EXPECT_LE(collected_events_timestamps_[i - 1],
513
4
              collected_events_timestamps_[i]);
514
4
  }
515
1
}
516
517
1
TEST_F(TraceEventCallbackTest, TraceEventCallbackWhileFull) {
518
1
  TraceLog::GetInstance()->SetEnabled(
519
1
      CategoryFilter("*"),
520
1
      TraceLog::RECORDING_MODE,
521
1
      TraceLog::RECORD_UNTIL_FULL);
522
255k
  do {
523
255k
    TRACE_EVENT_INSTANT0("all", "badger badger", TRACE_EVENT_SCOPE_GLOBAL);
524
255k
  } while (!TraceLog::GetInstance()->BufferIsFull());
525
1
  TraceLog::GetInstance()->SetEventCallbackEnabled(CategoryFilter("*"),
526
1
                                                   Callback);
527
1
  TRACE_EVENT_INSTANT0("all", "a snake", TRACE_EVENT_SCOPE_GLOBAL);
528
1
  TraceLog::GetInstance()->SetEventCallbackDisabled();
529
1
  ASSERT_EQ(1u, collected_events_names_.size());
530
1
  EXPECT_EQ("a snake", collected_events_names_[0]);
531
1
}
532
533
// 1: Enable callback, enable recording, disable callback, disable recording.
534
1
TEST_F(TraceEventCallbackTest, TraceEventCallbackAndRecording1) {
535
1
  TRACE_EVENT_INSTANT0("recording", "no", TRACE_EVENT_SCOPE_GLOBAL);
536
1
  TRACE_EVENT_INSTANT0("callback", "no", TRACE_EVENT_SCOPE_GLOBAL);
537
1
  TraceLog::GetInstance()->SetEventCallbackEnabled(CategoryFilter("callback"),
538
1
                                                   Callback);
539
1
  TRACE_EVENT_INSTANT0("recording", "no", TRACE_EVENT_SCOPE_GLOBAL);
540
1
  TRACE_EVENT_INSTANT0("callback", "yes", TRACE_EVENT_SCOPE_GLOBAL);
541
1
  TraceLog::GetInstance()->SetEnabled(
542
1
      CategoryFilter("recording"),
543
1
      TraceLog::RECORDING_MODE,
544
1
      TraceLog::RECORD_UNTIL_FULL);
545
1
  TRACE_EVENT_INSTANT0("recording", "yes", TRACE_EVENT_SCOPE_GLOBAL);
546
1
  TRACE_EVENT_INSTANT0("callback", "yes", TRACE_EVENT_SCOPE_GLOBAL);
547
1
  TraceLog::GetInstance()->SetEventCallbackDisabled();
548
1
  TRACE_EVENT_INSTANT0("recording", "yes", TRACE_EVENT_SCOPE_GLOBAL);
549
1
  TRACE_EVENT_INSTANT0("callback", "no", TRACE_EVENT_SCOPE_GLOBAL);
550
1
  EndTraceAndFlush();
551
1
  TRACE_EVENT_INSTANT0("recording", "no", TRACE_EVENT_SCOPE_GLOBAL);
552
1
  TRACE_EVENT_INSTANT0("callback", "no", TRACE_EVENT_SCOPE_GLOBAL);
553
554
1
  DropTracedMetadataRecords();
555
1
  ASSERT_NO_FATALS();
556
1
  VerifyCallbackAndRecordedEvents(2, 2);
557
1
}
558
559
// 2: Enable callback, enable recording, disable recording, disable callback.
560
1
TEST_F(TraceEventCallbackTest, TraceEventCallbackAndRecording2) {
561
1
  TRACE_EVENT_INSTANT0("recording", "no", TRACE_EVENT_SCOPE_GLOBAL);
562
1
  TRACE_EVENT_INSTANT0("callback", "no", TRACE_EVENT_SCOPE_GLOBAL);
563
1
  TraceLog::GetInstance()->SetEventCallbackEnabled(CategoryFilter("callback"),
564
1
                                                   Callback);
565
1
  TRACE_EVENT_INSTANT0("recording", "no", TRACE_EVENT_SCOPE_GLOBAL);
566
1
  TRACE_EVENT_INSTANT0("callback", "yes", TRACE_EVENT_SCOPE_GLOBAL);
567
1
  TraceLog::GetInstance()->SetEnabled(
568
1
      CategoryFilter("recording"),
569
1
      TraceLog::RECORDING_MODE,
570
1
      TraceLog::RECORD_UNTIL_FULL);
571
1
  TRACE_EVENT_INSTANT0("recording", "yes", TRACE_EVENT_SCOPE_GLOBAL);
572
1
  TRACE_EVENT_INSTANT0("callback", "yes", TRACE_EVENT_SCOPE_GLOBAL);
573
1
  EndTraceAndFlush();
574
1
  TRACE_EVENT_INSTANT0("recording", "no", TRACE_EVENT_SCOPE_GLOBAL);
575
1
  TRACE_EVENT_INSTANT0("callback", "yes", TRACE_EVENT_SCOPE_GLOBAL);
576
1
  TraceLog::GetInstance()->SetEventCallbackDisabled();
577
1
  TRACE_EVENT_INSTANT0("recording", "no", TRACE_EVENT_SCOPE_GLOBAL);
578
1
  TRACE_EVENT_INSTANT0("callback", "no", TRACE_EVENT_SCOPE_GLOBAL);
579
580
1
  DropTracedMetadataRecords();
581
1
  VerifyCallbackAndRecordedEvents(3, 1);
582
1
}
583
584
// 3: Enable recording, enable callback, disable callback, disable recording.
585
1
TEST_F(TraceEventCallbackTest, TraceEventCallbackAndRecording3) {
586
1
  TRACE_EVENT_INSTANT0("recording", "no", TRACE_EVENT_SCOPE_GLOBAL);
587
1
  TRACE_EVENT_INSTANT0("callback", "no", TRACE_EVENT_SCOPE_GLOBAL);
588
1
  TraceLog::GetInstance()->SetEnabled(
589
1
      CategoryFilter("recording"),
590
1
      TraceLog::RECORDING_MODE,
591
1
      TraceLog::RECORD_UNTIL_FULL);
592
1
  TRACE_EVENT_INSTANT0("recording", "yes", TRACE_EVENT_SCOPE_GLOBAL);
593
1
  TRACE_EVENT_INSTANT0("callback", "no", TRACE_EVENT_SCOPE_GLOBAL);
594
1
  TraceLog::GetInstance()->SetEventCallbackEnabled(CategoryFilter("callback"),
595
1
                                                   Callback);
596
1
  TRACE_EVENT_INSTANT0("recording", "yes", TRACE_EVENT_SCOPE_GLOBAL);
597
1
  TRACE_EVENT_INSTANT0("callback", "yes", TRACE_EVENT_SCOPE_GLOBAL);
598
1
  TraceLog::GetInstance()->SetEventCallbackDisabled();
599
1
  TRACE_EVENT_INSTANT0("recording", "yes", TRACE_EVENT_SCOPE_GLOBAL);
600
1
  TRACE_EVENT_INSTANT0("callback", "no", TRACE_EVENT_SCOPE_GLOBAL);
601
1
  EndTraceAndFlush();
602
1
  TRACE_EVENT_INSTANT0("recording", "no", TRACE_EVENT_SCOPE_GLOBAL);
603
1
  TRACE_EVENT_INSTANT0("callback", "no", TRACE_EVENT_SCOPE_GLOBAL);
604
605
1
  DropTracedMetadataRecords();
606
1
  VerifyCallbackAndRecordedEvents(1, 3);
607
1
}
608
609
// 4: Enable recording, enable callback, disable recording, disable callback.
610
1
TEST_F(TraceEventCallbackTest, TraceEventCallbackAndRecording4) {
611
1
  TRACE_EVENT_INSTANT0("recording", "no", TRACE_EVENT_SCOPE_GLOBAL);
612
1
  TRACE_EVENT_INSTANT0("callback", "no", TRACE_EVENT_SCOPE_GLOBAL);
613
1
  TraceLog::GetInstance()->SetEnabled(
614
1
      CategoryFilter("recording"),
615
1
      TraceLog::RECORDING_MODE,
616
1
      TraceLog::RECORD_UNTIL_FULL);
617
1
  TRACE_EVENT_INSTANT0("recording", "yes", TRACE_EVENT_SCOPE_GLOBAL);
618
1
  TRACE_EVENT_INSTANT0("callback", "no", TRACE_EVENT_SCOPE_GLOBAL);
619
1
  TraceLog::GetInstance()->SetEventCallbackEnabled(CategoryFilter("callback"),
620
1
                                                   Callback);
621
1
  TRACE_EVENT_INSTANT0("recording", "yes", TRACE_EVENT_SCOPE_GLOBAL);
622
1
  TRACE_EVENT_INSTANT0("callback", "yes", TRACE_EVENT_SCOPE_GLOBAL);
623
1
  EndTraceAndFlush();
624
1
  TRACE_EVENT_INSTANT0("recording", "no", TRACE_EVENT_SCOPE_GLOBAL);
625
1
  TRACE_EVENT_INSTANT0("callback", "yes", TRACE_EVENT_SCOPE_GLOBAL);
626
1
  TraceLog::GetInstance()->SetEventCallbackDisabled();
627
1
  TRACE_EVENT_INSTANT0("recording", "no", TRACE_EVENT_SCOPE_GLOBAL);
628
1
  TRACE_EVENT_INSTANT0("callback", "no", TRACE_EVENT_SCOPE_GLOBAL);
629
630
1
  DropTracedMetadataRecords();
631
1
  VerifyCallbackAndRecordedEvents(2, 2);
632
1
}
633
634
1
TEST_F(TraceEventCallbackTest, TraceEventCallbackAndRecordingDuration) {
635
1
  TraceLog::GetInstance()->SetEventCallbackEnabled(CategoryFilter("*"),
636
1
                                                   Callback);
637
1
  {
638
1
    TRACE_EVENT0("callback", "duration1");
639
1
    TraceLog::GetInstance()->SetEnabled(
640
1
        CategoryFilter("*"),
641
1
        TraceLog::RECORDING_MODE,
642
1
        TraceLog::RECORD_UNTIL_FULL);
643
1
    TRACE_EVENT0("callback", "duration2");
644
1
    EndTraceAndFlush();
645
1
    TRACE_EVENT0("callback", "duration3");
646
1
  }
647
1
  TraceLog::GetInstance()->SetEventCallbackDisabled();
648
649
1
  ASSERT_EQ(6u, collected_events_names_.size());
650
1
  VerifyCollectedEvent(0, TRACE_EVENT_PHASE_BEGIN, "callback", "duration1");
651
1
  VerifyCollectedEvent(1, TRACE_EVENT_PHASE_BEGIN, "callback", "duration2");
652
1
  VerifyCollectedEvent(2, TRACE_EVENT_PHASE_BEGIN, "callback", "duration3");
653
1
  VerifyCollectedEvent(3, TRACE_EVENT_PHASE_END, "callback", "duration3");
654
1
  VerifyCollectedEvent(4, TRACE_EVENT_PHASE_END, "callback", "duration2");
655
1
  VerifyCollectedEvent(5, TRACE_EVENT_PHASE_END, "callback", "duration1");
656
1
}
657
658
////////////////////////////////////////////////////////////
659
// Tests for synthetic delay
660
// (from chromium-base/debug/trace_event_synthetic_delay_unittest.cc)
661
////////////////////////////////////////////////////////////
662
663
namespace {
664
665
const int kTargetDurationMs = 100;
666
// Allow some leeway in timings to make it possible to run these tests with a
667
// wall clock time source too.
668
const int kShortDurationMs = 10;
669
670
}  // namespace
671
672
namespace debug {
673
674
class TraceEventSyntheticDelayTest : public YBTest,
675
                                     public TraceEventSyntheticDelayClock {
676
 public:
677
10
  TraceEventSyntheticDelayTest() {
678
10
    now_ = MonoTime::Min();
679
10
  }
680
681
10
  virtual ~TraceEventSyntheticDelayTest() {
682
10
    ResetTraceEventSyntheticDelays();
683
10
  }
684
685
  // TraceEventSyntheticDelayClock implementation.
686
1.05k
  MonoTime Now() override {
687
1.05k
    AdvanceTime(MonoDelta::FromMilliseconds(kShortDurationMs / 10));
688
1.05k
    return now_;
689
1.05k
  }
690
691
10
  TraceEventSyntheticDelay* ConfigureDelay(const char* name) {
692
10
    TraceEventSyntheticDelay* delay = TraceEventSyntheticDelay::Lookup(name);
693
10
    delay->SetClock(this);
694
10
    delay->SetTargetDuration(
695
10
      MonoDelta::FromMilliseconds(kTargetDurationMs));
696
10
    return delay;
697
10
  }
698
699
1.05k
  void AdvanceTime(MonoDelta delta) { now_.AddDelta(delta); }
700
701
9
  int TestFunction() {
702
9
    MonoTime start = Now();
703
9
    { TRACE_EVENT_SYNTHETIC_DELAY("test.Delay"); }
704
9
    MonoTime end = Now();
705
9
    return narrow_cast<int>(end.GetDeltaSince(start).ToMilliseconds());
706
9
  }
707
708
6
  int AsyncTestFunctionBegin() {
709
6
    MonoTime start = Now();
710
6
    { TRACE_EVENT_SYNTHETIC_DELAY_BEGIN("test.AsyncDelay"); }
711
6
    MonoTime end = Now();
712
6
    return narrow_cast<int>(end.GetDeltaSince(start).ToMilliseconds());
713
6
  }
714
715
8
  int AsyncTestFunctionEnd() {
716
8
    MonoTime start = Now();
717
8
    { TRACE_EVENT_SYNTHETIC_DELAY_END("test.AsyncDelay"); }
718
8
    MonoTime end = Now();
719
8
    return narrow_cast<int>(end.GetDeltaSince(start).ToMilliseconds());
720
8
  }
721
722
 private:
723
  MonoTime now_;
724
725
  DISALLOW_COPY_AND_ASSIGN(TraceEventSyntheticDelayTest);
726
};
727
728
1
TEST_F(TraceEventSyntheticDelayTest, StaticDelay) {
729
1
  TraceEventSyntheticDelay* delay = ConfigureDelay("test.Delay");
730
1
  delay->SetMode(TraceEventSyntheticDelay::STATIC);
731
1
  EXPECT_GE(TestFunction(), kTargetDurationMs);
732
1
}
733
734
1
TEST_F(TraceEventSyntheticDelayTest, OneShotDelay) {
735
1
  TraceEventSyntheticDelay* delay = ConfigureDelay("test.Delay");
736
1
  delay->SetMode(TraceEventSyntheticDelay::ONE_SHOT);
737
1
  EXPECT_GE(TestFunction(), kTargetDurationMs);
738
1
  EXPECT_LT(TestFunction(), kShortDurationMs);
739
740
1
  delay->SetTargetDuration(
741
1
      MonoDelta::FromMilliseconds(kTargetDurationMs));
742
1
  EXPECT_GE(TestFunction(), kTargetDurationMs);
743
1
}
744
745
1
TEST_F(TraceEventSyntheticDelayTest, AlternatingDelay) {
746
1
  TraceEventSyntheticDelay* delay = ConfigureDelay("test.Delay");
747
1
  delay->SetMode(TraceEventSyntheticDelay::ALTERNATING);
748
1
  EXPECT_GE(TestFunction(), kTargetDurationMs);
749
1
  EXPECT_LT(TestFunction(), kShortDurationMs);
750
1
  EXPECT_GE(TestFunction(), kTargetDurationMs);
751
1
  EXPECT_LT(TestFunction(), kShortDurationMs);
752
1
}
753
754
1
TEST_F(TraceEventSyntheticDelayTest, AsyncDelay) {
755
1
  ConfigureDelay("test.AsyncDelay");
756
1
  EXPECT_LT(AsyncTestFunctionBegin(), kShortDurationMs);
757
1
  EXPECT_GE(AsyncTestFunctionEnd(), kTargetDurationMs / 2);
758
1
}
759
760
1
TEST_F(TraceEventSyntheticDelayTest, AsyncDelayExceeded) {
761
1
  ConfigureDelay("test.AsyncDelay");
762
1
  EXPECT_LT(AsyncTestFunctionBegin(), kShortDurationMs);
763
1
  AdvanceTime(MonoDelta::FromMilliseconds(kTargetDurationMs));
764
1
  EXPECT_LT(AsyncTestFunctionEnd(), kShortDurationMs);
765
1
}
766
767
1
TEST_F(TraceEventSyntheticDelayTest, AsyncDelayNoActivation) {
768
1
  ConfigureDelay("test.AsyncDelay");
769
1
  EXPECT_LT(AsyncTestFunctionEnd(), kShortDurationMs);
770
1
}
771
772
1
TEST_F(TraceEventSyntheticDelayTest, AsyncDelayNested) {
773
1
  ConfigureDelay("test.AsyncDelay");
774
1
  EXPECT_LT(AsyncTestFunctionBegin(), kShortDurationMs);
775
1
  EXPECT_LT(AsyncTestFunctionBegin(), kShortDurationMs);
776
1
  EXPECT_LT(AsyncTestFunctionEnd(), kShortDurationMs);
777
1
  EXPECT_GE(AsyncTestFunctionEnd(), kTargetDurationMs / 2);
778
1
}
779
780
1
TEST_F(TraceEventSyntheticDelayTest, AsyncDelayUnbalanced) {
781
1
  ConfigureDelay("test.AsyncDelay");
782
1
  EXPECT_LT(AsyncTestFunctionBegin(), kShortDurationMs);
783
1
  EXPECT_GE(AsyncTestFunctionEnd(), kTargetDurationMs / 2);
784
1
  EXPECT_LT(AsyncTestFunctionEnd(), kShortDurationMs);
785
786
1
  EXPECT_LT(AsyncTestFunctionBegin(), kShortDurationMs);
787
1
  EXPECT_GE(AsyncTestFunctionEnd(), kTargetDurationMs / 2);
788
1
}
789
790
1
TEST_F(TraceEventSyntheticDelayTest, ResetDelays) {
791
1
  ConfigureDelay("test.Delay");
792
1
  ResetTraceEventSyntheticDelays();
793
1
  EXPECT_LT(TestFunction(), kShortDurationMs);
794
1
}
795
796
1
TEST_F(TraceEventSyntheticDelayTest, BeginParallel) {
797
1
  TraceEventSyntheticDelay* delay = ConfigureDelay("test.AsyncDelay");
798
1
  MonoTime end_times[2];
799
1
  MonoTime start_time = Now();
800
801
1
  delay->BeginParallel(&end_times[0]);
802
1
  EXPECT_FALSE(!end_times[0].Initialized());
803
804
1
  delay->BeginParallel(&end_times[1]);
805
1
  EXPECT_FALSE(!end_times[1].Initialized());
806
807
1
  delay->EndParallel(end_times[0]);
808
1
  EXPECT_GE(Now().GetDeltaSince(start_time).ToMilliseconds(), kTargetDurationMs);
809
810
1
  start_time = Now();
811
1
  delay->EndParallel(end_times[1]);
812
1
  EXPECT_LT(Now().GetDeltaSince(start_time).ToMilliseconds(), kShortDurationMs);
813
1
}
814
815
1
TEST_F(TraceTest, TestVLogTrace) {
816
3
  for (FLAGS_v = 0; FLAGS_v <= 1; FLAGS_v++) {
817
2
    TraceLog* tl = TraceLog::GetInstance();
818
2
    tl->SetEnabled(CategoryFilter(CategoryFilter::kDefaultCategoryFilterString),
819
2
                   TraceLog::RECORDING_MODE,
820
2
                   TraceLog::RECORD_CONTINUOUSLY);
821
2
    VLOG_AND_TRACE("test", 1) << "hello world";
822
2
    tl->SetDisabled();
823
2
    string trace_json = TraceResultBuffer::FlushTraceLogToString();
824
2
    ASSERT_STR_CONTAINS(trace_json, "hello world");
825
2
    ASSERT_STR_CONTAINS(trace_json, "trace-test.cc");
826
2
  }
827
1
}
828
829
namespace {
830
1
string FunctionWithSideEffect(bool* b) {
831
1
  *b = true;
832
1
  return "function-result";
833
1
}
834
} // anonymous namespace
835
836
// Test that, if tracing is not enabled, a VLOG_AND_TRACE doesn't evaluate its
837
// arguments.
838
1
TEST_F(TraceTest, TestVLogTraceLazyEvaluation) {
839
1
  FLAGS_v = 0;
840
1
  bool function_run = false;
841
1
  VLOG_AND_TRACE("test", 1) << FunctionWithSideEffect(&function_run);
842
1
  ASSERT_FALSE(function_run);
843
844
  // If we enable verbose logging, we should run the side effect even though
845
  // trace logging is disabled.
846
1
  FLAGS_v = 1;
847
1
  VLOG_AND_TRACE("test", 1) << FunctionWithSideEffect(&function_run);
848
1
  ASSERT_TRUE(function_run);
849
1
}
850
851
1
TEST_F(TraceTest, TestVLogAndEchoToConsole) {
852
1
  TraceLog* tl = TraceLog::GetInstance();
853
1
  tl->SetEnabled(CategoryFilter(CategoryFilter::kDefaultCategoryFilterString),
854
1
                 TraceLog::RECORDING_MODE,
855
1
                 TraceLog::ECHO_TO_CONSOLE);
856
1
  FLAGS_v = 1;
857
1
  VLOG_AND_TRACE("test", 1) << "hello world";
858
1
  tl->SetDisabled();
859
1
}
860
861
} // namespace debug
862
} // namespace yb