Source file src/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 || l.unitX != 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