iOS性能モニタリング(一)——CPU消費電力モニタリング

5788 ワード

前言:最近、戴銘先生の「性能モニタリング」に関する技術の共有を見て、収穫が多いような気がします.***目次は以下の通りである:iOS性能モニタリング(一)——CPU消費電力モニタリングiOS性能モニタリング(二)——メインスレッドカートンモニタリングiOS性能モニタリング(三)——方法消費時間モニタリング
この記事では、iOSパフォーマンスモニタリングツール(QiLagMonitor)の「CPU消費電力モニタリング」に関する機能モジュールについて説明します.
一、CPUアーキテクチャの理解
CPU(Central Processing Unit):中央プロセッサで、主に「演算器」、「コントローラ」、「レジスタ」の3つの部分から構成されています.演算器:いくつかの演算操作を担当します.(演算)コントローラ:CPUの各命令を発行するために必要な情報を担当します.(命令)レジスタ:演算プロセスまたは命令操作を格納する一時ファイル.(保存データ)
CPUは「処理命令」「実行操作」「制御時間」「処理データ」の4つの役割を果たす.私たちの人体の脳と似ていて、いろいろな生理活動を完成させるのに役立ちます.
市場では、よく知られているCPUアーキテクチャにはARM(arm64)やIntel(x86)などがあります.(PS:ARMとintelの違いについては、このブログを参照してください)
問:では、私たちのiPhoneにとって、どのようなCPUアーキテクチャがありますか.
現在、市場のほとんどのiPhoneはarm64アーキテクチャに基づいている.armアーキテクチャは消費電力が低いという特徴があるため、モバイル機器分野で広く応用されている.(intelは性能は良いが、消費電力が高い.そのため、モバイル端末分野の市場シェアを失った.)
CPUアーキテクチャ
モデル
armv6
iPhone、iPhone 2、iPhone 3G
armv7
iPhone3GS、iPhone 4、iPhone 4S、iPad、iPad 2
armv7s
iPhone 5、iPhone 5c
arm64
iPhone 5s、iPhone 6、iPhone 6 plus、iPhone 7、iPhone 7 plus、iPhone 8、iPhone 8 plus、iPhone X、iPhone XS、iPhone XR、iPhone 11、iPhone 11 pro、iPhone 11 pro max、iPad Air、iPad Air2、iPad mini2、iPad mini3、iPad mini4、iPad pro...
PS:CPUとGPUの比較?GPUは画像プロセッサです.ほとんどのコンピュータでは、GPUは画像の描画にのみ使用されます.現在の画面のすべてのピクセルをすばやく算出し、ディスプレイに描画します.
二、iOSはどのようにCPUの消費電力を監視しますか?QiCPUMonitorの大まかな実現構想を話します.
  • まず、現在のタスクtaskを取得する.現在生存しているすべてのスレッド情報は、タスクtaskから取得される.このとき、現在のタスクのすべての生存スレッド情報(threads)と「生存スレッド個数」(threadCount)を取得しました.
  • は次に、所定のCPU使用閾値を設定する.すべてのスレッドの情報を巡回して、スレッドがあるかどうかのCPU使用率cpu_usageが所定の閾値(例えばCPU使用率80%を超える)を「超える」かどうかを確認する.
  • .
  • スレッドのあるCPU使用率cpu_usageが所定の閾値を超えると、現在のスレッドの呼び出しのスタック情報が「記憶」される.

  • 三、QiCPUMonitorの具体的な実現
  • まず、単一スレッド情報を格納する構造体thread_basic_infoについて説明する.
  • struct thread_basic_info {
            time_value_t    user_time;      //       
            time_value_t    system_time;    //       
            integer_t       cpu_usage;      // CPU   (     1000)
            policy_t        policy;         //     
            integer_t       run_state;      //     
            integer_t       flags;          //     
            integer_t       suspend_count;  //        
            integer_t       sleep_time;     //     
    };
    

    名前
    紹介する
    user_time
    ユーザの実行時間(微妙に正確).
    system_time
    システムの動作時(微妙に正確).
    cpu_usage
    cpu使用率(理論上限1000).
    policy
    ポリシーをスケジュールします.
    run_state
    5つの「運転状態」:1>running運転中2>stopped停止3>waiting待機中4>uninterruptible中断不可5>haltedブロック
    flags
    3つのスレッドフラグ:1>swappedスワップ2>idleアイドル3>global forced idleグローバル強制アイドル.
    suspend_count
    スレッドが保留されているカウント.
    sleep_time
    スレッドが停止した時間(秒まで).
  • 次に、threadsthreadCountthisTaskの3つの変数を宣言します.

  • それぞれ表示:
    パラメータ名
    パラメータの意味
    threads
    現在のタスクtaskの下にあるすべてのスレッド情報を格納します.
    threadCount
    いくつかのスレッドを格納するために使用されます.
    thisTask
    現在のタスクtaskを格納します.
        thread_act_array_t threads;               //!     ,              。
        mach_msg_type_number_t threadCount = 0;   //!    ,            。
        const task_t thisTask = mach_task_self(); //!        task
    
  • は、その後、thisTaskを介して、対応するthreads情報およびthreadCountを取得する.
  •     kern_return_t kr = task_threads(thisTask, &threads, &threadCount); //!   thisTask,  threads  threadCount。
    
  • 同時に、取得に成功したかどうかを確認し、KERN_SUCCESS = 0は成功を表し、その他の対応するエラーコードは52種類ある.
  •     if (kr != KERN_SUCCESS) { //!       ,KERN_SUCCESS = 0     ,          52 。
            return;
        }
    
  • 最後に、現在のタスク内のすべての生存しているスレッドを巡り、各スレッドの情報を表示します.スレッドのあるCPU使用率(cpu_usage)が指定した閾値を超えるたびに、現在のスレッドの呼び出しスタックがデータベースに格納される.
  • .
        //!               
        for (int i = 0; i < threadCount; i++) {
            
            thread_info_data_t threadInfo; // 32 data
            thread_basic_info_t threadBaseInfo;
          
            mach_msg_type_number_t threadInfoCount = THREAD_INFO_MAX;
            
            if (thread_info((thread_act_t)threads[i], THREAD_BASIC_INFO, (thread_info_t)threadInfo, &threadInfoCount) == KERN_SUCCESS) {
                threadBaseInfo = (thread_basic_info_t)threadInfo; //        
                if (!(threadBaseInfo->flags & TH_FLAGS_IDLE)) {
                    integer_t cpuUsage = threadBaseInfo->cpu_usage / 10; // CPU  usage 1000,   10    CPU      。
                    if (cpuUsage > CPUMONITORRATE) { //         ,    
                        //cup                
                        NSString *reStr = qiStackOfThread(threads[i]);
                        QiCallStackModel *model = [[QiCallStackModel alloc] init];
                        model.stackStr = reStr;
                        //      
                        [[[QiLagDB shareInstance] increaseWithStackModel:model] subscribeNext:^(id x) {}];
                        NSLog(@"CPU useage overload thread stack:
    %@",reStr); } } } }

    モニタリングと同時にApp性能に影響を及ぼさないため,この判断は1つのタイマで3秒ごとにリフレッシュすればよい.
        //!    CPU   
        self.cpuMonitorTimer = [NSTimer scheduledTimerWithTimeInterval:3
                                                                 target:self
                                                               selector:@selector(updateCPUInfo)
                                                               userInfo:nil
                                                                repeats:YES];
    

    ソース:QiLagMonitor
    最後に、このシリーズはiOS業界の巨人の肩に立って完成しました.戴銘先生の素晴らしい技術の共有に感謝します.皆さんが成功して、仕事が順調であることを祈っています.添付して、戴銘先生の課程のリンク:《iOS開発の達人の授業》、ありがとうございます!