Release 0.1.21

-----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2
 
 iQEcBAABCAAGBQJag/M5AAoJEICFZJYl4YS0oNMH/RMuxp7T/rXUyt/XMpamTvTw
 qadebtlPqwVCefQmOxCbVvJ1mGmoYm1wJaIsynq2RDpVUNtibELjbWg9TWq0BuV3
 aidOK2/VOGs18CRVJFXxYLrptCZdh78mPIelxT2g4/Y0F1ANccD208f57RBp1Xlf
 TB/AqXfeejesxUfdxu0yDndY+fDUwrwqQHKmHicAcyuL/+F03HyUmNR7VLw0G7QR
 7NCvJyUwwLfhUfUk6QLKW/BSy0WveXUh5zzB2mebIKJn516nOm2iMHAZIJ0XS0M9
 pBf8la9OEkDOEqiiUGFx3E4KvgQ0DuJrj0JKhsM/rtyuXu2h+KG89prsn3z0Wdg=
 =RROT
 -----END PGP SIGNATURE-----

Merge tag '0.1.21' into react-16

Release 0.1.21
This commit is contained in:
Daniel Compton 2018-02-14 22:00:12 +13:00
commit 6cb36a3990
14 changed files with 341 additions and 110 deletions

View File

@ -1,9 +1,31 @@
# Change Log
All notable changes to this project will be documented in this file. This change log follows the conventions of [keepachangelog.com](http://keepachangelog.com/).
## Unreleased
## [0.1.21] - Unreleased
## [0.1.18] - 2018-01-31
### Fixed
* Avoid throwing an error `No item 0 in vector of length 0` under certain circumstances.
## [0.1.20] - 2018-02-14
### Upgrade notes
To take advantage of the more granular timing info in this version, you will need to upgrade to re-frame 0.10.5.
### Added
* A time-travelling debugger. Navigating forwards and backwards through the event history updates app-db to match. Be careful when using this with a stateful backend; as in the movies if you change too much or go too far back, the future can become unpredictable.
### Improved
* Improve Timing panel to show more granular timing info.
### Fixed
* Settings panel has a scroll bar if your screen height is too small.
## [0.1.19] - 2018-02-09
### Changed
@ -18,6 +40,12 @@ All notable changes to this project will be documented in this file. This change
* Garden source dependencies are now working if you don't have your own dependency on Garden.
* New app-db path inspectors default to `"""` instead of `"[]"` so you can see the help text.
## [0.1.18] - 2018-01-31
### Fixed
* Garden source dependencies now work if you don't have your own dependency on Garden.
## [0.1.17] - 2018-01-31

View File

@ -1,6 +1,6 @@
# re-frame-trace
`re-frame-trace` let's you look at the inner workings of a running `re-frame` application. It presents as a programmer's dashboard, delivering curated insight and illumination. Your capacity to debug will increase because you know more.
`re-frame-trace` let's you inspect the inner workings of a running `re-frame` application. It presents as a programmer's dashboard, delivering curated insight and illumination. A 10x programmer is the one with 10x more knowledge and insight.
### It Is Epoch Oriented
@ -14,16 +14,14 @@ Each `re-frame` event and its consequent computation forms a bounded "epoch"
which can be inspected, analysed and understood independently of other epochs. This
tool is epoch-oriented - it shows you one at a time.
And, yes, it has "time travel debugger" capabilities - you can go backwards
and forwards through epochs - but that's really not the most interesting or powerful
aspect of what `re-frame-trace` delivers.
And, yes, it has "time travel debugger" capabilities - you can go
[backwards and forwards through epochs](https://condenaststore.com/featured/the-conga-line-of-past-selves-a-string-liana-finck.html) - but that's really not the most interesting or powerful aspect of what `re-frame-trace` delivers.
### It Is About Trace Data
As it runs, `re-frame` logs "trace" as data (not strings).
This data trace provides an x-ray of your app's functioning.
`re-frame-trace` is essentially a consumer, processor and displayer of this x-ray trace data.
As it runs, `re-frame` logs "trace" as data, and this provides an x-ray (MRI?) of your app's inner
functioning. At its most basic level, `re-frame-trace` is a consumer, processor and presenter
of trace data.
### It Is About The Data Flow
@ -33,12 +31,38 @@ strongly defined by its "data oriented" design. `re-frame`
To understand what is happening in a `re-frame` app, you must understand
what data is "happening".
So, data is at the core of `re-frame-trace` in both of the ways just described,
and data is a powerful and leverageable substrate.
### It Is Always About The Data
So, clearly, data is at the core of `re-frame-trace` for both of the reasons
just outlined, but its importance is even more base and fundamental than that.
Each time you put a `println` into your program, you are printing out what?
And why? Invariably, it is data which fuels your debugging investigation,
confirming your current hypothesis, or not.
And when you write your unittests, you represent your expections as what? Correct
data is the very definition of success.
So, for debugging and understanding activities, more data, more easily is winning. Going back
and adding a `println` shouldn't be necessary. All the data you need should already
be captured, and it should be readily available in your REPL for further experimentation.
### Data Brings Code To Life
Perhaps you have seen LightTable in action?
In the small, it is a delightfully productive debugging environment because it co-renders
code and the data generated by running the code. The data provides a "paper trail" which
brings the code to life, revealing its dynamics and enriching
a programmer's understanding.
`re-frame-trace` has a similar goal, although the method is different.
### It Is A Data Dashboard
Except, there's often too much data - you can drown in the detail.
Observing raw data trace is both interesting and valuable, but it isn't enough.
First, we want to leverage this data for insights. And, second, there's often too much data - you
can drown in the detail.
So, `re-frame-trace` tries to be a "dashboard" which curates this
"raw data" into "information" through various kinds of analysis
@ -66,14 +90,25 @@ Four ways:
4. It helps you to find performance problems and/or detect where there is
unnecessary computation occurring.
Deeper knowledge is the goal. Easier debugging is the symptom.
Point 3, is primary, of course. But Point 2 is almost as important because we all spend a
lot of our time groking unfamiliar codebases. Being able to observe the inner
workings of a running app is a great way to bring code to life, reveal key
features, and build a cognative map of how the code is structured.
### Temporary Warning
> Some of the claims above are aspirational. `re-frame-trace` remains a WIP experiment. But we're getting there.
> Some of the claims above are aspirational. `re-frame-trace` [remains a WIP](https://github.com/Day8/re-frame-trace/issues/118).
## Sausage
We debated internally about the name `re-frame-trace`. While `-trace` is accurate, it is 100% sausage because it talks about low level function, and not higher level benefit (sizzle, sizzle). I wanted to call it `vox-datum` (voice of the data) but that was cruelly rejected, for reasons I don't care to remember. The pain. I mean, who the hell doesn't like a Latin name?? Philistines. Anyway, `-insight` and `-illumination` are the benefits, but they made the name waaaay too long. Naming things - it's just a nightmare! As is inertia. So, `-trace` it remains.
**Update:** a name change to `re-frame-10x` is on the cards. Disapointingly, my latest suggestion, `TenMinutesByTractor`, was also rejected. I shake my head. Why can noone see that we're all "code farmers" by profession?
## A Visual Sampler
Slightly out of date, but indicative ...
<img src="docs/images/re-frame-trace-demo.gif" height="500px">
## Installation
@ -82,7 +117,7 @@ If you are using leiningen, modify `project.clj` in the following ways. When puz
[![Clojars Project](https://img.shields.io/clojars/v/day8.re-frame/trace.svg)](https://clojars.org/day8.re-frame/trace)
- Update your re-frame dependency to at least `0.10.4` - `[re-frame "0.10.4"]`.
- Update your re-frame dependency to at least `0.10.5` - `[re-frame "0.10.5"]`.
- Add re-frame-trace as a dev dependency by placing `[day8.re-frame/trace "VERSION"]` within `:profiles :dev :dependencies`. For example:

View File

@ -1,16 +1,15 @@
# Inter Epoch Traces
# Intra Epoch Traces
> "Music is the space between the notes." - Claude Debussy
re-frame-trace is built around the idea of epochs. An epoch captures all of the traces that are emitted by re-frame after handling an event. But what about the traces that are emitted when re-frame *isn't* handling an event? These are the inter-epoch traces.
`re-frame-trace` is built around the idea of epochs. An epoch captures all of the trace emitted by re-frame during the handling an event. But what about the trace emitted when re-frame *isn't* handling an event? These are the intra-epoch traces.
Inter-epoch traces are emitted under (at least) four circumstances:
Intra-epoch traces are emitted under (at least) three circumstances:
* Mouse hover state causing subscriptions to run/re-run
* Click/input events sent to local ratoms (rather than as events to app-db)
* Figwheel disposing old subscriptions and re-rendering your application
* Resetting app-db in re-frame-trace
* Views sometimes have local state in the form of local ratoms which control, for example, the appearance of popups or mouseover annimations. When the state of these ratoms change, dependent views will likely rerender, and the trace to do with this rerendering will flow from reagent to `re-frame-trace`. But there'll be no "current" epoch to put it in. Because there was no event (just a pseudo event caused by the ratom reset)
* A Figwheel recompile and subsequent code reload will cause all existing subscriptions to be destroyed, andwill trigger a complete re-render of your application. Again, a flood of trace to do with subscriptions and views will arrive but have no epoch home.
* `re-frame-trace` itself resetting the value in `app-db`. Once again, there will be a flurry of subscription and view trace, but no epoch, because there was no event.
The first two of these are essential to your application, the latter two are incidental to the tooling.
The first of these is essential to the functioning of your application, which probably makes the trace interesting and informative. The last two are incidental to the tooling and are probably best ignored. Probably.
re-frame-trace collects any inter-epoch subscription traces and shows them in the subs panel with the next epoch. They are broken out into a separate section marked: "Inter-Epoch Subscriptions".
`re-frame-trace` collects any intra-epoch subscription traces and shows them in the subs panel with the next epoch. They are broken out into a separate section marked: "Intra-Epoch Subscriptions".

View File

@ -1,4 +1,4 @@
(defproject day8.re-frame/trace "0.1.19-react16"
(defproject day8.re-frame/trace "0.1.21-react16"
:description "Tracing and developer tools for re-frame apps"
:url "https://github.com/Day8/re-frame-trace"
:license {:name "MIT"}

View File

@ -19,6 +19,7 @@
{id1 {:id id1 :ns-str "re-com.box" :ns 're-com.box :sort 0}
id2 {:id id2 :ns-str "re-com.input-text" :ns 're-com.input-text :sort 1}}))
num-epochs (localstorage/get "retained-epochs" 5)
follows-events? (localstorage/get "app-db-follows-events?" true)
categories (localstorage/get "categories" #{:event :sub/run :sub/create :sub/dispose})]
(when using-trace?
(rf/dispatch [:global/enable-tracing]))
@ -29,6 +30,7 @@
(rf/dispatch [:settings/set-filtered-view-trace filtered-view-trace])
(rf/dispatch [:settings/set-low-level-trace low-level-trace])
(rf/dispatch [:settings/set-number-of-retained-epochs num-epochs])
(rf/dispatch [:settings/app-db-follows-events? follows-events?])
(rf/dispatch [:settings/debug? debug?])
(when external-window?
(rf/dispatch [:global/launch-external]))

View File

@ -112,13 +112,14 @@
(fn [db _]
(assoc-in db [:settings :paused?] true)))
(rf/reg-event-db
(rf/reg-event-fx
:settings/play
(fn [db _]
(-> db
(fn [{db :db} _]
{:db (-> db
(assoc-in [:settings :paused?] false)
(assoc-in [:epochs :current-epoch-index] nil)
(assoc-in [:epochs :current-epoch-id] nil))))
(assoc-in [:epochs :current-epoch-id] nil))
:dispatch [:snapshot/reset-current-epoch-app-db nil]}))
(rf/reg-event-db
:settings/set-number-of-retained-epochs
@ -218,6 +219,12 @@
(fn [db [_ debug?]]
(assoc-in db [:settings :debug?] debug?)))
(rf/reg-event-db
:settings/app-db-follows-events?
[(rf/path [:settings :app-db-follows-events?]) (fixed-after #(localstorage/save! "app-db-follows-events?" %))]
(fn [db [_ follows-events?]]
follows-events?))
;; Global
(defn mount [popup-window popup-document]
@ -505,6 +512,22 @@
(reset! re-frame.db/app-db new-db)
db))
(rf/reg-event-db
:snapshot/reset-current-epoch-app-db
(fn [db [_ new-id]]
(let [follows-events? (get-in db [:settings :app-db-follows-events?])
epochs (:epochs db)
match-id (or new-id
;; new-id may be nil when we call this event from :settings/play
(utils/last-in-vec (get epochs :match-ids)))
match (get-in epochs [:matches-by-id match-id])
event (metam/matched-event (:match-info match))]
(when follows-events?
;; Don't mess up the users app if there is a problem getting app-db-after.
(when-some [new-db (get-in event [:tags :app-db-after])]
(reset! re-frame.db/app-db new-db))))
db))
;;;
(defn first-match-id
@ -543,15 +566,21 @@
new-sub-state (last subscription-match-state)
timing (mapv (fn [match]
;; TODO: this isn't quite correct, shouldn't be using filtered-traces here
(let [epoch-traces (into []
(comp
(utils/id-between-xf (:id (first match)) (:id (last match))))
filtered-traces)
all-traces)
start-of-epoch (nth epoch-traces 0)
;; TODO: optimise trace searching
event-handler-trace (first (filter metam/event-handler? epoch-traces))
dofx-trace (first (filter metam/event-dofx? epoch-traces))
event-trace (first (filter metam/event-run? epoch-traces))
finish-run (or (first (filter metam/finish-run? epoch-traces))
(utils/last-in-vec epoch-traces))]
{:re-frame/event-time (metam/elapsed-time start-of-epoch finish-run)}))
{:re-frame/event-run-time (metam/elapsed-time start-of-epoch finish-run)
:re-frame/event-time (:duration event-trace)
:re-frame/event-handler-time (:duration event-handler-trace)
:re-frame/event-dofx-time (:duration dofx-trace)}))
new-matches)
new-matches (map (fn [match sub-match t] {:match-info match
@ -587,9 +616,11 @@
match-array-index (utils/find-index-in-vec (fn [x] (= current-id x)) match-ids)
new-id (nth match-ids (dec match-array-index))]
{:db (assoc db :current-epoch-id new-id)
:dispatch [:settings/pause]})
{:db (assoc db :current-epoch-id (nth (:match-ids db) (- (count (:match-ids db)) 2)))
:dispatch [:settings/pause]})))
:dispatch-n [[:settings/pause] [:snapshot/reset-current-epoch-app-db new-id]]})
(let [new-id (nth (:match-ids db)
(- (count (:match-ids db)) 2))]
{:db (assoc db :current-epoch-id new-id )
:dispatch-n [[:settings/pause] [:snapshot/reset-current-epoch-app-db new-id]]}))))
(rf/reg-event-fx
:epochs/next-epoch
@ -600,9 +631,10 @@
match-array-index (utils/find-index-in-vec (fn [x] (= current-id x)) match-ids)
new-id (nth match-ids (inc match-array-index))]
{:db (assoc db :current-epoch-id new-id)
:dispatch [:settings/pause]})
{:db (assoc db :current-epoch-id (last (:match-ids db)))
:dispatch [:settings/pause]})))
:dispatch-n [[:settings/pause] [:snapshot/reset-current-epoch-app-db new-id]]})
(let [new-id (last (:match-ids db))]
{:db (assoc db :current-epoch-id new-id)
:dispatch-n [[:settings/pause] [:snapshot/reset-current-epoch-app-db new-id]]}))))
(rf/reg-event-db
:epochs/reset

View File

@ -73,8 +73,7 @@
(let [start-of-epoch (:start ev1)
end-of-epoch (:end ev2)]
(when (and (some? start-of-epoch) (some? end-of-epoch))
#?(:cljs (js/Math.round (- end-of-epoch start-of-epoch))
:clj (Math/round ^double (- end-of-epoch start-of-epoch))))))
(- end-of-epoch start-of-epoch))))
(defn run-queue? [event]
(and (fsm-trigger? event)
@ -131,6 +130,7 @@
(defn subscription? [trace]
(and (= "sub" (namespace (:op-type trace)))
;; TODO: should we remove cached checks?
(not (get-in trace [:tags :cached?]))))
(defn subscription-created? [trace]
@ -167,7 +167,9 @@
(= 2 (get sub :layer))))
(defn finish-run? [event]
(defn finish-run?
"Marks the end of event processing running."
[event]
(and (fsm-trigger? event)
(= (:operation event)
[:running :finish-run])))
@ -175,6 +177,12 @@
(defn event-run? [event]
(= :event (:op-type event)))
(defn event-handler? [trace]
(= :event/handler (:op-type trace)))
(defn event-dofx? [trace]
(= :event/do-fx (:op-type trace)))
(defn start-of-epoch?
"Detects the start of a re-frame epoch

View File

@ -68,6 +68,12 @@
(fn [settings]
(:debug? settings)))
(rf/reg-sub
:settings/app-db-follows-events?
:<- [:settings/root]
(fn [settings]
(:app-db-follows-events? settings)))
;; App DB
(rf/reg-sub
@ -332,19 +338,60 @@
(fn [frame-traces]
(count (filter metam/request-animation-frame? frame-traces))))
(defn ^number +nil
"Returns the sum of nums. (+) returns nil (not 0 like in cljs.core)."
([] nil)
([x] x)
([x y] (cljs.core/+ x y))
([x y & more]
(reduce + (cljs.core/+ x y) more)))
(rf/reg-sub
:timing/animation-frame-time
:<- [:timing/animation-frame-traces]
(fn [frame-traces [_ frame-number]]
(let [frames (partition 2 frame-traces)
[start end] (first (drop (dec frame-number) frames))]
(metam/elapsed-time start end))))
:<- [:traces/current-event-traces]
(fn [[af-start-end epoch-traces] [_ frame-number]]
(let [frame-pairs (partition 2 af-start-end)
[start end] (nth frame-pairs (dec frame-number))
af-traces (into [] (metam/id-between-xf (:id start) (:id end)) epoch-traces)
total-time (metam/elapsed-time start end)
;; TODO: these times double count renders/subs that happened as a child of another
;; need to fix either here, at ingestion point, or most preferably in re-frame at tracing point.
subs-time (transduce (comp
(filter metam/subscription?)
(map :duration))
+nil af-traces)
render-time (transduce (comp
(filter metam/render?)
(map :duration))
+nil af-traces)]
{:timing/animation-frame-total total-time
:timing/animation-frame-subs subs-time
:timing/animation-frame-render render-time
;; TODO: handle rounding weirdness here, make sure it is never below 0.
:timing/animation-frame-misc (- total-time subs-time render-time)})))
(rf/reg-sub
:timing/event-processing-time
:<- [:epochs/current-match-state]
(fn [match]
(get-in match [:timing :re-frame/event-time])))
(let [{:re-frame/keys [event-time event-handler-time event-dofx-time event-run-time]} (get match :timing)
;; The scope of tracing is:
;; event-run-time
;; event-time
;; event-handler-time
;; event-dofx-time
;; <other stuff>
;; <other stuff>
remaining-interceptors (- event-time event-handler-time event-dofx-time)]
{:timing/event-total event-run-time
:timing/event-handler event-handler-time
:timing/event-effects event-dofx-time
:timing/event-interceptors remaining-interceptors
;; TODO: look at splitting out interceptors from misc, there was a suspiciously high amount of time
;; in misc on some events, so that needs to be investigated.
; :timing/event-misc (- event-run-time event-time)
:timing/event-misc (- event-run-time event-handler-time event-dofx-time)})))
(rf/reg-sub
:timing/render-time

View File

@ -0,0 +1,9 @@
(ns day8.re-frame.trace.view.code
(:require [day8.re-frame.trace.utils.re-com :as rc]
[mranderson047.re-frame.v0v10v2.re-frame.core :as rf]))
(defn render []
(let [code-traces (rf/subscribe [:epochs/current-code-traces])])
[rc/v-box
:children
[[:h1 "Code"]]])

View File

@ -7,6 +7,8 @@
[day8.re-frame.trace.view.subs :as subs]
[day8.re-frame.trace.view.views :as views]
[day8.re-frame.trace.view.traces :as traces]
[day8.re-frame.trace.view.code :as code]
[day8.re-frame.trace.view.parts :as parts]
[day8.re-frame.trace.view.timing :as timing]
[day8.re-frame.trace.view.debug :as debug]
[day8.re-frame.trace.view.settings :as settings]
@ -85,7 +87,10 @@
(defn standard-header [external-window?]
(let [current-event @(rf/subscribe [:epochs/current-event])
older-epochs-available? @(rf/subscribe [:epochs/older-epochs-available?])
newer-epochs-available? @(rf/subscribe [:epochs/newer-epochs-available?])]
newer-epochs-available? @(rf/subscribe [:epochs/newer-epochs-available?])
event-str (if (some? current-event)
(subs (prn-str current-event) 0 400)
"No event")]
[[rc/h-box
:align :center
:size "auto"
@ -98,8 +103,9 @@
:style {:max-height "42px" ;42 is exactly 2 lines which is perhaps neater than common/gs-50s (which would allow 3 lines to be seen)
:overflow-x "hidden"
:overflow-y "auto"
:background-color "white"}
:children [[:span.event-header (subs (prn-str current-event) 0 400)]]]
:background-color "white"
:font-style (if (some? current-event) "normal" "italic")}
:children [[:span.event-header event-str]]]
[:span.arrow (if newer-epochs-available?
{:on-click #(rf/dispatch [:epochs/next-epoch])}
{:class "arrow__disabled"})
@ -136,6 +142,10 @@
:children [(tab-button :event "Event")
(tab-button :app-db "app-db")
(tab-button :subs "Subs")
(when (:debug? opts)
(tab-button :code "Code"))
(when (:debug? opts)
(tab-button :parts "Parts"))
;(tab-button :views "Views")
(tab-button :traces "Trace")
(tab-button :timing "Timing")
@ -149,7 +159,7 @@
[rc/v-box
:size "auto"
:style {:margin-left common/gs-19s
:overflow-y (if (contains? #{:timing :debug :event :subs} @selected-tab)
:overflow-y (if (contains? #{:timing :debug :event :subs :settings :code :parts} @selected-tab)
"auto" "initial")
;:overflow "auto" ;; TODO: Might have to put this back or add scrolling within the panels
}
@ -158,8 +168,10 @@
:app-db [app-db/render db/app-db]
:subs [subs/render]
:views [views/render]
:traces [traces/render]
:code [code/render]
:parts [parts/render]
:timing [timing/render]
:traces [traces/render]
:debug [debug/render]
:settings [settings/render]
[app-db/render db/app-db])]]]))

View File

@ -0,0 +1,31 @@
(ns day8.re-frame.trace.view.parts
(:require [day8.re-frame.trace.utils.re-com :as rc]
[re-frame.registrar]
[re-frame.events]))
(defn render-registered [kind]
(for [[k v] (sort-by key (get @re-frame.registrar/kind->id->handler kind))]
^{:key (str kind "|" k)}
[:pre {:style {:border "1px black solid"
:padding "10px"
:margin-right "10px"}} (prn-str k)]))
(defn render-subs [kind]
(for [[k v] (sort-by key (get @re-frame.registrar/kind->id->handler kind))]
^{:key (str kind "|" k)}
[:pre {:style {:border "1px black solid"
:padding "10px"
:margin-right "10px"}}
(prn-str k)]))
(defn render []
[rc/v-box
:children [[:h1 "Events"]
(render-registered re-frame.events/kind)
[:h1 "Subscriptions"]
(render-subs re-frame.subs/kind)
[:h1 "FX"]
(render-registered re-frame.fx/kind)
[:h1 "co-fx"]
(render-registered re-frame.cofx/kind)
]])

View File

@ -92,6 +92,16 @@
[[:p num-epochs " epochs currently retained, involving " num-traces " traces."]]
settings-box-81])
[rc/line]
(let [follows-events? @(rf/subscribe [:settings/app-db-follows-events?])]
[settings-box
[[rc/checkbox
:model follows-events?
:label "sync app-db with epoch navigation"
:on-change #(rf/dispatch [:settings/app-db-follows-events? %])]]
[[:p "When you navigate to an epoch, update app-db to match. Causes UI to \"time travel\"."]]
settings-box-81])
[rc/line]
[settings-box
[[rc/h-box

View File

@ -9,9 +9,7 @@
(def timing-styles
[:#--re-frame-trace--
[:.timing-details
{:background-color common/white-background-color
:margin-top common/gs-31s
:padding common/gs-19}]
{:margin-top common/gs-31s}]
[:.timing-details--line
{:margin "1em 0"}]
@ -26,8 +24,12 @@
{:background-color common/disabled-background-color
:border (str "1px solid " common/border-line-color)
:font-weight "normal"
:font-size "14px"}]
:font-size "14px"
:width "63px"}]
[".timing-elapsed-panel"
{:padding "12px 12px 12px 0"
:margin common/gs-7s}]
[".timing-part-panel"
(merge (common/panel-style "3px")
{:padding "12px"
@ -42,25 +44,56 @@
[rc/v-box
:align :center
:gap "3px"
;; TODO: detect <1 ms timing here, to distinguish between none at all, and rounding to 0.
:children [[rc/label :class "bm-textbox-label" :label label]
[timing-tag (str time "ms")]]])
[timing-tag (cond
(nil? time) "-"
(= time 0) (str "0ms")
(< time 0.1) (str "<0.1ms")
(< time 1) (str (.toFixed time 1) "ms")
(some? time) (str (js/Math.round time) "ms")
)]]])
(defn render []
(let [timing-data-available? @(rf/subscribe [:timing/data-available?])]
(let [timing-data-available? @(rf/subscribe [:timing/data-available?])
event-processing-time @(rf/subscribe [:timing/event-processing-time])]
(if timing-data-available?
[rc/v-box
:class "timing-details"
:children [
:children [[rc/h-box
:class "timing-elapsed-panel"
:align :end
:children [[timing-section "elapsed" @(rf/subscribe [:timing/total-epoch-time])]
[rc/hyperlink-href
:label "guide me to greatness"
:style {:margin-left common/gs-19s}
:attr {:rel "noopener noreferrer"}
:target "_blank"
:href "https://github.com/Day8/re-frame-trace/blob/master/docs/HyperlinkedInformation/UnderstandingTiming.md"]]]
[rc/h-box
:gap common/gs-12s
:class "timing-part-panel"
:align :center
:children
[[timing-section "total" @(rf/subscribe [:timing/total-epoch-time])]
[timing-section "event" @(rf/subscribe [:timing/event-processing-time])]
[[rc/v-box
:align :center
:width common/gs-81s
:children [[:span "event"] [:span "processing"]]]
[timing-section "total" (:timing/event-total event-processing-time)]
[:span "="]
[timing-section "handler" (:timing/event-handler event-processing-time)]
[:span "+"]
[timing-section "effects" (:timing/event-effects event-processing-time)]
#_[:span "+"]
#_[timing-section "other int." (:timing/event-interceptors event-processing-time)]
[:span "+"]
[timing-section "misc" (:timing/event-misc event-processing-time)]
]]
(doall
(for [frame (range 1 (inc @(rf/subscribe [:timing/animation-frame-count])))
:let [frame-time (rf/subscribe [:timing/animation-frame-time frame])]]
:let [frame-time @(rf/subscribe [:timing/animation-frame-time frame])]]
(list
;^{:key (str "af-line" frame)}
;[rc/line :class "timing-details--line"]
@ -68,27 +101,19 @@
[rc/h-box
:align :center
:class "timing-part-panel"
:gap "25px"
:gap common/gs-12s
:children
[[rc/label :label (str "Animation frame #" frame)]
[timing-section "total" @frame-time]
#_[timing-section "subs" 2]
#_[timing-section "views" 3]]])))
[rc/line :class "timing-details--line"]
[rc/v-box
:children
[[rc/p "Be careful. There are two problems with these numbers:"]
[:ol
[:li "Accurately timing anything in the browser is a nightmare. One moment a given function takes 1ms and the next it takes 10ms, and you'll never know why. So bouncy."]
[:li "You're currently running the dev build, not the production build. So don't freak out too much. Yet."]]
[rc/hyperlink-href
:label "Timing documentation"
:style {:margin-left common/gs-7s}
:attr {:rel "noopener noreferrer"}
:target "_blank"
:href "https://github.com/Day8/re-frame-trace/blob/master/docs/HyperlinkedInformation/UnderstandingTiming.md"]]]]]
[[rc/v-box
:align :center
:width common/gs-81s
:children [[:span "animation"] [:span "frame"] [:span "#" frame]]]
[timing-section "total" (:timing/animation-frame-total frame-time)]
[:span "="]
[timing-section "subs" (:timing/animation-frame-subs frame-time)]
[:span "+"]
[timing-section "views" (:timing/animation-frame-render frame-time)]
[:span "+"]
[timing-section "react, etc" (:timing/animation-frame-misc frame-time)]]])))]]
[rc/v-box
:class "timing-details"
:children [[:h1 "No timing data available currently."]]])))

View File

@ -163,14 +163,7 @@
(if (:show-all? @trace-detail-expansions) "-" "+")]]
[:th "operations"]
[:th
[:button {:class (str/join " " ["filter-items-count"
(when (pos? (count @filter-items)) "active")])
:on-click #(rf/dispatch [:traces/reset-filter-items])}
(when (pos? (count @filter-items))
(str (count visible-traces) " of "))
(str (count @current-traces))]
" traces "
(when (pos? (count @current-traces))
[:span "(" [:button.text-button {:on-click #(rf/dispatch [:epochs/reset])} "clear"] ")"])]
(str (count visible-traces) " traces")
[:span "(" [:button.text-button {:on-click #(rf/dispatch [:epochs/reset])} "clear"] ")"]]
[:th {:style {:text-align "right"}} "meta"]]
[:tbody (render-traces visible-traces filter-items filter-input trace-detail-expansions)]]]]))))