(ns dev.memory (:require [metabase.util.log :as log]) (:import (java.lang.management ManagementFactory))) | |
measurement requires reflection as we don't know the concrete class
we can't using | (set! *warn-on-reflection* false) |
Measure the cumulative bytes allocated by a thread, ignoring whether its been collected. | (defn- get-thread-allocated-bytes
[]
(let [mx-bean (ManagementFactory/getThreadMXBean)
;; `getId`` is deprecated, we will need to update to `threadId` at some point.
thread-id (.getId (Thread/currentThread))]
;; this method is only defined for some platform implementations.
(assert (.isThreadAllocatedMemorySupported mx-bean))
(.getThreadAllocatedBytes mx-bean thread-id))) |
Format bytes as megabytes | (defn mb-str [bytes] (format "%.3f MB" (/ (double bytes) 1024 1024))) |
Measure the number of bytes allocated when calling the given function. | (defn measure-thread-allocations
[f]
(let [before (get-thread-allocated-bytes)
result (f)
after (get-thread-allocated-bytes)]
{:result result
:allocations (- after before)})) |
Measure the number of bytes allocated when evaluating the given body. | (defmacro measuring-thread-allocations
[& body]
`(let [m# (measure-thread-allocations #(do ~@body))]
(log/warnf "Allocated: %s" (mb-str (:allocations m#)))
(:result m#))) |
(def ^{:dynamic true
:private true} *memory-log-level* -1) | |
(defn- used-mb
[]
(let [rt (Runtime/getRuntime)
mb (* 1024.0 1024.0)]
(/ (- (.totalMemory rt) (.freeMemory rt)) mb))) | |
Executes body-fn and logs memory usage before and after execution. Returns the result of body-fn. | (defn log-memory-usage
[body-fn context]
(binding [*memory-log-level* (inc *memory-log-level*)]
(let [indent (apply str (repeat *memory-log-level* " "))
before (used-mb)
print-stats (fn
([stats]
(log/infof "%s%s | Memory before:: %.2f MB "
indent context stats))
([before after]
(log/infof "%s%s | Memory after:: %.2f MB (delta: %.2f MB)"
indent context after (- after before))))
_ (print-stats before)
result (body-fn)
after (used-mb)
_ (print-stats before after)]
result))) |
Executes body and logs memory usage before and after execution. Returns the result of body. | (defmacro with-memory-logging [context & body] `(log-memory-usage (fn [] ~@body) ~context)) |
(comment ;; almost correct, at least a constant error (measuring-thread-allocations (byte-array (* 1024 1024)))) | |