Implement auto fanspeed adjustment to maintain a target temperature and fanspeed below 85%, with an overheat check that will speed the fan up to 100%.
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 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
diff --git a/adl.c b/adl.c
index 3310204..614bfd1 100644
--- a/adl.c
+++ b/adl.c
@@ -199,19 +199,36 @@ void init_adl(int nDevs)
/* We're only interested in the top performance level */
lpOdPerformanceLevels = alloca(sizeof(ADLODPerformanceLevels) + (lev * sizeof(ADLODPerformanceLevel)));
lpOdPerformanceLevels->iSize = sizeof(ADLODPerformanceLevels) + sizeof(ADLODPerformanceLevel) * lev;
- if (ADL_Overdrive5_ODPerformanceLevels_Get(iAdapterIndex, 0, lpOdPerformanceLevels) != ADL_OK) {
+
+ /* Get default performance levels first */
+ if (ADL_Overdrive5_ODPerformanceLevels_Get(iAdapterIndex, 1, lpOdPerformanceLevels) != ADL_OK) {
applog(LOG_INFO, "Failed to ADL_Overdrive5_ODPerformanceLevels_Get");
continue;
}
+ /* Set the limits we'd use based on default gpu speeds */
+ ga->maxspeed = ga->minspeed = lpOdPerformanceLevels->aLevels[lev].iEngineClock;
+
+ /* Now get the current performance levels for any existing overclock */
+ ADL_Overdrive5_ODPerformanceLevels_Get(iAdapterIndex, 0, lpOdPerformanceLevels);
ga->iEngineClock = lpOdPerformanceLevels->aLevels[lev].iEngineClock;
ga->iMemoryClock = lpOdPerformanceLevels->aLevels[lev].iMemoryClock;
ga->iVddc = lpOdPerformanceLevels->aLevels[lev].iVddc;
+ /* Now use any parameters already set outside default as limits */
+ if (ga->iEngineClock < ga->minspeed)
+ ga->minspeed = ga->iEngineClock;
+ if (ga->iEngineClock > ga->maxspeed)
+ ga->maxspeed = ga->iEngineClock;
+
if (ADL_Overdrive5_FanSpeedInfo_Get(iAdapterIndex, 0, &ga->lpFanSpeedInfo) != ADL_OK) {
applog(LOG_INFO, "Failed to ADL_Overdrive5_FanSpeedInfo_Get");
continue;
}
+ /* Set some default temperatures for autotune when enabled */
+ ga->targettemp = 75;
+ ga->overtemp = 85;
+
gpus[devices - 1].has_adl = true;
}
@@ -293,7 +310,7 @@ int gpu_fanspeed(int gpu)
return 0;
ga = &gpus[gpu].adl;
- if (!(ga->lpFanSpeedInfo.iFlags & (ADL_DL_FANCTRL_SUPPORTS_RPM_READ | ADL_DL_FANCTRL_SUPPORTS_PERCENT_READ )))
+ if (!(ga->lpFanSpeedInfo.iFlags & ADL_DL_FANCTRL_SUPPORTS_RPM_READ))
return 0;
ga->lpFanSpeedValue.iSpeedType = ADL_DL_FANCTRL_SPEED_TYPE_RPM;
if (ADL_Overdrive5_FanSpeed_Get(ga->iAdapterIndex, 0, &ga->lpFanSpeedValue) != ADL_OK)
@@ -301,6 +318,22 @@ int gpu_fanspeed(int gpu)
return ga->lpFanSpeedValue.iFanSpeed;
}
+static int gpu_fanpercent(int gpu)
+{
+ struct gpu_adl *ga;
+
+ if (!gpus[gpu].has_adl || !adl_active)
+ return -1;
+
+ ga = &gpus[gpu].adl;
+ if (!(ga->lpFanSpeedInfo.iFlags & ADL_DL_FANCTRL_SUPPORTS_PERCENT_READ ))
+ return -1;
+ ga->lpFanSpeedValue.iSpeedType = ADL_DL_FANCTRL_SPEED_TYPE_PERCENT;
+ if (ADL_Overdrive5_FanSpeed_Get(ga->iAdapterIndex, 0, &ga->lpFanSpeedValue) != ADL_OK)
+ return -1;
+ return ga->lpFanSpeedValue.iFanSpeed;
+}
+
static void get_enginerange(int gpu, int *imin, int *imax)
{
struct gpu_adl *ga;
@@ -518,17 +551,74 @@ static int set_fanspeed(int gpu, int iFanSpeed)
return 0;
}
+void gpu_autotune(int gpu)
+{
+ struct gpu_adl *ga;
+ int temp, fanpercent;
+
+ if (!gpus[gpu].has_adl || !adl_active)
+ return;
+
+ temp = gpu_temp(gpu);
+ if (!temp)
+ return;
+ fanpercent = gpu_fanpercent(gpu);
+ if (fanpercent < 0)
+ return;
+
+ ga = &gpus[gpu].adl;
+ if (temp > ga->overtemp) {
+ applog(LOG_WARNING, "Overhead detected, increasing fan to 100%");
+ set_fanspeed(gpu, 100);
+ return;
+ }
+ if (temp > ga->targettemp && fanpercent < 85) {
+ if (opt_debug)
+ applog(LOG_DEBUG, "Temperature over target, increasing fanspeed");
+ set_fanspeed(gpu, fanpercent + 5);
+ return;
+ }
+ if (fanpercent && temp < ga->targettemp - 5) {
+ if (opt_debug)
+ applog(LOG_DEBUG, "Temperature 5 degrees below target, decreasing fanspeed");
+ set_fanspeed(gpu, fanpercent - 1);
+ }
+}
+
+void change_autosettings(int gpu)
+{
+ struct gpu_adl *ga = &gpus[gpu].adl;
+ char input;
+
+ wlogprint("Fan autotune is %s\n", ga->autofan ? "enabled" : "disabled");
+ wlogprint("Target temperature: %d\n", ga->targettemp);
+ wlogprint("Overheat temperature: %d\n", ga->overtemp);
+ wlogprint("Change [F]an [T]arget [O]verheat\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("Setting fan to 85 %% as safety precaution\n");
+ set_fanspeed(gpu, 85);
+ }
+ }
+}
+
void change_gpusettings(int gpu)
{
int val, imin = 0, imax = 0;
float fval, fmin = 0, fmax = 0;
char input;
- wlogprint("Change [E]ngine [F]an [M]emory [V]oltage\n");
+ wlogprint("Change [A]utomatic [E]ngine [F]an [M]emory [V]oltage\n");
wlogprint("Or press any other key to continue\n");
input = getch();
- if (!strncasecmp(&input, "e", 1)) {
+ 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("");
@@ -542,7 +632,7 @@ void change_gpusettings(int gpu)
wlogprint("Successfully modified engine clock speed\n");
else
wlogprint("Failed to modify engine clock speed\n");
- } else if (!strncasecmp(&input, "f", 1)) {
+ } else if (!strncasecmp(&input, "f", 1)) {
get_fanrange(gpu, &imin, &imax);
wlogprint("Enter fan percentage (%d - %d %)", imin, imax);
val = curses_int("");
diff --git a/adl.h b/adl.h
index 2e3fee7..1bd0e02 100644
--- a/adl.h
+++ b/adl.h
@@ -10,10 +10,12 @@ float gpu_vddc(int gpu);
int gpu_activity(int gpu);
int gpu_fanspeed(int gpu);
void change_gpusettings(int gpu);
+void gpu_autotune(int gpu);
void clear_adl(void);
#else /* HAVE_ADL */
void init_adl(int nDevs) {}
void change_gpusettings(int gpu) { }
+void gpu_autotune(int gpu) { }
void clear_adl(void) {}
#endif
#endif
diff --git a/main.c b/main.c
index e0d0164..f83fa8b 100644
--- a/main.c
+++ b/main.c
@@ -4337,6 +4337,8 @@ static void *watchdog_thread(void *userdata)
break;
thr = &thr_info[i];
gpu = thr->cgpu->cpu_gpu;
+ if (adl_active)
+ gpu_autotune(gpu);
/* Thread is waiting on getwork or disabled */
if (thr->getwork || !gpu_devices[gpu])
continue;
diff --git a/miner.h b/miner.h
index 58cf810..ad9d2ae 100644
--- a/miner.h
+++ b/miner.h
@@ -168,6 +168,13 @@ struct gpu_adl {
int iEngineClock;
int iMemoryClock;
int iVddc;
+
+ bool autofan;
+ bool autoengine;
+ int targettemp;
+ int overtemp;
+ int minspeed;
+ int maxspeed;
};
#endif