212 lines
7.0 KiB
C#
212 lines
7.0 KiB
C#
// 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) LibreHardwareMonitor and Contributors.
|
|
// Partial Copyright (C) Michael Möller <mmoeller@openhardwaremonitor.org> and Contributors.
|
|
// All Rights Reserved.
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.Text;
|
|
|
|
namespace LibreHardwareMonitor.Hardware.Cpu;
|
|
|
|
internal class CpuGroup : IGroup
|
|
{
|
|
private readonly List<GenericCpu> _hardware = new();
|
|
private readonly CpuId[][][] _threads;
|
|
|
|
public CpuGroup(ISettings settings)
|
|
{
|
|
CpuId[][] processorThreads = GetProcessorThreads();
|
|
_threads = new CpuId[processorThreads.Length][][];
|
|
|
|
int index = 0;
|
|
foreach (CpuId[] threads in processorThreads)
|
|
{
|
|
if (threads.Length == 0)
|
|
continue;
|
|
|
|
CpuId[][] coreThreads = GroupThreadsByCore(threads);
|
|
_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:
|
|
case 0x19:
|
|
case 0x1A:
|
|
_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 IReadOnlyList<IHardware> Hardware => _hardware;
|
|
|
|
public string GetReport()
|
|
{
|
|
if (_threads == null)
|
|
return null;
|
|
|
|
StringBuilder r = new();
|
|
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();
|
|
}
|
|
}
|
|
|
|
private static CpuId[][] GetProcessorThreads()
|
|
{
|
|
List<CpuId> threads = new();
|
|
|
|
for (int i = 0; i < ThreadAffinity.ProcessorGroupCount; i++)
|
|
{
|
|
for (int j = 0; j < 192; j++)
|
|
{
|
|
try
|
|
{
|
|
var cpuid = CpuId.Get(i, j);
|
|
if (cpuid != null)
|
|
threads.Add(cpuid);
|
|
}
|
|
catch (ArgumentOutOfRangeException)
|
|
{
|
|
// Continue...
|
|
}
|
|
}
|
|
}
|
|
|
|
SortedDictionary<uint, List<CpuId>> processors = new();
|
|
foreach (CpuId thread in threads)
|
|
{
|
|
processors.TryGetValue(thread.ProcessorId, out List<CpuId> list);
|
|
if (list == null)
|
|
{
|
|
list = new List<CpuId>();
|
|
processors.Add(thread.ProcessorId, list);
|
|
}
|
|
|
|
list.Add(thread);
|
|
}
|
|
|
|
CpuId[][] processorThreads = new CpuId[processors.Count][];
|
|
int index = 0;
|
|
foreach (List<CpuId> list in processors.Values)
|
|
{
|
|
processorThreads[index] = list.ToArray();
|
|
index++;
|
|
}
|
|
|
|
return processorThreads;
|
|
}
|
|
|
|
private static CpuId[][] GroupThreadsByCore(IEnumerable<CpuId> threads)
|
|
{
|
|
SortedDictionary<uint, List<CpuId>> cores = new();
|
|
foreach (CpuId thread in threads)
|
|
{
|
|
cores.TryGetValue(thread.CoreId, out List<CpuId> coreList);
|
|
if (coreList == null)
|
|
{
|
|
coreList = new List<CpuId>();
|
|
cores.Add(thread.CoreId, coreList);
|
|
}
|
|
|
|
coreList.Add(thread);
|
|
}
|
|
|
|
CpuId[][] coreThreads = new CpuId[cores.Count][];
|
|
int index = 0;
|
|
foreach (List<CpuId> list in cores.Values)
|
|
{
|
|
coreThreads[index] = list.ToArray();
|
|
index++;
|
|
}
|
|
|
|
return coreThreads;
|
|
}
|
|
|
|
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();
|
|
}
|
|
}
|
|
}
|