diff --git a/bin/ascoltami2 b/bin/ascoltami2 --- a/bin/ascoltami2 +++ b/bin/ascoltami2 @@ -11,9 +11,11 @@ from light9.ascoltami.player import Play from light9.ascoltami.playlist import Playlist, NoSuchSong from light9.ascoltami.webapp import makeWebApp, songUri, songLocation from light9 import networking, showconfig +from standardservice.scalessetup import gatherProcessStats from gi.repository import GObject, Gst +gatherProcessStats() class App(object): diff --git a/bin/collector b/bin/collector --- a/bin/collector +++ b/bin/collector @@ -25,6 +25,7 @@ from greplin.scales.cyclonehandler impor from light9.namespaces import L9 from light9.zmqtransport import parseJsonMessage, startZmq from rdfdb.syncedgraph import SyncedGraph +from standardservice.scalessetup import gatherProcessStats from light9.collector.output import Udmx, DummyOutput # noqa @@ -42,6 +43,7 @@ class Updates(cyclone.websocket.WebSocke json.loads(message) +gatherProcessStats() stats = scales.collection( '/webServer', scales.PmfStat('setAttr', recalcPeriod=1), diff --git a/bin/effecteval b/bin/effecteval --- a/bin/effecteval +++ b/bin/effecteval @@ -16,10 +16,12 @@ from light9.namespaces import L9 from rdfdb.patch import Patch from rdfdb.syncedgraph import SyncedGraph from greplin import scales +from standardservice.scalessetup import gatherProcessStats from cycloneerr import PrettyErrorHandler from light9.coffee import StaticCoffee +gatherProcessStats() class EffectEdit(PrettyErrorHandler, cyclone.web.RequestHandler): diff --git a/bin/vidref b/bin/vidref --- a/bin/vidref +++ b/bin/vidref @@ -30,6 +30,7 @@ from light9 import networking, showconfi from light9.newtypes import Song from light9.vidref import videorecorder from rdfdb.syncedgraph import SyncedGraph +from standardservice.scalessetup import gatherProcessStats parser = optparse.OptionParser() parser.add_option("-v", "--verbose", action="store_true", help="logging.DEBUG") @@ -37,6 +38,7 @@ parser.add_option("-v", "--verbose", act log.setLevel(logging.DEBUG if options.verbose else logging.INFO) +gatherProcessStats() stats = scales.collection( '/webServer', scales.RecentFpsStat('liveWebsocketFrameFps'), diff --git a/light9/effect/sequencer.py b/light9/effect/sequencer.py --- a/light9/effect/sequencer.py +++ b/light9/effect/sequencer.py @@ -20,12 +20,14 @@ from light9.effect.simple_outputs import from light9.namespaces import L9, RDF from light9.newtypes import DeviceUri, DeviceAttr, NoteUri, Curve, Song from rdfdb.syncedgraph import SyncedGraph +from standardservice.scalessetup import gatherProcessStats from greplin import scales import imp log = logging.getLogger('sequencer') +gatherProcessStats() updateStats = scales.collection( '/update/', scales.PmfStat('s0_getMusic', recalcPeriod=1), diff --git a/light9/web/index.html b/light9/web/index.html --- a/light9/web/index.html +++ b/light9/web/index.html @@ -9,6 +9,7 @@ + diff --git a/light9/web/stats-line.js b/light9/web/stats-line.js --- a/light9/web/stats-line.js +++ b/light9/web/stats-line.js @@ -20,13 +20,12 @@ class StatsLine extends LitElement { const reload = () => { fetch(this.name + '/stats/?format=json').then((resp) => { if (resp.ok) { - resp.json().then((msg) => { - - this.stats = msg; - setTimeout(reload, 1000); + resp.json().then((msg) => { + this.stats = msg; + setTimeout(reload, 1000); + }); + } }); - } - }); } reload(); } @@ -78,10 +77,21 @@ class StatsLine extends LitElement { } render() { + const now = Date.now() / 1000; const table = (d, path) => { - const cols = Object.keys(d); + let cols = Object.keys(d); cols.sort(); + + if (path.length == 0) { + ['webServer', 'process'].forEach((earlyKey) => { + let i = cols.indexOf(earlyKey); + if (i != -1) { + cols = [earlyKey].concat(cols.slice(0, i), cols.slice(i + 1)); + } + }); + } + const th = (col) => { return html`${col}`; }; @@ -130,7 +140,14 @@ class StatsLine extends LitElement { ` }, path)); }; - const drawLevel = (d, path) => { + const drawLevel = (d, path) => { + if (path.length == 1 && path[0] === 'process') { + const elem = this.shadowRoot.querySelector('#proc'); + if (elem) { + elem.data = d; + } + return html``; + } if (typeof d === 'object') { if (d instanceof TemplateResult) { return html`${d}`; diff --git a/light9/web/stats-process.js b/light9/web/stats-process.js new file mode 100644 --- /dev/null +++ b/light9/web/stats-process.js @@ -0,0 +1,86 @@ +import { LitElement, TemplateResult, html, css } from '/node_modules/lit-element/lit-element.js'; +import debug from '/lib/debug/debug-build-es6.js'; +import { rounding } from '/node_modules/significant-rounding/index.js'; + +const log = debug('process'); + +const remap = (x, lo, hi, outLo, outHi) => { + return outLo + (outHi - outLo) * Math.max(0, Math.min(1, (x - lo) / (hi - lo))); +}; + +class StatsProcess extends LitElement { + + static get properties() { + return { + data: { type: Object }, + }; + } + + firstUpdated() { + // inspired by https://codepen.io/qiruiyin/pen/qOopQx + var context = this.shadowRoot.firstElementChild, + ctx = context.getContext('2d'), + w = 64, + h = 64, + revs = 0; + + context.width = w; + context.height = h; + + let prev = Date.now() / 1000; + + var animate = () => { + requestAnimationFrame( animate ); + + const now = Date.now() / 1000; + ctx.beginPath(); + // wrong type of fade- never goes to 0 + ctx.fillStyle = '#00000003'; + ctx.fillRect(0, 0, w, h); + if (this.data.time < now - 2) { + return; + } + const dt = now - prev; + prev = now; + + const size = remap(this.data.memMb, /*in*/ 20, 600, /*out*/ 3, 30); + revs += dt * remap(this.data.cpuPercent, /*in*/ 0, 100, /*out*/ 4, 120); + const rad = remap(size, /*in*/ 3, 30, /*out*/ 14, 5); + + var x = w/2 + rad * Math.cos(revs / 6.28), + y = h/2 + rad * Math.sin(revs / 6.28); + + ctx.save(); + ctx.beginPath(); + ctx.fillStyle = "hsl(194, 100%, 42%)"; + ctx.arc(x, y, size, 0, 2*Math.PI); + ctx.fill(); + ctx.restore(); + + }; + animate(); + } + + updated(changedProperties) { + if (changedProperties.has('data')) { + this.shadowRoot.firstElementChild.setAttribute('title', `cpu ${this.data.cpuPercent}% mem ${this.data.memMb}MB`); + } + } + + static get styles() { + return css` + :host { + display: inline-block; + width: 64px; + height: 64px; + } + `; + } + + render() { + return html``; + + } +} +customElements.define('stats-process', StatsProcess); + diff --git a/requirements.txt b/requirements.txt --- a/requirements.txt +++ b/requirements.txt @@ -45,3 +45,4 @@ https://github.com/drewp/cyclone/archive cycloneerr==0.3.0 rdfdb==0.19.0 +standardservice==0.6.0