perfmonger 0.6.1 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -13
- data/.gitignore +6 -0
- data/.tachikoma.yml +1 -0
- data/.travis.yml +18 -6
- data/Gemfile +1 -3
- data/Guardfile +26 -0
- data/NEWS +21 -0
- data/README.md +8 -9
- data/Rakefile +33 -1
- data/core/Makefile +23 -0
- data/core/build.sh +48 -0
- data/core/perfmonger-player.go +165 -0
- data/core/perfmonger-recorder.go +296 -0
- data/core/perfmonger-summarizer.go +207 -0
- data/core/subsystem/Makefile +3 -0
- data/core/subsystem/perfmonger.go +60 -0
- data/core/subsystem/perfmonger_darwin.go +22 -0
- data/core/subsystem/perfmonger_linux.go +292 -0
- data/core/subsystem/perfmonger_linux_test.go +73 -0
- data/core/subsystem/stat.go +214 -0
- data/core/subsystem/stat_test.go +281 -0
- data/core/subsystem/usage.go +410 -0
- data/core/subsystem/usage_test.go +496 -0
- data/lib/exec/operationBinding.rb.svn-base +59 -0
- data/lib/exec/perfmonger-player_darwin_amd64 +0 -0
- data/lib/exec/perfmonger-player_linux_386 +0 -0
- data/lib/exec/perfmonger-player_linux_amd64 +0 -0
- data/lib/exec/perfmonger-recorder_darwin_amd64 +0 -0
- data/lib/exec/perfmonger-recorder_linux_386 +0 -0
- data/lib/exec/perfmonger-recorder_linux_amd64 +0 -0
- data/lib/exec/perfmonger-summarizer_darwin_amd64 +0 -0
- data/lib/exec/perfmonger-summarizer_linux_386 +0 -0
- data/lib/exec/perfmonger-summarizer_linux_amd64 +0 -0
- data/lib/exec/perfmonger-summary_linux_386 +0 -0
- data/lib/exec/perfmonger-summary_linux_amd64 +0 -0
- data/lib/perfmonger/cli.rb +8 -3
- data/lib/perfmonger/command/core.rb +62 -0
- data/lib/perfmonger/command/live.rb +39 -0
- data/lib/perfmonger/command/play.rb +56 -0
- data/lib/perfmonger/command/plot.rb +30 -22
- data/lib/perfmonger/command/record.rb +3 -2
- data/lib/perfmonger/command/record_option.rb +40 -59
- data/lib/perfmonger/command/server.rb +7 -2
- data/lib/perfmonger/command/stat.rb +2 -2
- data/lib/perfmonger/command/stat_option.rb +1 -1
- data/lib/perfmonger/command/summary.rb +11 -326
- data/lib/perfmonger/version.rb +1 -3
- data/lib/perfmonger.rb +3 -0
- data/misc/_perfmonger +128 -0
- data/misc/perfmonger-completion.bash +49 -0
- data/perfmonger.gemspec +6 -5
- data/spec/data/busy100.pgr +0 -0
- data/spec/fingerprint_spec.rb +35 -0
- data/spec/live_spec.rb +25 -0
- data/spec/perfmonger_spec.rb +37 -0
- data/spec/play_spec.rb +21 -0
- data/spec/plot_spec.rb +42 -0
- data/spec/record_spec.rb +15 -0
- data/spec/spec_helper.rb +33 -0
- data/spec/stat_spec.rb +15 -0
- data/spec/summary_spec.rb +51 -0
- data/spec/support/aruba.rb +11 -0
- data/wercker.yml +59 -0
- metadata +117 -45
- data/ext/perfmonger/extconf.rb +0 -19
- data/ext/perfmonger/perfmonger.h +0 -58
- data/ext/perfmonger/perfmonger_record.c +0 -754
- data/ext/perfmonger/sysstat/common.c +0 -627
- data/ext/perfmonger/sysstat/common.h +0 -207
- data/ext/perfmonger/sysstat/ioconf.c +0 -515
- data/ext/perfmonger/sysstat/ioconf.h +0 -84
- data/ext/perfmonger/sysstat/iostat.c +0 -1100
- data/ext/perfmonger/sysstat/iostat.h +0 -121
- data/ext/perfmonger/sysstat/libsysstat.h +0 -19
- data/ext/perfmonger/sysstat/mpstat.c +0 -953
- data/ext/perfmonger/sysstat/mpstat.h +0 -79
- data/ext/perfmonger/sysstat/rd_stats.c +0 -2388
- data/ext/perfmonger/sysstat/rd_stats.h +0 -651
- data/ext/perfmonger/sysstat/sysconfig.h +0 -13
- data/test/run-test.sh +0 -39
- data/test/spec/bin_spec.rb +0 -37
- data/test/spec/data/2devices.expected +0 -42
- data/test/spec/data/2devices.output +0 -42
- data/test/spec/spec_helper.rb +0 -20
- data/test/spec/summary_spec.rb +0 -193
- data/test/test-perfmonger.c +0 -145
- data/test/test.h +0 -9
@@ -0,0 +1,296 @@
|
|
1
|
+
//usr/bin/env go run $0 $@ ; exit
|
2
|
+
|
3
|
+
package main
|
4
|
+
|
5
|
+
import (
|
6
|
+
"bufio"
|
7
|
+
"encoding/gob"
|
8
|
+
"flag"
|
9
|
+
"fmt"
|
10
|
+
"io"
|
11
|
+
"os"
|
12
|
+
"os/exec"
|
13
|
+
"os/signal"
|
14
|
+
"strings"
|
15
|
+
"time"
|
16
|
+
|
17
|
+
"golang.org/x/crypto/ssh/terminal"
|
18
|
+
|
19
|
+
ss "github.com/hayamiz/perfmonger/core/subsystem"
|
20
|
+
)
|
21
|
+
|
22
|
+
type RecorderOption struct {
|
23
|
+
interval time.Duration
|
24
|
+
no_interval_backoff bool
|
25
|
+
timeout time.Duration
|
26
|
+
start_delay time.Duration
|
27
|
+
devsParts []string
|
28
|
+
output string
|
29
|
+
no_cpu bool
|
30
|
+
no_disk bool
|
31
|
+
no_net bool
|
32
|
+
debug bool
|
33
|
+
listDevices bool
|
34
|
+
player_bin string
|
35
|
+
disks string
|
36
|
+
targetDisks *map[string]bool
|
37
|
+
}
|
38
|
+
|
39
|
+
var option RecorderOption
|
40
|
+
|
41
|
+
// By default, measurement interval backoff is enabled.
|
42
|
+
// Minimum resoluton guaranteed: BACKOFF_RATIO / BACKOFF_THRESH
|
43
|
+
const (
|
44
|
+
BACKOFF_THRESH = 1000.0
|
45
|
+
BACKOFF_RATIO = 2.0
|
46
|
+
)
|
47
|
+
|
48
|
+
func parseArgs() {
|
49
|
+
// set options
|
50
|
+
flag.DurationVar(&option.interval, "interval",
|
51
|
+
time.Second, "Measurement interval")
|
52
|
+
flag.BoolVar(&option.no_interval_backoff, "no-interval-backoff",
|
53
|
+
false, "Disable interval backoff")
|
54
|
+
flag.DurationVar(&option.timeout, "timeout",
|
55
|
+
time.Second*0, "Measurement timeout")
|
56
|
+
flag.DurationVar(&option.start_delay, "start-delay",
|
57
|
+
time.Second*0, "Wait time before measurement")
|
58
|
+
flag.StringVar(&option.output, "output",
|
59
|
+
"-", "Output file name")
|
60
|
+
flag.BoolVar(&option.no_cpu, "no-cpu",
|
61
|
+
false, "Do not record CPU usage")
|
62
|
+
flag.BoolVar(&option.no_disk, "no-disk",
|
63
|
+
false, "Do not record disk usage")
|
64
|
+
flag.BoolVar(&option.no_net, "no-net",
|
65
|
+
false, "Do not record net usage")
|
66
|
+
flag.BoolVar(&option.debug, "debug",
|
67
|
+
false, "Enable debug mode")
|
68
|
+
flag.BoolVar(&option.listDevices, "list-devices",
|
69
|
+
false, "List devices and exits")
|
70
|
+
flag.StringVar(&option.disks, "disks",
|
71
|
+
"", "Disk devices to be monitored")
|
72
|
+
flag.StringVar(&option.player_bin, "player-bin",
|
73
|
+
"", "Run perfmonger-player to show JSON output")
|
74
|
+
|
75
|
+
flag.Parse()
|
76
|
+
|
77
|
+
if option.player_bin == "" && terminal.IsTerminal(int(os.Stdout.Fd())) &&
|
78
|
+
option.output == "-" {
|
79
|
+
fmt.Fprintf(os.Stderr, "[recording to data.pgr]\n")
|
80
|
+
option.output = "data.pgr"
|
81
|
+
}
|
82
|
+
|
83
|
+
if option.disks == "" {
|
84
|
+
option.targetDisks = nil
|
85
|
+
} else {
|
86
|
+
option.targetDisks = new(map[string]bool)
|
87
|
+
*option.targetDisks = make(map[string]bool)
|
88
|
+
for _, dev := range strings.Split(option.disks, ",") {
|
89
|
+
(*option.targetDisks)[dev] = true
|
90
|
+
}
|
91
|
+
}
|
92
|
+
|
93
|
+
if option.debug {
|
94
|
+
os.Stderr.WriteString(
|
95
|
+
fmt.Sprintf(
|
96
|
+
`== option
|
97
|
+
- output : %s
|
98
|
+
- interval : %s
|
99
|
+
- debug : %t
|
100
|
+
- remainings: %s
|
101
|
+
`,
|
102
|
+
option.output,
|
103
|
+
option.interval.String(),
|
104
|
+
option.debug,
|
105
|
+
fmt.Sprint(flag.Args())))
|
106
|
+
}
|
107
|
+
}
|
108
|
+
|
109
|
+
func main() {
|
110
|
+
var enc *gob.Encoder
|
111
|
+
var out *bufio.Writer
|
112
|
+
var err error
|
113
|
+
|
114
|
+
parseArgs()
|
115
|
+
|
116
|
+
hostname, _ := os.Hostname()
|
117
|
+
cheader := &ss.CommonHeader{ss.Linux, hostname, time.Now()}
|
118
|
+
|
119
|
+
platform_header := ss.NewPlatformHeader()
|
120
|
+
|
121
|
+
if option.listDevices {
|
122
|
+
for _, name := range platform_header.DevsParts {
|
123
|
+
os.Stderr.WriteString(name + "\n")
|
124
|
+
}
|
125
|
+
return
|
126
|
+
}
|
127
|
+
|
128
|
+
var player_cmd *exec.Cmd = nil
|
129
|
+
var player_stdin io.WriteCloser = nil
|
130
|
+
var player_stdout io.ReadCloser = nil
|
131
|
+
|
132
|
+
if option.player_bin != "" {
|
133
|
+
player_cmd = exec.Command(option.player_bin)
|
134
|
+
player_stdin, err = player_cmd.StdinPipe()
|
135
|
+
if err != nil {
|
136
|
+
fmt.Fprintf(os.Stderr, "Failed to get stdin of %s", option.player_bin)
|
137
|
+
player_cmd = nil
|
138
|
+
player_stdin = nil
|
139
|
+
}
|
140
|
+
player_stdout, err = player_cmd.StdoutPipe()
|
141
|
+
if err != nil {
|
142
|
+
fmt.Fprintf(os.Stderr, "Failed to get stdout of %s", option.player_bin)
|
143
|
+
player_cmd = nil
|
144
|
+
player_stdin = nil
|
145
|
+
player_stdout = nil
|
146
|
+
}
|
147
|
+
|
148
|
+
err = player_cmd.Start()
|
149
|
+
if err != nil {
|
150
|
+
fmt.Fprintf(os.Stderr, "Failed to start %s", option.player_bin)
|
151
|
+
player_cmd = nil
|
152
|
+
player_stdin = nil
|
153
|
+
player_stdout = nil
|
154
|
+
}
|
155
|
+
|
156
|
+
// read stdout of player and write to stdout
|
157
|
+
go func() {
|
158
|
+
var buf = make([]byte, 4096)
|
159
|
+
for {
|
160
|
+
n, err := player_stdout.Read(buf)
|
161
|
+
if err == io.EOF {
|
162
|
+
break
|
163
|
+
} else if err != nil {
|
164
|
+
panic(err)
|
165
|
+
}
|
166
|
+
|
167
|
+
if n == 0 {
|
168
|
+
continue
|
169
|
+
}
|
170
|
+
os.Stdout.Write(buf[0:n])
|
171
|
+
}
|
172
|
+
}()
|
173
|
+
}
|
174
|
+
|
175
|
+
if option.output == "-" {
|
176
|
+
out = bufio.NewWriter(os.Stdout)
|
177
|
+
if player_stdin != nil {
|
178
|
+
out = bufio.NewWriter(player_stdin)
|
179
|
+
}
|
180
|
+
} else {
|
181
|
+
file, err := os.Create(option.output)
|
182
|
+
if err != nil {
|
183
|
+
panic(err)
|
184
|
+
}
|
185
|
+
defer file.Close()
|
186
|
+
|
187
|
+
if player_stdin != nil {
|
188
|
+
out = bufio.NewWriter(io.MultiWriter(file, player_stdin))
|
189
|
+
} else {
|
190
|
+
out = bufio.NewWriter(file)
|
191
|
+
}
|
192
|
+
}
|
193
|
+
|
194
|
+
enc = gob.NewEncoder(out)
|
195
|
+
|
196
|
+
// Write the beginning sections
|
197
|
+
err = enc.Encode(cheader)
|
198
|
+
if err != nil {
|
199
|
+
panic(err)
|
200
|
+
}
|
201
|
+
|
202
|
+
err = enc.Encode(platform_header)
|
203
|
+
if err != nil {
|
204
|
+
panic(err)
|
205
|
+
}
|
206
|
+
|
207
|
+
// start delay
|
208
|
+
time.Sleep(option.start_delay)
|
209
|
+
|
210
|
+
var timeout_ch <-chan time.Time
|
211
|
+
var timeout_time time.Time
|
212
|
+
if option.timeout == time.Second*0 {
|
213
|
+
// dummy channel
|
214
|
+
timeout_ch = make(<-chan time.Time)
|
215
|
+
timeout_time = time.Now()
|
216
|
+
} else {
|
217
|
+
timeout_ch = time.After(option.timeout)
|
218
|
+
timeout_time = time.Now().Add(option.timeout)
|
219
|
+
}
|
220
|
+
|
221
|
+
// Loops
|
222
|
+
sigint_ch := make(chan os.Signal, 1)
|
223
|
+
running := true
|
224
|
+
next_time := time.Now()
|
225
|
+
record := ss.NewStatRecord()
|
226
|
+
backoff_counter := 0
|
227
|
+
|
228
|
+
// cause SIGINT to break loop
|
229
|
+
signal.Notify(sigint_ch, os.Interrupt)
|
230
|
+
|
231
|
+
for {
|
232
|
+
record.Time = time.Now()
|
233
|
+
|
234
|
+
if !option.no_cpu {
|
235
|
+
ss.ReadCpuStat(record)
|
236
|
+
}
|
237
|
+
if !option.no_disk {
|
238
|
+
ss.ReadDiskStats(record, option.targetDisks)
|
239
|
+
}
|
240
|
+
if !option.no_net {
|
241
|
+
ss.ReadNetStat(record)
|
242
|
+
}
|
243
|
+
|
244
|
+
err = enc.Encode(record)
|
245
|
+
if err != nil {
|
246
|
+
break
|
247
|
+
}
|
248
|
+
out.Flush()
|
249
|
+
|
250
|
+
if !running {
|
251
|
+
break
|
252
|
+
}
|
253
|
+
|
254
|
+
if !option.no_interval_backoff {
|
255
|
+
backoff_counter++
|
256
|
+
if backoff_counter >= BACKOFF_THRESH {
|
257
|
+
backoff_counter -= BACKOFF_THRESH
|
258
|
+
|
259
|
+
option.interval *= BACKOFF_RATIO
|
260
|
+
if option.interval.Seconds() > 3600.0 {
|
261
|
+
option.interval = time.Hour
|
262
|
+
}
|
263
|
+
}
|
264
|
+
}
|
265
|
+
|
266
|
+
next_time = next_time.Add(option.interval)
|
267
|
+
|
268
|
+
// wait for next iteration
|
269
|
+
select {
|
270
|
+
case <-sigint_ch:
|
271
|
+
running = false
|
272
|
+
break
|
273
|
+
case <-timeout_ch:
|
274
|
+
running = false
|
275
|
+
break
|
276
|
+
case <-time.After(next_time.Sub(time.Now())):
|
277
|
+
break
|
278
|
+
}
|
279
|
+
|
280
|
+
// If next_time and timeout_time is very close,
|
281
|
+
// avoid recording twice in a very short time
|
282
|
+
if option.timeout != time.Second*0 &&
|
283
|
+
timeout_time.Sub(next_time).Seconds() < 0.01 {
|
284
|
+
running = false
|
285
|
+
}
|
286
|
+
}
|
287
|
+
|
288
|
+
out.Flush()
|
289
|
+
|
290
|
+
if player_stdin != nil {
|
291
|
+
player_stdin.Close()
|
292
|
+
_ = player_cmd.Wait()
|
293
|
+
}
|
294
|
+
|
295
|
+
return
|
296
|
+
}
|
@@ -0,0 +1,207 @@
|
|
1
|
+
//usr/bin/env go run $0 $@ ; exit
|
2
|
+
|
3
|
+
package main
|
4
|
+
|
5
|
+
import (
|
6
|
+
"bytes"
|
7
|
+
"encoding/gob"
|
8
|
+
"flag"
|
9
|
+
"fmt"
|
10
|
+
"io"
|
11
|
+
"os"
|
12
|
+
"sort"
|
13
|
+
|
14
|
+
ss "github.com/hayamiz/perfmonger/core/subsystem"
|
15
|
+
)
|
16
|
+
|
17
|
+
type SummaryOption struct {
|
18
|
+
logfile string
|
19
|
+
title string
|
20
|
+
json bool
|
21
|
+
}
|
22
|
+
|
23
|
+
var option SummaryOption
|
24
|
+
|
25
|
+
func parseArgs() {
|
26
|
+
flag.BoolVar(&option.json, "json",
|
27
|
+
false, "Show summary in JSON")
|
28
|
+
flag.StringVar(&option.title, "title",
|
29
|
+
"", "Title of summary")
|
30
|
+
|
31
|
+
flag.Parse()
|
32
|
+
|
33
|
+
if len(flag.Args()) < 1 {
|
34
|
+
os.Exit(1)
|
35
|
+
}
|
36
|
+
|
37
|
+
option.logfile = flag.Args()[0]
|
38
|
+
}
|
39
|
+
|
40
|
+
func main() {
|
41
|
+
var cheader ss.CommonHeader
|
42
|
+
var pheader ss.PlatformHeader
|
43
|
+
|
44
|
+
parseArgs()
|
45
|
+
|
46
|
+
f, err := os.Open(option.logfile)
|
47
|
+
if err != nil {
|
48
|
+
panic(err)
|
49
|
+
}
|
50
|
+
dec := gob.NewDecoder(f)
|
51
|
+
|
52
|
+
err = dec.Decode(&cheader)
|
53
|
+
if err == io.EOF {
|
54
|
+
return
|
55
|
+
}
|
56
|
+
if err != nil {
|
57
|
+
panic(err)
|
58
|
+
}
|
59
|
+
err = dec.Decode(&pheader)
|
60
|
+
if err == io.EOF {
|
61
|
+
return
|
62
|
+
}
|
63
|
+
if err != nil {
|
64
|
+
panic(err)
|
65
|
+
}
|
66
|
+
|
67
|
+
var fst_record ss.StatRecord
|
68
|
+
// read first record
|
69
|
+
err = dec.Decode(&fst_record)
|
70
|
+
if err == io.EOF {
|
71
|
+
return
|
72
|
+
} else if err != nil {
|
73
|
+
panic(err)
|
74
|
+
}
|
75
|
+
|
76
|
+
// loop until last line
|
77
|
+
var lst_records [2]ss.StatRecord
|
78
|
+
idx := 0
|
79
|
+
for {
|
80
|
+
err = dec.Decode(&lst_records[idx])
|
81
|
+
if err == io.EOF {
|
82
|
+
idx ^= 1
|
83
|
+
break
|
84
|
+
} else if err != nil {
|
85
|
+
panic(err)
|
86
|
+
}
|
87
|
+
|
88
|
+
idx ^= 1
|
89
|
+
}
|
90
|
+
|
91
|
+
lst_record := lst_records[idx]
|
92
|
+
|
93
|
+
var cpu_usage *ss.CpuUsage = nil
|
94
|
+
var disk_usage *ss.DiskUsage = nil
|
95
|
+
var net_usage *ss.NetUsage = nil
|
96
|
+
|
97
|
+
if fst_record.Cpu != nil && lst_record.Cpu != nil {
|
98
|
+
cpu_usage, err = ss.GetCpuUsage(fst_record.Cpu, lst_record.Cpu)
|
99
|
+
}
|
100
|
+
|
101
|
+
if fst_record.Disk != nil && lst_record.Disk != nil {
|
102
|
+
disk_usage, err = ss.GetDiskUsage(
|
103
|
+
fst_record.Time, fst_record.Disk,
|
104
|
+
lst_record.Time, lst_record.Disk)
|
105
|
+
}
|
106
|
+
|
107
|
+
if fst_record.Disk != nil && lst_record.Disk != nil {
|
108
|
+
net_usage, err = ss.GetNetUsage(
|
109
|
+
fst_record.Time, fst_record.Net,
|
110
|
+
lst_record.Time, lst_record.Net)
|
111
|
+
}
|
112
|
+
|
113
|
+
interval := lst_record.Time.Sub(fst_record.Time)
|
114
|
+
|
115
|
+
if option.json {
|
116
|
+
buf := bytes.NewBuffer([]byte{})
|
117
|
+
|
118
|
+
buf.WriteString(fmt.Sprintf(`{"exectime":%.3f`, interval.Seconds()))
|
119
|
+
if cpu_usage != nil {
|
120
|
+
buf.WriteString(`,"cpu":`)
|
121
|
+
cpu_usage.WriteJsonTo(buf)
|
122
|
+
}
|
123
|
+
|
124
|
+
if disk_usage != nil {
|
125
|
+
buf.WriteString(`,"disk":`)
|
126
|
+
disk_usage.WriteJsonTo(buf)
|
127
|
+
}
|
128
|
+
|
129
|
+
if disk_usage != nil {
|
130
|
+
buf.WriteString(`,"net":`)
|
131
|
+
net_usage.WriteJsonTo(buf)
|
132
|
+
}
|
133
|
+
|
134
|
+
buf.WriteByte('}')
|
135
|
+
|
136
|
+
fmt.Println(buf.String())
|
137
|
+
} else {
|
138
|
+
if option.title == "" {
|
139
|
+
fmt.Println("== performance summary ==")
|
140
|
+
} else {
|
141
|
+
fmt.Printf("== performance summary of '%s' ==\n", option.title)
|
142
|
+
}
|
143
|
+
fmt.Printf(`
|
144
|
+
Duration: %.3f sec
|
145
|
+
|
146
|
+
`,
|
147
|
+
interval.Seconds())
|
148
|
+
if cpu_usage != nil {
|
149
|
+
fmt.Printf(`* Average CPU usage (MAX: %d %%)
|
150
|
+
* Non-idle usage: %.2f %%
|
151
|
+
%%usr: %.2f %%
|
152
|
+
%%sys: %.2f %%
|
153
|
+
%%irq: %.2f %%
|
154
|
+
%%soft: %.2f %%
|
155
|
+
%%other: %.2f %%
|
156
|
+
* Idle usage: %.2f %%
|
157
|
+
%%iowait: %.2f %%
|
158
|
+
%%idle: %.2f %%
|
159
|
+
|
160
|
+
`,
|
161
|
+
100*cpu_usage.NumCore,
|
162
|
+
100.0*float64(cpu_usage.NumCore)-cpu_usage.All.Idle-cpu_usage.All.Iowait,
|
163
|
+
cpu_usage.All.User+cpu_usage.All.Nice,
|
164
|
+
cpu_usage.All.Sys,
|
165
|
+
cpu_usage.All.Hardirq,
|
166
|
+
cpu_usage.All.Softirq,
|
167
|
+
cpu_usage.All.Steal,
|
168
|
+
cpu_usage.All.Idle+cpu_usage.All.Iowait,
|
169
|
+
cpu_usage.All.Iowait, cpu_usage.All.Idle)
|
170
|
+
}
|
171
|
+
|
172
|
+
if disk_usage != nil {
|
173
|
+
devices := []string{}
|
174
|
+
|
175
|
+
for device, _ := range *disk_usage {
|
176
|
+
if device != "total" {
|
177
|
+
devices = append(devices, device)
|
178
|
+
}
|
179
|
+
}
|
180
|
+
sort.Strings(devices)
|
181
|
+
if len(devices) > 1 {
|
182
|
+
devices = append(devices, "total")
|
183
|
+
}
|
184
|
+
|
185
|
+
for _, device := range devices {
|
186
|
+
e := (*disk_usage)[device]
|
187
|
+
fmt.Printf(`* Average DEVICE usage: %s
|
188
|
+
read IOPS: %.2f
|
189
|
+
write IOPS: %.2f
|
190
|
+
read throughput: %.2f MB/s
|
191
|
+
write throughput: %.2f MB/s
|
192
|
+
read latency: %.1f usec
|
193
|
+
write latency: %.1f usec
|
194
|
+
read amount: %.2f MB
|
195
|
+
write amount: %.2f MB
|
196
|
+
|
197
|
+
`,
|
198
|
+
device,
|
199
|
+
e.RdIops, e.WrIops,
|
200
|
+
e.RdSecps*512.0/1024.0/1024.0, e.WrSecps*512.0/1024.0/1024.0,
|
201
|
+
e.RdLatency*1000.0, e.WrLatency*1000.0,
|
202
|
+
float64(e.RdSectors*512)/1024.0/1024.0,
|
203
|
+
float64(e.WrSectors*512)/1024.0/1024.0)
|
204
|
+
}
|
205
|
+
}
|
206
|
+
}
|
207
|
+
}
|
@@ -0,0 +1,60 @@
|
|
1
|
+
package subsystem
|
2
|
+
|
3
|
+
import (
|
4
|
+
"time"
|
5
|
+
)
|
6
|
+
|
7
|
+
/*
|
8
|
+
|
9
|
+
PerfMonger binary format:
|
10
|
+
|
11
|
+
1. Common header
|
12
|
+
* platform type tag
|
13
|
+
* host info
|
14
|
+
* timestamp
|
15
|
+
* ...
|
16
|
+
2. Platform-dependent header
|
17
|
+
* List of devices
|
18
|
+
* List of NICs
|
19
|
+
* List of IRQs
|
20
|
+
* CPU topology
|
21
|
+
* ...
|
22
|
+
3. Record section
|
23
|
+
* Platform-dependent record data stream
|
24
|
+
|
25
|
+
*/
|
26
|
+
|
27
|
+
//
|
28
|
+
// Common header
|
29
|
+
//
|
30
|
+
|
31
|
+
const (
|
32
|
+
Linux = 1
|
33
|
+
Darwin = 2
|
34
|
+
)
|
35
|
+
|
36
|
+
type PlatformType int
|
37
|
+
|
38
|
+
type CommonHeader struct {
|
39
|
+
Platform PlatformType
|
40
|
+
Hostname string
|
41
|
+
StartTime time.Time
|
42
|
+
}
|
43
|
+
|
44
|
+
//
|
45
|
+
// Platform-dependent header
|
46
|
+
//
|
47
|
+
|
48
|
+
type LinuxDevice struct {
|
49
|
+
Name string
|
50
|
+
Parts []string
|
51
|
+
}
|
52
|
+
|
53
|
+
type LinuxHeader struct {
|
54
|
+
Devices map[string]LinuxDevice
|
55
|
+
DevsParts []string
|
56
|
+
}
|
57
|
+
|
58
|
+
type DarwinHeader struct {
|
59
|
+
DevsParts []string
|
60
|
+
}
|
@@ -0,0 +1,22 @@
|
|
1
|
+
// +build darwin
|
2
|
+
|
3
|
+
package subsystem
|
4
|
+
|
5
|
+
type PlatformHeader DarwinHeader
|
6
|
+
|
7
|
+
func NewPlatformHeader() *DarwinHeader {
|
8
|
+
header := new(DarwinHeader)
|
9
|
+
return header
|
10
|
+
}
|
11
|
+
|
12
|
+
func ReadCpuStat(record *StatRecord) error {
|
13
|
+
return nil
|
14
|
+
}
|
15
|
+
|
16
|
+
func ReadDiskStats(record *StatRecord, targets *map[string]bool) error {
|
17
|
+
return nil
|
18
|
+
}
|
19
|
+
|
20
|
+
func ReadNetStat(record *StatRecord) error {
|
21
|
+
return nil
|
22
|
+
}
|