0

Get NVIDIA driver version from NVML on 64-bit Windows

NVML provides a more reliable way to query for the NVIDIA driver
version. It also provides a query for NVIDIA CUDA compute capability
which corresponds to the GPU generation. This is a good value to use
for filtering GPUs based on hardware properties.

We now query NVML for driver version and CUDA compute capability in
case an NVIDIA GPU is encountered on Windows. NVML is loaded
dynamically from %ProgramW6432%/NVIDIA Corporation/NVSMI/nvml.dll.
In recent drivers the library is only shipped as a 64-bit binary, so
it won't load in case the 32-bit build of Chromium is used.

As a fallback, the actual NVIDIA driver version is parsed from the
driver version in the Windows registry. This best-effort parsing
should work for most versions, though every single version may not
conform to the expected format.

NVML has been present in NVIDIA drivers since version 270 published in
2011. Some functionality in NVML is exclusive to professional Quadro
or Tesla GPUs, but basic functionality like the queries used here are
available across NVIDIA GPU brands.

BUG=693090

Cq-Include-Trybots: luci.chromium.try:android_optional_gpu_tests_rel;luci.chromium.try:linux_optional_gpu_tests_rel;luci.chromium.try:mac_optional_gpu_tests_rel;luci.chromium.try:win_optional_gpu_tests_rel
Change-Id: I31b44021e00426fcfb2b850fea5d63c114c4569c
Reviewed-on: https://chromium-review.googlesource.com/1108199
Reviewed-by: Will Harris <wfh@chromium.org>
Reviewed-by: Nico Weber <thakis@chromium.org>
Reviewed-by: Scott Violet <sky@chromium.org>
Reviewed-by: Kenneth Russell <kbr@chromium.org>
Reviewed-by: Dominick Ng <dominickn@chromium.org>
Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>
Cr-Commit-Position: refs/heads/master@{#581820}
This commit is contained in:
Olli Etuaho
2018-08-09 07:49:15 +00:00
committed by Commit Bot
parent b4ce470bef
commit 1241aea53e
18 changed files with 5973 additions and 15 deletions

@ -226,6 +226,9 @@ std::unique_ptr<base::ListValue> BasicGpuInfoAsListValue(
NewDescriptionValuePair("Driver version", active_gpu.driver_version));
basic_info->Append(
NewDescriptionValuePair("Driver date", active_gpu.driver_date));
basic_info->Append(NewDescriptionValuePair(
"GPU CUDA compute capability major version",
std::make_unique<base::Value>(active_gpu.cuda_compute_capability_major)));
basic_info->Append(NewDescriptionValuePair("Pixel shader version",
gpu_info.pixel_shader_version));
basic_info->Append(NewDescriptionValuePair("Vertex shader version",

@ -1,6 +1,7 @@
include_rules = [
"+third_party/angle",
"+third_party/amd",
"+third_party/nvml",
"+third_party/re2",
"+third_party/smhasher",
"+third_party/swiftshader",

@ -168,6 +168,12 @@ source_set("config_sources") {
"setupapi.lib",
]
sources += [
"//third_party/nvml/nvml.h",
"nvml_info.cc",
"nvml_info.h",
]
if (is_chrome_branded && is_official_build) {
sources += [
"//third_party/amd/AmdCfxPxExt.h",

@ -489,7 +489,7 @@
"vendor_id": "0x10de",
"driver_version": {
"op": "<=",
"value": "8.17.12.6973"
"value": "269.73"
},
"features": [
"disable_d3d11"
@ -1850,7 +1850,7 @@
},
"driver_version": {
"op": "<",
"value": "21.21.13.7576"
"value": "375.76"
},
"vendor_id": "0x10de",
"features": [

@ -19,6 +19,8 @@ void EnumerateGPUDevice(const gpu::GPUInfo::GPUDevice& device,
enumerator->AddString("driverVendor", device.driver_vendor);
enumerator->AddString("driverVersion", device.driver_version);
enumerator->AddString("driverDate", device.driver_date);
enumerator->AddInt("cudaComputeCapabilityMajor",
device.cuda_compute_capability_major);
enumerator->EndGPUDevice();
}
@ -94,8 +96,8 @@ VideoDecodeAcceleratorCapabilities::~VideoDecodeAcceleratorCapabilities() =
GPUInfo::GPUDevice::GPUDevice()
: vendor_id(0),
device_id(0),
active(false) {
}
active(false),
cuda_compute_capability_major(0) {}
GPUInfo::GPUDevice::GPUDevice(const GPUInfo::GPUDevice& other) = default;

@ -137,6 +137,10 @@ struct GPU_EXPORT GPUInfo {
std::string driver_vendor;
std::string driver_version;
std::string driver_date;
// NVIDIA CUDA compute capability, major version. 0 if undetermined. Can be
// used to determine the hardware generation that the GPU belongs to.
int cuda_compute_capability_major;
};
GPUInfo();

@ -36,6 +36,7 @@
#include "base/threading/thread.h"
#include "base/trace_event/trace_event.h"
#include "base/win/scoped_com_initializer.h"
#include "gpu/config/nvml_info.h"
#include "third_party/vulkan/include/vulkan/vulkan.h"
namespace gpu {
@ -124,6 +125,28 @@ bool GetAMDSwitchableInfo(bool* is_switchable,
}
#endif
std::string ParseNVIDIARegistryDriverVersion(std::string registry_version) {
// The NVIDIA driver version in the registry is most commonly in the format:
// XX.XX.XD.DDDD
// Where "X" corresponds to an OS-specific digit and "D" corresponds to a
// digit of the actual driver version. We convert it to the following format:
// DDD.DD
// This matches with the actual driver version that NVML also returns.
std::string second_to_last_digits;
std::string last_digits;
if (!RE2::FullMatch(registry_version, "\\d+\\.\\d+\\.(\\d+)\\.(\\d+)",
&second_to_last_digits, &last_digits)) {
return registry_version;
}
std::string digits = second_to_last_digits + last_digits;
if (digits.length() < 5u) {
return registry_version;
}
digits.erase(0, digits.length() - 5u);
DCHECK(digits.length() == 5u);
return digits.substr(0u, 3u) + "." + digits.substr(3u);
}
bool CollectDriverInfoD3D(const std::wstring& device_id, GPUInfo* gpu_info) {
TRACE_EVENT0("gpu", "CollectDriverInfoD3D");
@ -199,6 +222,28 @@ bool CollectDriverInfoD3D(const std::wstring& device_id, GPUInfo* gpu_info) {
found_intel = true;
if (device.vendor_id == 0x1002)
found_amd = true;
if (device.vendor_id == 0x10de) {
std::string nvml_driver_version;
int major_cuda_compute_capability = 0;
int minor_cuda_compute_capability = 0;
bool nvml_success = GetNvmlDeviceInfo(
device.device_id, &nvml_driver_version,
&major_cuda_compute_capability, &minor_cuda_compute_capability);
if (nvml_success) {
// We use the NVML driver version instead of the registry version,
// since the registry version includes OS-specific digits that are
// not part of the actual driver version.
device.driver_version = nvml_driver_version;
device.cuda_compute_capability_major =
major_cuda_compute_capability;
} else {
// If we can't get the actual driver version from NVML, do
// best-effort parsing of the actual driver version from the
// registry driver version.
device.driver_version =
ParseNVIDIARegistryDriverVersion(device.driver_version);
}
}
devices.push_back(device);
}

126
gpu/config/nvml_info.cc Normal file

@ -0,0 +1,126 @@
// Copyright (c) 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "gpu/config/nvml_info.h"
#include <windows.h>
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/path_service.h"
#include "third_party/nvml/nvml.h"
namespace {
const unsigned int kDriverVersionCapacity = 80u;
} // anonymous namespace
typedef decltype(&nvmlInit) INITPROC;
typedef decltype(&nvmlShutdown) SHUTDOWNPROC;
typedef decltype(&nvmlSystemGetDriverVersion) GETDRIVERVERSIONPROC;
typedef decltype(&nvmlDeviceGetCount) DEVICEGETCOUNTPROC;
typedef decltype(&nvmlDeviceGetHandleByIndex) DEVICEGETHANDLEBYINDEXPROC;
typedef decltype(&nvmlDeviceGetPciInfo) DEVICEGETPCIINFOPROC;
typedef decltype(
&nvmlDeviceGetCudaComputeCapability) DEVICEGETCUDACOMPUTECAPABILITYPROC;
bool GetNvmlDeviceInfo(uint32_t pci_device_id,
std::string* driver_version,
int* major_cuda_compute_capability,
int* minor_cuda_compute_capability) {
DCHECK(major_cuda_compute_capability);
DCHECK(minor_cuda_compute_capability);
*major_cuda_compute_capability = 0;
*minor_cuda_compute_capability = 0;
base::FilePath dll_path;
if (!base::PathService::Get(base::DIR_PROGRAM_FILES6432, &dll_path)) {
return false;
}
dll_path = dll_path.Append(L"NVIDIA Corporation\\NVSMI\\nvml.dll");
HINSTANCE hinstNVML = LoadLibrary(dll_path.value().data());
if (!hinstNVML) {
return false;
}
INITPROC fnNvmlInit = (INITPROC)GetProcAddress(hinstNVML, "nvmlInit");
SHUTDOWNPROC fnNvmlShutdown =
(SHUTDOWNPROC)GetProcAddress(hinstNVML, "nvmlShutdown");
GETDRIVERVERSIONPROC fnNvmlSystemGetDriverVersion =
(GETDRIVERVERSIONPROC)GetProcAddress(hinstNVML,
"nvmlSystemGetDriverVersion");
DEVICEGETCOUNTPROC fnNvmlDeviceGetCount =
(DEVICEGETCOUNTPROC)GetProcAddress(hinstNVML, "nvmlDeviceGetCount");
DEVICEGETHANDLEBYINDEXPROC fnNvmlDeviceGetHandleByIndex =
(DEVICEGETHANDLEBYINDEXPROC)GetProcAddress(hinstNVML,
"nvmlDeviceGetHandleByIndex");
DEVICEGETPCIINFOPROC fnNvmlDeviceGetPciInfo =
(DEVICEGETPCIINFOPROC)GetProcAddress(hinstNVML, "nvmlDeviceGetPciInfo");
DEVICEGETCUDACOMPUTECAPABILITYPROC fnNvmlDeviceGetCudaComputeCapability =
(DEVICEGETCUDACOMPUTECAPABILITYPROC)GetProcAddress(
hinstNVML, "nvmlDeviceGetCudaComputeCapability");
if (!fnNvmlInit || !fnNvmlShutdown || !fnNvmlSystemGetDriverVersion) {
return false;
}
nvmlReturn_t result = fnNvmlInit();
if (NVML_SUCCESS != result) {
return false;
}
char driver_version_temp[kDriverVersionCapacity];
result =
fnNvmlSystemGetDriverVersion(driver_version_temp, kDriverVersionCapacity);
if (NVML_SUCCESS != result) {
fnNvmlShutdown();
return false;
}
*driver_version = driver_version_temp;
if (fnNvmlDeviceGetCount && fnNvmlDeviceGetHandleByIndex &&
fnNvmlDeviceGetPciInfo && fnNvmlDeviceGetCudaComputeCapability) {
unsigned int device_count;
result = fnNvmlDeviceGetCount(&device_count);
if (NVML_SUCCESS == result) {
for (unsigned int i = 0; i < device_count; i++) {
nvmlDevice_t device;
nvmlPciInfo_t pci;
result = fnNvmlDeviceGetHandleByIndex(i, &device);
if (NVML_SUCCESS != result) {
continue;
}
result = fnNvmlDeviceGetPciInfo(device, &pci);
if (NVML_SUCCESS != result) {
continue;
}
// We're looking for a particular PCI device.
if (pci.pciDeviceId != ((pci_device_id << 16) | 0x10deu)) {
continue;
}
result = fnNvmlDeviceGetCudaComputeCapability(
device, major_cuda_compute_capability,
minor_cuda_compute_capability);
if (NVML_SUCCESS != result) {
*major_cuda_compute_capability = 0;
*minor_cuda_compute_capability = 0;
}
}
}
}
result = fnNvmlShutdown();
if (NVML_SUCCESS != result) {
return false;
}
return true;
}

22
gpu/config/nvml_info.h Normal file

@ -0,0 +1,22 @@
// Copyright (c) 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef GPU_CONFIG_NVML_INFO_H_
#define GPU_CONFIG_NVML_INFO_H_
#include "build/build_config.h"
#include <stdint.h>
#include <string>
// Queries driver version and places it into driver_version. Writes
// major_cuda_compute_capability and minor_cuda_compute_capability of the GPU
// matching pci_device_id if one is found, or writes 0 into these outputs
// otherwise. Returns true on success.
bool GetNvmlDeviceInfo(uint32_t pci_device_id,
std::string* driver_version,
int* major_cuda_compute_capability,
int* minor_cuda_compute_capability);
#endif // GPU_CONFIG_NVML_INFO_H_

@ -448,7 +448,7 @@
},
{
"id": 59,
"description": "NVidia driver 8.15.11.8593 is crashy on Windows",
"description": "NVidia driver 185.93 is crashy on Windows",
"cr_bugs": [155749],
"os": {
"type": "win"
@ -456,7 +456,7 @@
"vendor_id": "0x10de",
"driver_version": {
"op": "=",
"value": "8.15.11.8593"
"value": "185.93"
},
"features": [
"accelerated_video_decode"
@ -499,7 +499,7 @@
},
{
"id": 69,
"description": "NVIDIA driver 8.17.11.9621 is buggy with Stage3D baseline mode",
"description": "NVIDIA driver 196.21 is buggy with Stage3D baseline mode",
"cr_bugs": [172771],
"os": {
"type": "win"
@ -507,7 +507,7 @@
"vendor_id": "0x10de",
"driver_version": {
"op": "=",
"value": "8.17.11.9621"
"value": "196.21"
},
"features": [
"flash_stage3d_baseline"
@ -515,7 +515,7 @@
},
{
"id": 70,
"description": "NVIDIA driver 8.17.11.8267 is buggy with Stage3D baseline mode",
"description": "NVIDIA driver 182.67 is buggy with Stage3D baseline mode",
"cr_bugs": [172771],
"os": {
"type": "win"
@ -523,7 +523,7 @@
"vendor_id": "0x10de",
"driver_version": {
"op": "=",
"value": "8.17.11.8267"
"value": "182.67"
},
"features": [
"flash_stage3d_baseline"
@ -699,8 +699,8 @@
"vendor_id": "0x10de",
"driver_version": {
"op": "between",
"value": "8.17.12.5729",
"value2": "8.17.12.8026"
"value": "257.29",
"value2": "280.26"
},
"features": [
"accelerated_video_decode"
@ -716,8 +716,8 @@
"vendor_id": "0x10de",
"driver_version": {
"op": "between",
"value": "9.18.13.783",
"value2": "9.18.13.1090"
"value": "307.83",
"value2": "310.90"
},
"features": [
"accelerated_video_decode"
@ -1429,7 +1429,7 @@
"vendor_id": "0x10de",
"driver_version": {
"op": "<=",
"value": "8.17.12.6973"
"value": "269.73"
},
"features": [
"accelerated_webgl2"

@ -19,6 +19,7 @@ struct GpuDevice {
string driver_vendor;
string driver_version;
string driver_date;
int32 cuda_compute_capability_major;
};
// gpu::VideoCodecProfile

@ -16,6 +16,7 @@ bool StructTraits<gpu::mojom::GpuDeviceDataView, gpu::GPUInfo::GPUDevice>::Read(
out->vendor_id = data.vendor_id();
out->device_id = data.device_id();
out->active = data.active();
out->cuda_compute_capability_major = data.cuda_compute_capability_major();
return data.ReadVendorString(&out->vendor_string) &&
data.ReadDeviceString(&out->device_string) &&
data.ReadDriverVendor(&out->driver_vendor) &&

@ -54,6 +54,11 @@ struct StructTraits<gpu::mojom::GpuDeviceDataView, gpu::GPUInfo::GPUDevice> {
static const std::string& driver_date(const gpu::GPUInfo::GPUDevice& input) {
return input.driver_date;
}
static int cuda_compute_capability_major(
const gpu::GPUInfo::GPUDevice& input) {
return input.cuda_compute_capability_major;
}
};
template <>

33
third_party/nvml/LICENSE vendored Normal file

@ -0,0 +1,33 @@
Copyright 1993-2017 NVIDIA Corporation. All rights reserved.
NOTICE TO USER:
This source code is subject to NVIDIA ownership rights under U.S. and
international Copyright laws. Users and possessors of this source code
are hereby granted a nonexclusive, royalty-free license to use this code
in individual and commercial software.
NVIDIA MAKES NO REPRESENTATION ABOUT THE SUITABILITY OF THIS SOURCE
CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR
IMPLIED WARRANTY OF ANY KIND. NVIDIA DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOURCE CODE, INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE.
IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL,
OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
OR PERFORMANCE OF THIS SOURCE CODE.
U.S. Government End Users. This source code is a "commercial item" as
that term is defined at 48 C.F.R. 2.101 (OCT 1995), consisting of
"commercial computer software" and "commercial computer software
documentation" as such terms are used in 48 C.F.R. 12.212 (SEPT 1995)
and is provided to the U.S. Government only as a commercial end item.
Consistent with 48 C.F.R.12.212 and 48 C.F.R. 227.7202-1 through
227.7202-4 (JUNE 1995), all U.S. Government End Users acquire the
source code with only those rights set forth herein.
Any use of this source code in individual and commercial software must
include, in the user documentation and internal comments to the code,
the above Disclaimer and U.S. Government End Users Notice.

2
third_party/nvml/OWNERS vendored Normal file

@ -0,0 +1,2 @@
kbr@chromium.org
zmo@chromium.org

20
third_party/nvml/README.chromium vendored Normal file

@ -0,0 +1,20 @@
Name: NVIDIA Management Library
Short Name: nvml
URL: https://developer.nvidia.com/nvidia-management-library-nvml
Version: 9.1.85
License: NVML license
License File: LICENSE
Security Critical: yes
Description:
This is a header file for interfacing with the NVML library that ships as a part
of NVIDIA proprietary drivers on Windows. The library can be used to query GPU
hardware and GPU driver information. Chromium loads the NVML library dynamically
and uses it for whitelisting and blacklisting purposes on Windows.
Points of contact at NVIDIA:
oetuaho@nvidia.com
amalp@nvidia.com
Local Modifications:
Trailing whitespace has been trimmed from the header file.

5684
third_party/nvml/nvml.h vendored Normal file

File diff suppressed because it is too large Load Diff

@ -461,6 +461,9 @@ PATH_SPECIFIC_WHITELISTED_LICENSES = {
'third_party/modp_b64': [
'UNKNOWN',
],
'third_party/nvml': [
'UNKNOWN',
],
# Missing license headers in openh264 sources: https://github.com/cisco/openh264/issues/2233
'third_party/openh264/src': [
'UNKNOWN',