Go 调用方根据其运行位置打印不同的程序计数器
我有下面的代码,它根据运行的位置打印不同的程序计数器值 代码:Go 调用方根据其运行位置打印不同的程序计数器,go,runtime,logrus,Go,Runtime,Logrus,我有下面的代码,它根据运行的位置打印不同的程序计数器值 代码: 当使用go run或编译的二进制文件运行时,它会打印(main.bar) 从Visual Studio代码运行代码时(仅在调试模式下工作正常) 运行时,(foo,bar,两者均缺失) 我正在使用一个框架(logrus),它依赖于PCs命令来执行一些操作(记录文件名)由于PC值根据其运行位置不断变化,因此它在调试模式下工作,但在使用go run或编译的二进制文件运行时失败 你知道是什么原因导致电脑加载方式不同吗?任何正在进行的配置或优
go run
或编译的二进制文件运行时,它会打印(main.bar
)foo
,bar
,两者均缺失)由于PC值根据其运行位置不断变化,因此它在调试模式下工作,但在使用
go run
或编译的二进制文件运行时失败
你知道是什么原因导致电脑加载方式不同吗?任何正在进行的配置或优化?状态文档:
要将这些PC转换为符号信息,如函数名和行号,请使用CallersFrames。CallersFrames解释内联函数,并将返回程序计数器调整为调用程序计数器。不鼓励直接迭代返回的PC片,因为在任何返回的PC上使用FuncForPC都不能解释内联或返回程序计数器调整
Doc建议使用从原始计数器获取函数信息,这些计数器了解并说明函数内联,例如:
pcs := make([]uintptr, 10)
n := runtime.Callers(0, pcs)
pcs = pcs[:n]
frames := runtime.CallersFrames(pcs)
for {
frame, more := frames.Next()
if !more {
break
}
fmt.Println("Function:", frame.Function)
}
无论您如何调用/运行它,都应该输出该命令(请在上尝试):
各国的文件:
要将这些PC转换为符号信息,如函数名和行号,请使用CallersFrames。CallersFrames解释内联函数,并将返回程序计数器调整为调用程序计数器。不鼓励直接迭代返回的PC片,因为在任何返回的PC上使用FuncForPC都不能解释内联或返回程序计数器调整
Doc建议使用从原始计数器获取函数信息,这些计数器了解并说明函数内联,例如:
pcs := make([]uintptr, 10)
n := runtime.Callers(0, pcs)
pcs = pcs[:n]
frames := runtime.CallersFrames(pcs)
for {
frame, more := frames.Next()
if !more {
break
}
fmt.Println("Function:", frame.Function)
}
无论您如何调用/运行它,都应该输出该命令(请在上尝试):
这可能是由于函数内联造成的,请参阅以了解其如何影响堆栈跟踪以及如何确认。这是否回答了您的问题@Marc I添加了
go:noinline
,但它仍然没有显示bar
方法。有没有其他配置在这里可能会有所帮助?无意冒犯,但您可能添加了错误的配置,或者没有重新编译二进制文件。你真的不应该这样做只是为了避开日志库中的一个bug。@Marc没有问题,我也怀疑我的实现:)有和没有go:noinline
有区别。唯一的区别是,现在goplayer
和使用go run
中的输出是相同的。但是,bar
不显示的问题仍然存在。奇怪的是,这在几周前就开始起作用了,我们刚刚开始注意到文件名
没有被logrus
记录下来,并深入研究了这个问题,这可能是由于函数内联造成的,请看它如何影响堆栈跟踪以及如何确认。这是否回答了您的问题@Marc I添加了go:noinline
,但它仍然没有显示bar
方法。有没有其他配置在这里可能会有所帮助?无意冒犯,但您可能添加了错误的配置,或者没有重新编译二进制文件。你真的不应该这样做只是为了避开日志库中的一个bug。@Marc没有问题,我也怀疑我的实现:)有和没有go:noinline
有区别。唯一的区别是,现在goplayer
和使用go run
中的输出是相同的。但是,bar
不显示的问题仍然存在。奇怪的是,这在几周前就起作用了,我们刚刚开始注意到logrus
没有记录filename
并深入研究了这个问题,不幸的是,logrus
框架内部使用运行时。调用方API来解决这个问题。那么,使用这个API调用有什么解决方法可以让它工作吗?调试模式是如何实现这一点的,可能会跳过一些优化步骤?@Bandikish更有可能在调试模式下运行时,禁用函数内联,以便您可以检查/跟踪每个函数调用。调试模式与性能无关,而是与可跟踪性有关。如果logrus
使用runtime.Callers()
而不使用runtime.CallersFrames()
,则它严重需要更新。对于常规调用堆栈,它使用runtime.CallersFrames()
,但在单例初始化期间,它使用此API来计算logrus包@BandiKishore是的,您应该在那里创建一个问题。不幸的是,logrus
框架内部使用runtime.Callers
API来解决这个问题。那么,使用这个API调用有什么解决方法可以让它工作吗?调试模式是如何实现这一点的,可能会跳过一些优化步骤?@Bandikish更有可能在调试模式下运行时,禁用函数内联,以便您可以检查/跟踪每个函数调用。调试模式与性能无关,而是与可跟踪性有关。如果logrus
使用runtime.Callers()
而不使用runtime.CallersFrames()
,则它严重需要更新。对于常规调用堆栈,它使用runtime.CallersFrames()
,但在单例初始化期间,它使用此API来计算logrus包@是的,你应该在那里制造一个问题。
Value of pc runtime.Callers
Value of pc main.bar
Value of pc main.foo
Value of pc main.main
Value of pc runtime.main
Value of pc runtime.goexit
Value of pc runtime.Callers
Value of pc runtime.Callers
Value of pc main.main
Value of pc main.main
Value of pc runtime.main
Value of pc runtime.goexit
pcs := make([]uintptr, 10)
n := runtime.Callers(0, pcs)
pcs = pcs[:n]
frames := runtime.CallersFrames(pcs)
for {
frame, more := frames.Next()
if !more {
break
}
fmt.Println("Function:", frame.Function)
}
Function: runtime.Callers
Function: main.bar
Function: main.foo
Function: main.main
Function: runtime.main