@@ -5,15 +5,15 @@ import (
55 "encoding/json"
66 "errors"
77 "fmt"
8- profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1"
98 "path"
109 "reflect"
1110 "strconv"
1211 "strings"
13- "time"
1412 "unicode"
1513
16- "github.com/grafana/pyroscope/pkg/og/agent/spy"
14+ profilev1 "github.com/grafana/pyroscope/api/gen/proto/go/google/v1"
15+ typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1"
16+ "github.com/grafana/pyroscope/pkg/model"
1717 "github.com/grafana/pyroscope/pkg/og/convert/perf"
1818 "github.com/grafana/pyroscope/pkg/og/convert/pprof"
1919 "github.com/grafana/pyroscope/pkg/og/storage/metadata"
@@ -187,37 +187,96 @@ func JSONToProfile(b []byte, name string, maxNodes int) ([]*flamebearer.Flamebea
187187 return []* flamebearer.FlamebearerProfile {& p }, nil
188188}
189189
190+ func getProfileType (name string , sampleType int , p * profilev1.Profile ) (* typesv1.ProfileType , error ) {
191+ tp := & typesv1.ProfileType {
192+ Name : name ,
193+ }
194+
195+ // check if the sampleID is valid
196+ if sampleType < 0 || sampleType >= len (p .SampleType ) {
197+ return nil , fmt .Errorf ("invalid sampleID: %d" , sampleType )
198+ }
199+
200+ invalidStr := func (i int ) bool {
201+ return i < 0 || i > len (p .StringTable )
202+ }
203+ if v := int (p .PeriodType .Type ); invalidStr (v ) {
204+ return nil , fmt .Errorf ("invalid PeriodType: %d" , v )
205+ } else {
206+ tp .PeriodType = p .StringTable [v ]
207+ }
208+ if v := int (p .PeriodType .Unit ); invalidStr (v ) {
209+ return nil , fmt .Errorf ("invalid PeriodUnit: %d" , v )
210+ } else {
211+ tp .PeriodUnit = p .StringTable [v ]
212+ }
213+ if v := int (p .SampleType [sampleType ].Type ); invalidStr (v ) {
214+ return nil , fmt .Errorf ("invalid SampleType[%d]: %d" , sampleType , v )
215+ } else {
216+ tp .SampleType = p .StringTable [v ]
217+ }
218+ if v := int (p .SampleType [sampleType ].Unit ); invalidStr (v ) {
219+ return nil , fmt .Errorf ("invalid SampleUnit[%d]: %d" , sampleType , v )
220+ } else {
221+ tp .SampleUnit = p .StringTable [v ]
222+ }
223+
224+ tp .ID = fmt .Sprintf ("%s:%s:%s:%s:%s" , name , tp .SampleType , tp .SampleUnit , tp .PeriodType , tp .PeriodUnit )
225+ return tp , nil
226+ }
227+
190228func PprofToProfile (b []byte , name string , maxNodes int ) ([]* flamebearer.FlamebearerProfile , error ) {
191229 p := new (profilev1.Profile )
192230 if err := pprof .Decode (bytes .NewReader (b ), p ); err != nil {
193231 return nil , fmt .Errorf ("parsing pprof: %w" , err )
194232 }
233+
234+ t := model .NewStacktraceTree (int (maxNodes * 2 ))
235+ stack := make ([]int32 , 0 , 64 )
236+ m := make (map [uint64 ]int32 )
237+
195238 fbs := make ([]* flamebearer.FlamebearerProfile , 0 )
196- for _ , stype := range tree .SampleTypes (p ) {
197- sampleRate := uint32 (100 )
198- units := metadata .SamplesUnits
199- if c , ok := tree .DefaultSampleTypeMapping [stype ]; ok {
200- units = c .Units
201- if c .Sampled && p .Period > 0 {
202- sampleRate = uint32 (time .Second / time .Duration (p .Period ))
239+ for sampleType := range p .SampleType {
240+ t .Reset ()
241+
242+ for i := range p .Sample {
243+ stack = stack [:0 ]
244+ for j := range p .Sample [i ].LocationId {
245+ locIdx := int (p .Sample [i ].LocationId [j ]) - 1
246+ if locIdx < 0 || len (p .Location ) <= locIdx {
247+ return nil , fmt .Errorf ("invalid location ID %d in sample %d" , p .Sample [i ].LocationId [j ], i )
248+ }
249+
250+ loc := p .Location [locIdx ]
251+ if len (loc .Line ) > 0 {
252+ for l := range loc .Line {
253+ stack = append (stack , int32 (p .Function [loc .Line [l ].FunctionId - 1 ].Name ))
254+ }
255+ continue
256+ }
257+ addr , ok := m [loc .Address ]
258+ if ! ok {
259+ addr = int32 (len (p .StringTable ))
260+ p .StringTable = append (p .StringTable , strconv .FormatInt (int64 (loc .Address ), 16 ))
261+ m [loc .Address ] = addr
262+ }
263+ stack = append (stack , addr )
203264 }
265+
266+ if sampleType < 0 || sampleType >= len (p .Sample [i ].Value ) {
267+ return nil , fmt .Errorf ("invalid sampleType index %d for sample %d (len=%d)" , sampleType , i , len (p .Sample [i ].Value ))
268+ }
269+
270+ t .Insert (stack , p .Sample [i ].Value [sampleType ])
204271 }
205- t := tree .New ()
206- tree .Get (p , stype , func (_labels * spy.Labels , name []byte , val int ) error {
207- t .Insert (name , uint64 (val ))
208- return nil
209- })
210- fb := flamebearer .NewProfile (flamebearer.ProfileConfig {
211- Tree : t ,
212- Name : stype ,
213- MaxNodes : maxNodes ,
214- Metadata : metadata.Metadata {
215- SpyName : "unknown" ,
216- SampleRate : sampleRate ,
217- Units : units ,
218- },
219- })
220- fbs = append (fbs , & fb )
272+
273+ tp , err := getProfileType (name , sampleType , p )
274+ if err != nil {
275+ return nil , err
276+ }
277+
278+ fg := model .NewFlameGraph (t .Tree (int64 (maxNodes ), p .StringTable ), int64 (maxNodes ))
279+ fbs = append (fbs , model .ExportToFlamebearer (fg , tp ))
221280 }
222281 if len (fbs ) == 0 {
223282 return nil , errors .New ("no supported sample type found" )
0 commit comments