Created
July 4, 2020 22:34
-
-
Save RutledgePaulV/0161060b01d5aa8fa98aa21a81b0460b to your computer and use it in GitHub Desktop.
A task timer for self-optimizing programs that favors recent timings over older timings.
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
(ns piped.tools | |
(:require [amalloy.ring-buffer :as rb])) | |
(defprotocol Timer | |
(start [this key] "Given some key, start timing it.") | |
(stop [this key] "Given some key, stop timing it.") | |
(avg [this] "Get the weighted average of timings tracked thus far with this timer. Recent timings are weighted more.")) | |
(defn weighted-average | |
"Calculates the weighted average of numbers. Each subsequent number is weighted one | |
more than the previous number was weighted. The first number is weighted at 1." | |
[numbers] | |
(let [{:keys [sum parts]} | |
(reduce | |
(fn [agg [weight time]] | |
(let [part (inc weight)] | |
(-> agg | |
(update :sum + (* part time)) | |
(update :parts + part)))) | |
{:sum 0 :parts 0} | |
(map-indexed vector numbers))] | |
(when (pos? parts) (/ sum parts)))) | |
(defn new-timer [capacity] | |
(let [state (atom {:pending {} :buffer (rb/ring-buffer capacity)})] | |
(reify Timer | |
(avg [this] (weighted-average (:buffer @state))) | |
(start [this key] | |
(let [time (System/currentTimeMillis)] | |
(swap! state assoc-in [:pending key] time) | |
time)) | |
(stop [this key] | |
(let [time (System/currentTimeMillis)] | |
(swap! state | |
(fn [old] | |
(let [start (get-in old [:pending key])] | |
(-> old | |
(update :pending dissoc key) | |
(update :buffer conj (- time start)))))) | |
time))))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment