1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
|
package dashboard
import (
"fmt"
"ior/internal/statsengine"
"strconv"
"time"
"github.com/charmbracelet/bubbles/table"
)
func renderSyscalls(snap *statsengine.Snapshot, width, height int) string {
return renderSyscallsWithOffset(snap, width, height, 0)
}
func renderSyscallsWithOffset(snap *statsengine.Snapshot, width, height, offset int) string {
if snap == nil {
return "Syscalls: waiting for stats..."
}
rows := syscallRows(snap.Syscalls())
if len(rows) == 0 {
return "Syscalls: no data"
}
columns := []table.Column{
{Title: "Syscall", Width: 16},
{Title: "Count", Width: 8},
{Title: "Rate/s", Width: 8},
{Title: "Avg", Width: 9},
{Title: "Min", Width: 9},
{Title: "Max", Width: 9},
{Title: "p50", Width: 9},
{Title: "p95", Width: 9},
{Title: "p99", Width: 9},
{Title: "Bytes", Width: 10},
{Title: "Errors", Width: 8},
}
tbl := table.New(
table.WithColumns(columns),
table.WithRows(rows),
table.WithFocused(true),
)
tbl.SetHeight(syscallTableHeight(height))
tbl.SetWidth(tableWidth(width))
cursor := clampOffset(offset, len(rows))
tbl.SetCursor(cursor)
return tbl.View() + fmt.Sprintf("\nRow %d/%d", cursor+1, len(rows))
}
func syscallRows(syscalls []statsengine.SyscallSnapshot) []table.Row {
rows := make([]table.Row, 0, len(syscalls))
for _, s := range syscalls {
rows = append(rows, table.Row{
s.Name,
strconv.FormatUint(s.Count, 10),
fmt.Sprintf("%.1f", s.RatePerSec),
formatDurationNs(s.LatencyMeanNs),
formatDurationUintNs(s.LatencyMinNs),
formatDurationUintNs(s.LatencyMaxNs),
formatDurationUintNs(s.LatencyP50Ns),
formatDurationUintNs(s.LatencyP95Ns),
formatDurationUintNs(s.LatencyP99Ns),
formatBytes(float64(s.Bytes)),
strconv.FormatUint(s.Errors, 10),
})
}
return rows
}
func formatDurationUintNs(v uint64) string {
return formatDurationNs(float64(v))
}
func formatDurationNs(v float64) string {
if v < 1000 {
return fmt.Sprintf("%.0fns", v)
}
us := v / 1000
if us < 1000 {
return fmt.Sprintf("%.1fµs", us)
}
ms := us / 1000
if ms < 1000 {
return fmt.Sprintf("%.1fms", ms)
}
s := ms / 1000
return (time.Duration(s * float64(time.Second))).String()
}
func syscallTableHeight(height int) int {
if height <= 0 {
return 10
}
h := height - 6
if h < 5 {
return 5
}
return h
}
func tableWidth(width int) int {
if width <= 0 {
return 80
}
if width < 60 {
return 60
}
return width
}
func clampOffset(offset, size int) int {
if size == 0 {
return 0
}
if offset < 0 {
return 0
}
if offset >= size {
return size - 1
}
return offset
}
|