authorgravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2021-04-26 12:33:11+02:00
committergravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2021-04-26 18:11:28+02:00
log896d93e1e6f7638afd1536c0d40d93a3faeb1356
treef01402d168d0441597244df2d1b36235d0120eab
parentbf67a3fdc9efea7126058b21e687c24868bc1268

stage2: Add framework for host CPU detection on Linux

Add a generic framework to parse /proc/cpuinfo and implement the model detection for 64bit SPARC targets as proof of concept.

2 files changed, 128 insertions(+), 5 deletions(-)

lib/std/zig/system.zig+10-5
...@@ -14,6 +14,7 @@ const process = std.process;...@@ -14,6 +14,7 @@ const process = std.process;
14const Target = std.Target;14const Target = std.Target;
15const CrossTarget = std.zig.CrossTarget;15const CrossTarget = std.zig.CrossTarget;
16const macos = @import("system/macos.zig");16const macos = @import("system/macos.zig");
17const linux = @import("system/linux.zig");
17pub const windows = @import("system/windows.zig");18pub const windows = @import("system/windows.zig");
1819
19pub const getSDKPath = macos.getSDKPath;20pub const getSDKPath = macos.getSDKPath;
...@@ -911,15 +912,19 @@ pub const NativeTargetInfo = struct {...@@ -911,15 +912,19 @@ pub const NativeTargetInfo = struct {
911 .x86_64, .i386 => {912 .x86_64, .i386 => {
912 return @import("system/x86.zig").detectNativeCpuAndFeatures(cpu_arch, os, cross_target);913 return @import("system/x86.zig").detectNativeCpuAndFeatures(cpu_arch, os, cross_target);
913 },914 },
914 else => {915 else => {},
915 // This architecture does not have CPU model & feature detection yet.
916 // See https://github.com/ziglang/zig/issues/4591
917 return null;
918 },
919 }916 }
917
918 // This architecture does not have CPU model & feature detection yet.
919 // See https://github.com/ziglang/zig/issues/4591
920 if (std.Target.current.os.tag != .linux)
921 return null;
922
923 return linux.detectNativeCpuAndFeatures();
920 }924 }
921};925};
922926
923test {927test {
924 _ = @import("system/macos.zig");928 _ = @import("system/macos.zig");
929 _ = @import("system/linux.zig");
925}930}
lib/std/zig/system/linux.zig created+118
...@@ -0,0 +1,118 @@
1const std = @import("std");
2const mem = std.mem;
3const io = std.io;
4const fs = std.fs;
5const fmt = std.fmt;
6const testing = std.testing;
7
8const Target = std.Target;
9const CrossTarget = std.zig.CrossTarget;
10
11const assert = std.debug.assert;
12
13const SparcCpuinfoImpl = struct {
14 model: ?*const Target.Cpu.Model = null,
15 is_64bit: bool = false,
16
17 const cpu_names = .{
18 .{ "SuperSparc", &Target.sparc.cpu.supersparc },
19 .{ "HyperSparc", &Target.sparc.cpu.hypersparc },
20 .{ "SpitFire", &Target.sparc.cpu.ultrasparc },
21 .{ "BlackBird", &Target.sparc.cpu.ultrasparc },
22 .{ "Sabre", &Target.sparc.cpu.ultrasparc },
23 .{ "Hummingbird", &Target.sparc.cpu.ultrasparc },
24 .{ "Cheetah", &Target.sparc.cpu.ultrasparc3 },
25 .{ "Jalapeno", &Target.sparc.cpu.ultrasparc3 },
26 .{ "Jaguar", &Target.sparc.cpu.ultrasparc3 },
27 .{ "Panther", &Target.sparc.cpu.ultrasparc3 },
28 .{ "Serrano", &Target.sparc.cpu.ultrasparc3 },
29 .{ "UltraSparc T1", &Target.sparc.cpu.niagara },
30 .{ "UltraSparc T2", &Target.sparc.cpu.niagara2 },
31 .{ "UltraSparc T3", &Target.sparc.cpu.niagara3 },
32 .{ "UltraSparc T4", &Target.sparc.cpu.niagara4 },
33 .{ "UltraSparc T5", &Target.sparc.cpu.niagara4 },
34 .{ "LEON", &Target.sparc.cpu.leon3 },
35 };
36
37 fn line_hook(self: *SparcCpuinfoImpl, key: []const u8, value: []const u8) !bool {
38 if (mem.eql(u8, key, "cpu")) {
39 inline for (cpu_names) |pair| {
40 if (mem.indexOfPos(u8, value, 0, pair[0]) != null) {
41 self.model = pair[1];
42 break;
43 }
44 }
45 } else if (mem.eql(u8, key, "type")) {
46 self.is_64bit = mem.eql(u8, value, "sun4u") or mem.eql(u8, value, "sun4v");
47 }
48
49 return true;
50 }
51
52 fn finalize(self: *const SparcCpuinfoImpl, arch: Target.Cpu.Arch) ?Target.Cpu {
53 // At the moment we only support 64bit SPARC systems.
54 assert(self.is_64bit);
55
56 return Target.Cpu{
57 .arch = arch,
58 .model = self.model orelse Target.Cpu.Model.generic(arch),
59 .features = Target.Cpu.Feature.Set.empty,
60 };
61 }
62};
63
64const SparcCpuinfoParser = CpuinfoParser(SparcCpuinfoImpl);
65
66test "cpuinfo: SPARC" {
67 const mock_cpuinfo =
68 \\cpu : UltraSparc T2 (Niagara2)
69 \\fpu : UltraSparc T2 integrated FPU
70 \\pmu : niagara2
71 \\type : sun4v
72 ;
73
74 var fbs = io.fixedBufferStream(mock_cpuinfo);
75
76 const r = SparcCpuinfoParser.parse(.sparcv9, fbs.reader()) catch unreachable;
77 testing.expectEqual(&Target.sparc.cpu.niagara2, r.?.model);
78}
79
80// The generic implementation of a /proc/cpuinfo parser.
81// For every line it invokes the line_hook method with the key and value strings
82// as first and second parameters. Returning false from the hook function stops
83// the iteration without raising an error.
84// When all the lines have been analyzed the finalize method is called.
85fn CpuinfoParser(comptime impl: anytype) type {
86 return struct {
87 fn parse(arch: Target.Cpu.Arch, reader: anytype) anyerror!?Target.Cpu {
88 var line_buf: [1024]u8 = undefined;
89 var obj: impl = .{};
90
91 while (true) {
92 const line = (try reader.readUntilDelimiterOrEof(&line_buf, '\n')) orelse break;
93 const colon_pos = mem.indexOfScalar(u8, line, ':') orelse continue;
94 const key = mem.trimRight(u8, line[0..colon_pos], " \t");
95 const value = mem.trimLeft(u8, line[colon_pos + 1 ..], " \t");
96
97 if (!try obj.line_hook(key, value))
98 break;
99 }
100
101 return obj.finalize(arch);
102 }
103 };
104}
105
106pub fn detectNativeCpuAndFeatures() ?Target.Cpu {
107 var f = fs.openFileAbsolute("/proc/cpuinfo", .{ .intended_io_mode = .blocking }) catch |err| switch (err) {
108 else => return null,
109 };
110 defer f.close();
111
112 switch (std.Target.current.cpu.arch) {
113 .sparcv9 => return SparcCpuinfoParser.parse(.sparcv9, f.reader()) catch null,
114 else => {},
115 }
116
117 return null;
118}