Как определить правильное извлечение данных для графических процессоровC#

Место общения программистов C#
Ответить
Anonymous
 Как определить правильное извлечение данных для графических процессоров

Сообщение Anonymous »

Мне не очень понравилось название, но я действительно не мог придумать другого способа его выразить.
Хорошо, сначала я должен сказать, что это будет очень похоже на вопрос, который я уже задавал, но уверяю вас, что это совсем другой вопрос.
Предыдущий вопрос был о критериях, которые я должен использовать при выборе основного графического процессора для отображения. Речь идет о том, как я проверяю, что отправленные мной данные правильно декодированы и правильны.
Во-первых, контекст: я переделываю инструмент C#, который я написал недавно, который должен извлекать аппаратные данные из ПК, а затем отправлять их в API (только для ПК с Windows). Моя единственная настоящая головная боль — это непоследовательный способ чтения графических процессоров.
Я использую ManagementBaseObjects из пакета System.Management.
Если быть точным, я в основном получаю свои данные с помощью этого кода:
searcher = new ManagementObjectSearcher($"Select * From {area}");

ManagementObjectCollection results = searcher.Get();

Дело в следующем: объект/данные, которые мне возвращаются, имеют uint в качестве информации о размере оперативной памяти. Это делает его слишком маленьким, чтобы правильно предоставить мне V-RAM более 4 ГБ.
Теперь, судя по тому, что я смог определить, я могу использовать HKLMRegistry, чтобы немного помочь мне здесь.
До сих пор, когда «нормальное» поле memorzSize было слишком маленьким, в объекте HKLM было поле qwMemorySize. ДО СИХ ПОР. (Я добавляю соответствующий код в самый конец)
Дело в том, что в БОЛЬШИНСТВЕ, но не ВСЕХ случаях, когда ОЗУ не слишком большая/отсутствует поле qwMemory, другие поля HKLM, кроме PNP-ID, хранятся в формате base64.
Теперь, когда (я надеюсь) предоставлен достаточный контекст, я попытаюсь сформулировать свои вопросы:
  • Всегда ли так, что если VRAM превышает 4 ГБ, будет поле qwMemorySize?
  • Когда такое поле НЕ отображается, всегда ли строки будут иметь формат Base64?
  • Если нет, то какие еще крайние случаи существуют
  • Как можно Я допускаю такие «различные случаи хранения данных», исходя из предположения, что я не могу просто считывать закодированную строку через API, но должен иметь все декодированное и читаемое, когда я отправляю ее в API?
Теперь я дам вам некоторый код, чтобы вы могли воссоздать то, что я сделал. Замечу, что вы можете игнорировать интерфейсы при пересоздании моего кода. Это просто для того, чтобы упростить поток кода в более крупном проекте. Но я думаю, что я сделал это достаточно хорошо, чтобы вы могли просто скопировать + вставить.
А теперь еще несколько примеров скриншотов.
Изображение первое — это вывод консоли, показывающий графический процессор, который превышает лимит и имеет поле qw, и графический процессор, который этого не делает. На рисунках ниже показано, как это выглядит в HKLM, в том же порядке.
Изображение

Если вы хотите увидеть, что находится в вашем собственном HKLM, просто откройте редактор реестра приложения и перейдите по пути Computer\HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Class\{4d36e968-e325-11ce-bfc1-08002be10318}\0000
Если у вас несколько графических процессоров, вы можете просмотреть их, проверив \0001 или 0002 и т. д. и т. п.
Изображение

Изображение

using Microsoft.Win32;
using System.Management;
using System.Text.Json;

namespace StackGPUQuestion
{
internal class Program
{
static void Main(string[] args)
{
GPUsInfo information = InfoExtractor.SimplifiedCondensationOfCode();

JsonSerializerOptions options = new JsonSerializerOptions() { WriteIndented = true };
string gpuInfoString = JsonSerializer.Serialize(information, options);
Console.WriteLine(gpuInfoString);
}
}

//Extensions---------------------------------------------------------------

public static class Extensions
{
//...
public static T GetPropVal(this ManagementBaseObject obj, string name)
{
//todo improve
//this is still a bit in the works, but it will suffice for this
return (T)obj.GetPropertyValue(name);
}
//...
}

//Extensions---------------------------------------------------------------

//System Management---------------------------------------------------------------

public class WinVideoControllerInfo
{
#region Properties

public string Name { get; set; }
public uint AdapterRAM { get; set; }
public string AdapterDACType { get; set; }
public string VideoProcessor { get; set; }

public string PNPDeviceID { get; set; }

#endregion

public WinVideoControllerInfo()
{
//This is empty on purpose. For the function of generics
}

public WinVideoControllerInfo Construct(ManagementBaseObject obj)//This will seem weird, but it has its use
{
return new WinVideoControllerInfo(obj);
}

public WinVideoControllerInfo(ManagementBaseObject obj)
{
Name = obj.GetPropVal(nameof(Name));
AdapterRAM = obj.GetPropVal(nameof(AdapterRAM));
AdapterDACType = obj.GetPropVal(nameof(AdapterDACType));
VideoProcessor = obj.GetPropVal(nameof(VideoProcessor));

PNPDeviceID = obj.GetPropVal(nameof(PNPDeviceID));
}
}

//System Management---------------------------------------------------------------

//HKLM---------------------------------------------------------------

//HKLM Support---------------------------------------------------------------

public interface IRegistry
{
///
/// Retrieves the value associated with the specified name, in the specified registry key.
/// If the name is not found in the specified key, returns a default value that you provide, or null if the specified key does not exist.
///
/// The full registry path of the key, beginning with a valid registry root, such as "HKEY_CURRENT_USER".
/// The name of the name/value pair.
/// The value to return if valueName does not exist.
///
object? GetValue(string keyName, string valueName, object? defaultValue);
}

public class Registry : IRegistry
{
public static Registry RegistryDefault => new();

public object? GetValue(string keyName, string valueName, object? defaultValue)
{
return Microsoft.Win32.Registry.GetValue(keyName, valueName, defaultValue);
}
}

public readonly struct RegistryEntry
{
///
/// The full registry path of the key, beginning with a valid registry root, such as "HKEY_CURRENT_USER".
///
public string FullPathToKey { get; }

///
/// The name of the name/value pair.
///
public string ValueName { get; }

///
/// The value to return if ValueName does not exist.
///
public string? DefaultValueNotFound { get; }

public RegistryEntry(string fullPathToKey, string valueName, string? defaultValue)
{
FullPathToKey = fullPathToKey;
ValueName = valueName;
DefaultValueNotFound = defaultValue;
}
}

//HKLM Support---------------------------------------------------------------

public class HKLMVideoController
{
private const string HKLMRegistryPathBase = @"HKEY_LOCAL_MACHINE\SYSTEM\ControlSet001\Control\Class\{4d36e968-e325-11ce-bfc1-08002be10318}\";
private readonly RegistryEntry _adapterStringRegistry;
private readonly RegistryEntry _biosStringRegistry;
private readonly RegistryEntry _chipTypeRegistry;
private readonly RegistryEntry _dacTypeRegistry;
private readonly RegistryEntry _memorySizeRegistry;
private readonly RegistryEntry _qwMemorySizeRegistry;

private readonly RegistryEntry _matchingDeviceIdRegistry;

private IRegistry _registryProvider;

#region Properties

#region Backers

private object _adapterString;
private object _biosString;
private object _chipType;
private object _dacType;
private object _memorySize;
private object _qwMemorySize;

private object _matchingDeviceId;

#endregion

public object AdapterString => _adapterString;
public object BiosString => _biosString;
public object ChipType => _chipType;
public object DacType => _dacType;
public object MemorySize => _memorySize;
public object QwMemorySize => _qwMemorySize;

public object MatchingDeviceId => _matchingDeviceId;

#endregion

private string HKLMRegistryPath;

public HKLMVideoController(string id = "0000")
{
_registryProvider = Registry.RegistryDefault;

HKLMRegistryPath = HKLMRegistryPathBase + id;

_adapterStringRegistry = new(HKLMRegistryPath, "HardwareInformation.AdapterString", null);
_biosStringRegistry = new(HKLMRegistryPath, "HardwareInformation.BiosString", null);
_chipTypeRegistry = new(HKLMRegistryPath, "HardwareInformation.ChipType", null);
_dacTypeRegistry = new(HKLMRegistryPath, "HardwareInformation.DacType", null);
_memorySizeRegistry = new(HKLMRegistryPath, "HardwareInformation.MemorySize", null);
_qwMemorySizeRegistry = new(HKLMRegistryPath, "HardwareInformation.qwMemorySize", null);

_matchingDeviceIdRegistry = new(HKLMRegistryPath, "MatchingDeviceId", null);

SetAllProperties();
}

private void SetAllProperties()
{
_adapterString = GetProperty(_adapterStringRegistry);
_biosString = GetProperty(_biosStringRegistry);
_chipType = GetProperty(_chipTypeRegistry);
_dacType = GetProperty(_dacTypeRegistry);
_memorySize = GetProperty(_memorySizeRegistry);
_qwMemorySize = GetProperty(_qwMemorySizeRegistry);

_matchingDeviceId = GetProperty(_matchingDeviceIdRegistry);
}

private object GetProperty(RegistryEntry propertyEntry)
{
object? propertyValue = _registryProvider.GetValue(propertyEntry.FullPathToKey, propertyEntry.ValueName, propertyEntry.DefaultValueNotFound);
propertyValue ??= Def(propertyEntry.ValueName);
return propertyValue;
}

private object Def(string valueName)
{
String str = $"Could not determine {valueName}";
object ing = str;
return ing;
}
}

//HKLM---------------------------------------------------------------

//Pairing---------------------------------------------------------------

public class VideoControllerPair
{
public WinVideoControllerInfo WinInfo { get; set; }
public HKLMVideoController HKLMInfo { get; set; }

public VideoControllerPair(WinVideoControllerInfo winInfo)
{
string driverPathId = SystemInformationRetriever.PNPToPathId(winInfo.PNPDeviceID);
HKLMVideoController hklmInfo = new(driverPathId);

WinInfo = winInfo;
HKLMInfo = hklmInfo;
}
}

//Pairing---------------------------------------------------------------

public static class SystemInformationRetriever
{
public static string PNPToPathId(string pnpId)
{
RegistryKey pnpRegistryEntry =
Microsoft.Win32.Registry.LocalMachine.OpenSubKey($@"SYSTEM\CurrentControlSet\Enum\{pnpId}");

object? driverValue = pnpRegistryEntry.GetValue("Driver");
string driverPath = driverValue.ToString();
string driverPathId = new(driverPath.TakeLast(4).ToArray());

return driverPathId;
}
}

//Very simplified version
public class GPUsInfo
{
/*
//actual properties
public int GPUCards => GPUUnits.Count;
public List GPUUnits { get; set; }
*/

//Simplified Property
public List Pairs { get; set; }

public GPUsInfo() { }

public GPUsInfo Construct(List winInfos)
{
return new GPUsInfo(winInfos);
}

public GPUsInfo(List winInfos)
{
if (!winInfos.Any())
{
throw new Exception();
}

List pairedInfos = new();

foreach (WinVideoControllerInfo winInfo in winInfos)
{
VideoControllerPair pairedInfo = new VideoControllerPair(winInfo);
pairedInfos.Add(pairedInfo);
}

Pairs = pairedInfos;

/*
// This would be the actual code
List infos = new();
foreach (VideoControllerPair pairedInfo in pairedInfos)
{
GPUInfo info = new GPUInfo(pairedInfo);
infos.Add(info);
}

GPUUnits = infos;
*/
}
}

//The following extract has been a bit modified from the way it persists in the project, so you guys can actually work with it

public static class InfoExtractor
{
public static GPUsInfo SimplifiedCondensationOfCode()
{
//simplified exert of Searcher Getter (GetSearcherResults(area))
string area = "Win32_VideoController";
ManagementObjectSearcher searcher = new ManagementObjectSearcher($"Select * From {area}");
ManagementObjectCollection results = searcher.Get();

//simplified exert of Extracting Information (RetrieveGenericInformation(area))
//ManagementObjectCollection rawInformation = GetSearcherResults(area);
ManagementObjectCollection rawInformation = results;

List winInfos = new List();

foreach (ManagementBaseObject information in rawInformation)
{
WinVideoControllerInfo winInfo = new WinVideoControllerInfo().Construct(information);
winInfos.Add(winInfo);
}

GPUsInfo info = new GPUsInfo().Construct(winInfos);
return info;
}
}
}

Дополнительно
Теперь конечной целью является как можно лучше реализовать класс GPUInfo (не GPUsInfo, а GPUInfo), который будет иметь следующие свойства
public string AdapterName { get; set; }

public string Processor { get; set; }

public string AdapterDac { get; set; }

public string BIOSString { get; set; }

public object RamSize { get; set; }

Каким образом лучше всего определить реализацию конструктора. Я знаю, что это кажется широким, поэтому это дополнение. По сути, речь идет о том, чтобы система знала, когда следует полагаться на Win, а когда на данные HKLM, а также знала, когда и не нужно декодировать и как.
Вот грубый старт для игры (не фактическая работающая версия, но, на мой взгляд, хорошая основа)
public GPUInfo(VideoControllerPair winInfo)
{
WinVideoControllerInfo a = winInfo.WinInfo;
HKLMVideoController b = winInfo.HKLMInfo;

var winName = a.Name;
var hklName = b.AdapterString;

var winVP = a.VideoProcessor;
var hklVP = b.ChipType;

var winDAC = a.AdapterDACType;
var hklDAC = b.DacType;

var winRam = a.AdapterRAM;
var hklRamOne = b.MemorySize;
var hklRamTwo = b.QwMemorySize;

//Preliminary

AdapterName = winName;
Processor = winVP;
AdapterDac = winDAC;

//todo

}


Подробнее здесь: https://stackoverflow.com/questions/798 ... n-for-gpus
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»