blob: 8b766fa316f65c42ceada46584fa52d77c90cda5 [file] [log] [blame]
// 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