static void get_fanrange(int gpu, int *imin, int *imax) { struct gpu_adl *ga; if (!gpus[gpu].has_adl || !adl_active) { wlogprint("Get fanrange not supported\n"); return; } ga = &gpus[gpu].adl; *imin = ga->lpFanSpeedInfo.iMinPercent; *imax = ga->lpFanSpeedInfo.iMaxPercent; }
static void get_vddcrange(int gpu, float *imin, float *imax) { struct gpu_adl *ga; if (!gpus[gpu].has_adl || !adl_active) { wlogprint("Get vddcrange not supported\n"); return; } ga = &gpus[gpu].adl; *imin = (float)ga->lpOdParameters.sVddc.iMin / 1000; *imax = (float)ga->lpOdParameters.sVddc.iMax / 1000; }
static void get_memoryrange(int gpu, int *imin, int *imax) { struct gpu_adl *ga; if (!gpus[gpu].has_adl || !adl_active) { wlogprint("Get memoryrange not supported\n"); return; } ga = &gpus[gpu].adl; *imin = ga->lpOdParameters.sMemoryClock.iMin / 100; *imax = ga->lpOdParameters.sMemoryClock.iMax / 100; }
static int set_fanspeed(int gpu, int iFanSpeed) { struct gpu_adl *ga; int ret = 1; if (!gpus[gpu].has_adl || !adl_active) { wlogprint("Set fanspeed not supported\n"); return ret; } ga = &gpus[gpu].adl; if (!(ga->lpFanSpeedInfo.iFlags & (ADL_DL_FANCTRL_SUPPORTS_RPM_WRITE | ADL_DL_FANCTRL_SUPPORTS_PERCENT_WRITE ))) { if (opt_debug) applog(LOG_DEBUG, "GPU %d doesn't support rpm or percent write", gpu); return ret; } /* Store what fanspeed we're actually aiming for for re-entrant changes * in case this device does not support fine setting changes */ ga->targetfan = iFanSpeed; lock_adl(); if (ADL_Overdrive5_FanSpeed_Get(ga->iAdapterIndex, 0, &ga->lpFanSpeedValue) != ADL_OK) { if (opt_debug) applog(LOG_DEBUG, "GPU %d call to fanspeed get failed", gpu); } if (!(ga->lpFanSpeedInfo.iFlags & ADL_DL_FANCTRL_SUPPORTS_PERCENT_WRITE)) { /* Must convert speed to an RPM */ iFanSpeed = ga->lpFanSpeedInfo.iMaxRPM * iFanSpeed / 100; ga->lpFanSpeedValue.iSpeedType = ADL_DL_FANCTRL_SPEED_TYPE_RPM; } else ga->lpFanSpeedValue.iSpeedType = ADL_DL_FANCTRL_SPEED_TYPE_PERCENT; if (!(ga->lpFanSpeedValue.iFlags & ADL_DL_FANCTRL_FLAG_USER_DEFINED_SPEED)) { /* If user defined is not already specified, set it first */ ga->lpFanSpeedValue.iFlags = ADL_DL_FANCTRL_FLAG_USER_DEFINED_SPEED; ADL_Overdrive5_FanSpeed_Set(ga->iAdapterIndex, 0, &ga->lpFanSpeedValue); } ga->lpFanSpeedValue.iFanSpeed = iFanSpeed; ret = ADL_Overdrive5_FanSpeed_Set(ga->iAdapterIndex, 0, &ga->lpFanSpeedValue); ga->managed = true; unlock_adl(); return ret; }
static int set_engineclock(int gpu, int iEngineClock) { ADLODPerformanceLevels *lpOdPerformanceLevels; int i, lev, ret = 1; struct gpu_adl *ga; if (!gpus[gpu].has_adl || !adl_active) { wlogprint("Set engineclock not supported\n"); return ret; } iEngineClock *= 100; ga = &gpus[gpu].adl; lev = ga->lpOdParameters.iNumberOfPerformanceLevels - 1; lpOdPerformanceLevels = alloca(sizeof(ADLODPerformanceLevels) + (lev * sizeof(ADLODPerformanceLevel))); lpOdPerformanceLevels->iSize = sizeof(ADLODPerformanceLevels) + sizeof(ADLODPerformanceLevel) * lev; lock_adl(); if (ADL_Overdrive5_ODPerformanceLevels_Get(ga->iAdapterIndex, 0, lpOdPerformanceLevels) != ADL_OK) goto out; for (i = 0; i < lev; i++) { if (lpOdPerformanceLevels->aLevels[i].iEngineClock > iEngineClock) lpOdPerformanceLevels->aLevels[i].iEngineClock = iEngineClock; } lpOdPerformanceLevels->aLevels[lev].iEngineClock = iEngineClock; ADL_Overdrive5_ODPerformanceLevels_Set(ga->iAdapterIndex, lpOdPerformanceLevels); ADL_Overdrive5_ODPerformanceLevels_Get(ga->iAdapterIndex, 0, lpOdPerformanceLevels); if (lpOdPerformanceLevels->aLevels[lev].iEngineClock == iEngineClock) ret = 0; ga->iEngineClock = lpOdPerformanceLevels->aLevels[lev].iEngineClock; if (ga->iEngineClock > ga->maxspeed) ga->maxspeed = ga->iEngineClock; if (ga->iEngineClock < ga->minspeed) ga->minspeed = ga->iEngineClock; ga->iMemoryClock = lpOdPerformanceLevels->aLevels[lev].iMemoryClock; ga->iVddc = lpOdPerformanceLevels->aLevels[lev].iVddc; ga->managed = true; out: unlock_adl(); return ret; }
static int set_powertune(int gpu, int iPercentage) { struct gpu_adl *ga; int dummy, ret = 1; if (!gpus[gpu].has_adl || !adl_active) { wlogprint("Set powertune not supported\n"); return ret; } ga = &gpus[gpu].adl; lock_adl(); ADL_Overdrive5_PowerControl_Set(ga->iAdapterIndex, iPercentage); ADL_Overdrive5_PowerControl_Get(ga->iAdapterIndex, &ga->iPercentage, &dummy); if (ga->iPercentage == iPercentage) ret = 0; ga->managed = true; unlock_adl(); return ret; }
void manage_gpu(void) { struct thr_info *thr; int selected, gpu, i; char checkin[40]; char input; if (!opt_g_threads) return; opt_loginput = true; immedok(logwin, true); clear_logwin(); retry: for (gpu = 0; gpu < nDevs; gpu++) { struct cgpu_info *cgpu = &gpus[gpu]; double displayed_rolling, displayed_total; bool mhash_base = true; displayed_rolling = cgpu->rolling; displayed_total = cgpu->total_mhashes / total_secs; if (displayed_rolling < 1) { displayed_rolling *= 1000; displayed_total *= 1000; mhash_base = false; } wlog("GPU %d: %.1f / %.1f %sh/s | A:%d R:%d HW:%d U:%.2f/m I:%d\n", gpu, displayed_rolling, displayed_total, mhash_base ? "M" : "K", cgpu->accepted, cgpu->rejected, cgpu->hw_errors, cgpu->utility, cgpu->intensity); #ifdef HAVE_ADL if (gpus[gpu].has_adl) { int engineclock = 0, memclock = 0, activity = 0, fanspeed = 0, fanpercent = 0, powertune = 0; float temp = 0, vddc = 0; if (gpu_stats(gpu, &temp, &engineclock, &memclock, &vddc, &activity, &fanspeed, &fanpercent, &powertune)) { char logline[255]; strcpy(logline, ""); // In case it has no data if (temp != -1) sprintf(logline, "%.1f C ", temp); if (fanspeed != -1 || fanpercent != -1) { tailsprintf(logline, "F: "); if (fanpercent != -1) tailsprintf(logline, "%d%% ", fanpercent); if (fanspeed != -1) tailsprintf(logline, "(%d RPM) ", fanspeed); tailsprintf(logline, " "); } if (engineclock != -1) tailsprintf(logline, "E: %d MHz ", engineclock); if (memclock != -1) tailsprintf(logline, "M: %d Mhz ", memclock); if (vddc != -1) tailsprintf(logline, "V: %.3fV ", vddc); if (activity != -1) tailsprintf(logline, "A: %d%% ", activity); if (powertune != -1) tailsprintf(logline, "P: %d%%", powertune); tailsprintf(logline, "\n"); wlog(logline); } } #endif wlog("Last initialised: %s\n", cgpu->init); wlog("Intensity: "); if (gpus[gpu].dynamic) wlog("Dynamic (only one thread in use)\n"); else wlog("%d\n", gpus[gpu].intensity); for (i = 0; i < mining_threads; i++) { thr = &thr_info[i]; if (thr->cgpu != cgpu) continue; get_datestamp(checkin, &thr->last); displayed_rolling = thr->rolling; if (!mhash_base) displayed_rolling *= 1000; wlog("Thread %d: %.1f %sh/s %s ", i, displayed_rolling, mhash_base ? "M" : "K" , cgpu->deven != DEV_DISABLED ? "Enabled" : "Disabled"); switch (cgpu->status) { default: case LIFE_WELL: wlog("ALIVE"); break; case LIFE_SICK: wlog("SICK reported in %s", checkin); break; case LIFE_DEAD: wlog("DEAD reported in %s", checkin); break; case LIFE_INIT: case LIFE_NOSTART: wlog("Never started"); break; } if (thr->pause) wlog(" paused"); wlog("\n"); } wlog("\n"); } wlogprint("[E]nable [D]isable [I]ntensity [R]estart GPU %s\n",adl_active ? "[C]hange settings" : ""); wlogprint("Or press any other key to continue\n"); input = getch(); if (nDevs == 1) selected = 0; else selected = -1; if (!strncasecmp(&input, "e", 1)) { struct cgpu_info *cgpu; if (selected) selected = curses_int("Select GPU to enable"); if (selected < 0 || selected >= nDevs) { wlogprint("Invalid selection\n"); goto retry; } if (gpus[selected].deven != DEV_DISABLED) { wlogprint("Device already enabled\n"); goto retry; } gpus[selected].deven = DEV_ENABLED; for (i = 0; i < mining_threads; ++i) { thr = &thr_info[i]; cgpu = thr->cgpu; if (cgpu->api != &opencl_api) continue; if (dev_from_id(i) != selected) continue; if (cgpu->status != LIFE_WELL) { wlogprint("Must restart device before enabling it"); goto retry; } applog(LOG_DEBUG, "Pushing ping to thread %d", thr->id); tq_push(thr->q, &ping); } goto retry; } if (!strncasecmp(&input, "d", 1)) { if (selected) selected = curses_int("Select GPU to disable"); if (selected < 0 || selected >= nDevs) { wlogprint("Invalid selection\n"); goto retry; } if (gpus[selected].deven == DEV_DISABLED) { wlogprint("Device already disabled\n"); goto retry; } gpus[selected].deven = DEV_DISABLED; goto retry; } else if (!strncasecmp(&input, "i", 1)) { int intensity; char *intvar; if (selected) selected = curses_int("Select GPU to change intensity on"); if (selected < 0 || selected >= nDevs) { wlogprint("Invalid selection\n"); goto retry; } intvar = curses_input("Set GPU scan intensity (d or " _MIN_INTENSITY_STR " -> " _MAX_INTENSITY_STR ")"); if (!intvar) { wlogprint("Invalid input\n"); goto retry; } if (!strncasecmp(intvar, "d", 1)) { wlogprint("Dynamic mode enabled on gpu %d\n", selected); gpus[selected].dynamic = true; pause_dynamic_threads(selected); free(intvar); goto retry; } intensity = atoi(intvar); free(intvar); if (intensity < MIN_INTENSITY || intensity > MAX_INTENSITY) { wlogprint("Invalid selection\n"); goto retry; } gpus[selected].dynamic = false; gpus[selected].intensity = intensity; wlogprint("Intensity on gpu %d set to %d\n", selected, intensity); pause_dynamic_threads(selected); goto retry; } else if (!strncasecmp(&input, "r", 1)) { if (selected) selected = curses_int("Select GPU to attempt to restart"); if (selected < 0 || selected >= nDevs) { wlogprint("Invalid selection\n"); goto retry; } wlogprint("Attempting to restart threads of GPU %d\n", selected); reinit_device(&gpus[selected]); goto retry; } else if (adl_active && (!strncasecmp(&input, "c", 1))) { if (selected) selected = curses_int("Select GPU to change settings on"); if (selected < 0 || selected >= nDevs) { wlogprint("Invalid selection\n"); goto retry; } change_gpusettings(selected); goto retry; } else clear_logwin(); immedok(logwin, false); opt_loginput = false; }
void change_gpusettings(int gpu) { struct gpu_adl *ga = &gpus[gpu].adl; float fval, fmin = 0, fmax = 0; int val, imin = 0, imax = 0; char input; int engineclock = 0, memclock = 0, activity = 0, fanspeed = 0, fanpercent = 0, powertune = 0; float temp = 0, vddc = 0; updated: if (gpu_stats(gpu, &temp, &engineclock, &memclock, &vddc, &activity, &fanspeed, &fanpercent, &powertune)) wlogprint("Temp: %.1f C\n", temp); if (fanpercent >= 0 || fanspeed >= 0) { wlogprint("Fan Speed: "); if (fanpercent >= 0) wlogprint("%d%% ", fanpercent); if (fanspeed >= 0) wlogprint("(%d RPM)", fanspeed); wlogprint("\n"); } wlogprint("Engine Clock: %d MHz\nMemory Clock: %d Mhz\nVddc: %.3f V\nActivity: %d%%\nPowertune: %d%%\n", engineclock, memclock, vddc, activity, powertune); wlogprint("Fan autotune is %s (%d-%d)\n", ga->autofan ? "enabled" : "disabled", gpus[gpu].min_fan, gpus[gpu].gpu_fan); wlogprint("GPU engine clock autotune is %s (%d-%d)\n", ga->autoengine ? "enabled" : "disabled", ga->minspeed / 100, ga->maxspeed / 100); wlogprint("Change [A]utomatic [E]ngine [F]an [M]emory [V]oltage [P]owertune\n"); wlogprint("Or press any other key to continue\n"); input = getch(); if (!strncasecmp(&input, "a", 1)) { change_autosettings(gpu); } else if (!strncasecmp(&input, "e", 1)) { get_enginerange(gpu, &imin, &imax); wlogprint("Enter GPU engine clock speed (%d - %d Mhz)", imin, imax); val = curses_int(""); if (val < imin || val > imax) { wlogprint("Value is outside safe range, are you sure?\n"); input = getch(); if (strncasecmp(&input, "y", 1)) return; } if (!set_engineclock(gpu, val)) wlogprint("Driver reports success but check values below\n"); else wlogprint("Failed to modify engine clock speed\n"); } else if (!strncasecmp(&input, "f", 1)) { get_fanrange(gpu, &imin, &imax); wlogprint("Enter fan percentage (%d - %d %)", imin, imax); val = curses_int(""); if (val < imin || val > imax) { wlogprint("Value is outside safe range, are you sure?\n"); input = getch(); if (strncasecmp(&input, "y", 1)) return; } if (!set_fanspeed(gpu, val)) wlogprint("Driver reports success but check values below\n"); else wlogprint("Failed to modify fan speed\n"); } else if (!strncasecmp(&input, "m", 1)) { get_memoryrange(gpu, &imin, &imax); wlogprint("Enter GPU memory clock speed (%d - %d Mhz)", imin, imax); val = curses_int(""); if (val < imin || val > imax) { wlogprint("Value is outside safe range, are you sure?\n"); input = getch(); if (strncasecmp(&input, "y", 1)) return; } if (!set_memoryclock(gpu, val)) wlogprint("Driver reports success but check values below\n"); else wlogprint("Failed to modify memory clock speed\n"); } else if (!strncasecmp(&input, "v", 1)) { get_vddcrange(gpu, &fmin, &fmax); wlogprint("Enter GPU voltage (%.3f - %.3f V)", fmin, fmax); fval = curses_float(""); if (fval < fmin || fval > fmax) { wlogprint("Value is outside safe range, are you sure?\n"); input = getch(); if (strncasecmp(&input, "y", 1)) return; } if (!set_vddc(gpu, fval)) wlogprint("Driver reports success but check values below\n"); else wlogprint("Failed to modify voltage\n"); } else if (!strncasecmp(&input, "p", 1)) { val = curses_int("Enter powertune value (-20 - 20)"); if (val < -20 || val > 20) { wlogprint("Value is outside safe range, are you sure?\n"); input = getch(); if (strncasecmp(&input, "y", 1)) return; } if (!set_powertune(gpu, val)) wlogprint("Driver reports success but check values below\n"); else wlogprint("Failed to modify powertune value\n"); } else { clear_logwin(); return; } sleep(1); goto updated; }
void change_autosettings(int gpu) { struct gpu_adl *ga = &gpus[gpu].adl; char input; int val; wlogprint("Target temperature: %d\n", ga->targettemp); wlogprint("Overheat temperature: %d\n", ga->overtemp); wlogprint("Cutoff temperature: %d\n", ga->cutofftemp); wlogprint("Toggle [F]an auto [G]PU auto\nChange [T]arget [O]verheat [C]utoff\n"); wlogprint("Or press any other key to continue\n"); input = getch(); if (!strncasecmp(&input, "f", 1)) { ga->autofan ^= true; wlogprint("Fan autotune is now %s\n", ga->autofan ? "enabled" : "disabled"); if (!ga->autofan) { wlogprint("Resetting fan to startup settings\n"); set_defaultfan(gpu); } } else if (!strncasecmp(&input, "g", 1)) { ga->autoengine ^= true; wlogprint("GPU engine clock autotune is now %s\n", ga->autoengine ? "enabled" : "disabled"); if (!ga->autoengine) { wlogprint("Resetting GPU engine clock to startup settings\n"); set_defaultengine(gpu); } } else if (!strncasecmp(&input, "t", 1)) { val = curses_int("Enter target temperature for this GPU in C (0-200)"); if (val < 0 || val > 200) wlogprint("Invalid temperature"); else ga->targettemp = val; } else if (!strncasecmp(&input, "o", 1)) { wlogprint("Enter overheat temperature for this GPU in C (%d+)", ga->targettemp); val = curses_int(""); if (val <= ga->targettemp || val > 200) wlogprint("Invalid temperature"); else ga->overtemp = val; } else if (!strncasecmp(&input, "c", 1)) { wlogprint("Enter cutoff temperature for this GPU in C (%d+)", ga->overtemp); val = curses_int(""); if (val <= ga->overtemp || val > 200) wlogprint("Invalid temperature"); else ga->cutofftemp = val; } }