Расчет средней нагрузки для конкретного процессаLinux

Ответить Пред. темаСлед. тема
Anonymous
 Расчет средней нагрузки для конкретного процесса

Сообщение Anonymous »

Я пытаюсь понять, как рассчитывается средняя нагрузка в Linux. Я использую команду top и получаю такой результат: средняя загрузка: 0,25, 0,67, 0,51. Значения увеличиваются, когда мой пример программы выполняется в цикле, а когда я останавливаю цикл, средняя нагрузка начинает уменьшаться.
В ходе поиска я понял, что данные, которые я ищу, хранится в массиве avenrun в течение 1 минуты, 5 минут и 15 минут.
команда top показывает среднюю загрузку всей системы, я пытаюсь программно вычислить загрузка определенного процесса/PID, как показано вверху?
Ниже приведен пример кода, который я написал, и я признаюсь, что некоторая его часть представляет собой просто объединение кода из кода ядра Linux,
p>

Код: Выделить всё

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

// Use the kernel's exported avenrun array
extern unsigned long avenrun[];

static struct timer_list load_timer;
#define FSHIFT 11
#define FIXED_1 (1 > FSHIFT;
}

static void update_load_avg(struct timer_list *t)
{
struct task_struct *p;
int nr_running = 0;
unsigned long active, sample_window;
long delta;

rcu_read_lock();
for_each_process(p) {
if (p->state == TASK_RUNNING || p->state == TASK_UNINTERRUPTIBLE)
nr_running++;
}
rcu_read_unlock();

active = nr_running * FIXED_1;
atomic_long_set(&calc_load_tasks, nr_running);

sample_window = READ_ONCE(calc_load_update);
if (time_before(jiffies, sample_window + 10)) {
mod_timer(&load_timer, jiffies + LOAD_FREQ);
return;
}

delta = 0;  // Simplified: In actual kernel, it includes NO_HZ delta calculations
if (delta)
atomic_long_add(delta, &calc_load_tasks);

active = atomic_long_read(&calc_load_tasks);
active = active > 0 ? active * FIXED_1 : 0;

// Use kernel's avenrun array
avenrun[0] = calc_load(avenrun[0], EXP_1, active);
avenrun[1] = calc_load(avenrun[1], EXP_5, active);
avenrun[2] = calc_load(avenrun[2], EXP_15, active);

printk(KERN_INFO "Load Average: %lu.%02lu, %lu.%02lu, %lu.%02lu\n",
avenrun[0] >> FSHIFT, (avenrun[0] & (FIXED_1 - 1)) * 100 / FIXED_1,
avenrun[1] >> FSHIFT, (avenrun[1] & (FIXED_1 - 1)) * 100 / FIXED_1,
avenrun[2] >> FSHIFT, (avenrun[2] & (FIXED_1 - 1)) * 100 / FIXED_1);

WRITE_ONCE(calc_load_update, sample_window + LOAD_FREQ);
mod_timer(&load_timer, jiffies + LOAD_FREQ);
}

static int proc_loadavg_show(struct seq_file *m, void *v)
{
// Use kernel's avenrun array
seq_printf(m, "Load Average: %lu.%02lu, %lu.%02lu, %lu.%02lu\n",
avenrun[0] >> FSHIFT, (avenrun[0] & (FIXED_1 - 1)) * 100 / FIXED_1,
avenrun[1] >> FSHIFT, (avenrun[1] & (FIXED_1 - 1)) * 100 / FIXED_1,
avenrun[2] >> FSHIFT, (avenrun[2] &  (FIXED_1 - 1)) * 100 / FIXED_1);
return 0;
}

static int proc_loadavg_open(struct inode *inode, struct file *file)
{
return single_open(file, proc_loadavg_show, NULL);
}

static const struct proc_ops proc_loadavg_ops = {
.proc_open    = proc_loadavg_open,
.proc_read    = seq_read,
.proc_lseek   = seq_lseek,
.proc_release = single_release,
};

static int __init loadavg_init(void)
{
proc_create("my_loadavg", 0, NULL, &proc_loadavg_ops);
timer_setup(&load_timer, update_load_avg, 0);
calc_load_update = jiffies;
mod_timer(&load_timer, jiffies + LOAD_FREQ);
return 0;
}

static void __exit loadavg_exit(void)
{
del_timer_sync(&load_timer);
remove_proc_entry("my_loadavg", NULL);
}

module_init(loadavg_init);
module_exit(loadavg_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("jshish");
MODULE_DESCRIPTION("A module to calculate load average similar to /proc/loadavg");
Проблема, с которой я столкнулся в приведенном выше коде, заключалась в том, что статистика, которую я читал, постоянно увеличивалась, и она не соответствовала тому, что я читал из /proc/loadavg.
Я начал отлаживать код и понял, что способ расчета nr_running неверен,

Код: Выделить всё

    rcu_read_lock();
for_each_process(p) {
if (p->state == TASK_RUNNING || p->state == TASK_UNINTERRUPTIBLE)
nr_running++;
}
rcu_read_unlock();

active = nr_running * FIXED_1;
atomic_long_set(&calc_load_tasks, nr_running);
Я закомментировалatomic_long_set(&calc_load_tasks, nr_running); и теперь то, что я прочитал, близко к тому, что я прочитал из /proc/loadavg. Я попробовал другой подход для получения nr_running, но cpu_rq не экспортируется (Linux ubuntu 5.15.0-113-generic) :(
Кроме того, использование cpu_rq даст мне только нагрузку на основе процессора, я полагаю, что это не зависит от PID:/

Код: Выделить всё

    for_each_online_cpu(cpu) {
nr_running += cpu_rq(cpu)->nr_running;
}

active = nr_running * FIXED_1;
atomic_long_set(&calc_load_tasks, nr_running);
Это часть моего пути по изучению внутреннего устройства ядра Linux и того, как работают различные его части.
Я постарался объяснить как можно больше и предоставил материал, который я пробовал. Пожалуйста, дайте мне знать, если я что-то пропустил в вопросе, и я это исправлю.
Спасибо

Подробнее здесь: https://stackoverflow.com/questions/787 ... ic-process
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «Linux»