Commit 5cad40b6 authored by Z Nguyen-Huu's avatar Z Nguyen-Huu Committed by Commit Bot

Trace turbo stack access counters per function

With this change, if we pass --trace-turbo-stack-accesses, output will
be something like:

=== Stack access counters ===
Number of functions: xx
Name: wasm-function#1, Loads: xx, Stores: xx
...
Total Loads: xx, Total Stores: xx

This only applies to optimized/wasm functions.

Bug: v8:10663
Change-Id: I0b08e3fa321b76dc53942c8fbffd14759978c7b2
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2283913
Commit-Queue: Z Nguyen-Huu <duongn@microsoft.com>
Reviewed-by: 's avatarSeth Brenith <seth.brenith@microsoft.com>
Reviewed-by: 's avatarJakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#68765}
parent 33535023
......@@ -423,12 +423,16 @@ ExternalReference ExternalReference::address_of_runtime_stats_flag() {
return ExternalReference(&TracingFlags::runtime_stats);
}
ExternalReference ExternalReference::address_of_load_from_stack_count() {
return ExternalReference(Isolate::load_from_stack_count_address());
ExternalReference ExternalReference::address_of_load_from_stack_count(
const char* function_name) {
return ExternalReference(
Isolate::load_from_stack_count_address(function_name));
}
ExternalReference ExternalReference::address_of_store_to_stack_count() {
return ExternalReference(Isolate::store_to_stack_count_address());
ExternalReference ExternalReference::address_of_store_to_stack_count(
const char* function_name) {
return ExternalReference(
Isolate::store_to_stack_count_address(function_name));
}
ExternalReference ExternalReference::address_of_one_half() {
......
......@@ -98,8 +98,6 @@ class StatsCounter;
"FLAG_mock_arraybuffer_allocator") \
V(address_of_one_half, "LDoubleConstant::one_half") \
V(address_of_runtime_stats_flag, "TracingFlags::runtime_stats") \
V(address_of_load_from_stack_count, "load_from_stack_count") \
V(address_of_store_to_stack_count, "store_to_stack_count") \
V(address_of_the_hole_nan, "the_hole_nan") \
V(address_of_uint32_bias, "uint32_bias") \
V(bytecode_size_table_address, "Bytecodes::bytecode_size_table_address") \
......@@ -326,6 +324,11 @@ class ExternalReference {
V8_EXPORT_PRIVATE V8_NOINLINE static ExternalReference
runtime_function_table_address_for_unittests(Isolate* isolate);
static V8_EXPORT_PRIVATE ExternalReference
address_of_load_from_stack_count(const char* function_name);
static V8_EXPORT_PRIVATE ExternalReference
address_of_store_to_stack_count(const char* function_name);
Address address() const { return address_; }
private:
......
......@@ -49,7 +49,8 @@ CodeGenerator::CodeGenerator(
int start_source_position, JumpOptimizationInfo* jump_opt,
PoisoningMitigationLevel poisoning_level, const AssemblerOptions& options,
int32_t builtin_index, size_t max_unoptimized_frame_height,
size_t max_pushed_argument_count, std::unique_ptr<AssemblerBuffer> buffer)
size_t max_pushed_argument_count, std::unique_ptr<AssemblerBuffer> buffer,
const char* debug_name)
: zone_(codegen_zone),
isolate_(isolate),
frame_access_state_(nullptr),
......@@ -83,7 +84,8 @@ CodeGenerator::CodeGenerator(
result_(kSuccess),
poisoning_level_(poisoning_level),
block_starts_(codegen_zone),
instr_starts_(codegen_zone) {
instr_starts_(codegen_zone),
debug_name_(debug_name) {
for (int i = 0; i < instructions->InstructionBlockCount(); ++i) {
new (&labels_[i]) Label;
}
......
......@@ -127,7 +127,8 @@ class V8_EXPORT_PRIVATE CodeGenerator final : public GapResolver::Assembler {
int start_source_position, JumpOptimizationInfo* jump_opt,
PoisoningMitigationLevel poisoning_level, const AssemblerOptions& options,
int32_t builtin_index, size_t max_unoptimized_frame_height,
size_t max_pushed_argument_count, std::unique_ptr<AssemblerBuffer> = {});
size_t max_pushed_argument_count, std::unique_ptr<AssemblerBuffer> = {},
const char* debug_name = nullptr);
// Generate native code. After calling AssembleCode, call FinalizeCode to
// produce the actual code object. If an error occurs during either phase,
......@@ -475,6 +476,8 @@ class V8_EXPORT_PRIVATE CodeGenerator final : public GapResolver::Assembler {
ZoneVector<int> block_starts_;
TurbolizerCodeOffsetsInfo offsets_info_;
ZoneVector<TurbolizerInstructionStartInfo> instr_starts_;
const char* debug_name_ = nullptr;
};
} // namespace compiler
......
......@@ -4673,14 +4673,18 @@ void CodeGenerator::PrepareForDeoptimizationExits(int deopt_count) {}
void CodeGenerator::IncrementStackAccessCounter(
InstructionOperand* source, InstructionOperand* destination) {
DCHECK(FLAG_trace_turbo_stack_accesses);
if (info()->IsNotOptimizedFunctionOrWasmFunction()) return;
DCHECK_NOT_NULL(debug_name_);
auto IncrementCounter = [&](ExternalReference counter) {
__ incl(__ ExternalReferenceAsOperand(counter));
};
if (source->IsAnyStackSlot()) {
IncrementCounter(ExternalReference::address_of_load_from_stack_count());
IncrementCounter(
ExternalReference::address_of_load_from_stack_count(debug_name_));
}
if (destination->IsAnyStackSlot()) {
IncrementCounter(ExternalReference::address_of_store_to_stack_count());
IncrementCounter(
ExternalReference::address_of_store_to_stack_count(debug_name_));
}
}
......
......@@ -506,7 +506,8 @@ class PipelineData {
osr_helper_, start_source_position_, jump_optimization_info_,
info()->GetPoisoningMitigationLevel(), assembler_options_,
info_->builtin_index(), max_unoptimized_frame_height(),
max_pushed_argument_count(), std::move(buffer));
max_pushed_argument_count(), std::move(buffer),
FLAG_trace_turbo_stack_accesses ? debug_name_.get() : nullptr);
}
void BeginPhaseKind(const char* phase_kind_name) {
......
......@@ -3323,10 +3323,12 @@ void Isolate::InitializeCodeRanges() {
namespace {
// Some global counters.
uint64_t load_from_stack_count = 0;
uint64_t store_to_stack_count = 0;
// This global counter contains number of stack loads/stores per optimized/wasm
// function.
using MapOfLoadsAndStoresPerFunction =
std::map<std::string /* function_name */,
std::pair<uint64_t /* loads */, uint64_t /* stores */>>;
MapOfLoadsAndStoresPerFunction* stack_access_count_map = nullptr;
} // namespace
bool Isolate::Init(ReadOnlyDeserializer* read_only_deserializer,
......@@ -3665,10 +3667,28 @@ std::unique_ptr<PersistentHandles> Isolate::NewPersistentHandles() {
void Isolate::DumpAndResetStats() {
if (FLAG_trace_turbo_stack_accesses) {
StdoutStream os;
os << "=== Load from stack counter: " << load_from_stack_count << std::endl;
os << "=== Store to stack counter: " << store_to_stack_count << std::endl;
load_from_stack_count = 0;
store_to_stack_count = 0;
uint64_t total_loads = 0;
uint64_t total_stores = 0;
os << "=== Stack access counters === " << std::endl;
if (!stack_access_count_map) {
os << "No stack accesses in optimized/wasm functions found.";
} else {
DCHECK_NOT_NULL(stack_access_count_map);
os << "Number of optimized/wasm stack-access functions: "
<< stack_access_count_map->size() << std::endl;
for (auto it = stack_access_count_map->cbegin();
it != stack_access_count_map->cend(); it++) {
std::string function_name((*it).first);
std::pair<uint64_t, uint64_t> per_func_count = (*it).second;
os << "Name: " << function_name << ", Loads: " << per_func_count.first
<< ", Stores: " << per_func_count.second << std::endl;
total_loads += per_func_count.first;
total_stores += per_func_count.second;
}
os << "Total Loads: " << total_loads << ", Total Stores: " << total_stores
<< std::endl;
stack_access_count_map = nullptr;
}
}
if (turbo_statistics() != nullptr) {
DCHECK(FLAG_turbo_stats || FLAG_turbo_stats_nvp);
......@@ -4563,13 +4583,29 @@ void Isolate::RemoveCodeMemoryChunk(MemoryChunk* chunk) {
#undef TRACE_ISOLATE
// static
Address Isolate::load_from_stack_count_address() {
return reinterpret_cast<Address>(&load_from_stack_count);
Address Isolate::load_from_stack_count_address(const char* function_name) {
DCHECK_NOT_NULL(function_name);
if (!stack_access_count_map) {
stack_access_count_map = new MapOfLoadsAndStoresPerFunction{};
}
auto& map = *stack_access_count_map;
std::string name(function_name);
// It is safe to return the address of std::map values.
// Only iterators and references to the erased elements are invalidated.
return reinterpret_cast<Address>(&map[name].first);
}
// static
Address Isolate::store_to_stack_count_address() {
return reinterpret_cast<Address>(&store_to_stack_count);
Address Isolate::store_to_stack_count_address(const char* function_name) {
DCHECK_NOT_NULL(function_name);
if (!stack_access_count_map) {
stack_access_count_map = new MapOfLoadsAndStoresPerFunction{};
}
auto& map = *stack_access_count_map;
std::string name(function_name);
// It is safe to return the address of std::map values.
// Only iterators and references to the erased elements are invalidated.
return reinterpret_cast<Address>(&map[name].second);
}
} // namespace internal
......
......@@ -1528,8 +1528,8 @@ class V8_EXPORT_PRIVATE Isolate final : private HiddenFactory {
bool RequiresCodeRange() const;
static Address load_from_stack_count_address();
static Address store_to_stack_count_address();
static Address load_from_stack_count_address(const char* function_name);
static Address store_to_stack_count_address(const char* function_name);
private:
explicit Isolate(std::unique_ptr<IsolateAllocator> isolate_allocator);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment