From 85570a5ec5342bc1bfa244a4b404c63f3ccdfd75 Mon Sep 17 00:00:00 2001 From: "alonso.torres" Date: Fri, 3 Oct 2025 10:37:40 +0200 Subject: [PATCH] WIP --- frontend/src/app/main/data/event.cljs | 85 +++++++++++++++++++ frontend/src/app/main/data/workspace.cljs | 20 +++-- .../src/app/main/data/workspace/viewport.cljs | 16 ++++ .../src/app/main/data/workspace/zoom.cljs | 25 ++++++ frontend/src/app/main/store.cljs | 39 ++++++++- frontend/src/app/util/debug.cljs | 2 +- frontend/src/app/util/http.cljs | 35 ++++++-- frontend/src/app/util/perf.cljs | 12 +++ 8 files changed, 216 insertions(+), 18 deletions(-) diff --git a/frontend/src/app/main/data/event.cljs b/frontend/src/app/main/data/event.cljs index 79cbde6d7e..7a5492c82e 100644 --- a/frontend/src/app/main/data/event.cljs +++ b/frontend/src/app/main/data/event.cljs @@ -10,8 +10,10 @@ [app.common.data :as d] [app.common.json :as json] [app.common.logging :as l] + [app.common.math :as math] [app.common.time :as ct] [app.config :as cf] + [app.main.refs :as refs] [app.main.repo :as rp] [app.util.globals :as g] [app.util.http :as http] @@ -183,10 +185,93 @@ (rx/of nil))) +(defn store-performace-info + [] + (letfn [(micro-benchmark [state] + (let [start (js/performance.now)] + (doseq [i (range 0 1e6)] + (* (math/sin i) (math/sqrt i))) + (let [end (js/performance.now)] + (assoc-in state [:performance-info :bench-result] (- end start))))) + + (count-shapes [file] + (if file + (->> file :data :pages-index vals + (map (comp count :objects)) + (reduce +)) + 0)) + + (count-library-data [files {:keys [id]}] + (let [data (get-in files [id :data])] + {:components (count (:components data)) + :colors (count (:colors data)) + :typographies (count (:typographies data))})) + + (save-file-data [] + (ptk/reify ::store-performance-info-save-file-data + ptk/UpdateEvent + (update [_ state] + (let [file-id (get state :current-file-id) + file (get-in state [:files file-id]) + file-size (count-shapes file) + + libraries + (-> (refs/select-libraries (:files state) (:id file)) + (update-vals (partial count-library-data (:files state)))) + + lib-sizes + (->> libraries + (vals) + (reduce (fn [acc {:keys [components colors typographies]}] + (-> acc + (update :components + components) + (update :colors + colors) + (update :typographies + typographies)))))] + (-> state + (assoc-in [:performance-info :file-size] file-size) + (assoc-in [:performance-info :library-sizes] lib-sizes) + (assoc-in [:performance-info :file-start-time] (js/performance.now)))))))] + + (ptk/reify ::store-performace-info + ptk/UpdateEvent + (update [_ state] + (-> state + micro-benchmark + (assoc-in [:performance-info :app-start-time] (js/performance.now)))) + + ptk/WatchEvent + (watch [_ _ stream] + (->> stream + (rx/filter #(= (ptk/type %) :app.main.data.workspace/all-libraries-resolved)) + (rx/take 1) + (rx/map save-file-data))) + + ptk/EffectEvent + (effect [_ _ _] + #_(let [observer + (js/PerformanceObserver. + (fn [list] + (doseq [entry (.getEntries list)] + (case (.-entryType entry) + "event" + (.log js/console "EVENT" (.-duration entry) (.-name entry)) + + "longtask" + (.log js/console "LONGTASK" (.-duration entry)) + + nil)) + + ))] + (.observe observer #js {:entryTypes #js ["event" "longtask"]})))))) + (defn initialize [] (when (contains? cf/flags :audit-log) (ptk/reify ::initialize + ptk/WatchEvent + (watch [_ _ _] + (rx/of (store-performace-info))) + ptk/EffectEvent (effect [_ _ stream] (let [session (atom nil) diff --git a/frontend/src/app/main/data/workspace.cljs b/frontend/src/app/main/data/workspace.cljs index 6dc1d9aa65..59df1bdc1e 100644 --- a/frontend/src/app/main/data/workspace.cljs +++ b/frontend/src/app/main/data/workspace.cljs @@ -187,6 +187,10 @@ (update [_ state] (update state :files assoc (:id library) library)))) +;; This events marks that all the libraries have been resolved +(def all-libraries-resolved + (ptk/reify ::all-libraries-resolved)) + (defn- fetch-libraries [file-id features] (ptk/reify ::fetch-libries @@ -198,13 +202,15 @@ (rx/concat (rx/of (dwl/libraries-fetched file-id libraries)) (rx/merge - (->> (rx/from libraries) - (rx/merge-map - (fn [{:keys [id synced-at]}] - (->> (rp/cmd! :get-file {:id id :features features}) - (rx/map #(assoc % :synced-at synced-at :library-of file-id))))) - (rx/mapcat resolve-file) - (rx/map library-resolved)) + (rx/concat + (->> (rx/from libraries) + (rx/merge-map + (fn [{:keys [id synced-at]}] + (->> (rp/cmd! :get-file {:id id :features features}) + (rx/map #(assoc % :synced-at synced-at :library-of file-id))))) + (rx/mapcat resolve-file) + (rx/map library-resolved)) + (rx/of all-libraries-resolved)) (->> (rx/from libraries) (rx/map :id) (rx/mapcat (fn [file-id] diff --git a/frontend/src/app/main/data/workspace/viewport.cljs b/frontend/src/app/main/data/workspace/viewport.cljs index d9f523003a..b06a963181 100644 --- a/frontend/src/app/main/data/workspace/viewport.cljs +++ b/frontend/src/app/main/data/workspace/viewport.cljs @@ -6,6 +6,7 @@ (ns app.main.data.workspace.viewport (:require + [app.util.timers :as ts] [app.common.data :as d] [app.common.data.macros :as dm] [app.common.files.helpers :as cfh] @@ -102,6 +103,17 @@ (update [_ state] (update state :workspace-local calculate-centered-viewbox position)))) +#_(defn measure-time-to-render [] + (let [start (js/performance.now)] + (ts/request-animation-frame + (fn [] + (js/scheduler.postTask + (fn [] + (let [end (js/performance.now)] + (println ">>" (- end start))) + ) + #js { "priority" "user-visible"}))))) + (defn update-viewport-position [{:keys [x y] :or {x identity y identity}}] @@ -113,6 +125,10 @@ (fn? y)) (ptk/reify ::update-viewport-position + ;;ptk/EffectEvent + ;;(effect [_ _ _] + ;; (measure-time-to-render)) + ptk/UpdateEvent (update [_ state] (update-in state [:workspace-local :vbox] diff --git a/frontend/src/app/main/data/workspace/zoom.cljs b/frontend/src/app/main/data/workspace/zoom.cljs index 843ea5f3f9..94fb269d46 100644 --- a/frontend/src/app/main/data/workspace/zoom.cljs +++ b/frontend/src/app/main/data/workspace/zoom.cljs @@ -6,6 +6,8 @@ (ns app.main.data.workspace.zoom (:require + [app.util.perf :as perf] + [app.util.timers :as ts] [app.common.data :as d] [app.common.data.macros :as dm] [app.common.files.helpers :as cfh] @@ -20,6 +22,17 @@ [beicon.v2.core :as rx] [potok.v2.core :as ptk])) +#_(defn measure-time-to-render [] + (let [start (js/performance.now)] + (ts/request-animation-frame + (fn [] + (js/scheduler.postTask + (fn [] + (let [end (js/performance.now)] + (println ">>" (- end start))) + ) + #js { "priority" "user-visible"}))))) + (defn impl-update-zoom [{:keys [vbox] :as local} center zoom] (let [new-zoom (if (fn? zoom) (zoom (:zoom local)) zoom) @@ -38,6 +51,10 @@ (increase-zoom ::auto)) ([center] (ptk/reify ::increase-zoom + ptk/EffectEvent + (effect [self _ _] + (perf/measure-time-to-render (ptk/type self))) + ptk/UpdateEvent (update [_ state] (let [center (if (= center ::auto) @ms/mouse-position center)] @@ -49,6 +66,10 @@ (decrease-zoom ::auto)) ([center] (ptk/reify ::decrease-zoom + ptk/EffectEvent + (effect [self _ _] + (perf/measure-time-to-render (ptk/type self))) + ptk/UpdateEvent (update [_ state] (let [center (if (= center ::auto) @ms/mouse-position center)] @@ -60,6 +81,10 @@ (set-zoom nil scale)) ([center scale] (ptk/reify ::set-zoom + ptk/EffectEvent + (effect [self _ _] + (perf/measure-time-to-render (ptk/type self))) + ptk/UpdateEvent (update [_ state] (let [vp (dm/get-in state [:workspace-local :vbox]) diff --git a/frontend/src/app/main/store.cljs b/frontend/src/app/main/store.cljs index 949e3b77e9..db4a43e706 100644 --- a/frontend/src/app/main/store.cljs +++ b/frontend/src/app/main/store.cljs @@ -6,6 +6,8 @@ (ns app.main.store (:require + [cuerdas.core :as str] + [app.util.timers :as ts] [app.common.logging :as log] [app.util.object :as obj] [app.util.timers :as tm] @@ -29,6 +31,36 @@ (def ^:dynamic *debug-events* false) + + + +(def current-measure (atom nil)) +(defn measure-time-to-render [event] + #_(if @current-measure + (swap! current-measure conj event) + + (let [start (js/performance.now)] + (reset! current-measure [event]) + + (ts/request-animation-frame + #(js/scheduler.postTask + (fn [] + (let [end (js/performance.now)] + (println + (str (- end start) "|" (str/join "," @current-measure)) )) + (reset! current-measure nil)) + + #js { "priority" "user-blocking"})))) + + + #_(let [start (js/performance.now)] + (ts/request-animation-frame + #(js/scheduler.postTask + (fn [] + (let [end (js/performance.now)] + (println (str "[" event "]" (- end start))))) + #js { "priority" "user-blocking"})))) + ;; Only created in development build (when *assert* (def debug-exclude-events @@ -38,6 +70,7 @@ :app.main.data.workspace.selection/change-hover-state}) (set! on-event (fn [e] + (when (and *debug-events* (ptk/event? e) (not (debug-exclude-events (ptk/type e)))) @@ -45,7 +78,11 @@ (defonce state (ptk/store {:resolve ptk/resolve - :on-event on-event + :on-event (fn [e] + (when (ptk/event? e) + (measure-time-to-render (ptk/type e))) + (on-event e)) + :on-error (fn [cause] (when cause #_(log/error :hint "unexpected exception on store" :cause cause) diff --git a/frontend/src/app/util/debug.cljs b/frontend/src/app/util/debug.cljs index d14f0793cf..2c8d9f6491 100644 --- a/frontend/src/app/util/debug.cljs +++ b/frontend/src/app/util/debug.cljs @@ -6,7 +6,7 @@ (ns app.util.debug) -(defonce state (atom #{#_:events})) +(defonce state (atom #{:events})) (def options #{;; Displays the bounding box for the shapes diff --git a/frontend/src/app/util/http.cljs b/frontend/src/app/util/http.cljs index aa7635c212..73ff0eebac 100644 --- a/frontend/src/app/util/http.cljs +++ b/frontend/src/app/util/http.cljs @@ -13,6 +13,7 @@ [app.config :as cfg] [app.util.cache :as c] [app.util.globals :as globals] + [app.util.perf :as perf] [app.util.webapi :as wapi] [beicon.v2.core :as rx] [cuerdas.core :as str] @@ -53,6 +54,10 @@ [] {"x-frontend-version" (:full cfg/version)}) +;; Storage to save the average time of the requests +(defonce network-averages + (atom {})) + (defn fetch [{:keys [method uri query headers body mode omit-default-headers credentials] :or {mode :cors @@ -87,17 +92,29 @@ :redirect "follow" :credentials credentials :referrerPolicy "no-referrer" - :signal signal}] + :signal signal} + + start (perf/timestamp)] (-> (js/fetch (str uri) params) - (p/then (fn [response] - (vreset! abortable? false) - (.next ^js subscriber response) - (.complete ^js subscriber))) - (p/catch (fn [err] - (vreset! abortable? false) - (when-not @unsubscribed? - (.error ^js subscriber err))))) + (p/then + (fn [response] + (vreset! abortable? false) + (.next ^js subscriber response) + (.complete ^js subscriber))) + (p/catch + (fn [err] + (vreset! abortable? false) + (when-not @unsubscribed? + (.error ^js subscriber err)))) + (p/finally + (fn [data] + (let [{:keys [count average] :or {count 0 average 0}} (get @network-averages (:path uri)) + current-time (- (perf/timestamp) start) + average (+ (* average (/ count (inc count))) + (/ current-time (inc count)) ) + count (inc count)] + (swap! network-averages assoc (:path uri) {:count count :average average}))))) (fn [] (vreset! unsubscribed? true) (when @abortable? diff --git a/frontend/src/app/util/perf.cljs b/frontend/src/app/util/perf.cljs index f958ba34f5..8e39b671ac 100644 --- a/frontend/src/app/util/perf.cljs +++ b/frontend/src/app/util/perf.cljs @@ -157,3 +157,15 @@ (let [p1 (now)] #(js/Math.floor (- (now) p1)))) +(defn measure-time-to-render [event] + (if (and (exists? js/globalThis) + (exists? (.-requestAnimationFrame js/globalThis)) + (exists? (.-scheduler js/globalThis)) + (exists? (.-postTask (.-scheduler js/globalThis)))) + (let [start (timestamp)] + (js/requestAnimationFrame + #(js/scheduler.postTask + (fn [] + (let [end (timestamp)] + (println (str "[" event "]" (- end start))))) + #js { "priority" "user-blocking"})))))