Skip to content
Draft
Prev Previous commit
Next Next commit
TaskInfo and ResourceUsageInfo struct queries
  • Loading branch information
milseman committed Feb 5, 2021
commit 544fc8ac3d45ac1d1658252bffefc40f43b361c9
33 changes: 2 additions & 31 deletions Sources/System/Process/ProcessID.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,36 +24,7 @@ public struct ProcessID: RawRepresentable, Hashable, Codable {
}

extension ProcessID {
public struct TaskInfo: RawRepresentable/*, Hashable, Codable*/ {
/// The raw C process id.
@_alwaysEmitIntoClient
public let rawValue: CInterop.ProcTaskInfo

/// Creates a strongly-typed process id from a raw C pid
@_alwaysEmitIntoClient
public init(rawValue: CInterop.ProcTaskInfo) { self.rawValue = rawValue }

fileprivate init(_ rawValue: CInterop.ProcTaskInfo) {
self.init(rawValue: rawValue)
}

}

public struct ResourceUsageInfo: RawRepresentable/*, Hashable, Codable*/ {
/// The raw C process id.
@_alwaysEmitIntoClient
public let rawValue: CInterop.RUsageInfo

/// Creates a strongly-typed process id from a raw C pid
@_alwaysEmitIntoClient
public init(rawValue: CInterop.RUsageInfo) { self.rawValue = rawValue }

fileprivate init(_ rawValue: CInterop.RUsageInfo) {
self.init(rawValue: rawValue)
}

fileprivate static var blank: ResourceUsageInfo {
ResourceUsageInfo(rusage_info_current())
}
public static func current() -> ProcessID {
ProcessID(getpid())
}
}
159 changes: 159 additions & 0 deletions Sources/System/Process/ResourceUsageInfo.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@

extension ProcessID {
public struct ResourceUsageInfo: RawRepresentable/*, Hashable, Codable*/ {
/// The raw C process id.
@_alwaysEmitIntoClient
public let rawValue: CInterop.RUsageInfo

/// Creates a strongly-typed process id from a raw C pid
@_alwaysEmitIntoClient
public init(rawValue: CInterop.RUsageInfo) { self.rawValue = rawValue }

fileprivate init(_ rawValue: CInterop.RUsageInfo) {
self.init(rawValue: rawValue)
}

fileprivate static var blank: ResourceUsageInfo {
ResourceUsageInfo(rusage_info_current())
}
}
}

// FIXME(DO NOT MERGE): system_foo wrappers for these and mocking
import CSystem
extension ProcessID {
public func getResourceUsageInfo() throws -> ResourceUsageInfo {
var current = ResourceUsageInfo.blank
try withUnsafeMutablePointer(to: &current) {
try $0.withMemoryRebound(to: rusage_info_t?.self, capacity: 1) {
guard 0 == proc_pid_rusage(self.rawValue, RUSAGE_INFO_CURRENT, $0) else {
throw Errno(rawValue: errno)
}
}
}
return current
}
}

// FIXME: docs or comments, the headers have none...
// FIXME: names
extension ProcessID.ResourceUsageInfo {
// FIXME: UUID proper type
public typealias UUID = (
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Foundation already has a wrapper for uuid_t -- perhaps we should investigate shrinking it into System.

UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8,
UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8, UInt8)

/// `ri_uuid`: TBD
public var uuid: UUID { rawValue.ri_uuid }

/// `ri_user_time`: TBD
public var userTime: UInt64 { rawValue.ri_user_time }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should specify units for all these dimensioned quantities, ideally at the type system level. Should these time intervals return whatever we end up using for timespec_t?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately the headers are not clear what even is here. It's like that ResourceUsageInfo will be split off from this PR eventually.


/// `ri_system_time`: TBD
public var systemTime: UInt64 { rawValue.ri_system_time }

/// `ri_pkg_idle_wkups`: TBD
public var pkgIdleWakeups: UInt64 { rawValue.ri_pkg_idle_wkups }

/// `ri_interrupt_wkups`: TBD
public var interruptWakeups: UInt64 { rawValue.ri_interrupt_wkups }

/// `ri_pageins`: TBD
public var pageIns: UInt64 { rawValue.ri_pageins }

/// `ri_wired_size`: TBD
public var wiredSize: UInt64 { rawValue.ri_wired_size }

/// `ri_resident_size`: TBD
public var residentSize: UInt64 { rawValue.ri_resident_size }

/// `ri_phys_footprint`: TBD
public var physicalFootprint: UInt64 { rawValue.ri_phys_footprint }

/// `ri_proc_start_abstime`: TBD
public var processStartAbsoluteTime: UInt64 { rawValue.ri_proc_start_abstime }

/// `ri_proc_exit_abstime`: TBD
public var processExitAbsoluteTime: UInt64 { rawValue.ri_proc_exit_abstime }

/// `ri_child_user_time`: TBD
public var childUserTime: UInt64 { rawValue.ri_child_user_time }

/// `ri_child_system_time`: TBD
public var childSystemTime: UInt64 { rawValue.ri_child_system_time }

/// `ri_child_pkg_idle_wkups`: TBD
public var childPkgIdleWakeups: UInt64 { rawValue.ri_child_pkg_idle_wkups }

/// `ri_child_interrupt_wkups`: TBD
public var childInterruptWakeups: UInt64 { rawValue.ri_child_interrupt_wkups }

/// `ri_child_pageins`: TBD
public var childPageIns: UInt64 { rawValue.ri_child_pageins }

/// `ri_child_elapsed_abstime`: TBD
public var childElapsedAbsoluteTime: UInt64 { rawValue.ri_child_elapsed_abstime }

/// `ri_diskio_bytesread`: TBD
public var diskIOBytesRead: UInt64 { rawValue.ri_diskio_bytesread }

/// `ri_diskio_byteswritten`: TBD
public var diskIOBytesWritten: UInt64 { rawValue.ri_diskio_byteswritten }

/// `ri_cpu_time_qos_default`: TBD
public var cpuTimeQOSDefault: UInt64 { rawValue.ri_cpu_time_qos_default }

/// `ri_cpu_time_qos_maintenance`: TBD
public var cpuTimeQOSMaintenance: UInt64 { rawValue.ri_cpu_time_qos_maintenance }

/// `ri_cpu_time_qos_background`: TBD
public var cpuTimeQOSBackground: UInt64 { rawValue.ri_cpu_time_qos_background }

/// `ri_cpu_time_qos_utility`: TBD
public var cpuTimeQOSUtility: UInt64 { rawValue.ri_cpu_time_qos_utility }

/// `ri_cpu_time_qos_legacy`: TBD
public var cpuTimeQOSLegacy: UInt64 { rawValue.ri_cpu_time_qos_legacy }

/// `ri_cpu_time_qos_user_initiated`: TBD
public var cpuTimeQOSUserInitiated: UInt64 { rawValue.ri_cpu_time_qos_user_initiated }

/// `ri_cpu_time_qos_user_interactive`: TBD
public var cpuTimeQOSUserInteractive: UInt64 { rawValue.ri_cpu_time_qos_user_interactive }

/// `ri_billed_system_time`: TBD
public var billedSystemTime: UInt64 { rawValue.ri_billed_system_time }

/// `ri_serviced_system_time`: TBD
public var servicedSystemTime: UInt64 { rawValue.ri_serviced_system_time }

/// `ri_logical_writes`: TBD
public var logicalWrites: UInt64 { rawValue.ri_logical_writes }

/// `ri_lifetime_max_phys_footprint`: TBD
public var lifetimeMaxPhysicalFootprint: UInt64 { rawValue.ri_lifetime_max_phys_footprint }

/// `ri_instructions`: TBD
public var instructions: UInt64 { rawValue.ri_instructions }

/// `ri_cycles`: TBD
public var cycles: UInt64 { rawValue.ri_cycles }

/// `ri_billed_energy`: TBD
public var billedEnergy: UInt64 { rawValue.ri_billed_energy }

/// `ri_serviced_energy`: TBD
public var servicedEnergy: UInt64 { rawValue.ri_serviced_energy }

/// `ri_interval_max_phys_footprint`: TBD
public var intervalMaxPhysicalFootprint: UInt64 { rawValue.ri_interval_max_phys_footprint }

/// `ri_runnable_time`: TBD
public var runnableTime: UInt64 { rawValue.ri_runnable_time }

/// `ri_flags`: TBD
public var flags: UInt64 { rawValue.ri_flags }

}


1 change: 0 additions & 1 deletion Sources/System/Process/SignalSet.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ extension SignalSet {
import Darwin

extension SignalSet {
// sigaddset
public mutating func insert(_ sig: Signal) {
_ = withUnsafeMutablePointer { sigaddset($0, sig.rawValue) }
}
Expand Down
82 changes: 82 additions & 0 deletions Sources/System/Process/TaskInfo.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@

// FIXME(DO NOT MERGE): system_foo wrappers for these and mocking
import CSystem

extension ProcessID {
public struct TaskInfo: RawRepresentable/*, Hashable, Codable*/ {
/// The raw C process id.
@_alwaysEmitIntoClient
public let rawValue: CInterop.ProcTaskInfo

/// Creates a strongly-typed process id from a raw C pid
@_alwaysEmitIntoClient
public init(rawValue: CInterop.ProcTaskInfo) { self.rawValue = rawValue }

fileprivate init(_ rawValue: CInterop.ProcTaskInfo) {
self.init(rawValue: rawValue)
}
}
public func getTaskInfo() throws -> TaskInfo {
var result = TaskInfo.RawValue()
try withUnsafeMutableBytes(of: &result) {
let val = proc_pidinfo(self.rawValue, PROC_PIDTASKINFO, 0, $0.baseAddress, Int32($0.count))
// What is this wacky shenanigans?
guard MemoryLayout<TaskInfo.RawValue>.stride == val else {
throw Errno(rawValue: val)
}
}
return TaskInfo(result)
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know what the intended scope is for this pull request, but a common need is to get the path and name for a PID. proc_pidpath and proc_name.

}

extension ProcessID.TaskInfo {

/// `pti_virtual_size`: virtual memory size (bytes)
public var virtualSize: UInt64 { UInt64(rawValue.pti_virtual_size) }

/// `pti_resident_size`: resident memory size (bytes)
public var residentSize: UInt64 { UInt64(rawValue.pti_resident_size) }

/// `pti_total_user`: total time
public var totalUserTime: UInt64 { UInt64(rawValue.pti_total_user) }

/// `pti_threads_user`: existing threads only
public var userThreads: UInt64 { UInt64(rawValue.pti_threads_user) }

/// `pti_policy`: default policy for new threads
public var policy: Int { Int(rawValue.pti_policy) }

/// `pti_faults`: number of page faults
public var pageFaults: Int { Int(rawValue.pti_faults) }

/// `pti_pageins`: number of actual pageins
public var pageIns: Int { Int(rawValue.pti_pageins) }

/// `pti_cow_faults`: number of copy-on-write faults
public var cowFaults: Int { Int(rawValue.pti_cow_faults) }

/// `pti_messages_sent`: number of messages sent
public var messagesSent: Int { Int(rawValue.pti_messages_sent) }

/// `pti_messages_received`: number of messages received
public var messagesReceived: Int { Int(rawValue.pti_messages_received) }

/// `pti_syscalls_mach`: number of mach system calls
public var syscallsMach: Int { Int(rawValue.pti_syscalls_mach) }

/// `pti_syscalls_unix`: number of unix system calls
public var syscallsUnix: Int { Int(rawValue.pti_syscalls_unix) }

/// `pti_csw`: number of context switches
public var contextSwitches: Int { Int(rawValue.pti_csw) }

/// `pti_threadnum`: number of threads in the task
public var taskThreads: Int { Int(rawValue.pti_threadnum) }

/// `pti_numrunning`: number of running threads
public var runningThreads: Int { Int(rawValue.pti_numrunning) }

/// `pti_priority`: task priority
public var taskPriority: Int { Int(rawValue.pti_priority) }

}