在Linux下自动调整进程优先级

时间:2010-09-25 21:36:25

标签: linux process

我正在尝试编写一个程序,根据配置文件(基本上是路径优先级对)自动设置进程优先级。

我认为最好的解决方案是替换execve()系统调用的内核模块。太糟糕了,系统调用表未在内核版本中导出> 2.6.0,所以如果没有真的丑陋的黑客攻击,就无法替换系统调用。

想要执行以下操作:

- 用shell脚本替换二进制文件,启动并重新编写二进制文件。 - 补丁/重新编译我的股票Ubuntu内核 - 像阅读内核可执行内存和猜测系统调用表位置一样丑陋的黑客攻击 - 运行流程的数量

真的希望成为:

- 能够根据可执行路径和配置文件控制任何进程的优先级。规则适用于任何用户。

您是否有人对如何完成此任务有任何想法?

7 个答案:

答案 0 :(得分:4)

如果您已经确定了投票解决方案,那么您要实施的大多数功能都已存在于Automatic Nice Daemon中。您可以根据进程名称,用户和组为进程配置好的级别。甚至可以根据目前使用的CPU时间动态调整流程优先级。

答案 1 :(得分:2)

有时轮询是必要的,甚至更多最终 - 不管你信不信。这取决于很多变量。

如果轮询开销足够低,它远远超过了开发自己的样式内核挂钩所增加的复杂性,成本和风险,以获得所需更改的通知。也就是说,挂钩或通知事件可用时,或者可以轻松注入时,如果情况需要,它们肯定会被使用。

这是经典的程序员“完美”思维。作为工程师,我们力求完美。这是现实世界,有时必须做出妥协。具有讽刺意味的是,在某些情况下,更完美的解决方案可能效率较低。

我为Windows开发了一个类似的'流程和流程优先级自动化'工具,称为Process Lasso(不是广告,它是免费的)。我有类似的选择,并制定了混合解决方案。内核模式挂钩可用于Windows中的某些与进程相关的事件(创建和销毁),但它们不仅不会在用户模式下公开,而且对监视其他进程指标也没有帮助。我认为任何操作系统都不会原生地通知您对任何流程指标的任何更改。许多不同钩子的开销可能比简单轮询要大得多。

最后,考虑到流程变化的HIGH频率,最好一次处理所有更改(间隔轮询)与通知事件/挂钩,这可能必须每秒处理多次。

你有权远离脚本。为什么?因为它们很慢(呃)。当然,linux调度程序通过降低其优先级并奖励(升级)I / O绑定线程的优先级来处理CPU绑定线程方面做得相当不错 - 所以即使在高负载下脚本应该我想是有回应。

答案 2 :(得分:1)

当然,只需遍历/ proc / nnn / exe即可获取正在运行的图像的路径名。只使用带有斜杠的那些,其他的是内核过程。

检查您是否已经处理了那个,否则在配置文件中查找新的优先级并使用renice(8)调整其优先级。

答案 3 :(得分:1)

您可能会考虑另一个攻击点:将系统的dynamic linker替换为应用逻辑的已修改的攻击点。 (请参阅此paper,了解一些很好的例子,说明可以从很大程度上被忽视的链接器黑客艺术中获得什么。)

这种方法存在问题的方法是使用纯粹静态链接的二进制文件。我怀疑在现代系统中有很多东西实际上没有动态链接(busybox-static之类的东西是明显的例外,尽管你可能会认为能够在你的控件之外获得一个最小的shell作为一个特征可怕的错误),所以这可能不是什么大问题。另一方面,如果优先级策略旨在为重载的共享多用户系统带来一些订单,那么您可能会看到智能用户准备应用程序的静态链接版本以避免链接器强加的优先级。

答案 4 :(得分:1)

如果您想将其作为内核模块,那么您可以考虑制作自己的二进制加载器。有关示例,请参阅以下内核源文件:

$KERNEL_SOURCE/fs/binfmt_elf.c
$KERNEL_SOURCE/fs/binfmt_misc.c
$KERNEL_SOURCE/fs/binfmt_script.c

他们可以让您初步了解从哪里开始。

您可以修改ELF加载程序以检查ELF文件中的其他部分,并在找到时使用其内容来更改计划优先级。然后,您甚至不需要管理单独的配置文件,只需向您想要以这种方式管理的每个ELF可执行文件添加一个新部分即可。有关如何向ELF文件添加新节的信息,请参阅binutils工具的objcopy / objdump。

答案 5 :(得分:0)

  

您是否有人对如何完成此任务有任何想法?

作为想法,请考虑在抱怨模式下使用apparmor。这会将某些消息记录到syslog中,您可以听到。

答案 6 :(得分:0)

如果通过执行具有已知路径的可执行文件来启动相关进程,则可以使用inotify机制来监视该文件上的事件。执行它将触发I_OPENI_ACCESS事件。

不幸的是,这不会告诉您哪个进程导致事件触发,但您可以检查哪个/proc/*/exe是相关可执行文件的符号链接,renice进程ID问题。

E.g。这是Perl中使用Linux::Inotify2的粗略实现(在Ubuntu上由liblinux-inotify2-perl包提供):

perl -MLinux::Inotify2 -e '
  use warnings;
  use strict;
  my $x = shift(@ARGV);
  my $w = new Linux::Inotify2;
  $w->watch($x, IN_ACCESS, sub
  {
    for (glob("/proc/*/exe"))
    {
      if (-r $_ && readlink($_) eq $x && m#^/proc/(\d+)/#)
      {
        system(@ARGV, $1)
      }
    }
  });
  1 while $w->poll
' /bin/ls renice

您当然可以将Perl代码保存到文件中,比如说onexecuting,添加第一行#!/usr/bin/env perl,使文件可执行,将其放在$PATH上,然后从使用onexecuting /bin/ls renice

然后,您可以使用此实用程序作为实现各种可执行文件策略的基础。 (或做其他事情)。