offline_profiling_info.cc revision 998c21661b5074c293cae818d0ab7c44dcda3a66
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"
2766f55237679db90cb0a0a265043a787932b466f8Calin Juravle#include "base/stl_util.h"
2831f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle#include "jit/profiling_info.h"
2931f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle#include "safe_map.h"
3031f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle
3131f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravlenamespace art {
3231f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle
33998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravlebool ProfileCompilationInfo::SaveProfilingInfo(const std::string& filename,
34998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle                                               const std::vector<ArtMethod*>& methods) {
3531f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle  if (methods.empty()) {
3631f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle    VLOG(profiler) << "No info to save to " << filename;
37998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle    return true;
3831f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle  }
3931f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle
40998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle  ProfileCompilationInfo info;
41998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle  if (!info.Load(filename)) {
42998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle    LOG(WARNING) << "Could not load previous profile data from file " << filename;
43998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle    return false;
44998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle  }
4531f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle  {
4631f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle    ScopedObjectAccess soa(Thread::Current());
4731f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle    for (auto it = methods.begin(); it != methods.end(); it++) {
48998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle      const DexFile* dex_file = (*it)->GetDexFile();
49998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle      if (!info.AddData(dex_file->GetLocation(),
50998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle                        dex_file->GetLocationChecksum(),
51998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle                        (*it)->GetDexMethodIndex())) {
52998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle        return false;
53998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle      }
5431f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle    }
5531f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle  }
5631f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle
5731f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle  // This doesn't need locking because we are trying to lock the file for exclusive
5831f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle  // access and fail immediately if we can't.
59998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle  bool result = info.Save(filename);
60998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle  if (result) {
614d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle    VLOG(profiler) << "Successfully saved profile info to " << filename
624d77b6a511659f26fdc711e23825ffa6e7feed7aCalin Juravle        << " Size: " << GetFileSizeBytes(filename);
63998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle  } else {
64998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle    VLOG(profiler) << "Failed to save profile info to " << filename;
6531f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle  }
66998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle  return result;
6731f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle}
6831f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle
69226501b317e148aa8a8983355e85acb59c1eee83Calin Juravleenum OpenMode {
70226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  READ,
71226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  READ_WRITE
72226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle};
73226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle
74226501b317e148aa8a8983355e85acb59c1eee83Calin Juravlestatic int OpenFile(const std::string& filename, OpenMode open_mode) {
75226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  int fd = -1;
76226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  switch (open_mode) {
77226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    case READ:
78226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle      fd = open(filename.c_str(), O_RDONLY);
79226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle      break;
80226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    case READ_WRITE:
81226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle      // TODO(calin) allow the shared uid of the app to access the file.
825e2b971e468ca73a8e10a120730b3b6f17fad408Calin Juravle      fd = open(filename.c_str(), O_WRONLY | O_TRUNC | O_NOFOLLOW | O_CLOEXEC);
83226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle      break;
84226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  }
85226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle
8631f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle  if (fd < 0) {
8731f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle    PLOG(WARNING) << "Failed to open profile file " << filename;
8831f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle    return -1;
8931f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle  }
9031f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle
9131f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle  // Lock the file for exclusive access but don't wait if we can't lock it.
9231f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle  int err = flock(fd, LOCK_EX | LOCK_NB);
9331f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle  if (err < 0) {
9431f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle    PLOG(WARNING) << "Failed to lock profile file " << filename;
9531f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle    return -1;
9631f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle  }
9731f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle  return fd;
9831f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle}
9931f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle
10031f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravlestatic bool CloseDescriptorForFile(int fd, const std::string& filename) {
10131f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle  // Now unlock the file, allowing another process in.
10231f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle  int err = flock(fd, LOCK_UN);
10331f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle  if (err < 0) {
10431f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle    PLOG(WARNING) << "Failed to unlock profile file " << filename;
10531f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle    return false;
10631f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle  }
10731f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle
10831f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle  // Done, close the file.
10931f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle  err = ::close(fd);
11031f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle  if (err < 0) {
11131f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle    PLOG(WARNING) << "Failed to close descriptor for profile file" << filename;
11231f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle    return false;
11331f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle  }
11431f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle
11531f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle  return true;
11631f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle}
11731f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle
11831f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravlestatic void WriteToFile(int fd, const std::ostringstream& os) {
11931f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle  std::string data(os.str());
12031f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle  const char *p = data.c_str();
12131f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle  size_t length = data.length();
12231f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle  do {
12331f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle    int n = ::write(fd, p, length);
12431f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle    p += n;
12531f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle    length -= n;
12631f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle  } while (length > 0);
12731f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle}
12831f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle
129226501b317e148aa8a8983355e85acb59c1eee83Calin Juravlestatic constexpr const char kFieldSeparator = ',';
130226501b317e148aa8a8983355e85acb59c1eee83Calin Juravlestatic constexpr const char kLineSeparator = '\n';
13131f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle
13231f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle/**
13331f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle * Serialization format:
13466f55237679db90cb0a0a265043a787932b466f8Calin Juravle *    dex_location1,dex_location_checksum1,method_id11,method_id12...
13566f55237679db90cb0a0a265043a787932b466f8Calin Juravle *    dex_location2,dex_location_checksum2,method_id21,method_id22...
13631f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle * e.g.
13766f55237679db90cb0a0a265043a787932b466f8Calin Juravle *    /system/priv-app/app/app.apk,131232145,11,23,454,54
13866f55237679db90cb0a0a265043a787932b466f8Calin Juravle *    /system/priv-app/app/app.apk:classes5.dex,218490184,39,13,49,1
13931f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle **/
140998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravlebool ProfileCompilationInfo::Save(const std::string& filename) {
141226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  int fd = OpenFile(filename, READ_WRITE);
14231f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle  if (fd == -1) {
14331f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle    return false;
14431f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle  }
14531f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle
14631f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle  // TODO(calin): Merge with a previous existing profile.
14731f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle  // TODO(calin): Profile this and see how much memory it takes. If too much,
14831f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle  // write to file directly.
14931f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle  std::ostringstream os;
150998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle  for (const auto& it : info_) {
151998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle    const std::string& dex_location = it.first;
152998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle    const DexFileData& dex_data = it.second;
153998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle
154998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle    os << dex_location << kFieldSeparator << dex_data.checksum;
155998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle    for (auto method_it : dex_data.method_set) {
15631f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle      os << kFieldSeparator << method_it;
15731f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle    }
15831f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle    os << kLineSeparator;
15931f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle  }
16031f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle
16131f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle  WriteToFile(fd, os);
16231f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle
16331f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle  return CloseDescriptorForFile(fd, filename);
16431f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle}
165226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle
166226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle// TODO(calin): This a duplicate of Utils::Split fixing the case where the first character
167226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle// is the separator. Merge the fix into Utils::Split once verified that it doesn't break its users.
168226501b317e148aa8a8983355e85acb59c1eee83Calin Juravlestatic void SplitString(const std::string& s, char separator, std::vector<std::string>* result) {
169226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  const char* p = s.data();
170226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  const char* end = p + s.size();
171226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  // Check if the first character is the separator.
172226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  if (p != end && *p ==separator) {
173226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    result->push_back("");
174226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    ++p;
175226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  }
176226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  // Process the rest of the characters.
177226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  while (p != end) {
178226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    if (*p == separator) {
179226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle      ++p;
180226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    } else {
181226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle      const char* start = p;
182226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle      while (++p != end && *p != separator) {
183226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle        // Skip to the next occurrence of the separator.
184226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle      }
185226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle      result->push_back(std::string(start, p - start));
186226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    }
187226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  }
188226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle}
189226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle
190998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravlebool ProfileCompilationInfo::AddData(const std::string& dex_location,
191998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle                                     uint32_t checksum,
192998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle                                     uint16_t method_idx) {
193998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle  auto info_it = info_.find(dex_location);
194998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle  if (info_it == info_.end()) {
195998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle    info_it = info_.Put(dex_location, DexFileData(checksum));
196998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle  }
197998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle  if (info_it->second.checksum != checksum) {
198998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle    LOG(WARNING) << "Checksum mismatch for dex " << dex_location;
199998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle    return false;
200998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle  }
201998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle  info_it->second.method_set.insert(method_idx);
202998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle  return true;
203998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle}
204998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle
205998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravlebool ProfileCompilationInfo::ProcessLine(const std::string& line) {
206226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  std::vector<std::string> parts;
207226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  SplitString(line, kFieldSeparator, &parts);
208226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  if (parts.size() < 3) {
209226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    LOG(WARNING) << "Invalid line: " << line;
210226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    return false;
211226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  }
212226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle
21366f55237679db90cb0a0a265043a787932b466f8Calin Juravle  const std::string& dex_location = parts[0];
214226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  uint32_t checksum;
215226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  if (!ParseInt(parts[1].c_str(), &checksum)) {
216226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    return false;
217226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  }
218226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle
219226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  for (size_t i = 2; i < parts.size(); i++) {
220226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    uint32_t method_idx;
221226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    if (!ParseInt(parts[i].c_str(), &method_idx)) {
222226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle      LOG(WARNING) << "Cannot parse method_idx " << parts[i];
223226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle      return false;
224226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    }
225998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle    AddData(dex_location, checksum, method_idx);
226226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  }
227226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  return true;
228226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle}
229226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle
230226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle// Parses the buffer (of length n) starting from start_from and identify new lines
231226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle// based on kLineSeparator marker.
232226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle// Returns the first position after kLineSeparator in the buffer (starting from start_from),
233226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle// or -1 if the marker doesn't appear.
234226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle// The processed characters are appended to the given line.
235226501b317e148aa8a8983355e85acb59c1eee83Calin Juravlestatic int GetLineFromBuffer(char* buffer, int n, int start_from, std::string& line) {
236226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  if (start_from >= n) {
237226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    return -1;
238226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  }
239226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  int new_line_pos = -1;
240226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  for (int i = start_from; i < n; i++) {
241226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    if (buffer[i] == kLineSeparator) {
242226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle      new_line_pos = i;
243226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle      break;
244226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    }
245226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  }
246226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  int append_limit = new_line_pos == -1 ? n : new_line_pos;
247226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  line.append(buffer + start_from, append_limit - start_from);
248226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  // Jump over kLineSeparator and return the position of the next character.
249226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  return new_line_pos == -1 ? new_line_pos : new_line_pos + 1;
250226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle}
251226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle
252998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravlebool ProfileCompilationInfo::Load(const std::string& filename) {
253998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle  int fd = OpenFile(filename, READ);
254226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  if (fd == -1) {
255226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    return false;
256226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  }
257226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle
258226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  std::string current_line;
259226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  const int kBufferSize = 1024;
260226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  char buffer[kBufferSize];
261226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  bool success = true;
262226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle
263226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  while (success) {
264226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    int n = read(fd, buffer, kBufferSize);
265226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    if (n < 0) {
266998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle      PLOG(WARNING) << "Error when reading profile file " << filename;
267226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle      success = false;
268226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle      break;
269226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    } else if (n == 0) {
270226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle      break;
271226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    }
272226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    // Detect the new lines from the buffer. If we manage to complete a line,
273226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    // process it. Otherwise append to the current line.
274226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    int current_start_pos = 0;
275226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    while (current_start_pos < n) {
276226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle      current_start_pos = GetLineFromBuffer(buffer, n, current_start_pos, current_line);
277226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle      if (current_start_pos == -1) {
278226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle        break;
279226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle      }
280998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle      if (!ProcessLine(current_line)) {
281226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle        success = false;
282226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle        break;
283226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle      }
284226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle      // Reset the current line (we just processed it).
285226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle      current_line.clear();
286226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    }
287226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  }
288226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  if (!success) {
289226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    info_.clear();
290226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  }
291998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle  return CloseDescriptorForFile(fd, filename) && success;
292998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle}
293998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle
294998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravlebool ProfileCompilationInfo::Load(const ProfileCompilationInfo& other) {
295998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle  for (const auto& other_it : other.info_) {
296998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle    const std::string& other_dex_location = other_it.first;
297998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle    const DexFileData& other_dex_data = other_it.second;
298998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle
299998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle    auto info_it = info_.find(other_dex_location);
300998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle    if (info_it == info_.end()) {
301998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle      info_it = info_.Put(other_dex_location, DexFileData(other_dex_data.checksum));
302998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle    }
303998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle    if (info_it->second.checksum != other_dex_data.checksum) {
304998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle      LOG(WARNING) << "Checksum mismatch for dex " << other_dex_location;
305998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle      return false;
306998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle    }
307998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle    info_it->second.method_set.insert(other_dex_data.method_set.begin(),
308998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle                                      other_dex_data.method_set.end());
309998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle  }
310998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle  return true;
311226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle}
312226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle
313226501b317e148aa8a8983355e85acb59c1eee83Calin Juravlebool ProfileCompilationInfo::ContainsMethod(const MethodReference& method_ref) const {
314998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle  auto info_it = info_.find(method_ref.dex_file->GetLocation());
315226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  if (info_it != info_.end()) {
316998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle    if (method_ref.dex_file->GetLocationChecksum() != info_it->second.checksum) {
317998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle      return false;
318226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    }
319998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle    const std::set<uint16_t>& methods = info_it->second.method_set;
320998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle    return methods.find(method_ref.dex_method_index) != methods.end();
321226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  }
322226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  return false;
323226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle}
324226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle
325998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravleuint32_t ProfileCompilationInfo::GetNumberOfMethods() const {
326998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle  uint32_t total = 0;
327998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle  for (const auto& it : info_) {
328998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle    total += it.second.method_set.size();
329998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle  }
330998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle  return total;
331998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle}
332998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle
333998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravlestd::string ProfileCompilationInfo::DumpInfo(const std::vector<const DexFile*>* dex_files,
334998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle                                             bool print_full_dex_location) const {
335226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  std::ostringstream os;
336226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  if (info_.empty()) {
337226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    return "ProfileInfo: empty";
338226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  }
339226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle
340226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  os << "ProfileInfo:";
341226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle
342226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  const std::string kFirstDexFileKeySubstitute = ":classes.dex";
343998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle  for (const auto& it : info_) {
344226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    os << "\n";
345998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle    const std::string& location = it.first;
346998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle    const DexFileData& dex_data = it.second;
347226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    if (print_full_dex_location) {
348226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle      os << location;
349226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    } else {
350226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle      // Replace the (empty) multidex suffix of the first key with a substitute for easier reading.
351226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle      std::string multidex_suffix = DexFile::GetMultiDexSuffix(location);
352226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle      os << (multidex_suffix.empty() ? kFirstDexFileKeySubstitute : multidex_suffix);
353226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    }
354998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle    for (const auto method_it : dex_data.method_set) {
355998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle      if (dex_files != nullptr) {
356998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle        const DexFile* dex_file = nullptr;
357998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle        for (size_t i = 0; i < dex_files->size(); i++) {
358998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle          if (location == (*dex_files)[i]->GetLocation()) {
359998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle            dex_file = (*dex_files)[i];
360998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle          }
361998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle        }
362998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle        if (dex_file != nullptr) {
363998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle          os << "\n  " << PrettyMethod(method_it, *dex_file, true);
364998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle        }
365226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle      }
366998c21661b5074c293cae818d0ab7c44dcda3a66Calin Juravle      os << "\n  " << method_it;
367226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle    }
368226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  }
369226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle  return os.str();
370226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle}
371226501b317e148aa8a8983355e85acb59c1eee83Calin Juravle
37231f2c155975c5794d481df03eb0947cb48d2c6b5Calin Juravle}  // namespace art
373