...

Source file src/pkg/cmd/vendor/github.com/google/pprof/profile/encode.go

     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 {
   218			if m.(*Profile).TimeNanos != 0 {
   219				return errConcatProfile
   220			}
   221			return decodeInt64(b, &m.(*Profile).TimeNanos)
   222		},
   223		// int64 duration_nanos = 10
   224		func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).DurationNanos) },
   225		// ValueType period_type = 11
   226		func(b *buffer, m message) error {
   227			x := new(ValueType)
   228			pp := m.(*Profile)
   229			pp.PeriodType = x
   230			return decodeMessage(b, x)
   231		},
   232		// int64 period = 12
   233		func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).Period) },
   234		// repeated int64 comment = 13
   235		func(b *buffer, m message) error { return decodeInt64s(b, &m.(*Profile).commentX) },
   236		// int64 defaultSampleType = 14
   237		func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).defaultSampleTypeX) },
   238	}
   239	
   240	// postDecode takes the unexported fields populated by decode (with
   241	// suffix X) and populates the corresponding exported fields.
   242	// The unexported fields are cleared up to facilitate testing.
   243	func (p *Profile) postDecode() error {
   244		var err error
   245		mappings := make(map[uint64]*Mapping, len(p.Mapping))
   246		mappingIds := make([]*Mapping, len(p.Mapping)+1)
   247		for _, m := range p.Mapping {
   248			m.File, err = getString(p.stringTable, &m.fileX, err)
   249			m.BuildID, err = getString(p.stringTable, &m.buildIDX, err)
   250			if m.ID < uint64(len(mappingIds)) {
   251				mappingIds[m.ID] = m
   252			} else {
   253				mappings[m.ID] = m
   254			}
   255		}
   256	
   257		functions := make(map[uint64]*Function, len(p.Function))
   258		functionIds := make([]*Function, len(p.Function)+1)
   259		for _, f := range p.Function {
   260			f.Name, err = getString(p.stringTable, &f.nameX, err)
   261			f.SystemName, err = getString(p.stringTable, &f.systemNameX, err)
   262			f.Filename, err = getString(p.stringTable, &f.filenameX, err)
   263			if f.ID < uint64(len(functionIds)) {
   264				functionIds[f.ID] = f
   265			} else {
   266				functions[f.ID] = f
   267			}
   268		}
   269	
   270		locations := make(map[uint64]*Location, len(p.Location))
   271		locationIds := make([]*Location, len(p.Location)+1)
   272		for _, l := range p.Location {
   273			if id := l.mappingIDX; id < uint64(len(mappingIds)) {
   274				l.Mapping = mappingIds[id]
   275			} else {
   276				l.Mapping = mappings[id]
   277			}
   278			l.mappingIDX = 0
   279			for i, ln := range l.Line {
   280				if id := ln.functionIDX; id != 0 {
   281					l.Line[i].functionIDX = 0
   282					if id < uint64(len(functionIds)) {
   283						l.Line[i].Function = functionIds[id]
   284					} else {
   285						l.Line[i].Function = functions[id]
   286					}
   287				}
   288			}
   289			if l.ID < uint64(len(locationIds)) {
   290				locationIds[l.ID] = l
   291			} else {
   292				locations[l.ID] = l
   293			}
   294		}
   295	
   296		for _, st := range p.SampleType {
   297			st.Type, err = getString(p.stringTable, &st.typeX, err)
   298			st.Unit, err = getString(p.stringTable, &st.unitX, err)
   299		}
   300	
   301		for _, s := range p.Sample {
   302			labels := make(map[string][]string, len(s.labelX))
   303			numLabels := make(map[string][]int64, len(s.labelX))
   304			numUnits := make(map[string][]string, len(s.labelX))
   305			for _, l := range s.labelX {
   306				var key, value string
   307				key, err = getString(p.stringTable, &l.keyX, err)
   308				if l.strX != 0 {
   309					value, err = getString(p.stringTable, &l.strX, err)
   310					labels[key] = append(labels[key], value)
   311				} else if l.numX != 0 {
   312					numValues := numLabels[key]
   313					units := numUnits[key]
   314					if l.unitX != 0 {
   315						var unit string
   316						unit, err = getString(p.stringTable, &l.unitX, err)
   317						units = padStringArray(units, len(numValues))
   318						numUnits[key] = append(units, unit)
   319					}
   320					numLabels[key] = append(numLabels[key], l.numX)
   321				}
   322			}
   323			if len(labels) > 0 {
   324				s.Label = labels
   325			}
   326			if len(numLabels) > 0 {
   327				s.NumLabel = numLabels
   328				for key, units := range numUnits {
   329					if len(units) > 0 {
   330						numUnits[key] = padStringArray(units, len(numLabels[key]))
   331					}
   332				}
   333				s.NumUnit = numUnits
   334			}
   335			s.Location = make([]*Location, len(s.locationIDX))
   336			for i, lid := range s.locationIDX {
   337				if lid < uint64(len(locationIds)) {
   338					s.Location[i] = locationIds[lid]
   339				} else {
   340					s.Location[i] = locations[lid]
   341				}
   342			}
   343			s.locationIDX = nil
   344		}
   345	
   346		p.DropFrames, err = getString(p.stringTable, &p.dropFramesX, err)
   347		p.KeepFrames, err = getString(p.stringTable, &p.keepFramesX, err)
   348	
   349		if pt := p.PeriodType; pt == nil {
   350			p.PeriodType = &ValueType{}
   351		}
   352	
   353		if pt := p.PeriodType; pt != nil {
   354			pt.Type, err = getString(p.stringTable, &pt.typeX, err)
   355			pt.Unit, err = getString(p.stringTable, &pt.unitX, err)
   356		}
   357	
   358		for _, i := range p.commentX {
   359			var c string
   360			c, err = getString(p.stringTable, &i, err)
   361			p.Comments = append(p.Comments, c)
   362		}
   363	
   364		p.commentX = nil
   365		p.DefaultSampleType, err = getString(p.stringTable, &p.defaultSampleTypeX, err)
   366		p.stringTable = nil
   367		return err
   368	}
   369	
   370	// padStringArray pads arr with enough empty strings to make arr
   371	// length l when arr's length is less than l.
   372	func padStringArray(arr []string, l int) []string {
   373		if l <= len(arr) {
   374			return arr
   375		}
   376		return append(arr, make([]string, l-len(arr))...)
   377	}
   378	
   379	func (p *ValueType) decoder() []decoder {
   380		return valueTypeDecoder
   381	}
   382	
   383	func (p *ValueType) encode(b *buffer) {
   384		encodeInt64Opt(b, 1, p.typeX)
   385		encodeInt64Opt(b, 2, p.unitX)
   386	}
   387	
   388	var valueTypeDecoder = []decoder{
   389		nil, // 0
   390		// optional int64 type = 1
   391		func(b *buffer, m message) error { return decodeInt64(b, &m.(*ValueType).typeX) },
   392		// optional int64 unit = 2
   393		func(b *buffer, m message) error { return decodeInt64(b, &m.(*ValueType).unitX) },
   394	}
   395	
   396	func (p *Sample) decoder() []decoder {
   397		return sampleDecoder
   398	}
   399	
   400	func (p *Sample) encode(b *buffer) {
   401		encodeUint64s(b, 1, p.locationIDX)
   402		encodeInt64s(b, 2, p.Value)
   403		for _, x := range p.labelX {
   404			encodeMessage(b, 3, x)
   405		}
   406	}
   407	
   408	var sampleDecoder = []decoder{
   409		nil, // 0
   410		// repeated uint64 location = 1
   411		func(b *buffer, m message) error { return decodeUint64s(b, &m.(*Sample).locationIDX) },
   412		// repeated int64 value = 2
   413		func(b *buffer, m message) error { return decodeInt64s(b, &m.(*Sample).Value) },
   414		// repeated Label label = 3
   415		func(b *buffer, m message) error {
   416			s := m.(*Sample)
   417			n := len(s.labelX)
   418			s.labelX = append(s.labelX, label{})
   419			return decodeMessage(b, &s.labelX[n])
   420		},
   421	}
   422	
   423	func (p label) decoder() []decoder {
   424		return labelDecoder
   425	}
   426	
   427	func (p label) encode(b *buffer) {
   428		encodeInt64Opt(b, 1, p.keyX)
   429		encodeInt64Opt(b, 2, p.strX)
   430		encodeInt64Opt(b, 3, p.numX)
   431		encodeInt64Opt(b, 4, p.unitX)
   432	}
   433	
   434	var labelDecoder = []decoder{
   435		nil, // 0
   436		// optional int64 key = 1
   437		func(b *buffer, m message) error { return decodeInt64(b, &m.(*label).keyX) },
   438		// optional int64 str = 2
   439		func(b *buffer, m message) error { return decodeInt64(b, &m.(*label).strX) },
   440		// optional int64 num = 3
   441		func(b *buffer, m message) error { return decodeInt64(b, &m.(*label).numX) },
   442		// optional int64 num = 4
   443		func(b *buffer, m message) error { return decodeInt64(b, &m.(*label).unitX) },
   444	}
   445	
   446	func (p *Mapping) decoder() []decoder {
   447		return mappingDecoder
   448	}
   449	
   450	func (p *Mapping) encode(b *buffer) {
   451		encodeUint64Opt(b, 1, p.ID)
   452		encodeUint64Opt(b, 2, p.Start)
   453		encodeUint64Opt(b, 3, p.Limit)
   454		encodeUint64Opt(b, 4, p.Offset)
   455		encodeInt64Opt(b, 5, p.fileX)
   456		encodeInt64Opt(b, 6, p.buildIDX)
   457		encodeBoolOpt(b, 7, p.HasFunctions)
   458		encodeBoolOpt(b, 8, p.HasFilenames)
   459		encodeBoolOpt(b, 9, p.HasLineNumbers)
   460		encodeBoolOpt(b, 10, p.HasInlineFrames)
   461	}
   462	
   463	var mappingDecoder = []decoder{
   464		nil, // 0
   465		func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).ID) },            // optional uint64 id = 1
   466		func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).Start) },         // optional uint64 memory_offset = 2
   467		func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).Limit) },         // optional uint64 memory_limit = 3
   468		func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).Offset) },        // optional uint64 file_offset = 4
   469		func(b *buffer, m message) error { return decodeInt64(b, &m.(*Mapping).fileX) },          // optional int64 filename = 5
   470		func(b *buffer, m message) error { return decodeInt64(b, &m.(*Mapping).buildIDX) },       // optional int64 build_id = 6
   471		func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasFunctions) },    // optional bool has_functions = 7
   472		func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasFilenames) },    // optional bool has_filenames = 8
   473		func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasLineNumbers) },  // optional bool has_line_numbers = 9
   474		func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasInlineFrames) }, // optional bool has_inline_frames = 10
   475	}
   476	
   477	func (p *Location) decoder() []decoder {
   478		return locationDecoder
   479	}
   480	
   481	func (p *Location) encode(b *buffer) {
   482		encodeUint64Opt(b, 1, p.ID)
   483		encodeUint64Opt(b, 2, p.mappingIDX)
   484		encodeUint64Opt(b, 3, p.Address)
   485		for i := range p.Line {
   486			encodeMessage(b, 4, &p.Line[i])
   487		}
   488		encodeBoolOpt(b, 5, p.IsFolded)
   489	}
   490	
   491	var locationDecoder = []decoder{
   492		nil, // 0
   493		func(b *buffer, m message) error { return decodeUint64(b, &m.(*Location).ID) },         // optional uint64 id = 1;
   494		func(b *buffer, m message) error { return decodeUint64(b, &m.(*Location).mappingIDX) }, // optional uint64 mapping_id = 2;
   495		func(b *buffer, m message) error { return decodeUint64(b, &m.(*Location).Address) },    // optional uint64 address = 3;
   496		func(b *buffer, m message) error { // repeated Line line = 4
   497			pp := m.(*Location)
   498			n := len(pp.Line)
   499			pp.Line = append(pp.Line, Line{})
   500			return decodeMessage(b, &pp.Line[n])
   501		},
   502		func(b *buffer, m message) error { return decodeBool(b, &m.(*Location).IsFolded) }, // optional bool is_folded = 5;
   503	}
   504	
   505	func (p *Line) decoder() []decoder {
   506		return lineDecoder
   507	}
   508	
   509	func (p *Line) encode(b *buffer) {
   510		encodeUint64Opt(b, 1, p.functionIDX)
   511		encodeInt64Opt(b, 2, p.Line)
   512	}
   513	
   514	var lineDecoder = []decoder{
   515		nil, // 0
   516		// optional uint64 function_id = 1
   517		func(b *buffer, m message) error { return decodeUint64(b, &m.(*Line).functionIDX) },
   518		// optional int64 line = 2
   519		func(b *buffer, m message) error { return decodeInt64(b, &m.(*Line).Line) },
   520	}
   521	
   522	func (p *Function) decoder() []decoder {
   523		return functionDecoder
   524	}
   525	
   526	func (p *Function) encode(b *buffer) {
   527		encodeUint64Opt(b, 1, p.ID)
   528		encodeInt64Opt(b, 2, p.nameX)
   529		encodeInt64Opt(b, 3, p.systemNameX)
   530		encodeInt64Opt(b, 4, p.filenameX)
   531		encodeInt64Opt(b, 5, p.StartLine)
   532	}
   533	
   534	var functionDecoder = []decoder{
   535		nil, // 0
   536		// optional uint64 id = 1
   537		func(b *buffer, m message) error { return decodeUint64(b, &m.(*Function).ID) },
   538		// optional int64 function_name = 2
   539		func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).nameX) },
   540		// optional int64 function_system_name = 3
   541		func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).systemNameX) },
   542		// repeated int64 filename = 4
   543		func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).filenameX) },
   544		// optional int64 start_line = 5
   545		func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).StartLine) },
   546	}
   547	
   548	func addString(strings map[string]int, s string) int64 {
   549		i, ok := strings[s]
   550		if !ok {
   551			i = len(strings)
   552			strings[s] = i
   553		}
   554		return int64(i)
   555	}
   556	
   557	func getString(strings []string, strng *int64, err error) (string, error) {
   558		if err != nil {
   559			return "", err
   560		}
   561		s := int(*strng)
   562		if s < 0 || s >= len(strings) {
   563			return "", errMalformed
   564		}
   565		*strng = 0
   566		return strings[s], nil
   567	}
   568	

View as plain text