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.
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
+ }