authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-11-27 13:05:33+01:00
committergravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2022-11-28 17:07:34+01:00
log49ce86bddf49efcd1de8768d728d77ea1c8849f8
tree792be61adc8d62693d8872d05d4c76a0187be848
parentf348fbc024f2fb6dcd9b06b58482cbcb3d79cd57

windows: fix logic for pulling info for each core


1 files changed, 68 insertions(+), 78 deletions(-)

lib/std/zig/system/windows.zig+68-78
...@@ -92,20 +92,61 @@ const Armv8CpuInfoImpl = struct {...@@ -92,20 +92,61 @@ const Armv8CpuInfoImpl = struct {
92 }92 }
93};93};
9494
95fn detectCpuModelArm64() !*const Target.Cpu.Model {95fn getCpuInfoFromRegistry(core: usize, comptime key: []const u8) ![]const u8 {
96 // Pull the CPU identifier from the registry.96 // Technically, a registry value can be as long as 16k u16s. However, MS recommends storing
97 // Assume max number of cores to be at 8.97 // values larger than 2048 in a file rather than directly in the registry, and since we
98 const max_cpu_count = 8;98 // are only accessing a system hive \Registry\Machine, we stick to MS guidelines.
99 const cpu_count = getCpuCount();99 // https://learn.microsoft.com/en-us/windows/win32/sysinfo/registry-element-size-limits
100 const max_sz_value = 2048;
101 const key_name = std.unicode.utf8ToUtf16LeStringLiteral(key);
102
103 // Originally, I wanted to issue a single call with a more complex table structure such that we
104 // would sequentially visit each CPU#d subkey in the registry and pull the value of interest into
105 // a buffer, however, NT seems to be expecting a single buffer per each table meaning we would
106 // end up pulling only the last CPU core info, overwriting everything else.
107 // If anyone can come up with a solution to this, please do!
108 const table_size = 2;
109 var table: [table_size + 1]std.os.windows.RTL_QUERY_REGISTRY_TABLE = undefined;
100110
101 if (cpu_count > max_cpu_count) return error.TooManyCpus;111 const topkey = std.unicode.utf8ToUtf16LeStringLiteral("\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\CentralProcessor");
102112
103 const table_size = max_cpu_count * 3;113 var buf: [max_sz_value]u16 = undefined;
104 const actual_table_size = cpu_count * 3;114 var buf_uni = std.os.windows.UNICODE_STRING{
105 var table: [table_size + 1]std.os.windows.RTL_QUERY_REGISTRY_TABLE = undefined;115 .Length = buf.len * 2,
116 .MaximumLength = buf.len * 2,
117 .Buffer = &buf,
118 };
119
120 const max_cpu_buf = 4;
121 var next_cpu_buf: [max_cpu_buf]u8 = undefined;
122 const next_cpu = try std.fmt.bufPrint(&next_cpu_buf, "{d}", .{core});
123
124 var subkey: [max_cpu_buf + 1]u16 = undefined;
125 const subkey_len = try std.unicode.utf8ToUtf16Le(&subkey, next_cpu);
126 subkey[subkey_len] = 0;
127
128 table[0] = .{
129 .QueryRoutine = null,
130 .Flags = std.os.windows.RTL_QUERY_REGISTRY_SUBKEY | std.os.windows.RTL_QUERY_REGISTRY_REQUIRED,
131 .Name = subkey[0..subkey_len :0],
132 .EntryContext = null,
133 .DefaultType = std.os.windows.REG_NONE,
134 .DefaultData = null,
135 .DefaultLength = 0,
136 };
137
138 table[1] = .{
139 .QueryRoutine = null,
140 .Flags = std.os.windows.RTL_QUERY_REGISTRY_DIRECT | std.os.windows.RTL_QUERY_REGISTRY_REQUIRED,
141 .Name = @intToPtr([*:0]u16, @ptrToInt(key_name)),
142 .EntryContext = &buf_uni,
143 .DefaultType = std.os.windows.REG_NONE,
144 .DefaultData = null,
145 .DefaultLength = 0,
146 };
106147
107 // Table sentinel148 // Table sentinel
108 table[actual_table_size] = .{149 table[table_size] = .{
109 .QueryRoutine = null,150 .QueryRoutine = null,
110 .Flags = 0,151 .Flags = 0,
111 .Name = null,152 .Name = null,
...@@ -115,64 +156,6 @@ fn detectCpuModelArm64() !*const Target.Cpu.Model {...@@ -115,64 +156,6 @@ fn detectCpuModelArm64() !*const Target.Cpu.Model {
115 .DefaultLength = 0,156 .DefaultLength = 0,
116 };157 };
117158
118 // Technically, a registry value can be as long as 16k u16s. However, MS recommends storing
119 // values larger than 2048 in a file rather than directly in the registry, and since we
120 // are only accessing a system hive \Registry\Machine, we stick to MS guidelines.
121 // https://learn.microsoft.com/en-us/windows/win32/sysinfo/registry-element-size-limits
122 const max_sz_value = 2048;
123 const key_name = std.unicode.utf8ToUtf16LeStringLiteral("Identifier");
124
125 var i: usize = 0;
126 var index: usize = 0;
127 while (i < cpu_count) : (i += 1) {
128 var buf: [max_sz_value]u16 = undefined;
129 var buf_uni = std.os.windows.UNICODE_STRING{
130 .Length = buf.len * 2,
131 .MaximumLength = buf.len * 2,
132 .Buffer = &buf,
133 };
134
135 var next_cpu_buf: [std.math.log2(max_cpu_count)]u8 = undefined;
136 const next_cpu = try std.fmt.bufPrint(&next_cpu_buf, "{d}", .{i});
137
138 var subkey: [std.math.log2(max_cpu_count) + 1]u16 = undefined;
139 const subkey_len = try std.unicode.utf8ToUtf16Le(&subkey, next_cpu);
140 subkey[subkey_len] = 0;
141
142 table[index] = .{
143 .QueryRoutine = null,
144 .Flags = std.os.windows.RTL_QUERY_REGISTRY_SUBKEY | std.os.windows.RTL_QUERY_REGISTRY_REQUIRED,
145 .Name = subkey[0..subkey_len :0],
146 .EntryContext = null,
147 .DefaultType = std.os.windows.REG_NONE,
148 .DefaultData = null,
149 .DefaultLength = 0,
150 };
151
152 table[index + 1] = .{
153 .QueryRoutine = null,
154 .Flags = std.os.windows.RTL_QUERY_REGISTRY_DIRECT | std.os.windows.RTL_QUERY_REGISTRY_REQUIRED,
155 .Name = @intToPtr([*:0]u16, @ptrToInt(key_name)),
156 .EntryContext = &buf_uni,
157 .DefaultType = std.os.windows.REG_NONE,
158 .DefaultData = null,
159 .DefaultLength = 0,
160 };
161
162 table[index + 2] = .{
163 .QueryRoutine = null,
164 .Flags = std.os.windows.RTL_QUERY_REGISTRY_TOPKEY,
165 .Name = null,
166 .EntryContext = null,
167 .DefaultType = std.os.windows.REG_NONE,
168 .DefaultData = null,
169 .DefaultLength = 0,
170 };
171
172 index += 3;
173 }
174
175 const topkey = std.unicode.utf8ToUtf16LeStringLiteral("\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\CentralProcessor");
176 const res = std.os.windows.ntdll.RtlQueryRegistryValues(159 const res = std.os.windows.ntdll.RtlQueryRegistryValues(
177 std.os.windows.RTL_REGISTRY_ABSOLUTE,160 std.os.windows.RTL_REGISTRY_ABSOLUTE,
178 topkey,161 topkey,
...@@ -181,22 +164,29 @@ fn detectCpuModelArm64() !*const Target.Cpu.Model {...@@ -181,22 +164,29 @@ fn detectCpuModelArm64() !*const Target.Cpu.Model {
181 null,164 null,
182 );165 );
183 switch (res) {166 switch (res) {
184 .SUCCESS => {},167 .SUCCESS => {
185 else => return error.QueryRegistryFailed,168 var identifier_buf: [max_sz_value * 2]u8 = undefined;
169 const len = try std.unicode.utf16leToUtf8(&identifier_buf, buf_uni.Buffer[0 .. buf_uni.Length / 2]);
170 return identifier_buf[0..len];
171 },
172 else => return std.os.windows.unexpectedStatus(res),
186 }173 }
174}
175
176fn detectCpuModelArm64() !*const Target.Cpu.Model {
177 // Pull the CPU identifier from the registry.
178 // Assume max number of cores to be at 8.
179 const max_cpu_count = 8;
180 const cpu_count = getCpuCount();
181
182 if (cpu_count > max_cpu_count) return error.TooManyCpus;
187183
188 // Parse the models from strings184 // Parse the models from strings
189 var parser = Armv8CpuInfoImpl{};185 var parser = Armv8CpuInfoImpl{};
190186
191 i = 0;187 var i: usize = 0;
192 index = 0;
193 while (i < cpu_count) : (i += 1) {188 while (i < cpu_count) : (i += 1) {
194 const entry = @ptrCast(*align(1) const std.os.windows.UNICODE_STRING, table[index + 1].EntryContext);189 const identifier = try getCpuInfoFromRegistry(i, "Identifier");
195 index += 3;
196
197 var identifier_buf: [max_sz_value * 2]u8 = undefined;
198 const len = try std.unicode.utf16leToUtf8(&identifier_buf, entry.Buffer[0 .. entry.Length / 2]);
199 const identifier = identifier_buf[0..len];
200 parser.parseOne(identifier);190 parser.parseOne(identifier);
201 }191 }
202192