Last active
March 5, 2021 23:05
-
-
Save Grazfather/be5d5d15057fc985e3c6f03e26dd1aa5 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bb | |
(ns context-times | |
(:require [clojure.data.csv :as csv] | |
[clojure.java.io :as io] | |
[clojure.java.shell :refer [sh]] | |
[clojure.string :as s] | |
[clojure.tools.cli :refer [parse-opts]])) | |
;; CLI | |
(def cli-options | |
[["-s" "--start COMMIT" "Start commit" | |
:default "@^^^" | |
] | |
["-e" "--end COMMIT" "End commit" | |
:default "@" | |
] | |
["-r" "--repetitions REP" "Number of times to run the command on each commit" | |
:default 5 | |
:parse-fn #(Integer/parseInt %) | |
:validate [#(> % 0) "Must be a number greater than 0"] | |
] | |
["-o" "--output FILENAME" "Filename to write CSV output to" | |
:default "stats.csv" | |
] | |
["-c" "--cmd COMMAND" "Python invocation to profile from GDB" | |
:default "gdb.execute(\"context\")"]]) | |
;; Git stuff | |
(defn get-revision-hash | |
[rev] | |
(-> (sh "git" "log" "-1" "--pretty=%h" rev) :out s/trim)) | |
(defn get-revision-title | |
[rev] | |
(-> (sh "git" "log" "-1" "--pretty=%s" rev) :out s/trim)) | |
(defn get-revisions-in-range | |
[start end] | |
(-> (sh "git" "rev-list" "--reverse" (str start ".." end)) :out s/split-lines)) | |
(defn get-current-branch | |
[] | |
(let [[_ _ branch] (->> (sh "git" "branch") | |
:out | |
(re-find #"\* (\(HEAD detached at )?([0-9a-zA-Z_\-.]+)"))] | |
branch)) | |
(defn checkout | |
[rev] | |
(sh "git" "checkout" "--quiet" rev)) | |
(defn run-on-revision | |
([f rev] (run-on-revision f rev 1)) | |
([f rev n] | |
(let [current (get-revision-hash "@")] | |
(try | |
(checkout rev) | |
(repeatedly n f) | |
(finally | |
(sh "git" "reset" "--hard" "--quiet") | |
(checkout current)))))) | |
;; GDB profile invocations | |
(defn time-gdb-command | |
[command] | |
(-> (sh "gdb" "-q" | |
"-ex" "start" | |
"-ex" "pi import profile" | |
"-ex" (str "pi profile.run(" (pr-str command) ", sort=\"cumtime\")") | |
"-ex" "quit" | |
"/bin/cat") | |
:out)) | |
(defn get-profile-time | |
[output] | |
(let [[_ t] (re-find #"\n\s+\d+\s+[0-9.]+\s+[0-9.]+\s+([0-9.]+)\s+[0-9.]+ profile:.+\n" output)] | |
(read-string t))) | |
(defn get-command-times | |
([cmd start end] (get-command-times cmd start end 1)) | |
([cmd start end n] | |
(let [revisions (get-revisions-in-range start end) | |
profiles (map #(run-on-revision #(time-gdb-command cmd) % n) revisions) | |
times (map #(map get-profile-time %) profiles)] | |
(map vector revisions times)))) | |
(defn write-stats | |
[stats filename] | |
(with-open [writer (io/writer filename)] | |
(->> stats | |
(map #(let [[rev times] %] | |
(apply vector rev (get-revision-title rev) times))) | |
(csv/write-csv writer)))) | |
(def opts (:options (parse-opts *command-line-args* cli-options))) | |
(let [start (:start opts) | |
end (:end opts) | |
reps (:repetitions opts) | |
cmd (:cmd opts) | |
filename (:output opts)] | |
(println (str "Running '" cmd "' on each revision between " start " and " end " " (str reps) | |
" times and writing output to " filename)) | |
(let [stats (get-command-times cmd start end reps)] | |
(write-stats stats filename))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment