Tutfe是一个分析库,非常适合理解运行时的组合,尤其是在复杂的调用堆栈中。
当我在我的项目中运行它时,我期望性能昂贵的一段代码没有在结果中注册成为高犯罪者,这导致发现Tufte(合理地)只捕获了线程 - 本地结果。
文档表明它使用{:dynamic? true}
选项在其他线程上内置了对仪器累积时间的约束,但似乎需要更多来捕获在其他线程上累积的时间,例如那些由pmap
这是原始的Tufte演示,引入了一些多线程:
(require '[taoensso.tufte :as tufte :refer (defnp p profiled profile)])
;; We'll request to send `profile` stats to `println`:
(tufte/add-basic-println-handler! {})
;;; Let's define a couple dummy fns to simulate doing some expensive work
(defn get-x [] (Thread/sleep 500) "x val")
(defn get-y []
(pmap
#(do
(Thread/sleep 500)
(print %))
(range 10)))
;; How do these fns perform? Let's check:
(profile ; Profile any `p` forms called during body execution
{:dynamic? true} ; Profiling options; we'll use the defaults for now
(dotimes [_ 5]
(p :get-x (get-x))
(p :get-y (get-y))))
输出表明println语句强制线程进行评估。然而,结果中没有显示得到的累积时间:
2187306594=> nil
=> #{:basic-println}
=> #'user/get-x
=> #'user/get-y
8904365271703695842110783956243415760829=> nil
pId nCalls Min Max MAD Mean Time% Time
:get-x 5 500.52ms 504.84ms 1.44ms 502.44ms 100 2.51s
:get-y 5 90.67μs 581.91μs 162.2μs 269.29μs 0 1.35ms
Clock Time 100 2.51s
Accounted Time 100 2.51s
答案 0 :(得分:3)
答案:懒惰的初始化。虽然数据正在打印到屏幕上,但是(profile...)
形式的结尾是在get-y
之外的间谍形式之外。
这会产生同样的效果:
(profile ; Profile any `p` forms called during body execution
{:dynamic? true} ; Profiling options; we'll use the defaults for now
(dotimes [_ 5]
(p :get-x (get-x))
(doall (p :get-y (get-y)))))
30167894521045768392530798241651268940371023657894=> nil
pId nCalls Min Max MAD Mean Time% Time
:get-x 5 500.07ms 504.58ms 1.41ms 503.08ms 50 2.52s
:get-y 5 80.25μs 126.18μs 15.98μs 104.84μs 0 524.18μs
Clock Time 100 5.03s
Accounted Time 50 2.52s
然而,这个实现了get-y配置文件中的延迟序列:
(profile ; Profile any `p` forms called during body execution
{:dynamic? true} ; Profiling options; we'll use the defaults for now
(dotimes [_ 5]
(p :get-x (get-x))
(p :get-y (doall (get-y)))))
12037645987105892436354169872031089546721058729634=> nil
pId nCalls Min Max MAD Mean Time% Time
:get-x 5 502.54ms 504.71ms 705.6μs 503.5ms 50 2.52s
:get-y 5 501.69ms 505.68ms 1.05ms 503.06ms 50 2.52s
Clock Time 100 5.03s
Accounted Time 100 5.03s
了解剖析经验非常重要,因为在处理惰性序列时,您会意识到它们的使用方式,而不是序列本身:
(profile ; Profile any `p` forms called during body execution
{:dynamic? true} ; Profiling options; we'll use the defaults for now
(dotimes [_ 5]
(p :get-x (get-x))
(p ::realize-y
(doall (p :get-y (get-y))))))
06538947123410695278450678913223071958645126380479=> nil
pId nCalls Min Max MAD Mean Time% Time
:user/realize-y 5 503.29ms 504.86ms 458.12μs 504.37ms 50 2.52s
:get-x 5 500.13ms 505.06ms 1.4ms 503.64ms 50 2.52s
:get-y 5 86.0μs 1.15ms 331.81μs 322.94μs 0 1.61ms
Clock Time 100 5.04s
Accounted Time 100 5.04s