github.com/petermattis/pebble@v0.0.0-20190905164901-ab51a2166067/metrics.go (about) 1 // Copyright 2019 The LevelDB-Go and Pebble Authors. All rights reserved. Use 2 // of this source code is governed by a BSD-style license that can be found in 3 // the LICENSE file. 4 5 package pebble 6 7 import ( 8 "bytes" 9 "fmt" 10 11 "github.com/petermattis/pebble/internal/humanize" 12 ) 13 14 // LevelMetrics holds per-level metrics such as the number of files and total 15 // size of the files, and compaction related metrics. 16 type LevelMetrics struct { 17 // The total number of files in the level. 18 NumFiles int64 19 // The total size in bytes of the files in the level. 20 Size uint64 21 // The level's compaction score. 22 Score float64 23 // The number of incoming bytes from other levels read during 24 // compactions. This excludes bytes moved and bytes ingested. For L0 this is 25 // the bytes written to the WAL. 26 BytesIn uint64 27 // The number of bytes ingested. 28 BytesIngested uint64 29 // The number of bytes moved into the level by a "move" compaction. 30 BytesMoved uint64 31 // The number of bytes read for compactions at the level. This includes bytes 32 // read from other levels (BytesIn), as well as bytes read for the level. 33 BytesRead uint64 34 // The number of bytes written during compactions. 35 BytesWritten uint64 36 } 37 38 // Add updates the counter metrics for the level. 39 func (m *LevelMetrics) Add(u *LevelMetrics) { 40 m.BytesIn += u.BytesIn 41 m.BytesIngested += u.BytesIngested 42 m.BytesMoved += u.BytesMoved 43 m.BytesRead += u.BytesRead 44 m.BytesWritten += u.BytesWritten 45 } 46 47 // WriteAmp computes the write amplification for compactions at this 48 // level. Computed as BytesWritten / BytesIn. 49 func (m *LevelMetrics) WriteAmp() float64 { 50 if m.BytesIn == 0 { 51 return 0 52 } 53 return float64(m.BytesWritten) / float64(m.BytesIn) 54 } 55 56 // format generates a string of the receiver's metrics, formatting it into the 57 // supplied buffer. 58 func (m *LevelMetrics) format(buf *bytes.Buffer) { 59 fmt.Fprintf(buf, "%6d %7s %7.2f %7s %7s %7s %7s %7s %7.1f\n", 60 m.NumFiles, 61 humanize.Uint64(m.Size), 62 m.Score, 63 humanize.Uint64(m.BytesIn), 64 humanize.Uint64(m.BytesIngested), 65 humanize.Uint64(m.BytesMoved), 66 humanize.Uint64(m.BytesRead), 67 humanize.Uint64(m.BytesWritten), 68 m.WriteAmp(), 69 ) 70 } 71 72 // VersionMetrics holds metrics for each level. 73 type VersionMetrics struct { 74 WAL struct { 75 // Number of live WAL files. 76 Files int64 77 // Number of obsolete WAL files. 78 ObsoleteFiles int64 79 // Size of the live data in the WAL files. Note that with WAL file 80 // recycling this is less than the actual on-disk size of the WAL files. 81 Size uint64 82 // Number of logical bytes written to the WAL. 83 BytesIn uint64 84 // Number of bytes written to the WAL. 85 BytesWritten uint64 86 } 87 Levels [numLevels]LevelMetrics 88 } 89 90 func (m *VersionMetrics) formatWAL(buf *bytes.Buffer) { 91 var writeAmp float64 92 if m.WAL.BytesIn > 0 { 93 writeAmp = float64(m.WAL.BytesWritten) / float64(m.WAL.BytesIn) 94 } 95 fmt.Fprintf(buf, " WAL %6d %7s - %7s - - - %7s %7.1f\n", 96 m.WAL.Files, 97 humanize.Uint64(m.WAL.Size), 98 humanize.Uint64(m.WAL.BytesIn), 99 humanize.Uint64(m.WAL.BytesWritten), 100 writeAmp) 101 } 102 103 // Pretty-print the metrics, showing a line for the WAL, a line per-level, and 104 // a total: 105 // 106 // level__files____size___score______in__ingest____move____read___write___w-amp 107 // WAL 1 53 M - 744 M - - - 765 M 1.0 108 // 0 6 285 M 3.00 712 M 0 B 0 B 0 B 707 M 1.0 109 // 1 0 0 B 0.00 0 B 0 B 0 B 0 B 0 B 0.0 110 // 2 0 0 B 0.00 0 B 0 B 0 B 0 B 0 B 0.0 111 // 3 0 0 B 0.00 0 B 0 B 0 B 0 B 0 B 0.0 112 // 4 0 0 B 0.00 0 B 0 B 0 B 0 B 0 B 0.0 113 // 5 80 312 M 1.09 328 M 0 B 0 B 580 M 580 M 1.8 114 // 6 23 110 M 0.35 110 M 0 B 0 B 146 M 146 M 1.3 115 // total 109 706 M 0.00 765 M 0 B 0 B 726 M 2.1 G 2.9 116 // 117 // The WAL "in" metric is the size of the batches written to the WAL. The WAL 118 // "write" metric is the size of the physical data written to the WAL which 119 // includes record fragment overhead. Write amplification is computed as 120 // bytes-written / bytes-in, except for the total row where bytes-in is 121 // replaced with WAL-bytes-written + bytes-ingested. 122 func (m *VersionMetrics) String() string { 123 var buf bytes.Buffer 124 var total LevelMetrics 125 fmt.Fprintf(&buf, "level__files____size___score______in__ingest____move____read___write___w-amp\n") 126 m.formatWAL(&buf) 127 for level := 0; level < numLevels; level++ { 128 l := &m.Levels[level] 129 fmt.Fprintf(&buf, "%5d ", level) 130 l.format(&buf) 131 total.Add(l) 132 total.NumFiles += l.NumFiles 133 total.Size += l.Size 134 } 135 // Compute total bytes-in as the bytes written to the WAL + bytes ingested 136 total.BytesIn = m.WAL.BytesWritten + total.BytesIngested 137 // Add the total bytes-in to the total bytes-written. This is to account for 138 // the bytes written to the log and bytes written externally and then 139 // ingested. 140 total.BytesWritten += total.BytesIn 141 fmt.Fprintf(&buf, "total ") 142 total.format(&buf) 143 return buf.String() 144 }