perfmonger 0.6.1 → 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
}
|