Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

### Fixes

- Normalize profiling cpu usage to percent (#7798)
- Detect development builds via provisioning profile and debugger attachment (#7702)
- Keep replayType as `buffer` for Session Replay triggered by an error (#7804)
- Fix race condition in scope observer notifications causing EXC_BAD_ACCESS during cold launch (#7807)
Expand Down
12 changes: 11 additions & 1 deletion Sources/Sentry/SentrySystemWrapper.mm
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
# import <mach/mach.h>
# include <thread>

@interface SentrySystemWrapper ()
+ (float)normalizeCPUUsage:(integer_t)threadCPUUsage processorCount:(long)processorCount;
@end

@implementation SentrySystemWrapper {
float processorCount;
}
Expand Down Expand Up @@ -42,6 +46,11 @@ - (SentryRAMBytes)memoryFootprintBytes:(NSError *__autoreleasing _Nullable *)err
return footprintBytes;
}

+ (float)normalizeCPUUsage:(integer_t)threadCPUUsage processorCount:(long)processorCount
{
return (static_cast<float>(threadCPUUsage) / TH_USAGE_SCALE) * 100.f / processorCount;
}

- (NSNumber *)cpuUsageWithError:(NSError **)error
{
mach_msg_type_number_t count;
Expand Down Expand Up @@ -76,7 +85,8 @@ - (NSNumber *)cpuUsageWithError:(NSError **)error
return nil;
}

usage += data.cpu_usage / processorCount;
usage += [SentrySystemWrapper normalizeCPUUsage:data.cpu_usage
processorCount:static_cast<long>(processorCount)];
}

vm_deallocate(mach_task_self(), reinterpret_cast<vm_address_t>(list), sizeof(*list) * count);
Expand Down
13 changes: 10 additions & 3 deletions Sources/Sentry/include/SentrySystemWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,19 @@ typedef mach_vm_size_t SentryRAMBytes;
- (SentryRAMBytes)memoryFootprintBytes:(NSError **)error;

/**
* @return The CPU usage per core, where the order of results corresponds to the core number as
* returned by the underlying system call, e.g. @c @[ @c <core-0-CPU-usage>, @c <core-1-CPU-usage>,
* @c ...] .
* @return The CPU usage of this process as a percentage of the device's total CPU capacity,
* normalized to a range from @c 0.0 to @c 100.0.
Comment thread
sentry[bot] marked this conversation as resolved.
*/
- (nullable NSNumber *)cpuUsageWithError:(NSError **)error;

# if defined(SENTRY_TEST) || defined(SENTRY_TEST_CI)
/**
* Test-only helper that normalizes a thread CPU usage value returned by Mach to the
* process's percentage of the device's total CPU capacity.
*/
+ (float)normalizeCPUUsage:(integer_t)threadCPUUsage processorCount:(long)processorCount;
# endif

// Only some architectures support reading energy.
# if defined(__arm__) || defined(__arm64__)
/**
Expand Down
16 changes: 11 additions & 5 deletions Tests/SentryProfilerTests/SentrySystemWrapperTests.swift
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import Foundation
import XCTest

#if os(iOS) || os(macOS)
Expand All @@ -7,11 +8,16 @@ class SentrySystemWrapperTests: XCTestCase {
}
lazy private var fixture = Fixture()

func testCPUUsageReportsData() throws {
XCTAssertNoThrow({
let cpuUsage = try XCTUnwrap(self.fixture.systemWrapper.cpuUsage())
XCTAssertTrue((0.0 ... 100.0).contains(cpuUsage.doubleValue))
})
func testCPUUsage_whenIdle_shouldReportNormalizedPercent() throws {
let cpuUsage = try XCTUnwrap(fixture.systemWrapper.cpuUsage())

XCTAssertTrue((0.0 ... 100.0).contains(cpuUsage.doubleValue))
}

func testNormalizeCPUUsage_shouldConvertMachScaleToPercentOfTotalCapacity() {
XCTAssertEqual(SentrySystemWrapper.normalizeCPUUsage(1_000, processorCount: 4), 25.0, accuracy: 0.001)
XCTAssertEqual(SentrySystemWrapper.normalizeCPUUsage(500, processorCount: 8), 6.25, accuracy: 0.001)
XCTAssertEqual(SentrySystemWrapper.normalizeCPUUsage(1_000, processorCount: 10), 10.0, accuracy: 0.001)
}

func testMemoryFootprint() {
Expand Down
Loading