使用perl脚本来最佳地使用可用的cpus

时间:2015-11-30 06:36:39

标签: perl parallel-processing cpu-usage

我编写了一个perl脚本,它多次启动一个程序,在for循环中使用不同的参数。该程序进行数值计算,并使用整个CPU,如果它可以得到一个。我有几个CPU可用,所以理想情况下,我想一次启动尽可能多的程序实例,因为有可用的CPU,但不是更多。由于可能正在运行其他进程,因此可用CPU的数量并不总是相同。

到目前为止,我所做的是:

#!/usr/bin/perl

use strict;
use warnings;

use IPC::Open2;
use Parallel::ForkManager;

my $program = "./program";

my($out, $in);
my $pid;

my $pm = new Parallel::ForkManager(44);

for my $x (0..100){
          my $childpid = $pm->start and next; 
          $pid= open2($out, $in, $program);

          print $in <<EOF;
          #input involving $x
EOF
          my $printstring = "";
          while(<$out>){
            if (/^\s*1\.000\s+(-\S+)D(\S+)\s*$/){
               $printstring .= "$1e$2";
            }
          }
          print $printstring, "\n";
          waitpid( $pid, 0 );
          $pm->finish;

}
$pm->wait_all_children;
print "\n\n END\n";

这显然包含一定数量的进程启动,从而可以使用固定数量的CPU,我不知道如何更改它以灵活地确定可用的CPU并相应地更改子进程数。任何想法如何做到这一点?

更新

为了清楚起见,这里的限制因素肯定是CPU时间而不是I / O的东西。

我调查了loadavg,但我对它的输出感到困惑。

68.71 66.40 63.72 70/1106 19247

与此同时,top显示

Tasks: 978 total,  23 running, 955 sleeping,   0 stopped,   0 zombie
Cpu(s):  2.1%us,  1.5%sy, 93.3%ni,  3.1%id,  0.0%wa,  0.0%hi,  0.0%si,  0.0%st

CPU的数量是48,所以我认为如果第四个数字(在这种情况下为70)大于48,我不应该再启动子进程,但根据顶部似乎有一些空闲CPU那里,虽然第四个数字是70。

2 个答案:

答案 0 :(得分:2)

我打算建议采取稍微不同的方法 - 如何,而不是“扼杀”&#39;基于加载的活动进程数 - 为什么不使用SIGSTOPSIGCONT

Parallel::ForkManager为您提供running_procs方法,该方法返回PID列表。

当负载平均值过高时,您可以signalSTOP的那些人。{#1}}

你可以找到&#34;太高&#34;使用Sys::Info::CPU(这也告诉你load)或者 - 或许看看Number of processors/cores in command line

但从理论上讲 - 当负载过高时,发出&#39; SIGSTOP&#39;对你的一些子进程。他们退出运行队列,并且可见但已暂停。

就平均负载而言 - 您会得到3个数字。 1m,5m和15m CPU负载。看看第一个,如果那个大于CPU的数量,你就会有争用。

答案 1 :(得分:1)

可能总会有进程弹跳,有些将使用比其他进程更多的CPU。我认为另一种方法是查看每个CPU使用其空闲百分比的繁忙程度。类似下面的代码片段就可以实现这个目标。然后,您可以设置一个阈值,以确定它是否超过某个空闲量。然后,您可以使用返回的数字来确定要启动的进程数量。这样的事情会让我相信:

#!/usr/bin/env perl

use strict;
use warnings;
use FileHandle;

#Get number of cores over 95% idle
# this can be adjusted
my $idle_percent=90;
my $free_cores=GetCores($idle_percent);
printf( "Cores over %s free: %s\n",$idle_percent,$free_cores);

sub GetCores {
    my $threshold=shift;
    my $cpu_idle_count=0;

    my $delta_time_sleep=2; #Amount of sleep between the 2 samples
    my @cpu_idle_totals;
    my @cpu_total_totals;

    for(0..1) {
        my $output_fh=FileHandle->new('/proc/stat','r') or die "No stat";
        # Get output of /proc/stat
        while ( my $line=$output_fh->getline() ) {
            chomp($line);
            my ($tag,$user,$nice,$system,$idle,$iowait,$irq,$softirq)
                =split( /\s+/, $line);

            if ( $tag=~ m/cpu(.+)/ ) {
                my $cpu_number=$1;

                my $total=( 
                    $user + $nice + $system + $idle 
                    + $iowait + $irq + $softirq
                );

                if ( defined( $cpu_idle_totals[$cpu_number] ) ) {
                    my $idle_delta=$idle-$cpu_idle_totals[$cpu_number];
                    my $total_delta=$total-$cpu_total_totals[$cpu_number];
                    my $usage=100 * (($idle_delta)/$total_delta);
                    printf("%s is %0.2f%% idle\n",$tag,$usage);

                    if ( $usage >= $threshold ) {
                        $cpu_idle_count++;
                    }
                }

                $cpu_idle_totals[$cpu_number]=$idle;
                $cpu_total_totals[$cpu_number]=$total;

            }
        }

        $output_fh->close();
        sleep $delta_time_sleep;
    }


    return $cpu_idle_count;
} 

输出:

cpu0 is 89.90% idle
cpu1 is 94.97% idle
cpu2 is 95.02% idle
cpu3 is 97.00% idle
cpu4 is 96.98% idle
cpu5 is 98.48% idle
cpu6 is 97.99% idle
cpu7 is 95.98% idle
Cores over 90% free:7