Source file src/internal/profile/encode.go

     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  
     5  package profile
     6  
     7  import (
     8  	"errors"
     9  	"fmt"
    10  	"sort"
    11  )
    12  
    13  func (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.
    20  func (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  
   108  func (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  
   135  var 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  	// repeated int64 comment = 13
   201  	func(b *buffer, m message) error { return decodeInt64s(b, &m.(*Profile).commentX) },
   202  	// int64 defaultSampleType = 14
   203  	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Profile).defaultSampleTypeX) },
   204  }
   205  
   206  // postDecode takes the unexported fields populated by decode (with
   207  // suffix X) and populates the corresponding exported fields.
   208  // The unexported fields are cleared up to facilitate testing.
   209  func (p *Profile) postDecode() error {
   210  	var err error
   211  
   212  	mappings := make(map[uint64]*Mapping)
   213  	for _, m := range p.Mapping {
   214  		m.File, err = getString(p.stringTable, &m.fileX, err)
   215  		m.BuildID, err = getString(p.stringTable, &m.buildIDX, err)
   216  		mappings[m.ID] = m
   217  	}
   218  
   219  	functions := make(map[uint64]*Function)
   220  	for _, f := range p.Function {
   221  		f.Name, err = getString(p.stringTable, &f.nameX, err)
   222  		f.SystemName, err = getString(p.stringTable, &f.systemNameX, err)
   223  		f.Filename, err = getString(p.stringTable, &f.filenameX, err)
   224  		functions[f.ID] = f
   225  	}
   226  
   227  	locations := make(map[uint64]*Location)
   228  	for _, l := range p.Location {
   229  		l.Mapping = mappings[l.mappingIDX]
   230  		l.mappingIDX = 0
   231  		for i, ln := range l.Line {
   232  			if id := ln.functionIDX; id != 0 {
   233  				l.Line[i].Function = functions[id]
   234  				if l.Line[i].Function == nil {
   235  					return fmt.Errorf("Function ID %d not found", id)
   236  				}
   237  				l.Line[i].functionIDX = 0
   238  			}
   239  		}
   240  		locations[l.ID] = l
   241  	}
   242  
   243  	for _, st := range p.SampleType {
   244  		st.Type, err = getString(p.stringTable, &st.typeX, err)
   245  		st.Unit, err = getString(p.stringTable, &st.unitX, err)
   246  	}
   247  
   248  	for _, s := range p.Sample {
   249  		labels := make(map[string][]string)
   250  		numLabels := make(map[string][]int64)
   251  		for _, l := range s.labelX {
   252  			var key, value string
   253  			key, err = getString(p.stringTable, &l.keyX, err)
   254  			if l.strX != 0 {
   255  				value, err = getString(p.stringTable, &l.strX, err)
   256  				labels[key] = append(labels[key], value)
   257  			} else {
   258  				numLabels[key] = append(numLabels[key], l.numX)
   259  			}
   260  		}
   261  		if len(labels) > 0 {
   262  			s.Label = labels
   263  		}
   264  		if len(numLabels) > 0 {
   265  			s.NumLabel = numLabels
   266  		}
   267  		s.Location = nil
   268  		for _, lid := range s.locationIDX {
   269  			s.Location = append(s.Location, locations[lid])
   270  		}
   271  		s.locationIDX = nil
   272  	}
   273  
   274  	p.DropFrames, err = getString(p.stringTable, &p.dropFramesX, err)
   275  	p.KeepFrames, err = getString(p.stringTable, &p.keepFramesX, err)
   276  
   277  	if pt := p.PeriodType; pt == nil {
   278  		p.PeriodType = &ValueType{}
   279  	}
   280  
   281  	if pt := p.PeriodType; pt != nil {
   282  		pt.Type, err = getString(p.stringTable, &pt.typeX, err)
   283  		pt.Unit, err = getString(p.stringTable, &pt.unitX, err)
   284  	}
   285  	for _, i := range p.commentX {
   286  		var c string
   287  		c, err = getString(p.stringTable, &i, err)
   288  		p.Comments = append(p.Comments, c)
   289  	}
   290  
   291  	p.commentX = nil
   292  	p.DefaultSampleType, err = getString(p.stringTable, &p.defaultSampleTypeX, err)
   293  	p.stringTable = nil
   294  	return err
   295  }
   296  
   297  func (p *ValueType) decoder() []decoder {
   298  	return valueTypeDecoder
   299  }
   300  
   301  func (p *ValueType) encode(b *buffer) {
   302  	encodeInt64Opt(b, 1, p.typeX)
   303  	encodeInt64Opt(b, 2, p.unitX)
   304  }
   305  
   306  var valueTypeDecoder = []decoder{
   307  	nil, // 0
   308  	// optional int64 type = 1
   309  	func(b *buffer, m message) error { return decodeInt64(b, &m.(*ValueType).typeX) },
   310  	// optional int64 unit = 2
   311  	func(b *buffer, m message) error { return decodeInt64(b, &m.(*ValueType).unitX) },
   312  }
   313  
   314  func (p *Sample) decoder() []decoder {
   315  	return sampleDecoder
   316  }
   317  
   318  func (p *Sample) encode(b *buffer) {
   319  	encodeUint64s(b, 1, p.locationIDX)
   320  	for _, x := range p.Value {
   321  		encodeInt64(b, 2, x)
   322  	}
   323  	for _, x := range p.labelX {
   324  		encodeMessage(b, 3, x)
   325  	}
   326  }
   327  
   328  var sampleDecoder = []decoder{
   329  	nil, // 0
   330  	// repeated uint64 location = 1
   331  	func(b *buffer, m message) error { return decodeUint64s(b, &m.(*Sample).locationIDX) },
   332  	// repeated int64 value = 2
   333  	func(b *buffer, m message) error { return decodeInt64s(b, &m.(*Sample).Value) },
   334  	// repeated Label label = 3
   335  	func(b *buffer, m message) error {
   336  		s := m.(*Sample)
   337  		n := len(s.labelX)
   338  		s.labelX = append(s.labelX, Label{})
   339  		return decodeMessage(b, &s.labelX[n])
   340  	},
   341  }
   342  
   343  func (p Label) decoder() []decoder {
   344  	return labelDecoder
   345  }
   346  
   347  func (p Label) encode(b *buffer) {
   348  	encodeInt64Opt(b, 1, p.keyX)
   349  	encodeInt64Opt(b, 2, p.strX)
   350  	encodeInt64Opt(b, 3, p.numX)
   351  }
   352  
   353  var labelDecoder = []decoder{
   354  	nil, // 0
   355  	// optional int64 key = 1
   356  	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Label).keyX) },
   357  	// optional int64 str = 2
   358  	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Label).strX) },
   359  	// optional int64 num = 3
   360  	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Label).numX) },
   361  }
   362  
   363  func (p *Mapping) decoder() []decoder {
   364  	return mappingDecoder
   365  }
   366  
   367  func (p *Mapping) encode(b *buffer) {
   368  	encodeUint64Opt(b, 1, p.ID)
   369  	encodeUint64Opt(b, 2, p.Start)
   370  	encodeUint64Opt(b, 3, p.Limit)
   371  	encodeUint64Opt(b, 4, p.Offset)
   372  	encodeInt64Opt(b, 5, p.fileX)
   373  	encodeInt64Opt(b, 6, p.buildIDX)
   374  	encodeBoolOpt(b, 7, p.HasFunctions)
   375  	encodeBoolOpt(b, 8, p.HasFilenames)
   376  	encodeBoolOpt(b, 9, p.HasLineNumbers)
   377  	encodeBoolOpt(b, 10, p.HasInlineFrames)
   378  }
   379  
   380  var mappingDecoder = []decoder{
   381  	nil, // 0
   382  	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).ID) },            // optional uint64 id = 1
   383  	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).Start) },         // optional uint64 memory_offset = 2
   384  	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).Limit) },         // optional uint64 memory_limit = 3
   385  	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Mapping).Offset) },        // optional uint64 file_offset = 4
   386  	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Mapping).fileX) },          // optional int64 filename = 5
   387  	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Mapping).buildIDX) },       // optional int64 build_id = 6
   388  	func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasFunctions) },    // optional bool has_functions = 7
   389  	func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasFilenames) },    // optional bool has_filenames = 8
   390  	func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasLineNumbers) },  // optional bool has_line_numbers = 9
   391  	func(b *buffer, m message) error { return decodeBool(b, &m.(*Mapping).HasInlineFrames) }, // optional bool has_inline_frames = 10
   392  }
   393  
   394  func (p *Location) decoder() []decoder {
   395  	return locationDecoder
   396  }
   397  
   398  func (p *Location) encode(b *buffer) {
   399  	encodeUint64Opt(b, 1, p.ID)
   400  	encodeUint64Opt(b, 2, p.mappingIDX)
   401  	encodeUint64Opt(b, 3, p.Address)
   402  	for i := range p.Line {
   403  		encodeMessage(b, 4, &p.Line[i])
   404  	}
   405  }
   406  
   407  var locationDecoder = []decoder{
   408  	nil, // 0
   409  	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Location).ID) },         // optional uint64 id = 1;
   410  	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Location).mappingIDX) }, // optional uint64 mapping_id = 2;
   411  	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Location).Address) },    // optional uint64 address = 3;
   412  	func(b *buffer, m message) error { // repeated Line line = 4
   413  		pp := m.(*Location)
   414  		n := len(pp.Line)
   415  		pp.Line = append(pp.Line, Line{})
   416  		return decodeMessage(b, &pp.Line[n])
   417  	},
   418  }
   419  
   420  func (p *Line) decoder() []decoder {
   421  	return lineDecoder
   422  }
   423  
   424  func (p *Line) encode(b *buffer) {
   425  	encodeUint64Opt(b, 1, p.functionIDX)
   426  	encodeInt64Opt(b, 2, p.Line)
   427  }
   428  
   429  var lineDecoder = []decoder{
   430  	nil, // 0
   431  	// optional uint64 function_id = 1
   432  	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Line).functionIDX) },
   433  	// optional int64 line = 2
   434  	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Line).Line) },
   435  }
   436  
   437  func (p *Function) decoder() []decoder {
   438  	return functionDecoder
   439  }
   440  
   441  func (p *Function) encode(b *buffer) {
   442  	encodeUint64Opt(b, 1, p.ID)
   443  	encodeInt64Opt(b, 2, p.nameX)
   444  	encodeInt64Opt(b, 3, p.systemNameX)
   445  	encodeInt64Opt(b, 4, p.filenameX)
   446  	encodeInt64Opt(b, 5, p.StartLine)
   447  }
   448  
   449  var functionDecoder = []decoder{
   450  	nil, // 0
   451  	// optional uint64 id = 1
   452  	func(b *buffer, m message) error { return decodeUint64(b, &m.(*Function).ID) },
   453  	// optional int64 function_name = 2
   454  	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).nameX) },
   455  	// optional int64 function_system_name = 3
   456  	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).systemNameX) },
   457  	// repeated int64 filename = 4
   458  	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).filenameX) },
   459  	// optional int64 start_line = 5
   460  	func(b *buffer, m message) error { return decodeInt64(b, &m.(*Function).StartLine) },
   461  }
   462  
   463  func addString(strings map[string]int, s string) int64 {
   464  	i, ok := strings[s]
   465  	if !ok {
   466  		i = len(strings)
   467  		strings[s] = i
   468  	}
   469  	return int64(i)
   470  }
   471  
   472  func getString(strings []string, strng *int64, err error) (string, error) {
   473  	if err != nil {
   474  		return "", err
   475  	}
   476  	s := int(*strng)
   477  	if s < 0 || s >= len(strings) {
   478  		return "", errMalformed
   479  	}
   480  	*strng = 0
   481  	return strings[s], nil
   482  }
   483  

View as plain text