#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 AddHintToBlock(size_t true_block_id, size_t false_block_id,
uint64_t hint) {
CHECK_LT(hint, 2);
block_hints_by_id.insert(std::make_pair(
std::make_pair(true_block_id, false_block_id), hint != 0));
}
#ifdef LOG_BUILTIN_BLOCK_COUNT
void AddBlockExecutionCount(size_t block_id, uint64_t executed_count) {
executed_count_.emplace(block_id, executed_count);
}
#endif
private:
bool hash_has_value_ = false;
};
const std::unordered_map<std::string, ProfileDataFromFileInternal>&
EnsureInitProfileData() {
static base::LeakyObject<
std::unordered_map<std::string, ProfileDataFromFileInternal>>
data;
static bool initialized = false;
if (initialized) return *data.get();
initialized = true;
#ifdef LOG_BUILTIN_BLOCK_COUNT
if (v8_flags.turbo_log_builtins_count_input) {
std::ifstream raw_count_file(
v8_flags.turbo_log_builtins_count_input.value());
CHECK_WITH_MSG(raw_count_file.good(),
"Can't read raw count file for log builtin hotness.");
for (std::string line; std::getline(raw_count_file, line);) {
std::string token;
std::istringstream line_stream(line);
if (!std::getline(line_stream, token, '\t')) continue;
if (token == ProfileDataFromFileConstants::kBlockCounterMarker) {
std::string builtin_name;
CHECK(std::getline(line_stream, builtin_name, '\t'));
std::string block_id_str;
CHECK(std::getline(line_stream, block_id_str, '\t'));
char* end = nullptr;
errno = 0;
uint32_t block_id =
static_cast<uint32_t>(strtoul(block_id_str.c_str(), &end, 10));
CHECK(errno == 0);
std::string executed_count_str;
CHECK(std::getline(line_stream, executed_count_str, '\t'));
uint64_t executed_count = static_cast<uint64_t>(
strtoul(executed_count_str.c_str(), &end, 10));
CHECK(errno == 0 && end != token.c_str());
std::getline(line_stream, token, '\t');
ProfileDataFromFileInternal& block_count = (*data.get())[builtin_name];
block_count.AddBlockExecutionCount(block_id, executed_count);
CHECK(line_stream.eof());
} else if (token == ProfileDataFromFileConstants::kBuiltinHashMarker) {
std::string builtin_name;
CHECK(std::getline(line_stream, builtin_name, '\t'));
std::getline(line_stream, token, '\t');
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& block_count = (*data.get())[builtin_name];
CHECK_IMPLIES(block_count.hash_has_value(), block_count.hash() == hash);
block_count.set_hash(hash);
}
}
}
#endif
const char* filename = v8_flags.turbo_profiling_input;
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::kBlockHintMarker) {
std::string builtin_name;
CHECK(std::getline(line_stream, builtin_name, ','));
CHECK(std::getline(line_stream, token, ','));
char* end = nullptr;
errno = 0;
uint32_t true_id = static_cast<uint32_t>(strtoul(token.c_str(), &end, 0));
CHECK(errno == 0 && end != token.c_str());
CHECK(std::getline(line_stream, token, ','));
uint32_t false_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());
uint64_t hint = strtoul(token.c_str(), &end, 10);
CHECK(errno == 0 && end != token.c_str());
ProfileDataFromFileInternal& hints_and_hash = (*data.get())[builtin_name];
hints_and_hash.AddHintToBlock(true_id, false_id, hint);
CHECK(line_stream.eof());
} else if (token == ProfileDataFromFileConstants::kBuiltinHashMarker) {
std::string builtin_name;
CHECK(std::getline(line_stream, builtin_name, ','));
std::getline(line_stream, token, ',');
CHECK(line_stream.eof());
char* end = nullptr;
errno = 0;
int hash = static_cast<int>(strtol(token.c_str(), &end, 0));
CHECK(errno == 0 && end != token.c_str());
ProfileDataFromFileInternal& hints_and_hash = (*data.get())[builtin_name];
CHECK_IMPLIES(hints_and_hash.hash_has_value(),
hints_and_hash.hash() == hash);
hints_and_hash.set_hash(hash);
}
}
for (const auto& pair : *data.get()) {
CHECK(pair.second.hash_has_value());
}
return *data.get();
}
}
const ProfileDataFromFile* ProfileDataFromFile::TryRead(const char* name) {
const auto& data = EnsureInitProfileData();
auto it = data.find(name);
return it == data.end() ? nullptr : &it->second;
}
}
}