< prev index next >

src/hotspot/share/gc/z/zPageCache.cpp

Print this page

        

@@ -1,7 +1,7 @@
 /*
- * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License version 2 only, as
  * published by the Free Software Foundation.

@@ -20,33 +20,43 @@
  * or visit www.oracle.com if you need additional information or have any
  * questions.
  */
 
 #include "precompiled.hpp"
+#include "gc/z/zGlobals.hpp"
 #include "gc/z/zList.inline.hpp"
 #include "gc/z/zNUMA.hpp"
 #include "gc/z/zPage.inline.hpp"
 #include "gc/z/zPageCache.hpp"
 #include "gc/z/zStat.hpp"
 #include "gc/z/zValue.inline.hpp"
+#include "jfr/jfrEvents.hpp"
 #include "logging/log.hpp"
+#include "memory/allocation.hpp"
 
 static const ZStatCounter ZCounterPageCacheHitL1("Memory", "Page Cache Hit L1", ZStatUnitOpsPerSecond);
 static const ZStatCounter ZCounterPageCacheHitL2("Memory", "Page Cache Hit L2", ZStatUnitOpsPerSecond);
 static const ZStatCounter ZCounterPageCacheHitL3("Memory", "Page Cache Hit L3", ZStatUnitOpsPerSecond);
 static const ZStatCounter ZCounterPageCacheMiss("Memory", "Page Cache Miss", ZStatUnitOpsPerSecond);
 
+class ZPageCacheFlushClosure : public StackObj {
+  friend class ZPageCache;
+
+protected:
+  const size_t _requested;
+  size_t       _flushed;
+
+public:
+  ZPageCacheFlushClosure(size_t requested);
+  virtual bool do_page(const ZPage* page) = 0;
+};
+
 ZPageCacheFlushClosure::ZPageCacheFlushClosure(size_t requested) :
     _requested(requested),
     _flushed(0) {}
 
-size_t ZPageCacheFlushClosure::overflushed() const {
-  return _flushed > _requested ? _flushed - _requested : 0;
-}
-
 ZPageCache::ZPageCache() :
-    _available(0),
     _small(),
     _medium(),
     _large() {}
 
 ZPage* ZPageCache::alloc_small_page() {

@@ -159,52 +169,44 @@
       if (size < oversized->size()) {
         // Split oversized page
         page = oversized->split(type, size);
 
         // Cache remainder
-        free_page_inner(oversized);
+        free_page(oversized);
       } else {
         // Re-type correctly sized page
         page = oversized->retype(type);
       }
     }
   }
 
-  if (page != NULL) {
-    _available -= page->size();
-  } else {
+  if (page == NULL) {
     ZStatInc(ZCounterPageCacheMiss);
   }
 
   return page;
 }
 
-void ZPageCache::free_page_inner(ZPage* page) {
+void ZPageCache::free_page(ZPage* page) {
   const uint8_t type = page->type();
   if (type == ZPageTypeSmall) {
     _small.get(page->numa_id()).insert_first(page);
   } else if (type == ZPageTypeMedium) {
     _medium.insert_first(page);
   } else {
     _large.insert_first(page);
   }
 }
 
-void ZPageCache::free_page(ZPage* page) {
-  free_page_inner(page);
-  _available += page->size();
-}
-
 bool ZPageCache::flush_list_inner(ZPageCacheFlushClosure* cl, ZList<ZPage>* from, ZList<ZPage>* to) {
   ZPage* const page = from->last();
   if (page == NULL || !cl->do_page(page)) {
     // Don't flush page
     return false;
   }
 
   // Flush page
-  _available -= page->size();
   from->remove(page);
   to->insert_last(page);
   return true;
 }
 

@@ -237,10 +239,94 @@
 void ZPageCache::flush(ZPageCacheFlushClosure* cl, ZList<ZPage>* to) {
   // Prefer flushing large, then medium and last small pages
   flush_list(cl, &_large, to);
   flush_list(cl, &_medium, to);
   flush_per_numa_lists(cl, &_small, to);
+
+  if (cl->_flushed > cl->_requested) {
+    // Overflushed, keep part of last page
+    const size_t overflushed = cl->_flushed - cl->_requested;
+    free_page(to->last()->split(overflushed));
+    cl->_flushed -= overflushed;
+  }
+}
+
+class ZPageCacheFlushForAllocationClosure : public ZPageCacheFlushClosure {
+public:
+  ZPageCacheFlushForAllocationClosure(size_t requested) :
+      ZPageCacheFlushClosure(requested) {}
+
+  virtual bool do_page(const ZPage* page) {
+    if (_flushed < _requested) {
+      // Flush page
+      _flushed += page->size();
+      return true;
+    }
+
+    // Don't flush page
+    return false;
+  }
+};
+
+void ZPageCache::flush_for_allocation(size_t requested, ZList<ZPage>* to) {
+  EventZPageCacheFlush event;
+
+  // Flush
+  ZPageCacheFlushForAllocationClosure cl(requested);
+  flush(&cl, to);
+
+  // Send event
+  event.commit(requested, true /* for_allocation */);
+}
+
+class ZPageCacheFlushForUncommitClosure : public ZPageCacheFlushClosure {
+private:
+  const uint64_t _now;
+  const uint64_t _delay;
+  uint64_t*      _timeout;
+
+public:
+  ZPageCacheFlushForUncommitClosure(size_t requested, uint64_t delay, uint64_t* timeout) :
+      ZPageCacheFlushClosure(requested),
+      _now(os::elapsedTime()),
+      _delay(delay),
+      _timeout(timeout) {}
+
+  virtual bool do_page(const ZPage* page) {
+    const uint64_t expires = page->last_used() + _delay;
+    const uint64_t timeout = expires - MIN2(expires, _now);
+
+    if (_flushed < _requested && timeout == 0) {
+      // Flush page
+      _flushed += page->size();
+      return true;
+    }
+
+    // Record shortest non-expired timeout
+    *_timeout = MIN2(*_timeout, timeout);
+
+    // Don't flush page
+    return false;
+  }
+};
+
+size_t ZPageCache::flush_for_uncommit(size_t requested, uint64_t delay, uint64_t* timeout, ZList<ZPage>* to) {
+  if (requested == 0) {
+    // Nothing to flush
+    return 0;
+  }
+
+  EventZPageCacheFlush event;
+
+  // Flush
+  ZPageCacheFlushForUncommitClosure cl(requested, delay, timeout);
+  flush(&cl, to);
+
+  // Send event
+  event.commit(requested, false /* for_allocation */);
+
+  return cl._flushed;
 }
 
 void ZPageCache::pages_do(ZPageClosure* cl) const {
   // Small
   ZPerNUMAConstIterator<ZList<ZPage> > iter_numa(&_small);
< prev index next >