(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)))) | |