🌴 Sync 2026-03-05 23:51:42

This commit is contained in:
github-actions[bot] committed 2026-03-05 23:51:42 +08:00
1 parent 97c049ed0a
commit 0acff03804
14253 files changed
+3893239

No files matched your search

+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 gSpotx2f
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+20
View File
@@ -0,0 +1,20 @@
#
# Copyright (C) 2025 gSpot (https://github.com/gSpotx2f/luci-app-cpu-perf)
#
# This is free software, licensed under the MIT License.
#
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-cpu-perf
PKG_VERSION:=0.6.1
PKG_RELEASE:=1
LUCI_TITLE:=CPU performance information and management for LuCI
LUCI_DEPENDS:=+ucode +ucode-mod-fs
LUCI_PKGARCH:=all
PKG_LICENSE:=MIT
#include $(TOPDIR)/feeds/luci/luci.mk
include $(TOPDIR)/feeds/luci/luci.mk
# call BuildPackage - OpenWrt buildroot signature
+47
View File
@@ -0,0 +1,47 @@
# luci-app-cpu-perf
CPU performance management for LuCI (OpenWrt webUI).
OpenWrt >= 22.03.
**Dependences:** ucode, ucode-mod-fs.
## Installation notes
**OpenWrt >= 25.12:**
wget --no-check-certificate -O /tmp/luci-app-cpu-perf-0.6.1-r1.apk https://github.com/gSpotx2f/packages-openwrt/raw/master/25.12/luci-app-cpu-perf-0.6.1-r1.apk
apk --allow-untrusted add /tmp/luci-app-cpu-perf-0.6.1-r1.apk
rm /tmp/luci-app-cpu-perf-0.6.1-r1.apk
service rpcd restart
service cpu-perf start
i18n-ru:
wget --no-check-certificate -O /tmp/luci-i18n-cpu-perf-ru-0.6.1-r1.apk https://github.com/gSpotx2f/packages-openwrt/raw/master/25.12/luci-i18n-cpu-perf-ru-0.6.1-r1.apk
apk --allow-untrusted add /tmp/luci-i18n-cpu-perf-ru-0.6.1-r1.apk
rm /tmp/luci-i18n-cpu-perf-ru-0.6.1-r1.apk
**OpenWrt <= 24.10:**
wget --no-check-certificate -O /tmp/luci-app-cpu-perf_0.6.1-r1_all.ipk https://github.com/gSpotx2f/packages-openwrt/raw/master/24.10/luci-app-cpu-perf_0.6.1-r1_all.ipk
opkg install /tmp/luci-app-cpu-perf_0.6.1-r1_all.ipk
rm /tmp/luci-app-cpu-perf_0.6.1-r1_all.ipk
service rpcd restart
service cpu-perf start
i18n-ru:
wget --no-check-certificate -O /tmp/luci-i18n-cpu-perf-ru_0.6.1-r1_all.ipk https://github.com/gSpotx2f/packages-openwrt/raw/master/24.10/luci-i18n-cpu-perf-ru_0.6.1-r1_all.ipk
opkg install /tmp/luci-i18n-cpu-perf-ru_0.6.1-r1_all.ipk
rm /tmp/luci-i18n-cpu-perf-ru_0.6.1-r1_all.ipk
## Screenshots:
![](https://github.com/gSpotx2f/luci-app-cpu-perf/blob/master/screenshots/00.jpg)
![](https://github.com/gSpotx2f/luci-app-cpu-perf/blob/master/screenshots/01.jpg)
![](https://github.com/gSpotx2f/luci-app-cpu-perf/blob/master/screenshots/02.jpg)
## Related LuCI applications:
CPU load: [https://github.com/gSpotx2f/luci-app-cpu-status](https://github.com/gSpotx2f/luci-app-cpu-status), [https://github.com/gSpotx2f/luci-app-cpu-status-mini](https://github.com/gSpotx2f/luci-app-cpu-status-mini).
Temperature: [https://github.com/gSpotx2f/luci-app-temp-status](https://github.com/gSpotx2f/luci-app-temp-status).
@@ -0,0 +1,706 @@
'use strict';
'require form';
'require poll';
'require rpc';
'require uci';
'require ui';
'require view';
const btnStyleEnabled = 'btn cbi-button-save';
const btnStyleDisabled = 'btn cbi-button-reset';
return view.extend({
appName : 'cpu-perf',
initStatus: null,
callCpuPerf: rpc.declare({
object: 'luci.cpu-perf',
method: 'getCpuPerf',
expect: { '': {} }
}),
callInitStatus: rpc.declare({
object: 'luci',
method: 'getInitList',
params: [ 'name' ],
expect: { '': {} }
}),
callInitAction: rpc.declare({
object: 'luci',
method: 'setInitAction',
params: [ 'name', 'action' ],
expect: { result: false }
}),
getInitStatus() {
return this.callInitStatus(this.appName).then(res => {
if(res) {
return res[this.appName].enabled;
} else {
throw _('Command failed');
}
}).catch(e => {
ui.addNotification(null,
E('p', _('Failed to get %s init status: %s').format(this.appName, e)));
});
},
handleServiceAction(action) {
return this.callInitAction(this.appName, action).then(success => {
if(!success) {
throw _('Command failed');
};
return true;
}).catch(e => {
ui.addNotification(null,
E('p', _('Service action failed "%s %s": %s').format(this.appName, action, e)));
});
},
serviceRestart(ev) {
poll.stop();
return this.handleServiceAction('restart').then(() => {
poll.start();
});
},
freqFormat(freq) {
if(!freq) {
return '-';
};
return (freq >= 1000000) ?
(freq / 1000000) + ' ' + _('GHz')
:
(freq / 1000) + ' ' + _('MHz');
},
updateCpuPerfData() {
this.callCpuPerf().then((data) => {
if(data.cpus) {
for(let i of Object.values(data.cpus)) {
let policy = data.freqPolicies[String(i.policy)];
if(policy) {
document.getElementById('cpu' + i.number + 'number').textContent =
_('CPU') + ' ' + i.number;
document.getElementById('cpu' + i.number + 'curFreq').textContent =
(policy.sCurFreq) ?
this.freqFormat(policy.sCurFreq)
:
this.freqFormat(policy.curFreq);
document.getElementById('cpu' + i.number + 'minFreq').textContent =
(policy.sMinFreq) ?
this.freqFormat(policy.sMinFreq)
:
this.freqFormat(policy.minFreq)
document.getElementById('cpu' + i.number + 'maxFreq').textContent =
(policy.sMaxFreq) ?
this.freqFormat(policy.sMaxFreq)
:
this.freqFormat(policy.maxFreq);
document.getElementById('cpu' + i.number + 'governor').textContent =
policy.governor || '-';
};
};
};
if(data.ondemand) {
document.getElementById('OdUpThreshold').textContent =
data.ondemand.upThreshold || '-';
document.getElementById('OdIgnNiceLoad').textContent =
(data.ondemand.ignNiceLoad !== undefined) ?
data.ondemand.ignNiceLoad : '-';
document.getElementById('OdSmpDownFactor').textContent =
data.ondemand.smpDownFactor || '-';
document.getElementById('OdPowersaveBias').textContent =
(data.ondemand.powersaveBias !== undefined) ?
data.ondemand.powersaveBias : '-';
};
if(data.conservative) {
document.getElementById('CoFreqStep').textContent =
(data.conservative.freqStep !== undefined) ?
data.conservative.freqStep : '-';
document.getElementById('CoDownThreshold').textContent =
data.conservative.downThreshold || '-';
document.getElementById('CoSmpDownFactor').textContent =
data.conservative.smpDownFactor || '-';
};
if(data.eas) {
document.getElementById('EasSchedEnergyAware').textContent =
(data.eas.schedEnergyAware !== undefined) ?
data.eas.schedEnergyAware : '-';
};
if(data.pcieAspm) {
document.getElementById('PaCurrentPolicy').textContent =
data.pcieAspm.currentPolicy || '-';
};
}).catch(e => {});
},
CBIBlockPerf: form.Value.extend({
__name__ : 'CBI.BlockPerf',
__init__(map, section, ctx, perfData) {
this.map = map;
this.section = section;
this.ctx = ctx;
this.perfData = perfData;
this.optional = true;
this.rmempty = true;
},
renderWidget(section_id, option_index, cfgvalue) {
let cpuTableTitles = [
_('CPU'),
_('Current frequency'),
_('Minimum frequency'),
_('Maximum frequency'),
_('Scaling governor'),
];
let cpuTable = E('table', { 'class': 'table' },
E('tr', { 'class': 'tr table-titles' }, [
E('th', { 'class': 'th left' }, cpuTableTitles[0]),
E('th', { 'class': 'th left' }, cpuTableTitles[1]),
E('th', { 'class': 'th left' }, cpuTableTitles[2]),
E('th', { 'class': 'th left' }, cpuTableTitles[3]),
E('th', { 'class': 'th left' }, cpuTableTitles[4]),
])
);
let ondemandTable, conservativeTable, easTable, pcieAspmTable;
if(this.perfData) {
if(this.perfData.cpus) {
for(let i of Object.values(this.perfData.cpus)) {
let policy = this.perfData.freqPolicies[String(i.policy)];
if(policy) {
cpuTable.append(
E('tr', { 'class': 'tr' }, [
E('td', {
'id': 'cpu' + i.number + 'number',
'class': 'td left',
'data-title': cpuTableTitles[0],
}, _('CPU') + ' ' + i.number),
E('td', {
'id': 'cpu' + i.number + 'curFreq',
'class': 'td left',
'data-title': cpuTableTitles[1],
}, (policy.sCurFreq) ?
this.ctx.freqFormat(policy.sCurFreq)
:
this.ctx.freqFormat(policy.curFreq)
),
E('td', {
'id': 'cpu' + i.number + 'minFreq',
'class': 'td left',
'data-title': cpuTableTitles[2],
}, (policy.sMinFreq) ?
this.ctx.freqFormat(policy.sMinFreq)
:
this.ctx.freqFormat(policy.minFreq)
),
E('td', {
'id': 'cpu' + i.number + 'maxFreq',
'class': 'td left',
'data-title': cpuTableTitles[3],
}, (policy.sMaxFreq) ?
this.ctx.freqFormat(policy.sMaxFreq)
:
this.ctx.freqFormat(policy.maxFreq)
),
E('td', {
'id': 'cpu' + i.number + 'governor',
'class': 'td left',
'data-title': cpuTableTitles[4],
}, policy.governor || '-'),
])
);
};
};
};
if(this.perfData.ondemand) {
ondemandTable = E('table', { 'class': 'table' }, [
E('tr', { 'class': 'tr' }, [
E('td', { 'class': 'td left', 'style':'width:33%' }, "up_threshold"),
E('td', { 'id': 'OdUpThreshold', 'class': 'td left' },
this.perfData.ondemand.upThreshold || '-'),
]),
E('tr', { 'class': 'tr' }, [
E('td', { 'class': 'td left' }, "ignore_nice_load"),
E('td', { 'id': 'OdIgnNiceLoad', 'class': 'td left' },
(this.perfData.ondemand.ignNiceLoad !== undefined) ?
this.perfData.ondemand.ignNiceLoad : '-'),
]),
E('tr', { 'class': 'tr' }, [
E('td', { 'class': 'td left' }, "sampling_down_factor"),
E('td', { 'id': 'OdSmpDownFactor', 'class': 'td left' },
this.perfData.ondemand.smpDownFactor || '-'),
]),
E('tr', { 'class': 'tr' }, [
E('td', { 'class': 'td left' }, "powersave_bias"),
E('td', { 'id': 'OdPowersaveBias', 'class': 'td left' },
(this.perfData.ondemand.powersaveBias !== undefined) ?
this.perfData.ondemand.powersaveBias : '-'),
]),
]);
};
if(this.perfData.conservative) {
conservativeTable = E('table', { 'class': 'table' }, [
E('tr', { 'class': 'tr' }, [
E('td', { 'class': 'td left', 'style':'width:33%' }, "freq_step"),
E('td', { 'id': 'CoFreqStep', 'class': 'td left' },
(this.perfData.conservative.freqStep !== undefined) ?
this.perfData.conservative.freqStep : '-'),
]),
E('tr', { 'class': 'tr' }, [
E('td', { 'class': 'td left' }, "down_threshold"),
E('td', { 'id': 'CoDownThreshold', 'class': 'td left' },
this.perfData.conservative.downThreshold || '-'),
]),
E('tr', { 'class': 'tr' }, [
E('td', { 'class': 'td left' }, "sampling_down_factor"),
E('td', { 'id': 'CoSmpDownFactor', 'class': 'td left' },
this.perfData.conservative.smpDownFactor || '-'),
]),
]);
};
if(this.perfData.pcieAspm) {
pcieAspmTable = E('table', { 'class': 'table' },
E('tr', { 'class': 'tr' }, [
E('td', { 'class': 'td left', 'style':'width:33%' }, "policy"),
E('td', { 'id': 'PaCurrentPolicy', 'class': 'td left' },
this.perfData.pcieAspm.currentPolicy || '-'),
])
);
};
if(this.perfData.eas) {
easTable = E('table', { 'class': 'table' },
E('tr', { 'class': 'tr' }, [
E('td', { 'class': 'td left', 'style':'width:33%' }, "sched_energy_aware"),
E('td', { 'id': 'EasSchedEnergyAware', 'class': 'td left' },
(this.perfData.eas.schedEnergyAware !== undefined) ?
this.perfData.eas.schedEnergyAware : '-'),
])
);
};
};
if(cpuTable.childNodes.length === 1){
cpuTable.append(
E('tr', { 'class': 'tr placeholder' },
E('td', { 'class': 'td' },
E('em', {}, _('No performance data...'))
)
)
);
};
let tables = [ cpuTable ];
if(ondemandTable) {
tables.push(
E('h3', {}, _("Ondemand governor")),
ondemandTable
);
};
if(conservativeTable) {
tables.push(
E('h3', {}, _("Conservative governor")),
conservativeTable,
);
};
if(easTable) {
tables.push(
E('h3', {}, _("EAS")),
easTable,
);
};
if(pcieAspmTable) {
tables.push(
E('h3', {}, _("PCIe ASPM")),
pcieAspmTable,
);
};
return E(tables);
},
}),
CBIBlockInitButton: form.Value.extend({
__name__ : 'CBI.BlockInitButton',
__init__(map, section, ctx) {
this.map = map;
this.section = section;
this.ctx = ctx;
this.optional = true;
this.rmempty = true;
},
renderWidget(section_id, option_index, cfgvalue) {
this.ctx.initButton = E('button', {
'class': (!this.ctx.initStatus) ? btnStyleDisabled : btnStyleEnabled,
'click': ui.createHandlerFn(this, () => {
return this.ctx.handleServiceAction(
(!this.ctx.initStatus) ? 'enable' : 'disable'
).then(success => {
if(!success) {
return;
};
if(!this.ctx.initStatus) {
this.ctx.initButton.textContent = _('Enabled');
this.ctx.initButton.className = btnStyleEnabled;
this.ctx.initStatus = true;
} else {
this.ctx.initButton.textContent = _('Disabled');
this.ctx.initButton.className = btnStyleDisabled;
this.ctx.initStatus = false;
};
});
}),
}, (!this.ctx.initStatus) ? _('Disabled') : _('Enabled'));
return E([
E('label', { 'class': 'cbi-value-title', 'for': 'initButton' },
_('Run at startup')
),
E('div', { 'class': 'cbi-value-field' }, [
E('div', {}, this.ctx.initButton),
E('input', {
'id' : 'initButton',
'type': 'hidden',
}),
]),
]);
},
}),
freqValidate(section_id, value, slave_elem, max=false) {
let slaveValue = slave_elem.formvalue(section_id);
if(value === '' || slaveValue === '') {
return true;
};
value = Number(value);
slaveValue = Number(slaveValue);
if((max && value >= slaveValue) || (!max && value <= slaveValue)) {
return true;
};
return `${_('Frequency value must not be')} ${max ? _('lower') : _('higher')} ${_('than the')} "${slave_elem.title}"!`;
},
load() {
return Promise.all([
this.getInitStatus(),
this.callCpuPerf(),
uci.load(this.appName),
]).catch(e => {
ui.addNotification(null, E('p', _('An error has occurred') + ': %s'.format(e.message)));
});
},
render(data) {
if(!data) {
return;
};
this.initStatus = data[0];
let cpuPerfDataArray = data[1];
let freqPolicyArray = cpuPerfDataArray.freqPolicies || {};
let pcieAspmPolicies;
if(cpuPerfDataArray.pcieAspm) {
pcieAspmPolicies = cpuPerfDataArray.pcieAspm.availPolicies;
};
let easValue;
if(cpuPerfDataArray.eas) {
easValue = cpuPerfDataArray.eas.schedEnergyAware;
};
let s, o, ss;
let m = new form.Map(this.appName,
_('CPU Performance'),
_('CPU performance management.'));
s = m.section(form.NamedSection, 'config', 'main');
/* Status */
s.tab('values', _('Current values'));
o = s.taboption('values', this.CBIBlockPerf, this, cpuPerfDataArray);
/* Performance managment */
s.tab('performance', _('Performance managment'));
// enabled
o = s.taboption('performance', form.Flag, 'enabled',
_('Enable'));
o.rmempty = false;
// init button
o = s.taboption('performance', this.CBIBlockInitButton, this);
/* CPU frequency policies */
let sections = uci.sections(this.appName, 'cpu_freq_policy');
if(sections.length == 0) {
o = s.taboption('performance', form.DummyValue, '_dummy');
o.rawhtml = true;
o.default = '<label class="cbi-value-title"></label><div class="cbi-value-field"><em>' +
_('CPU performance scaling is not available...') +
'</em></div>';
} else {
for(let section of sections) {
let sectionName = section['.name'];
let policyNum = Number(sectionName.replace('policy', ''));
let cpuString = '';
let cpus = freqPolicyArray[policyNum].cpu;
if(cpus && cpus.length > 0) {
let cpuArr = [];
cpus.forEach(e => {
cpuArr.push(_('CPU') + ' ' + e);
});
if(cpuArr.length > 0) {
cpuString = cpuArr.join(', ');
};
};
let o;
o = s.taboption('performance', form.SectionValue,
'cpu_freq_policy', form.NamedSection, sectionName, 'cpu_freq_policy');
ss = o.subsection;
ss.title = _('Policy') + ' ' + policyNum + ' ( ' + cpuString + ' )';
if(freqPolicyArray[policyNum]) {
if(freqPolicyArray[policyNum].sAvailGovernors &&
freqPolicyArray[policyNum].sAvailGovernors.length > 0) {
// scaling_governor
o = ss.option(form.ListValue,
'scaling_governor', _('Scaling governor'),
_('Scaling governors implement algorithms to estimate the required CPU capacity.')
);
o.rmempty = true;
o.optional = true;
freqPolicyArray[policyNum].sAvailGovernors.forEach(e => o.value(e));
};
if(freqPolicyArray[policyNum].sMinFreq && freqPolicyArray[policyNum].sMaxFreq &&
freqPolicyArray[policyNum].minFreq && freqPolicyArray[policyNum].maxFreq) {
let minFreq, maxFreq;
if(freqPolicyArray[policyNum].sAvailFreqs &&
freqPolicyArray[policyNum].sAvailFreqs.length > 0) {
let availFreqs = freqPolicyArray[policyNum].sAvailFreqs.map(e =>
[ e, this.freqFormat(e) ]
);
// scaling_min_freq
minFreq = ss.option(form.ListValue,
'scaling_min_freq', _('Minimum scaling frequency'),
_('Minimum frequency the CPU is allowed to be running.') +
' (' + _('default value:') + ' <code>' +
this.freqFormat(freqPolicyArray[policyNum].minFreq) + '</code>).'
);
minFreq.rmempty = true;
minFreq.optional = true;
// scaling_max_freq
maxFreq = ss.option(form.ListValue,
'scaling_max_freq', _('Maximum scaling frequency'),
_('Maximum frequency the CPU is allowed to be running.') +
' (' + _('default value:') + ' <code>' +
this.freqFormat(freqPolicyArray[policyNum].maxFreq) + '</code>).'
);
maxFreq.rmempty = true;
maxFreq.optional = true;
availFreqs.forEach(e => {
minFreq.value(e[0], e[1]);
maxFreq.value(e[0], e[1]);
});
} else {
// scaling_min_freq
minFreq = ss.option(form.Value,
'scaling_min_freq', `${_('Minimum scaling frequency')} (${_('KHz')})`,
_('Minimum frequency the CPU is allowed to be running.') +
' (' + _('default value:') + ' <code>' +
freqPolicyArray[policyNum].minFreq + '</code>).'
);
minFreq.rmempty = true;
minFreq.optional = true;
minFreq.datatype = `and(integer,range(${freqPolicyArray[policyNum].minFreq},${freqPolicyArray[policyNum].maxFreq}))`;
minFreq.placeholder = `${freqPolicyArray[policyNum].minFreq}-${freqPolicyArray[policyNum].maxFreq} ${_('KHz')}`;
// scaling_max_freq
maxFreq = ss.option(form.Value,
'scaling_max_freq', `${_('Maximum scaling frequency')} (${_('KHz')})`,
_('Maximum frequency the CPU is allowed to be running.') +
' (' + _('default value:') + ' <code>' +
freqPolicyArray[policyNum].maxFreq + '</code>).'
);
maxFreq.rmempty = true;
maxFreq.optional = true;
maxFreq.datatype = `and(integer,range(${freqPolicyArray[policyNum].minFreq},${freqPolicyArray[policyNum].maxFreq}))`;
maxFreq.placeholder = `${freqPolicyArray[policyNum].minFreq}-${freqPolicyArray[policyNum].maxFreq} ${_('KHz')}`;
};
minFreq.validate = L.bind(
function(section_id, value) {
return this.freqValidate(section_id, value, maxFreq, false);
},
this
);
maxFreq.validate = L.bind(
function(section_id, value) {
return this.freqValidate(section_id, value, minFreq, true);
},
this
);
};
};
if(!freqPolicyArray[policyNum] ||
!(freqPolicyArray[policyNum].sAvailGovernors &&
freqPolicyArray[policyNum].sAvailGovernors.length > 0) &&
!(freqPolicyArray[policyNum].sMinFreq && freqPolicyArray[policyNum].sMaxFreq &&
freqPolicyArray[policyNum].minFreq && freqPolicyArray[policyNum].maxFreq)) {
o = ss.option(form.DummyValue, '_dummy');
o.rawhtml = true;
o.default = '<label class="cbi-value-title"></label><div class="cbi-value-field"><em>' +
_('Performance scaling is not available for this policy...') +
'</em></div>';
};
};
};
/* Ondemand governor */
o = s.taboption('performance', form.SectionValue,
'ondemand', form.NamedSection, 'ondemand', 'governor');
ss = o.subsection;
ss.title = _("Ondemand governor");
// up_threshold
o = ss.option(form.Value,
'up_threshold', 'up_threshold',
_('If the estimated CPU load is above this value (in percent), the governor will set the frequency to the maximum value.')
);
o.rmempty = true;
o.optional = true;
o.placeholder = '1-100';
o.datatype = 'and(integer,range(1,100))';
// ignore_nice_load
o = ss.option(form.Flag,
'ignore_nice_load', 'ignore_nice_load',
_('If checked, it will cause the CPU load estimation code to treat the CPU time spent on executing tasks with "nice" levels greater than 0 as CPU idle time.')
);
o.rmempty = true;
o.optional = true;
// sampling_down_factor
o = ss.option(form.Value,
'sampling_down_factor', 'sampling_down_factor',
_('Frequency decrease deferral factor.')
);
o.rmempty = true;
o.optional = true;
o.placeholder = '1-100';
o.datatype = 'and(integer,range(1,100))';
// powersave_bias
o = ss.option(form.Value,
'powersave_bias', 'powersave_bias',
_('Reduction factor to apply to the original frequency target of the governor.')
);
o.rmempty = true;
o.optional = true;
o.placeholder = '0-1000';
o.datatype = 'and(integer,range(0,1000))';
/* Conservative governor */
o = s.taboption('performance', form.SectionValue,
'conservative', form.NamedSection, 'conservative', 'governor');
ss = o.subsection;
ss.title = _("Conservative governor");
// freq_step
o = ss.option(form.Value,
'freq_step', 'freq_step',
_('Frequency step in percent of the maximum frequency the governor is allowed to set.')
);
o.rmempty = true;
o.optional = true;
o.placeholder = '1-100';
o.datatype = 'and(integer,range(1,100))';
// down_threshold
o = ss.option(form.Value,
'down_threshold', 'down_threshold',
_('Threshold value (in percent) used to determine the frequency change direction.')
);
o.rmempty = true;
o.optional = true;
o.placeholder = '1-100';
o.datatype = 'and(integer,range(1,100))';
// sampling_down_factor
o = ss.option(form.Value,
'sampling_down_factor', 'sampling_down_factor',
_('Frequency decrease deferral factor.')
);
o.rmempty = true;
o.optional = true;
o.placeholder = '1-10';
o.datatype = 'and(integer,range(1,10))';
/* EAS */
if(easValue !== undefined ) {
o = s.taboption('performance', form.SectionValue,
'eas', form.NamedSection, 'eas', 'kernel');
ss = o.subsection;
ss.title = _("EAS");
// sched_energy_aware
o = ss.option(form.Flag, 'sched_energy_aware', 'sched_energy_aware',
_('Enable/disable Energy Aware Scheduling (EAS).')
);
o.rmempty = false;
o.default = '1';
};
/* PCIe ASPM */
if(pcieAspmPolicies && pcieAspmPolicies.length > 0) {
o = s.taboption('performance', form.SectionValue,
'pcie_aspm', form.NamedSection, 'pcie_aspm', 'module');
ss = o.subsection;
ss.title = _("PCIe ASPM");
// policy
o = ss.option(form.ListValue, 'policy', 'policy',
_('Active-State Power Management (ASPM) policy for PCIe links, which saves power by putting unused PCIe links into a low-power state.')
);
o.rmempty = true;
o.optional = true;
pcieAspmPolicies.forEach(e => o.value(e));
};
let mapPromise = m.render();
mapPromise.then(node => {
node.classList.add('fade-in');
poll.add(L.bind(this.updateCpuPerfData, this));
});
return mapPromise;
},
handleSaveApply(ev, mode) {
return this.handleSave(ev).then(() => {
ui.changes.apply(mode == '0');
window.setTimeout(() => this.serviceRestart(), 3000);
});
},
});
@@ -0,0 +1,95 @@
'use strict';
'require baseclass';
'require rpc';
document.head.append(E('style', {'type': 'text/css'},
`
.cpu-perf-area {
margin-bottom: 1em;
}
.cpu-perf-label {
display: inline-block;
word-wrap: break-word;
padding: 4px 8px;
width: 8em;
}
.cpu-perf-label-title {
display: block;
word-wrap: break-word;
width: 100%;
font-weight: bold;
}
.cpu-perf-label-value {
display: block;
word-wrap: break-word;
width: 100%;
}
.cpu-perf-empty-area {
width: 100%;
text-align: center;
}
`))
return baseclass.extend({
title : _('CPU Frequency'),
callCpuPerf: rpc.declare({
object: 'luci.cpu-perf',
method: 'getCpuPerf',
expect: { '': {} }
}),
freqFormat(freq) {
if(!freq) {
return '-';
};
return (freq >= 1e6) ?
Number((freq / 1e6).toFixed(3)) + ' ' + _('GHz')
:
Number((freq / 1e3).toFixed(3)) + ' ' + _('MHz');
},
load() {
return L.resolveDefault(this.callCpuPerf(), null);
},
render(data) {
if(!data) {
return;
};
let cpuFreqArea = E('div', { 'class': 'cpu-perf-area' });
if(data.cpus && data.freqPolicies) {
for(let i of Object.values(data.cpus)) {
let policy = data.freqPolicies[String(i.policy)];
if(policy) {
cpuFreqArea.append(
E('div', { 'class': 'cpu-perf-label' }, [
E('span', { 'class': 'cpu-perf-label-title' },
_('CPU') + ' ' + i.number + ':'
),
E('span', { 'class': 'cpu-perf-label-value' },
(policy.sCurFreq) ?
this.freqFormat(policy.sCurFreq)
:
this.freqFormat(policy.curFreq)
),
])
);
};
};
};
if(cpuFreqArea.childNodes.length == 0){
cpuFreqArea.append(
E('div', { 'class': 'cpu-perf-empty-area' },
E('em', {}, _('No CPU frequency data available...'))
)
);
};
return cpuFreqArea;
},
});
+151
View File
@@ -0,0 +1,151 @@
msgid ""
msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Project-Id-Version: \n"
"POT-Creation-Date: \n"
"PO-Revision-Date: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 3.0\n"
"Last-Translator: \n"
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : 2);\n"
"Language: ru\n"
msgid "Active-State Power Management (ASPM) policy for PCIe links, which saves power by putting unused PCIe links into a low-power state."
msgstr "Политика управления питанием в активном состоянии (ASPM) для каналов PCIe, которая экономит электроэнергию, переводя неиспользуемые каналы PCIe в состояние пониженного энергопотребления."
msgid "An error has occurred"
msgstr "Произошла ошибка"
msgid "CPU"
msgstr "ЦПУ"
msgid "CPU Frequency"
msgstr "Частота ЦПУ"
msgid "CPU Performance"
msgstr "Производительность ЦПУ"
msgid "CPU performance management."
msgstr "Управление производительностью процессора."
msgid "CPU performance scaling is not available..."
msgstr "Масштабирование производительности ЦПУ недоступно..."
msgid "Command failed"
msgstr "Команда не выполнена"
msgid "Conservative governor"
msgstr "Регулятор conservative"
msgid "Current frequency"
msgstr "Текущая частота"
msgid "Current values"
msgstr "Текущие значения"
msgid "Disabled"
msgstr "Отключено"
msgid "Enable"
msgstr "Включить"
msgid "Enabled"
msgstr "Включено"
msgid "Enable/disable Energy Aware Scheduling (EAS)."
msgstr "Включить/отключить Energy Aware Scheduling (EAS)."
msgid "Failed to get %s init status: %s"
msgstr "Не удалось получить статус инициализации %s: %s"
msgid "Frequency decrease deferral factor."
msgstr "Коэффициент отсрочки уменьшения частоты."
msgid "Frequency step in percent of the maximum frequency the governor is allowed to set."
msgstr "Шаг частоты в процентах от максимальной частоты, которую может установить регулятор."
msgid "Frequency value must not be"
msgstr "Значение частоты не должно быть"
msgid "GHz"
msgstr "ГГц"
msgid "If checked, it will cause the CPU load estimation code to treat the CPU time spent on executing tasks with \"nice\" levels greater than 0 as CPU idle time."
msgstr "Если включено, код оценки загрузки ЦПУ будет рассматривать время ЦПУ, затрачиваемое на выполнение задач с уровнями \"nice\" выше 0, как время простоя ЦПУ."
msgid "If the estimated CPU load is above this value (in percent), the governor will set the frequency to the maximum value."
msgstr "Если расчетная загрузка ЦПУ выше этого значения (в процентах), регулятор установит максимальное значение частоты."
msgid "KHz"
msgstr "КГц"
msgid "MHz"
msgstr "МГц"
msgid "Maximum frequency"
msgstr "Максимальная частота"
msgid "Maximum frequency the CPU is allowed to be running."
msgstr "Максимальная частота, на которой может работать ЦПУ."
msgid "Maximum scaling frequency"
msgstr "Максимальное масштабирование частоты"
msgid "Minimum frequency"
msgstr "Минимальная частота"
msgid "Minimum frequency the CPU is allowed to be running."
msgstr "Минимальная частота, на которой может работать ЦПУ."
msgid "Minimum scaling frequency"
msgstr "Минимальное масштабирование частоты"
msgid "No CPU frequency data available..."
msgstr "Нет данных о данных о частоте процессора..."
msgid "No performance data..."
msgstr "Нет данных о производительности..."
msgid "Ondemand governor"
msgstr "Регулятор ondemand"
msgid "Performance managment"
msgstr "Управление производительностью"
msgid "Performance scaling is not available for this policy..."
msgstr "Масштабирование производительности недоступно для этой политики..."
msgid "Policy"
msgstr "Политика"
msgid "Reduction factor to apply to the original frequency target of the governor."
msgstr "Коэффициент снижения, применяемый к исходной целевой частоте регулятора."
msgid "Run at startup"
msgstr "Запуск при старте системы"
msgid "Scaling governor"
msgstr "Регулятор масштабирования"
msgid "Scaling governors implement algorithms to estimate the required CPU capacity."
msgstr "Регуляторы масштабирования реализуют алгоритмы для оценки требуемой мощности ЦПУ."
msgid "Service action failed \"%s %s\": %s"
msgstr "Не удалось выполнить действие службы \"%s %s\": %s"
msgid "Threshold value (in percent) used to determine the frequency change direction."
msgstr "Пороговое значение (в процентах), используемое для определения направления изменения частоты."
msgid "default value:"
msgstr "стандартное значение:"
msgid "higher"
msgstr "выше"
msgid "lower"
msgstr "ниже"
msgid "than the"
msgstr "чем"
+140
View File
@@ -0,0 +1,140 @@
msgid ""
msgstr "Content-Type: text/plain; charset=UTF-8"
msgid "Active-State Power Management (ASPM) policy for PCIe links, which saves power by putting unused PCIe links into a low-power state."
msgstr ""
msgid "An error has occurred"
msgstr ""
msgid "CPU"
msgstr ""
msgid "CPU Frequency"
msgstr ""
msgid "CPU Performance"
msgstr ""
msgid "CPU performance management."
msgstr ""
msgid "CPU performance scaling is not available..."
msgstr ""
msgid "Command failed"
msgstr ""
msgid "Conservative governor"
msgstr ""
msgid "Current frequency"
msgstr ""
msgid "Current values"
msgstr ""
msgid "Disabled"
msgstr ""
msgid "Enable"
msgstr ""
msgid "Enabled"
msgstr ""
msgid "Enable/disable Energy Aware Scheduling (EAS)."
msgstr ""
msgid "Failed to get %s init status: %s"
msgstr ""
msgid "Frequency decrease deferral factor."
msgstr ""
msgid "Frequency step in percent of the maximum frequency the governor is allowed to set."
msgstr ""
msgid "Frequency value must not be"
msgstr ""
msgid "GHz"
msgstr ""
msgid "If checked, it will cause the CPU load estimation code to treat the CPU time spent on executing tasks with \"nice\" levels greater than 0 as CPU idle time."
msgstr ""
msgid "If the estimated CPU load is above this value (in percent), the governor will set the frequency to the maximum value."
msgstr ""
msgid "KHz"
msgstr ""
msgid "MHz"
msgstr ""
msgid "Maximum frequency"
msgstr ""
msgid "Maximum frequency the CPU is allowed to be running."
msgstr ""
msgid "Maximum scaling frequency"
msgstr ""
msgid "Minimum frequency"
msgstr ""
msgid "Minimum frequency the CPU is allowed to be running."
msgstr ""
msgid "Minimum scaling frequency"
msgstr ""
msgid "No CPU frequency data available..."
msgstr ""
msgid "No performance data..."
msgstr ""
msgid "Ondemand governor"
msgstr ""
msgid "Performance managment"
msgstr ""
msgid "Performance scaling is not available for this policy..."
msgstr ""
msgid "Policy"
msgstr ""
msgid "Reduction factor to apply to the original frequency target of the governor."
msgstr ""
msgid "Run at startup"
msgstr ""
msgid "Scaling governor"
msgstr ""
msgid "Scaling governors implement algorithms to estimate the required CPU capacity."
msgstr ""
msgid "Service action failed \"%s %s\": %s"
msgstr ""
msgid "Threshold value (in percent) used to determine the frequency change direction."
msgstr ""
msgid "default value:"
msgstr ""
msgid "higher"
msgstr ""
msgid "lower"
msgstr ""
msgid "than the"
msgstr ""
+1
View File
@@ -0,0 +1 @@
zh_Hans
+125
View File
@@ -0,0 +1,125 @@
msgid ""
msgstr "Content-Type: text/plain; charset=UTF-8"
msgid "An error has occurred"
msgstr "发生错误"
msgid "CPU"
msgstr "CPU"
msgid "CPU Performance"
msgstr "CPU 性能"
msgid "CPU performance management."
msgstr "CPU性能管理"
msgid "CPU performance scaling not available..."
msgstr "CPU 性能扩展不可用.."
msgid "Command failed"
msgstr "命令失败"
msgid "Conservative governor"
msgstr "Conservative调控器"
msgid "Conservative tunables"
msgstr "保守的可调参数"
msgid "Current frequency"
msgstr "当前频率"
msgid "Disabled"
msgstr "已禁用"
msgid "Enable"
msgstr "启用"
msgid "Enabled"
msgstr "已启用"
msgid "Failed to get %s init status: %s"
msgstr "获取初始状态失败%s:%s"
msgid "Frequency decrease deferral factor."
msgstr "频率降低延迟因数。"
msgid "Frequency step in percent of the maximum frequency the governor is allowed to set."
msgstr "频率步进,单位为调速器允许设置的最大频率的百分比。"
msgid "Frequency value must not be"
msgstr "频率值不得超过"
msgid "GHz"
msgstr "GHz"
msgid "If checked, it will cause the CPU load estimation code to treat the CPU time spent on executing tasks with \"nice\" levels greater than 0 as CPU idle time."
msgstr "如果启用,CPU 使用率估计代码会将执行高于 0 的“nice”级别的任务所花费的 CPU 时间视为 CPU 空闲时间。"
msgid "If the estimated CPU load is above this value (in percent), the governor will set the frequency to the maximum value."
msgstr "如果估计的 CPU 负载高于此值(百分比),调节器将把频率设置为最大值。"
msgid "KHz"
msgstr "KHz"
msgid "MHz"
msgstr "MHz"
msgid "Maximum frequency"
msgstr "最高频率"
msgid "Maximum frequency the CPU is allowed to be running."
msgstr "允许 CPU 运行的最高频率。"
msgid "Maximum scaling frequency"
msgstr "最大扩展频率"
msgid "Minimum frequency"
msgstr "最低频率"
msgid "Minimum frequency the CPU is allowed to be running."
msgstr "允许CPU运行的最低频率。"
msgid "Minimum scaling frequency"
msgstr "最小扩展频率"
msgid "No performance data..."
msgstr "没有性能数据..."
msgid "Ondemand governor"
msgstr "按需调节器"
msgid "Ondemand tunables"
msgstr "按需调节参数"
msgid "Performance managment"
msgstr "性能管理"
msgid "Performance scaling not available for this CPU..."
msgstr "性能缩放不适用于该CPU..."
msgid "Run at startup"
msgstr "在系统启动时运行"
msgid "Scaling governor"
msgstr "缩放控制"
msgid "Scaling governors implement algorithms to estimate the required CPU capacity."
msgstr "缩放调节器实现算法来估计所需的 CPU 容量。"
msgid "Service action failed \"%s %s\": %s"
msgstr "服务操作失败 \"%s %s\": %s"
msgid "Threshold value (in percent) used to determine the frequency change direction."
msgstr "用于确定频率变化方向的阈值(以百分比表示)。"
msgid "default value:"
msgstr "默认值:"
msgid "higher"
msgstr "更高"
msgid "lower"
msgstr "降低"
msgid "than the"
msgstr "比"
@@ -0,0 +1,11 @@
config main 'config'
option enabled '1'
config kernel 'eas'
config module 'pcie_aspm'
config governor 'ondemand'
config governor 'conservative'
+249
View File
@@ -0,0 +1,249 @@
#!/bin/sh /etc/rc.common
START=13
APP_NAME="cpu-perf"
SYSFS_CPU_DIR="/sys/devices/system/cpu"
SYSFS_CPU_FREQ_DIR="${SYSFS_CPU_DIR}/cpufreq"
OD_CPU_FREQ_DIR="${SYSFS_CPU_DIR}/cpufreq/ondemand"
OD_UP_THRESHOLD_FILE="${OD_CPU_FREQ_DIR}/up_threshold"
OD_IGN_NICE_LOAD_FILE="${OD_CPU_FREQ_DIR}/ignore_nice_load"
OD_SAMPLING_DOWN_FACTOR_FILE="${OD_CPU_FREQ_DIR}/sampling_down_factor"
OD_POWERSAVE_BIAS_FILE="${OD_CPU_FREQ_DIR}/powersave_bias"
OD_UP_THRESHOLD_DEF=95
OD_IGN_NICE_LOAD_DEF=0
OD_SAMPLING_DOWN_FACTOR_DEF=1
OD_POWERSAVE_BIAS_DEF=0
CO_CPU_FREQ_DIR="${SYSFS_CPU_DIR}/cpufreq/conservative"
CO_FREQ_STEP_FILE="${CO_CPU_FREQ_DIR}/freq_step"
CO_DOWN_THRESHOLD_FILE="${CO_CPU_FREQ_DIR}/down_threshold"
CO_SAMPLING_DOWN_FACTOR_FILE="${CO_CPU_FREQ_DIR}/sampling_down_factor"
CO_FREQ_STEP_DEF=5
CO_DOWN_THRESHOLD_DEF=20
CO_SAMPLING_DOWN_FACTOR_DEF=1
PA_POLICY_FILE="/sys/module/pcie_aspm/parameters/policy"
PA_POLICY_DEF="default"
EAS_FILE="/proc/sys/kernel/sched_energy_aware"
EAS_DEF=1
config_load $APP_NAME
get_cpu_freq_policies() {
echo $(ls "$SYSFS_CPU_FREQ_DIR" | grep "^policy[0-9]*$")
}
reset_cpu_freq_policy_config() {
while uci -q delete ${APP_NAME}.@cpu_freq_policy[0]; do :; done
for i in $(get_cpu_freq_policies)
do
uci set ${APP_NAME}.${i}="cpu_freq_policy"
done
uci commit "$APP_NAME"
}
CPU_FREQ_POLICY_UCI_SECTIONS=0
CPU_FREQ_POLICIES=$(get_cpu_freq_policies | wc -w)
cpu_freq_policy_section_counter() {
CPU_FREQ_POLICY_UCI_SECTIONS=$(($CPU_FREQ_POLICY_UCI_SECTIONS + 1))
}
check_cpu_freq_policy_sections() {
CPU_FREQ_POLICY_UCI_SECTIONS=0
config_foreach cpu_freq_policy_section_counter cpu_freq_policy
if [ $CPU_FREQ_POLICY_UCI_SECTIONS -ne $CPU_FREQ_POLICIES ]; then
reset_cpu_freq_policy_config
fi
}
set_cpu_freq_policy() {
local policy="$1"
local scaling_min_freq scaling_max_freq scaling_governor
local policy_dir="${SYSFS_CPU_FREQ_DIR}/${policy}"
[ ! -d $policy_dir ] && return
local scaling_min_freq_file="${policy_dir}/scaling_min_freq"
local scaling_max_freq_file="${policy_dir}/scaling_max_freq"
local scaling_governor_file="${policy_dir}/scaling_governor"
config_get scaling_min_freq $policy scaling_min_freq
config_get scaling_max_freq $policy scaling_max_freq
config_get scaling_governor $policy scaling_governor
if [ -n "$scaling_min_freq" -a -w "$scaling_min_freq_file" ]; then
echo "$scaling_min_freq" > "$scaling_min_freq_file"
fi
if [ -n "$scaling_max_freq" -a -w "$scaling_max_freq_file" ]; then
echo "$scaling_max_freq" > "$scaling_max_freq_file"
fi
if [ -n "$scaling_governor" -a -w "$scaling_governor_file" ]; then
echo "$scaling_governor" > "$scaling_governor_file"
fi
}
reset_cpu_freq_policy() {
local policy="$1"
local policy_dir="${SYSFS_CPU_FREQ_DIR}/${policy}"
[ ! -d $policy_dir ] && return
local min_freq_file="${policy_dir}/cpuinfo_min_freq"
local max_freq_file="${policy_dir}/cpuinfo_max_freq"
local scaling_min_freq_file="${policy_dir}/scaling_min_freq"
local scaling_max_freq_file="${policy_dir}/scaling_max_freq"
local scaling_governor_file="${policy_dir}/scaling_governor"
if [ -r "$min_freq_file" -a -w "$scaling_min_freq_file" ]; then
echo "$(cat $min_freq_file)" > "$scaling_min_freq_file"
fi
if [ -r "$max_freq_file" -a -w "$scaling_max_freq_file" ]; then
echo "$(cat $max_freq_file)" > "$scaling_max_freq_file"
fi
if [ -w "$scaling_governor_file" ]; then
echo "schedutil" > "$scaling_governor_file" 2> /dev/null
if [ $? -ne 0 ]; then
echo "ondemand" > "$scaling_governor_file" 2> /dev/null
if [ $? -ne 0 ]; then
echo "conservative" > "$scaling_governor_file" 2> /dev/null
if [ $? -ne 0 ]; then
echo "userspace" > "$scaling_governor_file" 2> /dev/null
fi
fi
fi
fi
}
set_ondemand_tunables() {
local up_threshold ignore_nice_load sampling_down_factor powersave_bias
[ ! -d "$OD_CPU_FREQ_DIR" ] && return 0
config_get up_threshold ondemand up_threshold
config_get ignore_nice_load ondemand ignore_nice_load
config_get sampling_down_factor ondemand sampling_down_factor
config_get powersave_bias ondemand powersave_bias
if [ -n "$up_threshold" -a -w "$OD_UP_THRESHOLD_FILE" ]; then
echo "$up_threshold" > "$OD_UP_THRESHOLD_FILE"
fi
if [ -n "$ignore_nice_load" -a -w "$OD_IGN_NICE_LOAD_FILE" ]; then
echo "$ignore_nice_load" > "$OD_IGN_NICE_LOAD_FILE"
fi
if [ -n "$sampling_down_factor" -a -w "$OD_SAMPLING_DOWN_FACTOR_FILE" ]; then
echo "$sampling_down_factor" > "$OD_SAMPLING_DOWN_FACTOR_FILE"
fi
if [ -n "$powersave_bias" -a -w "$OD_POWERSAVE_BIAS_FILE" ]; then
echo "$powersave_bias" > "$OD_POWERSAVE_BIAS_FILE"
fi
}
reset_ondemand_tunables() {
[ ! -d "$OD_CPU_FREQ_DIR" ] && return 0
if [ -w "$OD_UP_THRESHOLD_FILE" ]; then
echo "$OD_UP_THRESHOLD_DEF" > "$OD_UP_THRESHOLD_FILE"
fi
if [ -w "$OD_IGN_NICE_LOAD_FILE" ]; then
echo "$OD_IGN_NICE_LOAD_DEF" > "$OD_IGN_NICE_LOAD_FILE"
fi
if [ -w "$OD_SAMPLING_DOWN_FACTOR_FILE" ]; then
echo "$OD_SAMPLING_DOWN_FACTOR_DEF" > "$OD_SAMPLING_DOWN_FACTOR_FILE"
fi
if [ -w "$OD_POWERSAVE_BIAS_FILE" ]; then
echo "$OD_POWERSAVE_BIAS_DEF" > "$OD_POWERSAVE_BIAS_FILE"
fi
}
set_conservative_tunables() {
local freq_step down_threshold sampling_down_factor
[ ! -d "$CO_CPU_FREQ_DIR" ] && return 0
config_get freq_step conservative freq_step
config_get down_threshold conservative down_threshold
config_get sampling_down_factor conservative sampling_down_factor
if [ -n "$freq_step" -a -w "$CO_FREQ_STEP_FILE" ]; then
echo "$freq_step" > "$CO_FREQ_STEP_FILE"
fi
if [ -n "$down_threshold" -a -w "$CO_DOWN_THRESHOLD_FILE" ]; then
echo "$down_threshold" > "$CO_DOWN_THRESHOLD_FILE"
fi
if [ -n "$sampling_down_factor" -a -w "$CO_SAMPLING_DOWN_FACTOR_FILE" ]; then
echo "$sampling_down_factor" > "$CO_SAMPLING_DOWN_FACTOR_FILE"
fi
}
reset_conservative_tunables() {
[ ! -d "$CO_CPU_FREQ_DIR" ] && return 0
if [ -w "$CO_FREQ_STEP_FILE" ]; then
echo "$CO_FREQ_STEP_DEF" > "$CO_FREQ_STEP_FILE"
fi
if [ -w "$CO_DOWN_THRESHOLD_FILE" ]; then
echo "$CO_DOWN_THRESHOLD_DEF" > "$CO_DOWN_THRESHOLD_FILE"
fi
if [ -w "$CO_SAMPLING_DOWN_FACTOR_FILE" ]; then
echo "$CO_SAMPLING_DOWN_FACTOR_DEF" > "$CO_SAMPLING_DOWN_FACTOR_FILE"
fi
}
set_eas() {
config_get sched_energy_aware eas sched_energy_aware
if [ -n "$sched_energy_aware" -a -w "$EAS_FILE" ]; then
echo "$sched_energy_aware" > "$EAS_FILE" 2> /dev/null
fi
}
reset_eas() {
if [ -w "$EAS_FILE" ]; then
echo "$EAS_DEF" > "$EAS_FILE" 2> /dev/null
fi
}
set_pcie_aspm_policy() {
config_get policy pcie_aspm policy
if [ -n "$policy" -a -w "$PA_POLICY_FILE" ]; then
echo "$policy" > "$PA_POLICY_FILE" 2> /dev/null
fi
}
reset_pcie_aspm_policy() {
if [ -w "$PA_POLICY_FILE" ]; then
echo "$PA_POLICY_DEF" > "$PA_POLICY_FILE" 2> /dev/null
fi
}
start() {
local enabled
if [ -r "/etc/config/${APP_NAME}" ]; then
check_cpu_freq_policy_sections
enabled=$(uci get ${APP_NAME}.config.enabled)
if [ "$enabled" = "1" ]; then
set_eas
config_foreach set_cpu_freq_policy cpu_freq_policy
set_ondemand_tunables
set_conservative_tunables
set_pcie_aspm_policy
fi
else
exit 1
fi
}
stop() {
reset_eas
config_foreach reset_cpu_freq_policy cpu_freq_policy
reset_ondemand_tunables
reset_conservative_tunables
reset_pcie_aspm_policy
}
@@ -0,0 +1,14 @@
{
"admin/services/cpu-perf": {
"title": "CPU Performance",
"order": 10,
"action": {
"type": "view",
"path": "cpu-perf"
},
"depends": {
"acl": [ "luci-app-cpu-perf" ],
"uci": { "cpu-perf": true }
}
}
}
@@ -0,0 +1,15 @@
{
"luci-app-cpu-perf": {
"description": "Grant access to cpu-perf procedures",
"read": {
"uci": [ "cpu-perf" ],
"ubus": {
"luci": [ "getInitList", "setInitAction" ],
"luci.cpu-perf": [ "getCpuPerf" ]
}
},
"write": {
"uci": [ "cpu-perf" ]
}
}
}
@@ -0,0 +1,181 @@
'use strict';
import { basename, lsdir, readfile, readlink, stat } from 'fs';
const sysCpuDir = '/sys/devices/system/cpu';
const sysFreqPolicyDir = sysCpuDir + '/cpufreq';
const sysOndemandDir = sysFreqPolicyDir + '/ondemand';
const sysConservativeDir = sysFreqPolicyDir + '/conservative';
const sysPcieAspmPolicyFile = '/sys/module/pcie_aspm/parameters/policy';
const sysEasFile = '/proc/sys/kernel/sched_energy_aware';
function readFile(path) {
let r = readfile(path);
return r && trim(r);
}
function parseMultiValue(s, number) {
if(!s) {
return null;
}
let t = [];
s = replace(s, /[\]\[]/g, '');
for(let i in split(s, /[[:space:]]+/)) {
push(t, number ? int(i) : i);
}
return t;
}
const methods = {
getCpuPerf: {
call: function() {
let cpuPerf = {};
let eas = {};
let pcieAspm = {};
let ondemand = {};
let conservative = {};
let freqPolicies = {};
let cpus = {};
if(stat(sysEasFile)?.type == 'file') {
let schedEnergyAware = readFile(sysEasFile);
if(schedEnergyAware) {
eas['schedEnergyAware'] = int(schedEnergyAware);
}
cpuPerf['eas'] = eas;
}
if(stat(sysPcieAspmPolicyFile)?.type == 'file') {
let availPolicies = readFile(sysPcieAspmPolicyFile);
if(availPolicies) {
pcieAspm['availPolicies'] = parseMultiValue(availPolicies);
}
let currentPolicy = match(availPolicies, /\[[a-z]+\]/);
pcieAspm['currentPolicy'] = type(currentPolicy) == 'array' ? trim(currentPolicy[0], '[]') : '';
cpuPerf['pcieAspm'] = pcieAspm;
}
if(stat(sysOndemandDir)?.type == 'directory') {
let upThreshold = readFile(sysOndemandDir + '/up_threshold');
let ignNiceLoad = readFile(sysOndemandDir + '/ignore_nice_load');
let smpDownFactor = readFile(sysOndemandDir + '/sampling_down_factor');
let powersaveBias = readFile(sysOndemandDir + '/powersave_bias');
if(upThreshold) {
ondemand['upThreshold'] = int(upThreshold);
}
if(ignNiceLoad) {
ondemand['ignNiceLoad'] = int(ignNiceLoad);
}
if(smpDownFactor) {
ondemand['smpDownFactor'] = int(smpDownFactor);
}
if(powersaveBias) {
ondemand['powersaveBias'] = int(powersaveBias);
}
cpuPerf['ondemand'] = ondemand;
}
if(stat(sysConservativeDir)?.type == 'directory') {
let freqStep = readFile(sysConservativeDir + '/freq_step');
let downThreshold = readFile(sysConservativeDir + '/down_threshold');
let smpDownFactor = readFile(sysConservativeDir + '/sampling_down_factor');
if(freqStep) {
conservative['freqStep'] = int(freqStep);
}
if(downThreshold) {
conservative['downThreshold'] = int(downThreshold);
}
if(smpDownFactor) {
conservative['smpDownFactor'] = int(smpDownFactor);
}
cpuPerf['conservative'] = conservative;
}
if(stat(sysFreqPolicyDir)?.type == 'directory') {
for(let item in lsdir(sysFreqPolicyDir)) {
if(match(item, /^policy[0-9]+$/)) {
let policyDirPath = sprintf('%s/%s', sysFreqPolicyDir, item);
if(stat(policyDirPath)?.type == 'directory') {
let m = match(item, /[0-9]+/);
let dNumber = m && m[0];
if(dNumber) {
let sCurFreq = readFile(policyDirPath + '/scaling_cur_freq');
let curFreq = readFile(policyDirPath + '/cpuinfo_cur_freq');
let sMinFreq = readFile(policyDirPath + '/scaling_min_freq');
let minFreq = readFile(policyDirPath + '/cpuinfo_min_freq');
let sMaxFreq = readFile(policyDirPath + '/scaling_max_freq');
let maxFreq = readFile(policyDirPath + '/cpuinfo_max_freq');
let governor = readFile(policyDirPath + '/scaling_governor');
let sAvailFreqs = readFile(policyDirPath + '/scaling_available_frequencies');
if(sAvailFreqs) {
sAvailFreqs = parseMultiValue(sAvailFreqs, true);
}
let sAvailGovernors = readFile(policyDirPath + '/scaling_available_governors');
if(sAvailGovernors) {
sAvailGovernors = parseMultiValue(sAvailGovernors);
}
let d = { number: int(dNumber) };
if(sCurFreq) {
d['sCurFreq'] = int(sCurFreq);
}
if(curFreq) {
d['curFreq'] = int(curFreq);
}
if(sMinFreq) {
d['sMinFreq'] = int(sMinFreq);
}
if(minFreq) {
d['minFreq'] = int(minFreq);
}
if(sMaxFreq) {
d['sMaxFreq'] = int(sMaxFreq);
}
if(maxFreq) {
d['maxFreq'] = int(maxFreq);
}
if(governor) {
d['governor'] = governor;
}
if(sAvailFreqs) {
d['sAvailFreqs'] = sAvailFreqs;
}
if(sAvailGovernors) {
d['sAvailGovernors'] = sAvailGovernors;
}
d['cpu'] = [];
freqPolicies[dNumber] = d;
}
}
}
}
cpuPerf['freqPolicies'] = freqPolicies;
}
if(stat(sysCpuDir)?.type == 'directory') {
for(let item in lsdir(sysCpuDir)) {
if(match(item, /^cpu[0-9]+$/)) {
let deviceDirPath = sprintf('%s/%s/cpufreq', sysCpuDir, item);
if(stat(deviceDirPath)?.type == 'directory') {
let m = match(item, /[0-9]+/);
let dNumber = m && m[0];
if(dNumber) {
let cpuFreqPath = readlink(deviceDirPath);
if(cpuFreqPath) {
let policy = basename(cpuFreqPath);
let m = match(policy, /[0-9]+/);
policy = m && m[0];
if(policy) {
push(freqPolicies[policy].cpu, int(dNumber));
cpus[dNumber] = {
number: int(dNumber),
policy: int(policy),
};
}
}
}
}
}
}
cpuPerf['cpus'] = cpus;
}
return cpuPerf;
},
},
};
return { 'luci.cpu-perf': methods };
@@ -0,0 +1,4 @@
{
"config": "cpu-perf",
"init": "cpu-perf"
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 341 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB