From c38575f0d76ed0e98fbcb5332491a589ef4071a3 Mon Sep 17 00:00:00 2001 From: Sebastien Binet Date: Mon, 7 Mar 2022 18:36:29 +0100 Subject: [PATCH] groot/rcmd: improve Dump tree performances MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ``` name old time/op new time/op delta Dump-8 5.02s ± 2% 3.84s ± 2% -23.57% (p=0.000 n=29+27) name old alloc/op new alloc/op delta Dump-8 2.50GB ± 0% 2.40GB ± 0% -3.82% (p=0.000 n=29+30) name old allocs/op new allocs/op delta Dump-8 38.8M ± 0% 29.3M ± 0% -24.69% (p=0.000 n=30+30) ``` --- groot/rcmd/dump.go | 42 +++++++++++++++++++++++++++++++++++------ groot/rcmd/dump_test.go | 15 +++++++++++++++ 2 files changed, 51 insertions(+), 6 deletions(-) diff --git a/groot/rcmd/dump.go b/groot/rcmd/dump.go index f3a4395c9..fe1732aca 100644 --- a/groot/rcmd/dump.go +++ b/groot/rcmd/dump.go @@ -9,6 +9,7 @@ import ( "fmt" "io" "reflect" + "strconv" "go-hep.org/x/hep/groot" "go-hep.org/x/hep/groot/rdict" @@ -133,14 +134,43 @@ func (cmd *dumpCmd) dumpTree(t rtree.Tree) error { } defer r.Close() + names := make([][]byte, len(vars)) + for i, v := range vars { + name := v.Name + if v.Leaf != "" && v.Leaf != v.Name { + name = v.Name + "." + v.Leaf + } + names[i] = []byte(name) + } + + // FIXME(sbinet): don't use a "global" buffer for when rtree.Reader reads multiple + // events in parallel. + buf := make([]byte, 0, 8*1024) + hdr := make([]byte, 0, 6) err = r.Read(func(rctx rtree.RCtx) error { - for _, v := range vars { - name := v.Name - if v.Leaf != "" && v.Leaf != v.Name { - name = v.Name + "." + v.Leaf - } + hdr = hdr[:0] + hdr = append(hdr, '[') + switch { + case rctx.Entry < 10: + hdr = append(hdr, '0', '0') + case rctx.Entry < 100: + hdr = append(hdr, '0') + } + hdr = strconv.AppendInt(hdr, rctx.Entry, 10) + hdr = append(hdr, ']', '[') + for i, v := range vars { + buf = buf[:0] + buf = append(buf, hdr...) + buf = append(buf, names[i]...) + buf = append(buf, ']', ':', ' ') rv := reflect.Indirect(reflect.ValueOf(v.Value)) - fmt.Fprintf(cmd.w, "[%03d][%s]: %v\n", rctx.Entry, name, rv.Interface()) + // All of this is a convoluted (but efficient) way to do: + // fmt.Fprintf(cmd.w, "[%03d][%s]: %v\n", rctx.Entry, name, rv.Interface()) + buf = append(buf, fmt.Sprintf("%v\n", rv.Interface())...) + _, err = cmd.w.Write(buf) + if err != nil { + return err + } } return nil }) diff --git a/groot/rcmd/dump_test.go b/groot/rcmd/dump_test.go index ead458957..294060896 100644 --- a/groot/rcmd/dump_test.go +++ b/groot/rcmd/dump_test.go @@ -343,3 +343,18 @@ key[004]: tree;1 "my tree title" (TTree) }) } } + +func BenchmarkDump(b *testing.B) { + const deep = true + out := new(strings.Builder) + for i := 0; i < b.N; i++ { + b.StopTimer() + out.Reset() + b.StartTimer() + // big-file.root is: rtests.XrdRemote("testdata/SMHiggsToZZTo4L.root") + err := rcmd.Dump(out, "../testdata/big-file.root", deep, nil) + if err != nil { + b.Fatal(err) + } + } +}