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