Home | History | Annotate | Download | only in profile
      1 // Copyright 2014 Google Inc. All Rights Reserved.
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //     http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 package profile
     16 
     17 import (
     18 	"errors"
     19 	"sort"
     20 )
     21 
     22 func (p *Profile) decoder() []decoder {
     23 	return profileDecoder
     24 }
     25 
     26 // preEncode populates the unexported fields to be used by encode
     27 // (with suffix X) from the corresponding exported fields. The
     28 // exported fields are cleared up to facilitate testing.
     29 func (p *Profile) preEncode() {
     30 	strings := make(map[string]int)
     31 	addString(strings, "")
     32 
     33 	for _, st := range p.SampleType {
     34 		st.typeX = addString(strings, st.Type)
     35 		st.unitX = addString(strings, st.Unit)
     36 	}
     37 
     38 	for _, s := range p.Sample {
     39 		s.labelX = nil
     40 		var keys []string
     41 		for k := range s.Label {
     42 			keys = append(keys, k)
     43 		}
     44 		sort.Strings(keys)
     45 		for _, k := range keys {
     46 			vs := s.Label[k]
     47 			for _, v := range vs {
     48 				s.labelX = append(s.labelX,
     49 					label{
     50 						keyX: addString(strings, k),
     51 						strX: addString(strings, v),
     52 					},
     53 				)
     54 			}
     55 		}
     56 		var numKeys []string
     57 		for k := range s.NumLabel {
     58 			numKeys = append(numKeys, k)
     59 		}
     60 		sort.Strings(numKeys)
     61 		for _, k := range numKeys {
     62 			keyX := addString(strings, k)
     63 			vs := s.NumLabel[k]
     64 			units := s.NumUnit[k]
     65 			for i, v := range vs {
     66 				var unitX int64
     67 				if len(units) != 0 {
     68 					unitX = addString(strings, units[i])
     69 				}
     70 				s.labelX = append(s.labelX,
     71 					label{
     72 						keyX:  keyX,
     73 						numX:  v,
     74 						unitX: unitX,
     75 					},
     76 				)
     77 			}
     78 		}
     79 		s.locationIDX = make([]uint64, len(s.Location))
     80 		for i, loc := range s.Location {
     81 			s.locationIDX[i] = loc.ID
     82 		}
     83 	}
     84 
     85 	for _, m := range p.Mapping {
     86 		m.fileX = addString(strings, m.File)
     87 		m.buildIDX = addString(strings, m.BuildID)
     88 	}
     89 
     90 	for _, l := range p.Location {
     91 		for i, ln := range l.Line {
     92 			if ln.Function != nil {
     93 				l.Line[i].functionIDX = ln.Function.ID
     94 			} else {
     95 				l.Line[i].functionIDX = 0
     96 			}
     97 		}
     98 		if l.Mapping != nil {
     99 			l.mappingIDX = l.Mapping.ID
    100 		} else {
    101 			l.mappingIDX = 0
    102 		}
    103 	}
    104 	for _, f := range p.Function {
    105 		f.nameX = addString(strings, f.Name)
    106 		f.systemNameX = addString(strings, f.SystemName)
    107 		f.filenameX = addString(strings, f.Filename)
    108 	}
    109 
    110 	p.dropFramesX = addString(strings, p.DropFrames)
    111 	p.keepFramesX = addString(strings, p.KeepFrames)
    112 
    113 	if pt := p.PeriodType; pt != nil {
    114 		pt.typeX = addString(strings, pt.Type)
    115 		pt.unitX = addString(strings, pt.Unit)
    116 	}
    117 
    118 	p.commentX = nil
    119 	for _, c := range p.Comments {
    120 		p.commentX = append(p.commentX, addString(strings, c))
    121 	}
    122 
    123 	p.defaultSampleTypeX = addString(strings, p.DefaultSampleType)
    124 
    125 	p.stringTable = make([]string, len(strings))
    126 	for s, i := range strings {
    127 		p.stringTable[i] = s
    128 	}
    129 }
    130 
    131 func (p *Profile) encode(b *buffer) {
    132 	for _, x := range p.SampleType {
    133 		encodeMessage(b, 1, x)
    134 	}
    135 	for _, x := range p.Sample {
    136 		encodeMessage(b, 2, x)
    137 	}
    138 	for _, x := range p.Mapping {
    139 		encodeMessage(b, 3, x)
    140 	}
    141 	for _, x := range p.Location {
    142 		encodeMessage(b, 4, x)
    143 	}
    144 	for _, x := range p.Function {
    145 		encodeMessage(b, 5, x)
    146 	}
    147 	encodeStrings(b, 6, p.stringTable)
    148 	encodeInt64Opt(b, 7, p.dropFramesX)
    149 	encodeInt64Opt(b, 8, p.keepFramesX)
    150 	encodeInt64Opt(b, 9, p.TimeNanos)
    151 	encodeInt64Opt(b, 10, p.DurationNanos)
    152 	if pt := p.PeriodType; pt != nil && (pt.typeX != 0 || pt.unitX != 0) {
    153 		encodeMessage(b, 11, p.PeriodType)
    154 	}
    155 	encodeInt64Opt(b, 12, p.Period)
    156 	encodeInt64s(b, 13, p.commentX)
    157 	encodeInt64(b, 14, p.defaultSampleTypeX)
    158 }
    159 
    160 var profileDecoder = []decoder{
    161 	nil, // 0
    162 	// repeated ValueType sample_type = 1
    163 	func(b *buffer, m message) error {
    164 		x := new(ValueType)
    165 		pp := m.(*Profile)
    166 		pp.SampleType = append(pp.SampleType, x)
    167 		return decodeMessage(b, x)
    168 	},
    169 	// repeated Sample sample = 2
    170 	func(b *buffer, m message) error {
    171 		x := new(Sample)
    172 		pp := m.(*Profile)
    173 		pp.Sample = append(pp.Sample, x)
    174 		return decodeMessage(b, x)
    175 	},
    176 	// repeated Mapping mapping = 3
    177 	func(b *buffer, m message) error {
    178 		x := new(Mapping)
    179 		pp := m.(*Profile)
    180 		pp.Mapping = append(pp.Mapping, x)
    181 		return decodeMessage(b, x)
    182 	},
    183 	// repeated Location location = 4
    184 	func(b *buffer, m message) error {
    185 		x := new(Location)
    186 		x.Line = make([]Line, 0, 8) // Pre-allocate Line buffer
    187 		pp := m.(*Profile)
    188 		pp.Location = append(pp.Location, x)
    189 		err := decodeMessage(b, x)
    190 		var tmp []Line
    191 		x.Line = append(tmp, x.Line...) // Shrink to allocated size
    192 		return err
    193 	},
    194 	// repeated Function function = 5
    195 	func(b *buffer, m message) error {
    196 		x := new(Function)
    197 		pp := m.(*Profile)
    198 		pp.Function = append(pp.Function, x)
    199 		return decodeMessage(b, x)
    200 	},
    201 	// repeated string string_table = 6
    202 	func(b *buffer, m message) error {
    203 		err := decodeStrings(b, &m.(*Profile).stringTable)
    204 		if err != nil {
    205 			return err
    206 		}
    207 		if m.(*Profile).stringTable[0] != "" {
    208 			return errors.New("string_table[0] must be ''")
    209 		}
    210 		return nil
    211 	},
    212 	// int64 drop_frames = 7
    213 	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).dropFramesX) },
    214 	// int64 keep_frames = 8
    215 	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).keepFramesX) },
    216 	// int64 time_nanos = 9
    217 	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).TimeNanos) },
    218 	// int64 duration_nanos = 10
    219 	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).DurationNanos) },
    220 	// ValueType period_type = 11
    221 	func(b *buffer, m message) error {
    222 		x := new(ValueType)
    223 		pp := m.(*Profile)
    224 		pp.PeriodType = x
    225 		return decodeMessage(b, x)
    226 	},
    227 	// int64 period = 12
    228 	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).Period) },
    229 	// repeated int64 comment = 13
    230 	func(b *buffer, m message) error { return decodeInt64s(b, &m.(*Profile).commentX) },
    231 	// int64 defaultSampleType = 14
    232 	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).defaultSampleTypeX) },
    233 }
    234 
    235 // postDecode takes the unexported fields populated by decode (with
    236 // suffix X) and populates the corresponding exported fields.
    237 // The unexported fields are cleared up to facilitate testing.
    238 func (p *Profile) postDecode() error {
    239 	var err error
    240 	mappings := make(map[uint64]*Mapping, len(p.Mapping))
    241 	mappingIds := make([]*Mapping, len(p.Mapping)+1)
    242 	for _, m := range p.Mapping {
    243 		m.File, err = getString(p.stringTable, &m.fileX, err)
    244 		m.BuildID, err = getString(p.stringTable, &m.buildIDX, err)
    245 		if m.ID < uint64(len(mappingIds)) {
    246 			mappingIds[m.ID] = m
    247 		} else {
    248 			mappings[m.ID] = m
    249 		}
    250 	}
    251 
    252 	functions := make(map[uint64]*Function, len(p.Function))
    253 	functionIds := make([]*Function, len(p.Function)+1)
    254 	for _, f := range p.Function {
    255 		f.Name, err = getString(p.stringTable, &f.nameX, err)
    256 		f.SystemName, err = getString(p.stringTable, &f.systemNameX, err)
    257 		f.Filename, err = getString(p.stringTable, &f.filenameX, err)
    258 		if f.ID < uint64(len(functionIds)) {
    259 			functionIds[f.ID] = f
    260 		} else {
    261 			functions[f.ID] = f
    262 		}
    263 	}
    264 
    265 	locations := make(map[uint64]*Location, len(p.Location))
    266 	locationIds := make([]*Location, len(p.Location)+1)
    267 	for _, l := range p.Location {
    268 		if id := l.mappingIDX; id < uint64(len(mappingIds)) {
    269 			l.Mapping = mappingIds[id]
    270 		} else {
    271 			l.Mapping = mappings[id]
    272 		}
    273 		l.mappingIDX = 0
    274 		for i, ln := range l.Line {
    275 			if id := ln.functionIDX; id != 0 {
    276 				l.Line[i].functionIDX = 0
    277 				if id < uint64(len(functionIds)) {
    278 					l.Line[i].Function = functionIds[id]
    279 				} else {
    280 					l.Line[i].Function = functions[id]
    281 				}
    282 			}
    283 		}
    284 		if l.ID < uint64(len(locationIds)) {
    285 			locationIds[l.ID] = l
    286 		} else {
    287 			locations[l.ID] = l
    288 		}
    289 	}
    290 
    291 	for _, st := range p.SampleType {
    292 		st.Type, err = getString(p.stringTable, &st.typeX, err)
    293 		st.Unit, err = getString(p.stringTable, &st.unitX, err)
    294 	}
    295 
    296 	for _, s := range p.Sample {
    297 		labels := make(map[string][]string, len(s.labelX))
    298 		numLabels := make(map[string][]int64, len(s.labelX))
    299 		numUnits := make(map[string][]string, len(s.labelX))
    300 		for _, l := range s.labelX {
    301 			var key, value string
    302 			key, err = getString(p.stringTable, &l.keyX, err)
    303 			if l.strX != 0 {
    304 				value, err = getString(p.stringTable, &l.strX, err)
    305 				labels[key] = append(labels[key], value)
    306 			} else if l.numX != 0 {
    307 				numValues := numLabels[key]
    308 				units := numUnits[key]
    309 				if l.unitX != 0 {
    310 					var unit string
    311 					unit, err = getString(p.stringTable, &l.unitX, err)
    312 					units = padStringArray(units, len(numValues))
    313 					numUnits[key] = append(units, unit)
    314 				}
    315 				numLabels[key] = append(numLabels[key], l.numX)
    316 			}
    317 		}
    318 		if len(labels) > 0 {
    319 			s.Label = labels
    320 		}
    321 		if len(numLabels) > 0 {
    322 			s.NumLabel = numLabels
    323 			for key, units := range numUnits {
    324 				if len(units) > 0 {
    325 					numUnits[key] = padStringArray(units, len(numLabels[key]))
    326 				}
    327 			}
    328 			s.NumUnit = numUnits
    329 		}
    330 		s.Location = make([]*Location, len(s.locationIDX))
    331 		for i, lid := range s.locationIDX {
    332 			if lid < uint64(len(locationIds)) {
    333 				s.Location[i] = locationIds[lid]
    334 			} else {
    335 				s.Location[i] = locations[lid]
    336 			}
    337 		}
    338 		s.locationIDX = nil
    339 	}
    340 
    341 	p.DropFrames, err = getString(p.stringTable, &p.dropFramesX, err)
    342 	p.KeepFrames, err = getString(p.stringTable, &p.keepFramesX, err)
    343 
    344 	if pt := p.PeriodType; pt == nil {
    345 		p.PeriodType = &ValueType{}
    346 	}
    347 
    348 	if pt := p.PeriodType; pt != nil {
    349 		pt.Type, err = getString(p.stringTable, &pt.typeX, err)
    350 		pt.Unit, err = getString(p.stringTable, &pt.unitX, err)
    351 	}
    352 
    353 	for _, i := range p.commentX {
    354 		var c string
    355 		c, err = getString(p.stringTable, &i, err)
    356 		p.Comments = append(p.Comments, c)
    357 	}
    358 
    359 	p.commentX = nil
    360 	p.DefaultSampleType, err = getString(p.stringTable, &p.defaultSampleTypeX, err)
    361 	p.stringTable = nil
    362 	return err
    363 }
    364 
    365 // padStringArray pads arr with enough empty strings to make arr
    366 // length l when arr's length is less than l.
    367 func padStringArray(arr []string, l int) []string {
    368 	if l <= len(arr) {
    369 		return arr
    370 	}
    371 	return append(arr, make([]string, l-len(arr))...)
    372 }
    373 
    374 func (p *ValueType) decoder() []decoder {
    375 	return valueTypeDecoder
    376 }
    377 
    378 func (p *ValueType) encode(b *buffer) {
    379 	encodeInt64Opt(b, 1, p.typeX)
    380 	encodeInt64Opt(b, 2, p.unitX)
    381 }
    382 
    383 var valueTypeDecoder = []decoder{
    384 	nil, // 0
    385 	// optional int64 type = 1
    386 	func(b *buffer, m message) error { return decodeInt64(b, &m.(*ValueType).typeX) },
    387 	// optional int64 unit = 2
    388 	func(b *buffer, m message) error { return decodeInt64(b, &m.(*ValueType).unitX) },
    389 }
    390 
    391 func (p *Sample) decoder() []decoder {
    392 	return sampleDecoder
    393 }
    394 
    395 func (p *Sample) encode(b *buffer) {
    396 	encodeUint64s(b, 1, p.locationIDX)
    397 	encodeInt64s(b, 2, p.Value)
    398 	for _, x := range p.labelX {
    399 		encodeMessage(b, 3, x)
    400 	}
    401 }
    402 
    403 var sampleDecoder = []decoder{
    404 	nil, // 0
    405 	// repeated uint64 location = 1
    406 	func(b *buffer, m message) error { return decodeUint64s(b, &m.(*Sample).locationIDX) },
    407 	// repeated int64 value = 2
    408 	func(b *buffer, m message) error { return decodeInt64s(b, &m.(*Sample).Value) },
    409 	// repeated Label label = 3
    410 	func(b *buffer, m message) error {
    411 		s := m.(*Sample)
    412 		n := len(s.labelX)
    413 		s.labelX = append(s.labelX, label{})
    414 		return decodeMessage(b, &s.labelX[n])
    415 	},
    416 }
    417 
    418 func (p label) decoder() []decoder {
    419 	return labelDecoder
    420 }
    421 
    422 func (p label) encode(b *buffer) {
    423 	encodeInt64Opt(b, 1, p.keyX)
    424 	encodeInt64Opt(b, 2, p.strX)
    425 	encodeInt64Opt(b, 3, p.numX)
    426 	encodeInt64Opt(b, 4, p.unitX)
    427 }
    428 
    429 var labelDecoder = []decoder{
    430 	nil, // 0
    431 	// optional int64 key = 1
    432 	func(b *buffer, m message) error { return decodeInt64(b, &m.(*label).keyX) },
    433 	// optional int64 str = 2
    434 	func(b *buffer, m message) error { return decodeInt64(b, &m.(*label).strX) },
    435 	// optional int64 num = 3
    436 	func(b *buffer, m message) error { return decodeInt64(b, &m.(*label).numX) },
    437 	// optional int64 num = 4
    438 	func(b *buffer, m message) error { return decodeInt64(b, &m.(*label).unitX) },
    439 }
    440 
    441 func (p *Mapping) decoder() []decoder {
    442 	return mappingDecoder
    443 }
    444 
    445 func (p *Mapping) encode(b *buffer) {
    446 	encodeUint64Opt(b, 1, p.ID)
    447 	encodeUint64Opt(b, 2, p.Start)
    448 	encodeUint64Opt(b, 3, p.Limit)
    449 	encodeUint64Opt(b, 4, p.Offset)
    450 	encodeInt64Opt(b, 5, p.fileX)
    451 	encodeInt64Opt(b, 6, p.buildIDX)
    452 	encodeBoolOpt(b, 7, p.HasFunctions)
    453 	encodeBoolOpt(b, 8, p.HasFilenames)
    454 	encodeBoolOpt(b, 9, p.HasLineNumbers)
    455 	encodeBoolOpt(b, 10, p.HasInlineFrames)
    456 }
    457 
    458 var mappingDecoder = []decoder{
    459 	nil, // 0
    460 	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).ID) },            // optional uint64 id = 1
    461 	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).Start) },         // optional uint64 memory_offset = 2
    462 	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).Limit) },         // optional uint64 memory_limit = 3
    463 	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).Offset) },        // optional uint64 file_offset = 4
    464 	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Mapping).fileX) },          // optional int64 filename = 5
    465 	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Mapping).buildIDX) },       // optional int64 build_id = 6
    466 	func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasFunctions) },    // optional bool has_functions = 7
    467 	func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasFilenames) },    // optional bool has_filenames = 8
    468 	func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasLineNumbers) },  // optional bool has_line_numbers = 9
    469 	func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasInlineFrames) }, // optional bool has_inline_frames = 10
    470 }
    471 
    472 func (p *Location) decoder() []decoder {
    473 	return locationDecoder
    474 }
    475 
    476 func (p *Location) encode(b *buffer) {
    477 	encodeUint64Opt(b, 1, p.ID)
    478 	encodeUint64Opt(b, 2, p.mappingIDX)
    479 	encodeUint64Opt(b, 3, p.Address)
    480 	for i := range p.Line {
    481 		encodeMessage(b, 4, &p.Line[i])
    482 	}
    483 }
    484 
    485 var locationDecoder = []decoder{
    486 	nil, // 0
    487 	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Location).ID) },         // optional uint64 id = 1;
    488 	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Location).mappingIDX) }, // optional uint64 mapping_id = 2;
    489 	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Location).Address) },    // optional uint64 address = 3;
    490 	func(b *buffer, m message) error { // repeated Line line = 4
    491 		pp := m.(*Location)
    492 		n := len(pp.Line)
    493 		pp.Line = append(pp.Line, Line{})
    494 		return decodeMessage(b, &pp.Line[n])
    495 	},
    496 }
    497 
    498 func (p *Line) decoder() []decoder {
    499 	return lineDecoder
    500 }
    501 
    502 func (p *Line) encode(b *buffer) {
    503 	encodeUint64Opt(b, 1, p.functionIDX)
    504 	encodeInt64Opt(b, 2, p.Line)
    505 }
    506 
    507 var lineDecoder = []decoder{
    508 	nil, // 0
    509 	// optional uint64 function_id = 1
    510 	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Line).functionIDX) },
    511 	// optional int64 line = 2
    512 	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Line).Line) },
    513 }
    514 
    515 func (p *Function) decoder() []decoder {
    516 	return functionDecoder
    517 }
    518 
    519 func (p *Function) encode(b *buffer) {
    520 	encodeUint64Opt(b, 1, p.ID)
    521 	encodeInt64Opt(b, 2, p.nameX)
    522 	encodeInt64Opt(b, 3, p.systemNameX)
    523 	encodeInt64Opt(b, 4, p.filenameX)
    524 	encodeInt64Opt(b, 5, p.StartLine)
    525 }
    526 
    527 var functionDecoder = []decoder{
    528 	nil, // 0
    529 	// optional uint64 id = 1
    530 	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Function).ID) },
    531 	// optional int64 function_name = 2
    532 	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).nameX) },
    533 	// optional int64 function_system_name = 3
    534 	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).systemNameX) },
    535 	// repeated int64 filename = 4
    536 	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).filenameX) },
    537 	// optional int64 start_line = 5
    538 	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).StartLine) },
    539 }
    540 
    541 func addString(strings map[string]int, s string) int64 {
    542 	i, ok := strings[s]
    543 	if !ok {
    544 		i = len(strings)
    545 		strings[s] = i
    546 	}
    547 	return int64(i)
    548 }
    549 
    550 func getString(strings []string, strng *int64, err error) (string, error) {
    551 	if err != nil {
    552 		return "", err
    553 	}
    554 	s := int(*strng)
    555 	if s < 0 || s >= len(strings) {
    556 		return "", errMalformed
    557 	}
    558 	*strng = 0
    559 	return strings[s], nil
    560 }
    561