Add block-update latency tracking, raw share counters, and shares bar UI
Log ZMQ→mining.notify latency in ckpool (patch 0005), expose a raw reject counter (patch 0006), and surface both in the dashboard: - Block latency card shows avg/last ms, wasted work, and block count - SharesBar component shows session + all-time accepted/rejected with a Demon Slayer flame-slash animation on new shares - Miners card info moved to MinersTable section header - Latency stats and share counts persist across restarts via kv store - Removed misleading pool-wide share stats from per-worker/user pages (ckpool doesn't expose per-user raw counts)
This commit is contained in:
@@ -49,14 +49,23 @@ type AttemptEvent struct {
|
||||
RawLine string
|
||||
}
|
||||
|
||||
// LatencyEvent is emitted when ckpool logs the "Block update latency"
|
||||
// line from our patch 0005 — the milliseconds between ZMQ trigger and
|
||||
// mining.notify broadcast completion.
|
||||
type LatencyEvent struct {
|
||||
SeenAt time.Time
|
||||
LatencyMs int64
|
||||
}
|
||||
|
||||
// Tailer follows a log file, surviving rotation/truncation, and emits
|
||||
// parsed events. Create with New, then Run in a goroutine.
|
||||
type Tailer struct {
|
||||
Path string
|
||||
Events chan BlockEvent
|
||||
Attempts chan AttemptEvent
|
||||
Log *slog.Logger
|
||||
PollWait time.Duration // how long to sleep between EOF polls
|
||||
Path string
|
||||
Events chan BlockEvent
|
||||
Attempts chan AttemptEvent
|
||||
Latencies chan LatencyEvent
|
||||
Log *slog.Logger
|
||||
PollWait time.Duration // how long to sleep between EOF polls
|
||||
|
||||
// LoadCursor / SaveCursor, if both non-nil, persist the read
|
||||
// position across process restarts. LoadCursor returns (inode,
|
||||
@@ -77,11 +86,12 @@ type Tailer struct {
|
||||
|
||||
func New(path string, log *slog.Logger) *Tailer {
|
||||
return &Tailer{
|
||||
Path: path,
|
||||
Events: make(chan BlockEvent, 16),
|
||||
Attempts: make(chan AttemptEvent, 16),
|
||||
Log: log,
|
||||
PollWait: 500 * time.Millisecond,
|
||||
Path: path,
|
||||
Events: make(chan BlockEvent, 16),
|
||||
Attempts: make(chan AttemptEvent, 16),
|
||||
Latencies: make(chan LatencyEvent, 16),
|
||||
Log: log,
|
||||
PollWait: 500 * time.Millisecond,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,6 +104,9 @@ var (
|
||||
// "Submitting possible block solve share diff N !"
|
||||
// "Possible remote block solve diff N !"
|
||||
solveDiffRE = regexp.MustCompile(`(?:Possible|Submitting[^"]*possible).*block solve.*diff\s+([0-9eE.+-]+)`)
|
||||
// Matches the latency line from our patch 0005:
|
||||
// "Block update latency: 92ms (ZMQ trigger to mining.notify broadcast)"
|
||||
latencyRE = regexp.MustCompile(`Block update latency:\s+(\d+)ms`)
|
||||
)
|
||||
|
||||
// Run blocks until ctx is cancelled. It opens the file, seeks to either
|
||||
@@ -104,6 +117,7 @@ var (
|
||||
func (t *Tailer) Run(ctx context.Context) {
|
||||
defer close(t.Events)
|
||||
defer close(t.Attempts)
|
||||
defer close(t.Latencies)
|
||||
|
||||
var (
|
||||
f *os.File
|
||||
@@ -242,6 +256,15 @@ func (t *Tailer) Run(ctx context.Context) {
|
||||
}
|
||||
|
||||
func (t *Tailer) handleLine(line string) {
|
||||
if m := latencyRE.FindStringSubmatch(line); m != nil {
|
||||
if ms, err := strconv.ParseInt(m[1], 10, 64); err == nil {
|
||||
select {
|
||||
case t.Latencies <- LatencyEvent{SeenAt: time.Now(), LatencyMs: ms}:
|
||||
default:
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
if m := solveDiffRE.FindStringSubmatch(line); m != nil {
|
||||
var d float64
|
||||
if v, err := strconv.ParseFloat(m[1], 64); err == nil {
|
||||
|
||||
Reference in New Issue
Block a user