BenchmarkUtils.swift 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. /*
  2. * Copyright 2021, gRPC Authors All rights reserved.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. import Dispatch
  17. /// The results of a benchmark.
  18. struct BenchmarkResults {
  19. /// The description of the benchmark.
  20. var desc: String
  21. /// The duration of each run of the benchmark in milliseconds.
  22. var milliseconds: [UInt64]
  23. }
  24. extension BenchmarkResults: CustomStringConvertible {
  25. var description: String {
  26. return "\(self.desc): \(self.milliseconds.map(String.init).joined(separator: ","))"
  27. }
  28. }
  29. /// Runs the benchmark and prints the duration in milliseconds for each run.
  30. ///
  31. /// - Parameters:
  32. /// - description: A description of the benchmark.
  33. /// - benchmark: The benchmark which should be run.
  34. /// - spec: The specification for the test run.
  35. func measureAndPrint(description: String, benchmark: Benchmark, spec: TestSpec) {
  36. switch spec.action {
  37. case .list:
  38. print(description)
  39. case let .run(filter):
  40. guard filter.shouldRun(description) else {
  41. return
  42. }
  43. #if CACHEGRIND
  44. _ = measure(description, benchmark: benchmark, repeats: 1)
  45. #else
  46. print(measure(description, benchmark: benchmark, repeats: spec.repeats))
  47. #endif
  48. }
  49. }
  50. /// Runs the given benchmark multiple times, recording the wall time for each iteration.
  51. ///
  52. /// - Parameters:
  53. /// - description: A description of the benchmark.
  54. /// - benchmark: The benchmark to run.
  55. /// - repeats: the number of times to run the benchmark.
  56. func measure(_ description: String, benchmark: Benchmark, repeats: Int) -> BenchmarkResults {
  57. var milliseconds: [UInt64] = []
  58. for _ in 0 ..< repeats {
  59. do {
  60. try benchmark.setUp()
  61. #if !CACHEGRIND
  62. let start = DispatchTime.now().uptimeNanoseconds
  63. #endif
  64. _ = try benchmark.run()
  65. #if !CACHEGRIND
  66. let end = DispatchTime.now().uptimeNanoseconds
  67. milliseconds.append((end - start) / 1_000_000)
  68. #endif
  69. } catch {
  70. // If tearDown fails now then there's not a lot we can do!
  71. try? benchmark.tearDown()
  72. return BenchmarkResults(desc: description, milliseconds: [])
  73. }
  74. do {
  75. try benchmark.tearDown()
  76. } catch {
  77. return BenchmarkResults(desc: description, milliseconds: [])
  78. }
  79. }
  80. return BenchmarkResults(desc: description, milliseconds: milliseconds)
  81. }