Sometimes, Xcode Test cannot meet our need, so we need to write the testing function mannully. The main of testing function is measure time of code. Whether it is testing a CPU/GPU-intensive program or a read-write-intensive program, it is necessary to obtain the running time of the program or function to calculate performance.
If you measure the CLI (Command Line Interface) program, you can get the running time of the entire program by time
command. But if you want to test the running time of a function in the program code, or test a GUI program, this method will not work. We need to add a “timer” to the code to schedule the measurement work mannully.
There are two ways to implement this measurement in Swift. The first is more convenient but only can use on new systems. The second is more compatible but unsafe (the accuracy is slightly worse, but it can be ignored).
measure
After iOS 16 and macOS 13, Apple added new data structures Clock
and ContinuousClock
, both of which have a method measure
, which can be used to test the running time of a function.
It’s also very simple to use.
First, create a instance ContinuousClock
:
let clock = ContinuousClock()
Then use the following statement to get the running time of a function:
let elapsed = clock.measure {
someWork()
}
Notice, let
is mandatory. You cannot declare a variable before and then instantiate it here.
The elapsed
here is of type ContinuousClock.Instant.Duration
and needs to be converted into a string for use. The conversion method is as follows:
var duration: String = ""
let elapsed = clock.measure {
quicksort()
}
//elapsed.description is String
duration = elapsed.description
The entire code is:
struct ContentView: View {
var clock = ContinuousClock()
@State private var duration: String = ""
var body: some View {
VStack {
// Press button to quicksort
Text("点击按钮进行快速排序测试:")
.padding()
Button(action: {
// Get time interval, it is running time
let elapsed = clock.measure {
// test function is quicksort
quicksort()
}
// Convert time interval to String
duration = elapsed.description
}) {
Text("Start")
}
.padding()
// Display running time. Because elapsed.description end with string "second", din't add any suffix
Text("消耗时间为:\(duration)")
.padding()
}
.padding()
}
}
Here’s what it looks like when running in the app:
If it is not the latest system or you want to write related method functions by yourself, you can use the classic method: time difference. Record the start time and end time, and then make subtraction to get the running time.
So what is this time based on? The C language can use clock time to measure single thread function, but Swift only has clock time starting from iOS 16. Before that, only have Date
type. Fortunately, Date
can achieve our purpose, just use the timeIntervalSince1970
value.
The value timeIntervalSince1970
is a historical value. All systems (not just Apple systems) have this value, because 1970 is the starting time of Unix, or call “Unix Time”, and timeIntervalSince1970
is recorded time from 1970-01-01 00:00:00 to this moment. The accuracy can reach the decimal point to milliseconds (or even smaller, and the accuracy is similar to the previous method).
Since only one part is different from the previous method, the entire code is listed directly:
struct ContentView: View {
@State private var duration: String = ""
var body: some View {
VStack {
Text("点击按钮进行快速排序测试:")
.padding()
Button(action: {
// Record start time
let start_time = Date().timeIntervalSince1970
// run function measured
quicksort()
// Record end time
let end_time = Date().timeIntervalSince1970
//make subtraction to get the running time, and convert to String
duration = TimeInterval(end_time-start_time).description
}) {
Text("Start")
}
.padding()
// Because no suffix, so we add "seconds" here
Text("消耗时间为:\(duration) seconds")
.padding()
}
.padding()
}
}
The running effect is same as the previous method, so I don’t show here.
I hope these will help someone in need~