def start_get_gpu(device_id: str = None,
                  rpc_channel: InstrumentServer = None,
                  callback: callable = None,
                  ms_return: bool = False):
    """

    :param device_id:
    :param rpc_channel:
    :param callback:
    :param ms_return:
    :return:
    """

    if not callback:
        raise PyIOSDeviceException("callback can not be None")

    if not rpc_channel:
        _rpc_channel = init(device_id)
    else:
        _rpc_channel = rpc_channel

    def _callback(res):
        api_util.caller(res, callback)

    if ms_return:
        _rpc_channel.call(
            "com.apple.instruments.server.services.graphics.opengl",
            "setSamplingRate:", 0.0)
    _rpc_channel.call("com.apple.instruments.server.services.graphics.opengl",
                      "startSamplingAtTimeInterval:processIdentifier:", 0.0,
                      0.0)
    _rpc_channel.register_channel_callback(
        "com.apple.instruments.server.services.graphics.opengl", _callback)

    return _rpc_channel
def start_get_system(device_id: str = None,
                     rpc_channel: InstrumentServer = None,
                     callback: callable = None):
    """
    开始获取系统数据
    :param device_id:
    :param rpc_channel:
    :param callback:
    :return:
    """
    if not callback:
        raise PyIOSDeviceException("callback can not be None")

    if not rpc_channel:
        _rpc_channel = init(device_id)
    else:
        _rpc_channel = rpc_channel

    def _callback(res):
        api_util.system_caller(res, callback)

    _rpc_channel.register_unhandled_callback(lambda x: x)
    _rpc_channel.call(
        "com.apple.instruments.server.services.sysmontap",
        "setConfig:",
        {
            'ur':
            1000,  # 输出频率 ms
            'bm':
            0,
            'procAttrs': [
                'memVirtualSize', 'cpuUsage', 'procStatus', 'appSleep', 'uid',
                'vmPageIns', 'memRShrd', 'ctxSwitch', 'memCompressed',
                'intWakeups', 'cpuTotalSystem', 'responsiblePID',
                'physFootprint', 'cpuTotalUser', 'sysCallsUnix',
                'memResidentSize', 'sysCallsMach', 'memPurgeable',
                'diskBytesRead', 'machPortCount', '__suddenTerm', '__arch',
                'memRPrvt', 'msgSent', 'ppid', 'threadCount', 'memAnon',
                'diskBytesWritten', 'pgid', 'faults', 'msgRecv',
                '__restricted', 'pid', '__sandbox'
            ],  # 输出所有进程信息字段,字段顺序与自定义相同(全量自字段,按需使用)
            'sysAttrs': [
                'diskWriteOps', 'diskBytesRead', 'diskBytesWritten',
                'threadCount', 'vmCompressorPageCount', 'vmExtPageCount',
                'vmFreeCount', 'vmIntPageCount', 'vmPurgeableCount',
                'netPacketsIn', 'vmWireCount', 'netBytesIn', 'netPacketsOut',
                'diskReadOps', 'vmUsedCount', '__vmSwapUsage', 'netBytesOut'
            ],  # 系统信息字段
            'cpuUsage':
            True,
            'sampleInterval':
            1000000000
        })
    _rpc_channel.register_channel_callback(
        "com.apple.instruments.server.services.sysmontap", _callback)
    _rpc_channel.call("com.apple.instruments.server.services.sysmontap",
                      "start")
    return _rpc_channel
def stop_get_system(rpc_channel: InstrumentServer):
    """
    结束获取系统数据
    :param rpc_channel:
    :return:
    """
    if not rpc_channel:
        raise PyIOSDeviceException("rpc_channel can not be None")
    rpc_channel.call("com.apple.instruments.server.services.sysmontap", "stop")
 def stop_xcuitest(self, xcuitest=None):
     """
     停止 xcuitest
     :param xcuitest:
     :return:
     """
     if not xcuitest and not self.xcuitest:
         raise PyIOSDeviceException("xcuitest object can not be None")
     stop_xcuitest(xcuitest if xcuitest else self.xcuitest)
def stop_get_graphics_fps(rpc_channel: InstrumentServer):
    """
    停止获取 graphics 计算 fps
    :param rpc_channel:
    :return:
    """
    if not rpc_channel:
        raise PyIOSDeviceException("rpc_channel can not be None")
    rpc_channel.call("com.apple.instruments.server.services.graphics.opengl", "stopSampling")
def stop_get_fps(rpc_channel: InstrumentServer):
    """
    结束获取 fps 数据
    :param rpc_channel:
    :return:
    """
    if not rpc_channel:
        raise PyIOSDeviceException("rpc_channel can not be None")
    rpc_channel.call("com.apple.instruments.server.services.coreprofilesessiontap", "stop")
def stop_xcuitest(xcuitest):
    """
    停止 xcuitest
    :param xcuitest: 启动时可获取对象
    :return:
    """
    if type(xcuitest) == RunXCUITest:
        xcuitest.stop()
    else:
        raise PyIOSDeviceException("参数类型必须是 RunXCUITest")
def start_get_fps(device_id: str = None,
                  rpc_channel: InstrumentServer = None,
                  callback: callable = None):
    """
    开始获取 fps 相关数据
    :param device_id:
    :param rpc_channel:
    :param callback:
    :return:
    """
    if not callback:
        raise PyIOSDeviceException("callback can not be None")

    if not rpc_channel:
        _rpc_channel = init(device_id)
    else:
        _rpc_channel = rpc_channel

    NANO_SECOND = 1e9  # ns
    MOVIE_FRAME_COST = 1 / 24
    last_frame = None
    last_1_frame_cost, last_2_frame_cost, last_3_frame_cost = 0, 0, 0
    jank_count = 0
    big_jank_count = 0
    jank_time_count = 0
    mach_time_factor = 125 / 3
    frame_count = 0
    time_count = 0
    count_time = datetime.now().timestamp()
    _list = []

    def _callback(res):
        nonlocal frame_count, last_frame, last_1_frame_cost, last_2_frame_cost, last_3_frame_cost, time_count, mach_time_factor, \
            jank_count, big_jank_count, jank_time_count, _list, count_time
        if type(res.plist) is InstrumentRPCParseError:
            for args in kperf_data(res.raw.get_selector()):
                _time, code = args[0], args[7]
                if code == 830472984:
                    if not last_frame:
                        last_frame = long(_time)
                    else:
                        this_frame_cost = (long(_time) -
                                           last_frame) * mach_time_factor
                        if all([
                                last_3_frame_cost != 0, last_2_frame_cost != 0,
                                last_1_frame_cost != 0
                        ]):
                            if this_frame_cost > mean([last_3_frame_cost, last_2_frame_cost, last_1_frame_cost]) * 2 \
                                    and this_frame_cost > MOVIE_FRAME_COST * NANO_SECOND * 2:
                                jank_count += 1
                                jank_time_count += this_frame_cost
                                if this_frame_cost > mean(
                                        [last_3_frame_cost, last_2_frame_cost, last_1_frame_cost]) * 3 \
                                        and this_frame_cost > MOVIE_FRAME_COST * NANO_SECOND * 3:
                                    big_jank_count += 1

                        last_3_frame_cost, last_2_frame_cost, last_1_frame_cost = last_2_frame_cost, last_1_frame_cost, this_frame_cost
                        time_count += this_frame_cost
                        last_frame = long(_time)
                        frame_count += 1
                else:
                    time_count = (datetime.now().timestamp() -
                                  count_time) * NANO_SECOND
                if time_count > NANO_SECOND:
                    callback({
                        "currentTime": str(datetime.now()),
                        "FPS": frame_count / time_count * NANO_SECOND,
                        "jank": jank_count,
                        "big_jank": big_jank_count,
                        "stutter": jank_time_count / time_count
                    })
                    jank_count = 0
                    big_jank_count = 0
                    jank_time_count = 0
                    frame_count = 0
                    time_count = 0
                    count_time = datetime.now().timestamp()

    _rpc_channel.register_unhandled_callback(lambda x: x)
    # 获取mach time比例
    mach_time_info = _rpc_channel.call(
        "com.apple.instruments.server.services.deviceinfo",
        "machTimeInfo").parsed
    mach_time_factor = mach_time_info[1] / mach_time_info[2]
    _rpc_channel.register_channel_callback(
        "com.apple.instruments.server.services.coreprofilesessiontap",
        _callback)

    _rpc_channel.call(
        "com.apple.instruments.server.services.coreprofilesessiontap",
        "setConfig:", {
            'rp':
            10,
            'tc': [{
                'kdf2': {630784000, 833617920, 830472456},
                'tk': 3,
                'uuid': str(uuid.uuid4()).upper()
            }],
            'ur':
            500
        })

    _rpc_channel.call(
        "com.apple.instruments.server.services.coreprofilesessiontap", "start")

    return _rpc_channel