I don't know how i can submit anything that I've modified so i'm just going to leave them here.
I hope you guys like it.
The javascript file only contains changes to the text output in the html page, nothing more 😉
<!DOCTYPE html>
<html>
<head>
<title>Excavator OCTune © Created by NiceHash</title>
<style>
* {
padding: 0;
margin: 0;
}
body {
height: 100vh;
width: 100vw;
overflow: hidden;
font-family: system-ui, Ubuntu, sans-serif;
-webkit-font-smoothing: antialiased;
font-size: 14px;
background: black;
}
a {
color: rgb(48, 57, 182);
text-decoration: none;
}
h1 {
margin-bottom: 2rem;
}
.hidden {
visibility: hidden;
}
.container {
display: flex;
flex-direction: row;
background: #010d15;
color: #ccc;
height: calc(100vh - 110px);
overflow-y: auto;
overflow-x: hidden;
}
.control-pannel {
padding: 2rem 1rem 2rem 2rem;
width: 65vw;
}
.log-pannel {
padding: 2rem .5rem 2rem 1rem;
width: 35vw;
}
.log-pannel button {
float: right;
}
.log-pannel label {
font-size: 16px;
font-weight: 600;
}
table {
width: 100%;
text-align: center;
margin: .5rem 0 1rem;
}
.set-oc {
display: flex;
flex-direction: column;
width: 50%;
}
.form-group {
display: flex;
width: 100%;
height: 1.2rem;
padding: 0.2rem;
justify-content: flex-end;
align-items: center;
}
.form-group label,
.form-group h4 {
margin-right: auto;
}
.form-group input {
margin-right: 0.2rem;
width: 3rem;
}
button {
margin-left: 5px;
padding: .1rem .5rem;
background: #08385c;
color: #fff;
font-weight: 600;
border-width: 1px;
}
button:focus {
outline: none;
}
button.fixed {
width: 2.5rem;
}
button:disabled {
filter: grayscale(1);
cursor: not-allowed;
}
button#stop_auto_tune {
background: #9f0909;
}
.button-box {
margin-top: .7rem;
}
.dials {
display: flex;
flex-direction: row;
column-gap: 3rem;
margin-bottom: 2rem;
}
#selected-device {
width: auto;
}
break {
display: inline-block;
}
footer {
position: fixed;
bottom: 0;
left: 0;
width: 100vw;
display: flex;
flex-direction: column;
row-gap: 1rem;
padding: 1rem;
background: #031a2a;
color: #eee;
padding-right: 16px;
padding-left: 16px;
}
footer p {
font-weight: 500;
}
input[type="range"] {
-webkit-appearance: none;
-moz-appearance: none;
width: 135px;
margin: 5rem;
height: 10px;
padding: 0;
border-radius: 2px;
outline: none;
cursor: pointer;
background: #583c1d;
}
/*Chrome thumb*/
input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
-moz-appearance: none;
-webkit-border-radius: 5px;
height: 16px;
width: 16px;
border-radius: 5px;
background: #fba342;
border: 1px solid #c5c5c5;
}
/*Mozilla thumb*/
input[type="range"]::-moz-range-thumb {
-webkit-appearance: none;
-moz-appearance: none;
-moz-border-radius: 5px;
height: 14px;
width: 14px;
border-radius: 5px;
background: #fba342;
border: 1px solid #c5c5c5;
}
#log-view-div {
height: calc(100vh - 180px);
overflow: auto;
margin-top: 1rem;
font-size: 13px;
display: flex;
flex-direction: column;
row-gap: .6rem;
word-break: break-word;
}
.set-oc {
display: inline-block;
}
@media (max-width: 600px) {
.control-pannel {
padding: 2rem 1rem 2rem 2rem;
width: auto;
}
.dials {
flex-direction: column;
}
}
@media (max-width: 1366px) {
.container {
padding: 2rem;
flex-direction: column;
}
.control-pannel {
padding: 0;
width: 100%;
}
.set-oc {
width: 100%;
}
.log-pannel {
padding: 0;
width: 100%;
}
#log-view-div {
height: calc(100vh - 1000px);
}
}
.log-class-normal {
color: #ccc;
font-family: "Lucida Console";
font-weight: 600;
}
.log-class-warning {
color: lightsalmon;
font-family: "Lucida Console";
font-weight: 600;
}
.log-class-error {
color: orangered;
font-family: "Lucida Console";
font-weight: 600;
}
.log-class-ocscanner {
color: greenyellow;
font-family: "Lucida Console";
font-weight: 600;
}
.log-class-autotune {
color: #3986fa;
font-family: "Lucida Console";
font-weight: 600;
}
.auto-tune-disable {}
.temp-mem-high {
color: red;
font-weight: 600;
}
.temp-mem-med {
color: orange;
font-weight: 600;
}
.temp-mem-low {
color: forestgreen;
}
</style>
<script type="text/javascript" src="jquery.min.js"></script>
<script type="text/javascript" src="octune.js"></script>
</head>
<body onload="start_code()">
<div class="container">
<div class="control-pannel">
<h1>NiceHash QuickMiner Overclock Tool</h1>
<h2>Excavator Health Monitor</h2>
<table border="1">
<thead>
<tr>
<th>GPU ID</th>
<th>GPU Name</th>
<th>Temp<br />GPU ℃</th>
<th>Temp<br />VRAM ℃</th>
<th>Fan<br />(RPM)</th>
<th>Fan (%)</th>
<th>Fan reset</th>
<th>Core<br />MHz</th>
<th>Core<br />Limit</th>
<th>Memory<br />MHz</th>
<th>Selected?<br />
<input class="auto-tune-disable" type="checkbox" id="all-selected" onchange="all_selected_changed()" class="auto-tune-disable">
<label for="all-selected">All</label>
</th>
</tr>
</thead>
<tbody id="table-main-health">
</tbody>
</table>
<h2>Excavator OC Tunner</h2>
<table border="1">
<thead>
<tr>
<th>GPU ID</th>
<th>GPU Name</th>
<th>Min<br />KT</th>
<th>Avg<br />KT</th>
<th>UMed<br />KT</th>
<th>HW<br />err</th>
<th>HW<br />ok</th>
<th>Core<br />Delta</th>
<th>Mem<br />Delta</th>
<th>Power<br />Lim (W)</th>
<th>TDP<br />Lim (%)</th>
<th>Power<br />Real (W)</th>
<th>Speed<br />(MH/s)</th>
<th>Eff. (kH/J)</th>
</tr>
</thead>
<tbody id="table-main-oc">
</tbody>
<tfoot>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<th id="total-power">0</th>
<th id="total-speed">0</th>
<th id="total-eff">0</th>
</tr>
</tfoot>
</table>
<h2>Classic method for overclocking:</h2>
<div class="dials">
<div class="set-oc">
<div class="form-group">
<label for="selected-core">Core clock delta:</label>
<input class="auto-tune-disable" type="text" id="selected-core" value="" size="3" />
<button class="fixed auto-tune-disable" onclick="change_core_clock(-25)">-25</button>
<button class="fixed auto-tune-disable" onclick="change_core_clock(-10)">-10</button>
<button class="fixed auto-tune-disable" onclick="change_core_clock(10)">+10</button>
<button class="fixed auto-tune-disable" onclick="change_core_clock(25)">+25</button>
</div>
<div class="form-group">
<label for="selected-memory">Memory clock delta:</label>
<input class="auto-tune-disable" type="text" id="selected-memory" value="" size="3" />
<button class="fixed auto-tune-disable" onclick="change_mem_clock(-25)">-25</button>
<button class="fixed auto-tune-disable" onclick="change_mem_clock(-10)">-10</button>
<button class="fixed auto-tune-disable" onclick="change_mem_clock(10)">+10</button>
<button class="fixed auto-tune-disable" onclick="change_mem_clock(25)">+25</button>
</div>
<div class="form-group">
<label for="selected-power">Power limit (W):</label>
<input class="auto-tune-disable" type="text" id="selected-power" value="" size="3" />
<button class="fixed auto-tune-disable" onclick="change_power(-5)">-5</button>
<button class="fixed auto-tune-disable" onclick="change_power(-2)">-2</button>
<button class="fixed auto-tune-disable" onclick="change_power(2)">+2</button>
<button class="fixed auto-tune-disable" onclick="change_power(5)">+5</button>
</div>
<div class="form-group">
<label for="selected-fan">Fan speed (%):</label>
<input class="auto-tune-disable" type="text" id="selected-fan" value="" size="2" />
<button class="fixed auto-tune-disable" onclick="change_fan(-20)">-20</button>
<button class="fixed auto-tune-disable" onclick="change_fan(-5)">-5</button>
<button class="fixed auto-tune-disable" onclick="change_fan(5)">+5</button>
<button class="fixed auto-tune-disable" onclick="change_fan(20)">+20</button>
</div>
<div class="form-group button-box">
<span style="margin-right: auto">Apply Overclock: </span>
<button onclick="apply_oc()" class="auto-tune-disable">Single</button>
<button onclick="apply_oc_selected()" class="auto-tune-disable">Selected</button>
<button onclick="apply_oc_all()" class="auto-tune-disable">All</button>
</div>
</div>
<div class="set-oc">
<div class="form-group">
<label for="refresh-time">Refresh time:</label>
<input class="auto-tune-disable" type="range" min="1" max="5" value="2" class="slider" id="refresh-time" onchange="refresh_change()" />
<span style="display: flex;column-gap: 0.3rem;">
<div id="refresh-time-text">2</div> seconds
</span>
</div>
<div class="form-group">
<label for="selected-device">Single selected device:</label>
<select id="selected-device" onchange="pre_oc_fill()"></select>
</div>
<div class="form-group"></div>
<div class="form-group">
<button onclick="location.reload()" class="auto-tune-disable">Refresh page</button>
<button onclick="save_current_cmds()" class="auto-tune-disable">Save current configuration</button>
</div>
<div class="form-group button-box">
<h4>Reset:</h4>
<button onclick="reset_oc()" class="auto-tune-disable">Single</button>
<button onclick="reset_oc_selected()" class="auto-tune-disable">Selected</button>
<button onclick="reset_oc_all()" class="auto-tune-disable">All</button>
</div>
</div>
</div>
<h2>Alternative method for overclocking:</h2>
<div class="dials">
<div class="set-oc">
<div class="form-group">
<label for="selected-core-max">Core clock limit: (set to 0 to disable limit)</label>
<input class="auto-tune-disable" type="text" id="selected-core-max" value="210" size="3" />
<button class="fixed hidden"></button>
<button class="fixed hidden"></button>
<button class="fixed auto-tune-disable" onclick="change_core_clock_max(-15)">-15</button>
<button class="fixed auto-tune-disable" onclick="change_core_clock_max(15)">+15</button>
</div>
<div class="form-group">
<label for="selected-memory-abs">Memory clock (absolute):</label>
<input class="auto-tune-disable" type="text" id="selected-memory-abs" value="" size="3" />
<button class="fixed auto-tune-disable" onclick="change_mem_clock_abs(-25)">-25</button>
<button class="fixed auto-tune-disable" onclick="change_mem_clock_abs(-10)">-10</button>
<button class="fixed auto-tune-disable" onclick="change_mem_clock_abs(10)">+10</button>
<button class="fixed auto-tune-disable" onclick="change_mem_clock_abs(25)">+25</button>
</div>
<div class="form-group">
<p style="margin-right: auto;">Power limit is not set. Power depends on your set clocks!</p>
</div>
<div class="form-group">
<label for="selected-fan-alt">Fan speed (%):</label>
<input class="auto-tune-disable" type="text" id="selected-fan-alt" value="" size="2" />
<button class="fixed auto-tune-disable" onclick="change_fan_alt(-20)">-20</button>
<button class="fixed auto-tune-disable" onclick="change_fan_alt(-5)">-5</button>
<button class="fixed auto-tune-disable" onclick="change_fan_alt(5)">+5</button>
<button class="fixed auto-tune-disable" onclick="change_fan_alt(20)">+20</button>
</div>
<div class="form-group button-box">
<span style="margin-right: auto">Apply Overclock: </span>
<button onclick="apply_oc_alt()" class="auto-tune-disable">Single</button>
<button onclick="apply_oc_selected_alt()" class="auto-tune-disable">Selected</button>
<button onclick="apply_oc_all_alt()" class="auto-tune-disable">All</button>
</div>
</div>
<div class="set-oc">
<div class="form-group">
<label for="at-memory">Auto tune for absolute memory: (min: <span id="at-mem-min"></span>, max: <span id="at-mem-max"></span>)</label>
<input class="auto-tune-disable" type="text" id="at-memory" value="" size="3" />
</div>
<div class="form-group">
<label for="at-core-start">Starting core clock limit: </label>
<input class="auto-tune-disable" type="text" id="at-core-start" value="480" size="3" />
</div>
<div class="form-group">
<label for="at-core-end">Ending core clock limit: (Tune for max.)</label>
<input class="auto-tune-disable" type="text" id="at-core-end" value="1605" size="3" />
</div>
<div class="form-group">
<span style="margin-right: auto; width: 100%;">Tune for: </span>
<input class="auto-tune-disable" type="radio" id="at-eff" name="at-target" value="Efficiency" checked>
<label for="at-eff" style="margin-right: 1rem;">Efficiency</label>
<input class="auto-tune-disable" type="radio" id="at-speed" name="at-target" value="Speed">
<label for="at-speed">Speed</label>
</div>
<div class="form-group button-box">
<span style="margin-right: auto">Auto-tune: </span>
<button onclick="auto_tune_start(null)" class="auto-tune-disable" id="at-enable">Start</button>
<button onclick="auto_tune_start_selected()" class="auto-tune-disable" id="at-enable">Selected</button>
<button id="stop_auto_tune" disabled onclick="auto_tune_finish_now()">Stop Now</button>
</div>
</div>
</div>
</div>
<div class="log-pannel">
<button onclick="clear_logs()">Clear event logs</button>
<label for="log-view">Events:</label>
<div id="log-view-div"></div>
</div>
</div>
<footer>
<h4>Instructions how to use OCTune are available at
<a href="https://github.com/nicehash/NiceHashQuickMiner/wiki/OCTune" target="_blank">NiceHash QuickMiner GitHub Wiki</a>
</h4>
<p> NVIDIA NVML library has a memleak in function nvmlDeviceGetPowerUsage. Make sure you do not keep OCTune open when you do not need it.<br />If you keep it open, end result can be complete system memory exhaustion and Windows crash.</p>
</footer>
</body>
</html>
var url = "http://localhost:18000/";
var devices;
var devices_count = 0;
var refresh_time = 2000;
var updating_fans = 0;
var first_time = true;
var devices_indices = new Array();
var log_lines = new Array();
var log_index = 0;
var MAX_LOG_SIZE = 200;
var last_update_failed = false;
var tick_handler = null;
var selected_devices = new Array();
var session_id = null;
var session_missmatch_count = 0;
var GDDR6MemoryClockRange = [ 5800, 8800 ];
var GDDR6XMemoryClockRange3080 = [ 8250, 11250 ];
var GDDR6XMemoryClockRange3090 = [ 8500, 11500 ];
function start_code() {
session_id = gen_random_str();
clear_logs();
log_write('normal', 'Starting up...');
_tick();
}
var rg_alphabet = 'abcdefghijklmnopqrstuvwxyz0123456789';
function gen_random_str() {
var gen_str = '';
var c_count = rg_alphabet.length;
for (var i = 0; i < 16; ++i)
gen_str += rg_alphabet[Math.floor(Math.random() * c_count)];
return gen_str;
}
function log_write(t, s) {
//if (first_time) return;
var d = new Date();
var str = '<span class="log-class-' + t + '">[' + d.toLocaleString() + '] ';
str += s + '</span>';
log_lines[log_index] = str;
var start = log_index;
log_index = (log_index + 1) % MAX_LOG_SIZE;
var end = log_index;
// print whole log now
var all = '';
var i = 0;
while (start !== end) {
all += log_lines[start];
if (start === 0) start = MAX_LOG_SIZE - 1;
else --start;
}
$('#log-view-div').html(all);
}
function clear_logs() {
log_lines = new Array();
log_index = 0;
$('#log-view-div').html('');
for (var i = 0; i < MAX_LOG_SIZE; ++i)
log_lines[i] = '';
}
function _tick() {
var rf_time = 10000;
if (!last_update_failed) rf_time = refresh_time + 13;
tick_handler = setTimeout(_tick, rf_time);
updateAll();
}
//function check_multiple_tabs(psid) {
// if (psid == null) return;
// if (psid === session_id) return;
// ++session_missmatch_count;
// if (session_missmatch_count >= 4) {
// alert('Multiple open OCTune TABS detected! Please, use only one to improve performance of your mining!');
// session_missmatch_count = 0;
// }
//}
function updateAll() {
$.ajax({
url: url + "devices_cuda",
/*beforeSend: function (xhr) {
xhr.setRequestHeader('OCTune-ID', session_id);
},*/
//headers: { 'OCTune-ID': session_id },
success: function (data, textS, request) {
var reconn = last_update_failed;
last_update_failed = false;
if (data.error !== null) {
log_write('error', 'Failed to get cuda devices');
return;
}
//check_multiple_tabs(request.getResponseHeader('OCTune-ID-Previous'));
devices = data.devices;
devices_count = data.devices.length;
for (var i = 0; i < devices.length; ++i) {
var dd = devices[i];
if (dd.name === "GeForce RTX 3080")
dd.GDDRData = GDDR6XMemoryClockRange3080;
else if (dd.name === "GeForce RTX 3090")
dd.GDDRData = GDDR6XMemoryClockRange3090;
else if (parseInt(dd.details.sm_major) >= 7)
dd.GDDRData = GDDR6MemoryClockRange;
else
dd.GDDRData = null;
}
if (first_time) {
first_time = false;
//get_current_credentials();
// build table first time
var disp_health = '';
var disp = '';
for (var i = 0; i < devices_count; ++i) {
var k = devices[i].device_id;
devices_indices[k] = i;
disp += '<tr><td>' + k + '</td>';
disp += '<td>' + devices[i].name + '</td>';
disp += '<td id="device-' + k + '-kt-min"></td>';
disp += '<td id="device-' + k + '-kt-avg"></td>';
disp += '<td id="device-' + k + '-kt-umed"></td>';
disp += '<td id="device-' + k + '-hwerr"></td>';
disp += '<td id="device-' + k + '-hwok"></td>';
disp += '<td id="device-' + k + '-oc-core"></td>';
disp += '<td id="device-' + k + '-oc-mem"></td>';
disp += '<td id="device-' + k + '-oc-pwr"></td>';
disp += '<td id="device-' + k + '-oc-tdp"></td>';
disp += '<td id="device-' + k + '-power"></td>';
disp += '<td id="device-' + k + '-speed"></td>';
disp += '<th id="device-' + k + '-eff"></th>';
disp += '</tr>';
$('#selected-device').append($('<option>', {
value: k,
text: k + '. ' + devices[i].name
}));
disp_health += '<tr><td>' + k + '</td>';
disp_health += '<td>' + devices[i].name + '</td>';
disp_health += '<td id="device-' + k + '-temp"></td>';
disp_health += '<td id="device-' + k + '-temp-mem"></td>';
disp_health += '<td id="device-' + k + '-fan-rpm"></td>';
disp_health += '<td id="device-' + k + '-fan-perc"></td>';
disp_health += '<td><button onclick="reset_fan(' + k + ')">Reset</button></td>';
disp_health += '<td id="device-' + k + '-clock-core"></td>';
disp_health += '<td id="device-' + k + '-oc-core-limit"></td>';
disp_health += '<td id="device-' + k + '-clock-mem"></td>';
disp_health += '<td><input type="checkbox" id="device-' + k + '-selected" class="auto-tune-disable"></td>';
disp_health += '</tr>';
}
$('#table-main-oc').html(disp);
$('#table-main-health').html(disp_health);
pre_oc_fill();
}
if (reconn) pre_oc_fill();
for (var i = 0; i < devices.length; ++i) {
devices[i].oc_data.power_limit_watts = Math.floor(devices[i].oc_data.power_limit_watts);
var dd = devices[i];
var k = dd.device_id;
$('#device-' + k + '-id').html(dd.device_id);
$('#device-' + k + '-name').html(dd.name);
$('#device-' + k + '-temp').html(dd.gpu_temp);
$('#device-' + k + '-temp').removeClass('temp-mem-high');
$('#device-' + k + '-temp').removeClass('temp-mem-low');
$('#device-' + k + '-temp').removeClass('temp-mem-med');
var int_temp = parseInt(dd.gpu_temp);
if (int_temp > 85)
$('#device-' + k + '-temp').addClass('temp-mem-high');
else if (int_temp > 75)
$('#device-' + k + '-temp').addClass('temp-mem-med');
else
$('#device-' + k + '-temp').addClass('temp-mem-low');
if (dd.fans.length > 0) {
var rpm_text = '';
var level_text = '';
for (var d = 0; d < dd.fans.length; ++d) {
var fan = dd.fans[d];
if (d > 0) {
rpm_text += '<br/>';
level_text += '';
}
rpm_text += fan.current_rpm;
level_text += fan.current_level;
}
$('#device-' + k + '-fan-rpm').html(rpm_text);
$('#device-' + k + '-fan-perc').html(level_text);
dd.gpu_fan_speed = dd.fans[0].current_level;
}
else {
$('#device-' + k + '-fan-rpm').html(dd.gpu_fan_speed_rpm);
$('#device-' + k + '-fan-perc').html(dd.gpu_fan_speed);
}
if (updating_fans == 0)
$('#fan-level-' + k).val(dd.gpu_fan_speed);
if (dd.kernel_times.min > 0)
$('#device-' + k + '-kt-min').html(dd.kernel_times.min);
if (dd.kernel_times.umed > 0)
$('#device-' + k + '-kt-umed').html(dd.kernel_times.umed);
if (dd.kernel_times.avg > 0)
$('#device-' + k + '-kt-avg').html(dd.kernel_times.avg);
$('#device-' + k + '-hwerr').html(dd.hw_errors);
$('#device-' + k + '-hwok').html(dd.hw_errors_success);
$('#device-' + k + '-clock-core').html(dd.gpu_clock_core);
$('#device-' + k + '-clock-mem').html(dd.gpu_clock_memory);
$('#device-' + k + '-oc-core').html(dd.oc_data.core_clock_delta);
$('#device-' + k + '-oc-mem').html(dd.oc_data.memory_clock_delta);
$('#device-' + k + '-oc-core-limit').html(dd.oc_data.core_clock_limit);
$('#device-' + k + '-oc-pwr').html(dd.oc_data.power_limit_watts);
$('#device-' + k + '-oc-tdp').html(dd.oc_data.power_limit_tdp);
if (dd.gpu_power_usage != null)
$('#device-' + k + '-power').html(dd.gpu_power_usage.toFixed(2));
else
$('#device-' + k + '-power').html('N/A');
if (dd.__gddr6x_temp != undefined) {
$('#device-' + k + '-temp-mem').html(dd.__gddr6x_temp);
$('#device-' + k + '-temp-mem').removeClass('temp-mem-high');
$('#device-' + k + '-temp-mem').removeClass('temp-mem-low');
$('#device-' + k + '-temp-mem').removeClass('temp-mem-med');
int_temp = parseInt(dd.__gddr6x_temp);
if (int_temp > 105)
$('#device-' + k + '-temp-mem').addClass('temp-mem-high');
else if (int_temp > 95)
$('#device-' + k + '-temp-mem').addClass('temp-mem-med');
else
$('#device-' + k + '-temp-mem').addClass('temp-mem-low');
if (int_temp >= 110) {
log_write('warning', 'WARNING! Device #' + k + ' video card memory is OVERHEATING! Temperature: ' + int_temp + ' ℃');
}
}
else
$('#device-' + k + '-temp-mem').html('');
}
$.ajax({
url: url + "workers",
success: function (data) {
if (data.error !== null) return;
for (var i = 0; i < devices.length; ++i)
devices[i].speed = 0;
for (var i = 0; i < data.workers.length; ++i) {
var dev_id = data.workers[i].device_id;
var speed = data.workers[i].algorithms[0].speed / 1000000;
devices[dev_id].speed = speed;
var th_per_ke_str = data.workers[i].params_used; // "B=21888,TPB=64,S=2,KT=2"
var ssplit = th_per_ke_str.split(",");
var _blocks = 1;
var _tpb = 1;
var _streams = 1;
for (var t = 0; t < ssplit.length; ++t) {
var ssplit2 = ssplit[t].split("=");
if (ssplit2[0] === "B")
_blocks = parseInt(ssplit2[1]);
else if (ssplit2[0] === "TPB")
_tpb = parseInt(ssplit2[1]);
else if (ssplit2[0] === "S")
_streams = parseInt(ssplit2[1]);
}
devices[dev_id].hashes_per_ke = _blocks * _tpb * _streams;
}
for (var i = 0; i < devices.length; ++i) {
var dev_id = devices[i].device_id;
$('#device-' + dev_id + '-speed').html(devices[i].speed.toFixed(2));
if (devices[i].gpu_power_usage != null && devices[i].gpu_power_usage > 0) {
devices[i].eff = devices[i].speed * 1000 / devices[i].gpu_power_usage;
$('#device-' + dev_id + '-eff').html((devices[i].eff).toFixed(2));
}
}
// update totals
var t_speed = 0;
var t_power = 0;
for (var i = 0; i < devices_count; ++i) {
if (devices[i].gpu_power_usage != null) {
t_speed += devices[i].speed;
t_power += devices[i].gpu_power_usage;
}
}
$('#total-speed').html(t_speed.toFixed(2));
$('#total-power').html(t_power.toFixed(2));
if (t_power > 0)
$('#total-eff').html((t_speed * 1000 / t_power).toFixed(2));
},
error: function (data) {
log_write('error', 'Cannot connect: /workers');
}
});
}, error: function () {
log_write('error', 'Cannot connect: /cuda_devices');
last_update_failed = true;
}
});
}
function apply_oc_alt(dev_id) {
if (dev_id == null)
dev_id = $('#selected-device').val();
var core_max = $('#selected-core-max').val();
var memory = $('#selected-memory-abs').val();
var fanspd = parseInt($('#selected-fan-alt').val());
var fanss = null;
if (!isNaN(fanspd)) fanss = fanspd;
var strurl = url + 'setocprofile2?id=' + dev_id + '&core=' + core_max + '&memory=' + memory;
log_write('normal', 'Applying OC (alt) dev=' + dev_id + ' max core=' + core_max + ' memory=' + memory);
if (fanss != null) {
strurl += "&fan=" + fanss;
log_write('normal', 'With fan level: ' + fanss + '%');
}
$.ajax({
url: strurl,
success: function (data) {
if (data.error !== null) {
log_write('normal', 'Failed to apply OC (alt)');
}
else {
log_write('normal', 'Applied OC (alt) successfully');
}
},
error: function () { }
});
}
function apply_oc_all_alt() {
var core_max = $('#selected-core-max').val();
var memory = $('#selected-memory-abs').val();
var fanspd = parseInt($('#selected-fan-alt').val());
var fanss = null;
if (!isNaN(fanspd)) fanss = fanspd;
log_write('normal', 'Applying OC (alt) for all devices; core=' + core_max + ' mem=' + memory);
var urlend = "&core=" + core_max + "&memory=" + memory;
if (fanss != null) {
urlend += "&fan=" + fanss;
log_write('normal', 'With fan level: ' + fanss + '%');
}
for (var i = 0; i < devices.length; ++i) {
$.ajax({
url: url + "setocprofile2?id=" + devices[i].device_id + urlend,
indexValue: devices[i].device_id,
success: function (data, indexValue) {
if (data.error !== null) {
log_write('normal', 'Failed to apply OC (alt) for device #' + this.indexValue);
}
else {
log_write('normal', 'Applied OC (alt) successfully for device #' + this.indexValue);
}
}
});
}
}
function apply_oc_with_params(dev_id, core_delta, memory_delta, power, fan) {
var strurl = url + "setocprofile?id=" + dev_id + "&core=" + core_delta + "&memory=" + memory_delta + "&watts=" + power;
log_write('normal', 'Applying OC, dev=' + dev_id + ' core=' + core_delta + ' mem=' + memory_delta + ' pwr=' + power);
if (fan != null) {
strurl += "&fan=" + fan;
log_write('normal', 'With fan level: ' + fan + '%');
}
++updating_fans;
$.ajax({
url: strurl,
//indexValue: [dev_id, core_delta, memory_delta, power],
success: function (data) {
if (data.error !== null) {
log_write('normal', 'Failed to apply OC');
}
else {
log_write('normal', 'Applied OC successfully');
}
--updating_fans;
},
error: function () { --updating_fans; }
});
}
function apply_oc(dev_id) {
if (dev_id == null)
dev_id = $('#selected-device').val();
var core_delta = $('#selected-core').val();
var memory_delta = $('#selected-memory').val();
var power = $('#selected-power').val();
var fanspd = parseInt($('#selected-fan').val());
var fanss = null;
if (!isNaN(fanspd)) fanss = fanspd;
apply_oc_with_params(dev_id, core_delta, memory_delta, power, fanss);
}
function apply_oc_all() {
var core_delta = $('#selected-core').val();
var memory_delta = $('#selected-memory').val();
var power = $('#selected-power').val();
var fanspd = parseInt($('#selected-fan').val());
var fanss = '';
var fanlog = '';
if (!isNaN(fanspd)) {
fanss += '&fan=' + parseInt(fanspd);
fanlog += ' fan=' + parseInt(fanspd);
}
log_write('normal', 'Applying OC for all devices; core=' + core_delta + ' mem=' + memory_delta + ' pwr=' + power + fanlog);
for (var i = 0; i < devices.length; ++i) {
$.ajax({
url: url + "setocprofile?id=" + devices[i].device_id + "&core=" + core_delta + "&memory=" + memory_delta + "&watts=" + power + fanss,
indexValue: devices[i].device_id,
success: function (data, indexValue) {
if (data.error !== null) {
// handle err case
}
else {
log_write('normal', 'Applied OC successfully for device #' + this.indexValue);
}
}
});
}
}
function reset_oc(dev_id) {
if (dev == null)
dev_id = $('#selected-device').val();
log_write('normal', 'Resetting OC, dev=' + dev_id);
$.ajax({
url: url + "resetoc?id=" + dev_id,
success: function (data) {
if (data.error !== null) {
// handle err case
}
else {
log_write('normal', 'Reset OC successfully');
}
}
});
}
function reset_oc_all() {
log_write('normal', 'Resetting OC for all devices');
for (var i = 0; i < devices.length; ++i) {
$.ajax({
url: url + "resetoc?id=" + devices[i].device_id,
indexValue: devices[i].device_id,
success: function (data, indexValue) {
if (data.error !== null) {
// handle err case
}
else {
log_write('normal', 'Reset OC successfully for device #' + this.indexValue);
}
}
});
}
}
function change_core_clock_max(clk) {
$('#selected-core-max').val(parseInt($('#selected-core-max').val()) + clk);
}
function change_mem_clock_abs(clk) {
$('#selected-memory-abs').val(parseInt($('#selected-memory-abs').val()) + clk);
}
function change_core_clock(clk) {
$('#selected-core').val(parseInt($('#selected-core').val()) + clk);
}
function change_mem_clock(clk) {
$('#selected-memory').val(parseInt($('#selected-memory').val()) + clk);
}
function change_power(pwr) {
$('#selected-power').val(parseInt($('#selected-power').val()) + pwr);
}
function change_fan(f) {
var nw = parseInt($('#selected-fan').val());
if (isNaN(nw)) {
switch (f) {
case -20:
nw = 0; break;
case -5:
nw = 25; break;
case 5:
nw = 75; break;
case 20:
nw = 100; break;
default:
nw = 50; break;
}
}
nw += f;
if (nw > 100) nw = 100;
if (nw < 0) nw = 0;
$('#selected-fan').val(nw);
}
function change_fan_alt(f) {
var nw = parseInt($('#selected-fan-alt').val());
if (isNaN(nw)) {
switch (f) {
case -20:
nw = 0; break;
case -5:
nw = 25; break;
case 5:
nw = 75; break;
case 20:
nw = 100; break;
default:
nw = 50; break;
}
}
nw += f;
if (nw > 100) nw = 100;
if (nw < 0) nw = 0;
$('#selected-fan-alt').val(nw);
}
function refresh_change() {
var secs = $('#refresh-time').val();
//console.log(secs);
$('#refresh-time-text').html(secs);
refresh_time = parseInt(secs * 1000);
if (tick_handler != null) {
clearTimeout(tick_handler);
_tick();
}
}
function pre_oc_fill() {
var dev_id = $('#selected-device').val();
var device_ocs = devices[dev_id].oc_data;
$('#selected-core').val(device_ocs.core_clock_delta);
$('#selected-memory').val(device_ocs.memory_clock_delta);
$('#selected-power').val(device_ocs.power_limit_watts);
$('#selected-core-max').val(device_ocs.core_clock_limit);
$('#selected-memory-abs').val(devices[dev_id].gpu_clock_memory);
$('#at-memory').val(devices[dev_id].gpu_clock_memory);
if (devices[dev_id].GDDRData !== null)
{
$('#at-mem-min').html(devices[dev_id].GDDRData[0]);
$('#at-mem-max').html(devices[dev_id].GDDRData[1]);
$('#at-enable').attr('disabled', false);
}
else
{
$('#at-mem-min').html('N/A');
$('#at-mem-max').html('N/A');
$('#at-enable').attr('disabled', true);
}
var fans = devices[dev_id].fans;
if (fans.length > 0) {
if (!fans[0].is_auto) {
$('#selected-fan').val(fans[0].current_level);
$('#selected-fan-alt').val(fans[0].current_level);
}
else {
$('#selected-fan').val('');
$('#selected-fan-alt').val('');
}
}
else {
$('#selected-fan').val(devices[dev_id].gpu_fan_speed);
$('#selected-fan-alt').val(devices[dev_id].gpu_fan_speed);
}
}
function get_admin() {
$.ajax({
url: url + "elevate",
success: function (data) {
if (data.error !== null) {
log_write('error', 'Failed to acquire administrator privileges! Overclocking will not work.');
}
else {
log_write('normal', 'Administrator privileges acquired!');
}
},
error: function () {
log_write('normal', 'Administrator privileges acquired!');
}
});
}
function save_current_cmds() {
$.ajax({
url: url + "cmdcommit",
success: function (data) {
if (data.error !== null) {
log_write('error', 'Failed to save current commands.');
}
else {
log_write('normal', 'Configuration saved!');
alert('Your current overclock and fan settings have been commited to commands.json file. Previous configuration saved as .bak file.\n\n' +
'These settings will be applied next time Excavator is started.');
}
},
error: function () {
}
});
}
function apply_credentials() {
var username = $('#input-username').val();
var location = $('#input-location').val();
log_write('normal', 'Setting username: ' + username + ' (location: ' + location + ')');
$.ajax({
url: url + "quickstart?id=" + username + '&loc=' + location,
success: function (data) {
if (data.error !== null) {
log_write('error', 'Failed to apply new credentials.');
}
else {
log_write('normal', 'New credentials applied!');
}
},
error: function () {
}
});
}
function get_current_credentials() {
$.ajax({
url: url + 'api?command={"id":1,"method":"subscribe.info","params":[]}',
success: function (data) {
if (data.error !== null) {
}
else {
if (data.address.substring(0, 12) === 'nhmp-ssl.usa')
$('#input-location').val('usa');
else
$('#input-location').val('eu');
$('#input-username').val(data.login);
//log_write('normal', 'New credentials applied!');
}
},
error: function () {
}
});
}
function detect_selected_devices() {
selected_devices = new Array();
for (var i = 0; i < devices.length; ++i)
if ($('#device-' + devices[i].device_id + '-selected').is(":checked"))
selected_devices.push(i);
}
function make_action_for_selected(sfunc) {
detect_selected_devices();
while (selected_devices.length > 0) {
var popdev = selected_devices.pop();
sfunc(popdev);
}
}
function reset_oc_selected() {
make_action_for_selected(reset_oc);
}
function apply_oc_selected() {
make_action_for_selected(apply_oc);
}
function apply_oc_selected_alt() {
make_action_for_selected(apply_oc_alt);
}
// =========================================
// DEVICE HEALTH
// =========================================
function reset_fan(dev_id) {
$.ajax({
url: url + "fanreset?id=" + dev_id,
success: function (data) {
if (data.error !== null) {
// handle err case
}
else {
log_write('normal', 'Fan reset');
//updateAll();
}
}
});
}
function set_fan(i) {
var dev_id = devices[i].device_id;
var core_delta = devices[i].oc_data.core_clock_delta;
var memory_delta = devices[i].oc_data.memory_clock_delta;
var power = devices[i].oc_data.power_limit_watts;
var fan_level = $('#fan-level-' + dev_id).val();
apply_oc_with_params(dev_id, core_delta, memory_delta, power, fan_level);
}
function set_fan_all(level) {
var fan_level = $('#fan-speed-all').val();
for (var i = 0; i < devices.length; ++i) {
var dev_id = devices[i].device_id;
var core_delta = devices[i].oc_data.core_clock_delta;
var memory_delta = devices[i].oc_data.memory_clock_delta;
var power = devices[i].oc_data.power_limit_watts;
apply_oc_with_params(dev_id, core_delta, memory_delta, power, fan_level);
}
}
function all_selected_changed() {
var tocheck = false;
if ($("#all-selected").is(":checked")) tocheck = true;
for (var i = 0; i < devices.length; ++i)
$('#device-' + devices[i].device_id + '-selected').prop('checked', tocheck);
}
// =========================================
// AUTO TUNE
// =========================================
var at_running = false;
var at_req_to_end = false;
var at_device_id;
var at_device_index;
var at_fastest_core;
var at_eff_core;
var at_wanted_memory;
var at_current_clock;
var at_kt_lowest;
var at_power_sum;
var at_core_min;
var at_core_max;
var at_results;
var at_hashes_per_ke;
var at_prev_fan;
const KT_WAIT_TIME = 2500;
const CLOCK_STEP = 15;
const ABSOLUTE_CORE_MIN_CLOCK = 210;
var at_next_applied_clock;
// http_call_res:
// 0 = all OK
// 1 = call OK, but method failed
// 2 = call failed
function at_error(http_call_res, err_msg) {
if (http_call_res !== 0) {
if (http_call_res === 2)
log_write('autotune', 'Finished prematurely because HTTP API call failed. Did Excavator crash?');
else
log_write('autotune', err_msg);
$('.auto-tune-disable').each(function () {
$(this).attr('disabled', false);
});
// release scanner
at_running = false;
return;
}
// report last stable OC found
if (!at_req_to_end && at_fastest_core != null)
{
if (at_prev_fan != null)
at_prev_fan = '&fan=' + at_prev_fan;
else {
reset_fan(at_device_id);
at_prev_fan = '';
}
if ($("#at-eff").is(":checked")) {
at_next_applied_clock = at_eff_core;
at_call("setocprofile2?id=" + at_device_id +
"&core=" + at_eff_core + "&memory=" + at_wanted_memory + at_prev_fan,
function (data) {
log_write('autotune', 'Best OC for EFFICIENCY applied (memory: ' + at_wanted_memory +
'MHz, core clock limit: ' + at_next_applied_clock + 'MHz)');
}
);
}
else {
at_next_applied_clock = at_fastest_core;
at_call("setocprofile2?id=" + at_device_id +
"&core=" + at_fastest_core + "&memory=" + at_wanted_memory + at_prev_fan,
function (data) {
log_write('autotune', 'Best OC for SPEED applied (memory: ' + at_wanted_memory +
'MHz, core clock limit: ' + at_next_applied_clock + 'MHz)');
}
);
}
}
else
{
// reset OC to return everything back to normal
$.ajax({ url: url + "resetoc?id=" + at_device_id,
success: function (data) {
log_write('autotune', 'OC has been reset! Please, reapply it.');
}});
}
// report error
log_write('autotune', err_msg);
// release scanner
at_running = false;
if (selected_devices.length > 0) {
var dev = selected_devices.pop();
setTimeout(auto_tune_start, 1000, dev);
return;
}
$( '.auto-tune-disable' ).each(function() {
$( this ).attr('disabled', false);
});
}
function at_call(_url, _action) {
if (at_req_to_end) {
at_error(0, 'Cancelled by the user');
return;
}
$.ajax({
url: url + _url,
success: function (data) {
if (data.error !== null) {
at_error(1, data.error);
}
else {
_action(data);
}
},
error: function (data) {
at_error(2, null);
}
});
}
function at_resetoc(_action) {
at_call("resetoc?id=" + at_device_id,
function (data) { _action(data); });
}
function at_core_limit(_core, _action) {
// {"id":1,"method":"device.set.tdp","params":["0","150"]}
var _url = 'api?command={"id":1,"method":"device.set.core_abs","params":["' +
at_device_id + '","' + _core + '"]}';
at_call(_url, function (data) { _action(data); });
}
function at_get_ktumed(_action) {
at_call('getkerneltimes?id=' + at_device_id,
function (data) {
_action(data.kernel_times.umed);
});
}
function auto_tune_start(dev)
{
if (at_running)
{
log_write('autotune', 'Already running');
return; // already running
}
var mem_min = parseInt($('#at-mem-min').html());
var mem_max = parseInt($('#at-mem-max').html());
at_wanted_memory = parseInt($('#at-memory').val());
if (isNaN(at_wanted_memory) || at_wanted_memory < mem_min || at_wanted_memory > mem_max)
{
log_write('autotune', 'Invalid memory value; must be min=' + mem_min + ', max=' + mem_max);
return;
}
if (dev !== null) at_device_id = devices[dev].device_id;
else at_device_id = $('#selected-device').val();
at_device_index = devices_indices[at_device_id];
var at_core_max_dev = devices[at_device_index].gpu_clock_core_max;
at_hashes_per_ke = devices[at_device_index].hashes_per_ke;
if (at_hashes_per_ke === null || at_hashes_per_ke === 0)
at_hashes_per_ke = 1;
at_core_min = parseInt($('#at-core-start').val());
if (isNaN(at_core_min) || at_core_min < ABSOLUTE_CORE_MIN_CLOCK || at_core_min >= at_core_max)
{
log_write('autotune', 'Invalid core start value; must be min=210, max=' + at_core_max);
return;
}
at_core_max = parseInt($('#at-core-end').val());
if (isNaN(at_core_max) || at_core_max < at_core_min || at_core_max > at_core_max_dev) {
log_write('autotune', 'Invalid core end value; must be min=' + at_core_min + ', max=' + at_core_max_dev);
return;
}
if (devices[at_device_index].gpu_power_usage == null) {
log_write('autotune', 'Device #' + at_device_id + ': Cannot perform without support for power consumption reporting!');
return;
}
$( '.auto-tune-disable' ).each(function() {
$( this ).attr('disabled', true);
});
$('#stop_auto_tune').attr('disabled', false);
// round at_core_min number
var aa = at_core_min / CLOCK_STEP;
at_core_min = Math.floor(CLOCK_STEP * Math.floor(aa));
$('#at-core-start').val(at_core_min);
at_req_to_end = false;
at_running = true;
at_fastest_core = null;
at_eff_core = null;
at_results = new Array();
var fans = devices[at_device_index].fans;
if (fans.length > 0) {
if (!fans[0].is_auto) {
at_prev_fan = fans[0].current_level;
}
else {
at_prev_fan = null;
}
}
else {
at_prev_fan = devices[at_device_index].gpu_fan_speed;
}
log_write('autotune', 'Starting up for device id #' + at_device_id + ',<break> absolute memory clock: ' + at_wanted_memory + 'MHz');
log_write('autotune', 'Starting clock limit: ' + at_core_min + 'MHz,<break> ending clock limit: ' + at_core_max + 'MHz');
var delta_clock = at_core_max - at_core_min;
var clock_it = delta_clock / CLOCK_STEP;
if (clock_it < 1) clock_it = 1;
var total_time_sec = clock_it * 3 * KT_WAIT_TIME * 0.001;
log_write('autotune', 'Please, be patient,<break> this will take approx. ' + total_time_sec + ' seconds!');
// 1. reset OC first
log_write('autotune', 'Reset OC, set fan to 100%');
at_resetoc(function (data) {
at_call("fanset?id=" + at_device_id + "&level=100", function (data) {
at_step_3_4();
});
});
}
function auto_tune_start_selected() {
detect_selected_devices();
if (selected_devices.length < 1) {
log_write('autotune', 'No devices selected');
return;
}
var str = 'Doing for following devices: ';
for (var i = 0; i < selected_devices.length; ++i)
str += '#' + devices[selected_devices[i]].device_id + ' ';
log_write('autotune', str);
var dev = selected_devices.pop();
auto_tune_start(dev);
}
function auto_tune_finish_now()
{
if (!at_running) return;
at_for_devices = new Array();
log_write('autotune', 'Finishing by setting max core clock limit: ' + at_current_clock);
//at_req_to_end = true;
at_core_max = at_current_clock;pwr
$('#stop_auto_tune').attr('disabled', true);
}
function at_step_3_4() {
// 3. set mem clock to selected one
// 4. set core clock limit to max
//log_write('autotune', 'Set core clock limit to min: ' + at_core_min + 'MHz, mem clock: ' + at_wanted_memory + 'MHz');
at_current_clock = at_core_min;
at_call("setocprofile2?id=" + at_device_id +
"&core=" + at_core_min + "&memory=" + at_wanted_memory,
function (data) {
// need to wait a bit for kt to fill
setTimeout(at_step_5_mess_ktumed_1, KT_WAIT_TIME);
});
}
function at_step_5_inc_core() {
if (at_current_clock >= at_core_max) {
// we have reached the end, cannot decrease more
// just use last best kt umed
//at_step_6();
if (at_results.length == 0) {
at_error(0, 'No results!');
return;
}
// find best clock with lowest kt
var best_speed = at_results[0];
var best_eff = at_results[0];
for (var i = 1; i < at_results.length; ++i) {
if (at_results[i].kt < best_speed.kt)
best_speed = at_results[i];
if (at_results[i].eff > best_eff.eff)
best_eff = at_results[i];
}
at_fastest_core = best_speed.clock;
at_eff_core = best_eff.clock;
log_write('autotune', 'Found best SPEED @ max core clock limit: ' + at_fastest_core +
'MHz (eff: ' + best_speed.eff.toFixed(8) + ' ke/J, heff: ' + best_speed.heff.toFixed(2) + 'kH/J)');
log_write('autotune', 'Found best EFFICIENCY @ max core clock limit: ' + at_eff_core +
'MHz (eff: ' + best_eff.eff.toFixed(8) + ' ke/J, heff: ' + best_eff.heff.toFixed(2) + 'kH/J)');
at_error(0, 'All done!');
return
}
at_current_clock += CLOCK_STEP;
//log_write('autotune', 'Testing core limit: ' + at_current_clock);
at_core_limit(at_current_clock, function (data) {
// wait 2 sec then measure kt.avg
setTimeout(at_step_5_mess_ktumed_1, KT_WAIT_TIME);
});
}
function at_step_5_mess_ktumed_1() {
at_get_ktumed(function (data) {
at_kt_lowest = data;
at_power_sum = devices[at_device_index].gpu_power_usage;
setTimeout(at_step_5_mess_ktumed_2, KT_WAIT_TIME);
});
}
function at_step_5_mess_ktumed_2() {
at_get_ktumed(function (data) {
if (data < at_kt_lowest) at_kt_lowest = data;
at_power_sum += devices[at_device_index].gpu_power_usage;
setTimeout(at_step_5_mess_ktumed, KT_WAIT_TIME);
});
}
function at_step_5_mess_ktumed() {
at_get_ktumed(function (data) {
if (data < at_kt_lowest) at_kt_lowest = data;
at_power_sum += devices[at_device_index].gpu_power_usage;
at_power_sum /= 3;
var oneeff = at_kt_lowest * at_power_sum * 0.000001; // us/ke * J/s * 1/1000000 = J/ke
var eff = 1 / oneeff; // = ke/J (kernel executions per Joule)
var hash_eff = eff * at_hashes_per_ke * 0.001; // =kH/J (khashes per Joule)
log_write('autotune', 'kt.umed: ' + at_kt_lowest + ' us, clock: ' + at_current_clock + 'MHz,<break> pwr: ' +
at_power_sum.toFixed(2) + 'W, eff: ' + eff.toFixed(8) + ' ke/J, heff: ' + hash_eff.toFixed(2) + 'kH/J');
at_results.push({ "kt": at_kt_lowest, "clock": at_current_clock, "power": at_power_sum, "eff": eff, "heff": hash_eff });
at_step_5_inc_core();
});
}