Skip to content

Commit 6b0595d

Browse files
authored
Merge pull request #12117 from gottesmm/fix_multisource_benchmarks
Fix multisource benchmarks
2 parents 0c74e48 + 7a188c6 commit 6b0595d

File tree

6 files changed

+790
-4
lines changed

6 files changed

+790
-4
lines changed

benchmark/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,8 +126,13 @@ set(SWIFT_BENCH_MODULES
126126
)
127127

128128
set(SWIFT_MULTISOURCE_SWIFT3_BENCHES
129+
multi-source/PrimsSplit
129130
)
130131

132+
set(PrimsSplit_sources
133+
multi-source/PrimsSplit/Prims.swift
134+
multi-source/PrimsSplit/main.swift)
135+
131136
set(SWIFT_MULTISOURCE_SWIFT4_BENCHES
132137
)
133138

benchmark/cmake/modules/AddSwiftBenchmarkSuite.cmake

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -327,9 +327,11 @@ function (swift_benchmark_compile_archopts)
327327
endforeach()
328328

329329
foreach(module_name_path ${SWIFT_MULTISOURCE_SWIFT3_BENCHES})
330-
set(objfile_out)
330+
get_filename_component(module_name "${module_name_path}" NAME)
331+
331332
if ("${bench_flags}" MATCHES "-whole-module.*" AND
332333
NOT "${bench_flags}" MATCHES "-num-threads.*")
334+
set(objfile_out)
333335
add_swift_multisource_wmo_benchmark_library(objfile_out
334336
MODULE_PATH "${module_name_path}"
335337
SOURCE_DIR "${srcdir}"
@@ -338,8 +340,9 @@ function (swift_benchmark_compile_archopts)
338340
LIBRARY_FLAGS ${common_swift3_options} ${bench_flags}
339341
DEPENDS ${bench_library_objects} ${stdlib_dependencies})
340342
precondition(objfile_out)
341-
list(APPEND SWIFT_BENCH_OBJFILES "${objfile}")
343+
list(APPEND SWIFT_BENCH_OBJFILES "${objfile_out}")
342344
else()
345+
set(objfiles_out)
343346
add_swift_multisource_nonwmo_benchmark_library(objfiles_out
344347
MODULE_PATH "${module_name_path}"
345348
SOURCE_DIR "${srcdir}"
@@ -353,9 +356,11 @@ function (swift_benchmark_compile_archopts)
353356
endforeach()
354357

355358
foreach(module_name_path ${SWIFT_MULTISOURCE_SWIFT4_BENCHES})
356-
set(objfile_out)
359+
get_filename_component(module_name "${module_name_path}" NAME)
360+
357361
if ("${bench_flags}" MATCHES "-whole-module.*" AND
358362
NOT "${bench_flags}" MATCHES "-num-threads.*")
363+
set(objfile_out)
359364
add_swift_multisource_wmo_benchmark_library(objfile_out
360365
MODULE_PATH "${module_name_path}"
361366
SOURCE_DIR "${srcdir}"
@@ -364,8 +369,9 @@ function (swift_benchmark_compile_archopts)
364369
LIBRARY_FLAGS ${common_swift4_options} ${bench_flags}
365370
DEPENDS ${bench_library_objects} ${stdlib_dependencies})
366371
precondition(objfile_out)
367-
list(APPEND SWIFT_BENCH_OBJFILES "${objfile}")
372+
list(APPEND SWIFT_BENCH_OBJFILES "${objfile_out}")
368373
else()
374+
set(objfiles_out)
369375
add_swift_multisource_nonwmo_benchmark_library(objfiles_out
370376
MODULE_PATH "${module_name_path}"
371377
SOURCE_DIR "${srcdir}"
Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
//===--- Prims.swift ------------------------------------------------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
// The test implements Prim's algorithm for minimum spanning tree building.
14+
// http://en.wikipedia.org/wiki/Prim%27s_algorithm
15+
16+
// This class implements array-based heap (priority queue).
17+
// It is used to store edges from nodes in spanning tree to nodes outside of it.
18+
// We are interested only in the edges with the smallest costs, so if there are
19+
// several edges pointing to the same node, we keep only one from them. Thus,
20+
// it is enough to record this node instead.
21+
// We maintain a map (node index in graph)->(node index in heap) to be able to
22+
// update the heap fast when we add a new node to the tree.
23+
import TestsUtils
24+
25+
class PriorityQueue {
26+
final var heap: Array<EdgeCost>
27+
final var graphIndexToHeapIndexMap: Array<Int?>
28+
29+
// Create heap for graph with NUM nodes.
30+
init(Num: Int) {
31+
heap = Array<EdgeCost>()
32+
graphIndexToHeapIndexMap = Array<Int?>(repeating:nil, count: Num)
33+
}
34+
35+
func isEmpty() -> Bool {
36+
return heap.isEmpty
37+
}
38+
39+
// Insert element N to heap, maintaining the heap property.
40+
func insert(_ n: EdgeCost) {
41+
let ind: Int = heap.count
42+
heap.append(n)
43+
graphIndexToHeapIndexMap[n.to] = heap.count - 1
44+
bubbleUp(ind)
45+
}
46+
47+
// Insert element N if in's not in the heap, or update its cost if the new
48+
// value is less than the existing one.
49+
func insertOrUpdate(_ n: EdgeCost) {
50+
let id = n.to
51+
let c = n.cost
52+
if let ind = graphIndexToHeapIndexMap[id] {
53+
if heap[ind].cost <= c {
54+
// We don't need an edge with a bigger cost
55+
return
56+
}
57+
heap[ind].cost = c
58+
heap[ind].from = n.from
59+
bubbleUp(ind)
60+
} else {
61+
insert(n)
62+
}
63+
}
64+
65+
// Restore heap property by moving element at index IND up.
66+
// This is needed after insertion, and after decreasing an element's cost.
67+
func bubbleUp(_ ind: Int) {
68+
var ind = ind
69+
let c = heap[ind].cost
70+
while (ind != 0) {
71+
let p = getParentIndex(ind)
72+
if heap[p].cost > c {
73+
Swap(p, with: ind)
74+
ind = p
75+
} else {
76+
break
77+
}
78+
}
79+
}
80+
81+
// Pop minimum element from heap and restore the heap property after that.
82+
func pop() -> EdgeCost? {
83+
if (heap.isEmpty) {
84+
return nil
85+
}
86+
Swap(0, with:heap.count-1)
87+
let r = heap.removeLast()
88+
graphIndexToHeapIndexMap[r.to] = nil
89+
bubbleDown(0)
90+
return r
91+
}
92+
93+
// Restore heap property by moving element at index IND down.
94+
// This is needed after removing an element, and after increasing an
95+
// element's cost.
96+
func bubbleDown(_ ind: Int) {
97+
var ind = ind
98+
let n = heap.count
99+
while (ind < n) {
100+
let l = getLeftChildIndex(ind)
101+
let r = getRightChildIndex(ind)
102+
if (l >= n) {
103+
break
104+
}
105+
var min: Int
106+
if (r < n && heap[r].cost < heap[l].cost) {
107+
min = r
108+
} else {
109+
min = l
110+
}
111+
if (heap[ind].cost <= heap[min].cost) {
112+
break
113+
}
114+
Swap(ind, with: min)
115+
ind = min
116+
}
117+
}
118+
119+
// Swaps elements I and J in the heap and correspondingly updates
120+
// graphIndexToHeapIndexMap.
121+
func Swap(_ i: Int, with j : Int) {
122+
if (i == j) {
123+
return
124+
}
125+
(heap[i], heap[j]) = (heap[j], heap[i])
126+
let (I, J) = (heap[i].to, heap[j].to)
127+
(graphIndexToHeapIndexMap[I], graphIndexToHeapIndexMap[J]) =
128+
(graphIndexToHeapIndexMap[J], graphIndexToHeapIndexMap[I])
129+
}
130+
131+
// Dumps the heap.
132+
func dump() {
133+
print("QUEUE")
134+
for nodeCost in heap {
135+
let to: Int = nodeCost.to
136+
let from: Int = nodeCost.from
137+
let cost: Double = nodeCost.cost
138+
print("(\(from)->\(to), \(cost))")
139+
}
140+
}
141+
142+
func getLeftChildIndex(_ index : Int) -> Int {
143+
return index*2 + 1
144+
}
145+
func getRightChildIndex(_ index : Int) -> Int {
146+
return (index + 1)*2
147+
}
148+
func getParentIndex(_ childIndex : Int) -> Int {
149+
return (childIndex - 1)/2
150+
}
151+
}
152+
153+
struct GraphNode {
154+
var id: Int
155+
var adjList: Array<Int>
156+
157+
init(i : Int) {
158+
id = i
159+
adjList = Array<Int>()
160+
}
161+
}
162+
163+
struct EdgeCost {
164+
var to: Int
165+
var cost: Double
166+
var from: Int
167+
}
168+
169+
struct Edge : Equatable {
170+
var start: Int
171+
var end: Int
172+
}
173+
174+
func ==(lhs: Edge, rhs: Edge) -> Bool {
175+
return lhs.start == rhs.start && lhs.end == rhs.end
176+
}
177+
178+
extension Edge : Hashable {
179+
var hashValue: Int {
180+
get {
181+
return start.hashValue ^ end.hashValue
182+
}
183+
}
184+
}
185+
186+
func Prims(_ graph : Array<GraphNode>, _ fun : (Int, Int) -> Double) -> Array<Int?> {
187+
var treeEdges = Array<Int?>(repeating:nil, count:graph.count)
188+
189+
let queue = PriorityQueue(Num:graph.count)
190+
// Make the minimum spanning tree root its own parent for simplicity.
191+
queue.insert(EdgeCost(to: 0, cost: 0.0, from: 0))
192+
193+
// Take an element with the smallest cost from the queue and add its
194+
// neighbors to the queue if their cost was updated
195+
while !queue.isEmpty() {
196+
// Add an edge with minimum cost to the spanning tree
197+
let e = queue.pop()!
198+
let newnode = e.to
199+
// Add record about the edge newnode->e.from to treeEdges
200+
treeEdges[newnode] = e.from
201+
202+
// Check all adjacent nodes and add edges, ending outside the tree, to the
203+
// queue. If the queue already contains an edge to an adjacent node, we
204+
// replace existing one with the new one in case the new one costs less.
205+
for adjNodeIndex in graph[newnode].adjList {
206+
if treeEdges[adjNodeIndex] != nil {
207+
continue
208+
}
209+
let newcost = fun(newnode, graph[adjNodeIndex].id)
210+
queue.insertOrUpdate(EdgeCost(to: adjNodeIndex, cost: newcost, from: newnode))
211+
}
212+
}
213+
return treeEdges
214+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
2+
This test is just a split version of Prims.swift. The reason why this is here is
3+
to provide at least 1 multi-source benchmark for the purpose of validating that
4+
the multi-source benchmarks can build successfully.

0 commit comments

Comments
 (0)