iosswiftxcodecpu-usagexctest

How to calculate cpu usage of an APP in ios using swift latest version? I am on xCode 11 as of now


I am currently using this code:

public func cpuUsage(_ cpuModel:CpuIosModel?) -> Float { guard let cpuModel = cpuModel else {

        print("cpuUsage is empty")
        return -1
    }

    var kr: kern_return_t
    var task_info_count: mach_msg_type_number_t
   
    task_info_count = mach_msg_type_number_t(TASK_INFO_MAX)
    var tinfo = [integer_t](repeating: 0, count: Int(task_info_count))

    kr = task_info(mach_task_self_, task_flavor_t(TASK_BASIC_INFO), &tinfo, &task_info_count)
    if kr != KERN_SUCCESS {
        return -1
    }

    var thread_list: thread_act_array_t? = UnsafeMutablePointer(mutating: [thread_act_t]())
    var thread_count: mach_msg_type_number_t = 0
    defer {
        if let thread_list = thread_list {
            vm_deallocate(mach_task_self_, vm_address_t(UnsafePointer(thread_list).pointee), vm_size_t(thread_count))
        }
    }
    kr = task_threads(mach_task_self_, &thread_list, &thread_count)

    if kr != KERN_SUCCESS {

        return -1
    }

    var tot_cpu: Float = 0
    var usr_space_time: Int = 0      //time in ms
    var system_space_time:Int = 0    //time in ms
    var thread_sleep_time: Int = 0   // time in sec
    var counter:Int = 0

    if let thread_list = thread_list {

        for j in 0 ..< Int(thread_count) {
            var thread_info_count = mach_msg_type_number_t(THREAD_INFO_MAX)
            var thinfo = [integer_t](repeating: 0, count: Int(thread_info_count))
            kr = thread_info(thread_list[j], thread_flavor_t(THREAD_BASIC_INFO),
                             &thinfo, &thread_info_count)

            let threadBasicInfo = convertThreadInfoToThreadBasicInfo(thinfo)

            if threadBasicInfo.flags != TH_FLAGS_IDLE {
                tot_cpu += (Float(threadBasicInfo.cpu_usage) / Float(TH_USAGE_SCALE)) * 100.0
                usr_space_time += Int(threadBasicInfo.user_time.microseconds/1000)
                system_space_time += Int(threadBasicInfo.system_time.microseconds/1000)
                thread_sleep_time += Int(threadBasicInfo.sleep_time)
                counter = counter + 1
            }
           

        } // for each thread

        if counter != 0 {
            //setCpuData(tot_cpu,usr_space_time,system_space_time)
            setCpuData(tot_cpu: tot_cpu, usr_space_time: usr_space_time, system_space_time: system_space_time, thread_sleep_time: thread_sleep_time,cpuModel: cpuModel)
            print(usr_space_time)
            return -1
        }
    }
    return tot_cpu
}

fileprivate func convertThreadInfoToThreadBasicInfo(_ threadInfo: [integer_t]) -> thread_basic_info {
    var result = thread_basic_info()
    result.user_time = time_value_t(seconds: threadInfo[0], microseconds: threadInfo[1])
    result.system_time = time_value_t(seconds: threadInfo[2], microseconds: threadInfo[3])
    result.cpu_usage = threadInfo[4]
    result.policy = threadInfo[5]
    result.run_state = threadInfo[6]
    result.flags = threadInfo[7]
    result.suspend_count = threadInfo[8]
    result.sleep_time = threadInfo[9]
    return result
}

But this is always giving tot_cpu as 0. Please help if you have a working code. Also i got this piece of code from internet. Can someone please explain why threadInfo[4] in convertThreadInfoToThreadBasicInfo() function is holding cpu usage value. Is this a pre defined thing.


Solution

  • I'm not sure if it's what you are looking for or not but you can take a look at this implementation:

    func cpuUsage() -> Double {
      var totalUsageOfCPU: Double = 0.0
      var threadsList = UnsafeMutablePointer(mutating: [thread_act_t]())
      var threadsCount = mach_msg_type_number_t(0)
      let threadsResult = withUnsafeMutablePointer(to: &threadsList) {
        return $0.withMemoryRebound(to: thread_act_array_t?.self, capacity: 1) {
          task_threads(mach_task_self_, $0, &threadsCount)
        }
      }
      
      if threadsResult == KERN_SUCCESS {
        for index in 0..<threadsCount {
          var threadInfo = thread_basic_info()
          var threadInfoCount = mach_msg_type_number_t(THREAD_INFO_MAX)
          let infoResult = withUnsafeMutablePointer(to: &threadInfo) {
            $0.withMemoryRebound(to: integer_t.self, capacity: 1) {
              thread_info(threadsList[Int(index)], thread_flavor_t(THREAD_BASIC_INFO), $0, &threadInfoCount)
            }
          }
          
          guard infoResult == KERN_SUCCESS else {
            break
          }
          
          let threadBasicInfo = threadInfo as thread_basic_info
          if threadBasicInfo.flags & TH_FLAGS_IDLE == 0 {
            totalUsageOfCPU = (totalUsageOfCPU + (Double(threadBasicInfo.cpu_usage) / Double(TH_USAGE_SCALE) * 100.0))
          }
        }
      }
      
      vm_deallocate(mach_task_self_, vm_address_t(UInt(bitPattern: threadsList)), vm_size_t(Int(threadsCount) * MemoryLayout<thread_t>.stride))
      return totalUsageOfCPU
    }
    

    Refer: https://github.com/dani-gavrilov/GDPerformanceView-Swift/blob/1ee9895fa9279c9858e2b72c3eea579608bf7597/GDPerformanceView-Swift/GDPerformanceMonitoring/Performance%D0%A1alculator.swift#L94