|
| 1 | +(ns kaocha.plugin.alpha.parallel-profiling |
| 2 | + (:require [clojure.java.io :as io] |
| 3 | + [clojure.string :as str] |
| 4 | + [kaocha.plugin :as plugin :refer [defplugin]] |
| 5 | + [kaocha.output :as output] |
| 6 | + [kaocha.testable :as testable]) |
| 7 | + (:import java.time.Instant |
| 8 | + java.time.temporal.ChronoUnit)) |
| 9 | + |
| 10 | +(defn start [testable] |
| 11 | + (assoc testable ::start (Instant/now))) |
| 12 | + |
| 13 | +(defn stop [testable] |
| 14 | + (cond-> testable |
| 15 | + true (assoc ::end (Instant/now)) |
| 16 | + (::start testable) |
| 17 | + (assoc ::duration (.until (::start testable) |
| 18 | + (Instant/now) |
| 19 | + ChronoUnit/NANOS)))) |
| 20 | + |
| 21 | +(defplugin kaocha.plugin.alpha/parallel-profiling |
| 22 | + (config [config] |
| 23 | + (output/warn "Warning: The kaocha.plugin.alpha/parallel-profiling plugin is in an alpha status, like the parallel feature in general.") |
| 24 | + config |
| 25 | + ) |
| 26 | + (pre-run [test-plan] |
| 27 | + (start test-plan)) |
| 28 | + |
| 29 | + (post-run [test-plan] |
| 30 | + (stop test-plan)) |
| 31 | + |
| 32 | + (pre-test [testable _] |
| 33 | + (start testable)) |
| 34 | + |
| 35 | + (post-test [testable _] |
| 36 | + (stop testable)) |
| 37 | + |
| 38 | + (cli-options [opts] |
| 39 | + (conj opts |
| 40 | + [nil "--[no-]-parallel-profiling" "Show slowest tests of each type with timing information."] |
| 41 | + #_[nil "--profiling-count NUM" "Show this many slow tests of each kind in profile results." |
| 42 | + :parse-fn #(Integer/parseInt %)])) |
| 43 | + |
| 44 | + (config [{:kaocha/keys [cli-options] :as config}] |
| 45 | + (assoc config |
| 46 | + ::parallel-profiling? (:parallel-profiling cli-options (::parallel-profiling? config true)) |
| 47 | + #_#_::count (:profiling-count cli-options (::count config 3)))) |
| 48 | + |
| 49 | + (post-summary [result] |
| 50 | + (when (::parallel-profiling? result) |
| 51 | + (let [tests (->> result |
| 52 | + testable/test-seq |
| 53 | + (remove ::testable/load-error) |
| 54 | + (remove ::testable/skip)) |
| 55 | + #_#_types (group-by :kaocha.testable/type tests) |
| 56 | + threads (group-by #(get-in % [ :kaocha.testable/thread :name]) tests) |
| 57 | + total-duration (::duration result) |
| 58 | + #_#_limit (::count result) |
| 59 | + ] |
| 60 | + (->> (for [[thread tests] threads |
| 61 | + :when (and thread |
| 62 | + (some (complement nil?) (map ::start tests)) |
| 63 | + (some (complement nil?) (map ::end tests))) ;temporary fix until I figure out why these keys are sometimes missing. |
| 64 | + :let [start (reduce min (map ::start tests)) |
| 65 | + end (reduce max (map ::end tests)) |
| 66 | + span-ns (.until start |
| 67 | + end |
| 68 | + ChronoUnit/NANOS) |
| 69 | + span (cond |
| 70 | + (> span-ns 1e8) (format "%.2f s" (/ span-ns 1e9)) |
| 71 | + (> span-ns 1e5) (format "%.2f ms" (/ span-ns 1e9)) |
| 72 | + :else (str span-ns " ns")) |
| 73 | + utilization (float (* 100 (/ (reduce + (map ::duration tests)) span-ns))) |
| 74 | + utilization-external (float (* 100 (/ (reduce + (map ::duration tests)) total-duration))) |
| 75 | + ]] |
| 76 | + |
| 77 | + (println (format "Thread %s ran from %s to %s (%s), utilizing %.2f%% (internal) and %.2f%% (external)" |
| 78 | + thread start end span utilization utilization-external))) |
| 79 | + (flatten) |
| 80 | + (apply str) |
| 81 | + print) |
| 82 | + |
| 83 | + |
| 84 | + (println (format "\n%d threads ran in %f seconds." (count threads) (float (/ total-duration 1e9)))) |
| 85 | + (flush) |
| 86 | + |
| 87 | + )) |
| 88 | + result)) |
| 89 | + |
| 90 | +(.until (Instant/now) (Instant/now) ChronoUnit/NANOS) |
0 commit comments