Назад | Перейти на главную страницу

Хороший уровень не работает на Linux

У меня есть несколько процессов с высокой интенсивностью операций с плавающей запятой, выполняющих очень мало операций ввода-вывода. Один из них называется «xspec», который вычисляет числовую модель и каждую секунду возвращает результат с плавающей запятой обратно в главный процесс (через стандартный вывод). Он расположен на 19 уровне. У меня есть еще один простой процесс «cpufloattest», который просто выполняет численные вычисления в замкнутом цикле. Это непривлекательно.

У меня 4-ядерная система i7 с отключенной гиперпоточностью. Я запустил по 4 процесса каждого типа. Почему планировщик Linux (Linux 3.4.2) не ограничивает должным образом время ЦП, занимаемое процессами niced?

Cpu(s): 56.2%us,  1.0%sy, 41.8%ni,  0.0%id,  0.0%wa,  0.9%hi,  0.1%si,  0.0%st
Mem:  12297620k total, 12147472k used,   150148k free,   831564k buffers
Swap:  2104508k total,    71172k used,  2033336k free,  4753956k cached

  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND                                         
32399 jss       20   0 44728  32m  772 R 62.7  0.3   4:17.93 cpufloattest                                    
32400 jss       20   0 44728  32m  744 R 53.1  0.3   4:14.17 cpufloattest                                    
32402 jss       20   0 44728  32m  744 R 51.1  0.3   4:14.09 cpufloattest                                    
32398 jss       20   0 44728  32m  744 R 48.8  0.3   4:15.44 cpufloattest                                    
 3989 jss       39  19 1725m 690m 7744 R 44.1  5.8   1459:59 xspec                                           
 3981 jss       39  19 1725m 689m 7744 R 42.1  5.7   1459:34 xspec                                           
 3985 jss       39  19 1725m 689m 7744 R 42.1  5.7   1460:51 xspec                                           
 3993 jss       39  19 1725m 691m 7744 R 38.8  5.8   1458:24 xspec                                           

Планировщик делает то, что я ожидаю, если я запускаю 8 процессов cpufloattest, причем 4 из них задействованы (т.е. 4 с большей частью процессора и 4 с очень небольшим).

Я обнаружил, что вызывает эту проблему. Это связано с функцией «автогруппировки» планировщика CFS. Если я сделаю

echo 0 > /proc/sys/kernel/sched_autogroup_enabled 

Тогда все будет работать так, как вы ожидаете. Процессы nice 19 упали почти до нуля, когда запущены процессы nice 0.

Я попытаюсь найти, что именно делает автогруппировка, чтобы сломать мой вариант использования и обновить этот ответ.

Изменить ... Я поболтал с некоторыми специалистами по ядру в IRC, которые только что сказали, что я должен отключить его, если он не работает для моей рабочей нагрузки и что это был просто сумасшедший патч, который понравился Линусу. Я не уверен, почему автогруппировке не нравится моя рабочая нагрузка, но этот ответ предназначен для людей, которые сталкиваются с аналогичными проблемами.

Чтобы добавить некоторые детали к принятому ответу ... Поведение, которое вы видите, связано с функцией автогруппировки, которая была добавлена ​​в Linux 2.6.38 (в 2010 году). Предположительно в описанном сценарии две команды выполнялись в разные окна терминала. Если бы они были запущены в тем же окна терминала, то вы должны были видеть, что значение nice имеет эффект. Остальная часть этого ответа развивает историю.

Ядро предоставляет функцию, известную как автоматическая группировка, для повышения производительности интерактивного рабочего стола в условиях многопроцессорных рабочих нагрузок с интенсивным использованием ЦП, таких как сборка ядра Linux с большим количеством параллельных процессов сборки (т. Е. make(1) -j флаг).

Новая автогруппа создается при создании нового сеанса через setsid(2); это происходит, например, при запуске нового окна терминала. Новый процесс, созданный fork(2) наследует членство в автогруппе своего родителя. Таким образом, все процессы в сеансе являются членами одной автогруппы.

Когда автогруппировка включена (которая используется по умолчанию во многих дистрибутивах), все члены автогруппы помещаются в одну и ту же «группу задач» планировщика ядра. Планировщик ядра Linux использует алгоритм, который выравнивает распределение циклов ЦП по группам задач. Преимущества этого для производительности интерактивного рабочего стола можно описать на следующем примере.

Предположим, что есть две автогруппы, конкурирующие за один и тот же ЦП (т.е. предположим, что либо система с одним ЦП, либо использование taskset(1) чтобы ограничить все процессы одним и тем же процессором в системе SMP). Первая группа содержит десять процессов, связанных с процессором, из сборки ядра, запущенной с make -j10. Другой содержит единственный процесс, связанный с процессором: видеоплеер. Эффект автогруппировки состоит в том, что каждая из двух групп получает половину циклов процессора. То есть видеоплеер будет получать 50% циклов ЦП, а не только 9% циклов, что, вероятно, приведет к ухудшению воспроизведения видео. Ситуация в системе SMP более сложна, но общий эффект тот же: планировщик распределяет циклы ЦП по группам задач таким образом, чтобы автогруппа, содержащая большое количество процессов, связанных с ЦП, в конечном итоге не забирала циклы ЦП за счет других заданий в системе.

Хорошее значение и групповое планирование

При планировании процессов не в реальном времени (например, тех, которые запланированы по умолчанию SCHED_OTHER policy) планировщик использует метод, известный как «групповое планирование», согласно которому потоки планируются в «группах задач». Группы задач формируются в зависимости от обстоятельств, в данном случае актуальным является автогруппировка.

Если автогруппировка включена, то все потоки, которые (неявно) помещаются в автогруппу (т. Е. В один и тот же сеанс, созданный setsid(2)) образуют рабочую группу. Таким образом, каждая новая автогруппа представляет собой отдельную группу задач.

При групповом планировании значение nice потока влияет на решения по планированию. только относительно других потоков в той же группе задач. Это имеет некоторые неожиданные последствия с точки зрения традиционной семантики значения nice в системах UNIX. В частности, если включена автогруппировка, то с помощью nice(1) на процесс влияет только на планирование относительно других процессов, выполняемых в том же сеансе (обычно: в том же окне терминала).

И наоборот, для двух процессов, которые (например) являются единственными процессами с привязкой к ЦП в разных сеансах (например, разные окна терминала, каждое из которых связано с разными автогруппами), изменение значения nice процесса в одном из сеансов не влияет на решения планировщика относительно процесса в другом сеансе. Предположительно, это тот сценарий, который вы видели, хотя вы явно не упоминаете об использовании двух окон терминала.

Если вы хотите, чтобы автогруппировка не мешала традиционным nice поведение, как описано здесь, затем, как указано в принятом ответе, вы можете отключить эту функцию

echo 0 > /proc/sys/kernel/sched_autogroup_enabled

Однако имейте в виду, что это также приведет к отключению преимуществ для интерактивности рабочего стола, которые должна была обеспечивать функция автогруппировки (см. Выше).

Хорошее значение автогруппировки

Членство в автогруппе процесса можно просмотреть через файл /proc/[pid]/autogroup:

$ cat /proc/1/autogroup
/autogroup-1 nice 0

Этот файл также можно использовать для изменения пропускной способности ЦП, выделенной автогруппе. Для этого в файл записывается число из диапазона "nice", чтобы установить значение nice для автогруппы. Допустимый диапазон от +19 (низкий приоритет) до -20 (высокий приоритет).

Параметр nice autogroup имеет то же значение, что и значение процесса nice, но применяется к распределению циклов ЦП по автогруппе в целом на основе относительных значений nice других автогрупп. Для процесса внутри автогруппы циклы ЦП, которые он получает, будут произведением значения nice автогруппы (по сравнению с другими автогруппами) и значения nice процесса (по сравнению с другими процессами в той же автогруппе).

Не может быть именно что вы ищете, но пробовали ли вы команду cpulimit? Он меньше всего доступен в репозиториях Debian / Ubuntu.

С участием cpulimit вы можете настроить, сколько процентов общего процессорного времени может занять любой процесс. Другая возможность для вас может быть cgroups, но cpulimit более прямолинейный и простой в использовании.

Просто сократите xspec до одного процесса, так что у вас будет 4: 1 или 3: 1, это будет работать нормально.

Я думаю, вы хотите повысить приоритет? В этом случае вы захотите использовать отрицательное значение..

В вашем выводе cpufloattest имеет более высокий приоритет, чем xspec.

РЕДАКТИРОВАТЬ: вы можете использовать набор задач, чтобы настроить процесс на использование определенного процессора, хотя в этом случае это не обязательно.