Title: [143759] trunk/Source/_javascript_Core
Revision
143759
Author
[email protected]
Date
2013-02-22 11:16:03 -0800 (Fri, 22 Feb 2013)

Log Message

Code cache size should adapt to workload
https://bugs.webkit.org/show_bug.cgi?id=110560

Reviewed by Antti Koivisto.

(*) 5% PLT arithmetic mean speedup
(*) 10% PLT geometric mean speedup
(*) 3.4X microbenchmark speedup
(*) Reduces initial cache capacity by 16X

* runtime/CodeCache.cpp:
(JSC::CodeCache::CodeCache): Updated for interface change.

* runtime/CodeCache.h:
(JSC::SourceCodeValue::SourceCodeValue):
(SourceCodeValue): Turned the cache value into a struct so it can track its age.

(CodeCacheMap):
(JSC::CodeCacheMap::CodeCacheMap):
(JSC::CodeCacheMap::find):
(JSC::CodeCacheMap::set):
(JSC::CodeCacheMap::clear):
(JSC::CodeCacheMap::pruneIfNeeded):
(CodeCache): Grow and shrink in response to usage.

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/ChangeLog (143758 => 143759)


--- trunk/Source/_javascript_Core/ChangeLog	2013-02-22 19:14:22 UTC (rev 143758)
+++ trunk/Source/_javascript_Core/ChangeLog	2013-02-22 19:16:03 UTC (rev 143759)
@@ -1,3 +1,30 @@
+2013-02-21  Geoffrey Garen  <[email protected]>
+
+        Code cache size should adapt to workload
+        https://bugs.webkit.org/show_bug.cgi?id=110560
+
+        Reviewed by Antti Koivisto.
+
+        (*) 5% PLT arithmetic mean speedup
+        (*) 10% PLT geometric mean speedup
+        (*) 3.4X microbenchmark speedup
+        (*) Reduces initial cache capacity by 16X
+
+        * runtime/CodeCache.cpp:
+        (JSC::CodeCache::CodeCache): Updated for interface change.
+
+        * runtime/CodeCache.h:
+        (JSC::SourceCodeValue::SourceCodeValue):
+        (SourceCodeValue): Turned the cache value into a struct so it can track its age.
+
+        (CodeCacheMap):
+        (JSC::CodeCacheMap::CodeCacheMap):
+        (JSC::CodeCacheMap::find):
+        (JSC::CodeCacheMap::set):
+        (JSC::CodeCacheMap::clear):
+        (JSC::CodeCacheMap::pruneIfNeeded):
+        (CodeCache): Grow and shrink in response to usage.
+
 2013-02-21  Jessie Berlin  <[email protected]>
 
         Fix a typo that broke the 32 bit build.

Modified: trunk/Source/_javascript_Core/runtime/CodeCache.cpp (143758 => 143759)


--- trunk/Source/_javascript_Core/runtime/CodeCache.cpp	2013-02-22 19:14:22 UTC (rev 143758)
+++ trunk/Source/_javascript_Core/runtime/CodeCache.cpp	2013-02-22 19:16:03 UTC (rev 143759)
@@ -37,7 +37,6 @@
 namespace JSC {
 
 CodeCache::CodeCache()
-    : m_sourceCode(CacheSize)
 {
 }
 

Modified: trunk/Source/_javascript_Core/runtime/CodeCache.h (143758 => 143759)


--- trunk/Source/_javascript_Core/runtime/CodeCache.h	2013-02-22 19:14:22 UTC (rev 143758)
+++ trunk/Source/_javascript_Core/runtime/CodeCache.h	2013-02-22 19:16:03 UTC (rev 143759)
@@ -113,47 +113,100 @@
     static bool isEmptyValue(const SourceCodeKey& sourceCodeKey) { return sourceCodeKey.isNull(); }
 };
 
+struct SourceCodeValue {
+    SourceCodeValue()
+    {
+    }
+
+    SourceCodeValue(const Strong<JSCell>& cell, int64_t age)
+        : cell(cell)
+        , age(age)
+    {
+    }
+
+    Strong<JSCell> cell;
+    int64_t age;
+};
+
 class CodeCacheMap {
-    typedef HashMap<SourceCodeKey, Strong<JSCell>, SourceCodeKeyHash, SourceCodeKeyHashTraits> MapType;
+    typedef HashMap<SourceCodeKey, SourceCodeValue, SourceCodeKeyHash, SourceCodeKeyHashTraits> MapType;
     typedef MapType::iterator iterator;
 
 public:
-    CodeCacheMap(size_t capacity)
+    enum { MinCacheCapacity = 1000000 }; // Size in characters
+
+    CodeCacheMap()
         : m_size(0)
-        , m_capacity(capacity)
+        , m_capacity(MinCacheCapacity)
+        , m_age(0)
     {
     }
 
     const Strong<JSCell>* find(const SourceCodeKey& key)
     {
-        iterator result = m_map.find(key);
-        if (result == m_map.end())
+        iterator it = m_map.find(key);
+        if (it == m_map.end())
             return 0;
-        return &result->value;
+
+        size_t age = m_age - it->value.age;
+        if (age > m_capacity) {
+            // A requested object is older than the cache's capacity. We can
+            // infer that requested objects are subject to high eviction probability,
+            // so we grow the cache to improve our hit rate.
+            m_capacity += recencyBias * oldObjectSamplingMultiplier * key.length();
+        } else if (age < m_capacity / 2) {
+            // A requested object is much younger than the cache's capacity. We can
+            // infer that requested objects are subject to low eviction probability,
+            // so we shrink the cache to save memory.
+            m_capacity -= recencyBias * key.length();
+            if (m_capacity < MinCacheCapacity)
+                m_capacity = MinCacheCapacity;
+        }
+
+        it->value.age = m_age;
+        m_age += key.length();
+        return &it->value.cell;
     }
 
     void set(const SourceCodeKey& key, const Strong<JSCell>& value)
     {
-        while (m_size >= m_capacity) {
-            MapType::iterator it = m_map.begin();
-            m_size -= it->key.length();
-            m_map.remove(it);
-        }
+        pruneIfNeeded();
 
         m_size += key.length();
-        m_map.set(key, value);
+        m_age += key.length();
+        m_map.set(key, SourceCodeValue(value, m_age));
     }
 
     void clear()
     {
         m_size = 0;
+        m_age = 0;
         m_map.clear();
     }
 
 private:
+    // This constant factor biases cache capacity toward recent activity. We
+    // want to adapt to changing workloads.
+    static const int64_t recencyBias = 4;
+
+    // This constant factor treats a sampled event for one old object as if it
+    // happened for many old objects. Most old objects are evicted before we can
+    // sample them, so we need to extrapolate from the ones we do sample.
+    static const int64_t oldObjectSamplingMultiplier = 32;
+
+    void pruneIfNeeded()
+    {
+        while (m_size >= m_capacity) {
+            MapType::iterator it = m_map.begin();
+            m_size -= it->key.length();
+            m_map.remove(it);
+        }
+    }
+
     MapType m_map;
     size_t m_size;
     size_t m_capacity;
+    int64_t m_age;
 };
 
 // Caches top-level code such as <script>, eval(), new Function, and JSEvaluateScript().
@@ -177,8 +230,6 @@
     template <class UnlinkedCodeBlockType, class ExecutableType> 
     UnlinkedCodeBlockType* getCodeBlock(JSGlobalData&, ExecutableType*, const SourceCode&, JSParserStrictness, DebuggerMode, ProfilerMode, ParserError&);
 
-    enum { CacheSize = 16000000 }; // Size in characters
-
     CodeCacheMap m_sourceCode;
 };
 
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to