Skip to content

Instantly share code, notes, and snippets.

@ato
Created March 14, 2012 12:08
Show Gist options
  • Save ato/2036052 to your computer and use it in GitHub Desktop.
Save ato/2036052 to your computer and use it in GitHub Desktop.
Clojure startup time hack: refer
clojure.core/refer is relatively heavyweight. It gets called 7 times during Clojure
startup (4 times in 1.3.0). There's potential to shave off 10% of the startup time
by improving it. Probably even more for projects with a large number of small
namespaces.
This is just a quick experiment to see what's possible, it would need much refining.
It's not thread safe, doesn't print warnings and could probably be written more
elegantly.
java -Xbootclasspath/a:clojure.jar -cp clojure.jar clojure.main -e "(System/exit 0)"
master: 0.56 user 0.03 system 0:00.44 elapsed 136% CPU 189264k maxresident
patch: 0.42 user 0.03 system 0:00.38 elapsed 118% CPU 178000k maxresident
diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj
index e1aa2df..b747401 100644
--- a/src/clj/clojure/core.clj
+++ b/src/clj/clojure/core.clj
@@ -3743,6 +3743,11 @@
(= ns (.ns v))))
(ns-map ns))))
+(defn var-public? [ns ^clojure.lang.Var v]
+ (and (instance? clojure.lang.Var v)
+ (= ns (.ns v))
+ (.isPublic v)))
+
(defn refer
"refers to all public vars of ns, subject to filters.
filters can include at most one each of:
@@ -3759,7 +3764,22 @@
to a symbol different from the var's name, in order to prevent
clashes. Use :use in the ns macro in preference to calling this directly."
{:added "1.0"}
- [ns-sym & filters]
+ ;; quick and dirty hack at a fast path version
+ ;; beware: not thread safe and doesn't give var redefined
+ ;; warnings.
+ ([ns-sym]
+ (let [ns (find-ns ns-sym)
+ nsmap (ns-map ns)
+ m (loop [src (ns-map ns)
+ dst (transient (.getMappings *ns*))]
+ (if-let [entry (first src)]
+ (let [sym (key entry)
+ v (val entry)]
+ (recur (rest src) (if (var-public? ns v)
+ (assoc! dst sym v) dst)))
+ dst))]
+ (.setMappings *ns* (persistent! m))))
+ ([ns-sym & filters]
(let [ns (or (find-ns ns-sym) (throw (new Exception (str "No namespace: " ns-sym))))
fs (apply hash-map filters)
nspublics (ns-publics ns)
@@ -3776,7 +3796,7 @@
(if (get (ns-interns ns) sym)
(str sym " is not public")
(str sym " does not exist")))))
- (. *ns* (refer (or (rename sym) sym) v)))))))
+ (. *ns* (refer (or (rename sym) sym) v))))))))
(defn ns-refers
"Returns a map of the refer mappings for the namespace."
diff --git a/src/jvm/clojure/lang/Namespace.java b/src/jvm/clojure/lang/Namespace.java
index 0a4a38d..41aa2c6 100644
--- a/src/jvm/clojure/lang/Namespace.java
+++ b/src/jvm/clojure/lang/Namespace.java
@@ -192,6 +192,10 @@ public Object getMapping(Symbol name){
return mappings.get().valAt(name);
}
+public void setMappings(IPersistentMap map) {
+ mappings.set(map);
+}
+
public Var findInternedVar(Symbol symbol){
Object o = mappings.get().valAt(symbol);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment