mirror of
https://github.com/unraid/webgui.git
synced 2026-01-14 13:39:58 -06:00
CPU pinning: updated page structure
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
Menu="CPUset:2"
|
||||
Menu="CPUset:3"
|
||||
Title="CPU Isolation"
|
||||
Tag="leaf"
|
||||
---
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Menu="CPUset:1"
|
||||
Menu="CPUset:2"
|
||||
Title="CPU Pinning Docker"
|
||||
Tag="map-marker"
|
||||
---
|
||||
|
||||
@@ -1,201 +1,4 @@
|
||||
Menu="OtherSettings"
|
||||
Title="CPU Pinning VM"
|
||||
Title="CPU Pinning"
|
||||
Type="xmenu"
|
||||
Icon="grid.png"
|
||||
Tag="map-marker"
|
||||
---
|
||||
<?PHP
|
||||
/* Copyright 2005-2018, Lime Technology
|
||||
* Copyright 2012-2018, Bergware International.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
$libvirtd = pgrep('libvirtd')!==false;
|
||||
$dockerd = pgrep('dockerd')!==false;
|
||||
|
||||
$cpus = cpu_list();
|
||||
$total = count($cpus);
|
||||
$spinner = "<tr><td colspan='".($total+2)."'><div class='spinner'></div></td></tr>";
|
||||
$cpuset = implode(';',$cpus);
|
||||
|
||||
function create() {
|
||||
// create the table header. Make multiple rows when CPU cores are many ;)
|
||||
global $total,$cpus;
|
||||
$loop = floor(($total-1)/32)+1;
|
||||
$text = [];
|
||||
for ($c = 0; $c < $loop; $c++) {
|
||||
$max = ($c==$loop-1 ? ($total%32?:32) : 32);
|
||||
for ($n = 0; $n < $max; $n++) {
|
||||
unset($cpu1,$cpu2);
|
||||
list($cpu1, $cpu2) = preg_split('/[,-]/',$cpus[$c*32+$n]);
|
||||
$text[$n] .="$cpu1<br>";
|
||||
if ($cpu2) $text[$n] .= "$cpu2<br>";
|
||||
}
|
||||
}
|
||||
$label = implode('<br>',array_fill(0,$loop,'CPU:'.($cpu2 ? '<br>HT:':'')));
|
||||
echo "<th>$label</th>".implode(array_map(function($t){return "<th>$t</th>";},$text));
|
||||
}
|
||||
?>
|
||||
<style>
|
||||
table.tablesorter tr>th+th{text-align:right;vertical-align:top}
|
||||
table.tablesorter tr>td+td+td{vertical-align:top}
|
||||
table.tablesorter tr>th+th+th,table.tablesorter tr>td+td{text-align:center}
|
||||
table.tablesorter th:first-child,table.tablesorter td:first-child{width:180px;text-align:left}
|
||||
input.flat{margin:0}
|
||||
input.lock{margin:0}
|
||||
</style>
|
||||
<script>
|
||||
String.prototype.stripper = function(){return this.replace(/ |\(|\)|\[|\]/g,'');}
|
||||
|
||||
function apply(form) {
|
||||
// disable buttons
|
||||
$(form).find('input[value="Apply"]').prop('disabled',true);
|
||||
$(form).find('input[value="Reset"]').val('Done').prop('onclick',null).off('click').click(function(){done();});
|
||||
$('input[value="Done"]').prop('disabled',true);
|
||||
var wait = 0;
|
||||
var id = $(form).prop('name');
|
||||
var args = {};
|
||||
args['id'] = id;
|
||||
args['names'] = form.names.value;
|
||||
// get the 'checked' cpus
|
||||
$(form).find('input[type=checkbox]').each(function(){
|
||||
if ($(this).prop('checked')) args[$(this).prop('name')] = 'on';
|
||||
});
|
||||
// show the instant wait message
|
||||
$('#wait-'+id).show();
|
||||
// step 1: prepare the update and report back the changes
|
||||
$.post('/webGui/include/UpdateOne.php',args,function(reply){
|
||||
if (reply.error) {
|
||||
swal({type:'error', title:'Assignment error', text:reply.error},function(){
|
||||
$('#wait-'+id).hide();
|
||||
$(form).find('input[value="Done"]').val('Reset').prop('disabled',false).prop('onclick',null).off('click').click(function(){reset($('form[name="'+id+'"]'));});
|
||||
});
|
||||
} else if (reply.success) {
|
||||
var data = reply.success.split(';');
|
||||
wait = data.length;
|
||||
for (var i=0; i < data.length; i++) {
|
||||
var name = data[i];
|
||||
$('#'+id+'-'+name.stripper()).show('slow');
|
||||
// step 2: apply the changes by updating the vm or container
|
||||
$.post('/webGui/include/UpdateTwo.php',{id:id,name:encodeURI(name)},function(reply){
|
||||
if (reply.error) {
|
||||
// report error and reload table
|
||||
swal({type:'error', title:'Execution error', text:reply.error},function(){
|
||||
$('#wait-'+id).hide();
|
||||
$('input[value="Done"]').prop('disabled',false);
|
||||
reset($('form[name="'+id+'"]'));
|
||||
});
|
||||
} else {
|
||||
$('#'+id+'-'+reply.success.stripper()).hide('slow');
|
||||
// cleanup when all is done
|
||||
if (!--wait) {
|
||||
setTimeout(function(){$('#wait-'+id).hide();},500);
|
||||
$('input[value="Done"]').prop('disabled',false);
|
||||
// isolated cpus, need reboot notice?
|
||||
if (id == 'is') notice();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
$('#wait-'+id).hide();
|
||||
$('input[value="Done"]').prop('disabled',false);
|
||||
if (id == 'is') notice();
|
||||
}
|
||||
});
|
||||
}
|
||||
function vm() {
|
||||
// fetch the current vm assignments
|
||||
$.post('/webGui/include/CPUset.php',{id:'vm',cpus:'<?=$cpuset?>'},function(d){
|
||||
var data = d.split('\0');
|
||||
$('#table-vm').html(data[0]);
|
||||
$('#names-vm').val(data[1]);
|
||||
buttons(document.vm);
|
||||
});
|
||||
}
|
||||
function ct() {
|
||||
// fetch the current container assignments
|
||||
$.post('/webGui/include/CPUset.php',{id:'ct',cpus:'<?=$cpuset?>'},function(d){
|
||||
var data = d.split('\0');
|
||||
$('#table-ct').html(data[0]);
|
||||
$('#names-ct').val(data[1]);
|
||||
buttons(document.ct);
|
||||
});
|
||||
}
|
||||
function is() {
|
||||
// fetch the current isolcpu assignments
|
||||
$.post('/webGui/include/CPUset.php',{id:'is',cpus:'<?=$cpuset?>'},function(d){
|
||||
$('#table-is').html(d);
|
||||
buttons(document.is);
|
||||
});
|
||||
}
|
||||
function notice() {
|
||||
// notice to reboot system after changes
|
||||
$.post('/webGui/include/CPUset.php',{id:'cmd'},function(d){
|
||||
if (d==1) $('div.notice.isol').show(); else $('div.notice.isol').hide();
|
||||
});
|
||||
}
|
||||
function reset(form) {
|
||||
// undo changes without a complete refresh of the page
|
||||
$(form).find('input[value="Apply"]').prop('disabled',true);
|
||||
$(form).find('input[value="Reset"]').val('Done').prop('onclick',null).off('click').click(function(){done();});
|
||||
switch ($(form).prop('name')) {
|
||||
case 'vm': $('#table-vm').html("<?=$spinner?>"); $('div.spinner').html(unraid_logo); vm(); break;
|
||||
case 'ct': $('#table-ct').html("<?=$spinner?>"); $('div.spinner').html(unraid_logo); ct(); break;
|
||||
case 'is': $('#table-is').html("<?=$spinner?>"); $('div.spinner').html(unraid_logo); is(); break;
|
||||
}
|
||||
}
|
||||
function buttons(form) {
|
||||
$(form).find('input[type=checkbox]').each(function(){$(this).on('change',function(){
|
||||
var total = $(form).find('input[type=checkbox]').length;
|
||||
var checked = 'input[name^="'+$(this).prop('name').split(':')[0]+':'+'"]:checked';
|
||||
var cores = $(form).find(checked).length;
|
||||
// vms must have at least one core selected
|
||||
if ($(form).prop('name')=='vm') $(form).find(checked).prop('disabled',cores<2);
|
||||
// isolation may not have all cores selected
|
||||
if ($(form).prop('name')=='is' && $(this).prop('checked')) $(this).prop('checked',cores<total);
|
||||
// we need the Apply and Done buttons react on checkbox changes
|
||||
$(form).find('input[value="Apply"]').prop('disabled',false);
|
||||
$(form).find('input[value="Done"]').val('Reset').prop('onclick',null).off('click').click(function(){reset(form);});
|
||||
});});
|
||||
}
|
||||
$(function(){
|
||||
<?if ($libvirtd):?>
|
||||
vm();
|
||||
<?endif;?>
|
||||
<?if ($dockerd):?>
|
||||
ct();
|
||||
<?endif;?>
|
||||
is();
|
||||
notice();
|
||||
});
|
||||
</script>
|
||||
<?if ($libvirtd):?>
|
||||
<form name="vm">
|
||||
<input type="hidden" name="names" id="names-vm" value="">
|
||||
<table class='tablesorter shift' style='width:auto'>
|
||||
<thead><tr><th><i class="fa fa-list"></i> VM</th><?create()?></tr></thead>
|
||||
<tbody id="table-vm"><?=$spinner?></tbody>
|
||||
</table>
|
||||
<input type="button" value="Apply" onclick="apply(this.form)" disabled><input type="button" value="Done" onclick="done()"><span id="wait-vm" class="red-text" style="display:none"><i class="fa fa-spinner fa-spin"></i> Please wait...</span>
|
||||
</form>
|
||||
<?else:?>
|
||||
<div class="notice">No CPU pinning available. VM service must be started</div>
|
||||
<?endif;?>
|
||||
|
||||
> This page gives a total view of the current CPU pinning assignments for VMs.<br>
|
||||
> It also allows to modify these assignments.
|
||||
>
|
||||
> Running VMs are **stopped first** and restarted after the modification.<br>
|
||||
> Stopped VMs are instantly modified and new assignments become active when the user manually starts the VM.
|
||||
>
|
||||
> When ***Apply*** is pressed a scan is performed to find the changes, subsequently only VMs which have changes are modified in parallel.
|
||||
>
|
||||
> *Important: Please wait until all updates are finished before leaving this page*.
|
||||
Icon="grid.png"
|
||||
199
plugins/dynamix/CPUvms.page
Normal file
199
plugins/dynamix/CPUvms.page
Normal file
@@ -0,0 +1,199 @@
|
||||
Menu="CPUset:1"
|
||||
Title="CPU Pinning VM"
|
||||
Tag="map-marker"
|
||||
---
|
||||
<?PHP
|
||||
/* Copyright 2005-2018, Lime Technology
|
||||
* Copyright 2012-2018, Bergware International.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License version 2,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*/
|
||||
?>
|
||||
<?
|
||||
$libvirtd = pgrep('libvirtd')!==false;
|
||||
$dockerd = pgrep('dockerd')!==false;
|
||||
|
||||
$cpus = cpu_list();
|
||||
$total = count($cpus);
|
||||
$spinner = "<tr><td colspan='".($total+2)."'><div class='spinner'></div></td></tr>";
|
||||
$cpuset = implode(';',$cpus);
|
||||
|
||||
function create() {
|
||||
// create the table header. Make multiple rows when CPU cores are many ;)
|
||||
global $total,$cpus;
|
||||
$loop = floor(($total-1)/32)+1;
|
||||
$text = [];
|
||||
for ($c = 0; $c < $loop; $c++) {
|
||||
$max = ($c==$loop-1 ? ($total%32?:32) : 32);
|
||||
for ($n = 0; $n < $max; $n++) {
|
||||
unset($cpu1,$cpu2);
|
||||
list($cpu1, $cpu2) = preg_split('/[,-]/',$cpus[$c*32+$n]);
|
||||
$text[$n] .="$cpu1<br>";
|
||||
if ($cpu2) $text[$n] .= "$cpu2<br>";
|
||||
}
|
||||
}
|
||||
$label = implode('<br>',array_fill(0,$loop,'CPU:'.($cpu2 ? '<br>HT:':'')));
|
||||
echo "<th>$label</th>".implode(array_map(function($t){return "<th>$t</th>";},$text));
|
||||
}
|
||||
?>
|
||||
<style>
|
||||
table.tablesorter tr>th+th{text-align:right;vertical-align:top}
|
||||
table.tablesorter tr>td+td+td{vertical-align:top}
|
||||
table.tablesorter tr>th+th+th,table.tablesorter tr>td+td{text-align:center}
|
||||
table.tablesorter th:first-child,table.tablesorter td:first-child{width:180px;text-align:left}
|
||||
input.flat{margin:0}
|
||||
input.lock{margin:0}
|
||||
</style>
|
||||
<script>
|
||||
String.prototype.stripper = function(){return this.replace(/ |\(|\)|\[|\]/g,'');}
|
||||
|
||||
function apply(form) {
|
||||
// disable buttons
|
||||
$(form).find('input[value="Apply"]').prop('disabled',true);
|
||||
$(form).find('input[value="Reset"]').val('Done').prop('onclick',null).off('click').click(function(){done();});
|
||||
$('input[value="Done"]').prop('disabled',true);
|
||||
var wait = 0;
|
||||
var id = $(form).prop('name');
|
||||
var args = {};
|
||||
args['id'] = id;
|
||||
args['names'] = form.names.value;
|
||||
// get the 'checked' cpus
|
||||
$(form).find('input[type=checkbox]').each(function(){
|
||||
if ($(this).prop('checked')) args[$(this).prop('name')] = 'on';
|
||||
});
|
||||
// show the instant wait message
|
||||
$('#wait-'+id).show();
|
||||
// step 1: prepare the update and report back the changes
|
||||
$.post('/webGui/include/UpdateOne.php',args,function(reply){
|
||||
if (reply.error) {
|
||||
swal({type:'error', title:'Assignment error', text:reply.error},function(){
|
||||
$('#wait-'+id).hide();
|
||||
$(form).find('input[value="Done"]').val('Reset').prop('disabled',false).prop('onclick',null).off('click').click(function(){reset($('form[name="'+id+'"]'));});
|
||||
});
|
||||
} else if (reply.success) {
|
||||
var data = reply.success.split(';');
|
||||
wait = data.length;
|
||||
for (var i=0; i < data.length; i++) {
|
||||
var name = data[i];
|
||||
$('#'+id+'-'+name.stripper()).show('slow');
|
||||
// step 2: apply the changes by updating the vm or container
|
||||
$.post('/webGui/include/UpdateTwo.php',{id:id,name:encodeURI(name)},function(reply){
|
||||
if (reply.error) {
|
||||
// report error and reload table
|
||||
swal({type:'error', title:'Execution error', text:reply.error},function(){
|
||||
$('#wait-'+id).hide();
|
||||
$('input[value="Done"]').prop('disabled',false);
|
||||
reset($('form[name="'+id+'"]'));
|
||||
});
|
||||
} else {
|
||||
$('#'+id+'-'+reply.success.stripper()).hide('slow');
|
||||
// cleanup when all is done
|
||||
if (!--wait) {
|
||||
setTimeout(function(){$('#wait-'+id).hide();},500);
|
||||
$('input[value="Done"]').prop('disabled',false);
|
||||
// isolated cpus, need reboot notice?
|
||||
if (id == 'is') notice();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
$('#wait-'+id).hide();
|
||||
$('input[value="Done"]').prop('disabled',false);
|
||||
if (id == 'is') notice();
|
||||
}
|
||||
});
|
||||
}
|
||||
function vm() {
|
||||
// fetch the current vm assignments
|
||||
$.post('/webGui/include/CPUset.php',{id:'vm',cpus:'<?=$cpuset?>'},function(d){
|
||||
var data = d.split('\0');
|
||||
$('#table-vm').html(data[0]);
|
||||
$('#names-vm').val(data[1]);
|
||||
buttons(document.vm);
|
||||
});
|
||||
}
|
||||
function ct() {
|
||||
// fetch the current container assignments
|
||||
$.post('/webGui/include/CPUset.php',{id:'ct',cpus:'<?=$cpuset?>'},function(d){
|
||||
var data = d.split('\0');
|
||||
$('#table-ct').html(data[0]);
|
||||
$('#names-ct').val(data[1]);
|
||||
buttons(document.ct);
|
||||
});
|
||||
}
|
||||
function is() {
|
||||
// fetch the current isolcpu assignments
|
||||
$.post('/webGui/include/CPUset.php',{id:'is',cpus:'<?=$cpuset?>'},function(d){
|
||||
$('#table-is').html(d);
|
||||
buttons(document.is);
|
||||
});
|
||||
}
|
||||
function notice() {
|
||||
// notice to reboot system after changes
|
||||
$.post('/webGui/include/CPUset.php',{id:'cmd'},function(d){
|
||||
if (d==1) $('div.notice.isol').show(); else $('div.notice.isol').hide();
|
||||
});
|
||||
}
|
||||
function reset(form) {
|
||||
// undo changes without a complete refresh of the page
|
||||
$(form).find('input[value="Apply"]').prop('disabled',true);
|
||||
$(form).find('input[value="Reset"]').val('Done').prop('onclick',null).off('click').click(function(){done();});
|
||||
switch ($(form).prop('name')) {
|
||||
case 'vm': $('#table-vm').html("<?=$spinner?>"); $('div.spinner').html(unraid_logo); vm(); break;
|
||||
case 'ct': $('#table-ct').html("<?=$spinner?>"); $('div.spinner').html(unraid_logo); ct(); break;
|
||||
case 'is': $('#table-is').html("<?=$spinner?>"); $('div.spinner').html(unraid_logo); is(); break;
|
||||
}
|
||||
}
|
||||
function buttons(form) {
|
||||
$(form).find('input[type=checkbox]').each(function(){$(this).on('change',function(){
|
||||
var total = $(form).find('input[type=checkbox]').length;
|
||||
var checked = 'input[name^="'+$(this).prop('name').split(':')[0]+':'+'"]:checked';
|
||||
var cores = $(form).find(checked).length;
|
||||
// vms must have at least one core selected
|
||||
if ($(form).prop('name')=='vm') $(form).find(checked).prop('disabled',cores<2);
|
||||
// isolation may not have all cores selected
|
||||
if ($(form).prop('name')=='is' && $(this).prop('checked')) $(this).prop('checked',cores<total);
|
||||
// we need the Apply and Done buttons react on checkbox changes
|
||||
$(form).find('input[value="Apply"]').prop('disabled',false);
|
||||
$(form).find('input[value="Done"]').val('Reset').prop('onclick',null).off('click').click(function(){reset(form);});
|
||||
});});
|
||||
}
|
||||
$(function(){
|
||||
<?if ($libvirtd):?>
|
||||
vm();
|
||||
<?endif;?>
|
||||
<?if ($dockerd):?>
|
||||
ct();
|
||||
<?endif;?>
|
||||
is();
|
||||
notice();
|
||||
});
|
||||
</script>
|
||||
<?if ($libvirtd):?>
|
||||
<form name="vm">
|
||||
<input type="hidden" name="names" id="names-vm" value="">
|
||||
<table class='tablesorter shift' style='width:auto'>
|
||||
<thead><tr><th><i class="fa fa-list"></i> VM</th><?create()?></tr></thead>
|
||||
<tbody id="table-vm"><?=$spinner?></tbody>
|
||||
</table>
|
||||
<input type="button" value="Apply" onclick="apply(this.form)" disabled><input type="button" value="Done" onclick="done()"><span id="wait-vm" class="red-text" style="display:none"><i class="fa fa-spinner fa-spin"></i> Please wait...</span>
|
||||
</form>
|
||||
<?else:?>
|
||||
<div class="notice">No CPU pinning available. VM service must be started</div>
|
||||
<?endif;?>
|
||||
|
||||
> This page gives a total view of the current CPU pinning assignments for VMs.<br>
|
||||
> It also allows to modify these assignments.
|
||||
>
|
||||
> Running VMs are **stopped first** and restarted after the modification.<br>
|
||||
> Stopped VMs are instantly modified and new assignments become active when the user manually starts the VM.
|
||||
>
|
||||
> When ***Apply*** is pressed a scan is performed to find the changes, subsequently only VMs which have changes are modified in parallel.
|
||||
>
|
||||
> *Important: Please wait until all updates are finished before leaving this page*.
|
||||
Reference in New Issue
Block a user