Skip to content

Commit 5a685b5

Browse files
committed
[new] Refactor, modernize formatting code
Motivation: cleaner codebase, improved performance. Not intended to include any breaking changes.
1 parent f54ab18 commit 5a685b5

File tree

3 files changed

+102
-140
lines changed

3 files changed

+102
-140
lines changed

src/taoensso/tufte.cljc

Lines changed: 25 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -625,7 +625,24 @@
625625

626626
(enc/defaliases
627627
enc/chance
628-
impl/merge-pstats)
628+
impl/merge-pstats
629+
impl/format-pstats
630+
impl/format-grouped-pstats)
631+
632+
(comment
633+
(let [[_ ps1] (profiled {} (p :p1))
634+
[_ ps2] (profiled {} (p :p1))]
635+
(enc/qb 1e5 (merge-pstats ps1 ps2))) ; 74.38
636+
637+
(println
638+
(str "\n"
639+
(format-pstats
640+
(second
641+
(profiled {}
642+
(p :foo (Thread/sleep 200))
643+
(p :bar (Thread/sleep 500))
644+
(do (Thread/sleep 800))))
645+
{:columns [:clock :p50 :p95]}))))
629646

630647
(defn format-id-abbr-fn
631648
"Returns a cached (fn [id]) => abbreviated id with at most `n-full`
@@ -649,28 +666,6 @@
649666

650667
(comment (refer-tufte))
651668

652-
(defn format-pstats
653-
"Formats given pstats to a string table.
654-
Accounted < Clock => Some work was done that wasn't tracked by any p forms.
655-
Accounted > Clock => Nested p forms, and/or parallel threads."
656-
([ps ] (format-pstats ps nil))
657-
([ps opts]
658-
(when ps
659-
(let [{:keys [clock stats]} (if (instance? PStats ps) @ps ps)]
660-
(impl/format-pstats (get clock :total) stats opts)))))
661-
662-
(comment
663-
;; [:n :min :p25 :p50 :p75 :p90 :p95 :p99 :max :mean :mad :clock :sum]
664-
(println
665-
(str "\n"
666-
(format-pstats
667-
(second
668-
(profiled {}
669-
(p :foo (Thread/sleep 200))
670-
(p :bar (Thread/sleep 500))
671-
(do (Thread/sleep 800))))
672-
{:columns [:clock :p50 :p95]}))))
673-
674669
;;;; fnp stuff
675670

676671
(defn- fn-sigs [def? ?meta-id ?fn-sym sigs loc]
@@ -864,53 +859,15 @@
864859

865860
(comment
866861
(def my-sacc (add-accumulating-handler! {:ns-pattern "*"}))
867-
(future (profile {} (p :p1 (Thread/sleep 900))))
868-
(future (profile {:id :foo} (p :p1 (Thread/sleep 900))))
869-
(future (profile {:id :bar} (p :p1 (Thread/sleep 500))))
870-
(println (format-grouped-pstats @my-sacc {}
871-
#_{:format-pstats-opts {:columns [:n]}})))
872862

873-
(defn format-grouped-pstats
874-
"Alpha, subject to change.
875-
Takes a map of {<group-id> <PStats>} and formats a combined
876-
output string using `format-pstats`.
877-
878-
See also example clj project."
879-
([m] (format-grouped-pstats m nil))
880-
([m {:keys [group-sort-fn format-pstats-opts]
881-
:or {group-sort-fn (fn [m] (get-in m [:clock :total] 0))}}]
882-
883-
(when m
884-
(let [m ; {<group-id> <realised-pstats>}
885-
(persistent!
886-
(reduce-kv
887-
(fn [m k v] (assoc! m k (enc/force-ref v)))
888-
(transient m)
889-
m))
890-
891-
sorted-group-ids
892-
(sort-by (fn [id] (group-sort-fn (get m id)))
893-
enc/rcompare (keys m))
894-
895-
^long max-id-width
896-
(reduce-kv
897-
(fn [^long acc _ {:keys [clock stats]}]
898-
(if-let [c (impl/get-max-id-width stats format-pstats-opts)]
899-
(if (> (long c) acc) c acc)
900-
acc))
901-
0
902-
m)]
903-
904-
(enc/str-join "\n\n"
905-
(map (fn [id] (str id ",\n" (format-pstats (get m id) (assoc format-pstats-opts :max-id-width max-id-width)))))
906-
sorted-group-ids)))))
863+
(do
864+
(future (profile {} (p :p1 (Thread/sleep 900))))
865+
(future (profile {:id :foo} (p :p1 (Thread/sleep 900))))
866+
(future (profile {:id :bar} (p :p1 (Thread/sleep 500)))))
907867

908-
(comment
909-
(future
910-
(while true
911-
(when-let [m (not-empty @my-sacc)]
912-
(println (format-grouped-pstats m)))
913-
(Thread/sleep 10000))))
868+
(println
869+
(format-grouped-pstats @my-sacc
870+
{:format-pstats-opts {:columns [:n]}})))
914871

915872
;;;; Deprecated
916873

src/taoensso/tufte/impl.cljc

Lines changed: 75 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -438,50 +438,6 @@
438438

439439
;;;; Formatting
440440

441-
(defn- perc [n d] (str (Math/round (* (/ (double n) (double d)) 100.0)) "%"))
442-
(comment [(perc 1 1) (perc 1 100) (perc 12 44)])
443-
444-
(def ^:dynamic *fmt-opts* {:decimal-separator ".", :thousands-separator ","})
445-
(defn- fmt-num [precision n]
446-
;; Impln is inefficient but sufficient, and consistent between clj/s
447-
(let [n (enc/roundn precision n)
448-
neg? (neg? n)
449-
n-abs (Math/abs n)
450-
n-int-part (long n-abs)
451-
fmt-opts *fmt-opts*]
452-
(str
453-
(when neg? "-")
454-
(->>
455-
(str n-int-part)
456-
(reverse)
457-
(partition 3 3 "")
458-
(mapv str/join)
459-
(str/join (get fmt-opts :thousands-separator))
460-
(str/reverse))
461-
462-
(when-let [n-dec-part (and (pos? (long precision)) (- n-abs n-int-part))]
463-
(str (get fmt-opts :decimal-separator)
464-
(enc/substr (str n-dec-part "000000")
465-
:by-len 2 precision))))))
466-
467-
(comment
468-
(fmt-num 0 123123123.5555) ; "123,123,124"
469-
(fmt-num 2 123123123.5555) ; "123,123,123.56"
470-
(fmt-num 2 123123123) ; "123,123,123.00"
471-
(fmt-num 3 123) ; "123"
472-
)
473-
474-
(defn- fmt-nsecs [nanosecs]
475-
(let [ns (double nanosecs)]
476-
(cond
477-
(>= ns 6e10) (str (fmt-num 2 (/ ns 6e10)) "m")
478-
(>= ns 1e9) (str (fmt-num 2 (/ ns 1e9)) "s")
479-
(>= ns 1e6) (str (fmt-num 0 (/ ns 1e6)) "ms")
480-
(>= ns 1e3) (str (fmt-num 0 (/ ns 1e3)) "μs")
481-
:else (str (fmt-num 0 ns) "ns"))))
482-
483-
(comment (fmt-nsecs 1e3))
484-
485441
(def all-format-columns [:n :min :p25 :p50 :p75 :p90 :p95 :p99 :max :mean :mad :clock :sum])
486442
(def default-format-columns [:n :min #_:p25 :p50 #_:p75 :p90 :p95 :p99 :max :mean :mad :clock :sum])
487443

@@ -495,16 +451,13 @@
495451
(identical? columns all-format-columns) all-format-columns
496452
:else (mapv format-column columns))))
497453

498-
(comment (enc/qb 1e6 (format-columns [:min :n-calls :total])))
499-
500-
(def default-format-id-fn (fn [id] (str id)))
454+
(comment (enc/qb 1e6 (format-columns [:min :n-calls :total]))) ; 152.9
501455

502456
;; id-sstats* => {<id> <sstats>} or {<id> <sstats-map>}
503-
504457
(defn get-max-id-width
505458
[id-sstats*
506459
{:keys [format-id-fn]
507-
:or {format-id-fn default-format-id-fn}}]
460+
:or {format-id-fn (fn [id] (str id))}}]
508461

509462
(when id-sstats*
510463
(reduce-kv
@@ -514,15 +467,18 @@
514467
9 ; (count "Accounted")
515468
id-sstats*)))
516469

517-
(defn format-pstats
470+
(def ^:private format-n (enc/format-num-fn 0 0))
471+
472+
(defn format-pstats*
518473
"Given {<id> <sstats>} or {<id> <sstats-map>} pstats, returns a formatted
519474
table string. Assumes nanosecond clock, and stats based on profiling id'd
520475
nanosecond times."
521476
[clock-total id-sstats*
522477
{:keys [columns sort-fn format-id-fn max-id-width] :as opts
523-
:or {columns default-format-columns
524-
sort-fn (fn [ss] (get (enc/force-ref ss) :sum))
525-
format-id-fn default-format-id-fn}}]
478+
:or
479+
{columns default-format-columns
480+
sort-fn (fn [ss] (get (enc/force-ref ss) :sum))
481+
format-id-fn (fn [id] (str id))}}]
526482

527483
(when id-sstats*
528484
(let [columns (format-columns columns)
@@ -579,7 +535,7 @@
579535
(enc/sb-append sb " "))
580536
(append-col column (get-in column->pattern [column :heading])))
581537

582-
(enc/sb-append sb "\n\n")
538+
(enc/sb-append sb enc/newlines)
583539

584540
; Write id rows
585541
(doseq [id sorted-ids]
@@ -590,36 +546,36 @@
590546
(doseq [column columns]
591547
(enc/sb-append sb " ")
592548
(case column
593-
:n (append-col column (fmt-num 0 n))
594-
:mean (append-col column (fmt-nsecs mean))
595-
:mad (append-col column (str "±" (perc mad mean)))
596-
:sum (append-col column (perc sum clock-total))
597-
:clock (append-col column (fmt-nsecs sum))
598-
(do (append-col column (fmt-nsecs (get ssm column))))))
549+
:n (append-col column (format-n n))
550+
:mean (append-col column (enc/format-nsecs mean))
551+
:mad (append-col column (str "±" (enc/perc mad mean) "%"))
552+
:sum (append-col column (str (enc/perc sum clock-total) "%"))
553+
:clock (append-col column (enc/format-nsecs sum))
554+
(do (append-col column (enc/format-nsecs (get ssm column))))))
599555

600-
(enc/sb-append sb "\n")))
556+
(enc/sb-append sb enc/newline)))
601557

602558
; Write accounted row
603-
(enc/sb-append sb "\n")
559+
(enc/sb-append sb enc/newline)
604560
(append-col :id "Accounted")
605561
(doseq [column columns]
606562
(enc/sb-append sb " ")
607563
(case column
608-
:sum (append-col column (perc accounted-total clock-total))
609-
:clock (append-col column (fmt-nsecs accounted-total))
564+
:sum (append-col column (str (enc/perc accounted-total clock-total) "%"))
565+
:clock (append-col column (enc/format-nsecs accounted-total))
610566
(do (append-col column ""))))
611567

612568
; Write clock row
613-
(enc/sb-append sb "\n")
569+
(enc/sb-append sb enc/newline)
614570
(append-col :id "Clock")
615571
(doseq [column columns]
616572
(enc/sb-append sb " ")
617573
(case column
618574
:sum (append-col column "100%")
619-
:clock (append-col column (fmt-nsecs clock-total))
575+
:clock (append-col column (enc/format-nsecs clock-total))
620576
(do (append-col column ""))))
621577

622-
(enc/sb-append sb "\n")
578+
;; (enc/sb-append sb enc/newline)
623579
(str sb))))
624580

625581
(comment
@@ -628,11 +584,60 @@
628584

629585
(println
630586
(format-pstats (* 1e6 30)
631-
{:foo (summary-stats (rand-vs 1e4 20))
632-
:bar (summary-stats (rand-vs 1e2 50))
633-
:baz (summary-stats (rand-vs 1e5 30))}
587+
{:foo (stats/summary-stats (rand-vs 1e4 20))
588+
:bar (stats/summary-stats (rand-vs 1e2 50))
589+
:baz (stats/summary-stats (rand-vs 1e5 30))}
634590
{}) "\n"))
635591

592+
(defn ^:public format-pstats
593+
"Formats given pstats to a string table.
594+
Accounted < Clock => Some work was done that wasn't tracked by any p forms.
595+
Accounted > Clock => Nested p forms, and/or parallel threads."
596+
([ps ] (format-pstats ps nil))
597+
([ps opts]
598+
(when ps
599+
(let [{:keys [clock stats]} (enc/force-ref ps)]
600+
(format-pstats* (get clock :total) stats opts)))))
601+
602+
(defn ^:public format-grouped-pstats
603+
"Alpha, subject to change.
604+
Takes a map of {<profile-id> <pstats>} and formats a combined
605+
output string using `format-pstats`.
606+
607+
See also example Clj project."
608+
([m] (format-grouped-pstats m nil))
609+
([m {:keys [group-sort-fn format-pstats-opts]
610+
:or {group-sort-fn (fn [m] (get-in m [:clock :total] 0))}}]
611+
612+
(when m
613+
(let [m ; {<profile-id> <realised-pstats>}
614+
(persistent!
615+
(reduce-kv
616+
(fn [m k v] (assoc! m k (enc/force-ref v)))
617+
(transient m)
618+
m))
619+
620+
sorted-profile-ids
621+
(sort-by (fn [id] (group-sort-fn (get m id)))
622+
enc/rcompare (keys m))
623+
624+
^long max-id-width
625+
(reduce-kv
626+
(fn [^long acc _ {:keys [clock stats]}]
627+
(if-let [c (get-max-id-width stats format-pstats-opts)]
628+
(if (> (long c) acc) c acc)
629+
acc))
630+
0 m)
631+
632+
sep (str "," enc/newline)
633+
format-pstats-opts
634+
(assoc format-pstats-opts
635+
:max-id-width max-id-width)]
636+
637+
(enc/str-join enc/newlines
638+
(map (fn [id] (str id sep (format-pstats (get m id) format-pstats-opts))))
639+
sorted-profile-ids)))))
640+
636641
;;;; Output handlers
637642

638643
(enc/defonce handlers_ "{<hid> <handler-fn>}" (atom nil))

test/taoensso/tufte_tests.cljc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,7 @@
446446
:baz {:n 1}}}))])))]))
447447

448448
(deftest format-pstats
449-
[(testing "Basic format-pstats"
449+
[(testing "Basics"
450450
(let [data {:clock {:total 15}
451451
:stats {:foo {:n 10000
452452
:min 1
@@ -477,7 +477,7 @@
477477
(str/split-lines)
478478
(remove empty?))))]))
479479

480-
(testing "format-pstats with namespaced symbols"
480+
(testing "With namespaced symbols"
481481
(let [data {:clock {:total 15}
482482
:stats {:foo/bar {:n 10000
483483
:min 1

0 commit comments

Comments
 (0)