From e9361072c190127910277d82587f4569b3a3be43 Mon Sep 17 00:00:00 2001 From: Christophe Grand Date: Wed, 14 Nov 2018 14:05:40 +0100 Subject: [PATCH] 0.19.0 add x/time --- README.md | 20 +++++++++++++++- project.clj | 8 +++---- src/net/cgrand/xforms.cljc | 49 +++++++++++++++++++++++++++++++++++++- 3 files changed, 71 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 4403b01..97185a8 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Aggregators generally only make sense in the context of a higher-order transduce In `net.cgrand.xforms`: * regular ones: `partition` (1 arg), `reductions`, `for`, `take-last`, `drop-last`, `sort`, `sort-by`, `wrap`, `window` and `window-by-time` - * higher-order ones: `by-key`, `into-by-key`, `multiplex`, `transjuxt`, `partition` (2+ args) + * higher-order ones: `by-key`, `into-by-key`, `multiplex`, `transjuxt`, `partition` (2+ args), `time` * aggregators: `reduce`, `into`, `without`, `transjuxt`, `last`, `count`, `avg`, `sd`, `min`, `minimum`, `max`, `maximum`, `str` In `net.cgrand.xforms.io`: @@ -228,6 +228,24 @@ Evaluation count : 24 in 6 samples of 4 calls. ## Changelog +### 0.19.0 + +`time` allows to measure time spent in one transducer (excluding time spent downstream). + +```clj +=> (time ; good old Clojure time + (count (into [] (comp + (x/time "mapinc" (map inc)) + (x/time "filterodd" (filter odd?))) (range 1e6)))) +filterodd: 61.771738 msecs +mapinc: 143.895317 msecs +"Elapsed time: 438.34291 msecs" +500000 +``` + +First argument can be a function that gets passed the time (in ms), +this allows for example to log time instead of printing it. + ### 0.9.5 * Short (up to 4) literal collections (or literal collections with `:unroll` metadata) in collection positions in `x/for` are unrolled. diff --git a/project.clj b/project.clj index 4baac99..2df450a 100644 --- a/project.clj +++ b/project.clj @@ -1,8 +1,8 @@ -(defproject net.cgrand/xforms "0.18.2" +(defproject net.cgrand/xforms "0.19.0" :description "Extra transducers for Clojure" :url "https://github.com/cgrand/xforms" :license {:name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html"} - :dependencies [[org.clojure/clojure "1.8.0"] - [org.clojure/clojurescript "1.9.293"] - [net.cgrand/macrovich "0.2.0"]]) + :dependencies [[org.clojure/clojure "1.8.0" :scope "provided"] + [org.clojure/clojurescript "1.9.293" :scope "provided"] + [net.cgrand/macrovich "0.2.0"]]) \ No newline at end of file diff --git a/src/net/cgrand/xforms.cljc b/src/net/cgrand/xforms.cljc index 6a1924e..3740693 100644 --- a/src/net/cgrand/xforms.cljc +++ b/src/net/cgrand/xforms.cljc @@ -5,7 +5,9 @@ [net.cgrand.macrovich :as macros] [net.cgrand.xforms :refer [for kvrf let-complete]]) :clj (:require [net.cgrand.macrovich :as macros])) - (:refer-clojure :exclude [some reduce reductions into count for partition str last keys vals min max drop-last take-last sort sort-by]) + (:refer-clojure :exclude [some reduce reductions into count for partition + str last keys vals min max drop-last take-last + sort sort-by time]) (:require [#?(:clj clojure.core :cljs cljs.core) :as core] [net.cgrand.xforms.rfs :as rf]) #?(:cljs (:import [goog.structs Queue]))) @@ -737,6 +739,51 @@ ([xforms-map coll] (transduce (transjuxt xforms-map) rf/last coll))) +(macros/replace + [#?(:cljs {(java.util.concurrent.atomic.AtomicLong.) (atom 0) + (System/nanoTime) (system-time) + (.addAndGet at (- t (System/nanoTime))) (swap! at + (- t (system-time))) + (.addAndGet at (- (System/nanoTime) t)) (swap! at + (- (system-time) t)) + .size .getCount})] + + (defn time + "Measures the time spent in this transformation and prints the measured time. + tag-or-f may be either a function of 1 argument (measured time in ms) in which case + this function will be called instead of printing, or tag-or-f will be print before the measured time." + ([xform] (time "Elapsed time" xform)) + ([tag-or-f xform] + (let [pt (if (fn? tag-or-f) + tag-or-f + #(println (core/str tag-or-f ": " % " msecs")))] + (fn [rf] + (let [at (java.util.concurrent.atomic.AtomicLong.) + rf + (fn + ([] (rf)) + ([acc] (let [t (System/nanoTime) + r (rf acc)] + (.addAndGet at (- t (System/nanoTime))) + r)) + ([acc x] + (let [t (System/nanoTime) + r (rf acc x)] + (.addAndGet at (- t (System/nanoTime))) + r))) + rf (xform rf)] + (fn + ([] (rf)) + ([acc] + (let [t (System/nanoTime) + r (rf acc) + total (.addAndGet at (- (System/nanoTime) t))] + (pt #?(:clj (* total 1e-6) :cljs total)) + r)) + ([acc x] + (let [t (System/nanoTime) + r (rf acc x)] + (.addAndGet at (- (System/nanoTime) t)) + r))))))))) + #_(defn rollup "Roll-up input data along the provided dimensions (which are functions of one input item), Values of interest are extracted from items using the valfn function and are then summarized