|  | // 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 |