5
5
package sync
6
6
7
7
import (
8
+ "internal/cpu"
8
9
"internal/race"
9
10
"runtime"
10
11
"sync/atomic"
@@ -76,6 +77,7 @@ type poolLocal struct {
76
77
}
77
78
78
79
// from runtime
80
+ //
79
81
//go:linkname runtime_randn runtime.randn
80
82
func runtime_randn (n uint32 ) uint32
81
83
@@ -221,8 +223,9 @@ func (p *Pool) pinSlow() (*poolLocal, int) {
221
223
// Retry under the mutex.
222
224
// Can not lock the mutex while pinned.
223
225
runtime_procUnpin ()
224
- allPoolsMu .Lock ()
225
- defer allPoolsMu .Unlock ()
226
+ a := & allPools [uintptr (unsafe .Pointer (p ))% shardPoolsSize ]
227
+ a .lock .Lock ()
228
+ defer a .lock .Unlock ()
226
229
pid := runtime_procPin ()
227
230
// poolCleanup won't be called while we are pinned.
228
231
s := p .localSize
@@ -231,7 +234,7 @@ func (p *Pool) pinSlow() (*poolLocal, int) {
231
234
return indexLocal (l , pid ), pid
232
235
}
233
236
if p .local == nil {
234
- allPools = append (allPools , p )
237
+ a . s = append (a . s , p )
235
238
}
236
239
// If GOMAXPROCS changes between GCs, we re-allocate the array and lose the old one.
237
240
size := runtime .GOMAXPROCS (0 )
@@ -249,35 +252,47 @@ func poolCleanup() {
249
252
// pinned section (in effect, this has all Ps pinned).
250
253
251
254
// Drop victim caches from all pools.
252
- for _ , p := range oldPools {
253
- p .victim = nil
254
- p .victimSize = 0
255
+ for i , s := range oldPools {
256
+ for _ , p := range s .s {
257
+ p .victim = nil
258
+ p .victimSize = 0
259
+ }
260
+ oldPools [i ].s = nil
255
261
}
256
262
257
263
// Move primary cache to victim cache.
258
- for _ , p := range allPools {
259
- p .victim = p .local
260
- p .victimSize = p .localSize
261
- p .local = nil
262
- p .localSize = 0
264
+ for i := range allPools {
265
+ for _ , p := range allPools [i ].s {
266
+ p .victim = p .local
267
+ p .victimSize = p .localSize
268
+ p .local = nil
269
+ p .localSize = 0
270
+ }
271
+ oldPools [i ].s = allPools [i ].s
272
+ allPools [i ].s = nil
263
273
}
264
274
265
275
// The pools with non-empty primary caches now have non-empty
266
276
// victim caches and no pools have primary caches.
267
- oldPools , allPools = allPools , nil
268
277
}
269
278
270
- var (
271
- allPoolsMu Mutex
279
+ const shardPoolsSize = 256
272
280
281
+ var (
273
282
// allPools is the set of pools that have non-empty primary
274
283
// caches. Protected by either 1) allPoolsMu and pinning or 2)
275
284
// STW.
276
- allPools []* Pool
285
+ allPools [shardPoolsSize ]struct {
286
+ lock Mutex
287
+ s []* Pool
288
+ _ [cpu .CacheLinePadSize - unsafe .Sizeof ([]* Pool {}) - unsafe .Sizeof (Mutex {})]int8
289
+ }
277
290
278
291
// oldPools is the set of pools that may have non-empty victim
279
292
// caches. Protected by STW.
280
- oldPools []* Pool
293
+ oldPools [shardPoolsSize ]struct {
294
+ s []* Pool
295
+ }
281
296
)
282
297
283
298
func init () {
0 commit comments