Пример #1
0
static int update_task_from_task_info(task_t task, task_record_t *info)
{
     kern_return_t kr;
     struct task_basic_info_64 ti;
     mach_msg_type_number_t   count;

     count = TASK_BASIC_INFO_64_COUNT;
     kr = task_info(task, TASK_BASIC_INFO_64, (task_info_t)&ti, &count);
     if (kr != KERN_SUCCESS)
     {
          syslog(LOG_WARNING, "error in task_info(%i): %s", task, mach_error_string(kr));
          return -1;
     }

     info->p_time_user = info->time_user;
     info->p_time_kernel = info->time_kernel;

     struct timeval tv = {0,0};
     TIME_VALUE_TO_TIMEVAL(&ti.user_time, &info->time_user);
     TIME_VALUE_TO_TIMEVAL(&ti.system_time, &info->time_kernel);
     
     info->real_mem_size = ti.resident_size;
     info->virtual_mem_size = ti.virtual_size;

     return 0;
}
Пример #2
0
// We should consider moving this into each MacThread.
static void get_threads_profile_data(DNBProfileDataScanType scanType, task_t task, nub_process_t pid, std::vector<uint64_t> &threads_id, std::vector<std::string> &threads_name, std::vector<uint64_t> &threads_used_usec)
{
    kern_return_t kr;
    thread_act_array_t threads;
    mach_msg_type_number_t tcnt;
    
    kr = task_threads(task, &threads, &tcnt);
    if (kr != KERN_SUCCESS)
        return;
    
    for (int i = 0; i < tcnt; i++)
    {
        thread_identifier_info_data_t identifier_info;
        mach_msg_type_number_t count = THREAD_IDENTIFIER_INFO_COUNT;
        kr = ::thread_info(threads[i], THREAD_IDENTIFIER_INFO, (thread_info_t)&identifier_info, &count);
        if (kr != KERN_SUCCESS) continue;
        
        thread_basic_info_data_t basic_info;
        count = THREAD_BASIC_INFO_COUNT;
        kr = ::thread_info(threads[i], THREAD_BASIC_INFO, (thread_info_t)&basic_info, &count);
        if (kr != KERN_SUCCESS) continue;

        if ((basic_info.flags & TH_FLAGS_IDLE) == 0)
        {
            nub_thread_t tid = MachThread::GetGloballyUniqueThreadIDForMachPortID (threads[i]);
            threads_id.push_back(tid);
            
            if ((scanType & eProfileThreadName) && (identifier_info.thread_handle != 0))
            {
                struct proc_threadinfo proc_threadinfo;
                int len = ::proc_pidinfo(pid, PROC_PIDTHREADINFO, identifier_info.thread_handle, &proc_threadinfo, PROC_PIDTHREADINFO_SIZE);
                if (len && proc_threadinfo.pth_name[0])
                {
                    threads_name.push_back(proc_threadinfo.pth_name);
                }
                else
                {
                    threads_name.push_back("");
                }
            }
            else
            {
                threads_name.push_back("");
            }
            struct timeval tv;
            struct timeval thread_tv;
            TIME_VALUE_TO_TIMEVAL(&basic_info.user_time, &thread_tv);
            TIME_VALUE_TO_TIMEVAL(&basic_info.system_time, &tv);
            timeradd(&thread_tv, &tv, &thread_tv);
            uint64_t used_usec = thread_tv.tv_sec * 1000000ULL + thread_tv.tv_usec;
            threads_used_usec.push_back(used_usec);
        }
        
        kr = mach_port_deallocate(mach_task_self(), threads[i]);
    }
    kr = mach_vm_deallocate(mach_task_self(), (mach_vm_address_t)(uintptr_t)threads, tcnt * sizeof(*threads));
}
JNIEXPORT jdouble JNICALL
Java_com_sun_management_UnixOperatingSystem_getProcessCpuLoad
(JNIEnv *env, jobject dummy)
{
    // This code is influenced by the darwin top source

    struct task_basic_info_64 task_info_data;
    struct task_thread_times_info thread_info_data;
    struct timeval user_timeval, system_timeval, task_timeval;
    struct timeval now;
    mach_port_t task = mach_task_self();
    kern_return_t kr;

    static jlong last_task_time = 0;
    static jlong last_time      = 0;

    mach_msg_type_number_t thread_info_count = TASK_THREAD_TIMES_INFO_COUNT;
    kr = task_info(task,
            TASK_THREAD_TIMES_INFO,
            (task_info_t)&thread_info_data,
            &thread_info_count);
    if (kr != KERN_SUCCESS) {
        // Most likely cause: |task| is a zombie.
        return -1;
    }

    mach_msg_type_number_t count = TASK_BASIC_INFO_64_COUNT;
    kr = task_info(task,
            TASK_BASIC_INFO_64,
            (task_info_t)&task_info_data,
            &count);
    if (kr != KERN_SUCCESS) {
        // Most likely cause: |task| is a zombie.
        return -1;
    }

    /* Set total_time. */
    // thread info contains live time...
    TIME_VALUE_TO_TIMEVAL(&thread_info_data.user_time, &user_timeval);
    TIME_VALUE_TO_TIMEVAL(&thread_info_data.system_time, &system_timeval);
    timeradd(&user_timeval, &system_timeval, &task_timeval);

    // ... task info contains terminated time.
    TIME_VALUE_TO_TIMEVAL(&task_info_data.user_time, &user_timeval);
    TIME_VALUE_TO_TIMEVAL(&task_info_data.system_time, &system_timeval);
    timeradd(&user_timeval, &task_timeval, &task_timeval);
    timeradd(&system_timeval, &task_timeval, &task_timeval);

    if (gettimeofday(&now, NULL) < 0) {
       return -1;
    }
    jint ncpus      = JVM_ActiveProcessorCount();
    jlong time      = TIME_VALUE_TO_MICROSECONDS(now) * ncpus;
    jlong task_time = TIME_VALUE_TO_MICROSECONDS(task_timeval);

    if ((last_task_time == 0) || (last_time == 0)) {
        // First call, just set the last values.
        last_task_time = task_time;
        last_time      = time;
        // return 0 since we have no data, not -1 which indicates error
        return 0;
    }

    jlong task_time_delta = task_time - last_task_time;
    jlong time_delta      = time - last_time;
    if (time_delta == 0) {
        return -1;
    }

    jdouble cpu = (jdouble) task_time_delta / time_delta;

    last_task_time = task_time;
    last_time      = time;

    return cpu;
 }
Пример #4
0
std::string
MachTask::GetProfileData (DNBProfileDataScanType scanType)
{
    std::string result;
    
    static int32_t numCPU = -1;
    struct host_cpu_load_info host_info;
    if (scanType & eProfileHostCPU)
    {
        int32_t mib[] = {CTL_HW, HW_AVAILCPU};
        size_t len = sizeof(numCPU);
        if (numCPU == -1)
        {
            if (sysctl(mib, sizeof(mib) / sizeof(int32_t), &numCPU, &len, NULL, 0) != 0)
                return result;
        }
        
        mach_port_t localHost = mach_host_self();
        mach_msg_type_number_t count = HOST_CPU_LOAD_INFO_COUNT;
        kern_return_t kr = host_statistics(localHost, HOST_CPU_LOAD_INFO, (host_info_t)&host_info, &count);
        if (kr != KERN_SUCCESS)
            return result;
    }
    
    task_t task = TaskPort();
    if (task == TASK_NULL)
        return result;
    
    struct task_basic_info task_info;
    DNBError err;
    err = BasicInfo(task, &task_info);
    
    if (!err.Success())
        return result;
    
    uint64_t elapsed_usec = 0;
    uint64_t task_used_usec = 0;
    if (scanType & eProfileCPU)
    {
        // Get current used time.
        struct timeval current_used_time;
        struct timeval tv;
        TIME_VALUE_TO_TIMEVAL(&task_info.user_time, &current_used_time);
        TIME_VALUE_TO_TIMEVAL(&task_info.system_time, &tv);
        timeradd(&current_used_time, &tv, &current_used_time);
        task_used_usec = current_used_time.tv_sec * 1000000ULL + current_used_time.tv_usec;
        
        struct timeval current_elapsed_time;
        int res = gettimeofday(&current_elapsed_time, NULL);
        if (res == 0)
        {
            elapsed_usec = current_elapsed_time.tv_sec * 1000000ULL + current_elapsed_time.tv_usec;
        }
    }
    
    std::vector<uint64_t> threads_id;
    std::vector<std::string> threads_name;
    std::vector<uint64_t> threads_used_usec;

    if (scanType & eProfileThreadsCPU)
    {
        get_threads_profile_data(scanType, task, m_process->ProcessID(), threads_id, threads_name, threads_used_usec);
    }
    
    struct vm_statistics vm_stats;
    uint64_t physical_memory;
    mach_vm_size_t rprvt = 0;
    mach_vm_size_t rsize = 0;
    mach_vm_size_t vprvt = 0;
    mach_vm_size_t vsize = 0;
    mach_vm_size_t dirty_size = 0;
    mach_vm_size_t purgeable = 0;
    mach_vm_size_t anonymous = 0;
    if (m_vm_memory.GetMemoryProfile(scanType, task, task_info, m_process->GetCPUType(), m_process->ProcessID(), vm_stats, physical_memory, rprvt, rsize, vprvt, vsize, dirty_size, purgeable, anonymous))
    {
        std::ostringstream profile_data_stream;
        
        if (scanType & eProfileHostCPU)
        {
            profile_data_stream << "num_cpu:" << numCPU << ';';
            profile_data_stream << "host_user_ticks:" << host_info.cpu_ticks[CPU_STATE_USER] << ';';
            profile_data_stream << "host_sys_ticks:" << host_info.cpu_ticks[CPU_STATE_SYSTEM] << ';';
            profile_data_stream << "host_idle_ticks:" << host_info.cpu_ticks[CPU_STATE_IDLE] << ';';
        }
        
        if (scanType & eProfileCPU)
        {
            profile_data_stream << "elapsed_usec:" << elapsed_usec << ';';
            profile_data_stream << "task_used_usec:" << task_used_usec << ';';
        }
        
        if (scanType & eProfileThreadsCPU)
        {
            int num_threads = threads_id.size();
            for (int i=0; i<num_threads; i++)
            {
                profile_data_stream << "thread_used_id:" << std::hex << threads_id[i] << std::dec << ';';
                profile_data_stream << "thread_used_usec:" << threads_used_usec[i] << ';';
                
                if (scanType & eProfileThreadName)
                {
                    profile_data_stream << "thread_used_name:";
                    int len = threads_name[i].size();
                    if (len)
                    {
                        const char *thread_name = threads_name[i].c_str();
                        // Make sure that thread name doesn't interfere with our delimiter.
                        profile_data_stream << RAW_HEXBASE << std::setw(2);
                        const uint8_t *ubuf8 = (const uint8_t *)(thread_name);
                        for (int j=0; j<len; j++)
                        {
                            profile_data_stream << (uint32_t)(ubuf8[j]);
                        }
                        // Reset back to DECIMAL.
                        profile_data_stream << DECIMAL;
                    }
                    profile_data_stream << ';';
                }
            }
        }
        
        if (scanType & eProfileHostMemory)
            profile_data_stream << "total:" << physical_memory << ';';
        
        if (scanType & eProfileMemory)
        {
            static vm_size_t pagesize;
            static bool calculated = false;
            if (!calculated)
            {
                calculated = true;
                pagesize = PageSize();
            }
            
            profile_data_stream << "wired:" << vm_stats.wire_count * pagesize << ';';
            profile_data_stream << "active:" << vm_stats.active_count * pagesize << ';';
            profile_data_stream << "inactive:" << vm_stats.inactive_count * pagesize << ';';
            uint64_t total_used_count = vm_stats.wire_count + vm_stats.inactive_count + vm_stats.active_count;
            profile_data_stream << "used:" << total_used_count * pagesize << ';';
            profile_data_stream << "free:" << vm_stats.free_count * pagesize << ';';
            
            profile_data_stream << "rprvt:" << rprvt << ';';
            profile_data_stream << "rsize:" << rsize << ';';
            profile_data_stream << "vprvt:" << vprvt << ';';
            profile_data_stream << "vsize:" << vsize << ';';
            
            if (scanType & eProfileMemoryDirtyPage)
                profile_data_stream << "dirty:" << dirty_size << ';';

            if (scanType & eProfileMemoryAnonymous)
            {
                profile_data_stream << "purgeable:" << purgeable << ';';
                profile_data_stream << "anonymous:" << anonymous << ';';
            }
        }
        
        profile_data_stream << "--end--;";
        
        result = profile_data_stream.str();
    }
    
    return result;
}
Пример #5
0
/// Update information about threads count and CPU usage.
/// @param task [in] The port of task for with information is to be reterned.
/// @param tinfo [out] Information was updated with list of threads within given task. 
/// @return Upon successful completion 0 is returned.
static int update_threads_info(task_t task, task_record_t *tinfo)
{
     kern_return_t kr;
     thread_act_port_array_t threads_list;
     mach_msg_type_number_t threads_count, i;
     thread_record_t *thread;

     kr = task_threads(task, &threads_list, &threads_count);
     if (kr != KERN_SUCCESS)
     {
          syslog(LOG_WARNING, "error in task_threads(): %s", mach_error_string(kr));
          return -1;
     }
    
     free_threads_array(tinfo->threads_arr, tinfo->threads);
     free(tinfo->threads_arr);
     tinfo->threads = threads_count;
     tinfo->threads_arr = malloc(sizeof(thread_record_t*)*threads_count);

     for (i = 0; i < threads_count; i++)
     {
          thread_basic_info_data_t mach_thread_info;
          mach_msg_type_number_t count = THREAD_BASIC_INFO_COUNT;

          thread = calloc(1, sizeof(thread_record_t));
          tinfo->threads_arr[i] = thread;
          
          kr = thread_info(threads_list[i], THREAD_BASIC_INFO, (thread_info_t)&mach_thread_info, &count);
          if (kr != KERN_SUCCESS)
          {
               syslog(LOG_INFO, "error in thread_info(basic_info): %s", mach_error_string(kr));
               continue;
          }

          thread->run_state = mach_thread_info.run_state;
          thread->sleep_time = mach_thread_info.sleep_time;
          thread->suspend_count = mach_thread_info.suspend_count;
          thread->user_time = mach_thread_info.user_time;
          thread->system_time = mach_thread_info.system_time;
          thread->flags = mach_thread_info.flags;

          if ((mach_thread_info.flags & TH_FLAGS_IDLE) == 0)
          {
               struct timeval tv;
               TIME_VALUE_TO_TIMEVAL(&mach_thread_info.user_time, &tv);
               timeradd(&tinfo->time_user, &tv, &tinfo->time_user);
               TIME_VALUE_TO_TIMEVAL(&mach_thread_info.system_time, &tv);
               timeradd(&tinfo->time_kernel, &tv, &tinfo->time_kernel);
          }

          thread_identifier_info_data_t mach_thread_id_info;
          count = THREAD_IDENTIFIER_INFO_COUNT;

          kr = thread_info(threads_list[i], THREAD_IDENTIFIER_INFO, (thread_info_t)&mach_thread_id_info, &count);

          if (kr != KERN_SUCCESS)
          {
               syslog(LOG_INFO, "error in thread_info(id_info): %s", mach_error_string(kr));
               continue;
          }
    
          thread->thread_id = mach_thread_id_info.thread_id;

          kr = mach_port_deallocate(mach_task_self(), threads_list[i]);
          if (kr != KERN_SUCCESS)
          {
               syslog(LOG_INFO, "%s, error in mach_port_deallocate(): ", __FUNCTION__, mach_error_string(kr));
          }
     }

     kr = vm_deallocate(mach_task_self(), (vm_address_t)threads_list, threads_count * sizeof(thread_act_t));

     return 0;
}