Skip to content

Commit

Permalink
RUM-5555 Collect CPU usage
Browse files Browse the repository at this point in the history
  • Loading branch information
maxep committed Aug 20, 2024
1 parent 6d875cc commit 6dbeeb3
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 5 deletions.
13 changes: 13 additions & 0 deletions BenchmarkTests/Benchmarks/Sources/Benchmarks.swift
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,19 @@ public enum Benchmarks {
}
}

_ = meter.createDoubleObservableGauge(name: "ios.benchmark.cpu") { metric in
do {
let usage = try CPU.usage()
metric.observe(value: usage, labels: labels)
} catch {
logger.logRecordBuilder()
.setSeverity(.error)
.setAttributes(labels.mapValues { .string($0) })
.setBody("Failed to read CPU Metric: \(error)")
.emit()
}
}

OpenTelemetry.registerMeterProvider(meterProvider: meterProvider)
}
}
59 changes: 54 additions & 5 deletions BenchmarkTests/Benchmarks/Sources/Metrics.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ let TASK_VM_INFO_COUNT = mach_msg_type_number_t(MemoryLayout<task_vm_info_data_t
let TASK_VM_INFO_REV1_COUNT = mach_msg_type_number_t(MemoryLayout.offset(of: \task_vm_info_data_t.min_address)! / MemoryLayout<integer_t>.size)

enum MachError: Error {
case kernelError(kern_return_t)
case task_info(return: kern_return_t)
case task_threads(return: kern_return_t)
case thread_info(return: kern_return_t)
}

public enum Memory {
Expand All @@ -26,15 +28,62 @@ public enum Memory {
static func footprint() throws -> Double {
var info = task_vm_info_data_t()
var count = TASK_VM_INFO_COUNT
let kr = withUnsafeMutablePointer(to: &info) { infoPtr in
infoPtr.withMemoryRebound(to: integer_t.self, capacity: Int(count)) { intPtr in
task_info(mach_task_self_, task_flavor_t(TASK_VM_INFO), intPtr, &count)
let kr = withUnsafeMutablePointer(to: &info) {
$0.withMemoryRebound(to: integer_t.self, capacity: Int(count)) {
task_info(mach_task_self_, task_flavor_t(TASK_VM_INFO), $0, &count)
}
}

guard kr == KERN_SUCCESS, count >= TASK_VM_INFO_REV1_COUNT else {
throw MachError.kernelError(kr)
throw MachError.task_info(return: kr)
}

return Double(info.phys_footprint)
}
}

public enum CPU {
/// Collect single sample of current cpu usage.
///
/// The computation is based on https://gist.github.com/hisui/10004131#file-cpu-usage-cpp
/// It reads the `cpu_usage` from all thread to compute the application usage percentage.
///
/// - Returns: The cpu usage of all threads.
static func usage() throws -> Double {
var threads_list: thread_act_array_t?
var threads_count = mach_msg_type_number_t()
let kr = withUnsafeMutablePointer(to: &threads_list) {
$0.withMemoryRebound(to: thread_act_array_t?.self, capacity: 1) {
task_threads(mach_task_self_, $0, &threads_count)
}
}

guard kr == KERN_SUCCESS, let threads_list = threads_list else {
throw MachError.task_threads(return: kr)
}

defer {
vm_deallocate(mach_task_self_, vm_address_t(bitPattern: threads_list), vm_size_t(Int(threads_count) * MemoryLayout<thread_t>.stride))
}

return try (0..<threads_count).reduce(0) { result, index in
var basic_info = thread_basic_info()
var basic_info_count = mach_msg_type_number_t(THREAD_INFO_MAX)
let kr = withUnsafeMutablePointer(to: &basic_info) {
$0.withMemoryRebound(to: integer_t.self, capacity: 1) {
thread_info(threads_list[Int(index)], thread_flavor_t(THREAD_BASIC_INFO), $0, &basic_info_count)
}
}

guard kr == KERN_SUCCESS else {
throw MachError.thread_info(return: kr)
}

guard basic_info.flags != TH_FLAGS_IDLE else {
return result
}

return result + Double(basic_info.cpu_usage) / Double(TH_USAGE_SCALE)
}
}
}

0 comments on commit 6dbeeb3

Please sign in to comment.