11package profiler
22
33import (
4+ "fmt"
45 "strconv"
56
67 "github.com/yandex/perforator/perforator/agent/collector/pkg/profile"
7- lua_models "github.com/yandex/perforator/perforator/internal/linguist/lua/models"
88 "github.com/yandex/perforator/perforator/internal/linguist/models"
99 python_models "github.com/yandex/perforator/perforator/internal/linguist/python/models"
1010 "github.com/yandex/perforator/perforator/internal/linguist/symbolizer"
@@ -45,6 +45,7 @@ func newLuaSampleStackProcessor(symbolizer *symbolizer.Symbolizer) *sampleStackP
4545}
4646
4747func (s * sampleStackProcessor ) Process (builder * profile.SampleBuilder , stack * unwinder.InterpreterStack ) interpreterStackMetrics {
48+ println ("SPAR: stack_processor::Process" )
4849 processFrame := s .getFrameProcessor ()
4950 mtr := interpreterStackMetrics {}
5051
@@ -64,9 +65,11 @@ func (s *sampleStackProcessor) Process(builder *profile.SampleBuilder, stack *un
6465}
6566
6667func processFrameCommon (s * sampleStackProcessor , mtr * interpreterStackMetrics , loc * profile.LocationBuilder , frame * unwinder.InterpreterFrame ) {
68+ println ("SPAR: stack_processor::processFrameCommon" )
6769 symbol , exists := s .interpreterSymbolizer .Symbolize (& frame .SymbolKey )
6870 if ! exists {
6971 mtr .unsymbolizedFramesCount ++
72+
7073 loc .AddFrame ().
7174 SetName (models .UnsymbolizedInterpreterLocation ).
7275 SetStartLine (int64 (frame .SymbolKey .Linestart )).
@@ -83,6 +86,7 @@ func processFrameCommon(s *sampleStackProcessor, mtr *interpreterStackMetrics, l
8386
8487func processPythonFrame (s * sampleStackProcessor , mtr * interpreterStackMetrics , loc * profile.LocationBuilder , frame * unwinder.InterpreterFrame ) {
8588 loc .SetMapping ().SetPath (string (s .langMapping )).Finish ()
89+
8690 if frame .SymbolKey .Linestart == - 1 {
8791 loc .AddFrame ().SetName (python_models .PythonTrampolineFrame ).Finish ()
8892 return
@@ -320,21 +324,8 @@ var ffnames = []string{
320324 "buffer.decode" ,
321325}
322326
323- // see lj_frame.h
324- var ftsz = []string {
325- "LUA" ,
326- "C" ,
327- "CONT" ,
328- "VARG" ,
329- "LUAP" ,
330- "CP" ,
331- "PCALL" ,
332- "PCALLH" ,
333- }
334-
335327// internal frame decoding errors, see LuaUnwindError at perforator/agent/collector/progs/unwinder/lua/types.h
336328var frame_decoding_errors = []string {
337- "" ,
338329 "frame is null" ,
339330 "gc func is null" ,
340331 "bad frame function" ,
@@ -369,62 +360,131 @@ var entities = []string{
369360 "upvalue" ,
370361}
371362
363+ type LuaData struct {
364+ frame * unwinder.InterpreterFrame
365+ }
366+
367+ const (
368+ LuaPointerMask = 0xFFFFFFFFFFFF
369+ LuaPointerBitSize = 48
370+
371+ LuaContextTypeMask = 0x7
372+
373+ LuaFfidMask = 0xFF
374+ LuaFfidLua = 0
375+ LuaFfidC = 1
376+ LuaFfidInvalid = - 1
377+
378+ LuaUnwindErrorMask = 0x3
379+ LuaUnwindErrorBitSize = 2
380+
381+ LuaFrameGctMask = 0xF
382+
383+ LuaLineStartNotUsed = - 1
384+ )
385+
386+ func (ld * LuaData ) getObjectAddress () uint64 {
387+ return ld .frame .SymbolKey .ObjectAddr
388+ }
389+
390+ func (ld * LuaData ) GetLineStart () int32 {
391+ return ld .frame .SymbolKey .Linestart
392+ }
393+
394+ func (ld * LuaData ) GetFrameType () int {
395+ if ld .GetLineStart () != LuaLineStartNotUsed {
396+ return LuaFfidLua
397+ } else if ld .getObjectAddress () == 0 {
398+ return LuaFfidInvalid
399+ }
400+
401+ return int (ld .GetFfid ())
402+ }
403+
404+ func (ld * LuaData ) GetPtr () uint64 {
405+ return ld .getObjectAddress () & LuaPointerMask
406+ }
407+
408+ func (ld * LuaData ) GetContextType () unwinder.LuaContextType {
409+ return unwinder .LuaContextType ((ld .getObjectAddress () >> LuaPointerBitSize ) & LuaContextTypeMask )
410+ }
411+
412+ func (ld * LuaData ) GetFfid () uint8 {
413+ return uint8 ((ld .getObjectAddress () >> LuaPointerBitSize ) & LuaFfidMask )
414+ }
415+
416+ func (ld * LuaData ) GetErrorKind () unwinder.LuaUnwindError {
417+ return unwinder .LuaUnwindError ((ld .getObjectAddress () >> LuaPointerBitSize ) & LuaContextTypeMask )
418+ }
419+
420+ func (ld * LuaData ) GetFrameGct () uint8 {
421+ return uint8 ((ld .getObjectAddress () >> (LuaPointerBitSize + LuaUnwindErrorBitSize )) & LuaFrameGctMask )
422+ }
423+
372424func processLuaFrame (s * sampleStackProcessor , mtr * interpreterStackMetrics , loc * profile.LocationBuilder , frame * unwinder.InterpreterFrame ) {
425+ println ("SPAR: stack_processor::processLuaFrame" )
373426
374427 loc .SetMapping ().SetPath (string (s .langMapping )).Finish ()
428+
375429 symbol , exists := s .interpreterSymbolizer .Symbolize (& frame .SymbolKey )
430+
376431 if ! exists {
377432 mtr .unsymbolizedFramesCount ++
433+
378434 loc .AddFrame ().
379435 SetName (models .UnsymbolizedInterpreterLocation ).
380436 SetStartLine (int64 (frame .SymbolKey .Linestart )).
381437 Finish ()
382438 return
383439 }
440+
441+ luaData := LuaData {frame }
384442 name := symbol .Name
385443 filename := symbol .FileName
386444
387- if frame .SymbolKey .LuaInvalidFrame != 0 {
388- // Invalid frame, wasn't decoded as Lua function
445+ switch luaData .GetFrameType () {
446+ case LuaFfidInvalid :
447+ // Invalid frame
389448 name = "<Invalid Lua Frame>"
390- if int (frame .SymbolKey .LuaGct ) < len (gct ) {
391- name += "#" + gct [frame .SymbolKey .LuaGct ]
449+
450+ if int (luaData .GetFrameGct ()) < len (gct ) {
451+ name += "#" + gct [luaData .GetFrameGct ()]
392452 }
393- if int (frame .SymbolKey .LuaInvalidFrame ) < len (frame_decoding_errors ) {
394- name += ": " + frame_decoding_errors [frame .SymbolKey .LuaInvalidFrame ]
453+
454+ if int (luaData .GetErrorKind ()) < len (frame_decoding_errors ) {
455+ name += ": " + frame_decoding_errors [luaData .GetErrorKind ()]
395456 }
396- } else if frame .SymbolKey .LuaFfid == 0 {
397- // Lua function
398- if frame .SymbolKey .LuaEntity != 0 {
399- name = entities [frame .SymbolKey .LuaEntity ] + " " + name
457+ case LuaFfidLua :
458+ if luaData .GetContextType () != 0 {
459+ name = entities [luaData .GetContextType ()] + " " + name
400460 }
401- name = "[" + ftsz [frame .SymbolKey .LuaFtsz ] + "] " + name
402461
403462 // Usually scripts has @ appended at the beginning.
404463 // Perforator has same symbol, removing here.
405464 if filename [0 ] == '@' {
406465 filename = symbol .FileName [1 :]
407466 }
408- filename += ":" + strconv .Itoa (int (frame .SymbolKey .LuaLine ))
409- } else if frame .SymbolKey .LuaFfid == 1 {
410467
411- // this C function will be automatically symbolized by the native unwinder, no need to emit duplicated frame
412- // nevertheless, adding a native frame into interpreter stack confused merge algorithm (see postprocess.go)
413- name = lua_models .LuaTrampolineFrame
414-
415- } else {
416- // interpreter builtin aka fast function (ff)
417- name = "[builtin] " + ffnames [frame .SymbolKey .LuaFfid ] + "#" + strconv .Itoa (int (frame .SymbolKey .LuaFfid ))
468+ filename += ":" + strconv .Itoa (int (frame .SymbolKey .Linestart ))
469+ case LuaFfidC :
470+ // The frame will be symbolized by postprocess
471+ name = fmt .Sprintf ("function: 0x%x" , luaData .GetPtr ())
472+ default :
473+ // The frame will be symbolized by postprocess
474+ // If postprocess will fail, at least print its builtin number to find the name manually
475+ name = "[builtin] " + ffnames [luaData .GetFfid ()] + "#" + strconv .Itoa (int (luaData .GetFfid ()))
418476 }
477+
419478 loc .AddFrame ().
420- SetName (name ).
479+ SetName ("[lua] " + name ).
421480 SetFilename (filename ).
422481 SetStartLine (int64 (frame .SymbolKey .Linestart )).
423482 Finish ()
424-
425483}
426484
427485func (s * sampleStackProcessor ) getFrameProcessor () func (s * sampleStackProcessor , mtr * interpreterStackMetrics , loc * profile.LocationBuilder , frame * unwinder.InterpreterFrame ) {
486+ println ("SPAR: stack_processor::getFrameProcessor" )
487+
428488 switch s .langMapping {
429489 case profile .PythonSpecialMapping :
430490 return processPythonFrame
0 commit comments