perfmonger 0.6.1 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (87) hide show
  1. checksums.yaml +5 -13
  2. data/.gitignore +6 -0
  3. data/.tachikoma.yml +1 -0
  4. data/.travis.yml +18 -6
  5. data/Gemfile +1 -3
  6. data/Guardfile +26 -0
  7. data/NEWS +21 -0
  8. data/README.md +8 -9
  9. data/Rakefile +33 -1
  10. data/core/Makefile +23 -0
  11. data/core/build.sh +48 -0
  12. data/core/perfmonger-player.go +165 -0
  13. data/core/perfmonger-recorder.go +296 -0
  14. data/core/perfmonger-summarizer.go +207 -0
  15. data/core/subsystem/Makefile +3 -0
  16. data/core/subsystem/perfmonger.go +60 -0
  17. data/core/subsystem/perfmonger_darwin.go +22 -0
  18. data/core/subsystem/perfmonger_linux.go +292 -0
  19. data/core/subsystem/perfmonger_linux_test.go +73 -0
  20. data/core/subsystem/stat.go +214 -0
  21. data/core/subsystem/stat_test.go +281 -0
  22. data/core/subsystem/usage.go +410 -0
  23. data/core/subsystem/usage_test.go +496 -0
  24. data/lib/exec/operationBinding.rb.svn-base +59 -0
  25. data/lib/exec/perfmonger-player_darwin_amd64 +0 -0
  26. data/lib/exec/perfmonger-player_linux_386 +0 -0
  27. data/lib/exec/perfmonger-player_linux_amd64 +0 -0
  28. data/lib/exec/perfmonger-recorder_darwin_amd64 +0 -0
  29. data/lib/exec/perfmonger-recorder_linux_386 +0 -0
  30. data/lib/exec/perfmonger-recorder_linux_amd64 +0 -0
  31. data/lib/exec/perfmonger-summarizer_darwin_amd64 +0 -0
  32. data/lib/exec/perfmonger-summarizer_linux_386 +0 -0
  33. data/lib/exec/perfmonger-summarizer_linux_amd64 +0 -0
  34. data/lib/exec/perfmonger-summary_linux_386 +0 -0
  35. data/lib/exec/perfmonger-summary_linux_amd64 +0 -0
  36. data/lib/perfmonger/cli.rb +8 -3
  37. data/lib/perfmonger/command/core.rb +62 -0
  38. data/lib/perfmonger/command/live.rb +39 -0
  39. data/lib/perfmonger/command/play.rb +56 -0
  40. data/lib/perfmonger/command/plot.rb +30 -22
  41. data/lib/perfmonger/command/record.rb +3 -2
  42. data/lib/perfmonger/command/record_option.rb +40 -59
  43. data/lib/perfmonger/command/server.rb +7 -2
  44. data/lib/perfmonger/command/stat.rb +2 -2
  45. data/lib/perfmonger/command/stat_option.rb +1 -1
  46. data/lib/perfmonger/command/summary.rb +11 -326
  47. data/lib/perfmonger/version.rb +1 -3
  48. data/lib/perfmonger.rb +3 -0
  49. data/misc/_perfmonger +128 -0
  50. data/misc/perfmonger-completion.bash +49 -0
  51. data/perfmonger.gemspec +6 -5
  52. data/spec/data/busy100.pgr +0 -0
  53. data/spec/fingerprint_spec.rb +35 -0
  54. data/spec/live_spec.rb +25 -0
  55. data/spec/perfmonger_spec.rb +37 -0
  56. data/spec/play_spec.rb +21 -0
  57. data/spec/plot_spec.rb +42 -0
  58. data/spec/record_spec.rb +15 -0
  59. data/spec/spec_helper.rb +33 -0
  60. data/spec/stat_spec.rb +15 -0
  61. data/spec/summary_spec.rb +51 -0
  62. data/spec/support/aruba.rb +11 -0
  63. data/wercker.yml +59 -0
  64. metadata +117 -45
  65. data/ext/perfmonger/extconf.rb +0 -19
  66. data/ext/perfmonger/perfmonger.h +0 -58
  67. data/ext/perfmonger/perfmonger_record.c +0 -754
  68. data/ext/perfmonger/sysstat/common.c +0 -627
  69. data/ext/perfmonger/sysstat/common.h +0 -207
  70. data/ext/perfmonger/sysstat/ioconf.c +0 -515
  71. data/ext/perfmonger/sysstat/ioconf.h +0 -84
  72. data/ext/perfmonger/sysstat/iostat.c +0 -1100
  73. data/ext/perfmonger/sysstat/iostat.h +0 -121
  74. data/ext/perfmonger/sysstat/libsysstat.h +0 -19
  75. data/ext/perfmonger/sysstat/mpstat.c +0 -953
  76. data/ext/perfmonger/sysstat/mpstat.h +0 -79
  77. data/ext/perfmonger/sysstat/rd_stats.c +0 -2388
  78. data/ext/perfmonger/sysstat/rd_stats.h +0 -651
  79. data/ext/perfmonger/sysstat/sysconfig.h +0 -13
  80. data/test/run-test.sh +0 -39
  81. data/test/spec/bin_spec.rb +0 -37
  82. data/test/spec/data/2devices.expected +0 -42
  83. data/test/spec/data/2devices.output +0 -42
  84. data/test/spec/spec_helper.rb +0 -20
  85. data/test/spec/summary_spec.rb +0 -193
  86. data/test/test-perfmonger.c +0 -145
  87. data/test/test.h +0 -9
@@ -0,0 +1,292 @@
1
+ // +build linux
2
+
3
+ package subsystem
4
+
5
+ import (
6
+ "bufio"
7
+ "errors"
8
+ "fmt"
9
+ "io"
10
+ "os"
11
+ "runtime"
12
+ )
13
+
14
+ type PlatformHeader LinuxHeader
15
+
16
+ func NewPlatformHeader() *LinuxHeader {
17
+ header := new(LinuxHeader)
18
+ header.Devices = make(map[string]LinuxDevice)
19
+
20
+ header.getDevsParts()
21
+
22
+ return header
23
+ }
24
+
25
+ func (header *LinuxHeader) getDevsParts() {
26
+ f, err := os.Open("/proc/diskstats")
27
+ if err != nil {
28
+ panic(err)
29
+ }
30
+ defer f.Close()
31
+ scan := bufio.NewScanner(f)
32
+ for scan.Scan() {
33
+ var major, minor int
34
+ var name string
35
+ c, err := fmt.Sscanf(scan.Text(), "%d %d %s", &major, &minor, &name)
36
+ if err != nil {
37
+ panic(err)
38
+ }
39
+ if c != 3 {
40
+ continue
41
+ }
42
+
43
+ header.DevsParts = append(header.DevsParts, name)
44
+
45
+ if isDevice(name) {
46
+ header.Devices[name] = LinuxDevice{
47
+ name, getPartitions(name),
48
+ }
49
+ }
50
+ }
51
+ }
52
+
53
+ func isDevice(name string) bool {
54
+ stat, err := os.Stat(fmt.Sprintf("/sys/block/%s", name))
55
+ if err == nil && stat.IsDir() {
56
+ return true
57
+ }
58
+
59
+ return false
60
+ }
61
+
62
+ func getPartitions(name string) []string {
63
+ var dir *os.File
64
+ var fis []os.FileInfo
65
+ var err error
66
+ var parts = []string{}
67
+
68
+ dir, err = os.Open(fmt.Sprintf("/sys/block/%s", name))
69
+ if err != nil {
70
+ panic(err)
71
+ }
72
+ fis, err = dir.Readdir(0)
73
+ if err != nil {
74
+ panic(err)
75
+ }
76
+ for _, fi := range fis {
77
+ _, err := os.Stat(fmt.Sprintf("/sys/block/%s/%s/stat", name, fi.Name()))
78
+ if err == nil {
79
+ // partition exists
80
+ parts = append(parts, fi.Name())
81
+ }
82
+ }
83
+
84
+ return parts
85
+ }
86
+
87
+ func ReadCpuStat(record *StatRecord) error {
88
+ f, ferr := os.Open("/proc/stat")
89
+ if ferr != nil {
90
+ return ferr
91
+ }
92
+ defer f.Close()
93
+
94
+ if record.Cpu == nil {
95
+ record.Cpu = NewCpuStat(runtime.NumCPU())
96
+ } else {
97
+ record.Cpu.Clear()
98
+ }
99
+
100
+ if record.Proc == nil {
101
+ record.Proc = NewProcStat()
102
+ } else {
103
+ record.Proc.Clear()
104
+ }
105
+
106
+ scan := bufio.NewScanner(f)
107
+ for scan.Scan() {
108
+ var err error
109
+ var cpu string
110
+ line := scan.Text()
111
+ if line[0:4] == "cpu " {
112
+ _, err = fmt.Sscanf(line,
113
+ "%s %d %d %d %d %d %d %d %d %d %d",
114
+ &cpu,
115
+ &record.Cpu.All.User,
116
+ &record.Cpu.All.Nice,
117
+ &record.Cpu.All.Sys,
118
+ &record.Cpu.All.Idle,
119
+ &record.Cpu.All.Iowait,
120
+ &record.Cpu.All.Hardirq,
121
+ &record.Cpu.All.Softirq,
122
+ &record.Cpu.All.Steal,
123
+ &record.Cpu.All.Guest,
124
+ &record.Cpu.All.GuestNice)
125
+ if err != nil {
126
+ return err
127
+ }
128
+ } else if line[0:3] == "cpu" {
129
+ var n_core int
130
+ var core_stat *CpuCoreStat
131
+ // assume n_core < 10000
132
+ _, err = fmt.Sscanf(line[3:7], "%d", &n_core)
133
+ if err != nil {
134
+ return err
135
+ }
136
+
137
+ core_stat = &record.Cpu.CoreStats[n_core]
138
+ _, err = fmt.Sscanf(line,
139
+ "%s %d %d %d %d %d %d %d %d %d %d",
140
+ &cpu,
141
+ &core_stat.User,
142
+ &core_stat.Nice,
143
+ &core_stat.Sys,
144
+ &core_stat.Idle,
145
+ &core_stat.Iowait,
146
+ &core_stat.Hardirq,
147
+ &core_stat.Softirq,
148
+ &core_stat.Steal,
149
+ &core_stat.Guest,
150
+ &core_stat.GuestNice)
151
+ if err != nil {
152
+ return err
153
+ }
154
+ } else if line[0:5] == "ctxt " {
155
+ _, err = fmt.Sscanf(line[4:], "%d", &record.Proc.ContextSwitch)
156
+ if err != nil {
157
+ return err
158
+ }
159
+ } else if line[0:10] == "processes " {
160
+ _, err = fmt.Sscanf(line[10:], "%d", &record.Proc.Fork)
161
+ if err != nil {
162
+ return err
163
+ }
164
+ }
165
+ }
166
+
167
+ return nil
168
+ }
169
+
170
+ func ReadDiskStats(record *StatRecord, targets *map[string]bool) error {
171
+ if record == nil {
172
+ return errors.New("Valid *StatRecord is required.")
173
+ }
174
+
175
+ f, ferr := os.Open("/proc/diskstats")
176
+ if ferr != nil {
177
+ panic(ferr)
178
+ }
179
+ defer f.Close()
180
+
181
+ if record.Disk == nil {
182
+ record.Disk = NewDiskStat()
183
+ } else {
184
+ record.Disk.Clear()
185
+ }
186
+
187
+ scan := bufio.NewScanner(f)
188
+
189
+ var num_items int
190
+ var err error
191
+ for scan.Scan() {
192
+ var rdmerge_or_rdsec int64
193
+ var rdsec_or_wrios int64
194
+ var rdticks_or_wrsec int64
195
+
196
+ line := scan.Text()
197
+ entry := NewDiskStatEntry()
198
+
199
+ num_items, err = fmt.Sscanf(line,
200
+ "%d %d %s %d %d %d %d %d %d %d %d %d %d %d",
201
+ &entry.Major, &entry.Minor, &entry.Name,
202
+ &entry.RdIos, &rdmerge_or_rdsec, &rdsec_or_wrios, &rdticks_or_wrsec,
203
+ &entry.WrIos, &entry.WrMerges, &entry.WrSectors, &entry.WrTicks,
204
+ &entry.IosPgr, &entry.TotalTicks, &entry.ReqTicks)
205
+ if err != nil {
206
+ return err
207
+ }
208
+
209
+ if num_items == 14 {
210
+ entry.RdMerges = rdmerge_or_rdsec
211
+ entry.RdSectors = rdsec_or_wrios
212
+ entry.RdTicks = rdticks_or_wrsec
213
+ } else if num_items == 7 {
214
+ entry.RdSectors = rdmerge_or_rdsec
215
+ entry.WrIos = rdsec_or_wrios
216
+ entry.WrSectors = rdticks_or_wrsec
217
+ } else {
218
+ continue
219
+ }
220
+
221
+ if entry.RdIos == 0 && entry.WrIos == 0 {
222
+ continue
223
+ }
224
+
225
+ if targets != nil {
226
+ if _, ok := (*targets)[entry.Name]; !ok {
227
+ // device not in targets
228
+ continue
229
+ }
230
+ } else {
231
+ if !isDevice(entry.Name) {
232
+ continue
233
+ }
234
+ }
235
+
236
+ record.Disk.Entries = append(record.Disk.Entries, entry)
237
+ }
238
+
239
+ return nil
240
+ }
241
+
242
+ func ReadNetStat(record *StatRecord) error {
243
+ if record == nil {
244
+ return errors.New("Valid *StatRecord is required.")
245
+ }
246
+
247
+ net_stat := NewNetStat()
248
+
249
+ f, err := os.Open("/proc/net/dev")
250
+ if err != nil {
251
+ return err
252
+ }
253
+ defer f.Close()
254
+ scanner := bufio.NewScanner(f)
255
+
256
+ for scanner.Scan() {
257
+ line := scanner.Text()
258
+ switch {
259
+ case line[0:7] == "Inter-|":
260
+ continue
261
+ case line[0:7] == " face |":
262
+ continue
263
+ }
264
+
265
+ e := NewNetStatEntry()
266
+
267
+ var devname string
268
+ n, err := fmt.Sscanf(line,
269
+ "%s %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d", &devname,
270
+ &e.RxBytes, &e.RxPackets, &e.RxErrors, &e.RxDrops,
271
+ &e.RxFifo, &e.RxFrame, &e.RxCompressed, &e.RxMulticast,
272
+ &e.TxBytes, &e.TxPackets, &e.TxErrors, &e.TxDrops,
273
+ &e.TxFifo, &e.TxFrame, &e.TxCompressed, &e.TxMulticast)
274
+ if err == io.EOF {
275
+ break
276
+ } else if err != nil {
277
+ return err
278
+ }
279
+ if n != 17 {
280
+ continue
281
+ }
282
+
283
+ // trim trailing ":" from devname
284
+ e.Name = devname[0 : len(devname)-1]
285
+
286
+ net_stat.Entries = append(net_stat.Entries, e)
287
+ }
288
+
289
+ record.Net = net_stat
290
+
291
+ return nil
292
+ }
@@ -0,0 +1,73 @@
1
+ package subsystem
2
+
3
+ import (
4
+ "os"
5
+ "testing"
6
+ )
7
+
8
+ func TestReadDiskStat(t *testing.T) {
9
+ var err error
10
+ var stat_record *StatRecord = nil
11
+
12
+ err = ReadDiskStats(stat_record, nil)
13
+ if err == nil {
14
+ t.Errorf("Error should be returned with nil *StatRecord.")
15
+ }
16
+
17
+ _, err = os.Stat("/proc/diskstats")
18
+ if err != nil {
19
+ t.Skip("/proc/diskstats is not present.")
20
+ }
21
+
22
+ stat_record = NewStatRecord()
23
+ err = ReadDiskStats(stat_record, nil)
24
+ if err != nil {
25
+ t.Error("Error should not be returned with valid *StatRecord")
26
+ }
27
+ if stat_record.Disk == nil {
28
+ t.Error("stat_record.Disk should not be nil")
29
+ return
30
+ }
31
+ if len(stat_record.Disk.Entries) == 0 {
32
+ t.Error("No device found.")
33
+ }
34
+ }
35
+
36
+ func TestReadNetStat(t *testing.T) {
37
+ var err error
38
+ var stat_record *StatRecord = nil
39
+
40
+ err = ReadNetStat(stat_record)
41
+ if err == nil {
42
+ t.Errorf("Error should be returned with nil *StatRecord.")
43
+ }
44
+
45
+ _, err = os.Stat("/proc/net/dev")
46
+ if err != nil {
47
+ t.Skip("/proc/net/dev is not present.")
48
+ }
49
+
50
+ stat_record = NewStatRecord()
51
+ err = ReadNetStat(stat_record)
52
+ if err != nil {
53
+ t.Error("Error should not be returned with valid *StatRecord.")
54
+ }
55
+ if stat_record.Net == nil {
56
+ t.Error("stat_record.Net should not be nil")
57
+ return
58
+ }
59
+ if len(stat_record.Net.Entries) == 0 {
60
+ t.Error("No net device found, though every linux host should have 'lo'.")
61
+ }
62
+ // search 'lo'
63
+ lo_found := false
64
+ for _, entry := range stat_record.Net.Entries {
65
+ if entry.Name == "lo" {
66
+ lo_found = true
67
+ break
68
+ }
69
+ }
70
+ if !lo_found {
71
+ t.Error("Device 'lo' not found.")
72
+ }
73
+ }
@@ -0,0 +1,214 @@
1
+ package subsystem
2
+
3
+ import "time"
4
+
5
+ //
6
+ // Record
7
+ //
8
+
9
+ type CpuCoreStat struct {
10
+ User int64
11
+ Nice int64
12
+ Sys int64
13
+ Idle int64
14
+ Iowait int64
15
+ Hardirq int64
16
+ Softirq int64
17
+ Steal int64
18
+ Guest int64
19
+ GuestNice int64
20
+ }
21
+
22
+ type CpuStat struct {
23
+ All CpuCoreStat
24
+ NumCore int
25
+ CoreStats []CpuCoreStat
26
+ }
27
+
28
+ type ProcStat struct {
29
+ ContextSwitch int64
30
+ Fork int64
31
+ }
32
+
33
+ type SoftIrqStat struct {
34
+ Hi int64
35
+ Timer int64
36
+ NetTx int64
37
+ NetRx int64
38
+ Block int64
39
+ BlockIopoll int64
40
+ Tasklet int64
41
+ Sched int64
42
+ Hrtimer int64
43
+ Rcu int64
44
+ }
45
+
46
+ type DiskStatEntry struct {
47
+ Major uint
48
+ Minor uint
49
+ Name string
50
+ RdIos int64
51
+ RdMerges int64
52
+ RdSectors int64
53
+ RdTicks int64
54
+ WrIos int64
55
+ WrMerges int64
56
+ WrSectors int64
57
+ WrTicks int64
58
+ IosPgr int64
59
+ TotalTicks int64
60
+ ReqTicks int64
61
+ }
62
+
63
+ type DiskStat struct {
64
+ Entries []*DiskStatEntry
65
+ }
66
+
67
+ type NetStatEntry struct {
68
+ Name string
69
+ RxBytes int64
70
+ RxPackets int64
71
+ RxErrors int64
72
+ RxDrops int64
73
+ RxFifo int64
74
+ RxFrame int64
75
+ RxCompressed int64
76
+ RxMulticast int64
77
+ TxBytes int64
78
+ TxPackets int64
79
+ TxErrors int64
80
+ TxDrops int64
81
+ TxFifo int64
82
+ TxFrame int64
83
+ TxCompressed int64
84
+ TxMulticast int64
85
+ }
86
+
87
+ type NetStat struct {
88
+ Entries []*NetStatEntry
89
+ }
90
+
91
+ type StatRecord struct {
92
+ Time time.Time
93
+ Cpu *CpuStat
94
+ Proc *ProcStat
95
+ Disk *DiskStat
96
+ Softirq *SoftIrqStat
97
+ Net *NetStat
98
+ }
99
+
100
+ func (core_stat *CpuCoreStat) Clear() {
101
+ core_stat.User = 0
102
+ core_stat.Nice = 0
103
+ core_stat.Sys = 0
104
+ core_stat.Iowait = 0
105
+ core_stat.Steal = 0
106
+ core_stat.Hardirq = 0
107
+ core_stat.Softirq = 0
108
+ core_stat.Guest = 0
109
+ core_stat.GuestNice = 0
110
+ core_stat.Idle = 0
111
+ }
112
+
113
+ func (core_stat *CpuCoreStat) Uptime() int64 {
114
+ // Don't take Guest because User include Guest
115
+ return core_stat.User +
116
+ core_stat.Nice +
117
+ core_stat.Sys +
118
+ core_stat.Iowait +
119
+ core_stat.Steal +
120
+ core_stat.Hardirq +
121
+ core_stat.Softirq +
122
+ core_stat.Idle
123
+ }
124
+
125
+ func NewCpuStat(num_core int) *CpuStat {
126
+ if num_core < 1 {
127
+ return nil
128
+ }
129
+
130
+ cpu_stat := new(CpuStat)
131
+
132
+ cpu_stat.NumCore = num_core
133
+ cpu_stat.CoreStats = make([]CpuCoreStat, num_core)
134
+
135
+ return cpu_stat
136
+ }
137
+
138
+ func (cpu_stat *CpuStat) Clear() {
139
+ cpu_stat.All.Clear()
140
+ for idx, _ := range cpu_stat.CoreStats {
141
+ cpu_stat.CoreStats[idx].Clear()
142
+ }
143
+ }
144
+
145
+ func NewProcStat() *ProcStat {
146
+ return &ProcStat{0, 0}
147
+ }
148
+
149
+ func (proc_stat *ProcStat) Clear() {
150
+ proc_stat.ContextSwitch = 0
151
+ proc_stat.Fork = 0
152
+ }
153
+
154
+ func NewDiskStatEntry() *DiskStatEntry {
155
+ return new(DiskStatEntry)
156
+ }
157
+
158
+ func NewDiskStat() *DiskStat {
159
+ return &DiskStat{[]*DiskStatEntry{}}
160
+ }
161
+
162
+ func (disk_stat *DiskStat) Clear() {
163
+ disk_stat.Entries = []*DiskStatEntry{}
164
+ }
165
+
166
+ func (sirq_stat *SoftIrqStat) Clear() {
167
+ sirq_stat.Hi = 0
168
+ sirq_stat.Timer = 0
169
+ sirq_stat.NetTx = 0
170
+ sirq_stat.NetRx = 0
171
+ sirq_stat.Block = 0
172
+ sirq_stat.BlockIopoll = 0
173
+ sirq_stat.Tasklet = 0
174
+ sirq_stat.Sched = 0
175
+ sirq_stat.Hrtimer = 0
176
+ sirq_stat.Rcu = 0
177
+ }
178
+
179
+ func NewNetStatEntry() *NetStatEntry {
180
+ return new(NetStatEntry)
181
+ }
182
+
183
+ func (entry *NetStatEntry) Clear() {
184
+ entry.Name = ""
185
+ entry.RxBytes = 0
186
+ entry.RxPackets = 0
187
+ entry.RxErrors = 0
188
+ entry.RxDrops = 0
189
+ entry.TxBytes = 0
190
+ entry.TxPackets = 0
191
+ entry.TxErrors = 0
192
+ entry.TxDrops = 0
193
+ }
194
+
195
+ func NewNetStat() *NetStat {
196
+ return new(NetStat)
197
+ }
198
+
199
+ func NewStatRecord() *StatRecord {
200
+ return &StatRecord{
201
+ time.Now(),
202
+ nil,
203
+ nil,
204
+ nil,
205
+ nil,
206
+ nil,
207
+ }
208
+ }
209
+
210
+ func (rec *StatRecord) Clear() {
211
+ rec.Cpu.Clear()
212
+ rec.Proc.Clear()
213
+ rec.Disk.Clear()
214
+ }