/* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. Copyright (C) 2009-2020 Michael Möller */ using System; using System.Collections.Generic; using System.Globalization; using System.Text; namespace OpenHardwareMonitor.Hardware.CPU { internal class CPUGroup : IGroup { private readonly List hardware = new List(); private readonly CPUID[][][] threads; private static CPUID[][] GetProcessorThreads() { List threads = new List(); for (int i = 0; i < ThreadAffinity.ProcessorGroupCount; i++) { for (int j = 0; j < 64; j++) { try { if (!ThreadAffinity.IsValid(GroupAffinity.Single((ushort)i, j))) continue; var cpuid = CPUID.Get(i, j); if (cpuid != null) threads.Add(cpuid); } catch (ArgumentOutOfRangeException) { } } } SortedDictionary> processors = new SortedDictionary>(); foreach (CPUID thread in threads) { List list; processors.TryGetValue(thread.ProcessorId, out list); if (list == null) { list = new List(); processors.Add(thread.ProcessorId, list); } list.Add(thread); } CPUID[][] processorThreads = new CPUID[processors.Count][]; int index = 0; foreach (List list in processors.Values) { processorThreads[index] = list.ToArray(); index++; } return processorThreads; } private static CPUID[][] GroupThreadsByCore(IEnumerable threads) { SortedDictionary> cores = new SortedDictionary>(); foreach (CPUID thread in threads) { List coreList; cores.TryGetValue(thread.CoreId, out coreList); if (coreList == null) { coreList = new List(); cores.Add(thread.CoreId, coreList); } coreList.Add(thread); } CPUID[][] coreThreads = new CPUID[cores.Count][]; int index = 0; foreach (List list in cores.Values) { coreThreads[index] = list.ToArray(); index++; } return coreThreads; } public CPUGroup(ISettings settings) { CPUID[][] processorThreads = GetProcessorThreads(); this.threads = new CPUID[processorThreads.Length][][]; int index = 0; foreach (CPUID[] threads in processorThreads) { if (threads.Length == 0) continue; CPUID[][] coreThreads = GroupThreadsByCore(threads); this.threads[index] = coreThreads; switch (threads[0].Vendor) { case Vendor.Intel: hardware.Add(new IntelCPU(index, coreThreads, settings)); break; case Vendor.AMD: switch (threads[0].Family) { case 0x0F: hardware.Add(new AMD0FCPU(index, coreThreads, settings)); break; case 0x10: case 0x11: case 0x12: case 0x14: case 0x15: case 0x16: hardware.Add(new AMD10CPU(index, coreThreads, settings)); break; case 0x17: hardware.Add(new AMD17CPU(index, coreThreads, settings)); break; default: hardware.Add(new GenericCPU(index, coreThreads, settings)); break; } break; default: hardware.Add(new GenericCPU(index, coreThreads, settings)); break; } index++; } } public IHardware[] Hardware { get { return hardware.ToArray(); } } private static void AppendCpuidData(StringBuilder r, uint[,] data, uint offset) { for (int i = 0; i < data.GetLength(0); i++) { r.Append(" "); r.Append((i + offset).ToString("X8", CultureInfo.InvariantCulture)); for (int j = 0; j < 4; j++) { r.Append(" "); r.Append(data[i, j].ToString("X8", CultureInfo.InvariantCulture)); } r.AppendLine(); } } public string GetReport() { if (threads == null) return null; StringBuilder r = new StringBuilder(); r.AppendLine("CPUID"); r.AppendLine(); for (int i = 0; i < threads.Length; i++) { r.AppendLine("Processor " + i); r.AppendLine(); r.AppendFormat("Processor Vendor: {0}{1}", threads[i][0][0].Vendor, Environment.NewLine); r.AppendFormat("Processor Brand: {0}{1}", threads[i][0][0].BrandString, Environment.NewLine); r.AppendFormat("Family: 0x{0}{1}", threads[i][0][0].Family.ToString("X", CultureInfo.InvariantCulture), Environment.NewLine); r.AppendFormat("Model: 0x{0}{1}", threads[i][0][0].Model.ToString("X", CultureInfo.InvariantCulture), Environment.NewLine); r.AppendFormat("Stepping: 0x{0}{1}", threads[i][0][0].Stepping.ToString("X", CultureInfo.InvariantCulture), Environment.NewLine); r.AppendLine(); r.AppendLine("CPUID Return Values"); r.AppendLine(); for (int j = 0; j < threads[i].Length; j++) for (int k = 0; k < threads[i][j].Length; k++) { r.AppendLine(" CPU Group: " + threads[i][j][k].Group); r.AppendLine(" CPU Thread: " + threads[i][j][k].Thread); r.AppendLine(" APIC ID: " + threads[i][j][k].ApicId); r.AppendLine(" Processor ID: " + threads[i][j][k].ProcessorId); r.AppendLine(" Core ID: " + threads[i][j][k].CoreId); r.AppendLine(" Thread ID: " + threads[i][j][k].ThreadId); r.AppendLine(); r.AppendLine(" Function EAX EBX ECX EDX"); AppendCpuidData(r, threads[i][j][k].Data, CPUID.CPUID_0); AppendCpuidData(r, threads[i][j][k].ExtData, CPUID.CPUID_EXT); r.AppendLine(); } } return r.ToString(); } public void Close() { foreach (GenericCPU cpu in hardware) { cpu.Close(); } } } }