使用 perl 脚本优化使用可用的 cpu
use perl script to optimally use available cpus
我写了一个小的 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 .= "e";
}
}
print $printstring, "\n";
waitpid( $pid, 0 );
$pm->finish;
}
$pm->wait_all_children;
print "\n\n END\n";
这显然包含要启动的固定数量的进程,因此可以使用固定数量的 CPUs,我不知道如何改变它以灵活地确定可用的 CPUs 并相应地更改 children 的数量。任何想法如何做到这一点?
更新:
明确一点,这里的限制因素绝对是 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,我就不应该再启动child个进程了, 但根据 top 似乎有一些空闲 CPU 那里,虽然第四个数字是 70.
可能总会有进程跳来跳去,有些进程会比其他进程使用更多 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=;
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
我建议采取稍微不同的方法 - 怎么样,而不是 'throttling' 基于负载的活动进程数 - 为什么不使用 SIGSTOP
和 SIGCONT
。
Parallel::ForkManager
为您提供 running_procs
方法,其中 returns PID 列表。
当平均负载达到 'too high' 时,您可以 signal
将这些 STOP
。
您可以使用 Sys::Info::CPU
(This also tells you load
) or - perhaps look at Number of processors/cores in command line
找到 "too high"
但理论上 - 当负载过高时,向您的一些子进程发出 'SIGSTOP'。他们 应该 退出 运行 队列,可见但被暂停。
就平均负载而言 - 您会得到 3 个数字。 1m、5m 和 15m CPU 负载。查看第一个,如果它大于 CPU 的数量,则说明存在争用。
我写了一个小的 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 .= "e";
}
}
print $printstring, "\n";
waitpid( $pid, 0 );
$pm->finish;
}
$pm->wait_all_children;
print "\n\n END\n";
这显然包含要启动的固定数量的进程,因此可以使用固定数量的 CPUs,我不知道如何改变它以灵活地确定可用的 CPUs 并相应地更改 children 的数量。任何想法如何做到这一点?
更新:
明确一点,这里的限制因素绝对是 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,我就不应该再启动child个进程了, 但根据 top 似乎有一些空闲 CPU 那里,虽然第四个数字是 70.
可能总会有进程跳来跳去,有些进程会比其他进程使用更多 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=;
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
我建议采取稍微不同的方法 - 怎么样,而不是 'throttling' 基于负载的活动进程数 - 为什么不使用 SIGSTOP
和 SIGCONT
。
Parallel::ForkManager
为您提供 running_procs
方法,其中 returns PID 列表。
当平均负载达到 'too high' 时,您可以 signal
将这些 STOP
。
您可以使用 Sys::Info::CPU
(This also tells you load
) or - perhaps look at Number of processors/cores in command line
但理论上 - 当负载过高时,向您的一些子进程发出 'SIGSTOP'。他们 应该 退出 运行 队列,可见但被暂停。
就平均负载而言 - 您会得到 3 个数字。 1m、5m 和 15m CPU 负载。查看第一个,如果它大于 CPU 的数量,则说明存在争用。