@@ -200,22 +200,31 @@ func TestMutex(t *testing.T) {
200
200
})
201
201
}
202
202
203
- func profileToString (p * profile.Profile ) []string {
203
+ func profileToStrings (p * profile.Profile ) []string {
204
204
var res []string
205
205
for _ , s := range p .Sample {
206
- var funcs []string
207
- for i := len (s .Location ) - 1 ; i >= 0 ; i -- {
208
- loc := s .Location [i ]
209
- for j := len (loc .Line ) - 1 ; j >= 0 ; j -- {
210
- line := loc .Line [j ]
211
- funcs = append (funcs , line .Function .Name )
212
- }
213
- }
214
- res = append (res , fmt .Sprintf ("%s %v" , strings .Join (funcs , ";" ), s .Value ))
206
+ res = append (res , sampleToString (s ))
215
207
}
216
208
return res
217
209
}
218
210
211
+ func sampleToString (s * profile.Sample ) string {
212
+ var funcs []string
213
+ for i := len (s .Location ) - 1 ; i >= 0 ; i -- {
214
+ loc := s .Location [i ]
215
+ funcs = locationToStrings (loc , funcs )
216
+ }
217
+ return fmt .Sprintf ("%s %v" , strings .Join (funcs , ";" ), s .Value )
218
+ }
219
+
220
+ func locationToStrings (loc * profile.Location , funcs []string ) []string {
221
+ for j := range loc .Line {
222
+ line := loc .Line [len (loc .Line )- 1 - j ]
223
+ funcs = append (funcs , line .Function .Name )
224
+ }
225
+ return funcs
226
+ }
227
+
219
228
// This is a regression test for https://go.dev/issue/64528 .
220
229
func TestGenericsHashKeyInPprofBuilder (t * testing.T ) {
221
230
previousRate := runtime .MemProfileRate
@@ -232,15 +241,15 @@ func TestGenericsHashKeyInPprofBuilder(t *testing.T) {
232
241
233
242
runtime .GC ()
234
243
buf := bytes .NewBuffer (nil )
235
- if err := writeHeapProfile (buf ); err != nil {
244
+ if err := WriteHeapProfile (buf ); err != nil {
236
245
t .Fatalf ("writing profile: %v" , err )
237
246
}
238
247
p , err := profile .Parse (buf )
239
248
if err != nil {
240
249
t .Fatalf ("profile.Parse: %v" , err )
241
250
}
242
251
243
- actual := profileToString (p )
252
+ actual := profileToStrings (p )
244
253
expected := []string {
245
254
"testing.tRunner;github.com/grafana/pyroscope-go/godeltaprof/compat.TestGenericsHashKeyInPprofBuilder;github.com/grafana/pyroscope-go/godeltaprof/compat.genericAllocFunc[go.shape.uint32] [1 128 0 0]" ,
246
255
"testing.tRunner;github.com/grafana/pyroscope-go/godeltaprof/compat.TestGenericsHashKeyInPprofBuilder;github.com/grafana/pyroscope-go/godeltaprof/compat.genericAllocFunc[go.shape.uint32] [1 256 0 0]" ,
@@ -255,7 +264,84 @@ func TestGenericsHashKeyInPprofBuilder(t *testing.T) {
255
264
}
256
265
}
257
266
258
- func writeHeapProfile (w io.Writer ) error {
267
+ type opAlloc struct {
268
+ buf [128 ]byte
269
+ }
270
+
271
+ type opCall struct {
272
+ }
273
+
274
+ var sink []byte
275
+
276
+ func storeAlloc () {
277
+ sink = make ([]byte , 16 )
278
+ }
279
+
280
+ func nonRecursiveGenericAllocFunction [CurrentOp any , OtherOp any ](alloc bool ) {
281
+ if alloc {
282
+ storeAlloc ()
283
+ } else {
284
+ nonRecursiveGenericAllocFunction [OtherOp , CurrentOp ](true )
285
+ }
286
+ }
287
+
288
+ func TestGenericsInlineLocations (t * testing.T ) {
289
+ if OptimizationOff () {
290
+ t .Skip ("skipping test with optimizations disabled" )
291
+ }
292
+
293
+ previousRate := runtime .MemProfileRate
294
+ runtime .MemProfileRate = 1
295
+ defer func () {
296
+ runtime .MemProfileRate = previousRate
297
+ sink = nil
298
+ }()
299
+
300
+ nonRecursiveGenericAllocFunction [opAlloc , opCall ](true )
301
+ nonRecursiveGenericAllocFunction [opCall , opAlloc ](false )
302
+
303
+ runtime .GC ()
304
+
305
+ buf := bytes .NewBuffer (nil )
306
+ if err := WriteHeapProfile (buf ); err != nil {
307
+ t .Fatalf ("writing profile: %v" , err )
308
+ }
309
+ p , err := profile .Parse (buf )
310
+ if err != nil {
311
+ t .Fatalf ("profile.Parse: %v" , err )
312
+ }
313
+
314
+ const expectedSample = "testing.tRunner;github.com/grafana/pyroscope-go/godeltaprof/compat.TestGenericsInlineLocations;github.com/grafana/pyroscope-go/godeltaprof/compat.nonRecursiveGenericAllocFunction[go.shape.struct {},go.shape.struct { github.com/grafana/pyroscope-go/godeltaprof/compat.buf [128]uint8 }];github.com/grafana/pyroscope-go/godeltaprof/compat.nonRecursiveGenericAllocFunction[go.shape.struct { github.com/grafana/pyroscope-go/godeltaprof/compat.buf [128]uint8 },go.shape.struct {}];github.com/grafana/pyroscope-go/godeltaprof/compat.storeAlloc [1 16 1 16]"
315
+ const expectedLocation = "github.com/grafana/pyroscope-go/godeltaprof/compat.nonRecursiveGenericAllocFunction[go.shape.struct {},go.shape.struct { github.com/grafana/pyroscope-go/godeltaprof/compat.buf [128]uint8 }];github.com/grafana/pyroscope-go/godeltaprof/compat.nonRecursiveGenericAllocFunction[go.shape.struct { github.com/grafana/pyroscope-go/godeltaprof/compat.buf [128]uint8 },go.shape.struct {}];github.com/grafana/pyroscope-go/godeltaprof/compat.storeAlloc"
316
+ const expectedLocationNewInliner = "github.com/grafana/pyroscope-go/godeltaprof/compat.TestGenericsInlineLocations;" + expectedLocation
317
+ var s * profile.Sample
318
+ for _ , sample := range p .Sample {
319
+ if sampleToString (sample ) == expectedSample {
320
+ s = sample
321
+ break
322
+ }
323
+ }
324
+ if s == nil {
325
+ t .Fatalf ("expected \n %s\n got\n %s" , expectedSample , strings .Join (profileToStrings (p ), "\n " ))
326
+ }
327
+ loc := s .Location [0 ]
328
+ actual := strings .Join (locationToStrings (loc , nil ), ";" )
329
+ if expectedLocation != actual && expectedLocationNewInliner != actual {
330
+ t .Errorf ("expected a location with at least 3 functions\n %s\n got\n %s\n " , expectedLocation , actual )
331
+ }
332
+ }
333
+
334
+ func OptimizationOff () bool {
335
+ optimizationMarker := func () uintptr {
336
+ pc , _ , _ , _ := runtime .Caller (0 )
337
+ return pc
338
+ }
339
+ pc := optimizationMarker ()
340
+ f := runtime .FuncForPC (runtime .FuncForPC (pc ).Entry ())
341
+ return f .Name () == "github.com/grafana/pyroscope-go/godeltaprof/compat.OptimizationOff.func1"
342
+ }
343
+
344
+ func WriteHeapProfile (w io.Writer ) error {
259
345
runtime .GC ()
260
346
dh := godeltaprof .NewHeapProfilerWithOptions (godeltaprof.ProfileOptions {
261
347
GenericsFrames : true ,
0 commit comments