authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-26 16:02:07-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2021-04-26 16:02:07-04:00
log0de962fdd95c2770c8442e97c416b4bd42566a65
tree819e186636988018e9395a3fa2c45961c8a0e0ce
parent528a83dd6b0d73e450fca9594846fde233aa2e7a
parent7e6cc4c50565b6403bd2ecaabccd4ca37cb05ed2
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #8622 from LemonBoy/cpuinfo

stage2: Add framework for host CPU detection on Linux

2 files changed, 130 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+120
...@@ -0,0 +1,120 @@
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 const model = self.model orelse Target.Cpu.Model.generic(arch);
57 return Target.Cpu{
58 .arch = arch,
59 .model = model,
60 .features = model.features,
61 };
62 }
63};
64
65const SparcCpuinfoParser = CpuinfoParser(SparcCpuinfoImpl);
66
67test "cpuinfo: SPARC" {
68 const mock_cpuinfo =
69 \\cpu : UltraSparc T2 (Niagara2)
70 \\fpu : UltraSparc T2 integrated FPU
71 \\pmu : niagara2
72 \\type : sun4v
73 ;
74
75 var fbs = io.fixedBufferStream(mock_cpuinfo);
76
77 const r = SparcCpuinfoParser.parse(.sparcv9, fbs.reader()) catch unreachable;
78 testing.expectEqual(&Target.sparc.cpu.niagara2, r.?.model);
79 testing.expect(Target.sparc.cpu.niagara2.features.eql(r.?.features));
80}
81
82// The generic implementation of a /proc/cpuinfo parser.
83// For every line it invokes the line_hook method with the key and value strings
84// as first and second parameters. Returning false from the hook function stops
85// the iteration without raising an error.
86// When all the lines have been analyzed the finalize method is called.
87fn CpuinfoParser(comptime impl: anytype) type {
88 return struct {
89 fn parse(arch: Target.Cpu.Arch, reader: anytype) anyerror!?Target.Cpu {
90 var line_buf: [1024]u8 = undefined;
91 var obj: impl = .{};
92
93 while (true) {
94 const line = (try reader.readUntilDelimiterOrEof(&line_buf, '\n')) orelse break;
95 const colon_pos = mem.indexOfScalar(u8, line, ':') orelse continue;
96 const key = mem.trimRight(u8, line[0..colon_pos], " \t");
97 const value = mem.trimLeft(u8, line[colon_pos + 1 ..], " \t");
98
99 if (!try obj.line_hook(key, value))
100 break;
101 }
102
103 return obj.finalize(arch);
104 }
105 };
106}
107
108pub fn detectNativeCpuAndFeatures() ?Target.Cpu {
109 var f = fs.openFileAbsolute("/proc/cpuinfo", .{ .intended_io_mode = .blocking }) catch |err| switch (err) {
110 else => return null,
111 };
112 defer f.close();
113
114 switch (std.Target.current.cpu.arch) {
115 .sparcv9 => return SparcCpuinfoParser.parse(.sparcv9, f.reader()) catch null,
116 else => {},
117 }
118
119 return null;
120}