1 /*
   2  * Copyright (c) 2019, 2020, 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/zCPU.inline.hpp"
  26 #include "gc/z/zGlobals.hpp"
  27 #include "gc/z/zHeuristics.hpp"
  28 #include "logging/log.hpp"
  29 #include "runtime/globals.hpp"
  30 #include "runtime/os.hpp"
  31 #include "utilities/globalDefinitions.hpp"
  32 #include "utilities/powerOfTwo.hpp"
  33 
  34 void ZHeuristics::set_medium_page_size() {
  35   // Set ZPageSizeMedium so that a medium page occupies at most 3.125% of the
  36   // max heap size. ZPageSizeMedium is initially set to 0, which means medium
  37   // pages are effectively disabled. It is adjusted only if ZPageSizeMedium
  38   // becomes larger than ZPageSizeSmall.
  39   const size_t min = ZGranuleSize;
  40   const size_t max = ZGranuleSize * 16;
  41   const size_t unclamped = MaxHeapSize * 0.03125;
  42   const size_t clamped = clamp(unclamped, min, max);
  43   const size_t size = round_down_power_of_2(clamped);
  44 
  45   if (size > ZPageSizeSmall) {
  46     // Enable medium pages
  47     ZPageSizeMedium             = size;
  48     ZPageSizeMediumShift        = log2_intptr(ZPageSizeMedium);
  49     ZObjectSizeLimitMedium      = ZPageSizeMedium / 8;
  50     ZObjectAlignmentMediumShift = (int)ZPageSizeMediumShift - 13;
  51     ZObjectAlignmentMedium      = 1 << ZObjectAlignmentMediumShift;
  52   }
  53 }
  54 
  55 size_t ZHeuristics::max_reserve() {
  56   // Reserve one small page per worker plus one shared medium page. This is still just
  57   // an estimate and doesn't guarantee that we can't run out of memory during relocation.
  58   const uint nworkers = MAX2(ParallelGCThreads, ConcGCThreads);
  59   const size_t reserve = (nworkers * ZPageSizeSmall) + ZPageSizeMedium;
  60   return MIN2(MaxHeapSize, reserve);
  61 }
  62 
  63 bool ZHeuristics::use_per_cpu_shared_small_pages() {
  64   // Use per-CPU shared small pages only if these pages occupy at most 3.125%
  65   // of the max heap size. Otherwise fall back to using a single shared small
  66   // page. This is useful when using small heaps on large machines.
  67   const size_t per_cpu_share = (MaxHeapSize * 0.03125) / ZCPU::count();
  68   return per_cpu_share >= ZPageSizeSmall;
  69 }
  70 
  71 static uint nworkers_based_on_ncpus(double cpu_share_in_percent) {
  72   return ceil(os::initial_active_processor_count() * cpu_share_in_percent / 100.0);
  73 }
  74 
  75 static uint nworkers_based_on_heap_size(double reserve_share_in_percent) {
  76   const int nworkers = (MaxHeapSize * (reserve_share_in_percent / 100.0)) / ZPageSizeSmall;
  77   return MAX2(nworkers, 1);
  78 }
  79 
  80 static uint nworkers(double cpu_share_in_percent) {
  81   // Cap number of workers so that we don't use more than 2% of the max heap
  82   // for the small page reserve. This is useful when using small heaps on
  83   // large machines.
  84   return MIN2(nworkers_based_on_ncpus(cpu_share_in_percent),
  85               nworkers_based_on_heap_size(2.0));
  86 }
  87 
  88 uint ZHeuristics::nparallel_workers() {
  89   // Use 60% of the CPUs, rounded up. We would like to use as many threads as
  90   // possible to increase parallelism. However, using a thread count that is
  91   // close to the number of processors tends to lead to over-provisioning and
  92   // scheduling latency issues. Using 60% of the active processors appears to
  93   // be a fairly good balance.
  94   return nworkers(60.0);
  95 }
  96 
  97 uint ZHeuristics::nconcurrent_workers() {
  98   // Use 12.5% of the CPUs, rounded up. The number of concurrent threads we
  99   // would like to use heavily depends on the type of workload we are running.
 100   // Using too many threads will have a negative impact on the application
 101   // throughput, while using too few threads will prolong the GC-cycle and
 102   // we then risk being out-run by the application. Using 12.5% of the active
 103   // processors appears to be a fairly good balance.
 104   return nworkers(12.5);
 105 }