succd: run at 100Hz, monitor load and jitter
This commit is contained in:
parent
12f6815673
commit
96e07ece2d
|
@ -70,6 +70,9 @@ type apiData struct {
|
||||||
// HighReached is true when the system has reached a high vacuum stage.
|
// HighReached is true when the system has reached a high vacuum stage.
|
||||||
HighReached bool
|
HighReached bool
|
||||||
}
|
}
|
||||||
|
// LoopLoad is a percentage expressing how busy the processing loop is; 100
|
||||||
|
// is full utilization; >100 is lag.
|
||||||
|
LoopLoad int64
|
||||||
// System junk.
|
// System junk.
|
||||||
System struct {
|
System struct {
|
||||||
// Load of the system.
|
// Load of the system.
|
||||||
|
@ -114,6 +117,7 @@ func (s *webServer) apiData(skipSystem bool) *apiData {
|
||||||
ad.Pumps.DPOn = state.dpOn
|
ad.Pumps.DPOn = state.dpOn
|
||||||
ad.Feedback.RoughReached = rough
|
ad.Feedback.RoughReached = rough
|
||||||
ad.Feedback.HighReached = high
|
ad.Feedback.HighReached = high
|
||||||
|
ad.LoopLoad = s.d.loopLoad()
|
||||||
ad.System.Load = load
|
ad.System.Load = load
|
||||||
ad.System.Hostname = hostname
|
ad.System.Hostname = hostname
|
||||||
return &ad
|
return &ad
|
||||||
|
|
|
@ -100,27 +100,29 @@ td > span {
|
||||||
<tr>
|
<tr>
|
||||||
<th rowspan="3">Control</th>
|
<th rowspan="3">Control</th>
|
||||||
<th>RP</th>
|
<th>RP</th>
|
||||||
<td>
|
<td colspan="3">
|
||||||
<button id="rpon">On</button>
|
<button id="rpon">On</button>
|
||||||
<button id="rpoff">Off</button>
|
<button id="rpoff">Off</button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>DP</th>
|
<th>DP</th>
|
||||||
<td>
|
<td colspan="3">
|
||||||
<button id="dpon">On</button>
|
<button id="dpon">On</button>
|
||||||
<button id="dpoff">Off</button>
|
<button id="dpoff">Off</button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="2">
|
<td colspan="3">
|
||||||
<button id="pd">Pump Down</button>
|
<button id="pd">Pump Down</button>
|
||||||
<button id="vent">Vent</button>
|
<button id="vent">Vent</button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Status</th>
|
<th>Status</th>
|
||||||
<td id="status" colspan="4">OK</td>
|
<td id="status" colspan="1">OK</td>
|
||||||
|
<th>Load</th>
|
||||||
|
<td id="load" colspan="1">...</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</p>
|
</p>
|
||||||
|
@ -275,6 +277,7 @@ window.addEventListener("load", (_) => {
|
||||||
let ping = document.querySelector("#ping");
|
let ping = document.querySelector("#ping");
|
||||||
let trough = document.querySelector("#trough");
|
let trough = document.querySelector("#trough");
|
||||||
let thigh = document.querySelector("#thigh");
|
let thigh = document.querySelector("#thigh");
|
||||||
|
let load = document.querySelector("#load");
|
||||||
|
|
||||||
// Buttons
|
// Buttons
|
||||||
let pd = document.querySelector("#pd");
|
let pd = document.querySelector("#pd");
|
||||||
|
@ -354,6 +357,7 @@ window.addEventListener("load", (_) => {
|
||||||
thigh.innerHTML = "NOK";
|
thigh.innerHTML = "NOK";
|
||||||
thigh.style = "background-color: #f06060";
|
thigh.style = "background-color: #f06060";
|
||||||
}
|
}
|
||||||
|
load.innerHTML = data.LoopLoad.toString() + "%";
|
||||||
historicalPush(data.Pirani.MbarFloat);
|
historicalPush(data.Pirani.MbarFloat);
|
||||||
ping.innerHTML = Date.now();
|
ping.innerHTML = Date.now();
|
||||||
});
|
});
|
||||||
|
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sync"
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"k8s.io/klog"
|
"k8s.io/klog"
|
||||||
|
@ -23,6 +24,8 @@ type daemon struct {
|
||||||
gpioBelowRough gpio
|
gpioBelowRough gpio
|
||||||
gpioBelowHigh gpio
|
gpioBelowHigh gpio
|
||||||
|
|
||||||
|
load atomic.Int64
|
||||||
|
|
||||||
// mu guards the state below.
|
// mu guards the state below.
|
||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
daemonState
|
daemonState
|
||||||
|
@ -62,11 +65,22 @@ func (d *daemonState) vacuumStatus() (rough, high bool) {
|
||||||
|
|
||||||
// process runs the pain acquisition and control loop of succd.
|
// process runs the pain acquisition and control loop of succd.
|
||||||
func (d *daemon) process(ctx context.Context) {
|
func (d *daemon) process(ctx context.Context) {
|
||||||
ticker := time.NewTicker(time.Millisecond * 100)
|
var lastRun time.Time
|
||||||
|
hz := 100
|
||||||
|
period := time.Second / time.Duration(hz)
|
||||||
|
// Extra grace period for GC pauses and other non-realtime system jitter.
|
||||||
|
periodGrace := period + time.Millisecond*5
|
||||||
|
|
||||||
|
ticker := time.NewTicker(period)
|
||||||
defer ticker.Stop()
|
defer ticker.Stop()
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-ticker.C:
|
case <-ticker.C:
|
||||||
|
now := time.Now()
|
||||||
|
if elapsed := now.Sub(lastRun); !lastRun.IsZero() && elapsed > periodGrace {
|
||||||
|
klog.Warningf("Processing loop lag: took %s, want %s", elapsed, period)
|
||||||
|
}
|
||||||
|
lastRun = now
|
||||||
if err := d.processOnce(ctx); err != nil {
|
if err := d.processOnce(ctx); err != nil {
|
||||||
if errors.Is(err, ctx.Err()) {
|
if errors.Is(err, ctx.Err()) {
|
||||||
return
|
return
|
||||||
|
@ -75,6 +89,9 @@ func (d *daemon) process(ctx context.Context) {
|
||||||
time.Sleep(time.Second * 10)
|
time.Sleep(time.Second * 10)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
runtime := time.Since(lastRun)
|
||||||
|
load := int64(100 * runtime / period)
|
||||||
|
d.load.Store(load)
|
||||||
case <-ctx.Done():
|
case <-ctx.Done():
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import "k8s.io/klog"
|
||||||
//
|
//
|
||||||
// This is a subset of daemon functions limited to a safe, explicit subset.
|
// This is a subset of daemon functions limited to a safe, explicit subset.
|
||||||
type daemonController interface {
|
type daemonController interface {
|
||||||
|
loopLoad() int64
|
||||||
// snapshot returns an internally consistent copy of the daemon state.
|
// snapshot returns an internally consistent copy of the daemon state.
|
||||||
snapshot() *daemonState
|
snapshot() *daemonState
|
||||||
// rpSet enables/disables the roughing pump.
|
// rpSet enables/disables the roughing pump.
|
||||||
|
@ -19,6 +20,10 @@ type daemonController interface {
|
||||||
ventPress()
|
ventPress()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (d *daemon) loopLoad() int64 {
|
||||||
|
return d.load.Load()
|
||||||
|
}
|
||||||
|
|
||||||
func (d *daemon) snapshot() *daemonState {
|
func (d *daemon) snapshot() *daemonState {
|
||||||
d.mu.RLock()
|
d.mu.RLock()
|
||||||
ds := d.daemonState
|
ds := d.daemonState
|
||||||
|
|
Loading…
Reference in a new issue