mirror of
https://github.com/hanzoai/visor.git
synced 2026-09-24 17:04:14 +00:00
Any writes invalidates the cache line for other threads, so:
- Group fields by writer (Sentry-written, stub-written, both-written)
- Add padding between groups
- Ensure `fastPathDisabled` writes occur only for real bit flips.
Also add tests to ensure the context queue fields align across languages.
Memory usage unchanged. +348 bytes padding, doesn't change number of pages.
Benchmarks:
```
│ before │ after │
│ sec/op │ sec/op vs base │
Syscallbench/syscall.getpid-20 2.255µ ± 0% 2.255µ ± 0% ~ (p=1.000 n=16)
Hackbench/ipcMode.pipe/processMode.thread-20 4.180m ± 0% 3.446m ± 8% -17.57% (p=0.000 n=8)
Redis/operation.SET-20 27.97µ ± 3% 27.77µ ± 2% ~ (p=0.809 n=16)
Redis/operation.LPUSH-20 28.08µ ± 3% 27.66µ ± 4% ~ (p=0.108 n=16)
Redis/operation.LRANGE_100-20 46.25µ ± 2% 46.35µ ± 1% ~ (p=0.817 n=16)
Ffmpeg-20 25.22 ± 1% 25.26 ± 1% ~ (p=0.752 n=16)
IperfOneConnection/operation.Upload-20 2.723µ ± 35% 1.788µ ± 55% ~ (p=0.274 n=16)
IperfOneConnection/operation.Download-20 2.160µ ± 25% 2.134µ ± 23% ~ (p=0.724 n=16)
IperfManyConnections/operation.Upload/parallel.16-20 2.677µ ± 1% 2.668µ ± 1% ~ (p=0.596 n=16)
IperfManyConnections/operation.Download/parallel.16-20 2.618µ ± 2% 2.592µ ± 1% -0.99% (p=0.048 n=16)
NginxDocSize/filesize.1Kb/concurrency.100/filesystem.tmpfs-20 31.44µ ± 2% 30.73µ ± 1% -2.25% (p=0.023 n=16)
NginxDocSize/filesize.1Kb/concurrency.1/filesystem.tmpfs-20 161.6µ ± 2% 159.0µ ± 3% ~ (p=0.491 n=16)
Ruby/concurrency.25-20 192.7µ ± 1% 192.0µ ± 2% ~ (p=0.642 n=16)
geomean 64.70µ 61.31µ -5.24%
│ before │ after │
│ execution_time.s │ execution_time.s vs base │
Hackbench/ipcMode.pipe/processMode.thread-20 7.703 ± 2% 6.232 ± 6% -19.08% (p=0.000 n=8)
│ before │ after │
│ execution_time_per_loop.s │ execution_time_per_loop.s vs base │
Hackbench/ipcMode.pipe/processMode.thread-20 3.851m ± 2% 3.116m ± 6% -19.09% (p=0.000 n=8)
│ before │ after │
│ B/s │ B/s vs base │
IperfOneConnection/operation.Upload-20 44.84Gi ± 54% 68.30Gi ± 35% ~ (p=0.270 n=16)
IperfOneConnection/operation.Download-20 59.25Gi ± 25% 59.78Gi ± 25% ~ (p=0.724 n=16)
IperfManyConnections/operation.Upload/parallel.16-20 45.60Gi ± 1% 45.75Gi ± 1% ~ (p=0.590 n=16)
IperfManyConnections/operation.Download/parallel.16-20 46.63Gi ± 2% 47.10Gi ± 1% ~ (p=0.051 n=16)
geomean 48.75Gi 54.46Gi +11.71%
│ before │ after │
│ bandwidth.bytes_per_second │ bandwidth.bytes_per_second vs base │
IperfOneConnection/operation.Upload-20 4.537G ± 8% 4.537G ± 0% ~ (p=0.956 n=16)
IperfOneConnection/operation.Download-20 2.284G ± 98% 2.670G ± 69% ~ (p=0.809 n=16)
IperfManyConnections/operation.Upload/parallel.16-20 788.9M ± 2% 789.1M ± 0% ~ (p=0.897 n=16)
IperfManyConnections/operation.Download/parallel.16-20 652.2M ± 19% 652.3M ± 19% ~ (p=0.564 n=16)
geomean 1.520G 1.580G +4.00%
│ before │ after │
│ requests_per_second.QPS │ requests_per_second.QPS vs base │
NginxDocSize/filesize.1Kb/concurrency.100/filesystem.tmpfs-20 40.83k ± 2% 41.67k ± 2% +2.04% (p=0.021 n=16)
NginxDocSize/filesize.1Kb/concurrency.1/filesystem.tmpfs-20 8.298k ± 4% 8.460k ± 4% ~ (p=0.539 n=16)
Ruby/concurrency.25-20 6.290k ± 2% 6.256k ± 2% ~ (p=0.918 n=16)
geomean 12.87k 13.02k +1.15%
```
All other benchmarks show no changes after n=16.
56 lines
2.0 KiB
Go
56 lines
2.0 KiB
Go
// Copyright 2026 The gVisor Authors.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package systrap
|
|
|
|
import (
|
|
"testing"
|
|
"unsafe"
|
|
|
|
"gvisor.dev/gvisor/pkg/hostarch"
|
|
)
|
|
|
|
// TestContextQueueLayout ensures layout consistency of contextQueue.
|
|
func TestContextQueueLayout(t *testing.T) {
|
|
var q contextQueue
|
|
const line = uintptr(hostarch.CacheLineSize)
|
|
for _, tc := range []struct {
|
|
field string
|
|
got uintptr
|
|
want uintptr
|
|
}{
|
|
{"end", unsafe.Offsetof(q.end), 0 * line},
|
|
{"start", unsafe.Offsetof(q.start), 1 * line},
|
|
{"fastPathDisabled", unsafe.Offsetof(q.fastPathDisabled), 2 * line},
|
|
{"numAwakeContexts", unsafe.Offsetof(q.numAwakeContexts), 2*line + 4},
|
|
{"numActiveThreads", unsafe.Offsetof(q.numActiveThreads), 3 * line},
|
|
{"numSpinningThreads", unsafe.Offsetof(q.numSpinningThreads), 3*line + 4},
|
|
{"numThreadsToWakeup", unsafe.Offsetof(q.numThreadsToWakeup), 4 * line},
|
|
{"numActiveContexts", unsafe.Offsetof(q.numActiveContexts), 5 * line},
|
|
{"usedFastPath", unsafe.Offsetof(q.usedFastPath), 5*line + 4},
|
|
{"ringbuffer", unsafe.Offsetof(q.ringbuffer), 6 * line},
|
|
} {
|
|
if tc.got != tc.want {
|
|
t.Errorf("unsafe.Offsetof(contextQueue.%s) = %d, want %d", tc.field, tc.got, tc.want)
|
|
}
|
|
}
|
|
if got, want := unsafe.Sizeof(q), 6*line+uintptr(maxContextQueueEntries)*8; got != want {
|
|
t.Errorf("unsafe.Sizeof(contextQueue{}) = %d, want %d", got, want)
|
|
}
|
|
// Go's sync/atomic requires 64-bit words to be 8-byte aligned.
|
|
if off := unsafe.Offsetof(q.ringbuffer); off%8 != 0 {
|
|
t.Errorf("ringbuffer offset %d is not 8-byte aligned", off)
|
|
}
|
|
}
|