github.com/hikaru7719/go@v0.0.0-20181025140707-c8b2ac68906a/src/internal/traceparser/raw.go (about)

     1  // Copyright 2018 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package traceparser
     6  
     7  import (
     8  	"encoding/binary"
     9  	"fmt"
    10  	"hash/fnv"
    11  	"io"
    12  	"log"
    13  )
    14  
    15  // convert batches into their raw events. For small intervals (1 or 10 seconds)
    16  // this takes about 40% of the total Parse time.
    17  
    18  func (p *Parsed) batchify(b *batch) error {
    19  	evs := make([]rawEvent, 0)
    20  	p.seenArgs = make(map[uint64]*[]uint64)
    21  	hasher := fnv.New64()
    22  	r := p.r
    23  	r.Seek(int64(b.Off), 0)
    24  	var buf [1]byte
    25  	seenBatch := false // to terminate the loop on the second EvBatch
    26  
    27  	for off := b.Off; ; {
    28  		off0 := off // remember the beginning of the event
    29  		n, err := r.Read(buf[:])
    30  		if err != nil {
    31  			return err
    32  		}
    33  		off += n
    34  		typ := buf[0] << 2 >> 2 // event type is bottom 6 bits
    35  		if typ == EvFrequency || (typ == EvBatch && seenBatch) {
    36  			break // found trailer, or next batch
    37  		}
    38  		if typ == EvBatch {
    39  			seenBatch = true
    40  		}
    41  		if typ == EvString {
    42  			// skip over it. error checking was done in file.go
    43  			_, off, _ = readVal(r, off)
    44  			var ln uint64
    45  			ln, off, _ = readVal(r, off)
    46  			// PJW: why not just seek ahead ln bytes?
    47  			if false {
    48  				buf := make([]byte, ln)
    49  				var n int
    50  				n, _ = io.ReadFull(r, buf)
    51  				off += n
    52  			} else {
    53  				n, _ := r.Seek(int64(ln), 1)
    54  				off = int(n)
    55  			}
    56  			continue
    57  		}
    58  		// build the raw event and collect its arguments
    59  		ev := rawEvent{typ: typ, off: uint32(off0 - b.Off)}
    60  		var args []uint64
    61  		off, args, err = p.argsAt(off0, typ)
    62  		if err != nil {
    63  			// PJW: make sure this is useful
    64  			return fmt.Errorf("parsing %s failed at P=%d off=%d %v", evname(typ),
    65  				b.P, off0, err)
    66  		}
    67  
    68  		// have we seen the args before?
    69  		if len(args) > 0 {
    70  			ev.arg0 = args[0]
    71  			if len(args) > 1 {
    72  				hasher.Reset()
    73  				for i := 1; i < len(args); i++ {
    74  					var x [8]byte
    75  					binary.LittleEndian.PutUint64(x[:], args[i])
    76  					_, err := hasher.Write(x[:])
    77  					if err != nil {
    78  						log.Fatal(err)
    79  					}
    80  				}
    81  				hc := hasher.Sum64()
    82  				old, ok := p.seenArgs[hc]
    83  				if !ok {
    84  					final := make([]uint64, len(args)-1)
    85  					copy(final, args[1:])
    86  					p.seenArgs[hc] = &final
    87  				} else {
    88  					// is this a collision? PJW: make this precisely right
    89  					if len(*old) != len(args[1:]) {
    90  						log.Fatalf("COLLISION old:%v this:%v", *old, args[1:])
    91  					}
    92  				}
    93  				ev.args = p.seenArgs[hc]
    94  			}
    95  		}
    96  		if typ == EvUserLog {
    97  			// argsAt didn't read the string argument
    98  			var s string
    99  			s, off, err = readStr(r, off)
   100  			ev.sarg = s
   101  		}
   102  		evs = append(evs, ev)
   103  	}
   104  	b.raws = evs
   105  	return nil
   106  }