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