Home | History | Annotate | Download | only in profile
      1 // Copyright 2014 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 profile
      6 
      7 import (
      8 	"errors"
      9 	"fmt"
     10 	"sort"
     11 )
     12 
     13 func (p *Profile) decoder() []decoder {
     14 	return profileDecoder
     15 }
     16 
     17 // preEncode populates the unexported fields to be used by encode
     18 // (with suffix X) from the corresponding exported fields. The
     19 // exported fields are cleared up to facilitate testing.
     20 func (p *Profile) preEncode() {
     21 	strings := make(map[string]int)
     22 	addString(strings, "")
     23 
     24 	for _, st := range p.SampleType {
     25 		st.typeX = addString(strings, st.Type)
     26 		st.unitX = addString(strings, st.Unit)
     27 	}
     28 
     29 	for _, s := range p.Sample {
     30 		s.labelX = nil
     31 		var keys []string
     32 		for k := range s.Label {
     33 			keys = append(keys, k)
     34 		}
     35 		sort.Strings(keys)
     36 		for _, k := range keys {
     37 			vs := s.Label[k]
     38 			for _, v := range vs {
     39 				s.labelX = append(s.labelX,
     40 					Label{
     41 						keyX: addString(strings, k),
     42 						strX: addString(strings, v),
     43 					},
     44 				)
     45 			}
     46 		}
     47 		var numKeys []string
     48 		for k := range s.NumLabel {
     49 			numKeys = append(numKeys, k)
     50 		}
     51 		sort.Strings(numKeys)
     52 		for _, k := range numKeys {
     53 			vs := s.NumLabel[k]
     54 			for _, v := range vs {
     55 				s.labelX = append(s.labelX,
     56 					Label{
     57 						keyX: addString(strings, k),
     58 						numX: v,
     59 					},
     60 				)
     61 			}
     62 		}
     63 		s.locationIDX = nil
     64 		for _, l := range s.Location {
     65 			s.locationIDX = append(s.locationIDX, l.ID)
     66 		}
     67 	}
     68 
     69 	for _, m := range p.Mapping {
     70 		m.fileX = addString(strings, m.File)
     71 		m.buildIDX = addString(strings, m.BuildID)
     72 	}
     73 
     74 	for _, l := range p.Location {
     75 		for i, ln := range l.Line {
     76 			if ln.Function != nil {
     77 				l.Line[i].functionIDX = ln.Function.ID
     78 			} else {
     79 				l.Line[i].functionIDX = 0
     80 			}
     81 		}
     82 		if l.Mapping != nil {
     83 			l.mappingIDX = l.Mapping.ID
     84 		} else {
     85 			l.mappingIDX = 0
     86 		}
     87 	}
     88 	for _, f := range p.Function {
     89 		f.nameX = addString(strings, f.Name)
     90 		f.systemNameX = addString(strings, f.SystemName)
     91 		f.filenameX = addString(strings, f.Filename)
     92 	}
     93 
     94 	p.dropFramesX = addString(strings, p.DropFrames)
     95 	p.keepFramesX = addString(strings, p.KeepFrames)
     96 
     97 	if pt := p.PeriodType; pt != nil {
     98 		pt.typeX = addString(strings, pt.Type)
     99 		pt.unitX = addString(strings, pt.Unit)
    100 	}
    101 
    102 	p.stringTable = make([]string, len(strings))
    103 	for s, i := range strings {
    104 		p.stringTable[i] = s
    105 	}
    106 }
    107 
    108 func (p *Profile) encode(b *buffer) {
    109 	for _, x := range p.SampleType {
    110 		encodeMessage(b, 1, x)
    111 	}
    112 	for _, x := range p.Sample {
    113 		encodeMessage(b, 2, x)
    114 	}
    115 	for _, x := range p.Mapping {
    116 		encodeMessage(b, 3, x)
    117 	}
    118 	for _, x := range p.Location {
    119 		encodeMessage(b, 4, x)
    120 	}
    121 	for _, x := range p.Function {
    122 		encodeMessage(b, 5, x)
    123 	}
    124 	encodeStrings(b, 6, p.stringTable)
    125 	encodeInt64Opt(b, 7, p.dropFramesX)
    126 	encodeInt64Opt(b, 8, p.keepFramesX)
    127 	encodeInt64Opt(b, 9, p.TimeNanos)
    128 	encodeInt64Opt(b, 10, p.DurationNanos)
    129 	if pt := p.PeriodType; pt != nil && (pt.typeX != 0 || pt.unitX != 0) {
    130 		encodeMessage(b, 11, p.PeriodType)
    131 	}
    132 	encodeInt64Opt(b, 12, p.Period)
    133 }
    134 
    135 var profileDecoder = []decoder{
    136 	nil, // 0
    137 	// repeated ValueType sample_type = 1
    138 	func(b *buffer, m message) error {
    139 		x := new(ValueType)
    140 		pp := m.(*Profile)
    141 		pp.SampleType = append(pp.SampleType, x)
    142 		return decodeMessage(b, x)
    143 	},
    144 	// repeated Sample sample = 2
    145 	func(b *buffer, m message) error {
    146 		x := new(Sample)
    147 		pp := m.(*Profile)
    148 		pp.Sample = append(pp.Sample, x)
    149 		return decodeMessage(b, x)
    150 	},
    151 	// repeated Mapping mapping = 3
    152 	func(b *buffer, m message) error {
    153 		x := new(Mapping)
    154 		pp := m.(*Profile)
    155 		pp.Mapping = append(pp.Mapping, x)
    156 		return decodeMessage(b, x)
    157 	},
    158 	// repeated Location location = 4
    159 	func(b *buffer, m message) error {
    160 		x := new(Location)
    161 		pp := m.(*Profile)
    162 		pp.Location = append(pp.Location, x)
    163 		return decodeMessage(b, x)
    164 	},
    165 	// repeated Function function = 5
    166 	func(b *buffer, m message) error {
    167 		x := new(Function)
    168 		pp := m.(*Profile)
    169 		pp.Function = append(pp.Function, x)
    170 		return decodeMessage(b, x)
    171 	},
    172 	// repeated string string_table = 6
    173 	func(b *buffer, m message) error {
    174 		err := decodeStrings(b, &m.(*Profile).stringTable)
    175 		if err != nil {
    176 			return err
    177 		}
    178 		if *&m.(*Profile).stringTable[0] != "" {
    179 			return errors.New("string_table[0] must be ''")
    180 		}
    181 		return nil
    182 	},
    183 	// repeated int64 drop_frames = 7
    184 	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).dropFramesX) },
    185 	// repeated int64 keep_frames = 8
    186 	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).keepFramesX) },
    187 	// repeated int64 time_nanos = 9
    188 	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).TimeNanos) },
    189 	// repeated int64 duration_nanos = 10
    190 	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).DurationNanos) },
    191 	// optional string period_type = 11
    192 	func(b *buffer, m message) error {
    193 		x := new(ValueType)
    194 		pp := m.(*Profile)
    195 		pp.PeriodType = x
    196 		return decodeMessage(b, x)
    197 	},
    198 	// repeated int64 period = 12
    199 	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).Period) },
    200 }
    201 
    202 // postDecode takes the unexported fields populated by decode (with
    203 // suffix X) and populates the corresponding exported fields.
    204 // The unexported fields are cleared up to facilitate testing.
    205 func (p *Profile) postDecode() error {
    206 	var err error
    207 
    208 	mappings := make(map[uint64]*Mapping)
    209 	for _, m := range p.Mapping {
    210 		m.File, err = getString(p.stringTable, &m.fileX, err)
    211 		m.BuildID, err = getString(p.stringTable, &m.buildIDX, err)
    212 		mappings[m.ID] = m
    213 	}
    214 
    215 	functions := make(map[uint64]*Function)
    216 	for _, f := range p.Function {
    217 		f.Name, err = getString(p.stringTable, &f.nameX, err)
    218 		f.SystemName, err = getString(p.stringTable, &f.systemNameX, err)
    219 		f.Filename, err = getString(p.stringTable, &f.filenameX, err)
    220 		functions[f.ID] = f
    221 	}
    222 
    223 	locations := make(map[uint64]*Location)
    224 	for _, l := range p.Location {
    225 		l.Mapping = mappings[l.mappingIDX]
    226 		l.mappingIDX = 0
    227 		for i, ln := range l.Line {
    228 			if id := ln.functionIDX; id != 0 {
    229 				l.Line[i].Function = functions[id]
    230 				if l.Line[i].Function == nil {
    231 					return fmt.Errorf("Function ID %d not found", id)
    232 				}
    233 				l.Line[i].functionIDX = 0
    234 			}
    235 		}
    236 		locations[l.ID] = l
    237 	}
    238 
    239 	for _, st := range p.SampleType {
    240 		st.Type, err = getString(p.stringTable, &st.typeX, err)
    241 		st.Unit, err = getString(p.stringTable, &st.unitX, err)
    242 	}
    243 
    244 	for _, s := range p.Sample {
    245 		labels := make(map[string][]string)
    246 		numLabels := make(map[string][]int64)
    247 		for _, l := range s.labelX {
    248 			var key, value string
    249 			key, err = getString(p.stringTable, &l.keyX, err)
    250 			if l.strX != 0 {
    251 				value, err = getString(p.stringTable, &l.strX, err)
    252 				labels[key] = append(labels[key], value)
    253 			} else {
    254 				numLabels[key] = append(numLabels[key], l.numX)
    255 			}
    256 		}
    257 		if len(labels) > 0 {
    258 			s.Label = labels
    259 		}
    260 		if len(numLabels) > 0 {
    261 			s.NumLabel = numLabels
    262 		}
    263 		s.Location = nil
    264 		for _, lid := range s.locationIDX {
    265 			s.Location = append(s.Location, locations[lid])
    266 		}
    267 		s.locationIDX = nil
    268 	}
    269 
    270 	p.DropFrames, err = getString(p.stringTable, &p.dropFramesX, err)
    271 	p.KeepFrames, err = getString(p.stringTable, &p.keepFramesX, err)
    272 
    273 	if pt := p.PeriodType; pt == nil {
    274 		p.PeriodType = &ValueType{}
    275 	}
    276 
    277 	if pt := p.PeriodType; pt != nil {
    278 		pt.Type, err = getString(p.stringTable, &pt.typeX, err)
    279 		pt.Unit, err = getString(p.stringTable, &pt.unitX, err)
    280 	}
    281 	p.stringTable = nil
    282 	return nil
    283 }
    284 
    285 func (p *ValueType) decoder() []decoder {
    286 	return valueTypeDecoder
    287 }
    288 
    289 func (p *ValueType) encode(b *buffer) {
    290 	encodeInt64Opt(b, 1, p.typeX)
    291 	encodeInt64Opt(b, 2, p.unitX)
    292 }
    293 
    294 var valueTypeDecoder = []decoder{
    295 	nil, // 0
    296 	// optional int64 type = 1
    297 	func(b *buffer, m message) error { return decodeInt64(b, &m.(*ValueType).typeX) },
    298 	// optional int64 unit = 2
    299 	func(b *buffer, m message) error { return decodeInt64(b, &m.(*ValueType).unitX) },
    300 }
    301 
    302 func (p *Sample) decoder() []decoder {
    303 	return sampleDecoder
    304 }
    305 
    306 func (p *Sample) encode(b *buffer) {
    307 	encodeUint64s(b, 1, p.locationIDX)
    308 	for _, x := range p.Value {
    309 		encodeInt64(b, 2, x)
    310 	}
    311 	for _, x := range p.labelX {
    312 		encodeMessage(b, 3, x)
    313 	}
    314 }
    315 
    316 var sampleDecoder = []decoder{
    317 	nil, // 0
    318 	// repeated uint64 location = 1
    319 	func(b *buffer, m message) error { return decodeUint64s(b, &m.(*Sample).locationIDX) },
    320 	// repeated int64 value = 2
    321 	func(b *buffer, m message) error { return decodeInt64s(b, &m.(*Sample).Value) },
    322 	// repeated Label label = 3
    323 	func(b *buffer, m message) error {
    324 		s := m.(*Sample)
    325 		n := len(s.labelX)
    326 		s.labelX = append(s.labelX, Label{})
    327 		return decodeMessage(b, &s.labelX[n])
    328 	},
    329 }
    330 
    331 func (p Label) decoder() []decoder {
    332 	return labelDecoder
    333 }
    334 
    335 func (p Label) encode(b *buffer) {
    336 	encodeInt64Opt(b, 1, p.keyX)
    337 	encodeInt64Opt(b, 2, p.strX)
    338 	encodeInt64Opt(b, 3, p.numX)
    339 }
    340 
    341 var labelDecoder = []decoder{
    342 	nil, // 0
    343 	// optional int64 key = 1
    344 	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Label).keyX) },
    345 	// optional int64 str = 2
    346 	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Label).strX) },
    347 	// optional int64 num = 3
    348 	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Label).numX) },
    349 }
    350 
    351 func (p *Mapping) decoder() []decoder {
    352 	return mappingDecoder
    353 }
    354 
    355 func (p *Mapping) encode(b *buffer) {
    356 	encodeUint64Opt(b, 1, p.ID)
    357 	encodeUint64Opt(b, 2, p.Start)
    358 	encodeUint64Opt(b, 3, p.Limit)
    359 	encodeUint64Opt(b, 4, p.Offset)
    360 	encodeInt64Opt(b, 5, p.fileX)
    361 	encodeInt64Opt(b, 6, p.buildIDX)
    362 	encodeBoolOpt(b, 7, p.HasFunctions)
    363 	encodeBoolOpt(b, 8, p.HasFilenames)
    364 	encodeBoolOpt(b, 9, p.HasLineNumbers)
    365 	encodeBoolOpt(b, 10, p.HasInlineFrames)
    366 }
    367 
    368 var mappingDecoder = []decoder{
    369 	nil, // 0
    370 	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).ID) },            // optional uint64 id = 1
    371 	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).Start) },         // optional uint64 memory_offset = 2
    372 	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).Limit) },         // optional uint64 memory_limit = 3
    373 	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).Offset) },        // optional uint64 file_offset = 4
    374 	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Mapping).fileX) },          // optional int64 filename = 5
    375 	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Mapping).buildIDX) },       // optional int64 build_id = 6
    376 	func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasFunctions) },    // optional bool has_functions = 7
    377 	func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasFilenames) },    // optional bool has_filenames = 8
    378 	func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasLineNumbers) },  // optional bool has_line_numbers = 9
    379 	func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasInlineFrames) }, // optional bool has_inline_frames = 10
    380 }
    381 
    382 func (p *Location) decoder() []decoder {
    383 	return locationDecoder
    384 }
    385 
    386 func (p *Location) encode(b *buffer) {
    387 	encodeUint64Opt(b, 1, p.ID)
    388 	encodeUint64Opt(b, 2, p.mappingIDX)
    389 	encodeUint64Opt(b, 3, p.Address)
    390 	for i := range p.Line {
    391 		encodeMessage(b, 4, &p.Line[i])
    392 	}
    393 }
    394 
    395 var locationDecoder = []decoder{
    396 	nil, // 0
    397 	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Location).ID) },         // optional uint64 id = 1;
    398 	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Location).mappingIDX) }, // optional uint64 mapping_id = 2;
    399 	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Location).Address) },    // optional uint64 address = 3;
    400 	func(b *buffer, m message) error { // repeated Line line = 4
    401 		pp := m.(*Location)
    402 		n := len(pp.Line)
    403 		pp.Line = append(pp.Line, Line{})
    404 		return decodeMessage(b, &pp.Line[n])
    405 	},
    406 }
    407 
    408 func (p *Line) decoder() []decoder {
    409 	return lineDecoder
    410 }
    411 
    412 func (p *Line) encode(b *buffer) {
    413 	encodeUint64Opt(b, 1, p.functionIDX)
    414 	encodeInt64Opt(b, 2, p.Line)
    415 }
    416 
    417 var lineDecoder = []decoder{
    418 	nil, // 0
    419 	// optional uint64 function_id = 1
    420 	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Line).functionIDX) },
    421 	// optional int64 line = 2
    422 	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Line).Line) },
    423 }
    424 
    425 func (p *Function) decoder() []decoder {
    426 	return functionDecoder
    427 }
    428 
    429 func (p *Function) encode(b *buffer) {
    430 	encodeUint64Opt(b, 1, p.ID)
    431 	encodeInt64Opt(b, 2, p.nameX)
    432 	encodeInt64Opt(b, 3, p.systemNameX)
    433 	encodeInt64Opt(b, 4, p.filenameX)
    434 	encodeInt64Opt(b, 5, p.StartLine)
    435 }
    436 
    437 var functionDecoder = []decoder{
    438 	nil, // 0
    439 	// optional uint64 id = 1
    440 	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Function).ID) },
    441 	// optional int64 function_name = 2
    442 	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).nameX) },
    443 	// optional int64 function_system_name = 3
    444 	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).systemNameX) },
    445 	// repeated int64 filename = 4
    446 	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).filenameX) },
    447 	// optional int64 start_line = 5
    448 	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).StartLine) },
    449 }
    450 
    451 func addString(strings map[string]int, s string) int64 {
    452 	i, ok := strings[s]
    453 	if !ok {
    454 		i = len(strings)
    455 		strings[s] = i
    456 	}
    457 	return int64(i)
    458 }
    459 
    460 func getString(strings []string, strng *int64, err error) (string, error) {
    461 	if err != nil {
    462 		return "", err
    463 	}
    464 	s := int(*strng)
    465 	if s < 0 || s >= len(strings) {
    466 		return "", errMalformed
    467 	}
    468 	*strng = 0
    469 	return strings[s], nil
    470 }
    471