Skip to content

Commit c71e170

Browse files
gjcairoktoso
authored andcommitted
Fix potential arithmetic errors in CPUUsageCalculator
1 parent fedae66 commit c71e170

File tree

3 files changed

+27
-7
lines changed

3 files changed

+27
-7
lines changed

Sources/SystemMetrics/SystemMetrics.swift

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -276,10 +276,10 @@ public enum SystemMetrics {
276276
/// CPU usage is calculated as the number of CPU ticks used by this process between measurements.
277277
/// - Note: the first measurement will be calculated since the process' start time, since there's no
278278
/// previous measurement to take as reference.
279-
private struct CPUUsageCalculator {
279+
internal struct CPUUsageCalculator {
280280
/// The number of ticks after system boot that the last CPU usage stat was taken.
281281
private var previousTicksSinceSystemBoot: Int = 0
282-
/// The number of ticks the process actively used the CPU, as of the previous CPU usage measurement.
282+
/// The number of ticks the process actively used the CPU for, as of the previous CPU usage measurement.
283283
private var previousCPUTicks: Int = 0
284284

285285
mutating func getUsagePercentage(ticksSinceSystemBoot: Int, cpuTicks: Int) -> Double {
@@ -288,6 +288,10 @@ public enum SystemMetrics {
288288
self.previousCPUTicks = cpuTicks
289289
}
290290
let ticksBetweenMeasurements = ticksSinceSystemBoot - self.previousTicksSinceSystemBoot
291+
guard ticksBetweenMeasurements > 0 else {
292+
return 0
293+
}
294+
291295
let cpuTicksBetweenMeasurements = cpuTicks - self.previousCPUTicks
292296
return Double(cpuTicksBetweenMeasurements) * 100 / Double(ticksBetweenMeasurements)
293297
}
@@ -371,7 +375,8 @@ public enum SystemMetrics {
371375
var cpuUsage: Double = 0
372376
if cpuTicks > 0 {
373377
guard let uptimeString = uptimeFileContents.split(separator: " ").first,
374-
let uptimeSeconds = Float(uptimeString)
378+
let uptimeSeconds = Float(uptimeString),
379+
uptimeSeconds.isFinite
375380
else { return nil }
376381
let uptimeTicks = Int(ceilf(uptimeSeconds)) * ticks
377382
cpuUsage = SystemMetrics.cpuUsageCalculator.getUsagePercentage(ticksSinceSystemBoot: uptimeTicks, cpuTicks: cpuTicks)

Tests/SystemMetricsTests/SystemMetricsTests+XCTest.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ extension SystemMetricsTest {
2828
("testSystemMetricsGeneration", testSystemMetricsGeneration),
2929
("testSystemMetricsLabels", testSystemMetricsLabels),
3030
("testSystemMetricsConfiguration", testSystemMetricsConfiguration),
31+
("testCPUUsageCalculator", testCPUUsageCalculator),
3132
]
3233
}
3334
}

Tests/SystemMetricsTests/SystemMetricsTests.swift

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,6 @@ class SystemMetricsTest: XCTestCase {
2121
func testSystemMetricsGeneration() throws {
2222
#if os(Linux)
2323
let _metrics = SystemMetrics.linuxSystemMetrics()
24-
#else
25-
let _metrics = SystemMetrics.noopSystemMetrics()
26-
throw XCTSkip()
27-
#endif
2824
XCTAssertNotNil(_metrics)
2925
let metrics = _metrics!
3026
XCTAssertNotNil(metrics.virtualMemoryBytes)
@@ -34,6 +30,9 @@ class SystemMetricsTest: XCTestCase {
3430
XCTAssertNotNil(metrics.maxFileDescriptors)
3531
XCTAssertNotNil(metrics.openFileDescriptors)
3632
XCTAssertNotNil(metrics.cpuUsage)
33+
#else
34+
throw XCTSkip()
35+
#endif
3736
}
3837

3938
func testSystemMetricsLabels() throws {
@@ -89,4 +88,19 @@ class SystemMetricsTest: XCTestCase {
8988
XCTAssertFalse(configuration.dimensions.contains(where: { $0 == ("environment", "staging") }))
9089
XCTAssertFalse(configuration.dimensions.contains(where: { $0 == ("process", "example") }))
9190
}
91+
92+
func testCPUUsageCalculator() throws {
93+
#if os(Linux)
94+
var calculator = SystemMetrics.CPUUsageCalculator()
95+
var usage = calculator.getUsagePercentage(ticksSinceSystemBoot: 0, cpuTicks: 0)
96+
XCTAssertFalse(usage.isNaN)
97+
XCTAssertEqual(usage, 0)
98+
99+
usage = calculator.getUsagePercentage(ticksSinceSystemBoot: 20, cpuTicks: 10)
100+
XCTAssertFalse(usage.isNaN)
101+
XCTAssertEqual(usage, 50)
102+
#else
103+
throw XCTSkip()
104+
#endif
105+
}
92106
}

0 commit comments

Comments
 (0)