1 /*
2  * Copyright (c) 2016, 2018, 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/z/zMarkStack.inline.hpp"
26 #include "gc/z/zMarkStackAllocator.hpp"
27 #include "logging/log.hpp"
28 #include "utilities/debug.hpp"
29 #include "utilities/powerOfTwo.hpp"
30 
ZMarkStripe()31 ZMarkStripe::ZMarkStripe() :
32     _published(),
33     _overflowed() {}
34 
ZMarkStripeSet()35 ZMarkStripeSet::ZMarkStripeSet() :
36     _nstripes(0),
37     _nstripes_mask(0),
38     _stripes() {}
39 
set_nstripes(size_t nstripes)40 void ZMarkStripeSet::set_nstripes(size_t nstripes) {
41   assert(is_power_of_2(nstripes), "Must be a power of two");
42   assert(is_power_of_2(ZMarkStripesMax), "Must be a power of two");
43   assert(nstripes >= 1, "Invalid number of stripes");
44   assert(nstripes <= ZMarkStripesMax, "Invalid number of stripes");
45 
46   _nstripes = nstripes;
47   _nstripes_mask = nstripes - 1;
48 
49   log_debug(gc, marking)("Using " SIZE_FORMAT " mark stripes", _nstripes);
50 }
51 
is_empty() const52 bool ZMarkStripeSet::is_empty() const {
53   for (size_t i = 0; i < _nstripes; i++) {
54     if (!_stripes[i].is_empty()) {
55       return false;
56     }
57   }
58 
59   return true;
60 }
61 
stripe_for_worker(uint nworkers,uint worker_id)62 ZMarkStripe* ZMarkStripeSet::stripe_for_worker(uint nworkers, uint worker_id) {
63   const size_t spillover_limit = (nworkers / _nstripes) * _nstripes;
64   size_t index;
65 
66   if (worker_id < spillover_limit) {
67     // Not a spillover worker, use natural stripe
68     index = worker_id & _nstripes_mask;
69   } else {
70     // Distribute spillover workers evenly across stripes
71     const size_t spillover_nworkers = nworkers - spillover_limit;
72     const size_t spillover_worker_id = worker_id - spillover_limit;
73     const double spillover_chunk = (double)_nstripes / (double)spillover_nworkers;
74     index = spillover_worker_id * spillover_chunk;
75   }
76 
77   assert(index < _nstripes, "Invalid index");
78   return &_stripes[index];
79 }
80 
ZMarkThreadLocalStacks()81 ZMarkThreadLocalStacks::ZMarkThreadLocalStacks() :
82     _magazine(NULL) {
83   for (size_t i = 0; i < ZMarkStripesMax; i++) {
84     _stacks[i] = NULL;
85   }
86 }
87 
is_empty(const ZMarkStripeSet * stripes) const88 bool ZMarkThreadLocalStacks::is_empty(const ZMarkStripeSet* stripes) const {
89   for (size_t i = 0; i < stripes->nstripes(); i++) {
90     ZMarkStack* const stack = _stacks[i];
91     if (stack != NULL) {
92       return false;
93     }
94   }
95 
96   return true;
97 }
98 
allocate_stack(ZMarkStackAllocator * allocator)99 ZMarkStack* ZMarkThreadLocalStacks::allocate_stack(ZMarkStackAllocator* allocator) {
100   if (_magazine == NULL) {
101     // Allocate new magazine
102     _magazine = allocator->alloc_magazine();
103     if (_magazine == NULL) {
104       return NULL;
105     }
106   }
107 
108   ZMarkStack* stack = NULL;
109 
110   if (!_magazine->pop(stack)) {
111     // Magazine is empty, convert magazine into a new stack
112     _magazine->~ZMarkStackMagazine();
113     stack = new ((void*)_magazine) ZMarkStack();
114     _magazine = NULL;
115   }
116 
117   return stack;
118 }
119 
free_stack(ZMarkStackAllocator * allocator,ZMarkStack * stack)120 void ZMarkThreadLocalStacks::free_stack(ZMarkStackAllocator* allocator, ZMarkStack* stack) {
121   for (;;) {
122     if (_magazine == NULL) {
123       // Convert stack into a new magazine
124       stack->~ZMarkStack();
125       _magazine = new ((void*)stack) ZMarkStackMagazine();
126       return;
127     }
128 
129     if (_magazine->push(stack)) {
130       // Success
131       return;
132     }
133 
134     // Free and uninstall full magazine
135     allocator->free_magazine(_magazine);
136     _magazine = NULL;
137   }
138 }
139 
push_slow(ZMarkStackAllocator * allocator,ZMarkStripe * stripe,ZMarkStack ** stackp,ZMarkStackEntry entry,bool publish)140 bool ZMarkThreadLocalStacks::push_slow(ZMarkStackAllocator* allocator,
141                                        ZMarkStripe* stripe,
142                                        ZMarkStack** stackp,
143                                        ZMarkStackEntry entry,
144                                        bool publish) {
145   ZMarkStack* stack = *stackp;
146 
147   for (;;) {
148     if (stack == NULL) {
149       // Allocate and install new stack
150       *stackp = stack = allocate_stack(allocator);
151       if (stack == NULL) {
152         // Out of mark stack memory
153         return false;
154       }
155     }
156 
157     if (stack->push(entry)) {
158       // Success
159       return true;
160     }
161 
162     // Publish/Overflow and uninstall stack
163     stripe->publish_stack(stack, publish);
164     *stackp = stack = NULL;
165   }
166 }
167 
pop_slow(ZMarkStackAllocator * allocator,ZMarkStripe * stripe,ZMarkStack ** stackp,ZMarkStackEntry & entry)168 bool ZMarkThreadLocalStacks::pop_slow(ZMarkStackAllocator* allocator,
169                                       ZMarkStripe* stripe,
170                                       ZMarkStack** stackp,
171                                       ZMarkStackEntry& entry) {
172   ZMarkStack* stack = *stackp;
173 
174   for (;;) {
175     if (stack == NULL) {
176       // Try steal and install stack
177       *stackp = stack = stripe->steal_stack();
178       if (stack == NULL) {
179         // Nothing to steal
180         return false;
181       }
182     }
183 
184     if (stack->pop(entry)) {
185       // Success
186       return true;
187     }
188 
189     // Free and uninstall stack
190     free_stack(allocator, stack);
191     *stackp = stack = NULL;
192   }
193 }
194 
flush(ZMarkStackAllocator * allocator,ZMarkStripeSet * stripes)195 bool ZMarkThreadLocalStacks::flush(ZMarkStackAllocator* allocator, ZMarkStripeSet* stripes) {
196   bool flushed = false;
197 
198   // Flush all stacks
199   for (size_t i = 0; i < stripes->nstripes(); i++) {
200     ZMarkStripe* const stripe = stripes->stripe_at(i);
201     ZMarkStack** const stackp = &_stacks[i];
202     ZMarkStack* const stack = *stackp;
203     if (stack == NULL) {
204       continue;
205     }
206 
207     // Free/Publish and uninstall stack
208     if (stack->is_empty()) {
209       free_stack(allocator, stack);
210     } else {
211       stripe->publish_stack(stack);
212       flushed = true;
213     }
214     *stackp = NULL;
215   }
216 
217   return flushed;
218 }
219 
free(ZMarkStackAllocator * allocator)220 void ZMarkThreadLocalStacks::free(ZMarkStackAllocator* allocator) {
221   // Free and uninstall magazine
222   if (_magazine != NULL) {
223     allocator->free_magazine(_magazine);
224     _magazine = NULL;
225   }
226 }
227