Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: measure cpu energy usage estimates #3217

Merged
Merged
Show file tree
Hide file tree
Changes from 2 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
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Changelog

## Unreleased

### Features

- Record energy usage estimates for profiling (#3217)

## 8.9.4

Expand Down
36 changes: 36 additions & 0 deletions Sources/Sentry/SentryMetricProfiler.mm
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

NSString *const kSentryMetricProfilerSerializationKeyMemoryFootprint = @"memory_footprint";
NSString *const kSentryMetricProfilerSerializationKeyCPUUsageFormat = @"cpu_usage_%d";
NSString *const kSentryMetricProfilerSerializationKeyCPUEnergyUsage = @"cpu_energy_usage";

NSString *const kSentryMetricProfilerSerializationUnitBytes = @"byte";
NSString *const kSentryMetricProfilerSerializationUnitPercentage = @"percent";
Expand Down Expand Up @@ -82,6 +83,9 @@
NSMutableDictionary<NSNumber *, NSMutableArray<SentryMetricReading *> *> *_cpuUsage;

NSMutableArray<SentryMetricReading *> *_memoryFootprint;

NSNumber *previousEnergyReading;
NSMutableArray<SentryMetricReading *> *_cpuEnergyUsage;
}

- (instancetype)init
Expand All @@ -98,6 +102,7 @@
}

_memoryFootprint = [NSMutableArray<SentryMetricReading *> array];
_cpuEnergyUsage = [NSMutableArray<SentryMetricReading *> array];
}
return self;
}
Expand All @@ -123,8 +128,10 @@
and:(uint64_t)endSystemTime;
{
NSArray<SentryMetricReading *> *memoryFootprint;
NSArray<SentryMetricReading *> *cpuEnergyUsage;
NSDictionary<NSNumber *, NSArray<SentryMetricReading *> *> *cpuUsage;
@synchronized(self) {
cpuEnergyUsage = [NSArray<SentryMetricReading *> arrayWithArray:_cpuEnergyUsage];
memoryFootprint = [NSArray<SentryMetricReading *> arrayWithArray:_memoryFootprint];
cpuUsage = [NSDictionary<NSNumber *, NSArray<SentryMetricReading *> *>
dictionaryWithDictionary:_cpuUsage];
Expand All @@ -136,6 +143,11 @@
= serializeValuesWithNormalizedTime(memoryFootprint,
kSentryMetricProfilerSerializationUnitBytes, startSystemTime, endSystemTime);
}
if (cpuEnergyUsage.count > 0) {
dict[kSentryMetricProfilerSerializationKeyCPUEnergyUsage]
= serializeValuesWithNormalizedTime(cpuEnergyUsage,
kSentryMetricProfilerSerializationUnitBytes, startSystemTime, endSystemTime);
}

[cpuUsage enumerateKeysAndObjectsUsingBlock:^(NSNumber *_Nonnull core,
NSArray<SentryMetricReading *> *_Nonnull readings, BOOL *_Nonnull stop) {
Expand Down Expand Up @@ -167,6 +179,7 @@
eventHandler:^{
[weakSelf recordCPUPercentagePerCore];
[weakSelf recordMemoryFootprint];
[weakSelf recordEnergyUsageEstimate];
}];
}

Expand Down Expand Up @@ -205,6 +218,29 @@
}
}

- (void)recordEnergyUsageEstimate
{
NSError *error;
const auto reading =
[SentryDependencyContainer.sharedInstance.systemWrapper cpuEnergyUsageWithError:&error];
if (error) {
SENTRY_LOG_ERROR(@"Failed to read CPU energy usage: %@", error);
return;

Check warning on line 228 in Sources/Sentry/SentryMetricProfiler.mm

View check run for this annotation

Codecov / codecov/patch

Sources/Sentry/SentryMetricProfiler.mm#L228

Added line #L228 was not covered by tests
}

if (previousEnergyReading == nil) {
previousEnergyReading = reading;
return;
}

const auto value = reading.unsignedIntegerValue - previousEnergyReading.unsignedIntegerValue;
previousEnergyReading = reading;

@synchronized(self) {
[_cpuEnergyUsage addObject:[self metricReadingForValue:@(value)]];
}
}

- (SentryMetricReading *)metricReadingForValue:(NSNumber *)value
{
const auto reading = [[SentryMetricReading alloc] init];
Expand Down
18 changes: 18 additions & 0 deletions Sources/Sentry/SentrySystemWrapper.mm
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,22 @@
return result;
}

- (NSNumber *)cpuEnergyUsageWithError:(NSError **)error
{
struct task_power_info_v2 powerInfo;

mach_msg_type_number_t size = TASK_POWER_INFO_V2_COUNT;

task_t task = mach_task_self();
kern_return_t kr = task_info(task, TASK_POWER_INFO_V2, (task_info_t)&powerInfo, &size);
if (kr != KERN_SUCCESS) {
if (error) {
*error = NSErrorFromSentryErrorWithKernelError(
kSentryErrorKernel, @"Error with task_info(…TASK_POWER_INFO_V2…).", kr);
;

Check warning on line 74 in Sources/Sentry/SentrySystemWrapper.mm

View check run for this annotation

Codecov / codecov/patch

Sources/Sentry/SentrySystemWrapper.mm#L72-L74

Added lines #L72 - L74 were not covered by tests
}
}
return @(powerInfo.cpu_energy.total_system + powerInfo.cpu_energy.total_user);
armcknight marked this conversation as resolved.
Show resolved Hide resolved
}

@end
1 change: 1 addition & 0 deletions Sources/Sentry/include/SentryMetricProfiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ NS_ASSUME_NONNULL_BEGIN

SENTRY_EXTERN NSString *const kSentryMetricProfilerSerializationKeyMemoryFootprint;
SENTRY_EXTERN NSString *const kSentryMetricProfilerSerializationKeyCPUUsageFormat;
SENTRY_EXTERN NSString *const kSentryMetricProfilerSerializationKeyCPUEnergyUsage;

SENTRY_EXTERN NSString *const kSentryMetricProfilerSerializationUnitBytes;
SENTRY_EXTERN NSString *const kSentryMetricProfilerSerializationUnitPercentage;
Expand Down
2 changes: 2 additions & 0 deletions Sources/Sentry/include/SentrySystemWrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ typedef mach_vm_size_t SentryRAMBytes;
*/
- (nullable NSArray<NSNumber *> *)cpuUsagePerCore:(NSError **)error;

- (nullable NSNumber *)cpuEnergyUsageWithError:(NSError **)error;

@end

NS_ASSUME_NONNULL_END