NVAPIって知っていますか?
NVAPIとはNVIDIA社が提供しているAPIです。
NVIDIA社が提供している有名なAPIとしてはCUDAが存在しますが、CUDAとは違いNVAPIは搭載されているハードウェアの情報を取得することが主な使用用途だと思われます。
さて、私はGPUを酷使する機会が多少ながらもあり、その時にVRAMがどの程度使用されているかどうかを取得するためのNVAPIのコードを紹介します。
NVAPIをダウンロード#
まずは、NVAPIを以下のリンクからダウンロードしてきます。
今回この記事で利用しているNVAPIのバージョンは「R450」です。
ダウンロードが終えたファイルの中には nvapi.h
などのヘッタファイルがあり、ライブラリが入っているファイルが確認できます。
NVAPIファイルを、プログラムを作成する作業フォルダー内に配置してください。
VRAMの取得を行うコード#
C言語
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
#include <stdio.h>
#include "NVAPI/nvapi.h"
#if _M_AMD64
#pragma comment(lib, "NVAPI/amd64/nvapi64.lib")
#else
#pragma comment(lib, "NVAPI/x86/nvapi.lib")
#endif
int main() {
NvAPI_Status nStatus = NvAPI_Initialize();
if (nStatus == NVAPI_OK) {
NvPhysicalGpuHandle hGPUHandles[NVAPI_MAX_PHYSICAL_GPUS] = {0};
NvU32 count = 0;
nStatus = NvAPI_EnumPhysicalGPUs(hGPUHandles, &count);
if (nStatus == NVAPI_OK) {
printf("GPUS:%d\n", count);
} else {
printf("ErrorCode:%d\n", nStatus);
}
NvPhysicalGpuHandle hGPUHandle = hGPUHandles[0];
NV_DISPLAY_DRIVER_MEMORY_INFO_V1 MemoryInfo;
MemoryInfo.version = NV_DISPLAY_DRIVER_MEMORY_INFO_VER_1;
nStatus = NvAPI_GPU_GetMemoryInfo(hGPUHandle, &MemoryInfo);
if (nStatus == NVAPI_OK) {
printf("VRAM Total:%.5lf[GB]\n",
(double)MemoryInfo.dedicatedVideoMemory / 1048576);
printf("VRAM Can Use:%.5lf[GB]\n",
(double)MemoryInfo.availableDedicatedVideoMemory / 1048576);
} else {
printf("ErrorCode:%d\n", nStatus);
}
}
return 0;
}
|
今回使用するコンパイラはMSVC(cl.exe)を使用します。clangコンパイラでもコンパイル可能です。
gccコンパイラだとエラーが出て通りません。
コードの説明#
C言語
1
2
3
4
5
6
7
|
#include <stdio.h>
#include "NVAPI/nvapi.h"
#if _M_AMD64
#pragma comment(lib, "NVAPI/amd64/nvapi64.lib")
#else
#pragma comment(lib, "NVAPI/x86/nvapi.lib")
#endif
|
まず、標準出力のための stdio.h
VRAMを取得するための nvapi.h
を追加します。
nvapi.h
の下がわけわからんコードになっていますが、これはおまじないだと思ってコピーしてください。
この部分ではコンパイラが32ビット版を使用してコンパイルを行うか64ビット版のコンパイラを使用してコンパイルを行うかの違いです。深く考えない方が良いでしょう()
C言語
1
2
3
4
5
6
7
8
9
10
11
12
|
NvAPI_Status nStatus = NvAPI_Initialize();
if (nRet == NVAPI_OK) {
NvPhysicalGpuHandle hGPUHandles[NVAPI_MAX_PHYSICAL_GPUS] = {0};
NvU32 count = 0;
nStatus = NvAPI_EnumPhysicalGPUs(hGPUHandles, &count);
}
if (nStatus == NVAPI_OK) {
printf("GPUS:%d\n", count);
} else {
printf("ErrorCode:%d\n", nStatus);
}
NvPhysicalGpuHandle hGPUHandle = hGPUHandles[0];//下に続く
|
ここから本題です。
まず、 NvAPI_Initialize
関数を呼び出して初期化を行います。
この際、 NvAPI_Initialize
関数が NvAPI_Status
であるためステータスコードを取得しておくと後からエラーが出た時に対処がしやすいです。
無事に初期化が行われれば、 NVAPI_OK
ステータスが戻ってくるので、if文で判別してエラーがないことを確認できます。
つぎにGPU自体がコンピューターに何台搭載されていて、どのGPUのVRAMを取得したのかを選択します。
そして、 NvPhysicalGpuHandle hGPUHandles[NVAPI_MAX_PHYSICAL_GPUS] = {0};
で複数のGPUハンドルが格納するための変数を作ります。
NvAPI_EnumPhysicalGPUs
関数を使用してGPUハンドルを取得します。
後に、 NvPhysicalGpuHandle hGPUHandle = hGPUHandles[0];
を行うことにより、GPU0のハンドルが変数に格納されて、ようやくVRAMを取得できるような形となります。
C言語
1
2
3
4
5
6
7
8
9
10
11
|
NV_DISPLAY_DRIVER_MEMORY_INFO_V1 MemoryInfo;
MemoryInfo.version = NV_DISPLAY_DRIVER_MEMORY_INFO_VER_1;
nStatus = NvAPI_GPU_GetMemoryInfo(hGPUHandle, &MemoryInfo);
if (nStatus == NVAPI_OK) {
printf("VRAM Total:%.5lf[GB]\n",
(double)MemoryInfo.dedicatedVideoMemory / 1048576);
printf("VRAM Can Use:%.5lf[GB]\n",
(double)MemoryInfo.availableDedicatedVideoMemory / 1048576);
} else {
printf("ErrorCode:%d\n", nStatus);
}
|
まず、使用する構造体を変数宣言(MemoryInfoのこと)を行い、 MemoryInfo.version = NV_DISPLAY_DRIVER_MEMORY_INFO_VER_1;
で使用する構造体のドライバーを当てます。
そして、やっとのことでVRAMを取得するための関数が呼び出されます。
NvAPI_GPU_GetMemoryInfo(hGPUHandle, &MemoryInfo);
この関数ではGPUのハンドルと変数を引数として渡します。最後にこの構造体の値はすべてKBで取得されるためGBに変換して出力しています。
出力結果#
output
1
2
3
|
GPUS:1
VRAM Total:8.00000[GB]
VRAM Can Use:7.89844[GB]
|
私のパソコンに搭載しているグラフィックボードは、ASUS製の「GTX1070-8G」1機だけなのGPUSは1と表示され、Totalの所が8GBとなり、Can Useの所は使用可能量となっているので出力結果はリソースの使用状況によって変わります。
参考URL#