Skip to content

Instantly share code, notes, and snippets.

@algal
Last active August 16, 2022 07:45
Show Gist options
  • Star 10 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save algal/cd3b5dfc16c9d577846d96713f7fba40 to your computer and use it in GitHub Desktop.
Save algal/cd3b5dfc16c9d577846d96713f7fba40 to your computer and use it in GitHub Desktop.
Get virtual memory usage on iOS or macOS
import Darwin
import Foundation
// known good: Swift 5
// runs on macOS, probably works on iOS (but haven't tried)
/// Wraps `host_statistics64`, and provides info on virtual memory
///
/// - Returns: a `vm_statistics64`, or nil if the kernel reported an error
///
/// Relevant: https://opensource.apple.com/source/xnu/xnu-3789.51.2/osfmk/mach/vm_statistics.h.auto.html
func getVMStatistics64() -> vm_statistics64?
{
// the port number of the host (the current machine) http://web.mit.edu/darwin/src/modules/xnu/osfmk/man/mach_host_self.html
let host_port: host_t = mach_host_self()
// size of a vm_statistics_data in integer_t's
var host_size: mach_msg_type_number_t = mach_msg_type_number_t(UInt32(MemoryLayout<vm_statistics64_data_t>.size / MemoryLayout<integer_t>.size))
var returnData:vm_statistics64 = vm_statistics64.init()
let succeeded = withUnsafeMutablePointer(to: &returnData) {
(p:UnsafeMutablePointer<vm_statistics64>) -> Bool in
// host_statistics64() gives us a vm_statistics64 value, but it
// returns this via an out pointer of type integer_t, so we need to rebind our
// UnsafeMutablePointer<vm_statistics64> in order to use the function
return p.withMemoryRebound(to: integer_t.self, capacity: Int(host_size)) {
(pp:UnsafeMutablePointer<integer_t>) -> Bool in
let retvalue = host_statistics64(host_port, HOST_VM_INFO64,
pp, &host_size)
return retvalue == KERN_SUCCESS
}
}
return succeeded ? returnData : nil
}
/// Wrapper for `host_page_size`
///
/// - Returns: system's virtual page size, in bytes
///
/// Reference: http://web.mit.edu/darwin/src/modules/xnu/osfmk/man/host_page_size.html
func getPageSize() -> UInt
{
// the port number of the host (the current machine) http://web.mit.edu/darwin/src/modules/xnu/osfmk/man/mach_host_self.html
let host_port: host_t = mach_host_self()
// the page size of the host, in bytes http://web.mit.edu/darwin/src/modules/xnu/osfmk/man/host_page_size.html
var pagesize: vm_size_t = 0
host_page_size(host_port, &pagesize)
// assert: pagesize is initialized
return pagesize
}
extension vm_statistics64 {
var pageSizeInBytes:UInt64 { return UInt64(getPageSize()) }
var freeBytes:UInt64 { return UInt64(self.free_count) * self.pageSizeInBytes }
var activeBytes:UInt64 { return UInt64(self.active_count) * self.pageSizeInBytes }
var inactiveBytes:UInt64 { return UInt64(self.inactive_count) * self.pageSizeInBytes }
var wireBytes:UInt64 { return UInt64(self.wire_count) * self.pageSizeInBytes }
var zero_fillBytes:UInt64 { return UInt64(self.zero_fill_count) * self.pageSizeInBytes }
var purgeableBytes:UInt64 { return UInt64(self.purgeable_count) * self.pageSizeInBytes }
var speculativeBytes:UInt64 { return UInt64(self.speculative_count) * self.pageSizeInBytes }
var throttledBytes:UInt64 { return UInt64(self.throttled_count) * self.pageSizeInBytes }
var externalBytes:UInt64 { return UInt64(self.external_page_count) * self.pageSizeInBytes }
var internalBytes:UInt64 { return UInt64(self.internal_page_count) * self.pageSizeInBytes }
func debugString() -> String
{
let pageSizeInBytes:UInt64 = UInt64(getPageSize())
let d:[String:UInt64] = [
"free":UInt64(self.free_count),
"active":UInt64(self.active_count),
"inactive":UInt64(self.inactive_count),
"wire":UInt64(self.wire_count),
"zero_fill":self.zero_fill_count,
"purgeable":UInt64(self.purgeable_count),
"speculative":UInt64(self.speculative_count),
"throttled":UInt64(self.throttled_count),
"external":UInt64(self.external_page_count),
"internal":UInt64(self.internal_page_count)
]
var s = "Bytes associated with pages:\n"
for k in d.keys.sorted() {
let pageString = "\(k) pages:".padding(toLength: 30, withPad: " ", startingAt: 0)
let value = "\(d[k]! * pageSizeInBytes) B"
let prefixPad = repeatElement(" ", count: Swift.max(30 - value.count, 0)).joined()
let valueLeftPad = prefixPad + value
s.append("\(pageString) \t\t\(valueLeftPad)\n")
}
return s
}
}
let d = getVMStatistics64()
if let d = d {
print(d.debugString())
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment