blob: f7798ef7189f7de1738b1d24c193ffe3eb35a036 [file] [log] [blame] [edit]
// Copyright 2022 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "libhwsec-foundation/profiling/profiling.h"
#include <cctype>
#include <cstdlib>
#include <cstring>
#include <optional>
#include <string>
#include <base/files/file_path.h>
#include <base/files/file_util.h>
#include <base/logging.h>
#include <base/rand_util.h>
#include <base/strings/string_util.h>
#if ENABLE_PROFILING
extern "C" {
const char* __llvm_profile_get_filename();
void __llvm_profile_set_filename(const char*);
int __llvm_profile_write_file(void);
}
namespace {
class CodeProfiler {
public:
CodeProfiler() { hwsec_foundation::SetUpProfiling(); }
~CodeProfiler() { hwsec_foundation::End(); }
};
// This global variable handles the profraw generation for libhwsec-foundation.
CodeProfiler g_code_profiler;
} // namespace
#endif
namespace hwsec_foundation {
#if ENABLE_PROFILING
namespace {
constexpr char kProcessCommandNameFilename[] = "/proc/self/comm";
constexpr char kProfileFileDir[] =
"/mnt/stateful_partition/unencrypted/profraws";
constexpr char kProfileFileSuffix[] = "-%m-%p.profraw";
constexpr char kDefaultPrefix[] = "UNKNOWN";
std::optional<std::string> GetProcessCommandName() {
std::string name;
if (!base::ReadFileToString(base::FilePath(kProcessCommandNameFilename),
&name)) {
return {};
}
// Remove the characters we are not interested in, e.g., new line character.
base::TrimWhitespaceASCII(name, base::TRIM_TRAILING, &name);
return name;
}
std::string ConstructFilename(std::string command_name) {
// Get a random uint64_t.
// It helps maintain unique profraw filenames.
// Previously, we were using instrumented binary's signature,
// daemon name, and PID. But it doesn't always guarantee
// uniqueness (i.e. PIDs might be same in different namespaces).
std::string random_int = std::to_string(base::RandUint64());
// Build the entire string.
const base::FilePath filename =
base::FilePath(kProfileFileDir)
.Append(base::FilePath(command_name + "-" + random_int +
kProfileFileSuffix));
return filename.value();
}
} // namespace
void SetUpProfiling() {
std::string command_name = GetProcessCommandName().value_or(kDefaultPrefix);
if (command_name == kDefaultPrefix) {
LOG(WARNING) << ": Cannot fetch command name; use '" << kDefaultPrefix
<< "' instead.";
}
const char* current_profile_path = __llvm_profile_get_filename();
if (current_profile_path != nullptr && strlen(current_profile_path) != 0) {
LOG(WARNING) << __func__ << ": Overriding the current profile path: "
<< current_profile_path;
}
std::string profile_file_path = ConstructFilename(command_name);
// Set the destination filename for profraws.
__llvm_profile_set_filename(profile_file_path.c_str());
}
void End() {
__llvm_profile_write_file();
}
#else
void SetUpProfiling() {
// No-ops.
}
void End() {
// No-ops.
}
#endif
} // namespace hwsec_foundation