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 }