perfmonger 0.10.1 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +3 -0
  3. data/.travis.yml +9 -8
  4. data/HOWTO.md +0 -1
  5. data/NEWS +47 -3
  6. data/README.md +77 -27
  7. data/Rakefile +20 -9
  8. data/core/Makefile +10 -18
  9. data/core/build.sh +2 -2
  10. data/core/perfmonger-player.go +90 -40
  11. data/core/perfmonger-plot-formatter.go +18 -4
  12. data/core/perfmonger-recorder.go +22 -2
  13. data/core/perfmonger-summarizer.go +20 -14
  14. data/core/perfmonger-viewer.go +164 -0
  15. data/core/subsystem/Makefile +4 -0
  16. data/core/subsystem/perfmonger_linux.go +95 -0
  17. data/core/subsystem/perfmonger_linux_test.go +40 -0
  18. data/core/subsystem/stat.go +70 -0
  19. data/core/subsystem/stat_test.go +9 -0
  20. data/core/subsystem/usage.go +223 -66
  21. data/core/subsystem/usage_test.go +62 -32
  22. data/{bin → exe}/perfmonger +0 -0
  23. data/lib/perfmonger/command/fingerprint.rb +26 -1
  24. data/lib/perfmonger/command/live.rb +19 -0
  25. data/lib/perfmonger/command/play.rb +16 -0
  26. data/lib/perfmonger/command/plot.rb +25 -9
  27. data/lib/perfmonger/command/record.rb +1 -1
  28. data/lib/perfmonger/command/record_option.rb +16 -0
  29. data/lib/perfmonger/command/server.rb +1 -1
  30. data/lib/perfmonger/version.rb +1 -1
  31. data/misc/werker-box/Dockerfile +34 -0
  32. data/misc/werker-box/build-push.sh +7 -0
  33. data/perfmonger.gemspec +2 -1
  34. data/spec/data/busy100.pgr.played +3 -3
  35. data/spec/fingerprint_spec.rb +1 -1
  36. data/spec/live_spec.rb +2 -3
  37. data/spec/perfmonger_spec.rb +1 -1
  38. data/spec/play_spec.rb +1 -1
  39. data/spec/plot_spec.rb +16 -1
  40. data/spec/record_spec.rb +10 -1
  41. data/spec/spec_helper.rb +28 -3
  42. data/spec/stat_spec.rb +2 -2
  43. data/spec/summary_spec.rb +1 -1
  44. data/wercker.yml +29 -16
  45. metadata +28 -10
@@ -1,6 +1,7 @@
1
1
  package subsystem
2
2
 
3
3
  import (
4
+ "log"
4
5
  "os"
5
6
  "testing"
6
7
  )
@@ -71,3 +72,42 @@ func TestReadNetStat(t *testing.T) {
71
72
  t.Error("Device 'lo' not found.")
72
73
  }
73
74
  }
75
+
76
+ func TestReadMemStat(t *testing.T) {
77
+ var err error
78
+ var stat_record *StatRecord = nil
79
+
80
+ err = ReadMemStat(stat_record)
81
+ if err == nil {
82
+ t.Errorf("Error should not be returned with non-nil *StatRecord.")
83
+ }
84
+
85
+ _, err = os.Stat("/proc/meminfo")
86
+ if err != nil {
87
+ t.Skip("/proc/meminfo is not present.")
88
+ }
89
+
90
+ stat_record = NewStatRecord()
91
+ err = ReadMemStat(stat_record)
92
+ if err != nil {
93
+ log.Print(err)
94
+ t.Error("Error should not be returned with valid *StatRecord.")
95
+ return
96
+ }
97
+ if stat_record.Mem == nil {
98
+ t.Error("stat_record.Mem should not be nil")
99
+ return
100
+ }
101
+
102
+ if stat_record.Mem.MemTotal == 0 {
103
+ t.Error("Cannot read MemTotal correctly")
104
+ return
105
+ }
106
+
107
+ mem := stat_record.Mem
108
+
109
+ if (mem.MemFree + mem.Cached + mem.Buffers) > mem.MemTotal {
110
+ t.Error("Inconsistent meminfo values")
111
+ return
112
+ }
113
+ }
@@ -102,6 +102,38 @@ type NetStat struct {
102
102
  Entries []*NetStatEntry
103
103
  }
104
104
 
105
+ // all values are recorded in KB
106
+ type MemStat struct {
107
+ MemTotal int64
108
+ MemFree int64
109
+ Buffers int64
110
+ Cached int64
111
+ SwapCached int64
112
+ Active int64
113
+ Inactive int64
114
+ SwapTotal int64
115
+ SwapFree int64
116
+ Dirty int64
117
+ Writeback int64
118
+ AnonPages int64
119
+ Mapped int64
120
+ Shmem int64
121
+ Slab int64
122
+ SReclaimable int64
123
+ SUnreclaim int64
124
+ KernelStack int64
125
+ PageTables int64
126
+ NFS_Unstable int64
127
+ Bounce int64
128
+ CommitLimit int64
129
+ Committed_AS int64
130
+ AnonHugePages int64
131
+ HugePages_Total int64
132
+ HugePages_Free int64
133
+ HugePages_Rsvd int64
134
+ HugePages_Surp int64
135
+ }
136
+
105
137
  type StatRecord struct {
106
138
  Time time.Time
107
139
  Cpu *CpuStat
@@ -110,6 +142,7 @@ type StatRecord struct {
110
142
  Disk *DiskStat
111
143
  Softirq *SoftIrqStat
112
144
  Net *NetStat
145
+ Mem *MemStat
113
146
  }
114
147
 
115
148
  func (core_stat *CpuCoreStat) Clear() {
@@ -219,6 +252,42 @@ func NewNetStat() *NetStat {
219
252
  return new(NetStat)
220
253
  }
221
254
 
255
+ func NewMemStat() *MemStat {
256
+ return new(MemStat)
257
+ }
258
+
259
+ func (entry *MemStat) Clear() {
260
+ entry.MemTotal = 0
261
+ entry.MemFree = 0
262
+ entry.Buffers = 0
263
+ entry.Cached = 0
264
+ entry.SwapCached = 0
265
+ entry.Active = 0
266
+ entry.Inactive = 0
267
+ entry.SwapTotal = 0
268
+ entry.SwapFree = 0
269
+ entry.Dirty = 0
270
+ entry.Writeback = 0
271
+ entry.AnonPages = 0
272
+ entry.Mapped = 0
273
+ entry.Shmem = 0
274
+ entry.Slab = 0
275
+ entry.SReclaimable = 0
276
+ entry.NFS_Unstable = 0
277
+ entry.SUnreclaim = 0
278
+ entry.KernelStack = 0
279
+ entry.PageTables = 0
280
+ entry.NFS_Unstable = 0
281
+ entry.Bounce = 0
282
+ entry.CommitLimit = 0
283
+ entry.Committed_AS = 0
284
+ entry.AnonHugePages = 0
285
+ entry.HugePages_Total = 0
286
+ entry.HugePages_Free = 0
287
+ entry.HugePages_Rsvd = 0
288
+ entry.HugePages_Surp = 0
289
+ }
290
+
222
291
  func NewStatRecord() *StatRecord {
223
292
  return &StatRecord{
224
293
  time.Now(),
@@ -228,6 +297,7 @@ func NewStatRecord() *StatRecord {
228
297
  nil,
229
298
  nil,
230
299
  nil,
300
+ nil,
231
301
  }
232
302
  }
233
303
 
@@ -262,6 +262,14 @@ func TestNewNetStat(t *testing.T) {
262
262
  }
263
263
  }
264
264
 
265
+ func TestNewMemStat(t *testing.T) {
266
+ memstat := NewMemStat()
267
+
268
+ if memstat == nil {
269
+ t.Error("failed to create MemStat")
270
+ }
271
+ }
272
+
265
273
  func TestNewStatRecord(t *testing.T) {
266
274
  stat_record := NewStatRecord()
267
275
 
@@ -278,4 +286,5 @@ func TestNewStatRecord(t *testing.T) {
278
286
  checkFieldIsNil("Disk")
279
287
  checkFieldIsNil("Softirq")
280
288
  checkFieldIsNil("Net")
289
+ checkFieldIsNil("Mem")
281
290
  }
@@ -2,12 +2,13 @@ package subsystem
2
2
 
3
3
  import (
4
4
  "bytes"
5
- "encoding/json"
6
5
  "errors"
7
6
  "fmt"
8
7
  "regexp"
9
8
  "sort"
10
9
  "time"
10
+
11
+ projson "github.com/hayamiz/go-projson"
11
12
  )
12
13
 
13
14
  type CpuCoreUsage struct {
@@ -84,25 +85,56 @@ type NetUsageEntry struct {
84
85
 
85
86
  type NetUsage map[string]*NetUsageEntry
86
87
 
87
- func (ccusage *CpuCoreUsage) WriteJsonTo(buf *bytes.Buffer) {
88
- buf.WriteString(
89
- fmt.Sprintf(`{"usr":%.2f,"nice":%.2f,"sys":%.2f,"idle":%.2f,"iowait":%.2f,"hardirq":%.2f,"softirq":%.2f,"steal":%.2f,"guest":%.2f,"guestnice":%.2f}`,
90
- ccusage.User, ccusage.Nice, ccusage.Sys, ccusage.Idle, ccusage.Iowait,
91
- ccusage.Hardirq, ccusage.Softirq, ccusage.Steal, ccusage.Guest, ccusage.GuestNice))
88
+ type MemUsage struct {
89
+ mem *MemStat
92
90
  }
93
91
 
94
- func (cusage *CpuUsage) WriteJsonTo(buf *bytes.Buffer) {
95
- buf.WriteString(
96
- fmt.Sprintf(`{"num_core":%d,"all":`, cusage.NumCore))
97
- cusage.All.WriteJsonTo(buf)
98
- buf.WriteString(`,"cores":[`)
99
- for idx, ccusage := range cusage.CoreUsages {
100
- if idx > 0 {
101
- buf.WriteString(",")
102
- }
103
- ccusage.WriteJsonTo(buf)
92
+ var UseColor = false
93
+
94
+ func SetUseColor(use_color bool) {
95
+ UseColor = use_color
96
+ }
97
+
98
+ func (ccusage *CpuCoreUsage) WriteJsonTo(printer *projson.JsonPrinter) {
99
+ printer.BeginObject()
100
+ printer.PutKey("usr")
101
+ printer.PutFloatFmt(ccusage.User, "%.2f")
102
+ printer.PutKey("nice")
103
+ printer.PutFloatFmt(ccusage.Nice, "%.2f")
104
+ printer.PutKey("sys")
105
+ printer.PutFloatFmt(ccusage.Sys, "%.2f")
106
+ printer.PutKey("idle")
107
+ printer.PutFloatFmt(ccusage.Idle, "%.2f")
108
+ printer.PutKey("iowait")
109
+ printer.PutFloatFmt(ccusage.Iowait, "%.2f")
110
+ printer.PutKey("hardirq")
111
+ printer.PutFloatFmt(ccusage.Hardirq, "%.2f")
112
+ printer.PutKey("softirq")
113
+ printer.PutFloatFmt(ccusage.Softirq, "%.2f")
114
+ printer.PutKey("steal")
115
+ printer.PutFloatFmt(ccusage.Steal, "%.2f")
116
+ printer.PutKey("guest")
117
+ printer.PutFloatFmt(ccusage.Guest, "%.2f")
118
+ printer.PutKey("guestnice")
119
+ printer.PutFloatFmt(ccusage.GuestNice, "%.2f")
120
+ printer.FinishObject()
121
+ }
122
+
123
+ func (cusage *CpuUsage) WriteJsonTo(printer *projson.JsonPrinter) {
124
+ printer.BeginObject()
125
+ printer.PutKey("num_core")
126
+ printer.PutInt(cusage.NumCore)
127
+ printer.PutKey("all")
128
+
129
+ cusage.All.WriteJsonTo(printer)
130
+
131
+ printer.PutKey("cores")
132
+ printer.BeginArray()
133
+ for _, ccusage := range cusage.CoreUsages {
134
+ ccusage.WriteJsonTo(printer)
104
135
  }
105
- buf.WriteString(`]}`)
136
+ printer.FinishArray()
137
+ printer.FinishObject()
106
138
  }
107
139
 
108
140
  func GetCpuCoreUsage(c1 *CpuCoreStat, c2 *CpuCoreStat) (*CpuCoreUsage, error) {
@@ -225,35 +257,68 @@ func GetInterruptUsage(t1 time.Time, i1 *InterruptStat, t2 time.Time, i2 *Interr
225
257
  return usage, nil
226
258
  }
227
259
 
228
- func (intr_usage *InterruptUsage) WriteJsonTo(buf *bytes.Buffer) {
229
- buf.WriteString("{")
230
- buf.WriteString(`"core_dev_intr":[`)
231
- for idx, core_usage := range intr_usage.CoreIntrUsages {
232
- if idx > 0 {
233
- buf.WriteString(",")
234
- }
235
- fmt.Fprintf(buf, "%.2f", core_usage.Device)
260
+ func (intr_usage *InterruptUsage) WriteJsonTo(printer *projson.JsonPrinter) {
261
+ printer.BeginObject()
262
+ printer.PutKey("core_dev_intr")
263
+ printer.BeginArray()
264
+ for _, core_usage := range intr_usage.CoreIntrUsages {
265
+ printer.PutFloatFmt(core_usage.Device, "%.2f")
236
266
  }
237
- buf.WriteString(`],"core_sys_intr":[`)
238
- for idx, core_usage := range intr_usage.CoreIntrUsages {
239
- if idx > 0 {
240
- buf.WriteString(",")
241
- }
242
- fmt.Fprintf(buf, "%.2f", core_usage.System)
267
+ printer.FinishArray()
268
+
269
+ printer.PutKey("core_sys_intr")
270
+ printer.BeginArray()
271
+ for _, core_usage := range intr_usage.CoreIntrUsages {
272
+ printer.PutFloatFmt(core_usage.System, "%.2f")
243
273
  }
244
- buf.WriteString("]")
245
- buf.WriteString("}")
274
+ printer.FinishArray()
275
+ printer.FinishObject()
246
276
  }
247
277
 
248
- func (duentry *DiskUsageEntry) WriteJsonTo(buf *bytes.Buffer) {
249
- fmt.Fprintf(buf,
250
- `{"riops":%.2f,"wiops":%.2f,"rkbyteps":%.2f,"wkbyteps":%.2f,"rlatency":%.3f,"wlatency":%.3f,"rsize":%.2f,"wsize":%.2f,"qlen":%.2f}`,
251
- duentry.RdIops, duentry.WrIops, duentry.RdSecps/2.0, duentry.WrSecps/2.0,
252
- duentry.RdLatency, duentry.WrLatency,
253
- duentry.AvgRdSize, duentry.AvgWrSize, duentry.ReqQlen)
278
+ func (duentry *DiskUsageEntry) WriteJsonTo(printer *projson.JsonPrinter) {
279
+ printer.BeginObject()
280
+ printer.PutKey("riops")
281
+ printer.PutFloatFmt(duentry.RdIops, "%.2f")
282
+ printer.PutKey("wiops")
283
+ printer.PutFloatFmt(duentry.WrIops, "%.2f")
284
+ printer.PutKey("rkbyteps")
285
+ printer.PutFloatFmt(duentry.RdSecps/2.0, "%.2f")
286
+ printer.PutKey("wkbyteps")
287
+ printer.PutFloatFmt(duentry.WrSecps/2.0, "%.2f")
288
+ printer.PutKey("rlatency")
289
+ printer.PutFloatFmt(duentry.RdLatency, "%.3f")
290
+ printer.PutKey("wlatency")
291
+ printer.PutFloatFmt(duentry.WrLatency, "%.3f")
292
+ printer.PutKey("rsize")
293
+ printer.PutFloatFmt(duentry.AvgRdSize, "%.2f")
294
+ printer.PutKey("wsize")
295
+ printer.PutFloatFmt(duentry.AvgWrSize, "%.2f")
296
+ printer.PutKey("qlen")
297
+ printer.PutFloatFmt(duentry.ReqQlen, "%.2f")
298
+ printer.FinishObject()
254
299
  }
255
300
 
256
- func (dusage *DiskUsage) WriteJsonTo(buf *bytes.Buffer) {
301
+ func strarrayToString(arr []string) string {
302
+ buf := bytes.NewBuffer([]byte{})
303
+
304
+ fmt.Fprintf(buf, "[")
305
+ for i, elem := range arr {
306
+ if i > 0 {
307
+ fmt.Fprintf(buf, ",")
308
+ }
309
+
310
+ if UseColor {
311
+ fmt.Fprintf(buf, "\033[35m\"%s\"\033[0m", elem)
312
+ } else {
313
+ fmt.Fprintf(buf, "\"%s\"", elem)
314
+ }
315
+ }
316
+ fmt.Fprintf(buf, "]")
317
+
318
+ return buf.String()
319
+ }
320
+
321
+ func (dusage *DiskUsage) WriteJsonTo(printer *projson.JsonPrinter) {
257
322
  var devices []string
258
323
 
259
324
  for device, _ := range *dusage {
@@ -263,23 +328,24 @@ func (dusage *DiskUsage) WriteJsonTo(buf *bytes.Buffer) {
263
328
  }
264
329
  sort.Strings(devices)
265
330
 
266
- bytes, err := json.Marshal(devices)
267
- if err != nil {
268
- panic(err)
331
+ printer.BeginObject()
332
+ printer.PutKey("devices")
333
+ printer.BeginArray()
334
+ for _, device := range devices {
335
+ printer.PutString(device)
269
336
  }
270
- fmt.Fprintf(buf, `{"devices":%s`, string(bytes))
337
+ printer.FinishArray()
271
338
 
272
339
  devices = append(devices, "total")
273
340
 
274
341
  for _, device := range devices {
275
342
  usage := (*dusage)[device]
276
- buf.WriteString(`,"`)
277
- buf.WriteString(device)
278
- buf.WriteString(`":`)
279
- usage.WriteJsonTo(buf)
343
+
344
+ printer.PutKey(device)
345
+ usage.WriteJsonTo(printer)
280
346
  }
281
347
 
282
- buf.WriteByte('}')
348
+ printer.FinishObject()
283
349
  }
284
350
 
285
351
  func avgDelta(v int64, w int64, interval float64) float64 {
@@ -470,7 +536,7 @@ func GetNetUsage(t1 time.Time, d1 *NetStat, t2 time.Time, d2 *NetStat) (*NetUsag
470
536
  return net_usage, nil
471
537
  }
472
538
 
473
- func (nusage *NetUsage) WriteJsonTo(buf *bytes.Buffer) {
539
+ func (nusage *NetUsage) WriteJsonTo(printer *projson.JsonPrinter) {
474
540
  var devices []string
475
541
 
476
542
  for device, _ := range *nusage {
@@ -480,30 +546,121 @@ func (nusage *NetUsage) WriteJsonTo(buf *bytes.Buffer) {
480
546
  }
481
547
  sort.Strings(devices)
482
548
 
483
- bytes, err := json.Marshal(devices)
484
- if err != nil {
485
- panic(err)
549
+ printer.BeginObject()
550
+ printer.PutKey("devices")
551
+ printer.BeginArray()
552
+ for _, device := range devices {
553
+ printer.PutString(device)
486
554
  }
487
- fmt.Fprintf(buf, `{"devices":%s`, string(bytes))
555
+ printer.FinishArray()
488
556
 
489
557
  devices = append(devices, "total")
490
558
 
491
559
  for _, device := range devices {
492
560
  usage := (*nusage)[device]
493
- buf.WriteString(`,"`)
494
- buf.WriteString(device)
495
- buf.WriteString(`":`)
496
- usage.WriteJsonTo(buf)
561
+
562
+ printer.PutKey(device)
563
+ usage.WriteJsonTo(printer)
564
+ }
565
+
566
+ printer.FinishObject()
567
+ }
568
+
569
+ func GetMemUsage(mem *MemStat) (*MemUsage, error) {
570
+ if mem == nil {
571
+ return nil, errors.New("invalid memstat")
497
572
  }
498
573
 
499
- buf.WriteByte('}')
574
+ musage := new(MemUsage)
575
+ musage.mem = mem
576
+
577
+ return musage, nil
578
+ }
579
+
580
+ func (musage *MemUsage) WriteJsonTo(printer *projson.JsonPrinter) {
581
+ printer.BeginObject()
582
+
583
+ printer.PutKey("mem_total")
584
+ printer.PutInt64(musage.mem.MemTotal)
585
+ printer.PutKey("mem_used")
586
+ printer.PutInt64(musage.mem.MemTotal - musage.mem.MemFree - musage.mem.Buffers - musage.mem.Cached - musage.mem.SReclaimable)
587
+ printer.PutKey("mem_free")
588
+ printer.PutInt64(musage.mem.MemFree)
589
+ printer.PutKey("buffers")
590
+ printer.PutInt64(musage.mem.Buffers)
591
+ printer.PutKey("cached")
592
+ printer.PutInt64(musage.mem.Cached)
593
+ printer.PutKey("swap_cached")
594
+ printer.PutInt64(musage.mem.SwapCached)
595
+ printer.PutKey("active")
596
+ printer.PutInt64(musage.mem.Active)
597
+ printer.PutKey("inactive")
598
+ printer.PutInt64(musage.mem.Inactive)
599
+ printer.PutKey("swap_total")
600
+ printer.PutInt64(musage.mem.SwapTotal)
601
+ printer.PutKey("swap_free")
602
+ printer.PutInt64(musage.mem.SwapFree)
603
+ printer.PutKey("dirty")
604
+ printer.PutInt64(musage.mem.Dirty)
605
+ printer.PutKey("writeback")
606
+ printer.PutInt64(musage.mem.Writeback)
607
+ printer.PutKey("anon_pages")
608
+ printer.PutInt64(musage.mem.AnonPages)
609
+ printer.PutKey("mapped")
610
+ printer.PutInt64(musage.mem.Mapped)
611
+ printer.PutKey("shmem")
612
+ printer.PutInt64(musage.mem.Shmem)
613
+ printer.PutKey("slab")
614
+ printer.PutInt64(musage.mem.Slab)
615
+ printer.PutKey("s_reclaimable")
616
+ printer.PutInt64(musage.mem.SReclaimable)
617
+ printer.PutKey("s_unreclaim")
618
+ printer.PutInt64(musage.mem.SUnreclaim)
619
+ printer.PutKey("kernel_stack")
620
+ printer.PutInt64(musage.mem.KernelStack)
621
+ printer.PutKey("page_tables")
622
+ printer.PutInt64(musage.mem.PageTables)
623
+ printer.PutKey("nfs_unstable")
624
+ printer.PutInt64(musage.mem.NFS_Unstable)
625
+ printer.PutKey("bounce")
626
+ printer.PutInt64(musage.mem.Bounce)
627
+ printer.PutKey("commit_limit")
628
+ printer.PutInt64(musage.mem.CommitLimit)
629
+ printer.PutKey("committed_as")
630
+ printer.PutInt64(musage.mem.Committed_AS)
631
+ printer.PutKey("anon_huge_pages")
632
+ printer.PutInt64(musage.mem.AnonHugePages)
633
+ printer.PutKey("huge_pages_total")
634
+ printer.PutInt64(musage.mem.HugePages_Total)
635
+ printer.PutKey("huge_pages_free")
636
+ printer.PutInt64(musage.mem.HugePages_Free)
637
+ printer.PutKey("huge_pages_rsvd")
638
+ printer.PutInt64(musage.mem.HugePages_Rsvd)
639
+ printer.PutKey("huge_pages_surp")
640
+ printer.PutInt64(musage.mem.HugePages_Surp)
641
+
642
+ printer.FinishObject()
500
643
  }
501
644
 
502
- func (entry *NetUsageEntry) WriteJsonTo(buf *bytes.Buffer) {
503
- buf.WriteString(
504
- fmt.Sprintf(`{"rxkbyteps":%.2f,"rxpktps":%.2f,"rxerrps":%.2f,"rxdropps":%.2f,"txkbyteps":%.2f,"txpktps":%.2f,"txerrps":%.2f,"txdropps":%.2f}`,
505
- entry.RxBytesPerSec/1024.0, entry.RxPacketsPerSec,
506
- entry.RxErrorsPerSec, entry.RxDropsPerSec,
507
- entry.TxBytesPerSec/1024.0, entry.TxPacketsPerSec,
508
- entry.TxErrorsPerSec, entry.TxDropsPerSec))
645
+ func (entry *NetUsageEntry) WriteJsonTo(printer *projson.JsonPrinter) {
646
+ printer.BeginObject()
647
+
648
+ printer.PutKey("rxkbyteps")
649
+ printer.PutFloatFmt(entry.RxBytesPerSec/1024.0, "%.2f")
650
+ printer.PutKey("rxpktps")
651
+ printer.PutFloatFmt(entry.RxPacketsPerSec, "%.2f")
652
+ printer.PutKey("rxerrps")
653
+ printer.PutFloatFmt(entry.RxErrorsPerSec, "%.2f")
654
+ printer.PutKey("rxdropps")
655
+ printer.PutFloatFmt(entry.RxDropsPerSec, "%.2f")
656
+ printer.PutKey("txkbyteps")
657
+ printer.PutFloatFmt(entry.TxBytesPerSec/1024.0, "%.2f")
658
+ printer.PutKey("txpktps")
659
+ printer.PutFloatFmt(entry.TxPacketsPerSec, "%.2f")
660
+ printer.PutKey("txerrps")
661
+ printer.PutFloatFmt(entry.TxErrorsPerSec, "%.2f")
662
+ printer.PutKey("txdropps")
663
+ printer.PutFloatFmt(entry.TxDropsPerSec, "%.2f")
664
+
665
+ printer.FinishObject()
509
666
  }