Skip to content

Commit

Permalink
sampling-profiler: initial commit
Browse files Browse the repository at this point in the history
klauswuestefeld committed Nov 5, 2024
1 parent 75d2033 commit 834395d
Showing 3 changed files with 75 additions and 0 deletions.
3 changes: 3 additions & 0 deletions tools/sampling-profiler/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# sampling-profiler

A lightweight profiler that samples Thread/allStackTraces and allows you to filter relevant stack frames.
13 changes: 13 additions & 0 deletions tools/sampling-profiler/project.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
(defproject house.jux/tools.sampling-profiler "2024.11.05-SNAPSHOT"

:description "A lightweight profiler that samples Thread/allStackTraces and allows you to filter relevant stack frames."
:url "https://github.com/klauswuestefeld/simple-clj/tree/master/tools/sampling-profiler"

:license {:name "BSD 3-Clause"
:url "https://github.com/klauswuestefeld/simple-clj/blob/master/LICENSE"}

:dependencies []

:plugins [[lein-parent "0.3.9"]]
:parent-project {:coords [house.jux/parent-project "2024.06.10"]
:inherit [:deploy-repositories :dependencies]})
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
(ns house.jux--.tools.sampling-profiler--
#_(:require [clojure.pprint :refer [pprint]]))

(def summary (atom nil))
(def running (atom false))
(defn stop! []
(reset! running false))

(defn- tally-classes [summary stack]
(->> (seq stack)
(remove nil?)
(map #(.getClassName %))
(reduce (fn [summary class-name]
(update-in summary [:class->count class-name] (fnil inc 0)))
summary)))

(defn- summarize [summary thread->stack]
(as-> summary _
(update _ :sample-count inc)
(reduce tally-classes _ (vals thread->stack))))

(defn- summarize-samples! [{:keys [duration-sec interval-ms]}]
(let [end-time (+ (System/currentTimeMillis) (* 1000 duration-sec))]
(println "before loop")
(loop []
(println "looping")
(Thread/sleep interval-ms)
(swap! summary summarize (Thread/getAllStackTraces))
(if (and @running
(< (System/currentTimeMillis) end-time))
(recur)
(println "Profiling done.")))))

(defn start! [options]
(when @running
(throw (IllegalStateException. "Profiler was already running.")))
(reset! summary {:sample-count 0})
(reset! running true)
(println "before future")
(future
(println "in future")
(try
(println "before summarize")

(summarize-samples! options)
(catch Exception e
(.printStackTrace e)))))


(comment
; This will sample all thread stack frames every 20 milliseconds for a duration of 10 seconds. Useful for when the code being profiled hangs.
(start! {:interval-ms 20
:duration-sec 10})

; Run the code you want to profile...

(stop!) ; Stops profiling.
@summary ; Contains the summary at any moment.
)

0 comments on commit 834395d

Please sign in to comment.