static void last_nettime(struct timeval2 *last) { rd_lock(&netacc_lock); last->tv_sec = nettime.tv_sec; last->tv_usec = nettime.tv_usec; rd_unlock(&netacc_lock); }
/* In dynamic mode, only the first thread of each device will be in use. * This potentially could start a thread that was stopped with the start-stop * options if one were to disable dynamic from the menu on a paused GPU */ void pause_dynamic_threads(int gpu) { struct cgpu_info *cgpu = &gpus[gpu]; int i; rd_lock(&mining_thr_lock); for (i = 1; i < cgpu->threads; i++) { struct thr_info *thr; thr = cgpu->thr[i]; if (!thr->pause && cgpu->dynamic) { applog(LOG_WARNING, "Disabling extra threads due to dynamic mode."); applog(LOG_WARNING, "Tune dynamic intensity with --gpu-dyninterval"); } thr->pause = cgpu->dynamic; if (!cgpu->dynamic && cgpu->deven != DEV_DISABLED) cgsem_post(&thr->sem); } rd_unlock(&mining_thr_lock); }
void manage_gpu(void) { struct thr_info *thr; int selected, gpu, i; char checkin[40]; char input; if (!opt_g_threads) { applog(LOG_ERR, "opt_g_threads not set in manage_gpu()"); return; } opt_loginput = true; immedok(logwin, true); clear_logwin(); retry: // TODO: refactor 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 xI:%d rI:%d\n", gpu, displayed_rolling, displayed_total, mhash_base ? "M" : "K", cgpu->accepted, cgpu->rejected, cgpu->hw_errors, cgpu->utility, cgpu->intensity, cgpu->xintensity, cgpu->rawintensity); #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, sizeof(logline), "F: "); if (fanpercent != -1) tailsprintf(logline, sizeof(logline), "%d%% ", fanpercent); if (fanspeed != -1) tailsprintf(logline, sizeof(logline), "(%d RPM) ", fanspeed); tailsprintf(logline, sizeof(logline), " "); } if (engineclock != -1) tailsprintf(logline, sizeof(logline), "E: %d MHz ", engineclock); if (memclock != -1) tailsprintf(logline, sizeof(logline), "M: %d Mhz ", memclock); if (vddc != -1) tailsprintf(logline, sizeof(logline), "V: %.3fV ", vddc); if (activity != -1) tailsprintf(logline, sizeof(logline), "A: %d%% ", activity); if (powertune != -1) tailsprintf(logline, sizeof(logline), "P: %d%%", powertune); tailsprintf(logline, sizeof(logline), "\n"); _wlog(logline); } } #endif wlog("Last initialised: %s\n", cgpu->init); rd_lock(&mining_thr_lock); for (i = 0; i < mining_threads; i++) { thr = mining_thr[i]; if (thr->cgpu != cgpu) continue; get_datestamp(checkin, sizeof(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"); } rd_unlock(&mining_thr_lock); wlog("\n"); } wlogprint("[E]nable [D]isable [R]estart GPU %s\n",adl_active ? "[C]hange settings" : ""); wlogprint("[I]ntensity E[x]perimental intensity R[a]w Intensity\n"); wlogprint("Or press any other key to continue\n"); logwin_update(); 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; rd_lock(&mining_thr_lock); for (i = 0; i < mining_threads; ++i) { thr = mining_thr[i]; cgpu = thr->cgpu; if (cgpu->drv->drv_id != DRIVER_opencl) 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 sem post to thread %d", thr->id); cgsem_post(&thr->sem); } rd_unlock(&mining_thr_lock); goto retry; } else 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; gpus[selected].xintensity = 0; // Disable xintensity when enabling intensity gpus[selected].rawintensity = 0; // Disable raw intensity when enabling intensity wlogprint("Intensity on gpu %d set to %d\n", selected, intensity); pause_dynamic_threads(selected); goto retry; } else if (!strncasecmp(&input, "x", 1)) { int xintensity; char *intvar; if (selected) selected = curses_int("Select GPU to change experimental intensity on"); if (selected < 0 || selected >= nDevs) { wlogprint("Invalid selection\n"); goto retry; } intvar = curses_input("Set experimental GPU scan intensity (" MIN_XINTENSITY_STR " -> " MAX_XINTENSITY_STR ")"); if (!intvar) { wlogprint("Invalid input\n"); goto retry; } xintensity = atoi(intvar); free(intvar); if (xintensity < MIN_XINTENSITY || xintensity > MAX_XINTENSITY) { wlogprint("Invalid selection\n"); goto retry; } gpus[selected].dynamic = false; gpus[selected].intensity = 0; // Disable intensity when enabling xintensity gpus[selected].rawintensity = 0; // Disable raw intensity when enabling xintensity gpus[selected].xintensity = xintensity; wlogprint("Experimental intensity on gpu %d set to %d\n", selected, xintensity); pause_dynamic_threads(selected); goto retry; } else if (!strncasecmp(&input, "a", 1)) { int rawintensity; char *intvar; if (selected) selected = curses_int("Select GPU to change raw intensity on"); if (selected < 0 || selected >= nDevs) { wlogprint("Invalid selection\n"); goto retry; } intvar = curses_input("Set raw GPU scan intensity (" MIN_RAWINTENSITY_STR " -> " MAX_RAWINTENSITY_STR ")"); if (!intvar) { wlogprint("Invalid input\n"); goto retry; } rawintensity = atoi(intvar); free(intvar); if (rawintensity < MIN_RAWINTENSITY || rawintensity > MAX_RAWINTENSITY) { wlogprint("Invalid selection\n"); goto retry; } gpus[selected].dynamic = false; gpus[selected].intensity = 0; // Disable intensity when enabling raw intensity gpus[selected].xintensity = 0; // Disable xintensity when enabling raw intensity gpus[selected].rawintensity = rawintensity; wlogprint("Raw intensity on gpu %d set to %d\n", selected, rawintensity); 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; }
/* We have only one thread that ever re-initialises GPUs, thus if any GPU * init command fails due to a completely wedged GPU, the thread will never * return, unable to harm other GPUs. If it does return, it means we only had * a soft failure and then the reinit_gpu thread is ready to tackle another * GPU */ void *reinit_gpu(void *userdata) { struct thr_info *mythr = (struct thr_info *)userdata; struct cgpu_info *cgpu; struct thr_info *thr; struct timeval now; char name[256]; int thr_id; int gpu; pthread_detach(pthread_self()); select_cgpu: cgpu = (struct cgpu_info *)tq_pop(mythr->q, NULL); if (!cgpu) goto out; if (clDevicesNum() != nDevs) { applog(LOG_WARNING, "Hardware not reporting same number of active devices, will not attempt to restart GPU"); goto out; } gpu = cgpu->device_id; rd_lock(&mining_thr_lock); for (thr_id = 0; thr_id < mining_threads; ++thr_id) { thr = mining_thr[thr_id]; cgpu = thr->cgpu; if (cgpu->drv->drv_id != DRIVER_opencl) continue; if (dev_from_id(thr_id) != gpu) continue; thr->rolling = thr->cgpu->rolling = 0; /* Reports the last time we tried to revive a sick GPU */ cgtime(&thr->sick); if (!pthread_kill(thr->pth, 0)) { applog(LOG_WARNING, "Thread %d still exists, killing it off", thr_id); cg_completion_timeout(&thr_info_cancel_join, thr, 5000); thr->cgpu->drv->thread_shutdown(thr); } else applog(LOG_WARNING, "Thread %d no longer exists", thr_id); } rd_unlock(&mining_thr_lock); rd_lock(&mining_thr_lock); for (thr_id = 0; thr_id < mining_threads; ++thr_id) { int virtual_gpu; thr = mining_thr[thr_id]; cgpu = thr->cgpu; if (cgpu->drv->drv_id != DRIVER_opencl) continue; if (dev_from_id(thr_id) != gpu) continue; virtual_gpu = cgpu->virtual_gpu; /* Lose this ram cause we may get stuck here! */ //tq_freeze(thr->q); thr->q = tq_new(); if (!thr->q) quit(1, "Failed to tq_new in reinit_gpu"); /* Lose this ram cause we may dereference in the dying thread! */ //free(clState); applog(LOG_INFO, "Reinit GPU thread %d", thr_id); clStates[thr_id] = initCl(virtual_gpu, name, sizeof(name), &cgpu->algorithm); if (!clStates[thr_id]) { applog(LOG_ERR, "Failed to reinit GPU thread %d", thr_id); goto select_cgpu; } applog(LOG_INFO, "initCl() finished. Found %s", name); if (unlikely(thr_info_create(thr, NULL, miner_thread, thr))) { applog(LOG_ERR, "thread %d create failed", thr_id); return NULL; } applog(LOG_WARNING, "Thread %d restarted", thr_id); } rd_unlock(&mining_thr_lock); cgtime(&now); get_datestamp(cgpu->init, sizeof(cgpu->init), &now); rd_lock(&mining_thr_lock); for (thr_id = 0; thr_id < mining_threads; ++thr_id) { thr = mining_thr[thr_id]; cgpu = thr->cgpu; if (cgpu->drv->drv_id != DRIVER_opencl) continue; if (dev_from_id(thr_id) != gpu) continue; cgsem_post(&thr->sem); } rd_unlock(&mining_thr_lock); goto select_cgpu; out: return NULL; }