1 | /* |
2 | * Copyright (c) 2018, 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_GC_G1_G1REGIONMARKSTATSCACHE_HPP |
26 | #define SHARE_GC_G1_G1REGIONMARKSTATSCACHE_HPP |
27 | |
28 | #include "memory/allocation.hpp" |
29 | #include "utilities/debug.hpp" |
30 | #include "utilities/globalDefinitions.hpp" |
31 | #include "utilities/pair.hpp" |
32 | |
33 | // Per-Region statistics gathered during marking. |
34 | // |
35 | // This includes |
36 | // * the number of live words gathered during marking for the area from bottom |
37 | // to ntams. This is an exact measure. |
38 | // The code corrects later for the live data between ntams and top. |
39 | struct G1RegionMarkStats { |
40 | size_t _live_words; |
41 | |
42 | // Clear all members. |
43 | void clear() { |
44 | _live_words = 0; |
45 | } |
46 | // Clear all members after a marking overflow. Nothing to do as the live words |
47 | // are updated by the atomic mark. We do not remark objects after overflow. |
48 | void clear_during_overflow() { |
49 | } |
50 | |
51 | bool is_clear() const { return _live_words == 0; } |
52 | }; |
53 | |
54 | // Per-marking thread cache for the region mark statistics. |
55 | // |
56 | // Each cache is a larg'ish map of region-idx -> G1RegionMarkStats entries that cache |
57 | // currently gathered statistics; entries are evicted to the global statistics array |
58 | // on every collision. This minimizes synchronization overhead which would be required |
59 | // every time statistics change, as marking is very localized. |
60 | // The map entry number is a power of two to allow simple and fast hashing using |
61 | // logical and. |
62 | class G1RegionMarkStatsCache { |
63 | private: |
64 | // The array of statistics entries to evict to; the global array. |
65 | G1RegionMarkStats* _target; |
66 | // Number of entries in the eviction target. |
67 | uint _num_stats; |
68 | |
69 | // An entry of the statistics cache. |
70 | struct G1RegionMarkStatsCacheEntry { |
71 | uint _region_idx; |
72 | G1RegionMarkStats _stats; |
73 | |
74 | void clear() { |
75 | _region_idx = 0; |
76 | _stats.clear(); |
77 | } |
78 | |
79 | bool is_clear() const { |
80 | return _region_idx == 0 && _stats.is_clear(); |
81 | } |
82 | }; |
83 | |
84 | // The actual cache and its number of entries. |
85 | G1RegionMarkStatsCacheEntry* _cache; |
86 | uint _num_cache_entries; |
87 | |
88 | // Cache hits/miss counters. |
89 | size_t _cache_hits; |
90 | size_t _cache_misses; |
91 | |
92 | // Evict a given element of the statistics cache. |
93 | void evict(uint idx); |
94 | |
95 | size_t _num_cache_entries_mask; |
96 | |
97 | uint hash(uint idx) { |
98 | return idx & _num_cache_entries_mask; |
99 | } |
100 | |
101 | G1RegionMarkStatsCacheEntry* find_for_add(uint region_idx); |
102 | public: |
103 | G1RegionMarkStatsCache(G1RegionMarkStats* target, uint max_regions, uint num_cache_entries); |
104 | |
105 | ~G1RegionMarkStatsCache(); |
106 | |
107 | void add_live_words(uint region_idx, size_t live_words) { |
108 | G1RegionMarkStatsCacheEntry* const cur = find_for_add(region_idx); |
109 | cur->_stats._live_words += live_words; |
110 | } |
111 | |
112 | void reset(uint region_idx) { |
113 | uint const cache_idx = hash(region_idx); |
114 | G1RegionMarkStatsCacheEntry* cur = &_cache[cache_idx]; |
115 | if (cur->_region_idx == region_idx) { |
116 | _cache[cache_idx].clear(); |
117 | } |
118 | } |
119 | |
120 | // Evict all remaining statistics, returning cache hits and misses. |
121 | Pair<size_t, size_t> evict_all(); |
122 | |
123 | // Reset all cache entries to their default values. |
124 | void reset(); |
125 | |
126 | size_t hits() const { return _cache_hits; } |
127 | size_t misses() const { return _cache_misses; } |
128 | }; |
129 | |
130 | #endif // SHARE_GC_G1_G1REGIONMARKSTATSCACHE_HPP |
131 | |