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