jdk

Форк
0
/
trimNativeHeap.cpp 
269 строк · 8.6 Кб
1
/*
2
 * Copyright (c) 2023 SAP SE. All rights reserved.
3
 * Copyright (c) 2023 Red Hat Inc. All rights reserved.
4
 * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
5
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6
 *
7
 * This code is free software; you can redistribute it and/or modify it
8
 * under the terms of the GNU General Public License version 2 only, as
9
 * published by the Free Software Foundation.
10
 *
11
 * This code is distributed in the hope that it will be useful, but WITHOUT
12
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14
 * version 2 for more details (a copy is included in the LICENSE file that
15
 * accompanied this code).
16
 *
17
 * You should have received a copy of the GNU General Public License version
18
 * 2 along with this work; if not, write to the Free Software Foundation,
19
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
 *
21
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
 * or visit www.oracle.com if you need additional information or have any
23
 * questions.
24
 *
25
 */
26

27
#include "precompiled.hpp"
28
#include "logging/log.hpp"
29
#include "runtime/globals.hpp"
30
#include "runtime/globals_extension.hpp"
31
#include "runtime/mutex.hpp"
32
#include "runtime/mutexLocker.hpp"
33
#include "runtime/nonJavaThread.hpp"
34
#include "runtime/os.inline.hpp"
35
#include "runtime/safepoint.hpp"
36
#include "runtime/trimNativeHeap.hpp"
37
#include "utilities/debug.hpp"
38
#include "utilities/globalDefinitions.hpp"
39
#include "utilities/ostream.hpp"
40
#include "utilities/vmError.hpp"
41

42
class NativeHeapTrimmerThread : public NamedThread {
43

44
  // Upper limit for the backoff during pending/in-progress safepoint.
45
  // Chosen as reasonable value to balance the overheads of waking up
46
  // during the safepoint, which might have undesired effects on latencies,
47
  // and the accuracy in tracking the trimming interval.
48
  static constexpr int64_t safepoint_poll_ms = 250;
49

50
  Monitor* const _lock;
51
  bool _stop;
52
  uint16_t _suspend_count;
53

54
  // Statistics
55
  uint64_t _num_trims_performed;
56

57
  bool is_suspended() const {
58
    assert(_lock->is_locked(), "Must be");
59
    return _suspend_count > 0;
60
  }
61

62
  uint16_t inc_suspend_count() {
63
    assert(_lock->is_locked(), "Must be");
64
    assert(_suspend_count < UINT16_MAX, "Sanity");
65
    return ++_suspend_count;
66
  }
67

68
  uint16_t dec_suspend_count() {
69
    assert(_lock->is_locked(), "Must be");
70
    assert(_suspend_count != 0, "Sanity");
71
    return --_suspend_count;
72
  }
73

74
  bool at_or_nearing_safepoint() const {
75
    return SafepointSynchronize::is_at_safepoint() ||
76
           SafepointSynchronize::is_synchronizing();
77
  }
78

79
  // in seconds
80
  static double now() { return os::elapsedTime(); }
81
  static double to_ms(double seconds) { return seconds * 1000.0; }
82

83
  struct LogStartStopMark {
84
    void log(const char* s) { log_info(trimnative)("Native heap trimmer %s", s); }
85
    LogStartStopMark()  { log("start"); }
86
    ~LogStartStopMark() { log("stop"); }
87
  };
88

89
  void run() override {
90
    assert(NativeHeapTrimmer::enabled(), "Only call if enabled");
91

92
    LogStartStopMark lssm;
93

94
    const double interval_secs = (double)TrimNativeHeapInterval / 1000;
95

96
    while (true) {
97
      double tnow = now();
98
      double next_trim_time = tnow + interval_secs;
99

100
      unsigned times_suspended = 0;
101
      unsigned times_waited = 0;
102
      unsigned times_safepoint = 0;
103

104
      {
105
        MonitorLocker ml(_lock, Mutex::_no_safepoint_check_flag);
106
        if (_stop) return;
107

108
        while (at_or_nearing_safepoint() || is_suspended() || next_trim_time > tnow) {
109
          if (is_suspended()) {
110
            times_suspended ++;
111
            ml.wait(0); // infinite
112
          } else if (next_trim_time > tnow) {
113
            times_waited ++;
114
            const double wait_ms = MAX2(1.0, to_ms(next_trim_time - tnow));
115
            ml.wait((int64_t)wait_ms);
116
          } else if (at_or_nearing_safepoint()) {
117
            times_safepoint ++;
118
            const int64_t wait_ms = MIN2<int64_t>(TrimNativeHeapInterval, safepoint_poll_ms);
119
            ml.wait(wait_ms);
120
          }
121

122
          if (_stop) return;
123

124
          tnow = now();
125
        }
126
      }
127

128
      log_trace(trimnative)("Times: %u suspended, %u timed, %u safepoint",
129
                            times_suspended, times_waited, times_safepoint);
130

131
      execute_trim_and_log(tnow);
132
    }
133
  }
134

135
  // Execute the native trim, log results.
136
  void execute_trim_and_log(double t1) {
137
    assert(os::can_trim_native_heap(), "Unexpected");
138

139
    os::size_change_t sc = { 0, 0 };
140
    LogTarget(Info, trimnative) lt;
141
    const bool logging_enabled = lt.is_enabled();
142

143
    // We only collect size change information if we are logging; save the access to procfs otherwise.
144
    if (os::trim_native_heap(logging_enabled ? &sc : nullptr)) {
145
      _num_trims_performed++;
146
      if (logging_enabled) {
147
        double t2 = now();
148
        if (sc.after != SIZE_MAX) {
149
          const size_t delta = sc.after < sc.before ? (sc.before - sc.after) : (sc.after - sc.before);
150
          const char sign = sc.after < sc.before ? '-' : '+';
151
          log_info(trimnative)("Periodic Trim (" UINT64_FORMAT "): " PROPERFMT "->" PROPERFMT " (%c" PROPERFMT ") %.3fms",
152
                               _num_trims_performed,
153
                               PROPERFMTARGS(sc.before), PROPERFMTARGS(sc.after), sign, PROPERFMTARGS(delta),
154
                               to_ms(t2 - t1));
155
        } else {
156
          log_info(trimnative)("Periodic Trim (" UINT64_FORMAT "): complete (no details) %.3fms",
157
                               _num_trims_performed,
158
                               to_ms(t2 - t1));
159
        }
160
      }
161
    }
162
  }
163

164
public:
165

166
  NativeHeapTrimmerThread() :
167
    _lock(new (std::nothrow) PaddedMonitor(Mutex::nosafepoint, "NativeHeapTrimmer_lock")),
168
    _stop(false),
169
    _suspend_count(0),
170
    _num_trims_performed(0)
171
  {
172
    set_name("Native Heap Trimmer");
173
    if (os::create_thread(this, os::vm_thread)) {
174
      os::start_thread(this);
175
    }
176
  }
177

178
  void suspend(const char* reason) {
179
    assert(NativeHeapTrimmer::enabled(), "Only call if enabled");
180
    uint16_t n = 0;
181
    {
182
      MonitorLocker ml(_lock, Mutex::_no_safepoint_check_flag);
183
      n = inc_suspend_count();
184
      // No need to wakeup trimmer
185
    }
186
    log_debug(trimnative)("Trim suspended for %s (%u suspend requests)", reason, n);
187
  }
188

189
  void resume(const char* reason) {
190
    assert(NativeHeapTrimmer::enabled(), "Only call if enabled");
191
    uint16_t n = 0;
192
    {
193
      MonitorLocker ml(_lock, Mutex::_no_safepoint_check_flag);
194
      n = dec_suspend_count();
195
      if (n == 0) {
196
        ml.notify_all(); // pause end
197
      }
198
    }
199
    if (n == 0) {
200
      log_debug(trimnative)("Trim resumed after %s", reason);
201
    } else {
202
      log_debug(trimnative)("Trim still suspended after %s (%u suspend requests)", reason, n);
203
    }
204
  }
205

206
  void stop() {
207
    MonitorLocker ml(_lock, Mutex::_no_safepoint_check_flag);
208
    _stop = true;
209
    ml.notify_all();
210
  }
211

212
  void print_state(outputStream* st) const {
213
    int64_t num_trims = 0;
214
    bool stopped = false;
215
    uint16_t suspenders = 0;
216
    {
217
      // Don't pull lock during error reporting
218
      ConditionalMutexLocker ml(_lock, !VMError::is_error_reported(), Mutex::_no_safepoint_check_flag);
219
      num_trims = _num_trims_performed;
220
      stopped = _stop;
221
      suspenders = _suspend_count;
222
    }
223
    st->print_cr("Trims performed: " UINT64_FORMAT ", current suspend count: %d, stopped: %d",
224
                 num_trims, suspenders, stopped);
225
  }
226

227
}; // NativeHeapTrimmer
228

229
static NativeHeapTrimmerThread* g_trimmer_thread = nullptr;
230

231
void NativeHeapTrimmer::initialize() {
232
  assert(g_trimmer_thread == nullptr, "Only once");
233
  if (TrimNativeHeapInterval > 0) {
234
    if (!os::can_trim_native_heap()) {
235
      FLAG_SET_ERGO(TrimNativeHeapInterval, 0);
236
      log_warning(trimnative)("Native heap trim is not supported on this platform");
237
      return;
238
    }
239
    g_trimmer_thread = new NativeHeapTrimmerThread();
240
    log_info(trimnative)("Periodic native trim enabled (interval: %u ms)", TrimNativeHeapInterval);
241
  }
242
}
243

244
void NativeHeapTrimmer::cleanup() {
245
  if (g_trimmer_thread != nullptr) {
246
    g_trimmer_thread->stop();
247
  }
248
}
249

250
void NativeHeapTrimmer::suspend_periodic_trim(const char* reason) {
251
  if (g_trimmer_thread != nullptr) {
252
    g_trimmer_thread->suspend(reason);
253
  }
254
}
255

256
void NativeHeapTrimmer::resume_periodic_trim(const char* reason) {
257
  if (g_trimmer_thread != nullptr) {
258
    g_trimmer_thread->resume(reason);
259
  }
260
}
261

262
void NativeHeapTrimmer::print_state(outputStream* st) {
263
  if (g_trimmer_thread != nullptr) {
264
    st->print_cr("Periodic native trim enabled (interval: %u ms)", TrimNativeHeapInterval);
265
    g_trimmer_thread->print_state(st);
266
  } else {
267
    st->print_cr("Periodic native trim disabled");
268
  }
269
}
270

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.