1 : // Copyright 2014 Google Inc. All Rights Reserved.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 :
15 : #include "syzygy/agent/memprof/memory_profiler.h"
16 :
17 : #include "base/bind.h"
18 : #include "syzygy/agent/common/process_utils.h"
19 :
20 m : namespace agent {
21 m : namespace memprof {
22 :
23 m : MemoryProfiler::MemoryProfiler()
24 m : : function_call_logger_(&session_) {
25 m : SetDefaultParameters(¶meters_);
26 m : }
27 :
28 m : bool MemoryProfiler::Init() {
29 : // We don't care if parameter parsing fails at runtime; such parameters will
30 : // simply be ignored.
31 m : ParseParametersFromEnv(¶meters_);
32 m : PropagateParameters();
33 m : ThreadState* state = GetOrAllocateThreadState();
34 m : if (!trace::client::InitializeRpcSession(
35 m : &session_, state->segment())) {
36 m : return false;
37 m : }
38 :
39 : // Setup the DLL watcher. This will be notified of module load and unload
40 : // events as they occur.
41 m : dll_watcher_.Init(base::Bind(&MemoryProfiler::OnDllEvent,
42 m : base::Unretained(this)));
43 :
44 : // Log all modules that are already loaded when we are. Further modules
45 : // will be logged as they load and unload via the DllNotification
46 : // mechanism.
47 m : LogAllModules();
48 :
49 m : return true;
50 m : }
51 :
52 m : MemoryProfiler::ThreadState* MemoryProfiler::GetOrAllocateThreadState() {
53 m : ThreadState* data = GetOrAllocateThreadStateImpl();
54 m : if (!data->segment()->write_ptr && session_.IsTracing())
55 m : session_.AllocateBuffer(data->segment());
56 :
57 m : return data;
58 m : }
59 :
60 m : MemoryProfiler::ThreadState* MemoryProfiler::GetThreadState() {
61 m : return tls_.Get();
62 m : }
63 :
64 m : void MemoryProfiler::PropagateParameters() {
65 m : function_call_logger_.set_stack_trace_tracking(
66 m : parameters_.stack_trace_tracking);
67 m : function_call_logger_.set_serialize_timestamps(
68 m : parameters_.serialize_timestamps);
69 m : }
70 :
71 m : MemoryProfiler::ThreadState* MemoryProfiler::GetOrAllocateThreadStateImpl() {
72 m : ThreadState *data = tls_.Get();
73 m : if (data != NULL)
74 m : return data;
75 :
76 m : data = new ThreadState(this);
77 m : if (data == NULL) {
78 m : LOG(ERROR) << "Unable to allocate per-thread data";
79 m : return NULL;
80 m : }
81 :
82 m : thread_state_manager_.Register(data);
83 m : tls_.Set(data);
84 :
85 m : return data;
86 m : }
87 :
88 m : void MemoryProfiler::LogAllModules() {
89 m : agent::common::ModuleVector modules;
90 m : agent::common::GetProcessModules(&modules);
91 :
92 m : for (size_t i = 0; i < modules.size(); ++i) {
93 m : DCHECK(modules[i] != NULL);
94 m : LogModule(modules[i]);
95 m : }
96 :
97 : // We need to flush module events right away, so that the module is
98 : // defined in the trace file before events using that module start to
99 : // occur.
100 m : GetOrAllocateThreadState()->FlushSegment();
101 m : }
102 :
103 m : void MemoryProfiler::LogModule(HMODULE module) {
104 m : {
105 m : base::AutoLock lock(lock_);
106 m : bool inserted = logged_modules_.insert(module).second;
107 m : if (!inserted)
108 m : return;
109 m : }
110 :
111 m : ThreadState* state = GetOrAllocateThreadState();
112 m : agent::common::LogModule(module, &session_, state->segment());
113 m : }
114 :
115 m : void MemoryProfiler::OnDllEvent(
116 m : agent::common::DllNotificationWatcher::EventType type,
117 m : HMODULE module,
118 m : size_t module_size,
119 m : const base::StringPiece16& dll_path,
120 m : const base::StringPiece16& dll_base_name) {
121 m : switch (type) {
122 m : case agent::common::DllNotificationWatcher::kDllLoaded: {
123 m : LogModule(module);
124 m : break;
125 m : }
126 :
127 m : case agent::common::DllNotificationWatcher::kDllUnloaded: {
128 m : base::AutoLock lock(lock_);
129 m : logged_modules_.erase(module);
130 m : break;
131 m : }
132 m : }
133 :
134 m : return;
135 m : }
136 :
137 m : MemoryProfiler::ThreadState::ThreadState(MemoryProfiler* parent)
138 m : : parent_(parent) {
139 m : DCHECK_NE(static_cast<MemoryProfiler*>(nullptr), parent);
140 m : }
141 :
142 m : bool MemoryProfiler::ThreadState::FlushSegment() {
143 m : if (!parent_->session_.ExchangeBuffer(&segment_))
144 m : return false;
145 m : return true;
146 m : }
147 :
148 m : } // namespace memprof
149 m : } // namespace agent
|