Browse Source

win32: implement a nvapi.dll wrapper like nvml

Allow to get/set missing infos like the power limit on x86

squashed for a better min/max and device mapping

Signed-off-by: Tanguy Pruvot <tanguy.pruvot@gmail.com>
master
Tanguy Pruvot 9 years ago
parent
commit
0deb9a2aca
  1. 5
      Algo256/bmw.cu
  2. 5
      ccminer.cpp
  3. 1
      ccminer.vcxproj
  4. 3
      ccminer.vcxproj.filters
  5. 44
      compat/nvapi/nvapi_ccminer.h
  6. 128
      nvapi.cpp
  7. 69
      nvml.cpp

5
Algo256/bmw.cu

@ -6,9 +6,8 @@ extern "C" {
#include "sph/sph_bmw.h" #include "sph/sph_bmw.h"
} }
#include "miner.h" #include <miner.h>
#include <cuda_helper.h>
#include "cuda_helper.h"
static uint32_t *d_hash[MAX_GPUS]; static uint32_t *d_hash[MAX_GPUS];

5
ccminer.cpp

@ -295,12 +295,15 @@ Options:\n\
--max-rate=N[KMG] Only mine if net hashrate is less than specified value\n\ --max-rate=N[KMG] Only mine if net hashrate is less than specified value\n\
--max-diff=N Only mine if net difficulty is less than specified value\n\ --max-diff=N Only mine if net difficulty is less than specified value\n\
Can be tuned with --resume-diff=N to set a resume value\n" Can be tuned with --resume-diff=N to set a resume value\n"
#if defined(USE_WRAPNVML) && (defined(__linux) || defined(_WIN64)) /* via nvml */ #if defined(__linux) || defined(_WIN64) /* via nvml */
"\ "\
--mem-clock=3505 Set the gpu memory max clock (346.72+ driver)\n\ --mem-clock=3505 Set the gpu memory max clock (346.72+ driver)\n\
--gpu-clock=1150 Set the gpu engine max clock (346.72+ driver)\n\ --gpu-clock=1150 Set the gpu engine max clock (346.72+ driver)\n\
--pstate=0[,2] Set the gpu power state (352.21+ driver)\n\ --pstate=0[,2] Set the gpu power state (352.21+ driver)\n\
--plimit=100W Set the gpu power limit (352.21+ driver)\n" --plimit=100W Set the gpu power limit (352.21+ driver)\n"
#else /* via nvapi.dll */
"\
--plimit=100 Set the gpu power limit in percentage\n"
#endif #endif
#ifdef HAVE_SYSLOG_H #ifdef HAVE_SYSLOG_H
"\ "\

1
ccminer.vcxproj

@ -230,6 +230,7 @@
<TreatWChar_tAsBuiltInType>false</TreatWChar_tAsBuiltInType> <TreatWChar_tAsBuiltInType>false</TreatWChar_tAsBuiltInType>
<Optimization Condition="'$(Configuration)'=='Release'">Full</Optimization> <Optimization Condition="'$(Configuration)'=='Release'">Full</Optimization>
</ClCompile> </ClCompile>
<ClCompile Include="nvapi.cpp" />
<ClCompile Include="pools.cpp" /> <ClCompile Include="pools.cpp" />
<ClCompile Include="util.cpp" /> <ClCompile Include="util.cpp" />
<ClCompile Include="bench.cpp" /> <ClCompile Include="bench.cpp" />

3
ccminer.vcxproj.filters

@ -264,6 +264,9 @@
<ClCompile Include="sph\blake2s.c"> <ClCompile Include="sph\blake2s.c">
<Filter>Source Files\sph</Filter> <Filter>Source Files\sph</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="nvapi.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="algos.h"> <ClInclude Include="algos.h">

44
compat/nvapi/nvapi_ccminer.h

@ -1,2 +1,44 @@
/* todo: stripped version... or not */ #pragma once
#include "nvapi.h" #include "nvapi.h"
NvAPI_Status nvapi_dll_init();
typedef struct {
NvU32 version;
NvU32 flags;
struct
{
NvU32 pstate; // Assumption
NvU32 unknown1[2];
NvU32 min_power;
NvU32 unknown2[2];
NvU32 def_power;
NvU32 unknown3[2];
NvU32 max_power;
NvU32 unknown4; // 0
} entries[4];
} NVAPI_GPU_POWER_INFO;
typedef struct {
NvU32 version;
NvU32 flags;
struct {
NvU32 unknown1;
NvU32 unknown2;
NvU32 power; // percent * 1000
NvU32 unknown4;
} entries[4];
} NVAPI_GPU_POWER_STATUS;
#define NVAPI_GPU_POWER_STATUS_VER MAKE_NVAPI_VERSION(NVAPI_GPU_POWER_STATUS, 1)
#define NVAPI_GPU_POWER_INFO_VER MAKE_NVAPI_VERSION(NVAPI_GPU_POWER_INFO, 1)
NvAPI_Status NvAPI_DLL_GetInterfaceVersionString(NvAPI_ShortString string);
NvAPI_Status NvAPI_DLL_ClientPowerPoliciesGetInfo(NvPhysicalGpuHandle hPhysicalGpu, NVAPI_GPU_POWER_INFO* pInfo);
NvAPI_Status NvAPI_DLL_ClientPowerPoliciesGetStatus(NvPhysicalGpuHandle hPhysicalGpu, NVAPI_GPU_POWER_STATUS* pPolicies);
NvAPI_Status NvAPI_DLL_ClientPowerPoliciesSetStatus(NvPhysicalGpuHandle hPhysicalGpu, NVAPI_GPU_POWER_STATUS* pPolicies);
NvAPI_Status NvAPI_DLL_Unload();
#define NV_ASSERT(x) { NvAPI_Status ret = x; if(ret != NVAPI_OK) return ret; }

128
nvapi.cpp

@ -0,0 +1,128 @@
/**
* Wrapper to nvapi.dll to query informations missing for x86 binaries (there is no nvml x86)
* based on the work of https://github.com/ircubic/lib_gpu
*
* tpruvot@ccminer.org 06-2016
*/
#ifdef _WIN32
#include <windows.h>
#include <memory>
#include <stdexcept>
#include "compat/nvapi/nvapi_ccminer.h"
class NvAPILibraryHandle
{
typedef void *(*QueryPtr)(uint32_t);
private:
HMODULE library;
QueryPtr nvidia_query;
public:
NvAPILibraryHandle()
{
bool success = false;
library = LoadLibrary("nvapi.dll");
if (library != NULL) {
nvidia_query = reinterpret_cast<QueryPtr>(GetProcAddress(library, "nvapi_QueryInterface"));
if (nvidia_query != NULL) {
const uint32_t NVAPI_ID_INIT = 0x0150E828;
auto init = static_cast<NvAPI_Status(*)()>(nvidia_query(NVAPI_ID_INIT));
NvAPI_Status ret = init();
success = (ret == NVAPI_OK);
}
}
if (!success) {
throw std::runtime_error("Unable to locate NVAPI library!");
}
}
~NvAPILibraryHandle()
{
NvAPI_DLL_Unload();
FreeLibrary(library);
}
void *query(uint32_t ID)
{
return nvidia_query(ID);
}
};
static std::unique_ptr<NvAPILibraryHandle> nvidia_handle;
bool nvapi_dll_loaded = false;
NvAPI_Status nvapi_dll_init()
{
try {
if (!nvapi_dll_loaded) {
nvidia_handle = std::make_unique<NvAPILibraryHandle>();
nvapi_dll_loaded = true;
}
}
catch (std::runtime_error) {
nvapi_dll_loaded = false;
return NVAPI_ERROR;
}
return NVAPI_OK;
}
// Hidden nvapi.dll functions
#define NVAPI_ID_IFVERSION 0x01053FA5
NvAPI_Status NvAPI_DLL_GetInterfaceVersionString(NvAPI_ShortString string) {
static NvAPI_Status (*pointer)(NvAPI_ShortString string) = NULL;
if(!nvapi_dll_loaded) return NVAPI_API_NOT_INITIALIZED;
if(!pointer) {
pointer = (NvAPI_Status (*)(NvAPI_ShortString))nvidia_handle->query(NVAPI_ID_IFVERSION);
}
return (*pointer)(string);
}
#define NVAPI_ID_POWER_INFO 0x34206D86
NvAPI_Status NvAPI_DLL_ClientPowerPoliciesGetInfo(NvPhysicalGpuHandle handle, NVAPI_GPU_POWER_INFO* pInfo) {
static NvAPI_Status (*pointer)(NvPhysicalGpuHandle, NVAPI_GPU_POWER_INFO*) = NULL;
if(!nvapi_dll_loaded) return NVAPI_API_NOT_INITIALIZED;
if(!pointer) {
pointer = (NvAPI_Status (*)(NvPhysicalGpuHandle, NVAPI_GPU_POWER_INFO*))nvidia_handle->query(NVAPI_ID_POWER_INFO);
}
return (*pointer)(handle, pInfo);
}
#define NVAPI_ID_POWERPOL_GET 0x70916171
NvAPI_Status NvAPI_DLL_ClientPowerPoliciesGetStatus(NvPhysicalGpuHandle handle, NVAPI_GPU_POWER_STATUS* pPolicies) {
static NvAPI_Status (*pointer)(NvPhysicalGpuHandle, NVAPI_GPU_POWER_STATUS*) = NULL;
if(!nvapi_dll_loaded) return NVAPI_API_NOT_INITIALIZED;
if(!pointer) {
pointer = (NvAPI_Status (*)(NvPhysicalGpuHandle, NVAPI_GPU_POWER_STATUS*))nvidia_handle->query(NVAPI_ID_POWERPOL_GET);
}
return (*pointer)(handle, pPolicies);
}
#define NVAPI_ID_POWERPOL_SET 0x0AD95F5ED
NvAPI_Status NvAPI_DLL_ClientPowerPoliciesSetStatus(NvPhysicalGpuHandle handle, NVAPI_GPU_POWER_STATUS* pPolicies) {
static NvAPI_Status (*pointer)(NvPhysicalGpuHandle, NVAPI_GPU_POWER_STATUS*) = NULL;
if(!nvapi_dll_loaded) return NVAPI_API_NOT_INITIALIZED;
if(!pointer) {
pointer = (NvAPI_Status (*)(NvPhysicalGpuHandle, NVAPI_GPU_POWER_STATUS*))nvidia_handle->query(NVAPI_ID_POWERPOL_SET);
}
return (*pointer)(handle, pPolicies);
}
#define NVAPI_ID_UNLOAD 0xD22BDD7E
NvAPI_Status NvAPI_DLL_Unload() {
static NvAPI_Status (*pointer)() = NULL;
if(!nvapi_dll_loaded) return NVAPI_API_NOT_INITIALIZED;
if(!pointer) {
pointer = (NvAPI_Status (*)())nvidia_handle->query(NVAPI_ID_UNLOAD);
}
return (*pointer)();
}
#endif

69
nvml.cpp

@ -460,7 +460,7 @@ int nvml_set_pstate(nvml_handle *nvmlh, int dev_id)
nclocks = min(nclocks, 32); nclocks = min(nclocks, 32);
if (nclocks) if (nclocks)
nvmlh->nvmlDeviceGetSupportedMemoryClocks(nvmlh->devs[n], &nclocks, mem_clocks); nvmlh->nvmlDeviceGetSupportedMemoryClocks(nvmlh->devs[n], &nclocks, mem_clocks);
if (wanted_pstate+1 > nclocks) { if ((uint32_t) wanted_pstate+1 > nclocks) {
applog(LOG_WARNING, "GPU #%d: only %u mem clocks available (p-states)", dev_id, nclocks); applog(LOG_WARNING, "GPU #%d: only %u mem clocks available (p-states)", dev_id, nclocks);
} }
for (uint8_t u=0; u < nclocks; u++) { for (uint8_t u=0; u < nclocks; u++) {
@ -789,6 +789,8 @@ int nvml_destroy(nvml_handle *nvmlh)
return 0; return 0;
} }
// ----------------------------------------------------------------------------
/** /**
* nvapi alternative for windows x86 binaries * nvapi alternative for windows x86 binaries
* nvml api doesn't exists as 32bit dll :/// * nvml api doesn't exists as 32bit dll :///
@ -800,6 +802,7 @@ static int nvapi_dev_map[MAX_GPUS] = { 0 };
static NvDisplayHandle hDisplay_a[NVAPI_MAX_PHYSICAL_GPUS * 2] = { 0 }; static NvDisplayHandle hDisplay_a[NVAPI_MAX_PHYSICAL_GPUS * 2] = { 0 };
static NvPhysicalGpuHandle phys[NVAPI_MAX_PHYSICAL_GPUS] = { 0 }; static NvPhysicalGpuHandle phys[NVAPI_MAX_PHYSICAL_GPUS] = { 0 };
static NvU32 nvapi_dev_cnt = 0; static NvU32 nvapi_dev_cnt = 0;
extern bool nvapi_dll_loaded;
int nvapi_temperature(unsigned int devNum, unsigned int *temperature) int nvapi_temperature(unsigned int devNum, unsigned int *temperature)
{ {
@ -967,6 +970,52 @@ int nvapi_getbios(unsigned int devNum, char *desc, unsigned int maxlen)
return 0; return 0;
} }
uint8_t nvapi_getplimit(unsigned int devNum)
{
NvAPI_Status ret = NVAPI_OK;
NVAPI_GPU_POWER_STATUS pol = { 0 };
pol.version = NVAPI_GPU_POWER_STATUS_VER;
if ((ret = NvAPI_DLL_ClientPowerPoliciesGetStatus(phys[devNum], &pol)) != NVAPI_OK) {
NvAPI_ShortString string;
NvAPI_GetErrorMessage(ret, string);
if (opt_debug)
applog(LOG_DEBUG, "NVAPI GetPowerPoliciesStatus: %s", string);
return 0;
}
return (uint8_t) (pol.entries[0].power / 1000); // in percent
}
int nvapi_setplimit(unsigned int devNum, uint16_t percent)
{
NvAPI_Status ret = NVAPI_OK;
uint32_t val = percent * 1000;
NVAPI_GPU_POWER_INFO nfo = { 0 };
nfo.version = NVAPI_GPU_POWER_INFO_VER;
ret = NvAPI_DLL_ClientPowerPoliciesGetInfo(phys[devNum], &nfo);
if (ret == NVAPI_OK) {
if (val == 0)
val = nfo.entries[0].def_power;
else if (val < nfo.entries[0].min_power)
val = nfo.entries[0].min_power;
else if (val > nfo.entries[0].max_power)
val = nfo.entries[0].max_power;
}
NVAPI_GPU_POWER_STATUS pol = { 0 };
pol.version = NVAPI_GPU_POWER_STATUS_VER;
pol.flags = 1;
pol.entries[0].power = val;
if ((ret = NvAPI_DLL_ClientPowerPoliciesSetStatus(phys[devNum], &pol)) != NVAPI_OK) {
NvAPI_ShortString string;
NvAPI_GetErrorMessage(ret, string);
if (opt_debug)
applog(LOG_DEBUG, "NVAPI SetPowerPoliciesStatus: %s", string);
return -1;
}
return ret;
}
int nvapi_init() int nvapi_init()
{ {
int num_gpus = cuda_num_devices(); int num_gpus = cuda_num_devices();
@ -1017,11 +1066,12 @@ int nvapi_init()
applog(LOG_DEBUG, "NVAPI NvAPI_GPU_GetFullName: %s", string); applog(LOG_DEBUG, "NVAPI NvAPI_GPU_GetFullName: %s", string);
} }
} }
#if 0 #if 0
if (opt_debug) {
NvAPI_ShortString ver; NvAPI_ShortString ver;
NvAPI_GetInterfaceVersionString(ver); NvAPI_GetInterfaceVersionString(ver);
applog(LOG_DEBUG, "NVAPI Version: %s", ver); applog(LOG_DEBUG, "%s", ver);
}
#endif #endif
NvU32 udv; NvU32 udv;
@ -1031,6 +1081,19 @@ int nvapi_init()
sprintf(driver_version,"%d.%02d", udv / 100, udv % 100); sprintf(driver_version,"%d.%02d", udv / 100, udv % 100);
} }
// nvapi.dll
ret = nvapi_dll_init();
if (ret == NVAPI_OK) {
for (int n=0; n < opt_n_threads; n++) {
int dev_id = device_map[n % MAX_GPUS];
if (device_plimit[dev_id]) {
nvapi_setplimit(nvapi_dev_map[dev_id], device_plimit[dev_id]); // 0=default
uint32_t res = nvapi_getplimit(nvapi_dev_map[dev_id]);
gpulog(LOG_INFO, n, "NVAPI power limit is set to %u%%", res);
}
}
}
return 0; return 0;
} }
#endif #endif

Loading…
Cancel
Save