blob: ff828a3d75f68650ac1d0c4c826aeaa96a023c96 [file] [log] [blame]
jeffhaoe343b762011-12-05 16:36:44 -08001// Copyright 2011 Google Inc. All Rights Reserved.
2
3#include "trace.h"
4
jeffhaoa9ef3fd2011-12-13 18:33:43 -08005#include <sys/uio.h>
6
jeffhaoe343b762011-12-05 16:36:44 -08007#include "class_linker.h"
jeffhaoa9ef3fd2011-12-13 18:33:43 -08008#include "debugger.h"
jeffhaoe343b762011-12-05 16:36:44 -08009#include "dex_cache.h"
jeffhaoa9ef3fd2011-12-13 18:33:43 -080010#include "object_utils.h"
11#include "os.h"
jeffhaoe343b762011-12-05 16:36:44 -080012#include "runtime_support.h"
13#include "thread.h"
14
jeffhao2692b572011-12-16 15:42:28 -080015
16namespace art {
17
jeffhaoa9ef3fd2011-12-13 18:33:43 -080018static const uint32_t kTraceMethodActionMask = 0x03; // two bits
19static const char kTraceTokenChar = '*';
20static const uint16_t kTraceHeaderLength = 32;
21static const uint32_t kTraceMagicValue = 0x574f4c53;
22static const uint16_t kTraceVersionSingleClock = 2;
23static const uint16_t kTraceVersionDualClock = 3;
24static const uint16_t kTraceRecordSizeSingleClock = 10; // using v2
25static const uint16_t kTraceRecordSizeDualClock = 14; // using v3 with two timestamps
26
27static inline uint32_t TraceMethodId(uint32_t methodValue) {
28 return (methodValue & ~kTraceMethodActionMask);
29}
30static inline uint32_t TraceMethodCombine(uint32_t method, uint8_t traceEvent) {
31 return (method | traceEvent);
32}
33
jeffhaoa9ef3fd2011-12-13 18:33:43 -080034bool UseThreadCpuClock() {
35 // TODO: Allow control over which clock is used
36 return true;
37}
38
39bool UseWallClock() {
40 // TODO: Allow control over which clock is used
41 return true;
42}
43
44void MeasureClockOverhead() {
45 if (UseThreadCpuClock()) {
46 ThreadCpuMicroTime();
47 }
48 if (UseWallClock()) {
49 MicroTime();
50 }
51}
52
53uint32_t GetClockOverhead() {
54 uint64_t start = ThreadCpuMicroTime();
55
56 for (int i = 4000; i > 0; i--) {
57 MeasureClockOverhead();
58 MeasureClockOverhead();
59 MeasureClockOverhead();
60 MeasureClockOverhead();
61 MeasureClockOverhead();
62 MeasureClockOverhead();
63 MeasureClockOverhead();
64 MeasureClockOverhead();
65 }
66
67 uint64_t elapsed = ThreadCpuMicroTime() - start;
68 return uint32_t (elapsed / 32);
69}
70
71void Append2LE(uint8_t* buf, uint16_t val) {
72 *buf++ = (uint8_t) val;
73 *buf++ = (uint8_t) (val >> 8);
74}
75
76void Append4LE(uint8_t* buf, uint32_t val) {
77 *buf++ = (uint8_t) val;
78 *buf++ = (uint8_t) (val >> 8);
79 *buf++ = (uint8_t) (val >> 16);
80 *buf++ = (uint8_t) (val >> 24);
81}
82
83void Append8LE(uint8_t* buf, uint64_t val) {
84 *buf++ = (uint8_t) val;
85 *buf++ = (uint8_t) (val >> 8);
86 *buf++ = (uint8_t) (val >> 16);
87 *buf++ = (uint8_t) (val >> 24);
88 *buf++ = (uint8_t) (val >> 32);
89 *buf++ = (uint8_t) (val >> 40);
90 *buf++ = (uint8_t) (val >> 48);
91 *buf++ = (uint8_t) (val >> 56);
92}
93
jeffhaoe343b762011-12-05 16:36:44 -080094#if defined(__arm__)
95static bool InstallStubsClassVisitor(Class* klass, void* trace_stub) {
jeffhao2692b572011-12-16 15:42:28 -080096 Trace* tracer = Runtime::Current()->GetTracer();
jeffhaoe343b762011-12-05 16:36:44 -080097 for (size_t i = 0; i < klass->NumDirectMethods(); i++) {
98 Method* method = klass->GetDirectMethod(i);
99 if (method->GetCode() != trace_stub) {
jeffhao2692b572011-12-16 15:42:28 -0800100 tracer->SaveAndUpdateCode(method, trace_stub);
jeffhaoe343b762011-12-05 16:36:44 -0800101 }
102 }
103
104 for (size_t i = 0; i < klass->NumVirtualMethods(); i++) {
105 Method* method = klass->GetVirtualMethod(i);
106 if (method->GetCode() != trace_stub) {
jeffhao2692b572011-12-16 15:42:28 -0800107 tracer->SaveAndUpdateCode(method, trace_stub);
jeffhaoe343b762011-12-05 16:36:44 -0800108 }
109 }
110
111 if (!klass->IsArrayClass() && !klass->IsPrimitive()) {
112 CodeAndDirectMethods* c_and_dm = klass->GetDexCache()->GetCodeAndDirectMethods();
113 for (size_t i = 0; i < c_and_dm->NumCodeAndDirectMethods(); i++) {
114 Method* method = c_and_dm->GetResolvedMethod(i);
115 if (method != NULL && (size_t) method != i) {
116 c_and_dm->SetResolvedDirectMethodTraceEntry(i, trace_stub);
117 }
118 }
119 }
120 return true;
121}
122
123static bool UninstallStubsClassVisitor(Class* klass, void* trace_stub) {
jeffhao2692b572011-12-16 15:42:28 -0800124 Trace* tracer = Runtime::Current()->GetTracer();
jeffhaoe343b762011-12-05 16:36:44 -0800125 for (size_t i = 0; i < klass->NumDirectMethods(); i++) {
126 Method* method = klass->GetDirectMethod(i);
jeffhao2692b572011-12-16 15:42:28 -0800127 if (tracer->GetSavedCodeFromMap(method) != NULL) {
128 tracer->ResetSavedCode(method);
jeffhaoe343b762011-12-05 16:36:44 -0800129 }
130 }
131
132 for (size_t i = 0; i < klass->NumVirtualMethods(); i++) {
133 Method* method = klass->GetVirtualMethod(i);
jeffhao2692b572011-12-16 15:42:28 -0800134 if (tracer->GetSavedCodeFromMap(method) != NULL) {
135 tracer->ResetSavedCode(method);
jeffhaoe343b762011-12-05 16:36:44 -0800136 }
137 }
138
139 if (!klass->IsArrayClass() && !klass->IsPrimitive()) {
140 CodeAndDirectMethods* c_and_dm = klass->GetDexCache()->GetCodeAndDirectMethods();
141 for (size_t i = 0; i < c_and_dm->NumCodeAndDirectMethods(); i++) {
142 const void* code = c_and_dm->GetResolvedCode(i);
143 if (code == trace_stub) {
144 Method* method = klass->GetDexCache()->GetResolvedMethod(i);
jeffhao2692b572011-12-16 15:42:28 -0800145 if (tracer->GetSavedCodeFromMap(method) != NULL) {
146 tracer->ResetSavedCode(method);
jeffhaoe343b762011-12-05 16:36:44 -0800147 }
148 c_and_dm->SetResolvedDirectMethod(i, method);
149 }
150 }
151 }
152 return true;
153}
154
155static void TraceRestoreStack(Thread* t, void*) {
156 uintptr_t trace_exit = reinterpret_cast<uintptr_t>(art_trace_exit_from_code);
157
158 Frame frame = t->GetTopOfStack();
159 if (frame.GetSP() != 0) {
160 for ( ; frame.GetMethod() != 0; frame.Next()) {
161 if (t->IsTraceStackEmpty()) {
162 break;
163 }
164 uintptr_t pc = frame.GetReturnPC();
165 Method* method = frame.GetMethod();
166 if (trace_exit == pc) {
167 TraceStackFrame trace_frame = t->PopTraceStackFrame();
168 frame.SetReturnPC(trace_frame.return_pc_);
169 CHECK(method == trace_frame.method_);
170 }
171 }
172 }
173}
174#endif
175
jeffhaoe343b762011-12-05 16:36:44 -0800176void Trace::AddSavedCodeToMap(const Method* method, const void* code) {
177 saved_code_map_.insert(std::make_pair(method, code));
178}
179
180void Trace::RemoveSavedCodeFromMap(const Method* method) {
181 saved_code_map_.erase(method);
182}
183
184const void* Trace::GetSavedCodeFromMap(const Method* method) {
jeffhao2692b572011-12-16 15:42:28 -0800185 typedef std::map<const Method*, const void*>::const_iterator It; // TODO: C++0x auto
186 It it = saved_code_map_.find(method);
187 if (it == saved_code_map_.end()) {
188 return NULL;
189 } else {
190 return it->second;
191 }
jeffhaoe343b762011-12-05 16:36:44 -0800192}
193
194void Trace::SaveAndUpdateCode(Method* method, const void* new_code) {
195 CHECK(GetSavedCodeFromMap(method) == NULL);
196 AddSavedCodeToMap(method, method->GetCode());
197 method->SetCode(new_code);
198}
199
200void Trace::ResetSavedCode(Method* method) {
201 CHECK(GetSavedCodeFromMap(method) != NULL);
202 method->SetCode(GetSavedCodeFromMap(method));
203 RemoveSavedCodeFromMap(method);
204}
205
jeffhaoe343b762011-12-05 16:36:44 -0800206void Trace::Start(const char* trace_filename, int trace_fd, int buffer_size, int flags, bool direct_to_ddms) {
jeffhao2692b572011-12-16 15:42:28 -0800207 if (Runtime::Current()->IsMethodTracingActive()) {
jeffhaoa9ef3fd2011-12-13 18:33:43 -0800208 LOG(INFO) << "Trace already in progress, ignoring this request";
jeffhaoe343b762011-12-05 16:36:44 -0800209 return;
210 }
211
jeffhaoa9ef3fd2011-12-13 18:33:43 -0800212 ScopedThreadStateChange tsc(Thread::Current(), Thread::kRunnable);
213 Runtime::Current()->GetThreadList()->SuspendAll(false);
214
jeffhao2692b572011-12-16 15:42:28 -0800215 // Open trace file if not going directly to ddms.
216 File* trace_file = NULL;
jeffhaoa9ef3fd2011-12-13 18:33:43 -0800217 if (!direct_to_ddms) {
218 if (trace_fd < 0) {
jeffhao2692b572011-12-16 15:42:28 -0800219 trace_file = OS::OpenFile(trace_filename, true);
jeffhaoa9ef3fd2011-12-13 18:33:43 -0800220 } else {
jeffhao2692b572011-12-16 15:42:28 -0800221 trace_file = OS::FileFromFd("tracefile", trace_fd);
jeffhaoa9ef3fd2011-12-13 18:33:43 -0800222 }
jeffhao2692b572011-12-16 15:42:28 -0800223 if (trace_file == NULL) {
jeffhaoa9ef3fd2011-12-13 18:33:43 -0800224 PLOG(ERROR) << "Unable to open trace file '" << trace_filename;
225 Thread::Current()->ThrowNewException("Ljava/lang/RuntimeException;",
226 StringPrintf("Unable to open trace file '%s'", trace_filename).c_str());
227 Runtime::Current()->GetThreadList()->ResumeAll(false);
228 return;
229 }
230 }
jeffhaoa9ef3fd2011-12-13 18:33:43 -0800231
jeffhao2692b572011-12-16 15:42:28 -0800232 // Create Trace object.
233 Trace* tracer(new Trace(trace_file, buffer_size));
234 Runtime::Current()->EnableMethodTracing(tracer);
235 tracer->BeginTracing();
236
237 Runtime::Current()->GetThreadList()->ResumeAll(false);
238}
239
240void Trace::Stop() {
241 if (!Runtime::Current()->IsMethodTracingActive()) {
242 LOG(INFO) << "Trace stop requested, but no trace currently running";
243 return;
244 }
245
246 ScopedThreadStateChange tsc(Thread::Current(), Thread::kRunnable);
247 Runtime::Current()->GetThreadList()->SuspendAll(false);
248
249 Runtime::Current()->GetTracer()->FinishTracing();
250 Runtime::Current()->DisableMethodTracing();
251
252 Runtime::Current()->GetThreadList()->ResumeAll(false);
253}
254
255void Trace::BeginTracing() {
256 // Set the start time of tracing.
jeffhaoa9ef3fd2011-12-13 18:33:43 -0800257 start_time_ = MicroTime();
258
jeffhao2692b572011-12-16 15:42:28 -0800259 // Set trace version and record size.
jeffhaoa9ef3fd2011-12-13 18:33:43 -0800260 if (UseThreadCpuClock() && UseWallClock()) {
261 trace_version_ = kTraceVersionDualClock;
262 record_size_ = kTraceRecordSizeDualClock;
263 } else {
264 trace_version_ = kTraceVersionSingleClock;
265 record_size_ = kTraceRecordSizeSingleClock;
266 }
267
jeffhaoa9ef3fd2011-12-13 18:33:43 -0800268 // Set up the beginning of the trace.
jeffhao2692b572011-12-16 15:42:28 -0800269 memset(buf_.get(), 0, kTraceHeaderLength);
270 Append4LE(buf_.get(), kTraceMagicValue);
271 Append2LE(buf_.get() + 4, trace_version_);
272 Append2LE(buf_.get() + 6, kTraceHeaderLength);
273 Append8LE(buf_.get() + 8, start_time_);
jeffhaoa9ef3fd2011-12-13 18:33:43 -0800274 if (trace_version_ >= kTraceVersionDualClock) {
jeffhao2692b572011-12-16 15:42:28 -0800275 Append2LE(buf_.get() + 16, record_size_);
jeffhaoa9ef3fd2011-12-13 18:33:43 -0800276 }
jeffhaoa9ef3fd2011-12-13 18:33:43 -0800277
jeffhao2692b572011-12-16 15:42:28 -0800278 // Update current offset.
279 cur_offset_ = kTraceHeaderLength;
jeffhaoa9ef3fd2011-12-13 18:33:43 -0800280
281 // Install all method tracing stubs.
jeffhaoe343b762011-12-05 16:36:44 -0800282 InstallStubs();
jeffhaoe343b762011-12-05 16:36:44 -0800283}
284
jeffhao2692b572011-12-16 15:42:28 -0800285void Trace::FinishTracing() {
jeffhaoa9ef3fd2011-12-13 18:33:43 -0800286 // Uninstall all method tracing stubs.
jeffhaoe343b762011-12-05 16:36:44 -0800287 UninstallStubs();
jeffhaoa9ef3fd2011-12-13 18:33:43 -0800288
jeffhaoa9ef3fd2011-12-13 18:33:43 -0800289 // Compute elapsed time.
290 uint64_t elapsed = MicroTime() - start_time_;
291
292 size_t final_offset = cur_offset_;
293 uint32_t clock_overhead = GetClockOverhead();
294
295 GetVisitedMethods(final_offset);
296
297 std::ostringstream os;
298
299 os << StringPrintf("%cversion\n", kTraceTokenChar);
300 os << StringPrintf("%d\n", trace_version_);
301 os << StringPrintf("data-file-overflow=%s\n", overflow_ ? "true" : "false");
302 if (UseThreadCpuClock()) {
303 if (UseWallClock()) {
304 os << StringPrintf("clock=dual\n");
305 } else {
306 os << StringPrintf("clock=thread-cpu\n");
307 }
308 } else {
309 os << StringPrintf("clock=wall\n");
310 }
311 os << StringPrintf("elapsed-time-usec=%llu\n", elapsed);
312 os << StringPrintf("num-method-calls=%d\n", (final_offset - kTraceHeaderLength) / record_size_);
313 os << StringPrintf("clock-call-overhead-nsec=%d\n", clock_overhead);
314 os << StringPrintf("vm=art\n");
315 os << StringPrintf("%cthreads\n", kTraceTokenChar);
316 DumpThreadList(os);
317 os << StringPrintf("%cmethods\n", kTraceTokenChar);
318 DumpMethodList(os);
319 os << StringPrintf("%cend\n", kTraceTokenChar);
320
321 std::string header(os.str());
jeffhao2692b572011-12-16 15:42:28 -0800322 if (trace_file_.get() == NULL) {
jeffhaoa9ef3fd2011-12-13 18:33:43 -0800323 struct iovec iov[2];
324 iov[0].iov_base = reinterpret_cast<void*>(const_cast<char*>(header.c_str()));
325 iov[0].iov_len = header.length();
jeffhao2692b572011-12-16 15:42:28 -0800326 iov[1].iov_base = buf_.get();
jeffhaoa9ef3fd2011-12-13 18:33:43 -0800327 iov[1].iov_len = final_offset;
328 Dbg::DdmSendChunkV(CHUNK_TYPE("MPSE"), iov, 2);
329 } else {
330 if (!trace_file_->WriteFully(header.c_str(), header.length()) ||
jeffhao2692b572011-12-16 15:42:28 -0800331 !trace_file_->WriteFully(buf_.get(), final_offset)) {
jeffhaoa9ef3fd2011-12-13 18:33:43 -0800332 int err = errno;
333 LOG(ERROR) << "Trace data write failed: " << strerror(err);
334 Thread::Current()->ThrowNewException("Ljava/lang/RuntimeException;",
335 StringPrintf("Trace data write failed: %s", strerror(err)).c_str());
336 }
jeffhaoa9ef3fd2011-12-13 18:33:43 -0800337 }
jeffhaoa9ef3fd2011-12-13 18:33:43 -0800338}
339
340void Trace::LogMethodTraceEvent(Thread* self, const Method* method, Trace::TraceEvent event) {
341 if (thread_clock_base_map_.find(self) == thread_clock_base_map_.end()) {
342 uint64_t time = ThreadCpuMicroTime();
343 thread_clock_base_map_.insert(std::make_pair(self, time));
344 }
345
346 // Advance cur_offset_ atomically.
347 int32_t new_offset;
348 int32_t old_offset;
349 do {
350 old_offset = cur_offset_;
351 new_offset = old_offset + record_size_;
352 if (new_offset > buffer_size_) {
353 overflow_ = true;
354 return;
355 }
356 } while (android_atomic_release_cas(old_offset, new_offset, &cur_offset_) != 0);
357
358 uint32_t method_value = TraceMethodCombine(reinterpret_cast<uint32_t>(method), event);
359
360 // Write data
jeffhao2692b572011-12-16 15:42:28 -0800361 uint8_t* ptr = buf_.get() + old_offset;
jeffhaoa9ef3fd2011-12-13 18:33:43 -0800362 Append2LE(ptr, self->GetTid());
363 Append4LE(ptr + 2, method_value);
364 ptr += 6;
365
366 if (UseThreadCpuClock()) {
367 uint64_t thread_clock_base = thread_clock_base_map_.find(self)->second;
368 uint32_t thread_clock_diff = ThreadCpuMicroTime() - thread_clock_base;
369 Append4LE(ptr, thread_clock_diff);
370 ptr += 4;
371 }
372
373 if (UseWallClock()) {
374 uint32_t wall_clock_diff = MicroTime() - start_time_;
375 Append4LE(ptr, wall_clock_diff);
376 }
377}
378
379void Trace::GetVisitedMethods(size_t end_offset) {
jeffhao2692b572011-12-16 15:42:28 -0800380 uint8_t* ptr = buf_.get() + kTraceHeaderLength;
381 uint8_t* end = buf_.get() + end_offset;
jeffhaoa9ef3fd2011-12-13 18:33:43 -0800382
383 while (ptr < end) {
384 uint32_t method_value = ptr[2] | (ptr[3] << 8) | (ptr[4] << 16) | (ptr[5] << 24);
385 Method* method = reinterpret_cast<Method*>(TraceMethodId(method_value));
386 visited_methods_.insert(method);
387 ptr += record_size_;
388 }
389}
390
391void Trace::DumpMethodList(std::ostream& os) {
392 typedef std::set<const Method*>::const_iterator It; // TODO: C++0x auto
393 for (It it = visited_methods_.begin(); it != visited_methods_.end(); ++it) {
394 const Method* method = *it;
395 MethodHelper mh(method);
396 os << StringPrintf("0x%08x\t%s\t%s\t%s\t%s\t%d\n", (int) method,
397 PrettyDescriptor(mh.GetDeclaringClassDescriptor()).c_str(), mh.GetName(),
398 mh.GetSignature().c_str(), mh.GetDeclaringClassSourceFile(),
399 mh.GetLineNumFromNativePC(0));
400 }
jeffhaoa9ef3fd2011-12-13 18:33:43 -0800401}
402
403static void DumpThread(Thread* t, void* arg) {
404 std::ostream* os = reinterpret_cast<std::ostream*>(arg);
405 *os << StringPrintf("%d\t%s\n", t->GetTid(), t->GetName()->ToModifiedUtf8().c_str());
406}
407
408void Trace::DumpThreadList(std::ostream& os) {
409 ScopedThreadListLock thread_list_lock;
410 Runtime::Current()->GetThreadList()->ForEach(DumpThread, &os);
jeffhaoe343b762011-12-05 16:36:44 -0800411}
412
413void Trace::InstallStubs() {
414#if defined(__arm__)
jeffhaoe343b762011-12-05 16:36:44 -0800415 void* trace_stub = reinterpret_cast<void*>(art_trace_entry_from_code);
416 Runtime::Current()->GetClassLinker()->VisitClasses(InstallStubsClassVisitor, trace_stub);
jeffhaoe343b762011-12-05 16:36:44 -0800417#else
418 UNIMPLEMENTED(WARNING);
419#endif
420}
421
422void Trace::UninstallStubs() {
423#if defined(__arm__)
jeffhaoe343b762011-12-05 16:36:44 -0800424 void* trace_stub = reinterpret_cast<void*>(art_trace_entry_from_code);
425 Runtime::Current()->GetClassLinker()->VisitClasses(UninstallStubsClassVisitor, trace_stub);
426
427 // Restore stacks of all threads
428 {
429 ScopedThreadListLock thread_list_lock;
430 Runtime::Current()->GetThreadList()->ForEach(TraceRestoreStack, NULL);
431 }
jeffhaoe343b762011-12-05 16:36:44 -0800432#else
433 UNIMPLEMENTED(WARNING);
434#endif
435}
436
437} // namespace art