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.
39struct 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.
62class G1RegionMarkStatsCache {
63private:
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);
102public:
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