luci-app-irqbalance: add new package
authorPuran Lyu <pl2355@nyu.edu>
Fri, 29 Dec 2023 23:03:15 +0000 (18:03 -0500)
committerPaul Donald <itsascambutmailmeanyway@gmail.com>
Sat, 30 Dec 2023 23:36:31 +0000 (23:36 +0000)
Add LuCI interface for irqbalance package

Signed-off-by: Puran Lyu <pl2355@nyu.edu>
applications/luci-app-irqbalance/Makefile [new file with mode: 0644]
applications/luci-app-irqbalance/htdocs/luci-static/resources/view/irqbalance.js [new file with mode: 0644]
applications/luci-app-irqbalance/root/etc/uci-defaults/90_luci-irqbalance [new file with mode: 0644]
applications/luci-app-irqbalance/root/usr/share/luci/menu.d/luci-app-irqbalance.json [new file with mode: 0644]
applications/luci-app-irqbalance/root/usr/share/rpcd/acl.d/luci-app-irqbalance.json [new file with mode: 0644]

diff --git a/applications/luci-app-irqbalance/Makefile b/applications/luci-app-irqbalance/Makefile
new file mode 100644 (file)
index 0000000..91e97cd
--- /dev/null
@@ -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 (file)
index 0000000..280b6f1
--- /dev/null
@@ -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 (file)
index 0000000..e6ec84c
--- /dev/null
@@ -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 (file)
index 0000000..6a4b295
--- /dev/null
@@ -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 (file)
index 0000000..44b6f5f
--- /dev/null
@@ -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