From 54ac541f3606c3ecaa84a366f1d58aaca46e8163 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kurk=C3=B3=20Mih=C3=A1ly?= Date: Fri, 2 Mar 2018 16:02:53 +0200 Subject: [PATCH] cmd, ethdb, vendor: print iostats --- cmd/geth/chaincmd.go | 10 +++ ethdb/database.go | 8 ++ .../github.com/syndtr/goleveldb/leveldb/db.go | 10 ++- .../goleveldb/leveldb/storage/storage.go | 76 +++++++++++++++++++ 4 files changed, 103 insertions(+), 1 deletion(-) diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index 85d0c3acaa..7adfea5285 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -225,6 +225,11 @@ func importChain(ctx *cli.Context) error { utils.Fatalf("Failed to read database stats: %v", err) } fmt.Println(stats) + iostats, err := db.LDB().GetProperty("leveldb.iostats") + if err != nil { + utils.Fatalf("Failed to read database iostats: %v", err) + } + fmt.Println(iostats) fmt.Printf("Trie cache misses: %d\n", trie.CacheMisses()) fmt.Printf("Trie cache unloads: %d\n\n", trie.CacheUnloads()) @@ -254,6 +259,11 @@ func importChain(ctx *cli.Context) error { utils.Fatalf("Failed to read database stats: %v", err) } fmt.Println(stats) + iostats, err = db.LDB().GetProperty("leveldb.iostats") + if err != nil { + utils.Fatalf("Failed to read database iostats: %v", err) + } + fmt.Println(iostats) return nil } diff --git a/ethdb/database.go b/ethdb/database.go index 57d38f7f5f..59d74f0833 100644 --- a/ethdb/database.go +++ b/ethdb/database.go @@ -22,6 +22,7 @@ import ( "sync" "time" + "fmt" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" "github.com/syndtr/goleveldb/leveldb" @@ -221,6 +222,13 @@ func (db *LDBDatabase) meter(refresh time.Duration) { db.log.Error("Failed to read database stats", "err", err) return } + iostats, err := db.db.GetProperty("leveldb.iostats") + if err != nil { + db.log.Error("Failed to read database iostats", "err", err) + return + } + fmt.Println(iostats) + // Find the compaction table, skip the header lines := strings.Split(stats, "\n") for len(lines) > 0 && strings.TrimSpace(lines[0]) != "Compactions" { diff --git a/vendor/github.com/syndtr/goleveldb/leveldb/db.go b/vendor/github.com/syndtr/goleveldb/leveldb/db.go index ea5595eb3a..ff18235141 100644 --- a/vendor/github.com/syndtr/goleveldb/leveldb/db.go +++ b/vendor/github.com/syndtr/goleveldb/leveldb/db.go @@ -168,7 +168,7 @@ func openDB(s *session) (*DB, error) { // The returned DB instance is safe for concurrent use. // The DB must be closed after use, by calling Close method. func Open(stor storage.Storage, o *opt.Options) (db *DB, err error) { - s, err := newSession(stor, o) + s, err := newSession(storage.IOCounterWrapper(stor), o) if err != nil { return } @@ -906,6 +906,8 @@ func (db *DB) GetSnapshot() (*Snapshot, error) { // Returns the number of files at level 'n'. // leveldb.stats // Returns statistics of the underlying DB. +// leveldb.iostats +// Returns statistics of effective disk read and write. // leveldb.writedelay // Returns cumulative write delay caused by compaction. // leveldb.sstables @@ -959,6 +961,12 @@ func (db *DB) GetProperty(name string) (value string, err error) { level, len(tables), float64(tables.size())/1048576.0, duration.Seconds(), float64(read)/1048576.0, float64(write)/1048576.0) } + case p == "iostats": + var r, w float64 + if s, ok := db.s.stor.(storage.IOCounter); ok { + r, w = float64(s.Reads())/1048576.0, float64(s.Writes())/1048576.0 + } + value = fmt.Sprintf("Read(MB): %13.5f Write(MB): %13.5f", r, w) case p == "writedelay": writeDelayN, writeDelay := atomic.LoadInt32(&db.cWriteDelayN), time.Duration(atomic.LoadInt64(&db.cWriteDelay)) value = fmt.Sprintf("DelayN:%d Delay:%s", writeDelayN, writeDelay) diff --git a/vendor/github.com/syndtr/goleveldb/leveldb/storage/storage.go b/vendor/github.com/syndtr/goleveldb/leveldb/storage/storage.go index c16bce6b66..301a484ecf 100644 --- a/vendor/github.com/syndtr/goleveldb/leveldb/storage/storage.go +++ b/vendor/github.com/syndtr/goleveldb/leveldb/storage/storage.go @@ -11,6 +11,7 @@ import ( "errors" "fmt" "io" + "sync/atomic" ) // FileType represent a file type. @@ -177,3 +178,78 @@ type Storage interface { // called after the storage has been closed. Close() error } + +// IOCounter collects read and write statistics. +type IOCounter interface { + // Reads returns the cumulative number of read bytes of the underlying storage. + Reads() uint64 + // Writes returns the cumulative number of written bytes of the underlying storage. + Writes() uint64 +} + +type ioCounter struct { + Storage + read uint64 + write uint64 +} + +func (c *ioCounter) Open(fd FileDesc) (Reader, error) { + r, err := c.Storage.Open(fd) + return &meteredReader{r, c}, err +} + +func (c *ioCounter) Create(fd FileDesc) (Writer, error) { + w, err := c.Storage.Create(fd) + return &meteredWriter{w, c}, err +} + +func (c *ioCounter) Reads() uint64 { + return atomic.LoadUint64(&c.read) +} + +func (c *ioCounter) Writes() uint64 { + return atomic.LoadUint64(&c.write) +} + +// AddRead increases the number of read bytes by n. +func (c *ioCounter) AddRead(n uint64) uint64 { + return atomic.AddUint64(&c.read, n) +} + +// AddWrite increases the number of written bytes by n. +func (c *ioCounter) AddWrite(n uint64) uint64 { + return atomic.AddUint64(&c.write, n) +} + +// IOCounterWrapper returns the given storage wrapped by ioCounter. +func IOCounterWrapper(s Storage) Storage { + return &ioCounter{s, 0, 0} +} + +type meteredReader struct { + Reader + c *ioCounter +} + +func (r *meteredReader) Read(p []byte) (n int, err error) { + n, err = r.Reader.Read(p) + r.c.AddRead(uint64(n)) + return n, err +} + +func (r *meteredReader) ReadAt(p []byte, off int64) (n int, err error) { + n, err = r.Reader.ReadAt(p, off) + r.c.AddRead(uint64(n)) + return n, err +} + +type meteredWriter struct { + Writer + c *ioCounter +} + +func (w *meteredWriter) Write(p []byte) (n int, err error) { + n, err = w.Writer.Write(p) + w.c.AddWrite(uint64(n)) + return n, err +}