summary refs log tree commit diff
path: root/src/libexpr
diff options
context:
space:
mode:
authorEelco Dolstra <e.dolstra@tudelft.nl>2011-08-06 19:45:43 +0000
committerEelco Dolstra <e.dolstra@tudelft.nl>2011-08-06 19:45:43 +0000
commit2d663b502da16d6dc480bff7f58297d176d04246 (patch)
tree110fdbb8a5347f1a544ab994711173fa569f733f /src/libexpr
parent510033e78376987ca358cebfa020754e61733543 (diff)
downloadguix-2d663b502da16d6dc480bff7f58297d176d04246.tar.gz
* Cache the result of file evaluation (i.e, memoize evalFile()). This
  prevents files from being evaluated and stored as values multiple
  times.  For instance, evaluation of the ‘system’ attribute in NixOS
  causes ‘nixpkgs/pkgs/lib/lists.nix’ to be evaluated 2019 times.

  Caching gives a modest speedup and a decent memory footprint
  reduction (e.g., from 1.44s to 1.28s, and from 81 MiB to 59 MiB with
  GC_INITIAL_HEAP_SIZE=100000 on my system).

Diffstat (limited to 'src/libexpr')
-rw-r--r--src/libexpr/eval.cc24
-rw-r--r--src/libexpr/eval.hh9
2 files changed, 22 insertions, 11 deletions
diff --git a/src/libexpr/eval.cc b/src/libexpr/eval.cc
index 5aee3f05ea..d0bdaf2382 100644
--- a/src/libexpr/eval.cc
+++ b/src/libexpr/eval.cc
@@ -431,17 +431,19 @@ Value * EvalState::maybeThunk(Env & env, Expr * expr)
 
 void EvalState::evalFile(const Path & path, Value & v)
 {
-    startNest(nest, lvlTalkative, format("evaluating file `%1%'") % path);
-
-    Expr * e = parseExprFromFile(path);
-    
-    try {
-        /* !!! Maybe we should cache the evaluation result. */
-        eval(e, v);
-    } catch (Error & e) {
-        addErrorPrefix(e, "while evaluating the file `%1%':\n", path);
-        throw;
-    }
+    FileEvalCache::iterator i = fileEvalCache.find(path);
+    if (i == fileEvalCache.end()) {
+        startNest(nest, lvlTalkative, format("evaluating file `%1%'") % path);
+        Expr * e = parseExprFromFile(path);
+        try {
+            eval(e, v);
+        } catch (Error & e) {
+            addErrorPrefix(e, "while evaluating the file `%1%':\n", path);
+            throw;
+        }
+        fileEvalCache[path] = v;
+    } else
+        v = i->second;
 }
 
 
diff --git a/src/libexpr/eval.hh b/src/libexpr/eval.hh
index 413234f2bf..694d4407b8 100644
--- a/src/libexpr/eval.hh
+++ b/src/libexpr/eval.hh
@@ -211,8 +211,17 @@ private:
 
     bool allowUnsafeEquality;
 
+    /* A cache from path names to parse trees. */
     std::map<Path, Expr *> parseTrees;
 
+    /* A cache from path names to values. */
+#if HAVE_BOEHMGC
+    typedef std::map<Path, Value, std::less<Path>, gc_allocator<std::pair<const Path, Value> > > FileEvalCache;
+#else
+    typedef std::map<Path, Value> FileEvalCache;
+#endif
+    FileEvalCache fileEvalCache;
+
     typedef list<std::pair<string, Path> > SearchPath;
     SearchPath searchPath;
     SearchPath::iterator searchPathInsertionPoint;