NVAPIを使ったVRAMの取得

C言語
この記事は約7分で読めます。

NVAPIって知っていますか?NVAPIとはNVIDIA社が提供しているAPIです。NVIDIA社が提供している有名なAPIとしてはCUDAが存在しますが、CUDAとは違いNVAPIは搭載されているハードウェアの情報を取得することが主な使用用途だと思われます。

さて、私はGPUを酷使する機会が多少ながらもあり、その時にVRAMがどの程度使用されているかどうかを取得するためのNVAPIのコードを紹介します。

NVAPIをダウンロード

まずは、NVAPIを以下のリンクからダウンロードしてきます。今回この記事で利用しているNVAPIのバージョンは「R450」です。

ダウンロードが終えたファイルの中には「nvapi.h」などのヘッタファイルがあり、ライブラリが入っているファイルがあることが分かります。NVAPIファイルを、プログラムを作成する作業フォルダ内に配置してください。

VRAMの取得を行うコード

#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コンパイラだとエラーが出て通りません。

コードの説明

#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ビット版のコンパイラを使用してコンパイルを行うかの違いです。深く考えない方が良いでしょう()

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を取得できるような形となります。

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に変換して出力しています。

出力結果

GPUS:1
VRAM Total:8.00000[GB]
VRAM Can Use:7.89844[GB]

私のパソコンに搭載しているグラフィックボードはASUS製のGTX1070-8G 1機だけなのGPUSは1と表示され、Totalの所が8GBとなり、Can Useの所は使用可能量となっているので出力結果はリソースの使用状況によって変わります。

参考URL

購読する
Notify of
guest
0 コメント
Inline Feedbacks
すべてのコメントを読む
タイトルとURLをコピーしました