| // Copyright 2020 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "src/builtins/profile-data-reader.h" |
| |
| #include <fstream> |
| #include <iostream> |
| #include <unordered_map> |
| |
| #include "src/base/lazy-instance.h" |
| #include "src/flags/flags.h" |
| #include "src/utils/utils.h" |
| |
| namespace v8 { |
| namespace internal { |
| |
| namespace { |
| |
| class ProfileDataFromFileInternal : public ProfileDataFromFile { |
| public: |
| bool hash_has_value() const { return hash_has_value_; } |
| |
| void set_hash(int hash) { |
| hash_ = hash; |
| hash_has_value_ = true; |
| } |
| |
| void AddCountToBlock(size_t block_id, uint32_t count) { |
| if (block_counts_by_id_.size() <= block_id) { |
| // std::vector initializes new data to zero when resizing. |
| block_counts_by_id_.resize(block_id + 1); |
| } |
| block_counts_by_id_[block_id] += count; |
| } |
| |
| private: |
| bool hash_has_value_ = false; |
| }; |
| |
| const std::unordered_map<std::string, ProfileDataFromFileInternal>& |
| EnsureInitProfileData() { |
| static base::LeakyObject< |
| std::unordered_map<std::string, ProfileDataFromFileInternal>> |
| data; |
| #if !defined(V8_OS_STARBOARD) |
| static bool initialized = false; |
| |
| if (initialized) return *data.get(); |
| initialized = true; |
| const char* filename = FLAG_turbo_profiling_log_file; |
| if (filename == nullptr) return *data.get(); |
| std::ifstream file(filename); |
| CHECK_WITH_MSG(file.good(), "Can't read log file"); |
| for (std::string line; std::getline(file, line);) { |
| std::string token; |
| std::istringstream line_stream(line); |
| if (!std::getline(line_stream, token, ',')) continue; |
| if (token == ProfileDataFromFileConstants::kBlockCounterMarker) { |
| // Any line starting with kBlockCounterMarker is a block usage count. |
| // As defined by Logger::BasicBlockCounterEvent, the format is: |
| // literal kBlockCounterMarker , builtin_name , block_id , usage_count |
| std::string builtin_name; |
| CHECK(std::getline(line_stream, builtin_name, ',')); |
| CHECK(std::getline(line_stream, token, ',')); |
| char* end = nullptr; |
| uint32_t id = static_cast<uint32_t>(strtoul(token.c_str(), &end, 0)); |
| CHECK(errno == 0 && end != token.c_str()); |
| std::getline(line_stream, token, ','); |
| CHECK(line_stream.eof()); |
| uint32_t count = static_cast<uint32_t>(strtoul(token.c_str(), &end, 0)); |
| CHECK(errno == 0 && end != token.c_str()); |
| ProfileDataFromFileInternal& counters_and_hash = |
| (*data.get())[builtin_name]; |
| // We allow concatenating data from several Isolates, so we might see the |
| // same block multiple times. Just sum them all. |
| counters_and_hash.AddCountToBlock(id, count); |
| } else if (token == ProfileDataFromFileConstants::kBuiltinHashMarker) { |
| // Any line starting with kBuiltinHashMarker is a function hash record. |
| // As defined by Logger::BuiltinHashEvent, the format is: |
| // literal kBuiltinHashMarker , builtin_name , hash |
| std::string builtin_name; |
| CHECK(std::getline(line_stream, builtin_name, ',')); |
| std::getline(line_stream, token, ','); |
| CHECK(line_stream.eof()); |
| char* end = nullptr; |
| int hash = static_cast<int>(strtol(token.c_str(), &end, 0)); |
| CHECK(errno == 0 && end != token.c_str()); |
| ProfileDataFromFileInternal& counters_and_hash = |
| (*data.get())[builtin_name]; |
| // We allow concatenating data from several Isolates, but expect them all |
| // to be running the same build. Any file with mismatched hashes for a |
| // function is considered ill-formed. |
| CHECK_IMPLIES(counters_and_hash.hash_has_value(), |
| counters_and_hash.hash() == hash); |
| counters_and_hash.set_hash(hash); |
| } |
| } |
| for (const auto& pair : *data.get()) { |
| // Every function is required to have a hash in the log. |
| CHECK(pair.second.hash_has_value()); |
| } |
| if (data.get()->size() == 0) { |
| PrintF( |
| "No basic block counters were found in log file.\n" |
| "Did you build with v8_enable_builtins_profiling=true\n" |
| "and run with --turbo-profiling-log-builtins?\n"); |
| } |
| |
| #endif // V8_OS_STARBOARD |
| return *data.get(); |
| } |
| |
| } // namespace |
| |
| const ProfileDataFromFile* ProfileDataFromFile::TryRead(const char* name) { |
| const auto& data = EnsureInitProfileData(); |
| auto it = data.find(name); |
| return it == data.end() ? nullptr : &it->second; |
| } |
| |
| } // namespace internal |
| } // namespace v8 |