mirror of
https://github.com/nolen777/eagle0.git
synced 2026-07-28 20:55:44 +00:00
Include Linux runtime binaries in Shardok profiles (#8760)
This commit is contained in:
@@ -10,12 +10,14 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <ranges>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
|
||||
@@ -31,6 +33,8 @@
|
||||
namespace shardok {
|
||||
using grpc::Status;
|
||||
using grpc::StatusCode;
|
||||
using net::eagle0::common::CPU_PROFILE_ARTIFACT_TYPE_C_LIBRARY;
|
||||
using net::eagle0::common::CPU_PROFILE_ARTIFACT_TYPE_DYNAMIC_LINKER;
|
||||
using net::eagle0::common::CPU_PROFILE_ARTIFACT_TYPE_EXECUTABLE;
|
||||
using net::eagle0::common::CPU_PROFILE_ARTIFACT_TYPE_PROFILE;
|
||||
using net::eagle0::common::GameSetupInfo;
|
||||
@@ -40,6 +44,28 @@ using net::eagle0::common::VictoryCondition;
|
||||
using net::eagle0::shardok::api::PlacementCommand;
|
||||
using net::eagle0::shardok::common::EndGameCondition;
|
||||
|
||||
namespace {
|
||||
|
||||
auto FindMappedRuntimeFile(
|
||||
const std::string_view exactFilename,
|
||||
const std::string_view filenamePrefix = {}) -> std::string {
|
||||
std::ifstream maps("/proc/self/maps");
|
||||
for (std::string line; std::getline(maps, line);) {
|
||||
const auto pathStart = line.find('/');
|
||||
if (pathStart == std::string::npos) { continue; }
|
||||
|
||||
auto path = line.substr(pathStart);
|
||||
const auto filename = std::filesystem::path(path).filename().string();
|
||||
if (filename == exactFilename ||
|
||||
(!filenamePrefix.empty() && filename.starts_with(filenamePrefix))) {
|
||||
return path;
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
class NewGameException : public std::exception {
|
||||
private:
|
||||
Status status;
|
||||
@@ -168,9 +194,16 @@ auto EagleInterfaceImpl::DownloadCpuProfile(
|
||||
path = cpuProfiler_.ProfilePath();
|
||||
break;
|
||||
case CPU_PROFILE_ARTIFACT_TYPE_EXECUTABLE: path = cpuProfiler_.ExecutablePath(); break;
|
||||
case CPU_PROFILE_ARTIFACT_TYPE_C_LIBRARY: path = FindMappedRuntimeFile("libc.so.6"); break;
|
||||
case CPU_PROFILE_ARTIFACT_TYPE_DYNAMIC_LINKER:
|
||||
path = FindMappedRuntimeFile("", "ld-linux-");
|
||||
break;
|
||||
default: return Status(StatusCode::INVALID_ARGUMENT, "Unknown CPU profile artifact type");
|
||||
}
|
||||
|
||||
if (path.empty()) {
|
||||
return Status(StatusCode::NOT_FOUND, "CPU profile runtime artifact is not mapped");
|
||||
}
|
||||
std::ifstream input(path, std::ios::binary);
|
||||
if (!input.is_open()) {
|
||||
return Status(StatusCode::NOT_FOUND, "Unable to open CPU profile artifact");
|
||||
|
||||
@@ -37,6 +37,28 @@ type shardokProfileStatusResponse struct {
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
var shardokProfileArtifacts = []struct {
|
||||
filename string
|
||||
artifactType shardokpb.CpuProfileArtifactType
|
||||
}{
|
||||
{
|
||||
filename: "shardok.prof",
|
||||
artifactType: shardokpb.CpuProfileArtifactType_CPU_PROFILE_ARTIFACT_TYPE_PROFILE,
|
||||
},
|
||||
{
|
||||
filename: "shardok-server",
|
||||
artifactType: shardokpb.CpuProfileArtifactType_CPU_PROFILE_ARTIFACT_TYPE_EXECUTABLE,
|
||||
},
|
||||
{
|
||||
filename: "libc.so.6",
|
||||
artifactType: shardokpb.CpuProfileArtifactType_CPU_PROFILE_ARTIFACT_TYPE_C_LIBRARY,
|
||||
},
|
||||
{
|
||||
filename: "ld-linux-aarch64.so.1",
|
||||
artifactType: shardokpb.CpuProfileArtifactType_CPU_PROFILE_ARTIFACT_TYPE_DYNAMIC_LINKER,
|
||||
},
|
||||
}
|
||||
|
||||
func initializeShardokProfileClient() (*grpc.ClientConn, error) {
|
||||
if *shardokProfileAddr == "" {
|
||||
return nil, nil
|
||||
@@ -231,23 +253,16 @@ func handleShardokProfileDownload(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}()
|
||||
|
||||
if err := copyShardokProfileArtifact(
|
||||
ctx,
|
||||
zipWriter,
|
||||
"shardok.prof",
|
||||
shardokpb.CpuProfileArtifactType_CPU_PROFILE_ARTIFACT_TYPE_PROFILE,
|
||||
); err != nil {
|
||||
log.Printf("Failed to stream Shardok CPU profile: %v", err)
|
||||
return
|
||||
}
|
||||
if err := copyShardokProfileArtifact(
|
||||
ctx,
|
||||
zipWriter,
|
||||
"shardok-server",
|
||||
shardokpb.CpuProfileArtifactType_CPU_PROFILE_ARTIFACT_TYPE_EXECUTABLE,
|
||||
); err != nil {
|
||||
log.Printf("Failed to stream Shardok executable: %v", err)
|
||||
return
|
||||
for _, artifact := range shardokProfileArtifacts {
|
||||
if err := copyShardokProfileArtifact(
|
||||
ctx,
|
||||
zipWriter,
|
||||
artifact.filename,
|
||||
artifact.artifactType,
|
||||
); err != nil {
|
||||
log.Printf("Failed to stream Shardok CPU profile artifact %s: %v", artifact.filename, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
readme, err := zipWriter.Create("README.txt")
|
||||
@@ -255,7 +270,10 @@ func handleShardokProfileDownload(w http.ResponseWriter, r *http.Request) {
|
||||
log.Printf("Failed to add Shardok profile README: %v", err)
|
||||
return
|
||||
}
|
||||
if _, err := fmt.Fprintln(readme, "Analyze with: go tool pprof shardok-server shardok.prof"); err != nil {
|
||||
if _, err := fmt.Fprintln(
|
||||
readme,
|
||||
"Analyze with: PPROF_BINARY_PATH=. go tool pprof shardok-server shardok.prof",
|
||||
); err != nil {
|
||||
log.Printf("Failed to write Shardok profile README: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,6 +32,34 @@ func TestShardokProfileStatusResponse(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestShardokProfileArtifactsIncludeRuntimeBinaries(t *testing.T) {
|
||||
expected := map[string]shardokpb.CpuProfileArtifactType{
|
||||
"shardok.prof": shardokpb.CpuProfileArtifactType_CPU_PROFILE_ARTIFACT_TYPE_PROFILE,
|
||||
"shardok-server": shardokpb.CpuProfileArtifactType_CPU_PROFILE_ARTIFACT_TYPE_EXECUTABLE,
|
||||
"libc.so.6": shardokpb.CpuProfileArtifactType_CPU_PROFILE_ARTIFACT_TYPE_C_LIBRARY,
|
||||
"ld-linux-aarch64.so.1": shardokpb.CpuProfileArtifactType_CPU_PROFILE_ARTIFACT_TYPE_DYNAMIC_LINKER,
|
||||
}
|
||||
|
||||
for _, artifact := range shardokProfileArtifacts {
|
||||
expectedType, ok := expected[artifact.filename]
|
||||
if !ok {
|
||||
t.Fatalf("unexpected artifact %q", artifact.filename)
|
||||
}
|
||||
if artifact.artifactType != expectedType {
|
||||
t.Fatalf(
|
||||
"artifact %q has type %v, want %v",
|
||||
artifact.filename,
|
||||
artifact.artifactType,
|
||||
expectedType,
|
||||
)
|
||||
}
|
||||
delete(expected, artifact.filename)
|
||||
}
|
||||
if len(expected) != 0 {
|
||||
t.Fatalf("missing artifacts: %v", expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestShardokProfileStatusDisabled(t *testing.T) {
|
||||
previousClient := shardokProfileClient
|
||||
shardokProfileClient = nil
|
||||
|
||||
@@ -58,6 +58,8 @@ enum CpuProfileArtifactType {
|
||||
CPU_PROFILE_ARTIFACT_TYPE_UNSPECIFIED = 0;
|
||||
CPU_PROFILE_ARTIFACT_TYPE_PROFILE = 1;
|
||||
CPU_PROFILE_ARTIFACT_TYPE_EXECUTABLE = 2;
|
||||
CPU_PROFILE_ARTIFACT_TYPE_C_LIBRARY = 3;
|
||||
CPU_PROFILE_ARTIFACT_TYPE_DYNAMIC_LINKER = 4;
|
||||
}
|
||||
|
||||
message CpuProfileDownloadRequest {
|
||||
|
||||
Reference in New Issue
Block a user