forked from swiftlang/swift
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathExclusivity.swift
138 lines (123 loc) · 3.39 KB
/
Exclusivity.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
//===--- Exclusivity.swift -------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2021 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// A set of tests for measuring the enforcement overhead of memory access
// exclusivity rules.
//
//===----------------------------------------------------------------------===//
import TestsUtils
public let benchmarks = [
// At -Onone
// 25% swift_beginAccess
// 15% tlv_get_addr
// 15% swift_endAccess
BenchmarkInfo(
name: "ExclusivityGlobal",
runFunction: run_accessGlobal,
tags: [.runtime, .cpubench]
),
// At -Onone
// 23% swift_retain
// 22% swift_release
// 9% swift_beginAccess
// 3% swift_endAccess
BenchmarkInfo(
name: "ExclusivityInMatSet",
runFunction: run_accessInMatSet,
tags: [.runtime, .cpubench, .unstable]
),
// At -Onone
// 25% swift_release
// 23% swift_retain
// 16% swift_beginAccess
// 8% swift_endAccess
BenchmarkInfo(
name: "ExclusivityIndependent",
runFunction: run_accessIndependent,
tags: [.runtime, .cpubench]
),
]
// Initially these benchmarks only measure access checks at -Onone. In
// the future, access checks will also be emitted at -O.
// Measure memory access checks on a trivial global.
// ---
public var globalCounter: Int = 0
// TODO:
// - Merge begin/endAccess when no calls intervene (~2x speedup).
// - Move Swift runtime into the OS (~2x speedup).
// - Whole module analysis can remove exclusivity checks (> 10x speedup now, 4x speedup with runtime in OS).
// (The global's "public" qualifier should make the benchmark immune to this optimization.)
@inline(never)
public func run_accessGlobal(_ n: Int) {
globalCounter = 0
for _ in 1...10000*n {
globalCounter += 1
}
check(globalCounter == 10000*n)
}
// Measure memory access checks on a class property.
//
// Note: The end_unpaired_access forces a callback on the property's
// materializeForSet!
// ---
// Hopefully the optimizer will not see this as "final" and optimize away the
// materializeForSet.
public class C {
public var counter = 0
func inc() {
counter += 1
}
}
// Thunk
@inline(never)
func updateClass(_ c: C) {
c.inc()
}
// TODO: Replacing materializeForSet accessors with yield-once
// accessors should make the callback overhead go away.
@inline(never)
public func run_accessInMatSet(_ n: Int) {
let c = C()
for _ in 1...10000*n {
updateClass(c)
}
check(c.counter == 10000*n)
}
// Measure nested access to independent objects.
//
// A single access set is still faster than hashing for up to four accesses.
// ---
struct Var {
var val = 0
}
@inline(never)
func update(a: inout Var, b: inout Var, c: inout Var, d: inout Var) {
a.val += 1
b.val += 1
c.val += 1
d.val += 1
}
@inline(never)
public func run_accessIndependent(_ n: Int) {
var a = Var()
var b = Var()
var c = Var()
var d = Var()
let updateVars = {
update(a: &a, b: &b, c: &c, d: &d)
}
for _ in 1...1000*n {
updateVars()
}
check(a.val == 1000*n && b.val == 1000*n && c.val == 1000*n
&& d.val == 1000*n)
}