1 | /* |
2 | * Copyright (c) 1997, 2019, 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 | |
25 | #ifndef SHARE_RUNTIME_SWEEPER_HPP |
26 | #define SHARE_RUNTIME_SWEEPER_HPP |
27 | |
28 | class WhiteBox; |
29 | |
30 | #include "code/codeCache.hpp" |
31 | #include "utilities/ticks.hpp" |
32 | |
33 | class CodeBlobClosure; |
34 | |
35 | // An NmethodSweeper is an incremental cleaner for: |
36 | // - cleanup inline caches |
37 | // - reclamation of nmethods |
38 | // Removing nmethods from the code cache includes two operations |
39 | // 1) mark active nmethods |
40 | // Is done in 'mark_active_nmethods()'. This function is called at a |
41 | // safepoint and marks all nmethods that are active on a thread's stack. |
42 | // 2) sweep nmethods |
43 | // Is done in sweep_code_cache(). This function is the only place in the |
44 | // sweeper where memory is reclaimed. Note that sweep_code_cache() is not |
45 | // called at a safepoint. However, sweep_code_cache() stops executing if |
46 | // another thread requests a safepoint. Consequently, 'mark_active_nmethods()' |
47 | // and sweep_code_cache() cannot execute at the same time. |
48 | // To reclaim memory, nmethods are first marked as 'not-entrant'. Methods can |
49 | // be made not-entrant by (i) the sweeper, (ii) deoptimization, (iii) dependency |
50 | // invalidation, and (iv) being replaced by a different method version (tiered |
51 | // compilation). Not-entrant nmethods cannot be called by Java threads, but they |
52 | // can still be active on the stack. To ensure that active nmethods are not reclaimed, |
53 | // we have to wait until the next marking phase has completed. If a not-entrant |
54 | // nmethod was NOT marked as active, it can be converted to 'zombie' state. To safely |
55 | // remove the nmethod, all inline caches (IC) that point to the nmethod must be |
56 | // cleared. After that, the nmethod can be evicted from the code cache. Each nmethod's |
57 | // state change happens during separate sweeps. It may take at least 3 sweeps before an |
58 | // nmethod's space is freed. |
59 | |
60 | class NMethodSweeper : public AllStatic { |
61 | private: |
62 | enum MethodStateChange { |
63 | None, |
64 | MadeZombie, |
65 | Flushed |
66 | }; |
67 | static long _traversals; // Stack scan count, also sweep ID. |
68 | static long _total_nof_code_cache_sweeps; // Total number of full sweeps of the code cache |
69 | static long _time_counter; // Virtual time used to periodically invoke sweeper |
70 | static long _last_sweep; // Value of _time_counter when the last sweep happened |
71 | static CompiledMethodIterator _current; // Current compiled method |
72 | static int _seen; // Nof. nmethod we have currently processed in current pass of CodeCache |
73 | |
74 | static volatile int _sweep_started; // Flag to control conc sweeper |
75 | static volatile bool _should_sweep; // Indicates if we should invoke the sweeper |
76 | static volatile bool _force_sweep; // Indicates if we should force a sweep |
77 | static volatile int _bytes_changed; // Counts the total nmethod size if the nmethod changed from: |
78 | // 1) alive -> not_entrant |
79 | // 2) not_entrant -> zombie |
80 | // Stat counters |
81 | static long _total_nof_methods_reclaimed; // Accumulated nof methods flushed |
82 | static long _total_nof_c2_methods_reclaimed; // Accumulated nof C2-compiled methods flushed |
83 | static size_t _total_flushed_size; // Total size of flushed methods |
84 | static int _hotness_counter_reset_val; |
85 | |
86 | static Tickspan _total_time_sweeping; // Accumulated time sweeping |
87 | static Tickspan _total_time_this_sweep; // Total time this sweep |
88 | static Tickspan _peak_sweep_time; // Peak time for a full sweep |
89 | static Tickspan _peak_sweep_fraction_time; // Peak time sweeping one fraction |
90 | |
91 | static MethodStateChange process_compiled_method(CompiledMethod *nm); |
92 | |
93 | static void init_sweeper_log() NOT_DEBUG_RETURN; |
94 | static bool wait_for_stack_scanning(); |
95 | static void sweep_code_cache(); |
96 | static void handle_safepoint_request(); |
97 | static void do_stack_scanning(); |
98 | static void possibly_sweep(); |
99 | public: |
100 | static long traversal_count() { return _traversals; } |
101 | static int total_nof_methods_reclaimed() { return _total_nof_methods_reclaimed; } |
102 | static const Tickspan total_time_sweeping() { return _total_time_sweeping; } |
103 | static const Tickspan peak_sweep_time() { return _peak_sweep_time; } |
104 | static const Tickspan peak_sweep_fraction_time() { return _peak_sweep_fraction_time; } |
105 | static void log_sweep(const char* msg, const char* format = NULL, ...) ATTRIBUTE_PRINTF(2, 3); |
106 | |
107 | |
108 | #ifdef ASSERT |
109 | // Keep track of sweeper activity in the ring buffer |
110 | static void record_sweep(CompiledMethod* nm, int line); |
111 | static void report_events(int id, address entry); |
112 | static void report_events(); |
113 | #endif |
114 | |
115 | static void mark_active_nmethods(); // Invoked at the end of each safepoint |
116 | static CodeBlobClosure* prepare_mark_active_nmethods(); |
117 | static CodeBlobClosure* prepare_reset_hotness_counters(); |
118 | static void sweeper_loop(); |
119 | static void notify(int code_blob_type); // Possibly start the sweeper thread. |
120 | static void force_sweep(); |
121 | |
122 | static int hotness_counter_reset_val(); |
123 | static void report_state_change(nmethod* nm); |
124 | static void possibly_enable_sweeper(); |
125 | static void possibly_flush(nmethod* nm); |
126 | static void print(outputStream* out); // Printing/debugging |
127 | static void print() { print(tty); } |
128 | }; |
129 | |
130 | #endif // SHARE_RUNTIME_SWEEPER_HPP |
131 | |