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