|
517 | 517 |
|
518 | 518 | (deftype StatsAccumulator [acc]
|
519 | 519 | ;; `acc` - (latom {<profiling-id> <pstats>})
|
520 |
| - #?(:clj clojure.lang.IDeref :cljs IDeref) (#?(:clj deref :cljs -deref) [_] (enc/reset-in! acc {})) ; Drain |
521 |
| - #?(:clj clojure.lang.IFn :cljs IFn) (#?(:clj invoke :cljs -invoke) [_] (enc/reset-in! acc {})) ; Drain |
522 |
| - ( #?(:clj invoke :cljs -invoke) [_ profiling-id ps] |
523 |
| - (when (and profiling-id ps) |
524 |
| - ;; Contention would be expensive so consumer should serialize calls |
525 |
| - (acc profiling-id #(impl/merge-pstats % ps)) |
526 |
| - true))) |
| 520 | + |
| 521 | + #?(:cljs IDeref :clj clojure.lang.IDeref) |
| 522 | + #?(:clj (deref [this] @acc) |
| 523 | + :cljs (-deref [this] @acc)) |
| 524 | + |
| 525 | + #?(:cljs IFn :clj clojure.lang.IFn) |
| 526 | + #?(:clj (invoke [this] (enc/reset-in! acc {})) |
| 527 | + :cljs (-invoke [this] (enc/reset-in! acc {}))) |
| 528 | + |
| 529 | + ;; Contention would be expensive here so consumer may want to serialize calls |
| 530 | + #?(:clj (invoke [this id pstats] (when (and id pstats) (locking acc (acc id #(impl/merge-pstats % pstats))) true)) |
| 531 | + :cljs (-invoke [this id pstats] (when (and id pstats) (acc id #(impl/merge-pstats % pstats)) true)))) |
| 532 | + |
| 533 | +(comment |
| 534 | + (let [sacc (stats-accumulator) |
| 535 | + [_ ps1] (profiled {} (p :foo (Thread/sleep 10)))] |
| 536 | + (enc/qb 1e5 (sacc :id1 ps1)))) ; 45.01 |
527 | 537 |
|
528 | 538 | (defn stats-accumulator
|
529 | 539 | "Experimental, subject to change. Feedback welcome!
|
530 | 540 | Small util to help merge `pstats` from multiple runs and/or threads.
|
531 | 541 |
|
532 | 542 | Returns a stateful `StatsAccumulator` (`sacc`) with:
|
533 |
| - - (sacc <profiling-id> <pstats>) ; Merges given pstats under given profile id |
534 |
| - - @sacc ; Drains accumulator and returns drained |
535 |
| - ; {<profiling-id> <merged-pstats>} |
| 543 | + - (sacc <id> <pstats>) - Merges given pstats under given profiling id |
| 544 | + - (sacc) --------------- Returns current {<profiling-id> <merged-pstats>} and drains accumulator |
| 545 | + - @sacc ---------------- Returns current {<profiling-id> <merged-pstats>} WITHOUT draining |
536 | 546 |
|
537 |
| - Note that for performance reasons, you'll likely want some kind of |
538 |
| - async/buffer/serialization mechanism in front of merge calls. |
| 547 | + For performance you may want to use some sort of serialization |
| 548 | + mechanism (e.g. agent) to avoid high contention when merging. |
539 | 549 |
|
540 | 550 | One common pattern using `handler:accumulating` is to create a
|
541 |
| - system-wide accumulator that you deref every n minutes/etc. to get |
| 551 | + system-wide accumulator that you invoke every n minutes/etc. to get |
542 | 552 | a view of system-wide performance over the period, e.g.:
|
543 | 553 |
|
544 | 554 | (defonce my-sacc (stats-accumulator) ; Create an accumulator
|
|
548 | 558 | ;; Drain and print formatted stats every minute
|
549 | 559 | (future
|
550 | 560 | (while true
|
551 |
| - (when-let [m (not-empty @my-sacc)] |
| 561 | + (when-let [m (not-empty (my-sacc))] |
552 | 562 | (println (format-grouped-pstats m)))
|
553 | 563 | (Thread/sleep 60000))))
|
554 | 564 |
|
|
562 | 572 | (enc/qb 1e6 (stats-accumulator)) ; 45.37
|
563 | 573 | (let [sacc (stats-accumulator)]
|
564 | 574 | (sacc :profiled1 (second (profiled {} (p :p1 nil))))
|
565 |
| - (Thread/sleep 100) |
566 | 575 | (sacc :profiled2 (second (profiled {} (p :p2 nil))))
|
567 |
| - [@sacc @sacc])) |
| 576 | + [(sacc) (sacc)])) |
568 | 577 |
|
569 | 578 | (comment
|
570 | 579 | (def my-sacc (add-accumulating-handler! {:ns-pattern "*"}))
|
|
0 commit comments