1 /*
2  * Copyright (c) 2019, 2021, 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/shared/gc_globals.hpp"
26 #include "gc/z/zHeap.inline.hpp"
27 #include "gc/z/zLock.inline.hpp"
28 #include "gc/z/zStat.hpp"
29 #include "gc/z/zUncommitter.hpp"
30 #include "jfr/jfrEvents.hpp"
31 #include "logging/log.hpp"
32 
33 static const ZStatCounter ZCounterUncommit("Memory", "Uncommit", ZStatUnitBytesPerSecond);
34 
ZUncommitter(ZPageAllocator * page_allocator)35 ZUncommitter::ZUncommitter(ZPageAllocator* page_allocator) :
36     _page_allocator(page_allocator),
37     _lock(),
38     _stop(false) {
39   set_name("ZUncommitter");
40   create_and_start();
41 }
42 
wait(uint64_t timeout) const43 bool ZUncommitter::wait(uint64_t timeout) const {
44   ZLocker<ZConditionLock> locker(&_lock);
45   while (!ZUncommit && !_stop) {
46     _lock.wait();
47   }
48 
49   if (!_stop && timeout > 0) {
50     log_debug(gc, heap)("Uncommit Timeout: " UINT64_FORMAT "s", timeout);
51     _lock.wait(timeout * MILLIUNITS);
52   }
53 
54   return !_stop;
55 }
56 
should_continue() const57 bool ZUncommitter::should_continue() const {
58   ZLocker<ZConditionLock> locker(&_lock);
59   return !_stop;
60 }
61 
run_service()62 void ZUncommitter::run_service() {
63   uint64_t timeout = 0;
64 
65   while (wait(timeout)) {
66     EventZUncommit event;
67     size_t uncommitted = 0;
68 
69     while (should_continue()) {
70       // Uncommit chunk
71       const size_t flushed = _page_allocator->uncommit(&timeout);
72       if (flushed == 0) {
73         // Done
74         break;
75       }
76 
77       uncommitted += flushed;
78     }
79 
80     if (uncommitted > 0) {
81       // Update statistics
82       ZStatInc(ZCounterUncommit, uncommitted);
83       log_info(gc, heap)("Uncommitted: " SIZE_FORMAT "M(%.0f%%)",
84                          uncommitted / M, percent_of(uncommitted, ZHeap::heap()->max_capacity()));
85 
86       // Send event
87       event.commit(uncommitted);
88     }
89   }
90 }
91 
stop_service()92 void ZUncommitter::stop_service() {
93   ZLocker<ZConditionLock> locker(&_lock);
94   _stop = true;
95   _lock.notify_all();
96 }
97