offline_profiling_info.cc revision dabdc0fe183d4684f3cf4d70cb09d318cff81b42
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>
204d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle#include <vector>
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"
27877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle#include "base/scoped_flock.h"
2866f55237679db90cb0a0a265043a787932b466f8Calin Juravle#include "base/stl_util.h"
29dabdc0fe183d4684f3cf4d70cb09d318cff81b42Mathieu Chartier#include "base/systrace.h"
30877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle#include "base/unix_file/fd_file.h"
3131f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle#include "jit/profiling_info.h"
32877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle#include "os.h"
3331f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle#include "safe_map.h"
3431f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle
3531f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravlenamespace art {
3631f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle
3734900cc6d9a14fb29a51daca02fe4b3e47e1b64cCalin Juravle// Transform the actual dex location into relative paths.
3834900cc6d9a14fb29a51daca02fe4b3e47e1b64cCalin Juravle// Note: this is OK because we don't store profiles of different apps into the same file.
3934900cc6d9a14fb29a51daca02fe4b3e47e1b64cCalin Juravle// Apps with split apks don't cause trouble because each split has a different name and will not
4034900cc6d9a14fb29a51daca02fe4b3e47e1b64cCalin Juravle// collide with other entries.
4131708b736a2d75a9eb21f51038a7703f84f95f31Calin Juravlestd::string ProfileCompilationInfo::GetProfileDexFileKey(const std::string& dex_location) {
4234900cc6d9a14fb29a51daca02fe4b3e47e1b64cCalin Juravle  DCHECK(!dex_location.empty());
4334900cc6d9a14fb29a51daca02fe4b3e47e1b64cCalin Juravle  size_t last_sep_index = dex_location.find_last_of('/');
4434900cc6d9a14fb29a51daca02fe4b3e47e1b64cCalin Juravle  if (last_sep_index == std::string::npos) {
4534900cc6d9a14fb29a51daca02fe4b3e47e1b64cCalin Juravle    return dex_location;
4634900cc6d9a14fb29a51daca02fe4b3e47e1b64cCalin Juravle  } else {
4731708b736a2d75a9eb21f51038a7703f84f95f31Calin Juravle    DCHECK(last_sep_index < dex_location.size());
4831708b736a2d75a9eb21f51038a7703f84f95f31Calin Juravle    return dex_location.substr(last_sep_index + 1);
4934900cc6d9a14fb29a51daca02fe4b3e47e1b64cCalin Juravle  }
5034900cc6d9a14fb29a51daca02fe4b3e47e1b64cCalin Juravle}
5134900cc6d9a14fb29a51daca02fe4b3e47e1b64cCalin Juravle
528913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartierbool ProfileCompilationInfo::SaveProfilingInfo(
538913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier    const std::string& filename,
548913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier    const std::vector<ArtMethod*>& methods,
558913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier    const std::set<DexCacheResolvedClasses>& resolved_classes) {
568913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier  if (methods.empty() && resolved_classes.empty()) {
5731f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle    VLOG(profiler) << "No info to save to " << filename;
58998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle    return true;
5931f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle  }
6031f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle
61dabdc0fe183d4684f3cf4d70cb09d318cff81b42Mathieu Chartier  ScopedTrace trace(__PRETTY_FUNCTION__);
62877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle  ScopedFlock flock;
63877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle  std::string error;
64877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle  if (!flock.Init(filename.c_str(), O_RDWR | O_NOFOLLOW | O_CLOEXEC, /* block */ false, &error)) {
65877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle    LOG(WARNING) << "Couldn't lock the profile file " << filename << ": " << error;
66877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle    return false;
67877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle  }
68877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle
69877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle  int fd = flock.GetFile()->Fd();
70877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle
71998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle  ProfileCompilationInfo info;
72877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle  if (!info.Load(fd)) {
73998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle    LOG(WARNING) << "Could not load previous profile data from file " << filename;
74998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle    return false;
75998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle  }
7631f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle  {
7731f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle    ScopedObjectAccess soa(Thread::Current());
788913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier    for (ArtMethod* method : methods) {
798913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier      const DexFile* dex_file = method->GetDexFile();
808913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier      if (!info.AddMethodIndex(GetProfileDexFileKey(dex_file->GetLocation()),
818913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier                               dex_file->GetLocationChecksum(),
828913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier                               method->GetDexMethodIndex())) {
83998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle        return false;
84998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle      }
8531f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle    }
868913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier    for (const DexCacheResolvedClasses& dex_cache : resolved_classes) {
878913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier      info.AddResolvedClasses(dex_cache);
888913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier    }
8931f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle  }
9031f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle
91877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle  if (!flock.GetFile()->ClearContent()) {
92877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle    PLOG(WARNING) << "Could not clear profile file: " << filename;
93877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle    return false;
94877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle  }
95877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle
9631f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle  // This doesn't need locking because we are trying to lock the file for exclusive
9731f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle  // access and fail immediately if we can't.
98877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle  bool result = info.Save(fd);
99998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle  if (result) {
1004d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle    VLOG(profiler) << "Successfully saved profile info to " << filename
1014d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle        << " Size: " << GetFileSizeBytes(filename);
102998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle  } else {
103998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle    VLOG(profiler) << "Failed to save profile info to " << filename;
10431f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle  }
105998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle  return result;
10631f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle}
10731f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle
108877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravlestatic bool WriteToFile(int fd, const std::ostringstream& os) {
10931f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle  std::string data(os.str());
11031f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle  const char *p = data.c_str();
11131f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle  size_t length = data.length();
11231f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle  do {
113877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle    int n = TEMP_FAILURE_RETRY(write(fd, p, length));
114877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle    if (n < 0) {
115877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle      PLOG(WARNING) << "Failed to write to descriptor: " << fd;
116877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle      return false;
117877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle    }
11831f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle    p += n;
11931f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle    length -= n;
12031f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle  } while (length > 0);
121877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle  return true;
12231f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle}
12331f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle
124226501b317e148aa8a8983355e85acb59c1eee83Calin Juravlestatic constexpr const char kFieldSeparator = ',';
125226501b317e148aa8a8983355e85acb59c1eee83Calin Juravlestatic constexpr const char kLineSeparator = '\n';
1268913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartierstatic constexpr const char* kClassesMarker = "classes";
12731f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle
12831f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle/**
12931f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle * Serialization format:
1308913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier *    dex_location1,dex_location_checksum1,method_id11,method_id12...,classes,class_id1,class_id2...
1318913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier *    dex_location2,dex_location_checksum2,method_id21,method_id22...,classes,class_id1,class_id2...
13231f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle * e.g.
1338913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier *    app.apk,131232145,11,23,454,54,classes,1,2,4,1234
13434900cc6d9a14fb29a51daca02fe4b3e47e1b64cCalin Juravle *    app.apk:classes5.dex,218490184,39,13,49,1
13531f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle **/
136024160850fbbf28368eae951beb4c72e2ce8fce6Calin Juravlebool ProfileCompilationInfo::Save(int fd) {
137dabdc0fe183d4684f3cf4d70cb09d318cff81b42Mathieu Chartier  ScopedTrace trace(__PRETTY_FUNCTION__);
138024160850fbbf28368eae951beb4c72e2ce8fce6Calin Juravle  DCHECK_GE(fd, 0);
13931f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle  // TODO(calin): Profile this and see how much memory it takes. If too much,
14031f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle  // write to file directly.
14131f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle  std::ostringstream os;
142998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle  for (const auto& it : info_) {
143998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle    const std::string& dex_location = it.first;
144998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle    const DexFileData& dex_data = it.second;
1458913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier    if (dex_data.method_set.empty() && dex_data.class_set.empty()) {
1468913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier      continue;
1478913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier    }
148998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle
149998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle    os << dex_location << kFieldSeparator << dex_data.checksum;
150998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle    for (auto method_it : dex_data.method_set) {
15131f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle      os << kFieldSeparator << method_it;
15231f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle    }
1538913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier    if (!dex_data.class_set.empty()) {
1548913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier      os << kFieldSeparator << kClassesMarker;
1558913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier      for (auto class_id : dex_data.class_set) {
1568913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier        os << kFieldSeparator << class_id;
1578913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier      }
1588913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier    }
15931f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle    os << kLineSeparator;
16031f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle  }
16131f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle
162877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle  return WriteToFile(fd, os);
16331f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle}
164226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle
165226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle// TODO(calin): This a duplicate of Utils::Split fixing the case where the first character
166226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle// is the separator. Merge the fix into Utils::Split once verified that it doesn't break its users.
167226501b317e148aa8a8983355e85acb59c1eee83Calin Juravlestatic void SplitString(const std::string& s, char separator, std::vector<std::string>* result) {
168226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  const char* p = s.data();
169226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  const char* end = p + s.size();
170226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  // Check if the first character is the separator.
171226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  if (p != end && *p ==separator) {
172226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    result->push_back("");
173226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    ++p;
174226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  }
175226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  // Process the rest of the characters.
176226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  while (p != end) {
177226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    if (*p == separator) {
178226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle      ++p;
179226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    } else {
180226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle      const char* start = p;
181226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle      while (++p != end && *p != separator) {
182226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle        // Skip to the next occurrence of the separator.
183226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle      }
184226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle      result->push_back(std::string(start, p - start));
185226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    }
186226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  }
187226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle}
188226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle
1898913fc1a27df8cf3b37fd99e94d87f290591328eMathieu ChartierProfileCompilationInfo::DexFileData* ProfileCompilationInfo::GetOrAddDexFileData(
1908913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier    const std::string& dex_location,
1918913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier    uint32_t checksum) {
192998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle  auto info_it = info_.find(dex_location);
193998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle  if (info_it == info_.end()) {
194998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle    info_it = info_.Put(dex_location, DexFileData(checksum));
195998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle  }
196998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle  if (info_it->second.checksum != checksum) {
197998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle    LOG(WARNING) << "Checksum mismatch for dex " << dex_location;
1988913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier    return nullptr;
1998913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier  }
2008913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier  return &info_it->second;
2018913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier}
2028913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier
2038913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartierbool ProfileCompilationInfo::AddResolvedClasses(const DexCacheResolvedClasses& classes) {
2048913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier  const std::string dex_location = GetProfileDexFileKey(classes.GetDexLocation());
2058913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier  const uint32_t checksum = classes.GetLocationChecksum();
2068913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier  DexFileData* const data = GetOrAddDexFileData(dex_location, checksum);
2078913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier  if (data == nullptr) {
208998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle    return false;
209998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle  }
2108913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier  data->class_set.insert(classes.GetClasses().begin(), classes.GetClasses().end());
2118913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier  return true;
2128913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier}
2138913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier
2148913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartierbool ProfileCompilationInfo::AddMethodIndex(const std::string& dex_location,
2158913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier                                            uint32_t checksum,
2168913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier                                            uint16_t method_idx) {
2178913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier  DexFileData* const data = GetOrAddDexFileData(dex_location, checksum);
2188913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier  if (data == nullptr) {
2198913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier    return false;
2208913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier  }
2218913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier  data->method_set.insert(method_idx);
2228913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier  return true;
2238913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier}
2248913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier
2258913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartierbool ProfileCompilationInfo::AddClassIndex(const std::string& dex_location,
2268913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier                                           uint32_t checksum,
2278913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier                                           uint16_t class_idx) {
2288913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier  DexFileData* const data = GetOrAddDexFileData(dex_location, checksum);
2298913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier  if (data == nullptr) {
2308913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier    return false;
2318913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier  }
2328913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier  data->class_set.insert(class_idx);
233998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle  return true;
234998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle}
235998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle
236998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravlebool ProfileCompilationInfo::ProcessLine(const std::string& line) {
237226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  std::vector<std::string> parts;
238226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  SplitString(line, kFieldSeparator, &parts);
239226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  if (parts.size() < 3) {
240226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    LOG(WARNING) << "Invalid line: " << line;
241226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    return false;
242226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  }
243226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle
24466f55237679db90cb0a0a265043a787932b466f8Calin Juravle  const std::string& dex_location = parts[0];
245226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  uint32_t checksum;
246226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  if (!ParseInt(parts[1].c_str(), &checksum)) {
247226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    return false;
248226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  }
249226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle
250226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  for (size_t i = 2; i < parts.size(); i++) {
2518913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier    if (parts[i] == kClassesMarker) {
2528913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier      ++i;
2538913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier      // All of the remaining idx are class def indexes.
2548913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier      for (++i; i < parts.size(); ++i) {
2558913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier        uint32_t class_def_idx;
2568913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier        if (!ParseInt(parts[i].c_str(), &class_def_idx)) {
2578913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier          LOG(WARNING) << "Cannot parse class_def_idx " << parts[i];
2588913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier          return false;
2598913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier        } else if (class_def_idx >= std::numeric_limits<uint16_t>::max()) {
2608913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier          LOG(WARNING) << "Class def idx " << class_def_idx << " is larger than uint16_t max";
2618913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier          return false;
2628913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier        }
2638913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier        if (!AddClassIndex(dex_location, checksum, class_def_idx)) {
2648913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier          return false;
2658913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier        }
2668913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier      }
2678913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier      break;
2688913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier    }
269226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    uint32_t method_idx;
270226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    if (!ParseInt(parts[i].c_str(), &method_idx)) {
271226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle      LOG(WARNING) << "Cannot parse method_idx " << parts[i];
272226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle      return false;
273226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    }
2748913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier    if (!AddMethodIndex(dex_location, checksum, method_idx)) {
275877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle      return false;
276877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle    }
277226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  }
278226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  return true;
279226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle}
280226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle
281226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle// Parses the buffer (of length n) starting from start_from and identify new lines
282226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle// based on kLineSeparator marker.
283226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle// Returns the first position after kLineSeparator in the buffer (starting from start_from),
284226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle// or -1 if the marker doesn't appear.
285226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle// The processed characters are appended to the given line.
286226501b317e148aa8a8983355e85acb59c1eee83Calin Juravlestatic int GetLineFromBuffer(char* buffer, int n, int start_from, std::string& line) {
287226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  if (start_from >= n) {
288226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    return -1;
289226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  }
290226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  int new_line_pos = -1;
291226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  for (int i = start_from; i < n; i++) {
292226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    if (buffer[i] == kLineSeparator) {
293226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle      new_line_pos = i;
294226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle      break;
295226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    }
296226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  }
297226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  int append_limit = new_line_pos == -1 ? n : new_line_pos;
298226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  line.append(buffer + start_from, append_limit - start_from);
299226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  // Jump over kLineSeparator and return the position of the next character.
300226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  return new_line_pos == -1 ? new_line_pos : new_line_pos + 1;
301226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle}
302226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle
303024160850fbbf28368eae951beb4c72e2ce8fce6Calin Juravlebool ProfileCompilationInfo::Load(int fd) {
304dabdc0fe183d4684f3cf4d70cb09d318cff81b42Mathieu Chartier  ScopedTrace trace(__PRETTY_FUNCTION__);
305024160850fbbf28368eae951beb4c72e2ce8fce6Calin Juravle  DCHECK_GE(fd, 0);
306226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle
307226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  std::string current_line;
308226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  const int kBufferSize = 1024;
309226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  char buffer[kBufferSize];
310226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle
311877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle  while (true) {
312877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle    int n = TEMP_FAILURE_RETRY(read(fd, buffer, kBufferSize));
313226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    if (n < 0) {
314877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle      PLOG(WARNING) << "Error when reading profile file";
315877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle      return false;
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      }
327998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle      if (!ProcessLine(current_line)) {
328877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle        return false;
329226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle      }
330226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle      // Reset the current line (we just processed it).
331226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle      current_line.clear();
332226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    }
333226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  }
334877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle  return true;
335998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle}
336998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle
337998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravlebool ProfileCompilationInfo::Load(const ProfileCompilationInfo& other) {
338998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle  for (const auto& other_it : other.info_) {
339998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle    const std::string& other_dex_location = other_it.first;
340998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle    const DexFileData& other_dex_data = other_it.second;
341998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle
342998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle    auto info_it = info_.find(other_dex_location);
343998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle    if (info_it == info_.end()) {
344998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle      info_it = info_.Put(other_dex_location, DexFileData(other_dex_data.checksum));
345998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle    }
346998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle    if (info_it->second.checksum != other_dex_data.checksum) {
347998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle      LOG(WARNING) << "Checksum mismatch for dex " << other_dex_location;
348998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle      return false;
349998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle    }
350998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle    info_it->second.method_set.insert(other_dex_data.method_set.begin(),
351998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle                                      other_dex_data.method_set.end());
3528913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier    info_it->second.class_set.insert(other_dex_data.class_set.begin(),
3538913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier                                     other_dex_data.class_set.end());
354998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle  }
355998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle  return true;
356226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle}
357226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle
358226501b317e148aa8a8983355e85acb59c1eee83Calin Juravlebool ProfileCompilationInfo::ContainsMethod(const MethodReference& method_ref) const {
35934900cc6d9a14fb29a51daca02fe4b3e47e1b64cCalin Juravle  auto info_it = info_.find(GetProfileDexFileKey(method_ref.dex_file->GetLocation()));
360226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  if (info_it != info_.end()) {
361998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle    if (method_ref.dex_file->GetLocationChecksum() != info_it->second.checksum) {
362998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle      return false;
363226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    }
364998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle    const std::set<uint16_t>& methods = info_it->second.method_set;
365998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle    return methods.find(method_ref.dex_method_index) != methods.end();
366226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  }
367226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  return false;
368226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle}
369226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle
370998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravleuint32_t ProfileCompilationInfo::GetNumberOfMethods() const {
371998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle  uint32_t total = 0;
372998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle  for (const auto& it : info_) {
373998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle    total += it.second.method_set.size();
374998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle  }
375998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle  return total;
376998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle}
377998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle
378998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravlestd::string ProfileCompilationInfo::DumpInfo(const std::vector<const DexFile*>* dex_files,
379998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle                                             bool print_full_dex_location) const {
380226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  std::ostringstream os;
381226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  if (info_.empty()) {
382226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    return "ProfileInfo: empty";
383226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  }
384226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle
385226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  os << "ProfileInfo:";
386226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle
387226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  const std::string kFirstDexFileKeySubstitute = ":classes.dex";
388998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle  for (const auto& it : info_) {
389226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    os << "\n";
390998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle    const std::string& location = it.first;
391998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle    const DexFileData& dex_data = it.second;
392226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    if (print_full_dex_location) {
393226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle      os << location;
394226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    } else {
395226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle      // Replace the (empty) multidex suffix of the first key with a substitute for easier reading.
396226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle      std::string multidex_suffix = DexFile::GetMultiDexSuffix(location);
397226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle      os << (multidex_suffix.empty() ? kFirstDexFileKeySubstitute : multidex_suffix);
398226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    }
399998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle    for (const auto method_it : dex_data.method_set) {
400998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle      if (dex_files != nullptr) {
401998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle        const DexFile* dex_file = nullptr;
402998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle        for (size_t i = 0; i < dex_files->size(); i++) {
403998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle          if (location == (*dex_files)[i]->GetLocation()) {
404998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle            dex_file = (*dex_files)[i];
405998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle          }
406998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle        }
407998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle        if (dex_file != nullptr) {
408998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle          os << "\n  " << PrettyMethod(method_it, *dex_file, true);
409998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle        }
410226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle      }
411998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle      os << "\n  " << method_it;
412226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    }
413226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  }
414226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  return os.str();
415226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle}
416226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle
417024160850fbbf28368eae951beb4c72e2ce8fce6Calin Juravlebool ProfileCompilationInfo::Equals(const ProfileCompilationInfo& other) {
418877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle  return info_.Equals(other.info_);
419877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle}
420877fd963548a3175665bfef25b0d24bc0e5a0135Calin Juravle
4218913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartierstd::set<DexCacheResolvedClasses> ProfileCompilationInfo::GetResolvedClasses() const {
4228913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier  std::set<DexCacheResolvedClasses> ret;
4238913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier  for (auto&& pair : info_) {
4248913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier    const std::string& profile_key = pair.first;
4258913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier    const DexFileData& data = pair.second;
4268913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier    DexCacheResolvedClasses classes(profile_key, data.checksum);
4278913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier    classes.AddClasses(data.class_set.begin(), data.class_set.end());
4288913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier    ret.insert(classes);
4298913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier  }
4308913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier  return ret;
4318913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier}
4328913fc1a27df8cf3b37fd99e94d87f290591328eMathieu Chartier
43331f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle}  // namespace art
434