offline_profiling_info.cc revision 226501b317e148aa8a8983355e85acb59c1eee83
131f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle/* 231f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle * Copyright (C) 2015 The Android Open Source Project 331f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle * 431f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle * Licensed under the Apache License, Version 2.0 (the "License"); 531f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle * you may not use this file except in compliance with the License. 631f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle * You may obtain a copy of the License at 731f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle * 831f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle * http://www.apache.org/licenses/LICENSE-2.0 931f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle * 1031f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle * Unless required by applicable law or agreed to in writing, software 1131f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle * distributed under the License is distributed on an "AS IS" BASIS, 1231f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1331f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle * See the License for the specific language governing permissions and 1431f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle * limitations under the License. 1531f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle */ 1631f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle 1731f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle#include "offline_profiling_info.h" 1831f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle 1931f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle#include <fstream> 2031f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle#include <set> 2131f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle#include <sys/file.h> 2231f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle#include <sys/stat.h> 2331f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle#include <sys/uio.h> 2431f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle 2531f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle#include "art_method-inl.h" 2631f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle#include "base/mutex.h" 2731f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle#include "jit/profiling_info.h" 2831f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle#include "safe_map.h" 2931f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle#include "utils.h" 3031f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle 3131f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravlenamespace art { 3231f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle 3331f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle// An arbitrary value to throttle save requests. Set to 500ms for now. 3431f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravlestatic constexpr const uint64_t kMilisecondsToNano = 1000000; 3531f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravlestatic constexpr const uint64_t kMinimumTimeBetweenSavesNs = 500 * kMilisecondsToNano; 3631f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle 3731f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravlebool OfflineProfilingInfo::NeedsSaving(uint64_t last_update_time_ns) const { 3831f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle return last_update_time_ns - last_update_time_ns_.LoadRelaxed() > kMinimumTimeBetweenSavesNs; 3931f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle} 4031f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle 4131f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravlevoid OfflineProfilingInfo::SaveProfilingInfo(const std::string& filename, 4231f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle uint64_t last_update_time_ns, 4331f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle const std::set<ArtMethod*>& methods) { 4431f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle if (!NeedsSaving(last_update_time_ns)) { 4531f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle VLOG(profiler) << "No need to saved profile info to " << filename; 4631f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle return; 4731f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle } 4831f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle 4931f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle if (methods.empty()) { 5031f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle VLOG(profiler) << "No info to save to " << filename; 5131f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle return; 5231f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle } 5331f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle 5431f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle DexFileToMethodsMap info; 5531f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle { 5631f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle ScopedObjectAccess soa(Thread::Current()); 5731f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle for (auto it = methods.begin(); it != methods.end(); it++) { 5831f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle AddMethodInfo(*it, &info); 5931f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle } 6031f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle } 6131f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle 6231f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle // This doesn't need locking because we are trying to lock the file for exclusive 6331f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle // access and fail immediately if we can't. 6431f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle if (Serialize(filename, info)) { 6531f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle last_update_time_ns_.StoreRelaxed(last_update_time_ns); 6631f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle VLOG(profiler) << "Successfully saved profile info to " 6731f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle << filename << " with time stamp: " << last_update_time_ns; 6831f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle } 6931f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle} 7031f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle 7131f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravlevoid OfflineProfilingInfo::AddMethodInfo(ArtMethod* method, DexFileToMethodsMap* info) { 7231f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle DCHECK(method != nullptr); 7331f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle const DexFile* dex_file = method->GetDexFile(); 7431f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle 7531f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle auto info_it = info->find(dex_file); 7631f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle if (info_it == info->end()) { 7731f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle info_it = info->Put(dex_file, std::set<uint32_t>()); 7831f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle } 7931f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle info_it->second.insert(method->GetDexMethodIndex()); 8031f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle} 8131f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle 82226501b317e148aa8a8983355e85acb59c1eee83Calin Juravleenum OpenMode { 83226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle READ, 84226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle READ_WRITE 85226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle}; 86226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle 87226501b317e148aa8a8983355e85acb59c1eee83Calin Juravlestatic int OpenFile(const std::string& filename, OpenMode open_mode) { 88226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle int fd = -1; 89226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle switch (open_mode) { 90226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle case READ: 91226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle fd = open(filename.c_str(), O_RDONLY); 92226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle break; 93226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle case READ_WRITE: 94226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle // TODO(calin) allow the shared uid of the app to access the file. 95226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle fd = open(filename.c_str(), 96226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle O_CREAT | O_WRONLY | O_TRUNC | O_NOFOLLOW | O_CLOEXEC, 97226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle S_IRUSR | S_IWUSR); 98226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle break; 99226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle } 100226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle 10131f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle if (fd < 0) { 10231f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle PLOG(WARNING) << "Failed to open profile file " << filename; 10331f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle return -1; 10431f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle } 10531f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle 10631f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle // Lock the file for exclusive access but don't wait if we can't lock it. 10731f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle int err = flock(fd, LOCK_EX | LOCK_NB); 10831f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle if (err < 0) { 10931f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle PLOG(WARNING) << "Failed to lock profile file " << filename; 11031f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle return -1; 11131f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle } 11231f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle return fd; 11331f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle} 11431f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle 11531f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravlestatic bool CloseDescriptorForFile(int fd, const std::string& filename) { 11631f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle // Now unlock the file, allowing another process in. 11731f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle int err = flock(fd, LOCK_UN); 11831f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle if (err < 0) { 11931f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle PLOG(WARNING) << "Failed to unlock profile file " << filename; 12031f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle return false; 12131f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle } 12231f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle 12331f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle // Done, close the file. 12431f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle err = ::close(fd); 12531f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle if (err < 0) { 12631f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle PLOG(WARNING) << "Failed to close descriptor for profile file" << filename; 12731f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle return false; 12831f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle } 12931f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle 13031f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle return true; 13131f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle} 13231f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle 13331f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravlestatic void WriteToFile(int fd, const std::ostringstream& os) { 13431f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle std::string data(os.str()); 13531f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle const char *p = data.c_str(); 13631f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle size_t length = data.length(); 13731f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle do { 13831f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle int n = ::write(fd, p, length); 13931f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle p += n; 14031f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle length -= n; 14131f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle } while (length > 0); 14231f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle} 14331f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle 144226501b317e148aa8a8983355e85acb59c1eee83Calin Juravlestatic constexpr const char kFieldSeparator = ','; 145226501b317e148aa8a8983355e85acb59c1eee83Calin Juravlestatic constexpr const char kLineSeparator = '\n'; 14631f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle 14731f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle/** 14831f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle * Serialization format: 14931f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle * multidex_suffix1,dex_location_checksum1,method_id11,method_id12... 15031f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle * multidex_suffix2,dex_location_checksum2,method_id21,method_id22... 15131f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle * e.g. 15231f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle * ,131232145,11,23,454,54 -> this is the first dex file, it has no multidex suffix 15331f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle * :classes5.dex,218490184,39,13,49,1 -> this is the fifth dex file. 15431f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle **/ 15531f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravlebool OfflineProfilingInfo::Serialize(const std::string& filename, 15631f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle const DexFileToMethodsMap& info) const { 157226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle int fd = OpenFile(filename, READ_WRITE); 15831f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle if (fd == -1) { 15931f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle return false; 16031f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle } 16131f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle 16231f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle // TODO(calin): Merge with a previous existing profile. 16331f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle // TODO(calin): Profile this and see how much memory it takes. If too much, 16431f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle // write to file directly. 16531f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle std::ostringstream os; 16631f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle for (auto it : info) { 16731f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle const DexFile* dex_file = it.first; 16831f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle const std::set<uint32_t>& method_dex_ids = it.second; 16931f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle 17031f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle os << DexFile::GetMultiDexSuffix(dex_file->GetLocation()) 17131f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle << kFieldSeparator 17231f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle << dex_file->GetLocationChecksum(); 17331f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle for (auto method_it : method_dex_ids) { 17431f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle os << kFieldSeparator << method_it; 17531f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle } 17631f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle os << kLineSeparator; 17731f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle } 17831f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle 17931f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle WriteToFile(fd, os); 18031f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle 18131f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle return CloseDescriptorForFile(fd, filename); 18231f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle} 183226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle 184226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle// TODO(calin): This a duplicate of Utils::Split fixing the case where the first character 185226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle// is the separator. Merge the fix into Utils::Split once verified that it doesn't break its users. 186226501b317e148aa8a8983355e85acb59c1eee83Calin Juravlestatic void SplitString(const std::string& s, char separator, std::vector<std::string>* result) { 187226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle const char* p = s.data(); 188226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle const char* end = p + s.size(); 189226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle // Check if the first character is the separator. 190226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle if (p != end && *p ==separator) { 191226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle result->push_back(""); 192226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle ++p; 193226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle } 194226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle // Process the rest of the characters. 195226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle while (p != end) { 196226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle if (*p == separator) { 197226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle ++p; 198226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle } else { 199226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle const char* start = p; 200226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle while (++p != end && *p != separator) { 201226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle // Skip to the next occurrence of the separator. 202226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle } 203226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle result->push_back(std::string(start, p - start)); 204226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle } 205226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle } 206226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle} 207226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle 208226501b317e148aa8a8983355e85acb59c1eee83Calin Juravlebool ProfileCompilationInfo::ProcessLine(const std::string& line, 209226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle const std::vector<const DexFile*>& dex_files) { 210226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle std::vector<std::string> parts; 211226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle SplitString(line, kFieldSeparator, &parts); 212226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle if (parts.size() < 3) { 213226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle LOG(WARNING) << "Invalid line: " << line; 214226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle return false; 215226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle } 216226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle 217226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle const std::string& multidex_suffix = parts[0]; 218226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle uint32_t checksum; 219226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle if (!ParseInt(parts[1].c_str(), &checksum)) { 220226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle return false; 221226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle } 222226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle 223226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle const DexFile* current_dex_file = nullptr; 224226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle for (auto dex_file : dex_files) { 225226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle if (DexFile::GetMultiDexSuffix(dex_file->GetLocation()) == multidex_suffix) { 226226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle if (checksum != dex_file->GetLocationChecksum()) { 227226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle LOG(WARNING) << "Checksum mismatch for " 228226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle << dex_file->GetLocation() << " when parsing " << filename_; 229226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle return false; 230226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle } 231226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle current_dex_file = dex_file; 232226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle break; 233226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle } 234226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle } 235226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle if (current_dex_file == nullptr) { 236226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle return true; 237226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle } 238226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle 239226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle for (size_t i = 2; i < parts.size(); i++) { 240226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle uint32_t method_idx; 241226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle if (!ParseInt(parts[i].c_str(), &method_idx)) { 242226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle LOG(WARNING) << "Cannot parse method_idx " << parts[i]; 243226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle return false; 244226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle } 245226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle uint16_t class_idx = current_dex_file->GetMethodId(method_idx).class_idx_; 246226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle auto info_it = info_.find(current_dex_file); 247226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle if (info_it == info_.end()) { 248226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle info_it = info_.Put(current_dex_file, ClassToMethodsMap()); 249226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle } 250226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle ClassToMethodsMap& class_map = info_it->second; 251226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle auto class_it = class_map.find(class_idx); 252226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle if (class_it == class_map.end()) { 253226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle class_it = class_map.Put(class_idx, std::set<uint32_t>()); 254226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle } 255226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle class_it->second.insert(method_idx); 256226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle } 257226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle return true; 258226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle} 259226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle 260226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle// Parses the buffer (of length n) starting from start_from and identify new lines 261226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle// based on kLineSeparator marker. 262226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle// Returns the first position after kLineSeparator in the buffer (starting from start_from), 263226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle// or -1 if the marker doesn't appear. 264226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle// The processed characters are appended to the given line. 265226501b317e148aa8a8983355e85acb59c1eee83Calin Juravlestatic int GetLineFromBuffer(char* buffer, int n, int start_from, std::string& line) { 266226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle if (start_from >= n) { 267226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle return -1; 268226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle } 269226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle int new_line_pos = -1; 270226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle for (int i = start_from; i < n; i++) { 271226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle if (buffer[i] == kLineSeparator) { 272226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle new_line_pos = i; 273226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle break; 274226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle } 275226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle } 276226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle int append_limit = new_line_pos == -1 ? n : new_line_pos; 277226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle line.append(buffer + start_from, append_limit - start_from); 278226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle // Jump over kLineSeparator and return the position of the next character. 279226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle return new_line_pos == -1 ? new_line_pos : new_line_pos + 1; 280226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle} 281226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle 282226501b317e148aa8a8983355e85acb59c1eee83Calin Juravlebool ProfileCompilationInfo::Load(const std::vector<const DexFile*>& dex_files) { 283226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle if (dex_files.empty()) { 284226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle return true; 285226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle } 286226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle if (kIsDebugBuild) { 287226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle // In debug builds verify that the multidex suffixes are unique. 288226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle std::set<std::string> suffixes; 289226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle for (auto dex_file : dex_files) { 290226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle std::string multidex_suffix = DexFile::GetMultiDexSuffix(dex_file->GetLocation()); 291226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle DCHECK(suffixes.find(multidex_suffix) == suffixes.end()) 292226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle << "DexFiles appear to belong to different apks." 293226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle << " There are multiple dex files with the same multidex suffix: " 294226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle << multidex_suffix; 295226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle suffixes.insert(multidex_suffix); 296226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle } 297226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle } 298226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle info_.clear(); 299226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle 300226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle int fd = OpenFile(filename_, READ); 301226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle if (fd == -1) { 302226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle return false; 303226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle } 304226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle 305226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle std::string current_line; 306226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle const int kBufferSize = 1024; 307226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle char buffer[kBufferSize]; 308226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle bool success = true; 309226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle 310226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle while (success) { 311226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle int n = read(fd, buffer, kBufferSize); 312226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle if (n < 0) { 313226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle PLOG(WARNING) << "Error when reading profile file " << filename_; 314226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle success = false; 315226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle break; 316226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle } else if (n == 0) { 317226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle break; 318226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle } 319226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle // Detect the new lines from the buffer. If we manage to complete a line, 320226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle // process it. Otherwise append to the current line. 321226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle int current_start_pos = 0; 322226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle while (current_start_pos < n) { 323226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle current_start_pos = GetLineFromBuffer(buffer, n, current_start_pos, current_line); 324226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle if (current_start_pos == -1) { 325226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle break; 326226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle } 327226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle if (!ProcessLine(current_line, dex_files)) { 328226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle success = false; 329226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle break; 330226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle } 331226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle // Reset the current line (we just processed it). 332226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle current_line.clear(); 333226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle } 334226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle } 335226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle if (!success) { 336226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle info_.clear(); 337226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle } 338226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle return CloseDescriptorForFile(fd, filename_) && success; 339226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle} 340226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle 341226501b317e148aa8a8983355e85acb59c1eee83Calin Juravlebool ProfileCompilationInfo::ContainsMethod(const MethodReference& method_ref) const { 342226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle auto info_it = info_.find(method_ref.dex_file); 343226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle if (info_it != info_.end()) { 344226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle uint16_t class_idx = method_ref.dex_file->GetMethodId(method_ref.dex_method_index).class_idx_; 345226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle const ClassToMethodsMap& class_map = info_it->second; 346226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle auto class_it = class_map.find(class_idx); 347226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle if (class_it != class_map.end()) { 348226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle const std::set<uint32_t>& methods = class_it->second; 349226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle return methods.find(method_ref.dex_method_index) != methods.end(); 350226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle } 351226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle return false; 352226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle } 353226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle return false; 354226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle} 355226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle 356226501b317e148aa8a8983355e85acb59c1eee83Calin Juravlestd::string ProfileCompilationInfo::DumpInfo(bool print_full_dex_location) const { 357226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle std::ostringstream os; 358226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle if (info_.empty()) { 359226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle return "ProfileInfo: empty"; 360226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle } 361226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle 362226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle os << "ProfileInfo:"; 363226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle 364226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle // Use an additional map to achieve a predefined order based on the dex locations. 365226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle SafeMap<const std::string, const DexFile*> dex_locations_map; 366226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle for (auto info_it : info_) { 367226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle dex_locations_map.Put(info_it.first->GetLocation(), info_it.first); 368226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle } 369226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle 370226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle const std::string kFirstDexFileKeySubstitute = ":classes.dex"; 371226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle for (auto dex_file_it : dex_locations_map) { 372226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle os << "\n"; 373226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle const std::string& location = dex_file_it.first; 374226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle const DexFile* dex_file = dex_file_it.second; 375226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle if (print_full_dex_location) { 376226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle os << location; 377226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle } else { 378226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle // Replace the (empty) multidex suffix of the first key with a substitute for easier reading. 379226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle std::string multidex_suffix = DexFile::GetMultiDexSuffix(location); 380226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle os << (multidex_suffix.empty() ? kFirstDexFileKeySubstitute : multidex_suffix); 381226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle } 382226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle for (auto class_it : info_.find(dex_file)->second) { 383226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle for (auto method_it : class_it.second) { 384226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle os << "\n " << PrettyMethod(method_it, *dex_file, true); 385226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle } 386226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle } 387226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle } 388226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle return os.str(); 389226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle} 390226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle 39131f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle} // namespace art 392