From 062f5ab0db9597638c3fb70576773d68be96a68c Mon Sep 17 00:00:00 2001 From: Clemens Backes Date: Thu, 15 Sep 2022 19:00:35 +0200 Subject: [PATCH] [wasm][pgo] Refactor profile information generation Before adding serialization of tiering information, refactor the existing code to use a {ProfileGenerator} class. This makes it easier to add new methods that can use all existing fields (instead of having new functions that need a lot of parameters). R=jkummerow@chromium.org Bug: v8:13209 Change-Id: I0946cb1d507fde9e6d680ad588ba963c539d1d0c Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3899301 Commit-Queue: Clemens Backes Reviewed-by: Jakob Kummerow Cr-Commit-Position: refs/heads/main@{#83257} --- src/wasm/pgo.cc | 120 ++++++++++++++++++++++++++++++------------------ 1 file changed, 76 insertions(+), 44 deletions(-) diff --git a/src/wasm/pgo.cc b/src/wasm/pgo.cc index 1da327f79d..8d9069bee2 100644 --- a/src/wasm/pgo.cc +++ b/src/wasm/pgo.cc @@ -9,58 +9,78 @@ namespace v8::internal::wasm { -base::OwnedVector GetProfileData(const WasmModule* module) { - const TypeFeedbackStorage& type_feedback = module->type_feedback; - AccountingAllocator allocator; - Zone zone{&allocator, "wasm::GetProfileData"}; - ZoneBuffer buffer{&zone}; - base::MutexGuard mutex_guard{&type_feedback.mutex}; +class ProfileGenerator { + public: + ProfileGenerator(const WasmModule* module) + : module_(module), + type_feedback_mutex_guard_(&module->type_feedback.mutex) {} - // Get an ordered list of function indexes, so we generate deterministic data. - std::vector ordered_func_indexes; - ordered_func_indexes.reserve(type_feedback.feedback_for_function.size()); - for (const auto& entry : type_feedback.feedback_for_function) { - ordered_func_indexes.push_back(entry.first); + base::OwnedVector GetProfileData() { + ZoneBuffer buffer{&zone_}; + + SerializeTypeFeedback(buffer); + // TODO(13209): Serialize tiering information. + + return base::OwnedVector::Of(buffer); } - std::sort(ordered_func_indexes.begin(), ordered_func_indexes.end()); - buffer.write_u32v(static_cast(ordered_func_indexes.size())); - for (const uint32_t func_index : ordered_func_indexes) { - buffer.write_u32v(func_index); - // Serialize {feedback_vector}. - const FunctionTypeFeedback& feedback = - type_feedback.feedback_for_function.at(func_index); - buffer.write_u32v(static_cast(feedback.feedback_vector.size())); - for (const CallSiteFeedback& call_site_feedback : - feedback.feedback_vector) { - int cases = call_site_feedback.num_cases(); - buffer.write_i32v(cases); - for (int i = 0; i < cases; ++i) { - buffer.write_i32v(call_site_feedback.function_index(i)); - buffer.write_i32v(call_site_feedback.call_count(i)); + private: + void SerializeTypeFeedback(ZoneBuffer& buffer) { + std::unordered_map& feedback_for_function = + module_->type_feedback.feedback_for_function; + + // Get an ordered list of function indexes, so we generate deterministic + // data. + std::vector ordered_function_indexes; + ordered_function_indexes.reserve(feedback_for_function.size()); + for (const auto& entry : feedback_for_function) { + // Skip functions for which we have to feedback. + if (entry.second.feedback_vector.empty()) continue; + ordered_function_indexes.push_back(entry.first); + } + std::sort(ordered_function_indexes.begin(), ordered_function_indexes.end()); + + buffer.write_u32v(static_cast(ordered_function_indexes.size())); + for (const uint32_t func_index : ordered_function_indexes) { + buffer.write_u32v(func_index); + // Serialize {feedback_vector}. + const FunctionTypeFeedback& feedback = + feedback_for_function.at(func_index); + buffer.write_u32v(static_cast(feedback.feedback_vector.size())); + for (const CallSiteFeedback& call_site_feedback : + feedback.feedback_vector) { + int cases = call_site_feedback.num_cases(); + buffer.write_i32v(cases); + for (int i = 0; i < cases; ++i) { + buffer.write_i32v(call_site_feedback.function_index(i)); + buffer.write_i32v(call_site_feedback.call_count(i)); + } + } + // Serialize {call_targets}. + buffer.write_u32v(static_cast(feedback.call_targets.size())); + for (uint32_t call_target : feedback.call_targets) { + buffer.write_u32v(call_target); } } - // Serialize {call_targets}. - buffer.write_u32v(static_cast(feedback.call_targets.size())); - for (uint32_t call_target : feedback.call_targets) { - buffer.write_u32v(call_target); - } } - return base::OwnedVector::Of(buffer); -} -void RestoreProfileData(WasmModule* module, - base::Vector profile_data) { - TypeFeedbackStorage& type_feedback = module->type_feedback; - Decoder decoder{profile_data.begin(), profile_data.end()}; + private: + const WasmModule* module_; + AccountingAllocator allocator_; + Zone zone_{&allocator_, "wasm::ProfileGenerator"}; + base::MutexGuard type_feedback_mutex_guard_; +}; + +void DeserializeTypeFeedback(Decoder& decoder, WasmModule* module) { + std::unordered_map& feedback_for_function = + module->type_feedback.feedback_for_function; uint32_t num_entries = decoder.consume_u32v("num function entries"); CHECK_LE(num_entries, module->num_declared_functions); for (uint32_t missing_entries = num_entries; missing_entries > 0; --missing_entries) { uint32_t function_index = decoder.consume_u32v("function index"); - CHECK(!type_feedback.feedback_for_function.count(function_index)); - FunctionTypeFeedback& feedback = - type_feedback.feedback_for_function[function_index]; + CHECK(!feedback_for_function.count(function_index)); + FunctionTypeFeedback& feedback = feedback_for_function[function_index]; // Deserialize {feedback_vector}. uint32_t feedback_vector_size = decoder.consume_u32v("feedback vector size"); @@ -91,6 +111,14 @@ void RestoreProfileData(WasmModule* module, call_target = decoder.consume_u32v("call target"); } } +} + +void RestoreProfileData(WasmModule* module, + base::Vector profile_data) { + Decoder decoder{profile_data.begin(), profile_data.end()}; + + DeserializeTypeFeedback(decoder, module); + CHECK(decoder.ok()); CHECK_EQ(decoder.pc(), decoder.end()); } @@ -104,12 +132,15 @@ void DumpProfileToFile(const WasmModule* module, uint32_t hash = static_cast(GetWireBytesHash(wire_bytes)); base::EmbeddedVector filename; SNPrintF(filename, "profile-wasm-%08x", hash); - base::OwnedVector profile_data = GetProfileData(module); + + ProfileGenerator profile_generator{module}; + base::OwnedVector profile_data = profile_generator.GetProfileData(); + PrintF("Dumping Wasm PGO data to file '%s' (%zu bytes)\n", filename.begin(), profile_data.size()); if (FILE* file = base::OS::FOpen(filename.begin(), "wb")) { - CHECK_EQ(profile_data.size(), - fwrite(profile_data.begin(), 1, profile_data.size(), file)); + size_t written = fwrite(profile_data.begin(), 1, profile_data.size(), file); + CHECK_EQ(profile_data.size(), written); base::Fclose(file); } } @@ -148,7 +179,8 @@ void LoadProfileFromFile(WasmModule* module, RestoreProfileData(module, profile_data.as_vector()); // Check that the generated profile is deterministic. - DCHECK_EQ(profile_data.as_vector(), GetProfileData(module).as_vector()); + DCHECK_EQ(profile_data.as_vector(), + ProfileGenerator{module}.GetProfileData().as_vector()); } } // namespace v8::internal::wasm