xref: /aosp_15_r20/art/runtime/trace_profile.cc (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2024 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker #include "trace_profile.h"
18*795d594fSAndroid Build Coastguard Worker 
19*795d594fSAndroid Build Coastguard Worker #include "android-base/stringprintf.h"
20*795d594fSAndroid Build Coastguard Worker #include "art_method-inl.h"
21*795d594fSAndroid Build Coastguard Worker #include "base/leb128.h"
22*795d594fSAndroid Build Coastguard Worker #include "base/mutex.h"
23*795d594fSAndroid Build Coastguard Worker #include "base/unix_file/fd_file.h"
24*795d594fSAndroid Build Coastguard Worker #include "com_android_art_flags.h"
25*795d594fSAndroid Build Coastguard Worker #include "dex/descriptors_names.h"
26*795d594fSAndroid Build Coastguard Worker #include "runtime.h"
27*795d594fSAndroid Build Coastguard Worker #include "thread-current-inl.h"
28*795d594fSAndroid Build Coastguard Worker #include "thread.h"
29*795d594fSAndroid Build Coastguard Worker #include "thread_list.h"
30*795d594fSAndroid Build Coastguard Worker #include "trace.h"
31*795d594fSAndroid Build Coastguard Worker 
32*795d594fSAndroid Build Coastguard Worker namespace art_flags = com::android::art::flags;
33*795d594fSAndroid Build Coastguard Worker 
34*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
35*795d594fSAndroid Build Coastguard Worker 
36*795d594fSAndroid Build Coastguard Worker using android::base::StringPrintf;
37*795d594fSAndroid Build Coastguard Worker 
38*795d594fSAndroid Build Coastguard Worker // This specifies the maximum number of bits we need for encoding one entry. Each entry just
39*795d594fSAndroid Build Coastguard Worker // consists of a SLEB encoded value of method and action encodig which is a maximum of
40*795d594fSAndroid Build Coastguard Worker // sizeof(uintptr_t).
41*795d594fSAndroid Build Coastguard Worker static constexpr size_t kMaxBytesPerTraceEntry = sizeof(uintptr_t);
42*795d594fSAndroid Build Coastguard Worker 
43*795d594fSAndroid Build Coastguard Worker // We don't handle buffer overflows when processing the raw trace entries. We have a maximum of
44*795d594fSAndroid Build Coastguard Worker // kAlwaysOnTraceBufSize raw entries and we need a maximum of kMaxBytesPerTraceEntry to encode
45*795d594fSAndroid Build Coastguard Worker // each entry. To avoid overflow, we ensure that there are at least kMinBufSizeForEncodedData
46*795d594fSAndroid Build Coastguard Worker // bytes free space in the buffer.
47*795d594fSAndroid Build Coastguard Worker static constexpr size_t kMinBufSizeForEncodedData = kAlwaysOnTraceBufSize * kMaxBytesPerTraceEntry;
48*795d594fSAndroid Build Coastguard Worker 
49*795d594fSAndroid Build Coastguard Worker static constexpr size_t kProfileMagicValue = 0x4C4F4D54;
50*795d594fSAndroid Build Coastguard Worker 
51*795d594fSAndroid Build Coastguard Worker // TODO(mythria): 10 is a randomly chosen value. Tune it if required.
52*795d594fSAndroid Build Coastguard Worker static constexpr size_t kBufSizeForEncodedData = kMinBufSizeForEncodedData * 10;
53*795d594fSAndroid Build Coastguard Worker 
54*795d594fSAndroid Build Coastguard Worker static constexpr size_t kAlwaysOnTraceHeaderSize = 8;
55*795d594fSAndroid Build Coastguard Worker 
56*795d594fSAndroid Build Coastguard Worker bool TraceProfiler::profile_in_progress_ = false;
57*795d594fSAndroid Build Coastguard Worker 
AllocateBuffer(Thread * thread)58*795d594fSAndroid Build Coastguard Worker void TraceProfiler::AllocateBuffer(Thread* thread) {
59*795d594fSAndroid Build Coastguard Worker   if (!art_flags::always_enable_profile_code()) {
60*795d594fSAndroid Build Coastguard Worker     return;
61*795d594fSAndroid Build Coastguard Worker   }
62*795d594fSAndroid Build Coastguard Worker 
63*795d594fSAndroid Build Coastguard Worker   Thread* self = Thread::Current();
64*795d594fSAndroid Build Coastguard Worker   MutexLock mu(self, *Locks::trace_lock_);
65*795d594fSAndroid Build Coastguard Worker   if (!profile_in_progress_) {
66*795d594fSAndroid Build Coastguard Worker     return;
67*795d594fSAndroid Build Coastguard Worker   }
68*795d594fSAndroid Build Coastguard Worker 
69*795d594fSAndroid Build Coastguard Worker   auto buffer = new uintptr_t[kAlwaysOnTraceBufSize];
70*795d594fSAndroid Build Coastguard Worker   memset(buffer, 0, kAlwaysOnTraceBufSize * sizeof(uintptr_t));
71*795d594fSAndroid Build Coastguard Worker   thread->SetMethodTraceBuffer(buffer, kAlwaysOnTraceBufSize);
72*795d594fSAndroid Build Coastguard Worker }
73*795d594fSAndroid Build Coastguard Worker 
Start()74*795d594fSAndroid Build Coastguard Worker void TraceProfiler::Start() {
75*795d594fSAndroid Build Coastguard Worker   if (!art_flags::always_enable_profile_code()) {
76*795d594fSAndroid Build Coastguard Worker     LOG(ERROR) << "Feature not supported. Please build with ART_ALWAYS_ENABLE_PROFILE_CODE.";
77*795d594fSAndroid Build Coastguard Worker     return;
78*795d594fSAndroid Build Coastguard Worker   }
79*795d594fSAndroid Build Coastguard Worker 
80*795d594fSAndroid Build Coastguard Worker   Thread* self = Thread::Current();
81*795d594fSAndroid Build Coastguard Worker   MutexLock mu(self, *Locks::trace_lock_);
82*795d594fSAndroid Build Coastguard Worker   if (profile_in_progress_) {
83*795d594fSAndroid Build Coastguard Worker     LOG(ERROR) << "Profile already in progress. Ignoring this request";
84*795d594fSAndroid Build Coastguard Worker     return;
85*795d594fSAndroid Build Coastguard Worker   }
86*795d594fSAndroid Build Coastguard Worker 
87*795d594fSAndroid Build Coastguard Worker   if (Trace::IsTracingEnabledLocked()) {
88*795d594fSAndroid Build Coastguard Worker     LOG(ERROR) << "Cannot start a profile when method tracing is in progress";
89*795d594fSAndroid Build Coastguard Worker     return;
90*795d594fSAndroid Build Coastguard Worker   }
91*795d594fSAndroid Build Coastguard Worker 
92*795d594fSAndroid Build Coastguard Worker   profile_in_progress_ = true;
93*795d594fSAndroid Build Coastguard Worker 
94*795d594fSAndroid Build Coastguard Worker   ScopedSuspendAll ssa(__FUNCTION__);
95*795d594fSAndroid Build Coastguard Worker   MutexLock tl(self, *Locks::thread_list_lock_);
96*795d594fSAndroid Build Coastguard Worker   for (Thread* thread : Runtime::Current()->GetThreadList()->GetList()) {
97*795d594fSAndroid Build Coastguard Worker     auto buffer = new uintptr_t[kAlwaysOnTraceBufSize];
98*795d594fSAndroid Build Coastguard Worker     memset(buffer, 0, kAlwaysOnTraceBufSize * sizeof(uintptr_t));
99*795d594fSAndroid Build Coastguard Worker     thread->SetMethodTraceBuffer(buffer, kAlwaysOnTraceBufSize);
100*795d594fSAndroid Build Coastguard Worker   }
101*795d594fSAndroid Build Coastguard Worker }
102*795d594fSAndroid Build Coastguard Worker 
Stop()103*795d594fSAndroid Build Coastguard Worker void TraceProfiler::Stop() {
104*795d594fSAndroid Build Coastguard Worker   if (!art_flags::always_enable_profile_code()) {
105*795d594fSAndroid Build Coastguard Worker     LOG(ERROR) << "Feature not supported. Please build with ART_ALWAYS_ENABLE_PROFILE_CODE.";
106*795d594fSAndroid Build Coastguard Worker     return;
107*795d594fSAndroid Build Coastguard Worker   }
108*795d594fSAndroid Build Coastguard Worker 
109*795d594fSAndroid Build Coastguard Worker   Thread* self = Thread::Current();
110*795d594fSAndroid Build Coastguard Worker   MutexLock mu(self, *Locks::trace_lock_);
111*795d594fSAndroid Build Coastguard Worker   if (!profile_in_progress_) {
112*795d594fSAndroid Build Coastguard Worker     LOG(ERROR) << "No Profile in progress but a stop was requested";
113*795d594fSAndroid Build Coastguard Worker     return;
114*795d594fSAndroid Build Coastguard Worker   }
115*795d594fSAndroid Build Coastguard Worker 
116*795d594fSAndroid Build Coastguard Worker   ScopedSuspendAll ssa(__FUNCTION__);
117*795d594fSAndroid Build Coastguard Worker   MutexLock tl(self, *Locks::thread_list_lock_);
118*795d594fSAndroid Build Coastguard Worker   for (Thread* thread : Runtime::Current()->GetThreadList()->GetList()) {
119*795d594fSAndroid Build Coastguard Worker     auto buffer = thread->GetMethodTraceBuffer();
120*795d594fSAndroid Build Coastguard Worker     if (buffer != nullptr) {
121*795d594fSAndroid Build Coastguard Worker       delete[] buffer;
122*795d594fSAndroid Build Coastguard Worker       thread->SetMethodTraceBuffer(/* buffer= */ nullptr, /* offset= */ 0);
123*795d594fSAndroid Build Coastguard Worker     }
124*795d594fSAndroid Build Coastguard Worker   }
125*795d594fSAndroid Build Coastguard Worker 
126*795d594fSAndroid Build Coastguard Worker   profile_in_progress_ = false;
127*795d594fSAndroid Build Coastguard Worker }
128*795d594fSAndroid Build Coastguard Worker 
DumpBuffer(uint32_t thread_id,uintptr_t * method_trace_entries,uint8_t * buffer,std::unordered_set<ArtMethod * > & methods)129*795d594fSAndroid Build Coastguard Worker uint8_t* TraceProfiler::DumpBuffer(uint32_t thread_id,
130*795d594fSAndroid Build Coastguard Worker                                    uintptr_t* method_trace_entries,
131*795d594fSAndroid Build Coastguard Worker                                    uint8_t* buffer,
132*795d594fSAndroid Build Coastguard Worker                                    std::unordered_set<ArtMethod*>& methods) {
133*795d594fSAndroid Build Coastguard Worker   // Encode header at the end once we compute the number of records.
134*795d594fSAndroid Build Coastguard Worker   uint8_t* curr_buffer_ptr = buffer + kAlwaysOnTraceHeaderSize;
135*795d594fSAndroid Build Coastguard Worker 
136*795d594fSAndroid Build Coastguard Worker   int num_records = 0;
137*795d594fSAndroid Build Coastguard Worker   uintptr_t prev_method_action_encoding = 0;
138*795d594fSAndroid Build Coastguard Worker   int prev_action = -1;
139*795d594fSAndroid Build Coastguard Worker   for (size_t i = kAlwaysOnTraceBufSize - 1; i > 0; i-=1) {
140*795d594fSAndroid Build Coastguard Worker     uintptr_t method_action_encoding = method_trace_entries[i];
141*795d594fSAndroid Build Coastguard Worker     // 0 value indicates the rest of the entries are empty.
142*795d594fSAndroid Build Coastguard Worker     if (method_action_encoding == 0) {
143*795d594fSAndroid Build Coastguard Worker       break;
144*795d594fSAndroid Build Coastguard Worker     }
145*795d594fSAndroid Build Coastguard Worker 
146*795d594fSAndroid Build Coastguard Worker     int action = method_action_encoding & ~kMaskTraceAction;
147*795d594fSAndroid Build Coastguard Worker     int64_t diff;
148*795d594fSAndroid Build Coastguard Worker     if (action == TraceAction::kTraceMethodEnter) {
149*795d594fSAndroid Build Coastguard Worker       diff = method_action_encoding - prev_method_action_encoding;
150*795d594fSAndroid Build Coastguard Worker 
151*795d594fSAndroid Build Coastguard Worker       ArtMethod* method = reinterpret_cast<ArtMethod*>(method_action_encoding & kMaskTraceAction);
152*795d594fSAndroid Build Coastguard Worker       methods.insert(method);
153*795d594fSAndroid Build Coastguard Worker     } else {
154*795d594fSAndroid Build Coastguard Worker       // On a method exit, we don't record the information about method. We just need a 1 in the
155*795d594fSAndroid Build Coastguard Worker       // lsb and the method information can be derived from the last method that entered. To keep
156*795d594fSAndroid Build Coastguard Worker       // the encoded value small just add the smallest value to make the lsb one.
157*795d594fSAndroid Build Coastguard Worker       if (prev_action == TraceAction::kTraceMethodExit) {
158*795d594fSAndroid Build Coastguard Worker         diff = 0;
159*795d594fSAndroid Build Coastguard Worker       } else {
160*795d594fSAndroid Build Coastguard Worker         diff = 1;
161*795d594fSAndroid Build Coastguard Worker       }
162*795d594fSAndroid Build Coastguard Worker     }
163*795d594fSAndroid Build Coastguard Worker     curr_buffer_ptr = EncodeSignedLeb128(curr_buffer_ptr, diff);
164*795d594fSAndroid Build Coastguard Worker     num_records++;
165*795d594fSAndroid Build Coastguard Worker     prev_method_action_encoding = method_action_encoding;
166*795d594fSAndroid Build Coastguard Worker     prev_action = action;
167*795d594fSAndroid Build Coastguard Worker   }
168*795d594fSAndroid Build Coastguard Worker 
169*795d594fSAndroid Build Coastguard Worker   // Fill in header information:
170*795d594fSAndroid Build Coastguard Worker   // 1 byte of header identifier
171*795d594fSAndroid Build Coastguard Worker   // 4 bytes of thread_id
172*795d594fSAndroid Build Coastguard Worker   // 3 bytes of number of records
173*795d594fSAndroid Build Coastguard Worker   buffer[0] = kEntryHeaderV2;
174*795d594fSAndroid Build Coastguard Worker   Append4LE(buffer + 1, thread_id);
175*795d594fSAndroid Build Coastguard Worker   Append3LE(buffer + 5, num_records);
176*795d594fSAndroid Build Coastguard Worker   return curr_buffer_ptr;
177*795d594fSAndroid Build Coastguard Worker }
178*795d594fSAndroid Build Coastguard Worker 
Dump(int fd)179*795d594fSAndroid Build Coastguard Worker void TraceProfiler::Dump(int fd) {
180*795d594fSAndroid Build Coastguard Worker   if (!art_flags::always_enable_profile_code()) {
181*795d594fSAndroid Build Coastguard Worker     LOG(ERROR) << "Feature not supported. Please build with ART_ALWAYS_ENABLE_PROFILE_CODE.";
182*795d594fSAndroid Build Coastguard Worker     return;
183*795d594fSAndroid Build Coastguard Worker   }
184*795d594fSAndroid Build Coastguard Worker 
185*795d594fSAndroid Build Coastguard Worker   std::unique_ptr<File> trace_file(new File(fd, /*check_usage=*/true));
186*795d594fSAndroid Build Coastguard Worker   Dump(std::move(trace_file));
187*795d594fSAndroid Build Coastguard Worker }
188*795d594fSAndroid Build Coastguard Worker 
GetMethodInfoLine(ArtMethod * method)189*795d594fSAndroid Build Coastguard Worker std::string TraceProfiler::GetMethodInfoLine(ArtMethod* method) {
190*795d594fSAndroid Build Coastguard Worker   return StringPrintf("%s\t%s\t%s\t%s\n",
191*795d594fSAndroid Build Coastguard Worker                       PrettyDescriptor(method->GetDeclaringClassDescriptor()).c_str(),
192*795d594fSAndroid Build Coastguard Worker                       method->GetName(),
193*795d594fSAndroid Build Coastguard Worker                       method->GetSignature().ToString().c_str(),
194*795d594fSAndroid Build Coastguard Worker                       method->GetDeclaringClassSourceFile());
195*795d594fSAndroid Build Coastguard Worker }
196*795d594fSAndroid Build Coastguard Worker 
Dump(const char * filename)197*795d594fSAndroid Build Coastguard Worker void TraceProfiler::Dump(const char* filename) {
198*795d594fSAndroid Build Coastguard Worker   if (!art_flags::always_enable_profile_code()) {
199*795d594fSAndroid Build Coastguard Worker     LOG(ERROR) << "Feature not supported. Please build with ART_ALWAYS_ENABLE_PROFILE_CODE.";
200*795d594fSAndroid Build Coastguard Worker     return;
201*795d594fSAndroid Build Coastguard Worker   }
202*795d594fSAndroid Build Coastguard Worker 
203*795d594fSAndroid Build Coastguard Worker   std::unique_ptr<File> trace_file(OS::CreateEmptyFileWriteOnly(filename));
204*795d594fSAndroid Build Coastguard Worker   if (trace_file == nullptr) {
205*795d594fSAndroid Build Coastguard Worker     PLOG(ERROR) << "Unable to open trace file " << filename;
206*795d594fSAndroid Build Coastguard Worker     return;
207*795d594fSAndroid Build Coastguard Worker   }
208*795d594fSAndroid Build Coastguard Worker 
209*795d594fSAndroid Build Coastguard Worker   Dump(std::move(trace_file));
210*795d594fSAndroid Build Coastguard Worker }
211*795d594fSAndroid Build Coastguard Worker 
Dump(std::unique_ptr<File> && trace_file)212*795d594fSAndroid Build Coastguard Worker void TraceProfiler::Dump(std::unique_ptr<File>&& trace_file) {
213*795d594fSAndroid Build Coastguard Worker   Thread* self = Thread::Current();
214*795d594fSAndroid Build Coastguard Worker   std::unordered_set<ArtMethod*> traced_methods;
215*795d594fSAndroid Build Coastguard Worker   std::unordered_map<size_t, std::string> traced_threads;
216*795d594fSAndroid Build Coastguard Worker   MutexLock mu(self, *Locks::trace_lock_);
217*795d594fSAndroid Build Coastguard Worker   if (!profile_in_progress_) {
218*795d594fSAndroid Build Coastguard Worker     LOG(ERROR) << "No Profile in progress. Nothing to dump.";
219*795d594fSAndroid Build Coastguard Worker     return;
220*795d594fSAndroid Build Coastguard Worker   }
221*795d594fSAndroid Build Coastguard Worker 
222*795d594fSAndroid Build Coastguard Worker   uint8_t* buffer_ptr = new uint8_t[kBufSizeForEncodedData];
223*795d594fSAndroid Build Coastguard Worker   uint8_t* curr_buffer_ptr = buffer_ptr;
224*795d594fSAndroid Build Coastguard Worker 
225*795d594fSAndroid Build Coastguard Worker   // Add a header for the trace: 4-bits of magic value and 2-bits for the version.
226*795d594fSAndroid Build Coastguard Worker   Append4LE(curr_buffer_ptr, kProfileMagicValue);
227*795d594fSAndroid Build Coastguard Worker   Append2LE(curr_buffer_ptr + 4, /*trace_version=*/ 1);
228*795d594fSAndroid Build Coastguard Worker   curr_buffer_ptr += 6;
229*795d594fSAndroid Build Coastguard Worker 
230*795d594fSAndroid Build Coastguard Worker   ScopedSuspendAll ssa(__FUNCTION__);
231*795d594fSAndroid Build Coastguard Worker   MutexLock tl(self, *Locks::thread_list_lock_);
232*795d594fSAndroid Build Coastguard Worker   for (Thread* thread : Runtime::Current()->GetThreadList()->GetList()) {
233*795d594fSAndroid Build Coastguard Worker     auto method_trace_entries = thread->GetMethodTraceBuffer();
234*795d594fSAndroid Build Coastguard Worker     if (method_trace_entries == nullptr) {
235*795d594fSAndroid Build Coastguard Worker       continue;
236*795d594fSAndroid Build Coastguard Worker     }
237*795d594fSAndroid Build Coastguard Worker 
238*795d594fSAndroid Build Coastguard Worker     std::string thread_name;
239*795d594fSAndroid Build Coastguard Worker     thread->GetThreadName(thread_name);
240*795d594fSAndroid Build Coastguard Worker     traced_threads.emplace(thread->GetThreadId(), thread_name);
241*795d594fSAndroid Build Coastguard Worker 
242*795d594fSAndroid Build Coastguard Worker     size_t offset = curr_buffer_ptr - buffer_ptr;
243*795d594fSAndroid Build Coastguard Worker     if (offset >= kMinBufSizeForEncodedData) {
244*795d594fSAndroid Build Coastguard Worker       if (!trace_file->WriteFully(buffer_ptr, offset)) {
245*795d594fSAndroid Build Coastguard Worker         PLOG(WARNING) << "Failed streaming a tracing event.";
246*795d594fSAndroid Build Coastguard Worker       }
247*795d594fSAndroid Build Coastguard Worker       curr_buffer_ptr = buffer_ptr;
248*795d594fSAndroid Build Coastguard Worker     }
249*795d594fSAndroid Build Coastguard Worker     curr_buffer_ptr =
250*795d594fSAndroid Build Coastguard Worker         DumpBuffer(thread->GetTid(), method_trace_entries, curr_buffer_ptr, traced_methods);
251*795d594fSAndroid Build Coastguard Worker     // Reset the buffer and continue profiling. We need to set the buffer to
252*795d594fSAndroid Build Coastguard Worker     // zeroes, since we use a circular buffer and detect empty entries by
253*795d594fSAndroid Build Coastguard Worker     // checking for zeroes.
254*795d594fSAndroid Build Coastguard Worker     memset(method_trace_entries, 0, kAlwaysOnTraceBufSize * sizeof(uintptr_t));
255*795d594fSAndroid Build Coastguard Worker     // Reset the current pointer.
256*795d594fSAndroid Build Coastguard Worker     thread->SetMethodTraceBufferCurrentEntry(kAlwaysOnTraceBufSize);
257*795d594fSAndroid Build Coastguard Worker   }
258*795d594fSAndroid Build Coastguard Worker 
259*795d594fSAndroid Build Coastguard Worker   // Write any remaining data to file and close the file.
260*795d594fSAndroid Build Coastguard Worker   if (curr_buffer_ptr != buffer_ptr) {
261*795d594fSAndroid Build Coastguard Worker     if (!trace_file->WriteFully(buffer_ptr, curr_buffer_ptr - buffer_ptr)) {
262*795d594fSAndroid Build Coastguard Worker       PLOG(WARNING) << "Failed streaming a tracing event.";
263*795d594fSAndroid Build Coastguard Worker     }
264*795d594fSAndroid Build Coastguard Worker   }
265*795d594fSAndroid Build Coastguard Worker 
266*795d594fSAndroid Build Coastguard Worker   std::ostringstream os;
267*795d594fSAndroid Build Coastguard Worker   // Dump data about thread information.
268*795d594fSAndroid Build Coastguard Worker   os << "\n*threads\n";
269*795d594fSAndroid Build Coastguard Worker   for (const auto& it : traced_threads) {
270*795d594fSAndroid Build Coastguard Worker     os << it.first << "\t" << it.second << "\n";
271*795d594fSAndroid Build Coastguard Worker   }
272*795d594fSAndroid Build Coastguard Worker 
273*795d594fSAndroid Build Coastguard Worker   // Dump data about method information.
274*795d594fSAndroid Build Coastguard Worker   os << "*methods\n";
275*795d594fSAndroid Build Coastguard Worker   for (ArtMethod* method : traced_methods) {
276*795d594fSAndroid Build Coastguard Worker     uint64_t method_id = reinterpret_cast<uint64_t>(method);
277*795d594fSAndroid Build Coastguard Worker     os << method_id << "\t" << GetMethodInfoLine(method);
278*795d594fSAndroid Build Coastguard Worker   }
279*795d594fSAndroid Build Coastguard Worker 
280*795d594fSAndroid Build Coastguard Worker   os << "*end";
281*795d594fSAndroid Build Coastguard Worker 
282*795d594fSAndroid Build Coastguard Worker   std::string info = os.str();
283*795d594fSAndroid Build Coastguard Worker   if (!trace_file->WriteFully(info.c_str(), info.length())) {
284*795d594fSAndroid Build Coastguard Worker     PLOG(WARNING) << "Failed writing information to file";
285*795d594fSAndroid Build Coastguard Worker   }
286*795d594fSAndroid Build Coastguard Worker 
287*795d594fSAndroid Build Coastguard Worker   if (!trace_file->Close()) {
288*795d594fSAndroid Build Coastguard Worker     PLOG(WARNING) << "Failed to close file.";
289*795d594fSAndroid Build Coastguard Worker   }
290*795d594fSAndroid Build Coastguard Worker }
291*795d594fSAndroid Build Coastguard Worker 
ReleaseThreadBuffer(Thread * self)292*795d594fSAndroid Build Coastguard Worker void TraceProfiler::ReleaseThreadBuffer(Thread* self) {
293*795d594fSAndroid Build Coastguard Worker   if (!IsTraceProfileInProgress()) {
294*795d594fSAndroid Build Coastguard Worker     return;
295*795d594fSAndroid Build Coastguard Worker   }
296*795d594fSAndroid Build Coastguard Worker   // TODO(mythria): Maybe it's good to cache these and dump them when requested. For now just
297*795d594fSAndroid Build Coastguard Worker   // relese the buffer when a thread is exiting.
298*795d594fSAndroid Build Coastguard Worker   auto buffer = self->GetMethodTraceBuffer();
299*795d594fSAndroid Build Coastguard Worker   delete[] buffer;
300*795d594fSAndroid Build Coastguard Worker   self->SetMethodTraceBuffer(nullptr, 0);
301*795d594fSAndroid Build Coastguard Worker }
302*795d594fSAndroid Build Coastguard Worker 
IsTraceProfileInProgress()303*795d594fSAndroid Build Coastguard Worker bool TraceProfiler::IsTraceProfileInProgress() {
304*795d594fSAndroid Build Coastguard Worker   return profile_in_progress_;
305*795d594fSAndroid Build Coastguard Worker }
306*795d594fSAndroid Build Coastguard Worker 
307*795d594fSAndroid Build Coastguard Worker }  // namespace art
308