src/hotspot/share/gc/z/zPageCache.cpp
changeset 50525 767cdb97f103
child 54162 f344a0c6e19e
equal deleted inserted replaced
50524:04f4e983c2f7 50525:767cdb97f103
       
     1 /*
       
     2  * Copyright (c) 2015, 2017, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.
       
     8  *
       
     9  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    12  * version 2 for more details (a copy is included in the LICENSE file that
       
    13  * accompanied this code).
       
    14  *
       
    15  * You should have received a copy of the GNU General Public License version
       
    16  * 2 along with this work; if not, write to the Free Software Foundation,
       
    17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    18  *
       
    19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    20  * or visit www.oracle.com if you need additional information or have any
       
    21  * questions.
       
    22  */
       
    23 
       
    24 #include "precompiled.hpp"
       
    25 #include "gc/z/zList.inline.hpp"
       
    26 #include "gc/z/zNUMA.hpp"
       
    27 #include "gc/z/zPage.inline.hpp"
       
    28 #include "gc/z/zPageCache.hpp"
       
    29 #include "gc/z/zStat.hpp"
       
    30 #include "logging/log.hpp"
       
    31 
       
    32 static const ZStatCounter ZCounterPageCacheHitL1("Memory", "Page Cache Hit L1", ZStatUnitOpsPerSecond);
       
    33 static const ZStatCounter ZCounterPageCacheHitL2("Memory", "Page Cache Hit L2", ZStatUnitOpsPerSecond);
       
    34 static const ZStatCounter ZCounterPageCacheMiss("Memory", "Page Cache Miss", ZStatUnitOpsPerSecond);
       
    35 static const ZStatCounter ZCounterPageCacheFlush("Memory", "Page Cache Flush", ZStatUnitBytesPerSecond);
       
    36 
       
    37 ZPageCache::ZPageCache() :
       
    38     _available(0),
       
    39     _small(),
       
    40     _medium(),
       
    41     _large() {}
       
    42 
       
    43 ZPage* ZPageCache::alloc_small_page() {
       
    44   const uint32_t numa_id = ZNUMA::id();
       
    45   const uint32_t numa_count = ZNUMA::count();
       
    46 
       
    47   // Try NUMA local page cache
       
    48   ZPage* const l1_page = _small.get(numa_id).remove_first();
       
    49   if (l1_page != NULL) {
       
    50     ZStatInc(ZCounterPageCacheHitL1);
       
    51     return l1_page;
       
    52   }
       
    53 
       
    54   // Try NUMA remote page cache(s)
       
    55   uint32_t remote_numa_id = numa_id + 1;
       
    56   const uint32_t remote_numa_count = numa_count - 1;
       
    57   for (uint32_t i = 0; i < remote_numa_count; i++) {
       
    58     if (remote_numa_id == numa_count) {
       
    59       remote_numa_id = 0;
       
    60     }
       
    61 
       
    62     ZPage* const l2_page = _small.get(remote_numa_id).remove_first();
       
    63     if (l2_page != NULL) {
       
    64       ZStatInc(ZCounterPageCacheHitL2);
       
    65       return l2_page;
       
    66     }
       
    67 
       
    68     remote_numa_id++;
       
    69   }
       
    70 
       
    71   ZStatInc(ZCounterPageCacheMiss);
       
    72   return NULL;
       
    73 }
       
    74 
       
    75 ZPage* ZPageCache::alloc_medium_page() {
       
    76   ZPage* const l1_page = _medium.remove_first();
       
    77   if (l1_page != NULL) {
       
    78     ZStatInc(ZCounterPageCacheHitL1);
       
    79     return l1_page;
       
    80   }
       
    81 
       
    82   ZStatInc(ZCounterPageCacheMiss);
       
    83   return NULL;
       
    84 }
       
    85 
       
    86 ZPage* ZPageCache::alloc_large_page(size_t size) {
       
    87   // Find a page with the right size
       
    88   ZListIterator<ZPage> iter(&_large);
       
    89   for (ZPage* l1_page; iter.next(&l1_page);) {
       
    90     if (l1_page->size() == size) {
       
    91       // Page found
       
    92       _large.remove(l1_page);
       
    93       ZStatInc(ZCounterPageCacheHitL1);
       
    94       return l1_page;
       
    95     }
       
    96   }
       
    97 
       
    98   ZStatInc(ZCounterPageCacheMiss);
       
    99   return NULL;
       
   100 }
       
   101 
       
   102 ZPage* ZPageCache::alloc_page(uint8_t type, size_t size) {
       
   103   ZPage* page;
       
   104 
       
   105   if (type == ZPageTypeSmall) {
       
   106     page = alloc_small_page();
       
   107   } else if (type == ZPageTypeMedium) {
       
   108     page = alloc_medium_page();
       
   109   } else {
       
   110     page = alloc_large_page(size);
       
   111   }
       
   112 
       
   113   if (page != NULL) {
       
   114     _available -= page->size();
       
   115   }
       
   116 
       
   117   return page;
       
   118 }
       
   119 
       
   120 void ZPageCache::free_page(ZPage* page) {
       
   121   assert(!page->is_active(), "Invalid page state");
       
   122   assert(!page->is_pinned(), "Invalid page state");
       
   123   assert(!page->is_detached(), "Invalid page state");
       
   124 
       
   125   const uint8_t type = page->type();
       
   126   if (type == ZPageTypeSmall) {
       
   127     _small.get(page->numa_id()).insert_first(page);
       
   128   } else if (type == ZPageTypeMedium) {
       
   129     _medium.insert_first(page);
       
   130   } else {
       
   131     _large.insert_first(page);
       
   132   }
       
   133 
       
   134   _available += page->size();
       
   135 }
       
   136 
       
   137 void ZPageCache::flush_list(ZList<ZPage>* from, size_t requested, ZList<ZPage>* to, size_t* flushed) {
       
   138   while (*flushed < requested) {
       
   139     // Flush least recently used
       
   140     ZPage* const page = from->remove_last();
       
   141     if (page == NULL) {
       
   142       break;
       
   143     }
       
   144 
       
   145     *flushed += page->size();
       
   146     to->insert_last(page);
       
   147   }
       
   148 }
       
   149 
       
   150 void ZPageCache::flush_per_numa_lists(ZPerNUMA<ZList<ZPage> >* from, size_t requested, ZList<ZPage>* to, size_t* flushed) {
       
   151   const uint32_t numa_count = ZNUMA::count();
       
   152   uint32_t numa_empty = 0;
       
   153   uint32_t numa_next = 0;
       
   154 
       
   155   // Flush lists round-robin
       
   156   while (*flushed < requested) {
       
   157     ZPage* const page = from->get(numa_next).remove_last();
       
   158 
       
   159     if (++numa_next == numa_count) {
       
   160       numa_next = 0;
       
   161     }
       
   162 
       
   163     if (page == NULL) {
       
   164       // List is empty
       
   165       if (++numa_empty == numa_count) {
       
   166         // All lists are empty
       
   167         break;
       
   168       }
       
   169 
       
   170       // Try next list
       
   171       continue;
       
   172     }
       
   173 
       
   174     // Flush page
       
   175     numa_empty = 0;
       
   176     *flushed += page->size();
       
   177     to->insert_last(page);
       
   178   }
       
   179 }
       
   180 
       
   181 void ZPageCache::flush(ZList<ZPage>* to, size_t requested) {
       
   182   size_t flushed = 0;
       
   183 
       
   184   // Prefer flushing large, then medium and last small pages
       
   185   flush_list(&_large, requested, to, &flushed);
       
   186   flush_list(&_medium, requested, to, &flushed);
       
   187   flush_per_numa_lists(&_small, requested, to, &flushed);
       
   188 
       
   189   ZStatInc(ZCounterPageCacheFlush, flushed);
       
   190 
       
   191   log_info(gc, heap)("Page Cache Flushed: "
       
   192                      SIZE_FORMAT "M requested, "
       
   193                      SIZE_FORMAT "M(" SIZE_FORMAT "M->" SIZE_FORMAT "M) flushed",
       
   194                      requested / M, flushed / M , _available / M, (_available - flushed) / M);
       
   195 
       
   196   _available -= flushed;
       
   197 }