blob: 0278138d6ee8a8fb89fb7d4966fb99aff53bd8ce [file] [log] [blame]
Calin Juravle4d77b6a2015-12-01 18:38:09 +00001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "profile_saver.h"
18
19#include "art_method-inl.h"
20#include "scoped_thread_state_change.h"
21#include "oat_file_manager.h"
22
23namespace art {
24
25// An arbitrary value to throttle save requests. Set to 500ms for now.
26static constexpr const uint64_t kMilisecondsToNano = 1000000;
27static constexpr const uint64_t kMinimumTimeBetweenCodeCacheUpdatesNs = 500 * kMilisecondsToNano;
28
29// TODO: read the constants from ProfileOptions,
30// Add a random delay each time we go to sleep so that we don't hammer the CPU
31// with all profile savers running at the same time.
32static constexpr const uint64_t kRandomDelayMaxMs = 10 * 1000; // 10 seconds
33static constexpr const uint64_t kMaxBackoffMs = 4 * 60 * 1000; // 4 minutes
34static constexpr const uint64_t kSavePeriodMs = 4 * 1000; // 4 seconds
35static constexpr const double kBackoffCoef = 1.5;
36
37static constexpr const uint32_t kMinimumNrOrMethodsToSave = 10;
38
39ProfileSaver* ProfileSaver::instance_ = nullptr;
40pthread_t ProfileSaver::profiler_pthread_ = 0U;
41
42ProfileSaver::ProfileSaver(const std::string& output_filename,
43 jit::JitCodeCache* jit_code_cache,
44 const std::vector<std::string>& code_paths)
45 : output_filename_(output_filename),
46 jit_code_cache_(jit_code_cache),
47 tracked_dex_base_locations_(code_paths.begin(), code_paths.end()),
48 code_cache_last_update_time_ns_(0),
49 shutting_down_(false),
50 wait_lock_("ProfileSaver wait lock"),
51 period_condition_("ProfileSaver period condition", wait_lock_) {
52}
53
54void ProfileSaver::Run() {
55 srand(MicroTime() * getpid());
56 Thread* self = Thread::Current();
57
58 uint64_t save_period_ms = kSavePeriodMs;
59 VLOG(profiler) << "Save profiling information every " << save_period_ms << " ms";
60 while (true) {
61 if (ShuttingDown(self)) {
62 break;
63 }
64
65 uint64_t random_sleep_delay_ms = rand() % kRandomDelayMaxMs;
66 uint64_t sleep_time_ms = save_period_ms + random_sleep_delay_ms;
67 {
68 MutexLock mu(self, wait_lock_);
69 period_condition_.TimedWait(self, sleep_time_ms, 0);
70 }
71
72 if (ShuttingDown(self)) {
73 break;
74 }
75
76 if (!ProcessProfilingInfo() && save_period_ms < kMaxBackoffMs) {
77 // If we don't need to save now it is less likely that we will need to do
78 // so in the future. Increase the time between saves according to the
79 // kBackoffCoef, but make it no larger than kMaxBackoffMs.
80 save_period_ms = static_cast<uint64_t>(kBackoffCoef * save_period_ms);
81 } else {
82 // Reset the period to the initial value as it's highly likely to JIT again.
83 save_period_ms = kSavePeriodMs;
84 }
85 }
86}
87
88bool ProfileSaver::ProcessProfilingInfo() {
89 VLOG(profiler) << "Initiating save profiling information to: " << output_filename_;
90
91 uint64_t last_update_time_ns = jit_code_cache_->GetLastUpdateTimeNs();
92 if (last_update_time_ns - code_cache_last_update_time_ns_
93 > kMinimumTimeBetweenCodeCacheUpdatesNs) {
94 VLOG(profiler) << "Not enough time has passed since the last code cache update.";
95 return false;
96 }
97
98 uint64_t start = NanoTime();
99 code_cache_last_update_time_ns_ = last_update_time_ns;
100 std::vector<ArtMethod*> methods;
101 {
102 ScopedObjectAccess soa(Thread::Current());
103 jit_code_cache_->GetCompiledArtMethods(tracked_dex_base_locations_, methods);
104 }
105 if (methods.size() < kMinimumNrOrMethodsToSave) {
106 VLOG(profiler) << "Not enough information to save. Nr of methods: " << methods.size();
107 return false;
108 }
109 offline_profiling_info_.SaveProfilingInfo(output_filename_, methods);
110
111 VLOG(profiler) << "Saved profile time: " << PrettyDuration(NanoTime() - start);
112
113 return true;
114}
115
116void* ProfileSaver::RunProfileSaverThread(void* arg) {
117 Runtime* runtime = Runtime::Current();
118 ProfileSaver* profile_saver = reinterpret_cast<ProfileSaver*>(arg);
119
120 CHECK(runtime->AttachCurrentThread("Profile Saver",
121 /*as_daemon*/true,
122 runtime->GetSystemThreadGroup(),
123 /*create_peer*/true));
124 profile_saver->Run();
125
126 runtime->DetachCurrentThread();
127 VLOG(profiler) << "Profile saver shutdown";
128 return nullptr;
129}
130
131void ProfileSaver::Start(const std::string& output_filename,
132 jit::JitCodeCache* jit_code_cache,
133 const std::vector<std::string>& code_paths) {
134 DCHECK(Runtime::Current()->UseJit());
135 DCHECK(!output_filename.empty());
136 DCHECK(jit_code_cache != nullptr);
137
138 MutexLock mu(Thread::Current(), *Locks::profiler_lock_);
139 // Don't start two profile saver threads.
140 if (instance_ != nullptr) {
141 DCHECK(false) << "Tried to start two profile savers";
142 return;
143 }
144
145 VLOG(profiler) << "Starting profile saver using output file: " << output_filename
146 << ". Tracking: " << Join(code_paths, ':');
147
148 instance_ = new ProfileSaver(output_filename, jit_code_cache, code_paths);
149
150 // Create a new thread which does the saving.
151 CHECK_PTHREAD_CALL(
152 pthread_create,
153 (&profiler_pthread_, nullptr, &RunProfileSaverThread, reinterpret_cast<void*>(instance_)),
154 "Profile saver thread");
155}
156
157void ProfileSaver::Stop() {
158 ProfileSaver* profile_saver = nullptr;
159 pthread_t profiler_pthread = 0U;
160
161 {
162 MutexLock profiler_mutex(Thread::Current(), *Locks::profiler_lock_);
163 VLOG(profiler) << "Stopping profile saver thread for file: " << instance_->output_filename_;
164 profile_saver = instance_;
165 profiler_pthread = profiler_pthread_;
166 if (instance_ == nullptr) {
167 DCHECK(false) << "Tried to stop a profile saver which was not started";
168 return;
169 }
170 if (instance_->shutting_down_) {
171 DCHECK(false) << "Tried to stop the profile saver twice";
172 return;
173 }
174 instance_->shutting_down_ = true;
175 }
176
177 {
178 // Wake up the saver thread if it is sleeping to allow for a clean exit.
179 MutexLock wait_mutex(Thread::Current(), profile_saver->wait_lock_);
180 profile_saver->period_condition_.Signal(Thread::Current());
181 }
182
183 // Wait for the saver thread to stop.
184 CHECK_PTHREAD_CALL(pthread_join, (profiler_pthread, nullptr), "profile saver thread shutdown");
185
186 {
187 MutexLock profiler_mutex(Thread::Current(), *Locks::profiler_lock_);
188 instance_ = nullptr;
189 profiler_pthread_ = 0U;
190 }
191 delete profile_saver;
192}
193
194bool ProfileSaver::ShuttingDown(Thread* self) {
195 MutexLock mu(self, *Locks::profiler_lock_);
196 return shutting_down_;
197}
198
199bool ProfileSaver::IsStarted() {
200 MutexLock mu(Thread::Current(), *Locks::profiler_lock_);
201 return instance_ != nullptr;
202}
203
204} // namespace art