我想在Linux机器上创建一个接近100%的负载。这是四核系统,我要所有核都全速运转。理想情况下,CPU负载将持续一段指定的时间,然后停止。我希望bash里有什么妙招。我在想某种无限循环。


当前回答

awk是一种编写长时间运行的CPU循环的好方法,它不会产生大量内存流量或系统调用,也不会使用大量内存或污染缓存,从而使其他内核的速度降低到最低程度。(如果您使用简单的CPU-stress方法进行安装,则stress或stress-ng也可以做到这一点。)

awk 'BEGIN{for(i=0;i<100000000;i++){}}'   # about 3 seconds on 4GHz Skylake

这是一个计数循环,所以你可以让它在有限时间后自行退出。(Awk使用FP数字,因此由于舍入,i++可能无法达到2^54这样的限制,但这比几秒到几分钟所需的要大得多。)

要并行运行它,可以使用shell循环在后台启动n次

for i in {1..6};do awk 'BEGIN{for(i=0;i<100000000;i++){}}' & done

######     6 threads                      each running about 3 seconds
$ for i in {1..6};do awk 'BEGIN{for(i=0;i<100000000;i++){}}' & done
[1] 3047561
[2] 3047562
[3] 3047563
[4] 3047564
[5] 3047565
[6] 3047566
$              # this shell is usable.
(wait a while before pressing return)
[1]   Done                    awk 'BEGIN{for(i=0;i<100000000;i++){}}'
[2]   Done                    awk 'BEGIN{for(i=0;i<100000000;i++){}}'
[3]   Done                    awk 'BEGIN{for(i=0;i<100000000;i++){}}'
[4]   Done                    awk 'BEGIN{for(i=0;i<100000000;i++){}}'
[5]-  Done                    awk 'BEGIN{for(i=0;i<100000000;i++){}}'
[6]+  Done                    awk 'BEGIN{for(i=0;i<100000000;i++){}}'
$

我使用perf来查看它对CPU的负载:它每个时钟周期运行2.6条指令,所以它对共享同一个物理内核的超线程不是最友好的。但是它的缓存占用非常小,即使在L1d缓存中也可以忽略不计。strace将显示它在退出之前不进行系统调用。

$ perf stat -r5 -d awk 'BEGIN{for(i=0;i<100000000;i++){}}'

 Performance counter stats for 'awk BEGIN{for(i=0;i<100000000;i++){}}' (5 runs):

          3,277.56 msec task-clock                #    0.997 CPUs utilized            ( +-  0.24% )
                 7      context-switches          #    2.130 /sec                     ( +- 12.29% )
                 1      cpu-migrations            #    0.304 /sec                     ( +- 40.00% )
               180      page-faults               #   54.765 /sec                     ( +-  0.18% )
    13,708,412,234      cycles                    #    4.171 GHz                      ( +-  0.18% )  (62.29%)
    35,786,486,833      instructions              #    2.61  insn per cycle           ( +-  0.03% )  (74.92%)
     9,696,339,695      branches                  #    2.950 G/sec                    ( +-  0.02% )  (74.99%)
           340,155      branch-misses             #    0.00% of all branches          ( +-122.42% )  (75.08%)
    12,108,293,527      L1-dcache-loads           #    3.684 G/sec                    ( +-  0.04% )  (75.10%)
           217,064      L1-dcache-load-misses     #    0.00% of all L1-dcache accesses  ( +- 17.23% )  (75.10%)
            48,695      LLC-loads                 #   14.816 K/sec                    ( +- 31.69% )  (49.90%)
             5,966      LLC-load-misses           #   13.45% of all LL-cache accesses  ( +- 31.45% )  (49.81%)

           3.28711 +- 0.00772 seconds time elapsed  ( +-  0.23% )

对x86 CPU上的其他超线程最“友好”的是这样的C程序,它只是在循环中运行暂停指令。(或可移植地,Rust程序运行std::hint::spin_loop。)至于操作系统的进程调度器,它停留在用户空间(与yield()系统调用不同),但在硬件上,它不会占用太多资源,让其他逻辑核心拥有多个周期的前端。

#include <immintrin.h>
int main(){                    // use atoi(argv[1])*10000ULL as a loop count if you want.
    while(1) _mm_pause();
}

其他回答

使用这里提到的例子,以及IRC的帮助,我开发了自己的CPU压力测试脚本。它使用每个线程一个子shell和无限循环技术。您还可以交互地指定线程数和时间量。

#!/bin/bash
# Simple CPU stress test script

# Read the user's input
echo -n "Number of CPU threads to test: "
read cpu_threads
echo -n "Duration of the test (in seconds): "
read cpu_time

# Run an endless loop on each thread to generate 100% CPU
echo -e "\E[32mStressing ${cpu_threads} threads for ${cpu_time} seconds...\E[37m"
for i in $(seq ${cpu_threads}); do
    let thread=${i}-1
    (taskset -cp ${thread} $BASHPID; while true; do true; done) &
done

# Once the time runs out, kill all of the loops
sleep ${cpu_time}
echo -e "\E[32mStressing complete.\E[37m"
kill 0

我认为这个更简单。打开“终端”,输入以下命令并按“Enter”。

yes > /dev/null &

要充分利用现代CPU,一行命令是不够的,您可能需要重复该命令以耗尽所有CPU功率。

为了结束这一切,简单地说

killall yes

这个想法最初是在这里发现的,尽管它是为Mac用户设计的,但这应该也适用于*nix。

你可以在这里下载一个程序

在Linux系统上轻松安装

./configure
make
make install

并在简单的命令行中启动它

stress -c 40

让所有的cpu(不管你有多少)都有40个线程,每个线程在随机生成的数字上运行复杂的根号计算。

您甚至可以定义程序的超时时间

stress -c 40 -timeout 10s

与提议的dd命令解决方案不同,dd命令主要处理IO,因此不会因为处理数据而真正使系统过载。

压力程序会使系统超负荷因为要处理计算。

这对我来说很有用:

bash -c 'for (( I=100000000000000000000 ; I>=0 ; I++ )) ; do echo $(( I+I*I )) & echo $(( I*I-I )) & echo $(( I-I*I*I )) & echo $(( I+I*I*I )) ; done' &>/dev/null

它只使用bash。

利用这里的想法,创建的代码在设定的持续时间后自动退出,不需要杀死进程

#!/bin/bash
echo "Usage : ./killproc_ds.sh 6 60  (6 threads for 60 secs)"

# Define variables
NUM_PROCS=${1:-6} #How much scaling you want to do
duration=${2:-20}    # seconds

function infinite_loop {
endtime=$(($(date +%s) + $duration))
while (($(date +%s) < $endtime)); do
    #echo $(date +%s)
    echo $((13**99)) 1>/dev/null 2>&1
    $(dd if=/dev/urandom count=10000 status=none| bzip2 -9 >> /dev/null) 2>&1 >&/dev/null
done
echo "Done Stressing the system - for thread $1"
}


echo Running for duration $duration secs, spawning $NUM_PROCS threads in background
for i in `seq ${NUM_PROCS}` ;
do
# Put an infinite loop
    infinite_loop $i  &
done