blob: ec289ea2b565c6358f450a9a374b7110a1c5e0a7 [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 }
Calin Juravle4d77b6a2015-12-01 18:38:09 +0000109
Calin Juravle998c2162015-12-21 15:39:33 +0200110 ProfileCompilationInfo::SaveProfilingInfo(output_filename_, methods);
111 VLOG(profiler) << "Profile process time: " << PrettyDuration(NanoTime() - start);
Calin Juravle4d77b6a2015-12-01 18:38:09 +0000112 return true;
113}
114
115void* ProfileSaver::RunProfileSaverThread(void* arg) {
116 Runtime* runtime = Runtime::Current();
117 ProfileSaver* profile_saver = reinterpret_cast<ProfileSaver*>(arg);
118
119 CHECK(runtime->AttachCurrentThread("Profile Saver",
120 /*as_daemon*/true,
121 runtime->GetSystemThreadGroup(),
122 /*create_peer*/true));
123 profile_saver->Run();
124
125 runtime->DetachCurrentThread();
126 VLOG(profiler) << "Profile saver shutdown";
127 return nullptr;
128}
129
130void ProfileSaver::Start(const std::string& output_filename,
131 jit::JitCodeCache* jit_code_cache,
132 const std::vector<std::string>& code_paths) {
133 DCHECK(Runtime::Current()->UseJit());
134 DCHECK(!output_filename.empty());
135 DCHECK(jit_code_cache != nullptr);
136
137 MutexLock mu(Thread::Current(), *Locks::profiler_lock_);
138 // Don't start two profile saver threads.
139 if (instance_ != nullptr) {
140 DCHECK(false) << "Tried to start two profile savers";
141 return;
142 }
143
144 VLOG(profiler) << "Starting profile saver using output file: " << output_filename
145 << ". Tracking: " << Join(code_paths, ':');
146
147 instance_ = new ProfileSaver(output_filename, jit_code_cache, code_paths);
148
149 // Create a new thread which does the saving.
150 CHECK_PTHREAD_CALL(
151 pthread_create,
152 (&profiler_pthread_, nullptr, &RunProfileSaverThread, reinterpret_cast<void*>(instance_)),
153 "Profile saver thread");
154}
155
156void ProfileSaver::Stop() {
157 ProfileSaver* profile_saver = nullptr;
158 pthread_t profiler_pthread = 0U;
159
160 {
161 MutexLock profiler_mutex(Thread::Current(), *Locks::profiler_lock_);
162 VLOG(profiler) << "Stopping profile saver thread for file: " << instance_->output_filename_;
163 profile_saver = instance_;
164 profiler_pthread = profiler_pthread_;
165 if (instance_ == nullptr) {
166 DCHECK(false) << "Tried to stop a profile saver which was not started";
167 return;
168 }
169 if (instance_->shutting_down_) {
170 DCHECK(false) << "Tried to stop the profile saver twice";
171 return;
172 }
173 instance_->shutting_down_ = true;
174 }
175
176 {
177 // Wake up the saver thread if it is sleeping to allow for a clean exit.
178 MutexLock wait_mutex(Thread::Current(), profile_saver->wait_lock_);
179 profile_saver->period_condition_.Signal(Thread::Current());
180 }
181
182 // Wait for the saver thread to stop.
183 CHECK_PTHREAD_CALL(pthread_join, (profiler_pthread, nullptr), "profile saver thread shutdown");
184
185 {
186 MutexLock profiler_mutex(Thread::Current(), *Locks::profiler_lock_);
187 instance_ = nullptr;
188 profiler_pthread_ = 0U;
189 }
190 delete profile_saver;
191}
192
193bool ProfileSaver::ShuttingDown(Thread* self) {
194 MutexLock mu(self, *Locks::profiler_lock_);
195 return shutting_down_;
196}
197
198bool ProfileSaver::IsStarted() {
199 MutexLock mu(Thread::Current(), *Locks::profiler_lock_);
200 return instance_ != nullptr;
201}
202
203} // namespace art