src/share/vm/gc_implementation/g1/g1MMUTracker.cpp

changeset 0
f90c822e73f8
child 6876
710a3c8b516e
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/share/vm/gc_implementation/g1/g1MMUTracker.cpp	Wed Apr 27 01:25:04 2016 +0800
     1.3 @@ -0,0 +1,185 @@
     1.4 +/*
     1.5 + * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
     1.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     1.7 + *
     1.8 + * This code is free software; you can redistribute it and/or modify it
     1.9 + * under the terms of the GNU General Public License version 2 only, as
    1.10 + * published by the Free Software Foundation.
    1.11 + *
    1.12 + * This code is distributed in the hope that it will be useful, but WITHOUT
    1.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    1.14 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
    1.15 + * version 2 for more details (a copy is included in the LICENSE file that
    1.16 + * accompanied this code).
    1.17 + *
    1.18 + * You should have received a copy of the GNU General Public License version
    1.19 + * 2 along with this work; if not, write to the Free Software Foundation,
    1.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
    1.21 + *
    1.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    1.23 + * or visit www.oracle.com if you need additional information or have any
    1.24 + * questions.
    1.25 + *
    1.26 + */
    1.27 +
    1.28 +#include "precompiled.hpp"
    1.29 +#include "gc_implementation/g1/g1MMUTracker.hpp"
    1.30 +#include "runtime/mutexLocker.hpp"
    1.31 +#include "utilities/ostream.hpp"
    1.32 +
    1.33 +#define _DISABLE_MMU                             0
    1.34 +
    1.35 +// can't rely on comparing doubles with tolerating a small margin for error
    1.36 +#define SMALL_MARGIN 0.0000001
    1.37 +#define is_double_leq_0(_value) ( (_value) < SMALL_MARGIN )
    1.38 +#define is_double_leq(_val1, _val2) is_double_leq_0((_val1) - (_val2))
    1.39 +#define is_double_geq(_val1, _val2) is_double_leq_0((_val2) - (_val1))
    1.40 +
    1.41 +/***** ALL TIMES ARE IN SECS!!!!!!! *****/
    1.42 +
    1.43 +G1MMUTracker::G1MMUTracker(double time_slice, double max_gc_time) :
    1.44 +  _time_slice(time_slice),
    1.45 +  _max_gc_time(max_gc_time) { }
    1.46 +
    1.47 +G1MMUTrackerQueue::G1MMUTrackerQueue(double time_slice, double max_gc_time) :
    1.48 +  G1MMUTracker(time_slice, max_gc_time),
    1.49 +  _head_index(0),
    1.50 +  _tail_index(trim_index(_head_index+1)),
    1.51 +  _no_entries(0) { }
    1.52 +
    1.53 +void G1MMUTrackerQueue::remove_expired_entries(double current_time) {
    1.54 +  double limit = current_time - _time_slice;
    1.55 +  while (_no_entries > 0) {
    1.56 +    if (is_double_geq(limit, _array[_tail_index].end_time())) {
    1.57 +      _tail_index = trim_index(_tail_index + 1);
    1.58 +      --_no_entries;
    1.59 +    } else
    1.60 +      return;
    1.61 +  }
    1.62 +  guarantee(_no_entries == 0, "should have no entries in the array");
    1.63 +}
    1.64 +
    1.65 +double G1MMUTrackerQueue::calculate_gc_time(double current_time) {
    1.66 +  double gc_time = 0.0;
    1.67 +  double limit = current_time - _time_slice;
    1.68 +  for (int i = 0; i < _no_entries; ++i) {
    1.69 +    int index = trim_index(_tail_index + i);
    1.70 +    G1MMUTrackerQueueElem *elem = &_array[index];
    1.71 +    if (elem->end_time() > limit) {
    1.72 +      if (elem->start_time() > limit)
    1.73 +        gc_time += elem->duration();
    1.74 +      else
    1.75 +        gc_time += elem->end_time() - limit;
    1.76 +    }
    1.77 +  }
    1.78 +  return gc_time;
    1.79 +}
    1.80 +
    1.81 +void G1MMUTrackerQueue::add_pause(double start, double end, bool gc_thread) {
    1.82 +  double longest_allowed = longest_pause_internal(start);
    1.83 +  if (longest_allowed < 0.0)
    1.84 +    longest_allowed = 0.0;
    1.85 +  double duration = end - start;
    1.86 +
    1.87 +  remove_expired_entries(end);
    1.88 +  if (_no_entries == QueueLength) {
    1.89 +    // OK, we've filled up the queue. There are a few ways
    1.90 +    // of dealing with this "gracefully"
    1.91 +    //   increase the array size (:-)
    1.92 +    //   remove the oldest entry (this might allow more GC time for
    1.93 +    //     the time slice than what's allowed) - this is what we
    1.94 +    //     currently do
    1.95 +    //   consolidate the two entries with the minimum gap between them
    1.96 +    //     (this might allow less GC time than what's allowed)
    1.97 +
    1.98 +    // In the case where ScavengeALot is true, such overflow is not
    1.99 +    // uncommon; in such cases, we can, without much loss of precision
   1.100 +    // or performance (we are GC'ing most of the time anyway!),
   1.101 +    // simply overwrite the oldest entry in the tracker.
   1.102 +
   1.103 +    _head_index = trim_index(_head_index + 1);
   1.104 +    assert(_head_index == _tail_index, "Because we have a full circular buffer");
   1.105 +    _tail_index = trim_index(_tail_index + 1);
   1.106 +  } else {
   1.107 +    _head_index = trim_index(_head_index + 1);
   1.108 +    ++_no_entries;
   1.109 +  }
   1.110 +  _array[_head_index] = G1MMUTrackerQueueElem(start, end);
   1.111 +}
   1.112 +
   1.113 +// basically the _internal call does not remove expired entries
   1.114 +// this is for trying things out in the future and a couple
   1.115 +// of other places (debugging)
   1.116 +
   1.117 +double G1MMUTrackerQueue::longest_pause(double current_time) {
   1.118 +  if (_DISABLE_MMU)
   1.119 +    return _max_gc_time;
   1.120 +
   1.121 +  MutexLockerEx x(MMUTracker_lock, Mutex::_no_safepoint_check_flag);
   1.122 +  remove_expired_entries(current_time);
   1.123 +
   1.124 +  return longest_pause_internal(current_time);
   1.125 +}
   1.126 +
   1.127 +double G1MMUTrackerQueue::longest_pause_internal(double current_time) {
   1.128 +  double target_time = _max_gc_time;
   1.129 +
   1.130 +  while( 1 ) {
   1.131 +    double gc_time =
   1.132 +      calculate_gc_time(current_time + target_time);
   1.133 +    double diff = target_time + gc_time - _max_gc_time;
   1.134 +    if (!is_double_leq_0(diff)) {
   1.135 +      target_time -= diff;
   1.136 +      if (is_double_leq_0(target_time)) {
   1.137 +        target_time = -1.0;
   1.138 +        break;
   1.139 +      }
   1.140 +    } else {
   1.141 +      break;
   1.142 +    }
   1.143 +  }
   1.144 +
   1.145 +  return target_time;
   1.146 +}
   1.147 +
   1.148 +// basically the _internal call does not remove expired entries
   1.149 +// this is for trying things out in the future and a couple
   1.150 +// of other places (debugging)
   1.151 +
   1.152 +double G1MMUTrackerQueue::when_sec(double current_time, double pause_time) {
   1.153 +  if (_DISABLE_MMU)
   1.154 +    return 0.0;
   1.155 +
   1.156 +  MutexLockerEx x(MMUTracker_lock, Mutex::_no_safepoint_check_flag);
   1.157 +  remove_expired_entries(current_time);
   1.158 +
   1.159 +  return when_internal(current_time, pause_time);
   1.160 +}
   1.161 +
   1.162 +double G1MMUTrackerQueue::when_internal(double current_time,
   1.163 +                                        double pause_time) {
   1.164 +  // if the pause is over the maximum, just assume that it's the maximum
   1.165 +  double adjusted_pause_time =
   1.166 +    (pause_time > max_gc_time()) ? max_gc_time() : pause_time;
   1.167 +  double earliest_end = current_time + adjusted_pause_time;
   1.168 +  double limit = earliest_end - _time_slice;
   1.169 +  double gc_time = calculate_gc_time(earliest_end);
   1.170 +  double diff = gc_time + adjusted_pause_time - max_gc_time();
   1.171 +  if (is_double_leq_0(diff))
   1.172 +    return 0.0;
   1.173 +
   1.174 +  int index = _tail_index;
   1.175 +  while ( 1 ) {
   1.176 +    G1MMUTrackerQueueElem *elem = &_array[index];
   1.177 +    if (elem->end_time() > limit) {
   1.178 +      if (elem->start_time() > limit)
   1.179 +        diff -= elem->duration();
   1.180 +      else
   1.181 +        diff -= elem->end_time() - limit;
   1.182 +      if (is_double_leq_0(diff))
   1.183 +        return  elem->end_time() + diff + _time_slice - adjusted_pause_time - current_time;
   1.184 +    }
   1.185 +    index = trim_index(index+1);
   1.186 +    guarantee(index != trim_index(_head_index + 1), "should not go past head");
   1.187 +  }
   1.188 +}

mercurial