|
438 | 438 |
|
439 | 439 | ;;;; Formatting
|
440 | 440 |
|
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 |
| - |
485 | 441 | (def all-format-columns [:n :min :p25 :p50 :p75 :p90 :p95 :p99 :max :mean :mad :clock :sum])
|
486 | 442 | (def default-format-columns [:n :min #_:p25 :p50 #_:p75 :p90 :p95 :p99 :max :mean :mad :clock :sum])
|
487 | 443 |
|
|
495 | 451 | (identical? columns all-format-columns) all-format-columns
|
496 | 452 | :else (mapv format-column columns))))
|
497 | 453 |
|
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 |
501 | 455 |
|
502 | 456 | ;; id-sstats* => {<id> <sstats>} or {<id> <sstats-map>}
|
503 |
| - |
504 | 457 | (defn get-max-id-width
|
505 | 458 | [id-sstats*
|
506 | 459 | {:keys [format-id-fn]
|
507 |
| - :or {format-id-fn default-format-id-fn}}] |
| 460 | + :or {format-id-fn (fn [id] (str id))}}] |
508 | 461 |
|
509 | 462 | (when id-sstats*
|
510 | 463 | (reduce-kv
|
|
514 | 467 | 9 ; (count "Accounted")
|
515 | 468 | id-sstats*)))
|
516 | 469 |
|
517 |
| -(defn format-pstats |
| 470 | +(def ^:private format-n (enc/format-num-fn 0 0)) |
| 471 | + |
| 472 | +(defn format-pstats* |
518 | 473 | "Given {<id> <sstats>} or {<id> <sstats-map>} pstats, returns a formatted
|
519 | 474 | table string. Assumes nanosecond clock, and stats based on profiling id'd
|
520 | 475 | nanosecond times."
|
521 | 476 | [clock-total id-sstats*
|
522 | 477 | {: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))}}] |
526 | 482 |
|
527 | 483 | (when id-sstats*
|
528 | 484 | (let [columns (format-columns columns)
|
|
579 | 535 | (enc/sb-append sb " "))
|
580 | 536 | (append-col column (get-in column->pattern [column :heading])))
|
581 | 537 |
|
582 |
| - (enc/sb-append sb "\n\n") |
| 538 | + (enc/sb-append sb enc/newlines) |
583 | 539 |
|
584 | 540 | ; Write id rows
|
585 | 541 | (doseq [id sorted-ids]
|
|
590 | 546 | (doseq [column columns]
|
591 | 547 | (enc/sb-append sb " ")
|
592 | 548 | (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)))))) |
599 | 555 |
|
600 |
| - (enc/sb-append sb "\n"))) |
| 556 | + (enc/sb-append sb enc/newline))) |
601 | 557 |
|
602 | 558 | ; Write accounted row
|
603 |
| - (enc/sb-append sb "\n") |
| 559 | + (enc/sb-append sb enc/newline) |
604 | 560 | (append-col :id "Accounted")
|
605 | 561 | (doseq [column columns]
|
606 | 562 | (enc/sb-append sb " ")
|
607 | 563 | (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)) |
610 | 566 | (do (append-col column ""))))
|
611 | 567 |
|
612 | 568 | ; Write clock row
|
613 |
| - (enc/sb-append sb "\n") |
| 569 | + (enc/sb-append sb enc/newline) |
614 | 570 | (append-col :id "Clock")
|
615 | 571 | (doseq [column columns]
|
616 | 572 | (enc/sb-append sb " ")
|
617 | 573 | (case column
|
618 | 574 | :sum (append-col column "100%")
|
619 |
| - :clock (append-col column (fmt-nsecs clock-total)) |
| 575 | + :clock (append-col column (enc/format-nsecs clock-total)) |
620 | 576 | (do (append-col column ""))))
|
621 | 577 |
|
622 |
| - (enc/sb-append sb "\n") |
| 578 | + ;; (enc/sb-append sb enc/newline) |
623 | 579 | (str sb))))
|
624 | 580 |
|
625 | 581 | (comment
|
|
628 | 584 |
|
629 | 585 | (println
|
630 | 586 | (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))} |
634 | 590 | {}) "\n"))
|
635 | 591 |
|
| 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 | + |
636 | 641 | ;;;; Output handlers
|
637 | 642 |
|
638 | 643 | (enc/defonce handlers_ "{<hid> <handler-fn>}" (atom nil))
|
|
0 commit comments