|
436 | 436 |
|
437 | 437 | ;;;; Formatting
|
438 | 438 |
|
439 |
| -(defn- perc [n d] (str (Math/round (* (/ (double n) (double d)) 100.0)) "%")) |
440 |
| -(comment [(perc 1 1) (perc 1 100) (perc 12 44)]) |
441 |
| - |
442 |
| -(def ^:dynamic *fmt-opts* {:decimal-separator ".", :thousands-separator ","}) |
443 |
| -(defn- fmt-num [precision n] |
444 |
| - ;; Impln is inefficient but sufficient, and consistent between clj/s |
445 |
| - (let [n (enc/roundn precision n) |
446 |
| - neg? (neg? n) |
447 |
| - n-abs (Math/abs n) |
448 |
| - n-int-part (long n-abs) |
449 |
| - fmt-opts *fmt-opts*] |
450 |
| - (str |
451 |
| - (when neg? "-") |
452 |
| - (->> |
453 |
| - (str n-int-part) |
454 |
| - (reverse) |
455 |
| - (partition 3 3 "") |
456 |
| - (mapv str/join) |
457 |
| - (str/join (get fmt-opts :thousands-separator)) |
458 |
| - (str/reverse)) |
459 |
| - |
460 |
| - (when-let [n-dec-part (and (pos? (long precision)) (- n-abs n-int-part))] |
461 |
| - (str (get fmt-opts :decimal-separator) |
462 |
| - (enc/substr (str n-dec-part "000000") |
463 |
| - :by-len 2 precision)))))) |
464 |
| - |
465 |
| -(comment |
466 |
| - (fmt-num 0 123123123.5555) ; "123,123,124" |
467 |
| - (fmt-num 2 123123123.5555) ; "123,123,123.56" |
468 |
| - (fmt-num 2 123123123) ; "123,123,123.00" |
469 |
| - (fmt-num 3 123) ; "123" |
470 |
| - ) |
471 |
| - |
472 |
| -(defn- fmt-nsecs [nanosecs] |
473 |
| - (let [ns (double nanosecs)] |
474 |
| - (cond |
475 |
| - (>= ns 6e10) (str (fmt-num 2 (/ ns 6e10)) "m") |
476 |
| - (>= ns 1e9) (str (fmt-num 2 (/ ns 1e9)) "s") |
477 |
| - (>= ns 1e6) (str (fmt-num 0 (/ ns 1e6)) "ms") |
478 |
| - (>= ns 1e3) (str (fmt-num 0 (/ ns 1e3)) "μs") |
479 |
| - :else (str (fmt-num 0 ns) "ns")))) |
480 |
| - |
481 |
| -(comment (fmt-nsecs 1e3)) |
482 |
| - |
483 | 439 | (def all-format-columns [:n :min :p25 :p50 :p75 :p90 :p95 :p99 :max :mean :mad :clock :sum])
|
484 | 440 | (def default-format-columns [:n :min #_:p25 :p50 #_:p75 :p90 :p95 :p99 :max :mean :mad :clock :sum])
|
485 | 441 |
|
|
493 | 449 | (identical? columns all-format-columns) all-format-columns
|
494 | 450 | :else (mapv format-column columns))))
|
495 | 451 |
|
496 |
| -(comment (enc/qb 1e6 (format-columns [:min :n-calls :total]))) |
497 |
| - |
498 |
| -(def default-format-id-fn (fn [id] (str id))) |
| 452 | +(comment (enc/qb 1e6 (format-columns [:min :n-calls :total]))) ; 152.9 |
499 | 453 |
|
500 | 454 | ;; id-sstats* => {<id> <sstats>} or {<id> <sstats-map>}
|
501 |
| - |
502 | 455 | (defn get-max-id-width
|
503 | 456 | [id-sstats*
|
504 | 457 | {:keys [format-id-fn]
|
505 |
| - :or {format-id-fn default-format-id-fn}}] |
| 458 | + :or {format-id-fn (fn [id] (str id))}}] |
506 | 459 |
|
507 | 460 | (when id-sstats*
|
508 | 461 | (reduce-kv
|
|
512 | 465 | 9 ; (count "Accounted")
|
513 | 466 | id-sstats*)))
|
514 | 467 |
|
515 |
| -(defn format-pstats |
| 468 | +(def ^:private format-n (enc/format-num-fn 0 0)) |
| 469 | + |
| 470 | +(defn format-pstats* |
516 | 471 | "Given {<id> <sstats>} or {<id> <sstats-map>} pstats, returns a formatted
|
517 | 472 | table string. Assumes nanosecond clock, and stats based on profiling id'd
|
518 | 473 | nanosecond times."
|
519 | 474 | [clock-total id-sstats*
|
520 | 475 | {:keys [columns sort-fn format-id-fn max-id-width] :as opts
|
521 |
| - :or {columns default-format-columns |
522 |
| - sort-fn (fn [ss] (get (enc/force-ref ss) :sum)) |
523 |
| - format-id-fn default-format-id-fn}}] |
| 476 | + :or |
| 477 | + {columns default-format-columns |
| 478 | + sort-fn (fn [ss] (get (enc/force-ref ss) :sum)) |
| 479 | + format-id-fn (fn [id] (str id))}}] |
524 | 480 |
|
525 | 481 | (when id-sstats*
|
526 | 482 | (let [columns (format-columns columns)
|
|
577 | 533 | (enc/sb-append sb " "))
|
578 | 534 | (append-col column (get-in column->pattern [column :heading])))
|
579 | 535 |
|
580 |
| - (enc/sb-append sb "\n\n") |
| 536 | + (enc/sb-append sb enc/newlines) |
581 | 537 |
|
582 | 538 | ; Write id rows
|
583 | 539 | (doseq [id sorted-ids]
|
|
588 | 544 | (doseq [column columns]
|
589 | 545 | (enc/sb-append sb " ")
|
590 | 546 | (case column
|
591 |
| - :n (append-col column (fmt-num 0 n)) |
592 |
| - :mean (append-col column (fmt-nsecs mean)) |
593 |
| - :mad (append-col column (str "±" (perc mad mean))) |
594 |
| - :sum (append-col column (perc sum clock-total)) |
595 |
| - :clock (append-col column (fmt-nsecs sum)) |
596 |
| - (do (append-col column (fmt-nsecs (get ssm column)))))) |
| 547 | + :n (append-col column (format-n n)) |
| 548 | + :mean (append-col column (enc/format-nsecs mean)) |
| 549 | + :mad (append-col column (str "±" (enc/perc mad mean) "%")) |
| 550 | + :sum (append-col column (str (enc/perc sum clock-total) "%")) |
| 551 | + :clock (append-col column (enc/format-nsecs sum)) |
| 552 | + (do (append-col column (enc/format-nsecs (get ssm column)))))) |
597 | 553 |
|
598 |
| - (enc/sb-append sb "\n"))) |
| 554 | + (enc/sb-append sb enc/newline))) |
599 | 555 |
|
600 | 556 | ; Write accounted row
|
601 |
| - (enc/sb-append sb "\n") |
| 557 | + (enc/sb-append sb enc/newline) |
602 | 558 | (append-col :id "Accounted")
|
603 | 559 | (doseq [column columns]
|
604 | 560 | (enc/sb-append sb " ")
|
605 | 561 | (case column
|
606 |
| - :sum (append-col column (perc accounted-total clock-total)) |
607 |
| - :clock (append-col column (fmt-nsecs accounted-total)) |
| 562 | + :sum (append-col column (str (enc/perc accounted-total clock-total) "%")) |
| 563 | + :clock (append-col column (enc/format-nsecs accounted-total)) |
608 | 564 | (do (append-col column ""))))
|
609 | 565 |
|
610 | 566 | ; Write clock row
|
611 |
| - (enc/sb-append sb "\n") |
| 567 | + (enc/sb-append sb enc/newline) |
612 | 568 | (append-col :id "Clock")
|
613 | 569 | (doseq [column columns]
|
614 | 570 | (enc/sb-append sb " ")
|
615 | 571 | (case column
|
616 | 572 | :sum (append-col column "100%")
|
617 |
| - :clock (append-col column (fmt-nsecs clock-total)) |
| 573 | + :clock (append-col column (enc/format-nsecs clock-total)) |
618 | 574 | (do (append-col column ""))))
|
619 | 575 |
|
620 |
| - (enc/sb-append sb "\n") |
| 576 | + ;; (enc/sb-append sb enc/newline) |
621 | 577 | (str sb))))
|
622 | 578 |
|
623 | 579 | (comment
|
|
626 | 582 |
|
627 | 583 | (println
|
628 | 584 | (format-pstats (* 1e6 30)
|
629 |
| - {:foo (summary-stats (rand-vs 1e4 20)) |
630 |
| - :bar (summary-stats (rand-vs 1e2 50)) |
631 |
| - :baz (summary-stats (rand-vs 1e5 30))} |
| 585 | + {:foo (stats/summary-stats (rand-vs 1e4 20)) |
| 586 | + :bar (stats/summary-stats (rand-vs 1e2 50)) |
| 587 | + :baz (stats/summary-stats (rand-vs 1e5 30))} |
632 | 588 | {}) "\n"))
|
633 | 589 |
|
| 590 | +(defn ^:public format-pstats |
| 591 | + "Formats given pstats to a string table. |
| 592 | + Accounted < Clock => Some work was done that wasn't tracked by any p forms. |
| 593 | + Accounted > Clock => Nested p forms, and/or parallel threads." |
| 594 | + ([ps ] (format-pstats ps nil)) |
| 595 | + ([ps opts] |
| 596 | + (when ps |
| 597 | + (let [{:keys [clock stats]} (enc/force-ref ps)] |
| 598 | + (format-pstats* (get clock :total) stats opts))))) |
| 599 | + |
| 600 | +(defn ^:public format-grouped-pstats |
| 601 | + "Alpha, subject to change. |
| 602 | + Takes a map of {<profile-id> <pstats>} and formats a combined |
| 603 | + output string using `format-pstats`. |
| 604 | +
|
| 605 | + See also example Clj project." |
| 606 | + ([m] (format-grouped-pstats m nil)) |
| 607 | + ([m {:keys [group-sort-fn format-pstats-opts] |
| 608 | + :or {group-sort-fn (fn [m] (get-in m [:clock :total] 0))}}] |
| 609 | + |
| 610 | + (when m |
| 611 | + (let [m ; {<profile-id> <realised-pstats>} |
| 612 | + (persistent! |
| 613 | + (reduce-kv |
| 614 | + (fn [m k v] (assoc! m k (enc/force-ref v))) |
| 615 | + (transient m) |
| 616 | + m)) |
| 617 | + |
| 618 | + sorted-profile-ids |
| 619 | + (sort-by (fn [id] (group-sort-fn (get m id))) |
| 620 | + enc/rcompare (keys m)) |
| 621 | + |
| 622 | + ^long max-id-width |
| 623 | + (reduce-kv |
| 624 | + (fn [^long acc _ {:keys [clock stats]}] |
| 625 | + (if-let [c (get-max-id-width stats format-pstats-opts)] |
| 626 | + (if (> (long c) acc) c acc) |
| 627 | + acc)) |
| 628 | + 0 m) |
| 629 | + |
| 630 | + sep (str "," enc/newline) |
| 631 | + format-pstats-opts |
| 632 | + (assoc format-pstats-opts |
| 633 | + :max-id-width max-id-width)] |
| 634 | + |
| 635 | + (enc/str-join enc/newlines |
| 636 | + (map (fn [id] (str id sep (format-pstats (get m id) format-pstats-opts)))) |
| 637 | + sorted-profile-ids))))) |
| 638 | + |
634 | 639 | ;;;; Output handlers
|
635 | 640 |
|
636 | 641 | (enc/defonce handlers_ "{<hid> <handler-fn>}" (atom nil))
|
|
0 commit comments