检测使用主线程的时间百分比

Detect percentage of time main thread is used

我正在尝试检测主线程忙碌的时间百分比,以便我可以在用户使用该应用程序时记录此指标。目前,在答案 here 的帮助下,我能找到的最接近的是 basic_info 中的 user_time 但是我怎么知道正在使用哪个线程以及它是否是主线程?那么从这里我如何知道该会话的时间占应用程序总时间的百分比运行?

当应用程序在前台时,主线程一直在使用。 因此,您可以在 applicationDidBecomeActive 中安排一个计时器并在 applicationWillResignActive 中失效,并在需要时获取累计秒数。

所以我设法使用以下方法解决了这个问题:

class MainThreadAnalyser {
    typealias SumTotal = (total: Double, elements: Double)

    private var threadPercentages = [Double]()

    private let timeIntervalSeconds: Double

    init(timeIntervalSeconds: Double) {
        self.timeIntervalSeconds = timeIntervalSeconds
        if #available(iOS 10.0, *) {
            self.startCPUMonitoring(timeIntervalSeconds: self.timeIntervalSeconds)
        }
    }

    func getAverageCpuUsage() -> Double? {
        let sumTotal = threadPercentages.reduce((total: 0, elements: 0)) { (sum, item) -> SumTotal in
            var result = sum
            if item > 0 {
                result.total += item
                result.elements += 1
            }

            return result
        }

        return sumTotal.elements > 0 ? sumTotal.total / sumTotal.elements : nil
    }

    @available(iOS 10.0, *)
    private func startCPUMonitoring(timeIntervalSeconds: Double) {
        Timer.scheduledTimer(withTimeInterval: timeIntervalSeconds, repeats: true) { [weak self] _ in
            guard let strongSelf = self else { return }
            if let cpuUsage = strongSelf.cpuUsage() {
                strongSelf.threadPercentages.append(cpuUsage)
            }
        }
    }

    private func cpuUsage() -> Double? {
        var kernReturn: kern_return_t
        var taskInfoCount: mach_msg_type_number_t

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

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

        var threadArray: thread_act_array_t? = UnsafeMutablePointer(mutating: [thread_act_t]())
        var threadCount: mach_msg_type_number_t = 0
        defer {
            if let threadArray = threadArray {
                vm_deallocate(mach_task_self_, vm_address_t(UnsafePointer(threadArray).pointee), vm_size_t(threadCount))
            }
        }

        kernReturn = task_threads(mach_task_self_, &threadArray, &threadCount)

        if kernReturn != KERN_SUCCESS {
            return -1
        }

        var totalCPU: Double?

        if let threadArray = threadArray {

            for index in 0 ..< Int(threadCount) {
                var threadInfoCount = mach_msg_type_number_t(THREAD_INFO_MAX)
                var thinfo = [integer_t](repeating: 0, count: Int(threadInfoCount))
                kernReturn = thread_info(threadArray[index], thread_flavor_t(THREAD_BASIC_INFO),
                                 &thinfo, &threadInfoCount)
                if kernReturn != KERN_SUCCESS {
                    return -1
                }

                if index == 0 {
                    let cpuUse = thinfo[4]
                    totalCPU = Double(cpuUse/10)

                }
            }
        }

        return totalCPU
    }
}