Skip to content

Commit 4b2c6c0

Browse files
committed
Add a test for testing the runtime function counters functionality
1 parent a590e49 commit 4b2c6c0

File tree

1 file changed

+256
-0
lines changed

1 file changed

+256
-0
lines changed
Lines changed: 256 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,256 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-build-swift %s -o %t/test_runtime_function_counters
3+
// RUN: %target-run %t/test_runtime_function_counters 2>&1 | %FileCheck %s
4+
// REQUIRES: asserts
5+
// REQUIRES: executable_test
6+
7+
/// Test functionality related to the runtime function counters.
8+
9+
class C {
10+
var next: C? = nil
11+
func test(_ c: C) {
12+
}
13+
}
14+
15+
struct MyStruct {
16+
var ref1: AnyObject? = C()
17+
var ref2: AnyObject = C()
18+
var str: String = ""
19+
}
20+
21+
public final class List<T> {
22+
var value: T
23+
var next: List<T>?
24+
25+
init(_ value: T) {
26+
self.value = value
27+
self.next = nil
28+
}
29+
30+
init(_ value: T, _ tail: List<T>) {
31+
self.value = value
32+
self.next = tail
33+
}
34+
}
35+
36+
public func length<T>(_ l: List<T>) -> Int {
37+
var ll: List<T>? = l
38+
var len = 0
39+
while ll != nil {
40+
len = len + 1
41+
ll = ll?.next
42+
}
43+
return len
44+
}
45+
46+
/// CHECK-LABEL: TEST: Collect references inside objects
47+
/// Constant strings do not have an owner, thus no references.
48+
/// CHECK: Constant string: []
49+
/// An array has one reference
50+
/// CHECK: Array<Int>: [{{[0-9a-fA-Fx]+}}]
51+
/// MyStruct has two references
52+
/// CHECK: MyStruct: [{{[0-9a-fA-Fx]+}}, {{[0-9a-fA-Fx]+}}]
53+
/// Dictionary has once reference
54+
/// CHECK: Dictionary<Int, Int>: [{{[0-9a-fA-Fx]+}}]
55+
/// Set has once reference
56+
/// CHECK: Set<Int>: [{{[0-9a-fA-Fx]+}}]
57+
/// Test collection of references inside different types of objects.
58+
@inline(never)
59+
func testCollectReferencesInsideObject() {
60+
print("TEST: Collect references inside objects")
61+
let s = "MyString"
62+
let aint = [1,2,3,4]
63+
let dint = [1:1, 2:2]
64+
let sint: Set<Int> = [1,2,3,4]
65+
66+
print("Constant string: \(_collectReferencesInsideObject(s))")
67+
print("Array<Int>: \(_collectReferencesInsideObject(aint))")
68+
print("MyStruct: \(_collectReferencesInsideObject(MyStruct()))")
69+
print("Dictionary<Int, Int>: \(_collectReferencesInsideObject(dint))")
70+
print("Set<Int>: \(_collectReferencesInsideObject(sint))")
71+
72+
var mystring = "MyString"
73+
mystring.append("End")
74+
testString(mystring)
75+
testDict(dint)
76+
testObjectCycle()
77+
}
78+
79+
80+
/// CHECK-LABEL: TEST: APIs from _RuntimeFunctionCounters
81+
/// CHECK: Number of runtime function pointers:
82+
/// Test some APIs from _RuntimeFunctionCounters
83+
func testRuntimeCounters() {
84+
print("TEST: APIs from _RuntimeFunctionCounters")
85+
let numRuntimeFunctionPointer =
86+
_RuntimeFunctionCounters.getNumRuntimeFunctionCounters()
87+
88+
print("Number of runtime function pointers: \(numRuntimeFunctionPointer)")
89+
90+
let names = _RuntimeFunctionCounters.getRuntimeFunctionNames()
91+
let offsets = _RuntimeFunctionCounters.getRuntimeFunctionCountersOffsets()
92+
93+
for i in 0..<numRuntimeFunctionPointer {
94+
print("Runtime function \(i) : \(names[i]) at offset: \(offsets[i])")
95+
}
96+
97+
var d: [Int : Int] = [:]
98+
let globalCounters1 = _GlobalRuntimeFunctionCountersState()
99+
100+
for i in 0..<50 {
101+
let k = i
102+
let v = i*i
103+
d[k] = v
104+
}
105+
106+
let globalCounters2 = _GlobalRuntimeFunctionCountersState()
107+
108+
globalCounters1.dumpDiff(globalCounters2)
109+
}
110+
111+
/// Test finding references inside a String object.
112+
@inline(never)
113+
func testString(_ s: String) {
114+
print("TEST: Collect references for strings")
115+
let refs = _collectReferencesInsideObject(s)
116+
print("References are: \(refs)")
117+
let objectCounters1 = _ObjectRuntimeFunctionCountersState(refs[0])
118+
let _ = [String](repeating: s, count: 4)
119+
let objectCounters2 = _ObjectRuntimeFunctionCountersState(refs[0])
120+
objectCounters1.dumpDiff(objectCounters2)
121+
}
122+
123+
/// Test finding references inside a Dictionary object.
124+
@inline(never)
125+
func testDict(_ _dint: [Int : Int]) {
126+
print("TEST: Collect references for dictionaries")
127+
var dint = _dint
128+
dint[3] = 3
129+
let refs = _collectReferencesInsideObject(dint)
130+
print("References are: \(refs)")
131+
let objectCounters1 = _ObjectRuntimeFunctionCountersState(refs[0])
132+
dint[222] = 222
133+
dint[2222] = 2222
134+
let objectCounters2 = _ObjectRuntimeFunctionCountersState(refs[0])
135+
objectCounters1.dumpDiff(objectCounters2)
136+
}
137+
138+
/// Test finding references inside an object graph with a cycle.
139+
/// It should not result in a stack overflow.
140+
@inline(never)
141+
func testObjectCycle() {
142+
print("TEST: Collect references on object graph with cycles")
143+
print("testObjectCycle")
144+
let c1 = C()
145+
let c2 = C()
146+
c1.next = c1
147+
c2.next = c1
148+
let refs = _collectReferencesInsideObject(c1)
149+
print("References are: \(refs)")
150+
let objectCounters1 = _ObjectRuntimeFunctionCountersState(refs[0])
151+
c1.next = nil
152+
c2.next = nil
153+
let objectCounters2 = _ObjectRuntimeFunctionCountersState(refs[0])
154+
objectCounters1.dumpDiff(objectCounters2, skipUnchanged: true)
155+
}
156+
157+
/// Test runtime function counters for a List object.
158+
@inline(never)
159+
func testLists() {
160+
print("TEST: Runtime function counters for Lists")
161+
print("testLists")
162+
let globalCounters1 = _GlobalRuntimeFunctionCountersState()
163+
var l: List<Int>? = List(1, List(2, List(3, List(4, List(5)))))
164+
let refs = _collectReferencesInsideObject(l!)
165+
let globalCounters11 = _GlobalRuntimeFunctionCountersState()
166+
let _ = _collectReferencesInsideObject(l!)
167+
let globalCounters111 = _GlobalRuntimeFunctionCountersState()
168+
169+
print("Global counters diff for 11")
170+
globalCounters1.dumpDiff(globalCounters11, skipUnchanged: true)
171+
print("Global counters diff for 111")
172+
globalCounters1.dumpDiff(globalCounters111, skipUnchanged: true)
173+
174+
let len = length(l!)
175+
let globalCounters2 = _GlobalRuntimeFunctionCountersState()
176+
print("Length of the list is \(len)")
177+
print("Global counters diff after constructing a list and computing its length")
178+
globalCounters1.dumpDiff(globalCounters2, skipUnchanged: true)
179+
let objectCounters1 = _ObjectRuntimeFunctionCountersState(refs[0])
180+
l = nil
181+
let objectCounters2 = _ObjectRuntimeFunctionCountersState(refs[0])
182+
print("List head counters after list becomes unreferenced")
183+
objectCounters1.dumpDiff(objectCounters2, skipUnchanged: true)
184+
}
185+
186+
/// Test the _measureRuntimeFunctionCountersDiffs API.
187+
@inline(never)
188+
func testMeasureRuntimeFunctionCountersDiffs() {
189+
print("TEST: Measure runtime function counters diff")
190+
let l: List<Int>? = List(1, List(2, List(3, List(4, List(5)))))
191+
let refs = _collectReferencesInsideObject(l!)
192+
var len = 0
193+
let (globalCounters, objectsCountersDiffs) =
194+
_measureRuntimeFunctionCountersDiffs(objects: [refs[0]]) {
195+
len = length(l!)
196+
}
197+
print("List length is: \(len)")
198+
print("Global counters changes")
199+
globalCounters.dump(skipUnchanged: true)
200+
print("Objects counters changes")
201+
for (i, objectCounters) in objectsCountersDiffs.enumerated() {
202+
print("Object counters diff for \(refs[i])")
203+
objectCounters.dump(skipUnchanged: true)
204+
}
205+
}
206+
207+
/// This is a handler that is invoked on each runtime functions counters update.
208+
@inline(never)
209+
func updatesHandler(object: UnsafeRawPointer, functionId: Int64) {
210+
let savedMode = _RuntimeFunctionCounters.disableRuntimeFunctionCountersUpdates()
211+
print("Start handler")
212+
let functionName = _RuntimeFunctionCounters.runtimeFunctionNames[Int(functionId)]
213+
print("Function \(functionName) was invoked on object \(object)")
214+
print("End handler")
215+
_RuntimeFunctionCounters.enableRuntimeFunctionCountersUpdates(mode: savedMode)
216+
}
217+
218+
/// CHECK-LABEL: TEST: Provide runtime function counters update handler
219+
/// TEST: Start handler
220+
/// TEST: End handler
221+
/// Test that you can provide custom handlers for runtime functions counters
222+
/// updates.
223+
@inline(never)
224+
func testFunctionRuntimeCountersUpdateHandler() {
225+
print("TEST: Provide runtime function counters update handler")
226+
let l: List<Int>? = List(1, List(2, List(3, List(4, List(5)))))
227+
let oldHandler =
228+
_RuntimeFunctionCounters.setGlobalRuntimeFunctionCountersUpdateHandler(
229+
handler: updatesHandler)
230+
let len = length(l!)
231+
_ = _RuntimeFunctionCounters.setGlobalRuntimeFunctionCountersUpdateHandler(
232+
handler: oldHandler)
233+
print("Restored old handler")
234+
print(len)
235+
}
236+
237+
/// Enable runtime function counters stats collection.
238+
_RuntimeFunctionCounters.enableRuntimeFunctionCountersUpdates()
239+
240+
/// Test collection of references inside different types of objects.
241+
testCollectReferencesInsideObject()
242+
243+
/// Test some APIs from _RuntimeFunctionCounters.
244+
testRuntimeCounters()
245+
246+
/// Test dumping of counters for all objects.
247+
_RuntimeFunctionCounters.dumpObjectsRuntimeFunctionPointers()
248+
249+
/// Test runtime function counters for a List object.
250+
testLists()
251+
252+
/// Test the _measureRuntimeFunctionCountersDiffs API.
253+
testMeasureRuntimeFunctionCountersDiffs()
254+
255+
/// Test that you can provide custom handlers for runtime functions counters updates.
256+
testFunctionRuntimeCountersUpdateHandler()

0 commit comments

Comments
 (0)