blob: e36a95147580ee82f67c2260c29ceb2e6f0d0618 [file] [log] [blame]
// Copyright 2018 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package traceparser
import (
"encoding/binary"
"fmt"
"hash/fnv"
"io"
"log"
)
// convert batches into their raw events. For small intervals (1 or 10 seconds)
// this takes about 40% of the total Parse time.
func (p *Parsed) batchify(b *batch) error {
evs := make([]rawEvent, 0)
p.seenArgs = make(map[uint64]*[]uint64)
hasher := fnv.New64()
r := p.r
r.Seek(int64(b.Off), 0)
var buf [1]byte
seenBatch := false // to terminate the loop on the second EvBatch
for off := b.Off; ; {
off0 := off // remember the beginning of the event
n, err := r.Read(buf[:])
if err != nil {
return err
}
off += n
typ := buf[0] << 2 >> 2 // event type is bottom 6 bits
if typ == EvFrequency || (typ == EvBatch && seenBatch) {
break // found trailer, or next batch
}
if typ == EvBatch {
seenBatch = true
}
if typ == EvString {
// skip over it. error checking was done in file.go
_, off, _ = readVal(r, off)
var ln uint64
ln, off, _ = readVal(r, off)
// PJW: why not just seek ahead ln bytes?
if false {
buf := make([]byte, ln)
var n int
n, _ = io.ReadFull(r, buf)
off += n
} else {
n, _ := r.Seek(int64(ln), 1)
off = int(n)
}
continue
}
// build the raw event and collect its arguments
ev := rawEvent{typ: typ, off: uint32(off0 - b.Off)}
var args []uint64
off, args, err = p.argsAt(off0, typ)
if err != nil {
// PJW: make sure this is useful
return fmt.Errorf("parsing %s failed at P=%d off=%d %v", evname(typ),
b.P, off0, err)
}
// have we seen the args before?
if len(args) > 0 {
ev.arg0 = args[0]
if len(args) > 1 {
hasher.Reset()
for i := 1; i < len(args); i++ {
var x [8]byte
binary.LittleEndian.PutUint64(x[:], args[i])
_, err := hasher.Write(x[:])
if err != nil {
log.Fatal(err)
}
}
hc := hasher.Sum64()
old, ok := p.seenArgs[hc]
if !ok {
final := make([]uint64, len(args)-1)
copy(final, args[1:])
p.seenArgs[hc] = &final
} else {
// is this a collision? PJW: make this precisely right
if len(*old) != len(args[1:]) {
log.Fatalf("COLLISION old:%v this:%v", *old, args[1:])
}
}
ev.args = p.seenArgs[hc]
}
}
if typ == EvUserLog {
// argsAt didn't read the string argument
var s string
s, off, err = readStr(r, off)
ev.sarg = s
}
evs = append(evs, ev)
}
b.raws = evs
return nil
}