summaryrefslogtreecommitdiff
path: root/chromium/components/heap_profiling/test_driver.h
blob: f897c67204e7024412d8074def241c70c9b98512 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef COMPONENTS_HEAP_PROFILING_TEST_DRIVER_H_
#define COMPONENTS_HEAP_PROFILING_TEST_DRIVER_H_

#include <vector>

#include "base/allocator/partition_allocator/partition_alloc.h"
#include "base/macros.h"
#include "base/memory/ref_counted_memory.h"
#include "base/synchronization/waitable_event.h"
#include "components/services/heap_profiling/public/mojom/heap_profiling_client.mojom.h"

namespace base {
class Value;
}  // namespace base

namespace heap_profiling {

enum class Mode;

// This class runs tests for the Heap Profiling Service, a cross-platform,
// multi-process component.
//
// Chrome on Android does not support browser_tests. It does support
// content_browsertests, but those are not multi-process tests. On Android,
// processes have to be started via the Activity mechanism, and the test
// infrastructure does not support this.
//
// To avoid test-code duplication, all tests are pulled into this class.
// browser_tests will directly call this class. The android
// chrome_public_test_apk will invoke this class via a JNI shim. Since the
// latter is not running within the gtest framework, this class cannot use
// EXPECT* and ASSERT* macros. Instead, this class will return a bool indicating
// success of the entire test. On failure, errors will be output via LOG(ERROR).
// These will show up in the browser_tests output stream, and will be captured
// by logcat [the Android logging facility]. The latter is already the canonical
// mechanism for investigating test failures.
//
// Note: Outputting to stderr will not have the desired effect, since that is
// not captured by logcat.
class TestDriver {
 public:
  struct Options {
    // The profiling mode to test.
    Mode mode;

    // The stack profiling mode to test.
    mojom::StackMode stack_mode;

    // Whether the caller has already started profiling with the given mode.
    // When false, the test driver is responsible for starting profiling.
    bool profiling_already_started;

    // Whether to test sampling.
    bool should_sample;

    // When set to true, the internal sampling_rate is set to 2. While this
    // doesn't record all allocations, it should record all test allocations
    // made in this file with exponentially high probability.
    // When set to false, the internal sampling rate is set to 10000.
    bool sample_everything;
  };

  TestDriver();
  ~TestDriver();

  // If this is called on the content::BrowserThread::UI thread, then the
  // platform must support nested message loops. [This is currently not
  // supported on Android].
  //
  // Returns whether the test run was successful. Expectation/Assertion failures
  // will be printed via LOG(ERROR).
  bool RunTest(const Options& options);

 private:
  // Populates |has_started_| and then signals |wait_for_ui_thread_|.
  void GetHasStartedOnUIThread();

  // Populates |initialization_success_| with the result of
  // |RunInitializationOnUIThread|, and then signals |wait_for_ui_thread_|.
  void CheckOrStartProfilingOnUIThreadAndSignal();

  // Calls Supervisor::SetKeepSmallAllocations() and then signals
  // |wait_for_ui_thread_|.
  void SetKeepSmallAllocationsOnUIThreadAndSignal();

  // If profiling is expected to already be started, confirm it.
  // Otherwise, start profiling with the given mode.
  // This method must only be called on platforms that supported nested run
  // loops on the UI thread.
  bool CheckOrStartProfilingOnUIThreadWithNestedRunLoops();

  // If profiling is expected to already be started, confirm it.
  // Otherwise, start profiling with the given mode.
  // This method must only be called on platforms that are running the
  // TestDriver from a non-UI thread, which allows for async signalling.
  bool CheckOrStartProfilingOnUIThreadWithAsyncSignalling();

  // Performs allocations. These are expected to be profiled.
  void MakeTestAllocations();

  // Collects a trace that contains a heap dump. The result is stored in
  // |serialized_trace_|.
  //
  // When |synchronous| is true, this method spins a nested message loop. When
  // |synchronous| is false, this method posts some tasks that will eventually
  // signal |wait_for_ui_thread_|.
  void CollectResults(bool synchronous);

  void TraceFinished(base::Closure closure,
                     bool success,
                     std::string trace_json);

  bool ValidateBrowserAllocations(base::Value* dump_json);
  bool ValidateRendererAllocations(base::Value* dump_json);

  bool ShouldProfileBrowser();
  bool ShouldProfileRenderer();
  bool ShouldIncludeNativeThreadNames();
  bool HasPseudoFrames();
  bool HasNativeFrames();
  bool IsRecordingAllAllocations();

  void WaitForProfilingToStartForAllRenderersUIThread();

  // Android does not support nested RunLoops. Instead, it signals
  // |wait_for_ui_thread_| when finished.
  void WaitForProfilingToStartForAllRenderersUIThreadAndSignal();
  void WaitForProfilingToStartForAllRenderersUIThreadCallback(
      std::vector<base::ProcessId> results);

  Options options_;

  // Allocations made by this class. Intentionally leaked, since deallocating
  // them would trigger a large number of IPCs, which is slow.
  std::vector<char*> leaks_;

  // Sum of size of all variadic allocations.
  size_t total_variadic_allocations_ = 0;

  // Use to make PA allocations, which should also be shimmed.
  base::PartitionAllocatorGeneric partition_allocator_;

  // Contains nothing until |CollectResults| has been called.
  std::string serialized_trace_;

  // Whether the test was invoked on the ui thread.
  bool running_on_ui_thread_ = true;

  // Whether the supervisor has started.
  bool has_started_ = false;

  // Whether an error has occurred.
  bool initialization_success_ = false;

  // When |true|, initialization will wait for the allocator shim to enable
  // before continuing.
  bool wait_for_profiling_to_start_ = false;

  base::WaitableEvent wait_for_ui_thread_;

  DISALLOW_COPY_AND_ASSIGN(TestDriver);
};

}  // namespace heap_profiling

#endif  // COMPONENTS_HEAP_PROFILING_TEST_DRIVER_H_