为什么 Haskell 配置文件中的成本中心堆栈会混乱?

huangapple go评论52阅读模式
英文:

Why does the cost centre stack gets jumbled up in the Haskell profile file?

问题

我正在尝试对我的Haskell项目进行性能分析,但在.profile文件中,函数调用栈的打印顺序似乎有点混乱。

例如,当检查.profile文件中的成本中心(https://hackage.haskell.org/package/ghc-prof-1.4.1.12/docs/src/GHC.Prof.Types.html#CostCentre)堆栈时,以下是我看到的成本中心堆栈。

logError
  log
   findCustomerFromDB
    getDBConfig
     rSet
      rSetB
       preInitEncryptedOrder
        decodeOrderDetails
         mkOptionKey
          encode
           fromEncoding
           genericToJSON
            unTagged
           value
            encodeToBuilder
             array
              unId
              emptyArray_

但是,我无法理解为什么在log函数内部,性能分析器将数据库调用打印为其子函数。
(附注:在代码中,我没有在log函数内部执行数据库调用。)

英文:

I am trying to profile my project in Haskell, but in the profile file (.prof) I am seeing the order in which the function stack is getting printed seems a little jumbled up.

For example, when checking the cost center (https://hackage.haskell.org/package/ghc-prof-1.4.1.12/docs/src/GHC.Prof.Types.html#CostCentre) stack in the .prof file, below is the cost center stack I see.

logError
  log
   findCustomerFromDB
    getDBConfig
     rSet
      rSetB
       preInitEncryptedOrder
        decodeOrderDetails
         mkOptionKey
          encode
           fromEncoding
           genericToJSON
            unTagged
           value
            encodeToBuilder
             array
              unId
              emptyArray_

But, I am not able to wrap my head around why inside the log function, profiler is printing database calls as its children.
(PS: In code, I’m not doing DB call inside log function)

答案1

得分: 1

以下是您要翻译的内容:

呼叫中心堆栈的构建完全按照成本中心的输入和退出进行构建,因此其构建不受抽样的影响。程序执行期间存在的并不是所有呼叫中心堆栈都会被抽样,但任何被抽样的呼叫中心堆栈都将是一个实际的呼叫堆栈,而不是抽样误差的某种产物。

此外,呼叫中心堆栈在创建时存储在thunk中,并在评估thunk时恢复,因此懒惰评估不会产生奇怪的混合堆栈,代表在某个不可预测的时间强制执行懒惰值时发生的函数调用。

因此,只要这些成本中心已经被正确命名(即,没有漂浮的SCC pragma带有错误的名称),并且只要您没有查看一个名为log的函数的代码并将其与完全不同的log函数的分析信息进行比较,您的呼叫堆栈除了明显的解释之外没有逻辑解释:findCustomerFromDB实际上是由log函数调用的,要么直接调用,要么通过一些其他内联函数间接调用。

我建议仔细检查您的log函数,并查看它是否调用一个添加一些调试信息到记录的字符串的辅助函数,比如启动了引发问题请求的客户的名称。

英文:

The call center stack is constructed exactly, as cost centers are entered and exited, so its construction is not affected by sampling. Not all call center stacks that exist during the execution of a program will be sampled, but any call center stack that is sampled will be an actual call stack, not some artifact of sampling error.

In addition, call center stacks are stored in thunks at the time of creation and restored when the thunk is evaluated, so lazy evaluation will not produce weird, hybrid stacks representing function calls that happened to be in effect when a lazy value was actually forced at some unpredictable time.

So, provided these cost centers have been correctly named (i.e., no stray SCC pragmas with the wrong name floating around) and provided you aren't looking at the code for one function named log and comparing it to the profiling information for a totally different log function, there is no logical explanation for your call stack other than the obvious one: findCustomerFromDB is, in fact, called by the log function, either directly, or through some other inlined function.

I'd suggest scrutinizing your log function and checking if it calls a helper function that adds some debugging information to logged strings, like the name of the customer that initiated the offending request.

huangapple
  • 本文由 发表于 2023年4月17日 04:42:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/76030238.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定