11cb0ef41Sopenharmony_ci// Copyright 2014 the V8 project authors. All rights reserved.
21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be
31cb0ef41Sopenharmony_ci// found in the LICENSE file.
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ci#include "src/diagnostics/basic-block-profiler.h"
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_ci#include <algorithm>
81cb0ef41Sopenharmony_ci#include <numeric>
91cb0ef41Sopenharmony_ci#include <sstream>
101cb0ef41Sopenharmony_ci
111cb0ef41Sopenharmony_ci#include "src/base/lazy-instance.h"
121cb0ef41Sopenharmony_ci#include "src/heap/heap-inl.h"
131cb0ef41Sopenharmony_ci#include "src/objects/shared-function-info-inl.h"
141cb0ef41Sopenharmony_ci
151cb0ef41Sopenharmony_cinamespace v8 {
161cb0ef41Sopenharmony_cinamespace internal {
171cb0ef41Sopenharmony_ci
181cb0ef41Sopenharmony_ciDEFINE_LAZY_LEAKY_OBJECT_GETTER(BasicBlockProfiler, BasicBlockProfiler::Get)
191cb0ef41Sopenharmony_ci
201cb0ef41Sopenharmony_ciBasicBlockProfilerData::BasicBlockProfilerData(size_t n_blocks)
211cb0ef41Sopenharmony_ci    : block_ids_(n_blocks), counts_(n_blocks, 0) {}
221cb0ef41Sopenharmony_ci
231cb0ef41Sopenharmony_civoid BasicBlockProfilerData::SetCode(const std::ostringstream& os) {
241cb0ef41Sopenharmony_ci  code_ = os.str();
251cb0ef41Sopenharmony_ci}
261cb0ef41Sopenharmony_ci
271cb0ef41Sopenharmony_civoid BasicBlockProfilerData::SetFunctionName(std::unique_ptr<char[]> name) {
281cb0ef41Sopenharmony_ci  function_name_ = name.get();
291cb0ef41Sopenharmony_ci}
301cb0ef41Sopenharmony_ci
311cb0ef41Sopenharmony_civoid BasicBlockProfilerData::SetSchedule(const std::ostringstream& os) {
321cb0ef41Sopenharmony_ci  schedule_ = os.str();
331cb0ef41Sopenharmony_ci}
341cb0ef41Sopenharmony_ci
351cb0ef41Sopenharmony_civoid BasicBlockProfilerData::SetBlockId(size_t offset, int32_t id) {
361cb0ef41Sopenharmony_ci  DCHECK(offset < n_blocks());
371cb0ef41Sopenharmony_ci  block_ids_[offset] = id;
381cb0ef41Sopenharmony_ci}
391cb0ef41Sopenharmony_ci
401cb0ef41Sopenharmony_civoid BasicBlockProfilerData::SetHash(int hash) { hash_ = hash; }
411cb0ef41Sopenharmony_ci
421cb0ef41Sopenharmony_civoid BasicBlockProfilerData::ResetCounts() {
431cb0ef41Sopenharmony_ci  for (size_t i = 0; i < n_blocks(); ++i) {
441cb0ef41Sopenharmony_ci    counts_[i] = 0;
451cb0ef41Sopenharmony_ci  }
461cb0ef41Sopenharmony_ci}
471cb0ef41Sopenharmony_ci
481cb0ef41Sopenharmony_ciBasicBlockProfilerData* BasicBlockProfiler::NewData(size_t n_blocks) {
491cb0ef41Sopenharmony_ci  base::MutexGuard lock(&data_list_mutex_);
501cb0ef41Sopenharmony_ci  auto data = std::make_unique<BasicBlockProfilerData>(n_blocks);
511cb0ef41Sopenharmony_ci  BasicBlockProfilerData* data_ptr = data.get();
521cb0ef41Sopenharmony_ci  data_list_.push_back(std::move(data));
531cb0ef41Sopenharmony_ci  return data_ptr;
541cb0ef41Sopenharmony_ci}
551cb0ef41Sopenharmony_ci
561cb0ef41Sopenharmony_cinamespace {
571cb0ef41Sopenharmony_ciHandle<String> CopyStringToJSHeap(const std::string& source, Isolate* isolate) {
581cb0ef41Sopenharmony_ci  return isolate->factory()->NewStringFromAsciiChecked(source.c_str(),
591cb0ef41Sopenharmony_ci                                                       AllocationType::kOld);
601cb0ef41Sopenharmony_ci}
611cb0ef41Sopenharmony_ci
621cb0ef41Sopenharmony_ciconstexpr int kBlockIdSlotSize = kInt32Size;
631cb0ef41Sopenharmony_ciconstexpr int kBlockCountSlotSize = kInt32Size;
641cb0ef41Sopenharmony_ci}  // namespace
651cb0ef41Sopenharmony_ci
661cb0ef41Sopenharmony_ciBasicBlockProfilerData::BasicBlockProfilerData(
671cb0ef41Sopenharmony_ci    Handle<OnHeapBasicBlockProfilerData> js_heap_data, Isolate* isolate) {
681cb0ef41Sopenharmony_ci  DisallowHeapAllocation no_gc;
691cb0ef41Sopenharmony_ci  CopyFromJSHeap(*js_heap_data);
701cb0ef41Sopenharmony_ci}
711cb0ef41Sopenharmony_ci
721cb0ef41Sopenharmony_ciBasicBlockProfilerData::BasicBlockProfilerData(
731cb0ef41Sopenharmony_ci    OnHeapBasicBlockProfilerData js_heap_data) {
741cb0ef41Sopenharmony_ci  CopyFromJSHeap(js_heap_data);
751cb0ef41Sopenharmony_ci}
761cb0ef41Sopenharmony_ci
771cb0ef41Sopenharmony_civoid BasicBlockProfilerData::CopyFromJSHeap(
781cb0ef41Sopenharmony_ci    OnHeapBasicBlockProfilerData js_heap_data) {
791cb0ef41Sopenharmony_ci  function_name_ = js_heap_data.name().ToCString().get();
801cb0ef41Sopenharmony_ci  schedule_ = js_heap_data.schedule().ToCString().get();
811cb0ef41Sopenharmony_ci  code_ = js_heap_data.code().ToCString().get();
821cb0ef41Sopenharmony_ci  ByteArray counts(js_heap_data.counts());
831cb0ef41Sopenharmony_ci  for (int i = 0; i < counts.length() / kBlockCountSlotSize; ++i) {
841cb0ef41Sopenharmony_ci    counts_.push_back(counts.get_uint32(i));
851cb0ef41Sopenharmony_ci  }
861cb0ef41Sopenharmony_ci  ByteArray block_ids(js_heap_data.block_ids());
871cb0ef41Sopenharmony_ci  for (int i = 0; i < block_ids.length() / kBlockIdSlotSize; ++i) {
881cb0ef41Sopenharmony_ci    block_ids_.push_back(block_ids.get_int(i));
891cb0ef41Sopenharmony_ci  }
901cb0ef41Sopenharmony_ci  CHECK_EQ(block_ids_.size(), counts_.size());
911cb0ef41Sopenharmony_ci  hash_ = js_heap_data.hash();
921cb0ef41Sopenharmony_ci}
931cb0ef41Sopenharmony_ci
941cb0ef41Sopenharmony_ciHandle<OnHeapBasicBlockProfilerData> BasicBlockProfilerData::CopyToJSHeap(
951cb0ef41Sopenharmony_ci    Isolate* isolate) {
961cb0ef41Sopenharmony_ci  int id_array_size_in_bytes = static_cast<int>(n_blocks() * kBlockIdSlotSize);
971cb0ef41Sopenharmony_ci  CHECK(id_array_size_in_bytes >= 0 &&
981cb0ef41Sopenharmony_ci        static_cast<size_t>(id_array_size_in_bytes) / kBlockIdSlotSize ==
991cb0ef41Sopenharmony_ci            n_blocks());  // Overflow
1001cb0ef41Sopenharmony_ci  Handle<ByteArray> block_ids = isolate->factory()->NewByteArray(
1011cb0ef41Sopenharmony_ci      id_array_size_in_bytes, AllocationType::kOld);
1021cb0ef41Sopenharmony_ci  for (int i = 0; i < static_cast<int>(n_blocks()); ++i) {
1031cb0ef41Sopenharmony_ci    block_ids->set_int(i, block_ids_[i]);
1041cb0ef41Sopenharmony_ci  }
1051cb0ef41Sopenharmony_ci
1061cb0ef41Sopenharmony_ci  int counts_array_size_in_bytes =
1071cb0ef41Sopenharmony_ci      static_cast<int>(n_blocks() * kBlockCountSlotSize);
1081cb0ef41Sopenharmony_ci  CHECK(counts_array_size_in_bytes >= 0 &&
1091cb0ef41Sopenharmony_ci        static_cast<size_t>(counts_array_size_in_bytes) / kBlockCountSlotSize ==
1101cb0ef41Sopenharmony_ci            n_blocks());  // Overflow
1111cb0ef41Sopenharmony_ci  Handle<ByteArray> counts = isolate->factory()->NewByteArray(
1121cb0ef41Sopenharmony_ci      counts_array_size_in_bytes, AllocationType::kOld);
1131cb0ef41Sopenharmony_ci  for (int i = 0; i < static_cast<int>(n_blocks()); ++i) {
1141cb0ef41Sopenharmony_ci    counts->set_uint32(i, counts_[i]);
1151cb0ef41Sopenharmony_ci  }
1161cb0ef41Sopenharmony_ci  Handle<String> name = CopyStringToJSHeap(function_name_, isolate);
1171cb0ef41Sopenharmony_ci  Handle<String> schedule = CopyStringToJSHeap(schedule_, isolate);
1181cb0ef41Sopenharmony_ci  Handle<String> code = CopyStringToJSHeap(code_, isolate);
1191cb0ef41Sopenharmony_ci
1201cb0ef41Sopenharmony_ci  return isolate->factory()->NewOnHeapBasicBlockProfilerData(
1211cb0ef41Sopenharmony_ci      block_ids, counts, name, schedule, code, hash_, AllocationType::kOld);
1221cb0ef41Sopenharmony_ci}
1231cb0ef41Sopenharmony_ci
1241cb0ef41Sopenharmony_civoid BasicBlockProfiler::ResetCounts(Isolate* isolate) {
1251cb0ef41Sopenharmony_ci  for (const auto& data : data_list_) {
1261cb0ef41Sopenharmony_ci    data->ResetCounts();
1271cb0ef41Sopenharmony_ci  }
1281cb0ef41Sopenharmony_ci  HandleScope scope(isolate);
1291cb0ef41Sopenharmony_ci  Handle<ArrayList> list(isolate->heap()->basic_block_profiling_data(),
1301cb0ef41Sopenharmony_ci                         isolate);
1311cb0ef41Sopenharmony_ci  for (int i = 0; i < list->Length(); ++i) {
1321cb0ef41Sopenharmony_ci    Handle<ByteArray> counts(
1331cb0ef41Sopenharmony_ci        OnHeapBasicBlockProfilerData::cast(list->Get(i)).counts(), isolate);
1341cb0ef41Sopenharmony_ci    for (int j = 0; j < counts->length() / kBlockCountSlotSize; ++j) {
1351cb0ef41Sopenharmony_ci      counts->set_uint32(j, 0);
1361cb0ef41Sopenharmony_ci    }
1371cb0ef41Sopenharmony_ci  }
1381cb0ef41Sopenharmony_ci}
1391cb0ef41Sopenharmony_ci
1401cb0ef41Sopenharmony_cibool BasicBlockProfiler::HasData(Isolate* isolate) {
1411cb0ef41Sopenharmony_ci  return data_list_.size() > 0 ||
1421cb0ef41Sopenharmony_ci         isolate->heap()->basic_block_profiling_data().Length() > 0;
1431cb0ef41Sopenharmony_ci}
1441cb0ef41Sopenharmony_ci
1451cb0ef41Sopenharmony_civoid BasicBlockProfiler::Print(std::ostream& os, Isolate* isolate) {
1461cb0ef41Sopenharmony_ci  os << "---- Start Profiling Data ----" << std::endl;
1471cb0ef41Sopenharmony_ci  for (const auto& data : data_list_) {
1481cb0ef41Sopenharmony_ci    os << *data;
1491cb0ef41Sopenharmony_ci  }
1501cb0ef41Sopenharmony_ci  HandleScope scope(isolate);
1511cb0ef41Sopenharmony_ci  Handle<ArrayList> list(isolate->heap()->basic_block_profiling_data(),
1521cb0ef41Sopenharmony_ci                         isolate);
1531cb0ef41Sopenharmony_ci  std::unordered_set<std::string> builtin_names;
1541cb0ef41Sopenharmony_ci  for (int i = 0; i < list->Length(); ++i) {
1551cb0ef41Sopenharmony_ci    BasicBlockProfilerData data(
1561cb0ef41Sopenharmony_ci        handle(OnHeapBasicBlockProfilerData::cast(list->Get(i)), isolate),
1571cb0ef41Sopenharmony_ci        isolate);
1581cb0ef41Sopenharmony_ci    // Print data for builtins to both stdout and the log file, if logging is
1591cb0ef41Sopenharmony_ci    // enabled.
1601cb0ef41Sopenharmony_ci    os << data;
1611cb0ef41Sopenharmony_ci    data.Log(isolate);
1621cb0ef41Sopenharmony_ci    // Ensure that all builtin names are unique; otherwise profile-guided
1631cb0ef41Sopenharmony_ci    // optimization might get confused.
1641cb0ef41Sopenharmony_ci    CHECK(builtin_names.insert(data.function_name_).second);
1651cb0ef41Sopenharmony_ci  }
1661cb0ef41Sopenharmony_ci  os << "---- End Profiling Data ----" << std::endl;
1671cb0ef41Sopenharmony_ci}
1681cb0ef41Sopenharmony_ci
1691cb0ef41Sopenharmony_cistd::vector<bool> BasicBlockProfiler::GetCoverageBitmap(Isolate* isolate) {
1701cb0ef41Sopenharmony_ci  DisallowGarbageCollection no_gc;
1711cb0ef41Sopenharmony_ci  ArrayList list(isolate->heap()->basic_block_profiling_data());
1721cb0ef41Sopenharmony_ci  std::vector<bool> out;
1731cb0ef41Sopenharmony_ci  int list_length = list.Length();
1741cb0ef41Sopenharmony_ci  for (int i = 0; i < list_length; ++i) {
1751cb0ef41Sopenharmony_ci    BasicBlockProfilerData data(
1761cb0ef41Sopenharmony_ci        OnHeapBasicBlockProfilerData::cast(list.Get(i)));
1771cb0ef41Sopenharmony_ci    for (size_t j = 0; j < data.n_blocks(); ++j) {
1781cb0ef41Sopenharmony_ci      out.push_back(data.counts_[j] > 0);
1791cb0ef41Sopenharmony_ci    }
1801cb0ef41Sopenharmony_ci  }
1811cb0ef41Sopenharmony_ci  return out;
1821cb0ef41Sopenharmony_ci}
1831cb0ef41Sopenharmony_ci
1841cb0ef41Sopenharmony_civoid BasicBlockProfilerData::Log(Isolate* isolate) {
1851cb0ef41Sopenharmony_ci  bool any_nonzero_counter = false;
1861cb0ef41Sopenharmony_ci  for (size_t i = 0; i < n_blocks(); ++i) {
1871cb0ef41Sopenharmony_ci    if (counts_[i] > 0) {
1881cb0ef41Sopenharmony_ci      any_nonzero_counter = true;
1891cb0ef41Sopenharmony_ci      isolate->logger()->BasicBlockCounterEvent(function_name_.c_str(),
1901cb0ef41Sopenharmony_ci                                                block_ids_[i], counts_[i]);
1911cb0ef41Sopenharmony_ci    }
1921cb0ef41Sopenharmony_ci  }
1931cb0ef41Sopenharmony_ci  if (any_nonzero_counter) {
1941cb0ef41Sopenharmony_ci    isolate->logger()->BuiltinHashEvent(function_name_.c_str(), hash_);
1951cb0ef41Sopenharmony_ci  }
1961cb0ef41Sopenharmony_ci}
1971cb0ef41Sopenharmony_ci
1981cb0ef41Sopenharmony_cistd::ostream& operator<<(std::ostream& os, const BasicBlockProfilerData& d) {
1991cb0ef41Sopenharmony_ci  if (std::all_of(d.counts_.cbegin(), d.counts_.cend(),
2001cb0ef41Sopenharmony_ci                  [](uint32_t count) { return count == 0; })) {
2011cb0ef41Sopenharmony_ci    // No data was collected for this function.
2021cb0ef41Sopenharmony_ci    return os;
2031cb0ef41Sopenharmony_ci  }
2041cb0ef41Sopenharmony_ci  const char* name = "unknown function";
2051cb0ef41Sopenharmony_ci  if (!d.function_name_.empty()) {
2061cb0ef41Sopenharmony_ci    name = d.function_name_.c_str();
2071cb0ef41Sopenharmony_ci  }
2081cb0ef41Sopenharmony_ci  if (!d.schedule_.empty()) {
2091cb0ef41Sopenharmony_ci    os << "schedule for " << name << " (B0 entered " << d.counts_[0]
2101cb0ef41Sopenharmony_ci       << " times)" << std::endl;
2111cb0ef41Sopenharmony_ci    os << d.schedule_.c_str() << std::endl;
2121cb0ef41Sopenharmony_ci  }
2131cb0ef41Sopenharmony_ci  os << "block counts for " << name << ":" << std::endl;
2141cb0ef41Sopenharmony_ci  std::vector<std::pair<size_t, uint32_t>> pairs;
2151cb0ef41Sopenharmony_ci  pairs.reserve(d.n_blocks());
2161cb0ef41Sopenharmony_ci  for (size_t i = 0; i < d.n_blocks(); ++i) {
2171cb0ef41Sopenharmony_ci    pairs.push_back(std::make_pair(i, d.counts_[i]));
2181cb0ef41Sopenharmony_ci  }
2191cb0ef41Sopenharmony_ci  std::sort(
2201cb0ef41Sopenharmony_ci      pairs.begin(), pairs.end(),
2211cb0ef41Sopenharmony_ci      [=](std::pair<size_t, uint32_t> left, std::pair<size_t, uint32_t> right) {
2221cb0ef41Sopenharmony_ci        if (right.second == left.second) return left.first < right.first;
2231cb0ef41Sopenharmony_ci        return right.second < left.second;
2241cb0ef41Sopenharmony_ci      });
2251cb0ef41Sopenharmony_ci  for (auto it : pairs) {
2261cb0ef41Sopenharmony_ci    if (it.second == 0) break;
2271cb0ef41Sopenharmony_ci    os << "block B" << it.first << " : " << it.second << std::endl;
2281cb0ef41Sopenharmony_ci  }
2291cb0ef41Sopenharmony_ci  os << std::endl;
2301cb0ef41Sopenharmony_ci  if (!d.code_.empty()) {
2311cb0ef41Sopenharmony_ci    os << d.code_.c_str() << std::endl;
2321cb0ef41Sopenharmony_ci  }
2331cb0ef41Sopenharmony_ci  return os;
2341cb0ef41Sopenharmony_ci}
2351cb0ef41Sopenharmony_ci
2361cb0ef41Sopenharmony_ci}  // namespace internal
2371cb0ef41Sopenharmony_ci}  // namespace v8
238