offline_profiling_info.cc revision 31f2c155975c5794d481df03eb0947cb48d2c6b5
1/* 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 "offline_profiling_info.h" 18 19#include <fstream> 20#include <set> 21#include <sys/file.h> 22#include <sys/stat.h> 23#include <sys/uio.h> 24 25#include "art_method-inl.h" 26#include "base/mutex.h" 27#include "jit/profiling_info.h" 28#include "safe_map.h" 29#include "utils.h" 30 31namespace art { 32 33// An arbitrary value to throttle save requests. Set to 500ms for now. 34static constexpr const uint64_t kMilisecondsToNano = 1000000; 35static constexpr const uint64_t kMinimumTimeBetweenSavesNs = 500 * kMilisecondsToNano; 36 37bool OfflineProfilingInfo::NeedsSaving(uint64_t last_update_time_ns) const { 38 return last_update_time_ns - last_update_time_ns_.LoadRelaxed() > kMinimumTimeBetweenSavesNs; 39} 40 41void OfflineProfilingInfo::SaveProfilingInfo(const std::string& filename, 42 uint64_t last_update_time_ns, 43 const std::set<ArtMethod*>& methods) { 44 if (!NeedsSaving(last_update_time_ns)) { 45 VLOG(profiler) << "No need to saved profile info to " << filename; 46 return; 47 } 48 49 if (methods.empty()) { 50 VLOG(profiler) << "No info to save to " << filename; 51 return; 52 } 53 54 DexFileToMethodsMap info; 55 { 56 ScopedObjectAccess soa(Thread::Current()); 57 for (auto it = methods.begin(); it != methods.end(); it++) { 58 AddMethodInfo(*it, &info); 59 } 60 } 61 62 // This doesn't need locking because we are trying to lock the file for exclusive 63 // access and fail immediately if we can't. 64 if (Serialize(filename, info)) { 65 last_update_time_ns_.StoreRelaxed(last_update_time_ns); 66 VLOG(profiler) << "Successfully saved profile info to " 67 << filename << " with time stamp: " << last_update_time_ns; 68 } 69} 70 71 72void OfflineProfilingInfo::AddMethodInfo(ArtMethod* method, DexFileToMethodsMap* info) { 73 DCHECK(method != nullptr); 74 const DexFile* dex_file = method->GetDexFile(); 75 76 auto info_it = info->find(dex_file); 77 if (info_it == info->end()) { 78 info_it = info->Put(dex_file, std::set<uint32_t>()); 79 } 80 info_it->second.insert(method->GetDexMethodIndex()); 81} 82 83static int OpenOrCreateFile(const std::string& filename) { 84 // TODO(calin) allow the shared uid of the app to access the file. 85 int fd = open(filename.c_str(), 86 O_CREAT | O_WRONLY | O_TRUNC | O_NOFOLLOW | O_CLOEXEC, 87 S_IRUSR | S_IWUSR); 88 if (fd < 0) { 89 PLOG(WARNING) << "Failed to open profile file " << filename; 90 return -1; 91 } 92 93 // Lock the file for exclusive access but don't wait if we can't lock it. 94 int err = flock(fd, LOCK_EX | LOCK_NB); 95 if (err < 0) { 96 PLOG(WARNING) << "Failed to lock profile file " << filename; 97 return -1; 98 } 99 100 return fd; 101} 102 103static bool CloseDescriptorForFile(int fd, const std::string& filename) { 104 // Now unlock the file, allowing another process in. 105 int err = flock(fd, LOCK_UN); 106 if (err < 0) { 107 PLOG(WARNING) << "Failed to unlock profile file " << filename; 108 return false; 109 } 110 111 // Done, close the file. 112 err = ::close(fd); 113 if (err < 0) { 114 PLOG(WARNING) << "Failed to close descriptor for profile file" << filename; 115 return false; 116 } 117 118 return true; 119} 120 121static void WriteToFile(int fd, const std::ostringstream& os) { 122 std::string data(os.str()); 123 const char *p = data.c_str(); 124 size_t length = data.length(); 125 do { 126 int n = ::write(fd, p, length); 127 p += n; 128 length -= n; 129 } while (length > 0); 130} 131 132static constexpr char kFieldSeparator = ','; 133static constexpr char kLineSeparator = '\n'; 134 135/** 136 * Serialization format: 137 * multidex_suffix1,dex_location_checksum1,method_id11,method_id12... 138 * multidex_suffix2,dex_location_checksum2,method_id21,method_id22... 139 * e.g. 140 * ,131232145,11,23,454,54 -> this is the first dex file, it has no multidex suffix 141 * :classes5.dex,218490184,39,13,49,1 -> this is the fifth dex file. 142 **/ 143bool OfflineProfilingInfo::Serialize(const std::string& filename, 144 const DexFileToMethodsMap& info) const { 145 int fd = OpenOrCreateFile(filename); 146 if (fd == -1) { 147 return false; 148 } 149 150 // TODO(calin): Merge with a previous existing profile. 151 // TODO(calin): Profile this and see how much memory it takes. If too much, 152 // write to file directly. 153 std::ostringstream os; 154 for (auto it : info) { 155 const DexFile* dex_file = it.first; 156 const std::set<uint32_t>& method_dex_ids = it.second; 157 158 os << DexFile::GetMultiDexSuffix(dex_file->GetLocation()) 159 << kFieldSeparator 160 << dex_file->GetLocationChecksum(); 161 for (auto method_it : method_dex_ids) { 162 os << kFieldSeparator << method_it; 163 } 164 os << kLineSeparator; 165 } 166 167 WriteToFile(fd, os); 168 169 return CloseDescriptorForFile(fd, filename); 170} 171} // namespace art 172