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 5package profile 6 7import ( 8 "errors" 9 "fmt" 10 "sort" 11) 12 13func (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. 20func (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 108func (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 135var 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. 205func (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 285func (p *ValueType) decoder() []decoder { 286 return valueTypeDecoder 287} 288 289func (p *ValueType) encode(b *buffer) { 290 encodeInt64Opt(b, 1, p.typeX) 291 encodeInt64Opt(b, 2, p.unitX) 292} 293 294var 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 302func (p *Sample) decoder() []decoder { 303 return sampleDecoder 304} 305 306func (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 316var 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 331func (p Label) decoder() []decoder { 332 return labelDecoder 333} 334 335func (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 341var 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 351func (p *Mapping) decoder() []decoder { 352 return mappingDecoder 353} 354 355func (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 368var 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 382func (p *Location) decoder() []decoder { 383 return locationDecoder 384} 385 386func (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 395var 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 408func (p *Line) decoder() []decoder { 409 return lineDecoder 410} 411 412func (p *Line) encode(b *buffer) { 413 encodeUint64Opt(b, 1, p.functionIDX) 414 encodeInt64Opt(b, 2, p.Line) 415} 416 417var 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 425func (p *Function) decoder() []decoder { 426 return functionDecoder 427} 428 429func (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 437var 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 451func 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 460func 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