diff options
5 files changed, 185 insertions, 0 deletions
diff --git a/applications/luci-app-irqbalance/Makefile b/applications/luci-app-irqbalance/Makefile new file mode 100644 index 0000000000..91e97cdc39 --- /dev/null +++ b/applications/luci-app-irqbalance/Makefile @@ -0,0 +1,13 @@ +# Copyright 2023 Puran Lyu <pl2355@nyu.edu> +# This is free software, licensed under the Apache License, Version 2.0. + +include $(TOPDIR)/rules.mk + +LUCI_TITLE:=LuCI support for irqbalance +LUCI_DEPENDS:=+luci-base +irqbalance + +PKG_LICENSE:=Apache-2.0 + +include ../../luci.mk + +# call BuildPackage - OpenWrt buildroot signature diff --git a/applications/luci-app-irqbalance/htdocs/luci-static/resources/view/irqbalance.js b/applications/luci-app-irqbalance/htdocs/luci-static/resources/view/irqbalance.js new file mode 100644 index 0000000000..280b6f19c7 --- /dev/null +++ b/applications/luci-app-irqbalance/htdocs/luci-static/resources/view/irqbalance.js @@ -0,0 +1,116 @@ +'use strict'; +'require view'; +'require fs'; +'require form'; +'require ui'; +'require rpc'; + +const callServiceList = rpc.declare({ + object: 'service', + method: 'list', + params: ['name'], + expect: { '': {} }, +}); + +function getServiceStatus() { + return L.resolveDefault(callServiceList('irqbalance'), {}).then(function (res) { + try { + return res['irqbalance']['instances']['irqbalance']['running']; + } catch (e) { + return false; + } + }); +} + +function renderStatus(isRunning) { + const spanTemp = '<span style="color:%s"><strong>%s</strong></span>'; + + return isRunning + ? String.format(spanTemp, 'green', _('RUNNING')) + : String.format(spanTemp, 'red', _('NOT RUNNING')); +} + +return view.extend({ + load() { + return L.resolveDefault(fs.read_direct('/proc/interrupts')); + }, + + render(data) { + const cpuNum = data.match(/\bCPU\d+\b/g).map(i => i.slice(3)), // cpuNum = data.match(/(?<=\bCPU)\d+\b/g), // Safari did not support RegExp lookbehind assertion before version 16.4. + irqNum = data.match(/\b\d+(?=: )/g); + let m, s, o; + + m = new form.Map('irqbalance', _('irqbalance'), _('The purpose of irqbalance is to distribute hardware interrupts across processors/cores on a multiprocessor/multicore system in order to increase performance.')); + + s = m.section(form.NamedSection); + s.anonymous = true; + s.render = function () { + L.Poll.add(function () { + return L.resolveDefault(getServiceStatus()).then(function (res) { + const view = document.getElementById('status'); + view.innerHTML = renderStatus(res); + }); + }); + + return E('div', { class: 'cbi-section' }, [ + E('p', { id: 'status' }, _('Loading...')) + ]); + } + + s = m.section(form.TypedSection, 'irqbalance', _('Snapshot of current IRQs')); + s.anonymous = true; + + s = m.section(form.NamedSection); + s.anonymous = true; + s.render = function () { + const snapshot = new ui.Textarea(data.slice(0, -1), { + readonly: true, + placeholder: _('Loading...'), + monospace: true, + rows: data.split('\n').length - 1, + }); + return snapshot.render(); + } + + s = m.section(form.TypedSection, 'irqbalance', _('General settings')); + s.anonymous = true; + + o = s.option(form.Flag, 'enabled', _('Enable')); + o.default = '0'; + o.rmempty = false; + + o = s.option(form.Value, 'deepestcache', _('Deepest cache'), _('Cache level at which irqbalance partitions cache domains.')); + o.placeholder = '2'; + o.datatype = 'uinteger'; + o.optional = true; + + o = s.option(form.Value, 'interval', _('Interval'), _('Value in seconds.')); + o.placeholder = '10'; + o.datatype = 'uinteger'; + o.optional = true; + + o = s.option(form.Value, 'banned_cpulist', _('Exclude CPUs'), _('List of CPUs to ignore, can be an integer or integers separated by commas.') + '<br />' + _('Valid values: %s.').format(cpuNum.join(', '))); + o.placeholder = '0'; + o.optional = true; + o.validate = function (section_id, value) { + for (const i of value.split(',')) { + if (!cpuNum.includes(i) && i != '') { + return _('Invalid'); + } + } + return true; + } + + o = s.option(form.DynamicList, 'banirq', _('Exclude IRQs'), _('List of IRQs to ignore.') + '<br />' + _('Valid values: %s.').format(irqNum.join(', '))); + o.placeholder = '36'; + o.datatype = 'uinteger'; + o.optional = true; + o.validate = function (section_id, value) { + return !irqNum.includes(value) && value != '' + ? _('Invalid') + : true; + } + + return m.render(); + } +}); diff --git a/applications/luci-app-irqbalance/root/etc/uci-defaults/90_luci-irqbalance b/applications/luci-app-irqbalance/root/etc/uci-defaults/90_luci-irqbalance new file mode 100644 index 0000000000..e6ec84c4db --- /dev/null +++ b/applications/luci-app-irqbalance/root/etc/uci-defaults/90_luci-irqbalance @@ -0,0 +1,10 @@ +#!/bin/sh + +uci -q batch <<-EOF >/dev/null + delete ucitrack.@irqbalance[-1] + add ucitrack irqbalance + set ucitrack.@irqbalance[-1].init=irqbalance + commit ucitrack +EOF + +exit 0 diff --git a/applications/luci-app-irqbalance/root/usr/share/luci/menu.d/luci-app-irqbalance.json b/applications/luci-app-irqbalance/root/usr/share/luci/menu.d/luci-app-irqbalance.json new file mode 100644 index 0000000000..6a4b29589b --- /dev/null +++ b/applications/luci-app-irqbalance/root/usr/share/luci/menu.d/luci-app-irqbalance.json @@ -0,0 +1,21 @@ +{ + "admin/services/irqbalance": { + "title": "irqbalance", + "order": 90, + "action": { + "type": "view", + "path": "irqbalance" + }, + "depends": { + "acl": [ + "luci-app-irqbalance" + ], + "uci": { + "irqbalance": true + }, + "fs": { + "/proc/interrupts": "file" + } + } + } +}
\ No newline at end of file diff --git a/applications/luci-app-irqbalance/root/usr/share/rpcd/acl.d/luci-app-irqbalance.json b/applications/luci-app-irqbalance/root/usr/share/rpcd/acl.d/luci-app-irqbalance.json new file mode 100644 index 0000000000..44b6f5ff23 --- /dev/null +++ b/applications/luci-app-irqbalance/root/usr/share/rpcd/acl.d/luci-app-irqbalance.json @@ -0,0 +1,25 @@ +{ + "luci-app-irqbalance": { + "description": "Grant UCI access for luci-app-irqbalance", + "read": { + "file": { + "/proc/interrupts": [ + "read" + ] + }, + "ubus": { + "service": [ + "list" + ] + }, + "uci": [ + "irqbalance" + ] + }, + "write": { + "uci": [ + "irqbalance" + ] + } + } +}
\ No newline at end of file |