lib/gpalloc/src/profiling/setup/host.zig

daab053ee43316e1809a84551d573ddd1e5bf3d2

 1 const std = @import("std");
 2 const sys = @import("sys");
 3 
 4 const fs_io = sys.fs.debugIo();
 5 
 6 pub fn procs(allocator: std.mem.Allocator, process_io: std.Io) ![]const u8 {
 7     if (try commandOutputTrimmed(allocator, process_io, &.{"nproc"})) |value| {
 8         return value;
 9     }
10     const sysctl_argv = [_][]const u8{ "sysctl", "-n", "hw.physicalcpu" };
11     if (try commandOutputTrimmed(allocator, process_io, &sysctl_argv)) |value| {
12         return value;
13     }
14     return try allocator.dupe(u8, "1");
15 }
16 
17 fn commandOutputTrimmed(
18     allocator: std.mem.Allocator,
19     process_io: std.Io,
20     argv: []const []const u8,
21 ) !?[]const u8 {
22     const result = sys.process.run(allocator, process_io, .{
23         .argv = argv,
24         .stdout_limit = .limited(1024),
25         .stderr_limit = .limited(1024),
26     }) catch |err| switch (err) {
27         error.FileNotFound => return null,
28         else => return err,
29     };
30     defer allocator.free(result.stderr);
31     defer allocator.free(result.stdout);
32     if (!exitedZero(result.term)) return null;
33     const trimmed = std.mem.trim(u8, result.stdout, " \t\r\n");
34     if (trimmed.len == 0) return null;
35     return try allocator.dupe(u8, trimmed);
36 }
37 
38 pub fn commandOnPath(
39     allocator: std.mem.Allocator,
40     env: *const sys.process.Environ.Map,
41     name: []const u8,
42 ) !bool {
43     if (std.mem.indexOfScalar(u8, name, '/') != null) return canExecute(name);
44     const path = env.get("PATH") orelse return false;
45     var dirs = std.mem.splitScalar(u8, path, ':');
46     while (dirs.next()) |raw_dir| {
47         const dir = if (raw_dir.len == 0) "." else raw_dir;
48         const candidate = try std.fs.path.join(allocator, &.{ dir, name });
49         defer allocator.free(candidate);
50         if (canExecute(candidate)) return true;
51     }
52     return false;
53 }
54 
55 fn canExecute(path: []const u8) bool {
56     sys.fs.cwd().access(fs_io, path, .{ .execute = true }) catch return false;
57     return true;
58 }
59 
60 pub fn isDir(path: []const u8) bool {
61     var dir = sys.fs.cwd().openDir(fs_io, path, .{}) catch return false;
62     dir.close(fs_io);
63     return true;
64 }
65 
66 pub fn runInherited(process_io: std.Io, cwd: ?[]const u8, argv: []const []const u8) !u8 {
67     var child = sys.process.spawn(process_io, .{
68         .argv = argv,
69         .cwd = if (cwd) |path| .{ .path = path } else .inherit,
70         .stdin = .inherit,
71         .stdout = .inherit,
72         .stderr = .inherit,
73     }) catch |err| switch (err) {
74         error.FileNotFound => return 127,
75         else => return err,
76     };
77     defer sys.process.killAndReap(&child, process_io);
78     return exitCode(try sys.process.wait(&child, process_io));
79 }
80 
81 fn exitedZero(term: sys.process.Termination) bool {
82     return switch (term) {
83         .exited => |code| code == 0,
84         else => false,
85     };
86 }
87 
88 fn exitCode(term: sys.process.Termination) u8 {
89     return switch (term) {
90         .exited => |code| code,
91         .signal => 128,
92         .stopped => 128,
93         .unknown => 1,
94     };
95 }