自分のアプリが使っているCPU時間とメモリサイズを取得する

SysStats MonitorSysStats Liteでは、iPhone/iPod touchシステム全体の、メモリ使用状況を表示しています。この中には、暗黙的にこれらのアプリケーション自身が使用しているメモリサイズも含まれています。そのことは、PCではほぼ誤差の範囲かもしれませんが、iPhone/iPod touchでは若干影響があります。
例えば、SysStats Monitorですべての画面を開いて、さらにヘルプドキュメントを参照すると、10MB以上のメモリを消費します。これは、iPhone 3Gでは、およそ10%になります。そのため、空きメモリの容量が、実際よりも逼迫しているように見えてしまいます。
このように、小さな影響なのですが、実態をさらに正確に把握するために、SysStats MonitorSysStats Liteでは、自分が使っているメモリサイズを併記しています。
CPUは、さらに影響は小さいですが、バックグラウンドの使用率を正確に把握することできるので、自分が使っているCPU使用率を併記しています(SysStats Monitorのみ)。

http://web.me.com/kimada/images/screenshots/ssm_dashboard_v100.png

これらの情報は、開発者がアプリケーションのデバッグを行う時にも役立つ情報であり、以前、自分のアプリが使用しているメモリサイズを取得するには - The iPhone Development Playgroundでも説明した通り、開発者向けのInstrumentsというツールを使うことで見ることができます。ただ、アプリケーション自体に仕込んでおくことでも、デバッグ時に便利に使用できると思うので、その方法について説明しておきたいと思います。

使用する関数

MacOSXカーネルは、Machをベースとしています。Machでは、UNIXのプロセスに相当するものは、タスクと呼ばれていますが、そのタスクの基本情報を取得するtask_info関数を使用します。

task_info man page

コーディング例

以下に、task_info関数で、メモリ使用量とCPU使用時間を取得して、ログに出力する例を示します。

#include <mach/mach.h>

// CPU使用時間をミリ秒に変換する関数
#define tval2msec(tval) \
((tval.seconds * 1000) + (tval.microseconds / 1000))

//
// CPU使用時間とメモリ使用量を、ログに出力する例
//
+ (void)logCurrentTaskInfo {
    
    //
    // タスク基本情報(TASK_BASIC_INFO)を取得する
    //
    
    struct task_basic_info t_info;
    mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT;
    
    if (task_info(current_task(), TASK_BASIC_INFO, (task_info_t)&t_info, &t_info_count)!= KERN_SUCCESS)
    {
        NSLog(@"%s(): Error in task_info(): %s",
              __FUNCTION__, strerror(errno));
        return;
    }
    
    // メモリ使用量(bytes)
    vm_size_t rss = t_info.resident_size;
    
    // すでに終了したスレッドのCPU使用時間
    uint64_t userTime = tval2msec(t_info.user_time);
    uint64_t systemTime = tval2msec(t_info.system_time);
    
    
    //
    // 実行中のスレッドのCPU使用時間(TASK_THREAD_TIMES_INFO_COUNT)を取得する。
    //
    
    struct task_thread_times_info tti;
    t_info_count = TASK_THREAD_TIMES_INFO_COUNT;
    
    kern_return_t status = task_info(current_task(), TASK_THREAD_TIMES_INFO,
                                     (task_info_t)&tti, &t_info_count);
    if (status != KERN_SUCCESS) {
        NSLog(@"%s(): Error in task_info(): %s",
              __FUNCTION__, strerror(errno));
        return;
    }
    
    // 取得したCPU時間を、TASK_BASIC_INFOのCPU使用時間と合算する。
    userTime += tval2msec(tti.user_time);
    systemTime += tval2msec(tti.system_time);
    
    NSLog(@"resident_size=%u, userTime=%qu ms, systemTime=%qu ms", rss, userTime, systemTime);
    
    
}

この方法で取得したCPU使用時間を2回取得し、その差分を経過時間で除算することで、CPU使用率を求めることができます。