Skip to documentation
SLOP

tiny.profiling.environment

Reference tiny.profiling environment

Defined in tiny.profiling.

API (6)

Actions

Public operations.

Types and contracts

Public types and contracts.

No direct callersNo direct callstiny.profilingenvironment
Static calls · unresolved targets: unknown · external targets: unknown.

Source

Called byCallsprivate; no linksrc.profiling.experiment.runprepareContextiteration.runexecuterecordcollectMetadataprivate; no linksrc.profiling.environmentcollectProcessAffinityprivate; no linksrc.profiling.environmentcommandCaptureprivate; no linksrc.profiling.environmentcpuModelprivate; no linksrc.profiling.environmentreadTrimmedprivate; no linksrc.profiling.frequencycollectenvironmentcollect
Static calls · unresolved targets: 0 · external targets: 1.
Called byCallsanalyze.comparecomparisonSupporttest; no linksrc.profiling.environmenttest: profiling environment permits a...test; no linksrc.profiling.environmenttest: profiling environment rejects h...test; no linksrc.profiling.environmenttest: profiling environment requires ...test; no linksrc.profiling.environmenttest: profiling environment requires ...test; no linksrc.profiling.environmenttest: profiling environment requires ...private; no linksrc.profiling.environmentmandatoryprivate; no linksrc.profiling.environmentsameenvironmentcomparisonSupport
Static calls · unresolved targets: 1 · external targets: 0.
Called byCallsanalyze.loadloadRunprivate; no linksrc.profiling.report.modelloadManifestjsonasU64jsonobjectenvironmentparse
Static calls · unresolved targets: 2 · external targets: 1.
Called byCallsNo direct callsprivate; no linksrc.profiling.analyze.renderwriteComparisonSupportJsonprivate; no linksrc.profiling.analyze.renderwriteRunJsonprivate; no linksrc.profiling.experiment.receiptwriteEnvironmentiteration.receiptwriteJsonprivate; no linksrc.profiling.recordwriteEnvironmentJsonenvironmentwriteJson
Static calls · unresolved targets: 1 · external targets: 3.

Source: src/profiling/environment.zig

zig
const std = @import("std");const builtin = @import("builtin");const pretty = @import("pretty");const sys = @import("sys");const frequency = @import("frequency.zig");const json = @import("json.zig");const pretty_json = pretty.json;const max_command_bytes = 4096;const max_cpuinfo_bytes = 4 * 1024 * 1024;const max_identity_bytes = 256;const max_process_status_bytes = 64 * 1024;pub const Host = struct {    hostname: ?[]const u8 = null,    os: ?[]const u8 = null,    kernel: ?[]const u8 = null,    arch: ?[]const u8 = null,    cpu_model: ?[]const u8 = null,    cpu_count: ?u64 = null,    cpu_frequency_policy: ?[]const u8 = null,    process_cpu_affinity: ?[]const u8 = null,    process_memory_affinity: ?[]const u8 = null,};pub const ComparisonSupport = enum {    supported,    missing_optimize,    optimize_mismatch,    missing_host,    os_mismatch,    arch_mismatch,    cpu_count_mismatch,    hostname_mismatch,    kernel_mismatch,    cpu_model_mismatch,    cpu_frequency_policy_missing,    cpu_frequency_policy_mismatch,    process_cpu_affinity_missing,    process_cpu_affinity_mismatch,    process_memory_affinity_missing,    process_memory_affinity_mismatch,};const ProcessAffinity = struct {    cpu: ?[]const u8 = null,    memory: ?[]const u8 = null,};pub fn collect(    allocator: std.mem.Allocator,    process_io: std.Io,) !Host {    const process_affinity = if (builtin.target.os.tag == .linux)        try collectProcessAffinity(allocator)    else        ProcessAffinity{};    const cpu_frequency_policy = if (process_affinity.cpu) |affinity|        try frequency.collect(allocator, affinity)    else        null;    const hostname = (try readTrimmed(        allocator,        "/proc/sys/kernel/hostname",        max_identity_bytes,    )) orelse try commandCapture(allocator, process_io, &.{"hostname"});    const kernel = (try readTrimmed(        allocator,        "/proc/sys/kernel/osrelease",        max_identity_bytes,    )) orelse try commandCapture(allocator, process_io, &.{ "uname", "-r" });    return .{        .hostname = hostname,        .os = @tagName(builtin.target.os.tag),        .kernel = kernel,        .arch = @tagName(builtin.cpu.arch),        .cpu_model = try cpuModel(allocator),        .cpu_count = @intCast(sys.thread.cpuCount()),        .cpu_frequency_policy = cpu_frequency_policy,        .process_cpu_affinity = process_affinity.cpu,        .process_memory_affinity = process_affinity.memory,    };}pub fn parse(value: ?std.json.Value) Host {    const object = json.object(value orelse return .{}) catch return .{};    const host = json.object(object.get("host") orelse return .{}) catch return .{};    return .{        .hostname = json.string(host.get("hostname")),        .os = json.string(host.get("os")),        .kernel = json.string(host.get("kernel")),        .arch = json.string(host.get("arch")),        .cpu_model = json.string(host.get("cpu_model")),        .cpu_count = json.asU64(host.get("cpu_count")),        .cpu_frequency_policy = json.string(host.get("cpu_frequency_policy")),        .process_cpu_affinity = json.string(host.get("process_cpu_affinity")),        .process_memory_affinity = json.string(host.get("process_memory_affinity")),    };}pub fn writeJson(out: *pretty_json.Writer, host: Host) !void {    try out.beginObject();    try out.objectField("hostname");    try out.write(host.hostname);    try out.objectField("os");    try out.write(host.os);    try out.objectField("kernel");    try out.write(host.kernel);    try out.objectField("arch");    try out.write(host.arch);    try out.objectField("cpu_model");    try out.write(host.cpu_model);    try out.objectField("cpu_count");    try out.write(host.cpu_count);    try out.objectField("cpu_frequency_policy");    try out.write(host.cpu_frequency_policy);    try out.objectField("process_cpu_affinity");    try out.write(host.process_cpu_affinity);    try out.objectField("process_memory_affinity");    try out.write(host.process_memory_affinity);    try out.endObject();}pub fn comparisonSupport(    baseline_optimize: ?[]const u8,    baseline_host: Host,    candidate_optimize: ?[]const u8,    candidate_host: Host,) ComparisonSupport {    const baseline_mode = baseline_optimize orelse return .missing_optimize;    const candidate_mode = candidate_optimize orelse return .missing_optimize;    if (!std.mem.eql(u8, baseline_mode, candidate_mode)) return .optimize_mismatch;    if (!mandatory(baseline_host) or !mandatory(candidate_host)) return .missing_host;    if (!same(baseline_host.os, candidate_host.os)) return .os_mismatch;    if (!same(baseline_host.arch, candidate_host.arch)) return .arch_mismatch;    if (baseline_host.cpu_count.? != candidate_host.cpu_count.?) return .cpu_count_mismatch;    if (!same(baseline_host.hostname, candidate_host.hostname)) return .hostname_mismatch;    if (!same(baseline_host.kernel, candidate_host.kernel)) return .kernel_mismatch;    if (!same(baseline_host.cpu_model, candidate_host.cpu_model)) return .cpu_model_mismatch;    const linux = std.mem.eql(u8, baseline_host.os.?, "linux");    if (linux and        (baseline_host.process_cpu_affinity == null or            candidate_host.process_cpu_affinity == null))    {        return .process_cpu_affinity_missing;    }    if (!same(        baseline_host.process_cpu_affinity,        candidate_host.process_cpu_affinity,    )) return .process_cpu_affinity_mismatch;    if (linux and        (baseline_host.process_memory_affinity == null or            candidate_host.process_memory_affinity == null))    {        return .process_memory_affinity_missing;    }    if (!same(        baseline_host.process_memory_affinity,        candidate_host.process_memory_affinity,    )) return .process_memory_affinity_mismatch;    if (linux and        (baseline_host.cpu_frequency_policy == null or            candidate_host.cpu_frequency_policy == null))    {        return .cpu_frequency_policy_missing;    }    if (!same(        baseline_host.cpu_frequency_policy,        candidate_host.cpu_frequency_policy,    )) return .cpu_frequency_policy_mismatch;    return .supported;}fn mandatory(host: Host) bool {    return host.os != null and host.arch != null and host.cpu_count != null;}fn same(baseline: ?[]const u8, candidate: ?[]const u8) bool {    if (baseline == null or candidate == null) return baseline == null and candidate == null;    return std.mem.eql(u8, baseline.?, candidate.?);}fn commandCapture(    allocator: std.mem.Allocator,    process_io: std.Io,    argv: []const []const u8,) !?[]const u8 {    const result = sys.process.run(allocator, process_io, .{        .argv = argv,        .stdout_limit = .limited(max_command_bytes),        .stderr_limit = .limited(max_command_bytes),    }) catch return null;    defer allocator.free(result.stderr);    if (sys.process.exitCode(result.term) != 0) {        allocator.free(result.stdout);        return null;    }    const trimmed = std.mem.trim(u8, result.stdout, " \t\r\n");    if (trimmed.len == 0) {        allocator.free(result.stdout);        return null;    }    const copy = try allocator.dupe(u8, trimmed);    allocator.free(result.stdout);    return copy;}fn cpuModel(allocator: std.mem.Allocator) !?[]const u8 {    const text = try readBounded(        allocator,        "/proc/cpuinfo",        max_cpuinfo_bytes,    ) orelse return null;    defer allocator.free(text);    const model = parseCpuModel(text) orelse return null;    return try allocator.dupe(u8, model);}fn collectProcessAffinity(allocator: std.mem.Allocator) !ProcessAffinity {    const text = try readBounded(        allocator,        "/proc/self/status",        max_process_status_bytes,    ) orelse return .{};    defer allocator.free(text);    const affinity = parseProcessAffinity(text);    const cpu = if (affinity.cpu) |value| try allocator.dupe(u8, value) else null;    errdefer if (cpu) |value| allocator.free(value);    return .{        .cpu = cpu,        .memory = if (affinity.memory) |value| try allocator.dupe(u8, value) else null,    };}fn parseProcessAffinity(text: []const u8) ProcessAffinity {    return .{        .cpu = field(text, "Cpus_allowed_list"),        .memory = field(text, "Mems_allowed_list"),    };}fn parseCpuModel(text: []const u8) ?[]const u8 {    return field(text, "model name") orelse        field(text, "Hardware") orelse        field(text, "Processor");}fn field(text: []const u8, name: []const u8) ?[]const u8 {    var lines = std.mem.splitScalar(u8, text, '\n');    while (lines.next()) |line| {        const split = std.mem.indexOfScalar(u8, line, ':') orelse continue;        const key = std.mem.trim(u8, line[0..split], " \t\r");        if (!std.ascii.eqlIgnoreCase(key, name)) continue;        const value = std.mem.trim(u8, line[split + 1 ..], " \t\r");        if (value.len != 0) return value;    }    return null;}fn readTrimmed(    allocator: std.mem.Allocator,    path: []const u8,    limit: usize,) !?[]const u8 {    const text = try readBounded(allocator, path, limit) orelse return null;    defer allocator.free(text);    const value = std.mem.trim(u8, text, " \t\r\n");    if (value.len == 0) return null;    return try allocator.dupe(u8, value);}fn readBounded(    allocator: std.mem.Allocator,    path: []const u8,    limit: usize,) !?[]u8 {    std.debug.assert(limit > 0);    std.debug.assert(std.fs.path.isAbsolute(path));    var file = sys.fs.openAbsoluteFile(path, .{}) catch return null;    defer file.close(sys.fs.debugIo());    var buffer: [4096]u8 = undefined;    var reader = file.readerStreaming(sys.fs.debugIo(), &buffer);    return reader.interface.allocRemaining(allocator, .limited(limit)) catch return null;}test "profiling environment parses Linux CPU models" {    try std.testing.expectEqualStrings(        "AMD Ryzen 7 7800X3D 8-Core Processor",        parseCpuModel(            \\processor : 0            \\model name : AMD Ryzen 7 7800X3D 8-Core Processor            \\        ).?,    );    try std.testing.expectEqualStrings(        "Raspberry Pi 5 Model B Rev 1.0",        parseCpuModel(            \\processor : 0            \\Hardware : Raspberry Pi 5 Model B Rev 1.0            \\        ).?,    );}test "profiling environment parses the process affinity envelope" {    const affinity = parseProcessAffinity(        \\Name: tiny-profile        \\Cpus_allowed: 0000ffff        \\Cpus_allowed_list: 0-15        \\Mems_allowed: 00000000,00000001        \\Mems_allowed_list: 0        \\    );    try std.testing.expectEqualStrings("0-15", affinity.cpu.?);    try std.testing.expectEqualStrings("0", affinity.memory.?);    const missing = parseProcessAffinity("Name:\ttiny-profile\n");    try std.testing.expectEqual(null, missing.cpu);    try std.testing.expectEqual(null, missing.memory);}const test_linux_host = Host{    .hostname = "bench-a",    .os = "linux",    .kernel = "7.0.11",    .arch = "x86_64",    .cpu_model = "AMD Ryzen 7 7800X3D",    .cpu_count = 16,    .cpu_frequency_policy = "policy-a",    .process_cpu_affinity = "0-15",    .process_memory_affinity = "0",};test "profiling environment requires matching build and mandatory host fields" {    const host = test_linux_host;    try std.testing.expectEqual(        ComparisonSupport.supported,        comparisonSupport("ReleaseFast", host, "ReleaseFast", host),    );    try std.testing.expectEqual(        ComparisonSupport.missing_optimize,        comparisonSupport(null, host, "ReleaseFast", host),    );    try std.testing.expectEqual(        ComparisonSupport.optimize_mismatch,        comparisonSupport("ReleaseSafe", host, "ReleaseFast", host),    );    var candidate = host;    candidate.cpu_count = null;    try std.testing.expectEqual(        ComparisonSupport.missing_host,        comparisonSupport("ReleaseFast", host, "ReleaseFast", candidate),    );    candidate = host;    candidate.os = "freebsd";    try std.testing.expectEqual(        ComparisonSupport.os_mismatch,        comparisonSupport("ReleaseFast", host, "ReleaseFast", candidate),    );    candidate = host;    candidate.arch = "aarch64";    try std.testing.expectEqual(        ComparisonSupport.arch_mismatch,        comparisonSupport("ReleaseFast", host, "ReleaseFast", candidate),    );    candidate = host;    candidate.cpu_count = 8;    try std.testing.expectEqual(        ComparisonSupport.cpu_count_mismatch,        comparisonSupport("ReleaseFast", host, "ReleaseFast", candidate),    );}test "profiling environment rejects host drift" {    const host = test_linux_host;    var candidate = host;    candidate.hostname = "bench-b";    try std.testing.expectEqual(        ComparisonSupport.hostname_mismatch,        comparisonSupport("ReleaseFast", host, "ReleaseFast", candidate),    );    candidate = host;    candidate.kernel = "7.0.12";    try std.testing.expectEqual(        ComparisonSupport.kernel_mismatch,        comparisonSupport("ReleaseFast", host, "ReleaseFast", candidate),    );    candidate = host;    candidate.cpu_model = "AMD Ryzen 9 9950X3D";    try std.testing.expectEqual(        ComparisonSupport.cpu_model_mismatch,        comparisonSupport("ReleaseFast", host, "ReleaseFast", candidate),    );    candidate.hostname = null;    try std.testing.expectEqual(        ComparisonSupport.hostname_mismatch,        comparisonSupport("ReleaseFast", host, "ReleaseFast", candidate),    );    candidate = host;    candidate.kernel = null;    var baseline = host;    baseline.kernel = null;    try std.testing.expectEqual(        ComparisonSupport.supported,        comparisonSupport("ReleaseFast", baseline, "ReleaseFast", candidate),    );}test "profiling environment requires matching Linux process affinity" {    const host = test_linux_host;    var candidate = host;    candidate.process_cpu_affinity = "0-7";    try std.testing.expectEqual(        ComparisonSupport.process_cpu_affinity_mismatch,        comparisonSupport("ReleaseFast", host, "ReleaseFast", candidate),    );    candidate = host;    candidate.process_memory_affinity = "1";    try std.testing.expectEqual(        ComparisonSupport.process_memory_affinity_mismatch,        comparisonSupport("ReleaseFast", host, "ReleaseFast", candidate),    );    candidate = host;    candidate.process_cpu_affinity = null;    try std.testing.expectEqual(        ComparisonSupport.process_cpu_affinity_missing,        comparisonSupport("ReleaseFast", host, "ReleaseFast", candidate),    );    candidate = host;    candidate.process_memory_affinity = null;    try std.testing.expectEqual(        ComparisonSupport.process_memory_affinity_missing,        comparisonSupport("ReleaseFast", host, "ReleaseFast", candidate),    );}test "profiling environment requires matching Linux frequency policy" {    const host = test_linux_host;    var candidate = host;    candidate.cpu_frequency_policy = "policy-b";    try std.testing.expectEqual(        ComparisonSupport.cpu_frequency_policy_mismatch,        comparisonSupport("ReleaseFast", host, "ReleaseFast", candidate),    );    candidate = host;    candidate.cpu_frequency_policy = null;    try std.testing.expectEqual(        ComparisonSupport.cpu_frequency_policy_missing,        comparisonSupport("ReleaseFast", host, "ReleaseFast", candidate),    );}test "profiling environment permits absent affinity outside Linux" {    const host = Host{        .os = "macos",        .arch = "aarch64",        .cpu_count = 8,    };    try std.testing.expectEqual(        ComparisonSupport.supported,        comparisonSupport("ReleaseFast", host, "ReleaseFast", host),    );    var candidate = host;    candidate.process_cpu_affinity = "0-7";    try std.testing.expectEqual(        ComparisonSupport.process_cpu_affinity_mismatch,        comparisonSupport("ReleaseFast", host, "ReleaseFast", candidate),    );    candidate = host;    candidate.cpu_frequency_policy = "policy-a";    try std.testing.expectEqual(        ComparisonSupport.cpu_frequency_policy_mismatch,        comparisonSupport("ReleaseFast", host, "ReleaseFast", candidate),    );}

Source: src/profiling/root.zig:22

zig
pub const environment = @import("environment.zig");

Audit

Definitions6
Public names6
Members9
Version26.7.0
Revisiondaab053ee433