1#include "raid/core/manifest.hpp"2#include "raid/core/error.hpp"3#include <fstream>4#include <chrono>5#include <thread>6#include <sys/resource.h>7#ifdef __APPLE__8#include <sys/sysctl.h>9#include <sys/types.h>10#endif11#include <unistd.h>12#include <cstdio>1314namespace raid {1516namespace {17#ifdef __APPLE__18std::string sysctl_str(const char* name) { char buf[256]; size_t n = sizeof buf; if (sysctlbyname(name, buf, &n, nullptr, 0) == 0) return std::string(buf, n > 0 ? n - 1 : 0); return ""; }19i64 sysctl_i64(const char* name) { i64 v = 0; size_t n = sizeof v; if (sysctlbyname(name, &v, &n, nullptr, 0) == 0) return v; return -1; }20#endif21std::string shell(const char* cmd) {22 std::string out; if (FILE* p = popen(cmd, "r")) { char b[512]; while (fgets(b, sizeof b, p)) out += b; pclose(p); }23 while (!out.empty() && (out.back() == '\n' || out.back() == ' ')) out.pop_back();24 return out;25}26} // namespace2728std::string now_utc_iso() {29 const auto now = std::chrono::system_clock::now();30 return timestamp_iso(Timestamp(std::chrono::duration_cast<std::chrono::microseconds>(now.time_since_epoch()).count()));31}3233u64 peak_rss_bytes() { struct rusage ru{}; getrusage(RUSAGE_SELF, &ru);34#ifdef __APPLE__35 return static_cast<u64>(ru.ru_maxrss);36#else37 return static_cast<u64>(ru.ru_maxrss) * 1024;38#endif39}4041nlohmann::json host_info() {42 nlohmann::json j;43 char host[256]; gethostname(host, sizeof host); j["hostname"] = host;44 j["hardware_threads"] = std::thread::hardware_concurrency();45#ifdef __APPLE__46 j["chip"] = sysctl_str("machdep.cpu.brand_string"); j["ncpu"] = sysctl_i64("hw.ncpu"); j["perf_cores"] = sysctl_i64("hw.perflevel0.physicalcpu");47 j["eff_cores"] = sysctl_i64("hw.perflevel1.physicalcpu"); j["mem_bytes"] = sysctl_i64("hw.memsize"); j["os_version"] = sysctl_str("kern.osproductversion");48 j["os_build"] = sysctl_str("kern.osversion"); j["model"] = sysctl_str("hw.model");49 j["thermal"] = shell("pmset -g therm 2>/dev/null | tr '\\n' ';'"); j["power"] = shell("pmset -g batt 2>/dev/null | head -1");50 j["load_avg"] = shell("sysctl -n vm.loadavg");51#else52 j["os"] = shell("uname -sr"); j["chip"] = shell("grep -m1 'model name' /proc/cpuinfo | cut -d: -f2"); j["load_avg"] = shell("cat /proc/loadavg");53#endif54#if defined(__clang__)55 j["compiler"] = std::string("clang ") + __clang_version__;56#elif defined(__GNUC__)57 j["compiler"] = std::string("gcc ") + __VERSION__;58#endif59 j["raid_version"] = RAID_VERSION;60#ifdef RAID_WITH_ACCELERATE61 j["blas"] = "Apple Accelerate";62#else63 j["blas"] = "Eigen built-in";64#endif65 return j;66}6768nlohmann::json ExperimentManifest::to_json() const {69 return {{"experiment", experiment}, {"created_at_utc", created_at_utc}, {"raid_version", raid_version}, {"git_commit", git_commit},70 {"host", host}, {"plan", plan}, {"seed", seed}, {"inputs", inputs}, {"parameters", parameters}, {"records", records}};71}72void ExperimentManifest::save(const std::string& path) const {73 std::ofstream f(path); RAID_REQUIRE(f.good(), io, "cannot write " + path); f << to_json().dump(1) << "\n";74}7576} // namespace raid77