如何增加新产生的进程的CPU频率

我一直在做一个业余爱好项目(用C编写),而且还远远没有完成。 这很重要,所以我最近决定做一些基准testing,以certificate我解决问题的方法不是低效的。

$ time ./old real 1m55.92 user 0m54.29 sys 0m33.24 

我重新devise了部分程序,以显着消除不必要的操作,减less了内存caching未命中和分支预测错误。 美妙的Callgrind工具向我展示了越来越多令人印象深刻的数字。 大部分的基准testing都是在没有外部过程的情况下完成的。

 $ time ./old --dry-run real 0m00.75 user 0m00.28 sys 0m00.24 $ time ./new --dry-run real 0m00.15 user 0m00.12 sys 0m00.02 

很显然,我至less在做正确的事情。 然而真正运行这个程序告诉了另外一个故事。

 $ time ./new real 2m00.29 user 0m53.74 sys 0m36.22 

正如你可能已经注意到的,时间主要取决于外部过程。 我不知道是什么导致了回归。 没有什么奇怪的东西。 只是一个传统的vfork / execve / waitpid由单个线程完成,按相同的顺序运行相同的程序。

有些东西必须导致分叉缓慢,所以我做了一个小testing(类似于下面的testing),这只会产生新的进程,并没有与我的程序相关的开销。 显然这是最快的。

 #define _GNU_SOURCE #include <fcntl.h> #include <sys/wait.h> #include <unistd.h> int main(int argc, const char **argv) { static const char *const _argv[] = {"/usr/bin/md5sum", "test.c", 0}; int fd = open("/dev/null", O_WRONLY); dup2(fd, STDOUT_FILENO); close(fd); for (int i = 0; i < 100000; i++) { int pid = vfork(); int status; if (!pid) { execve("/usr/bin/md5sum", (char*const*)_argv, environ); _exit(1); } waitpid(pid, &status, 0); } return 0; } $ time ./test real 1m58.63 user 0m68.05 sys 0m30.96 

我猜不会。

在这个时候,我决定为州长投票,时代变得更好:

 $ for i in 0 1 2 3 4 5 6 7; do sudo sh -c "echo performance > /sys/devices/system/cpu/cpu$i/cpufreq/scaling_governor";done $ time ./test real 1m03.44 user 0m29.30 sys 0m10.66 

似乎每个新进程都在一个单独的内核上进行调度,并且需要一段时间才能切换到更高的频率。 我不能说为什么旧版本跑得更快。 也许这是幸运的。 也许它(由于效率低下)导致CPUselect较早的频率。

改变州长的一个不错的副作用是编译时间也改善了。 显然编译需要分叉许多新的进程。 这不是一个可行的解决scheme,因为这个程序将不得不在其他人的桌面(和笔记本电脑)上运行。

我发现改善原始时间的唯一方法是通过在开始处添加以下代码来将程序(和subprocess)限制为单个CPU:

 cpu_set_t mask; CPU_ZERO(&mask); CPU_SET(0, &mask); sched_setaffinity(0, sizeof(mask), &mask); 

尽pipe使用默认的“ondemand”省长,哪个实际上是最快的:

 $ time ./test real 0m59.74 user 0m29.02 sys 0m10.67 

这不仅是一个骇人的解决scheme,而且在启动的程序使用multithreading的情况下效果不佳。 我的程序无法知道这一点。

有没有人有任何想法如何让产生的进程运行在高CPU时钟频率? 它必须是自动的,不需要特权。 尽pipe目前为止我只在Linux上testing过,但是我打算把它们转移到或多或less所有受欢迎和不受欢迎的桌面操作系统上(也可以在服务器上运行)。 任何平台上的任何想法是受欢迎的。

CPU频率被大多数操作系统视为系统属性。 因此,您不能在没有root权限的情况下更改它。 有一些关于扩展的研究允许通过具体的程序; 然而,由于即使对于相同的通用架构,能量/性能模型也不同,您很难找到一个通用的解决方案。

另外请注意,为了保证公平,linux调度器共享孩子第一个时代的perent和子进程的执行时间。 这可能会对您的问题产生影响。