Skip to content

Commit 573e552

Browse files
authored
Merge pull request swiftlang#30049 from gottesmm/pr-84af955fa93e4646656fdbeff3a2df1e1a5399ea
2 parents 9ae6813 + 583b2b0 commit 573e552

File tree

1 file changed

+233
-1
lines changed

1 file changed

+233
-1
lines changed

benchmark/single-source/PrimsNonStrongRef.swift

Lines changed: 233 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,23 @@ public let PrimsNonStrongRef: [BenchmarkInfo] = ({
3535
var benchmarks: [BenchmarkInfo] = []
3636
#if false
3737
// TODO: Stabilize weak benchmark.
38-
benchmarks..append(BenchmarkInfo(
38+
benchmarks.append(BenchmarkInfo(
3939
name: "Prims.NonStrongRef.Weak",
4040
runFunction: run_PrimsWeak,
4141
tags: [.validation, .algorithm],
4242
setUpFunction: {
4343
touchGlobalInfo()
4444
blackHole(weakPrimsState)
4545
}))
46+
// TODO: Stabilize weak benchmark.
47+
benchmarks.append(BenchmarkInfo(
48+
name: "Prims.NonStrongRef.Weak.Closure",
49+
runFunction: run_PrimsWeakClosureAccess,
50+
tags: [.validation, .algorithm],
51+
setUpFunction: {
52+
touchGlobalInfo()
53+
blackHole(weakPrimsState)
54+
}))
4655
#endif
4756
benchmarks.append(BenchmarkInfo(
4857
name: "Prims.NonStrongRef.UnownedSafe",
@@ -52,6 +61,14 @@ public let PrimsNonStrongRef: [BenchmarkInfo] = ({
5261
touchGlobalInfo()
5362
blackHole(unownedSafePrimsState)
5463
}))
64+
benchmarks.append(BenchmarkInfo(
65+
name: "Prims.NonStrongRef.UnownedSafe.Closure",
66+
runFunction: run_PrimsUnownedSafeClosureAccess,
67+
tags: [.validation, .algorithm],
68+
setUpFunction: {
69+
touchGlobalInfo()
70+
blackHole(unownedSafePrimsState)
71+
}))
5572
benchmarks.append(BenchmarkInfo(
5673
name: "Prims.NonStrongRef.UnownedUnsafe",
5774
runFunction: run_PrimsUnownedUnsafe,
@@ -60,6 +77,14 @@ public let PrimsNonStrongRef: [BenchmarkInfo] = ({
6077
touchGlobalInfo()
6178
blackHole(unownedUnsafePrimsState)
6279
}))
80+
benchmarks.append(BenchmarkInfo(
81+
name: "Prims.NonStrongRef.UnownedUnsafe.Closure",
82+
runFunction: run_PrimsUnownedUnsafeClosureAccess,
83+
tags: [.validation, .algorithm],
84+
setUpFunction: {
85+
touchGlobalInfo()
86+
blackHole(unownedUnsafePrimsState)
87+
}))
6388
benchmarks.append(BenchmarkInfo(
6489
name: "Prims.NonStrongRef.Unmanaged",
6590
runFunction: run_PrimsUnmanaged,
@@ -68,6 +93,30 @@ public let PrimsNonStrongRef: [BenchmarkInfo] = ({
6893
touchGlobalInfo()
6994
blackHole(unmanagedPrimsState)
7095
}))
96+
benchmarks.append(BenchmarkInfo(
97+
name: "Prims.NonStrongRef.Unmanaged.Closure",
98+
runFunction: run_PrimsUnmanagedClosureAccess,
99+
tags: [.validation, .algorithm, .api],
100+
setUpFunction: {
101+
touchGlobalInfo()
102+
blackHole(unmanagedPrimsState)
103+
}))
104+
benchmarks.append(BenchmarkInfo(
105+
name: "Prims.NonStrongRef.UnmanagedUGR",
106+
runFunction: run_PrimsUnmanagedUGR,
107+
tags: [.validation, .algorithm, .api],
108+
setUpFunction: {
109+
touchGlobalInfo()
110+
blackHole(unmanagedUGRPrimsState)
111+
}))
112+
benchmarks.append(BenchmarkInfo(
113+
name: "Prims.NonStrongRef.UnmanagedUGR.Closure",
114+
runFunction: run_PrimsUnmanagedUGRClosureAccess,
115+
tags: [.validation, .algorithm, .api],
116+
setUpFunction: {
117+
touchGlobalInfo()
118+
blackHole(unmanagedUGRPrimsState)
119+
}))
71120
return benchmarks
72121
})()
73122

@@ -617,6 +666,7 @@ let weakPrimsState = PrimsState(WeakGraphNode.self)
617666
let unownedSafePrimsState = PrimsState(UnownedSafeGraphNode.self)
618667
let unownedUnsafePrimsState = PrimsState(UnownedUnsafeGraphNode.self)
619668
let unmanagedPrimsState = PrimsState(UnmanagedGraphNode.self)
669+
let unmanagedUGRPrimsState = PrimsState(UnmanagedUGRGraphNode.self)
620670

621671
//===----------------------------------------------------------------------===//
622672
// Protocols
@@ -628,11 +678,16 @@ protocol ValueBox : Hashable {
628678
init(_ inputValue: ValueType)
629679
var value: ValueType { get }
630680

681+
func withValue<Result>(_ f: (ValueType) throws -> Result) rethrows -> Result
631682
func free()
632683
}
633684

634685
extension ValueBox {
635686
func free() {}
687+
@_transparent
688+
func withValue<Result>(_ f: (ValueType) throws -> Result) rethrows -> Result {
689+
return try f(value)
690+
}
636691
}
637692

638693
protocol GraphNode {
@@ -727,6 +782,46 @@ extension UnmanagedVarBox : Hashable where T : Hashable {
727782
}
728783
}
729784

785+
struct UnmanagedUGRVarBox<T : AnyObject & Hashable> {
786+
var _value: Unmanaged<T>
787+
788+
init(_ inputValue: T) {
789+
_value = Unmanaged<T>.passRetained(inputValue)
790+
}
791+
}
792+
793+
extension UnmanagedUGRVarBox : ValueBox where T : GraphNode {
794+
typealias ValueType = T
795+
796+
func free() {
797+
_value.release()
798+
}
799+
800+
var value: T { return _value._withUnsafeGuaranteedRef { $0 } }
801+
802+
func withValue<Result>(_ f: (ValueType) throws -> Result) rethrows -> Result {
803+
try _value._withUnsafeGuaranteedRef { try f($0) }
804+
}
805+
}
806+
807+
extension UnmanagedUGRVarBox : Equatable where T : Equatable {
808+
}
809+
810+
func ==<T>(lhs: UnmanagedUGRVarBox<T>, rhs: UnmanagedUGRVarBox<T>) -> Bool {
811+
return lhs._value._withUnsafeGuaranteedRef { x in
812+
return rhs._value._withUnsafeGuaranteedRef { y in
813+
return x == y
814+
}}
815+
}
816+
817+
extension UnmanagedUGRVarBox : Hashable where T : Hashable {
818+
func hash(into hasher: inout Hasher) {
819+
_value._withUnsafeGuaranteedRef {
820+
hasher.combine(ObjectIdentifier($0))
821+
}
822+
}
823+
}
824+
730825
//===----------------------------------------------------------------------===//
731826
// Graph Node Implementations
732827
//===----------------------------------------------------------------------===//
@@ -849,6 +944,41 @@ func ==(lhs: UnmanagedGraphNode, rhs: UnmanagedGraphNode) -> Bool {
849944
return lhs === rhs
850945
}
851946

947+
948+
final class UnmanagedUGRGraphNode {
949+
/// This id is only meant for dumping the state of the graph. It is not meant
950+
/// to be used functionally by the algorithm.
951+
var id: Int
952+
953+
var adjList: Array<UnmanagedUGRVarBox<UnmanagedUGRGraphNode>>
954+
955+
init(id inputId: Int) {
956+
id = inputId
957+
adjList = Array<UnmanagedUGRVarBox<UnmanagedUGRGraphNode>>()
958+
}
959+
960+
deinit {
961+
for x in adjList {
962+
x.free()
963+
}
964+
}
965+
}
966+
967+
extension UnmanagedUGRGraphNode : GraphNode {
968+
typealias BoxType = UnmanagedUGRVarBox<UnmanagedUGRGraphNode>
969+
}
970+
971+
extension UnmanagedUGRGraphNode : Equatable {}
972+
extension UnmanagedUGRGraphNode : Hashable {
973+
func hash(into hasher: inout Hasher) {
974+
hasher.combine(ObjectIdentifier(self))
975+
}
976+
}
977+
978+
func ==(lhs: UnmanagedUGRGraphNode, rhs: UnmanagedUGRGraphNode) -> Bool {
979+
return lhs === rhs
980+
}
981+
852982
//===----------------------------------------------------------------------===//
853983
// Edge Implementation
854984
//===----------------------------------------------------------------------===//
@@ -1054,6 +1184,41 @@ where Node.BoxType == Box, Box.ValueType == Node
10541184
return treeEdges
10551185
}
10561186

1187+
func primsMainLoopClosureAccess<Node : GraphNode, Box>(
1188+
_ graph : Array<Node>,
1189+
_ fun : (Node.BoxType, Node.BoxType) -> Double) -> Array<Int?>
1190+
where Node.BoxType == Box, Box.ValueType == Node
1191+
{
1192+
var treeEdges = Array<Int?>(repeating:nil, count:graph.count)
1193+
let queue = PriorityQueue<Node>(count: graph.count)
1194+
1195+
// Make the minimum spanning tree root its own parent for simplicity.
1196+
queue.insert(EdgeCost(to: graph[0], cost: 0.0, from: graph[0]))
1197+
1198+
// Take an element with the smallest cost from the queue and add its
1199+
// neighbors to the queue if their cost was updated
1200+
while !queue.isEmpty {
1201+
// Add an edge with minimum cost to the spanning tree
1202+
let e = queue.pop()!
1203+
let newnode: Node.BoxType = e.to
1204+
1205+
// Add record about the edge newnode->e.from to treeEdges
1206+
treeEdges[newnode.withValue { $0.id }] = e.from.withValue { $0.id }
1207+
1208+
// Check all adjacent nodes and add edges, ending outside the tree, to the
1209+
// queue. If the queue already contains an edge to an adjacent node, we
1210+
// replace existing one with the new one in case the new one costs less.
1211+
for toNode: Box in (newnode.withValue { $0.adjList }) {
1212+
if treeEdges[toNode.withValue { $0.id }] != nil {
1213+
continue
1214+
}
1215+
let newcost = fun(newnode, toNode)
1216+
queue.insertOrUpdate(EdgeCost(to: toNode, cost: newcost, from: newnode))
1217+
}
1218+
}
1219+
return treeEdges
1220+
}
1221+
10571222
//===----------------------------------------------------------------------===//
10581223
// Top Level Entrypoints
10591224
//===----------------------------------------------------------------------===//
@@ -1079,6 +1244,25 @@ func run_PrimsNonStrongRef<Node: GraphNode, Box>(_ state: PrimsState<Node, Box>)
10791244
CheckResults(Int(cost) == 49324)
10801245
}
10811246

1247+
@inline(__always)
1248+
func run_PrimsNonStrongRefClosureAccess<Node: GraphNode, Box>(_ state: PrimsState<Node, Box>) where Node.BoxType == Box, Box.ValueType == Node {
1249+
let graph = state.graph
1250+
let map = state.edgeToCostMap
1251+
1252+
// Find spanning tree
1253+
let treeEdges = primsMainLoopClosureAccess(graph, { (start: Box, end: Box) in
1254+
return map[Edge(start: start, end: end)]!
1255+
})
1256+
1257+
// Compute its cost in order to check results
1258+
var cost = 0.0
1259+
for i in 1..<treeEdges.count {
1260+
if let n = treeEdges[i] {
1261+
cost += map[Edge(start: Box(graph[n]), end: Box(graph[i]))]!
1262+
}
1263+
}
1264+
CheckResults(Int(cost) == 49324)
1265+
}
10821266

10831267

10841268
@inline(never)
@@ -1089,6 +1273,14 @@ public func run_PrimsWeak(_ N: Int) {
10891273
}
10901274
}
10911275

1276+
@inline(never)
1277+
public func run_PrimsWeakClosureAccess(_ N: Int) {
1278+
let state = weakPrimsState
1279+
for _ in 0..<N {
1280+
run_PrimsNonStrongRefClosureAccess(state)
1281+
}
1282+
}
1283+
10921284
@inline(never)
10931285
public func run_PrimsUnownedSafe(_ N: Int) {
10941286
let state = unownedSafePrimsState
@@ -1097,6 +1289,14 @@ public func run_PrimsUnownedSafe(_ N: Int) {
10971289
}
10981290
}
10991291

1292+
@inline(never)
1293+
public func run_PrimsUnownedSafeClosureAccess(_ N: Int) {
1294+
let state = unownedSafePrimsState
1295+
for _ in 0..<N {
1296+
run_PrimsNonStrongRefClosureAccess(state)
1297+
}
1298+
}
1299+
11001300
@inline(never)
11011301
public func run_PrimsUnownedUnsafe(_ N: Int) {
11021302
let state = unownedUnsafePrimsState
@@ -1105,10 +1305,42 @@ public func run_PrimsUnownedUnsafe(_ N: Int) {
11051305
}
11061306
}
11071307

1308+
@inline(never)
1309+
public func run_PrimsUnownedUnsafeClosureAccess(_ N: Int) {
1310+
let state = unownedUnsafePrimsState
1311+
for _ in 0..<N {
1312+
run_PrimsNonStrongRefClosureAccess(state)
1313+
}
1314+
}
1315+
11081316
@inline(never)
11091317
public func run_PrimsUnmanaged(_ N: Int) {
11101318
let state = unmanagedPrimsState
11111319
for _ in 0..<N {
11121320
run_PrimsNonStrongRef(state)
11131321
}
11141322
}
1323+
1324+
@inline(never)
1325+
public func run_PrimsUnmanagedClosureAccess(_ N: Int) {
1326+
let state = unmanagedPrimsState
1327+
for _ in 0..<N {
1328+
run_PrimsNonStrongRefClosureAccess(state)
1329+
}
1330+
}
1331+
1332+
@inline(never)
1333+
public func run_PrimsUnmanagedUGR(_ N: Int) {
1334+
let state = unmanagedUGRPrimsState
1335+
for _ in 0..<N {
1336+
run_PrimsNonStrongRef(state)
1337+
}
1338+
}
1339+
1340+
@inline(never)
1341+
public func run_PrimsUnmanagedUGRClosureAccess(_ N: Int) {
1342+
let state = unmanagedUGRPrimsState
1343+
for _ in 0..<N {
1344+
run_PrimsNonStrongRefClosureAccess(state)
1345+
}
1346+
}

0 commit comments

Comments
 (0)