Skip to content

Commit

Permalink
RUMM-1276 PR comments addressed
Browse files Browse the repository at this point in the history
  • Loading branch information
buranmert committed Jun 12, 2021
1 parent 3410029 commit 22c9ba0
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 15 deletions.
13 changes: 11 additions & 2 deletions Sources/Datadog/RUM/RUMVitals/VitalCPUReader.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import Foundation
import UIKit.UIApplication

/// A class reading the CPU ticks (_1 second = 600 ticks_) since the start of the process.
/// A class reading the CPU ticks of the processor.
internal class VitalCPUReader: VitalReader {
/// host_cpu_load_info_count is 4 (tested in iOS 14.4)
private static let host_cpu_load_info_count = MemoryLayout<host_cpu_load_info>.stride / MemoryLayout<integer_t>.stride
Expand All @@ -28,6 +28,9 @@ internal class VitalCPUReader: VitalReader {
return nil
}

// TODO: RUMM-1276 appWillResignActive&appDidBecomeActive are called in main thread
// IF readVitalData() is called from non-main threads, they must be synchronized

@objc
private func appWillResignActive() {
utilizedTicksWhenResigningActive = readUtilizedTicks()
Expand Down Expand Up @@ -60,7 +63,13 @@ internal class VitalCPUReader: VitalReader {
}
}
if result != KERN_SUCCESS {
// TODO: RUMM-1276 use sdkLogger to log errors?
// in case of error, refer to `kern_return.h` (Objc)
// as its Swift interface doesn't have integer values
//
// NOTE: RUMM-1276 consider using sdkLogger.errorOnce(...) to avoid flooding
InternalMonitoringFeature.instance?.monitor.sdkLogger.error(
"CPU Vital cannot be read! Error code: \(result)"
)
return nil
}

Expand Down
36 changes: 23 additions & 13 deletions Tests/DatadogTests/Datadog/RUM/RUMVitals/VitalCPUReaderTest.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,9 @@ class VitalCPUReaderTest: XCTestCase {
let testNotificationCenter = NotificationCenter()
lazy var cpuReader = VitalCPUReader(notificationCenter: testNotificationCenter)

func test_whenCPUUnderHeavyLoad_itMeasuresHigherCPUTicks() throws {
func testWhenCPUUnderHeavyLoadItMeasuresHigherCPUTicks() throws {
let highLoadAverage = try averageCPUTicks {
for _ in 0...500_000 {
let random = Double.random(in: Double.leastNonzeroMagnitude...Double.greatestFiniteMagnitude)
_ = tan(random).squareRoot()
}
heavyLoad()
}

let lowLoadAverage = try averageCPUTicks {
Expand All @@ -27,14 +24,7 @@ class VitalCPUReaderTest: XCTestCase {
XCTAssertGreaterThan(highLoadAverage, lowLoadAverage)
}

func test_whenInactiveAppState_itIggnoresCPUTicks() throws {
let heavyLoad = {
for _ in 0...500_000 {
let random = Double.random(in: Double.leastNonzeroMagnitude...Double.greatestFiniteMagnitude)
_ = tan(random).squareRoot()
}
}

func testWhenInactiveAppStateItIgnoresCPUTicks() throws {
let baseline = try XCTUnwrap(cpuReader.readVitalData())
testNotificationCenter.post(name: UIApplication.willResignActiveNotification, object: nil)
heavyLoad()
Expand All @@ -52,7 +42,9 @@ class VitalCPUReaderTest: XCTestCase {
private func averageCPUTicks(with block: () -> Void) throws -> Double {
let startDate = Date()
let startUtilization = try XCTUnwrap(cpuReader.readVitalData())

block()

let endUtilization = try XCTUnwrap(cpuReader.readVitalData())
let duration = Date().timeIntervalSince(startDate)

Expand All @@ -62,3 +54,21 @@ class VitalCPUReaderTest: XCTestCase {
return utilization
}
}

fileprivate func heavyLoad() {
// cpuTicksResolution is measured by trial&error.
// most of the time `readVitalData()` returns incremented data after 0.01sec.
// however, sometimes it returns the same value for 1.0sec.
// looking at the source code, iOS should update cpu ticks at
// every thread scheduling and/or system->user/user->system mode changes in CPU.
// but empirically, it gets stuck for 1.0sec randomly.
let worstCaseCPUTicksResolution: TimeInterval = 1.0
let startDate = Date()

while Date().timeIntervalSince(startDate) <= worstCaseCPUTicksResolution {
for _ in 0...100_000 {
let random = Double.random(in: Double.leastNonzeroMagnitude...Double.greatestFiniteMagnitude)
_ = tan(random).squareRoot()
}
}
}

0 comments on commit 22c9ba0

Please sign in to comment.