Repository: airbnb/lottie-ios
File: Tests/PerformanceTests.swift (Swift)

Code before:

  // MARK: Internal

  func testAnimationViewSetup_simpleAnimation() {
    // Compare the performance of displaying this simple animation in the two animation engines
    let ratio = compareEngineSetupPerformance(for: simpleAnimation, iterations: 2000)

    // This is basically a snapshot test for the performance of the Core Animation engine
    // compared to the Main Thread engine. Currently, the Core Animation engine is
    // about 1.6x slower than the Main Thread engine in this example.
    XCTAssertEqual(ratio, 1.6, accuracy: 0.2)
  }

  func testAnimationViewSetup_complexAnimation() {
    let ratio = compareEngineSetupPerformance(for: complexAnimation, iterations: 500)
    XCTAssertEqual(ratio, 1.75, accuracy: 0.3)
  }

  func testAnimationViewScrubbing_simpleAnimation() {
    let ratio = compareEngineScrubbingPerformance(for: simpleAnimation, iterations: 1000)
    XCTAssertEqual(ratio, 0.05, accuracy: 0.02)
  }

  func testAnimationViewScrubbing_complexAnimation() {
    let ratio = compareEngineScrubbingPerformance(for: complexAnimation, iterations: 1000)
    XCTAssertEqual(ratio, 0.002, accuracy: 0.001)
  }

  // MARK: Private

  private let simpleAnimation = Animation.named(
    "loading_dots_1",
    bundle: .module,
    subdirectory: "Samples/LottieFiles")!

  private let complexAnimation = Animation.named(
    "LottieLogo2",
    bundle: .module,
    subdirectory: "Samples")!

  /// Compares initializing the given animation with both the Main Thread and Core Animation engine,
  /// and returns the ratio of how much slower the Core Animation is than the Main Thread engine
  private func compareEngineSetupPerformance(for animation: Animation, iterations: Int) -> Double {
    let mainThreadEnginePerformance = measurePerformance {
      for _ in 0 ..< iterations {
        setupAnimationView(with: animation, configuration: .init(renderingEngine: .mainThread))
      }
    }

    print("Main thread engine took \(mainThreadEnginePerformance) seconds")


Review comment (suggestion):
I was pretty impressed with this number -- interactively scrubbing the current frame of a complex animation in the new rendering engine is up to 500x faster than in the main thread engine

Code after:

  // MARK: Internal

  func testAnimationViewSetup_simpleAnimation() {
    // Compare the performance of displaying this simple animation in the two animation engines
    let ratio = compareEngineSetupPerformance(for: simpleAnimation, iterations: 2000)

    // This is basically a snapshot test for the performance of the Core Animation engine
    // compared to the Main Thread engine. Currently, the Core Animation engine is
    // about the same speed as the Main Thread engine in this example.
    XCTAssertEqual(ratio, 1.0, accuracy: 0.15)
  }

  func testAnimationViewSetup_complexAnimation() {
    let ratio = compareEngineSetupPerformance(for: complexAnimation, iterations: 500)

    // The Core Animation engine is currently about 1.6x slower than the
    // Main Thread engine in this example.
    XCTAssertEqual(ratio, 1.6, accuracy: 0.3)
  }

  func testAnimationViewScrubbing_simpleAnimation() {
    let ratio = compareEngineScrubbingPerformance(for: simpleAnimation, iterations: 2000)
    XCTAssertEqual(ratio, 0.002, accuracy: 0.001)
  }

  func testAnimationViewScrubbing_complexAnimation() {
    let ratio = compareEngineScrubbingPerformance(for: complexAnimation, iterations: 2000)
    XCTAssertEqual(ratio, 0.0005, accuracy: 0.00035)
  }

  override func setUp() {
    TestHelpers.performanceTestsAreRunning = true
  }

  override func tearDown() {
    TestHelpers.performanceTestsAreRunning = false
  }

  // MARK: Private

  private let simpleAnimation = Animation.named(
    "loading_dots_1",
    bundle: .module,
    subdirectory: "Samples/LottieFiles")!

  private let complexAnimation = Animation.named(
    "LottieLogo2",
    bundle: .module,
    subdirectory: "Samples")!