Как получить общее использование процессора приложением из /proc/pid/stat?

Мне было интересно, как рассчитать общее использование процессора процессом.

Если я сделаю cat /proc/pid/statЯ думаю, что соответствующие поля ( взяты из lindevdoc.org):

  1. Время процессора, потраченное в пользовательском коде, измеренное в jiffies
  2. Время процессора в коде ядра, измеренное в jiffies
  3. Время ЦП, потраченное на код пользователя, включая время от детей
  4. Время процессора, потраченное на код ядра, включая время от детей

Так общее время потратить сумму полей от 14 до 17?

5 ответов

Решение

подготовка

Чтобы рассчитать загрузку процессора для конкретного процесса, вам потребуется следующее:

  1. /proc/uptime
    • #1 время работы системы (секунды)
  2. /proc/[PID]/stat
    • #14utime - время процессора в пользовательском коде измеряется в тактах
    • #15stime - время процессора в коде ядра измеряется в тактах
    • #16cutime - Ожидание детского процессорного времени в пользовательском коде (в тактах)
    • #17cstime - Ожидание детского процессорного времени в коде ядра (в тактах)
    • #22starttime - время начала процесса, измеряется в тактах
  3. Герц (количество тактов в секунду) вашей системы.
    • В большинстве случаев, getconf CLK_TCK может использоваться для возврата количества тактов.
    • sysconf(_SC_CLK_TCK) Вызов функции C также может использоваться для возврата значения герца.

расчет

Сначала мы определяем общее время, потраченное на процесс:

total_time = utime + stime

Мы также должны решить, хотим ли мы включить время от дочерних процессов. Если мы это сделаем, то мы добавим эти значения в total_time:

total_time = total_time + cutime + cstime

Далее мы получаем общее время, прошедшее с момента начала процесса:

seconds = uptime - (starttime / Hertz)

Наконец, мы рассчитываем процент использования процессора:

cpu_usage = 100 * ((total_time / Hertz) / seconds)

Смотрите также

Top и PS не показывают тот же результат процессора

Как получить общее использование процессора в Linux (C++)

Расчет использования процессора процессом в Linux

Да, вы можете так сказать. Вы можете преобразовать эти значения в секунды, используя формулу:

      sec = jiffies / HZ ; here - HZ = number of ticks per second

Значение HZ настраивается - выполняется во время настройки ядра.

Вот мое простое решение, написанное на BASH. Это системный монитор linux / unix и менеджер процессов через procfs, например " top " или " ps ". Существует две версии: простая монохромная (быстрая) и цветная (немного медленная, но полезная, особенно для отслеживания состояния процессов). Я сделал сортировку по загрузке процессора.

https://github.com/AraKhachatryan/top

  • utime, stime, cutime, cstime, starttime, используемые для получения информации об использовании процессора и полученные из файла /proc/[pid]/stat.

  • Параметры state, ppid, priority, nice, num_threads также получены из файла /proc/[pid]/stat.

  • Параметры resident и data_and_stack, используемые для получения информации об использовании памяти и полученные из файла /proc/[pid]/statm.


    function my_ps
    {
        pid_array=`ls /proc | grep -E '^[0-9]+$'`
        clock_ticks=$(getconf CLK_TCK)
        total_memory=$( grep -Po '(?<=MemTotal:\s{8})(\d+)' /proc/meminfo )

        cat /dev/null > .data.ps

        for pid in $pid_array
        do
            if [ -r /proc/$pid/stat ]
            then
                stat_array=( `sed -E 's/(\([^\s)]+)\s([^)]+\))/\1_\2/g' /proc/$pid/stat` )
                uptime_array=( `cat /proc/uptime` )
                statm_array=( `cat /proc/$pid/statm` )
                comm=( `grep -Po '^[^\s\/]+' /proc/$pid/comm` )
                user_id=$( grep -Po '(?<=Uid:\s)(\d+)' /proc/$pid/status )

                user=$( id -nu $user_id )
                uptime=${uptime_array[0]}

                state=${stat_array[2]}
                ppid=${stat_array[3]}
                priority=${stat_array[17]}
                nice=${stat_array[18]}

                utime=${stat_array[13]}
                stime=${stat_array[14]}
                cutime=${stat_array[15]}
                cstime=${stat_array[16]}
                num_threads=${stat_array[19]}
                starttime=${stat_array[21]}

                total_time=$(( $utime + $stime ))
                #add $cstime - CPU time spent in user and kernel code ( can olso add $cutime - CPU time spent in user code )
                total_time=$(( $total_time + $cstime ))
                seconds=$( awk 'BEGIN {print ( '$uptime' - ('$starttime' / '$clock_ticks') )}' )
                cpu_usage=$( awk 'BEGIN {print ( 100 * (('$total_time' / '$clock_ticks') / '$seconds') )}' )

                resident=${statm_array[1]}
                data_and_stack=${statm_array[5]}
                memory_usage=$( awk 'BEGIN {print( (('$resident' + '$data_and_stack' ) * 100) / '$total_memory'  )}' )

                printf "%-6d %-6d %-10s %-4d %-5d %-4s %-4u %-7.2f %-7.2f %-18s\n" $pid $ppid $user $priority $nice $state $num_threads $memory_usage $cpu_usage $comm >> .data.ps

            fi
        done

        clear
        printf "\e[30;107m%-6s %-6s %-10s %-4s %-3s %-6s %-4s %-7s %-7s %-18s\e[0m\n" "PID" "PPID" "USER" "PR" "NI" "STATE" "THR" "%MEM" "%CPU" "COMMAND"
        sort -nr -k9 .data.ps | head -$1
        read_options
    }

скриншот рабочего скрипта

Если нужно подсчитать, сколько% процессорного времени использовалось процессом за последние 10 секунд

  1. получить total_time (13+14) в jiffies => t1 starttime(22) в jiffies => s1

- задержка 10 секунд

total_time (13+14) в jiffies => t2 starttime(22) в jiffies => s2

t2-t1 * 100 / s2 - s1 не даст%??

Вот еще один способ, которым я получил использование процессора моего приложения. Я сделал это в Android, и он делает основной запрос ядра и получает загрузку процессора для ваших приложений, используя то, что возвращает вершина.

public void myWonderfulApp()
{
   // Some wonderfully written code here
   Integer lMyProcessID = android.os.Process.myPid();
   int lMyCPUUsage = getAppCPUUsage( lMyProcessID );
   // More magic
}


// Alternate way that I switched to.  I found the first version was slower
// this version only returns a single line for the app, so far less parsing
// and processing.
public static float getTotalCPUUsage2()
{
    try
    {
        // read global stats file for total CPU
        BufferedReader reader = new BufferedReader(new FileReader("/proc/stat"));
        String[] sa = reader.readLine().split("[ ]+", 9);
        long work = Long.parseLong(sa[1]) + Long.parseLong(sa[2]) + Long.parseLong(sa[3]);
        long total = work + Long.parseLong(sa[4]) + Long.parseLong(sa[5]) + Long.parseLong(sa[6]) + Long.parseLong(sa[7]);
        reader.close();

        // calculate and convert to percentage
        return restrictPercentage(work * 100 / (float) total);
    }
    catch (Exception ex)
    {
        Logger.e(Constants.TAG, "Unable to get Total CPU usage");
    }

    // if there was an issue, just return 0
    return 0;
}

// This is an alternate way, but it takes the entire output of 
// top, so there is a fair bit of parsing.
public static int getAppCPUUsage( Integer aAppPID)
{
    int lReturn = 0;
    // make sure a valid pid was passed
    if ( null == aAppPID && aAppPID > 0)
    {
        return lReturn;
    }

    try
    {
        // Make a call to top so we have all the processes CPU
        Process lTopProcess = Runtime.getRuntime().exec("top");
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(lTopProcess.getInputStream()));

        String lLine;

        // While we have stuff to read and we have not found our PID, process the lines
        while ( (lLine = bufferedReader.readLine()) != null )
        {
            // Split on 4, the CPU % is the 3rd field .
            // NOTE: We trim because sometimes we had the first field in the split be a "".
            String[] lSplit = lLine.trim().split("[ ]+", 4);

            // Don't even bother if we don't have at least the 4
            if ( lSplit.length > 3 )
            {
                // Make sure we can handle if we can't parse the int
                try
                {
                    // On the line that is our process, field 0 is a PID
                    Integer lCurrentPID = Integer.parseInt(lSplit[0]);

                    // Did we find our process?
                    if (aAppPID.equals(lCurrentPID))
                    {
                        // This is us, strip off the % and return it
                        String lCPU = lSplit[2].replace("%", "");

                        lReturn = Integer.parseInt(lCPU);
                        break;
                    }
                }
                catch( NumberFormatException e )
                {
                    // No op.  We expect this when it's not a PID line
                }
            }
        }

        bufferedReader.close();
        lTopProcess.destroy();      // Cleanup the process, otherwise you make a nice hand warmer out of your device

    }
    catch( IOException ex )
    {
        // Log bad stuff happened
    }
    catch (Exception ex)
    {
        // Log bad stuff happened
    }

    // if there was an issue, just return 0
    return lReturn;
}

Вот что вы ищете:

//USER_HZ detection, from openssl code
#ifndef HZ
# if defined(_SC_CLK_TCK) \
     && (!defined(OPENSSL_SYS_VMS) || __CTRL_VER >= 70000000)
#  define HZ ((double)sysconf(_SC_CLK_TCK))
# else
#  ifndef CLK_TCK
#   ifndef _BSD_CLK_TCK_ /* FreeBSD hack */
#    define HZ  100.0
#   else /* _BSD_CLK_TCK_ */
#    define HZ ((double)_BSD_CLK_TCK_)
#   endif
#  else /* CLK_TCK */
#   define HZ ((double)CLK_TCK)
#  endif
# endif
#endif

Этот код на самом деле из cpulimit, но использует фрагменты openssl.

Другие вопросы по тегам