You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
737 lines
17 KiB
737 lines
17 KiB
#! /usr/bin/perl
|
|
#
|
|
# Copyright © 2017 Intel Corporation
|
|
#
|
|
# Permission is hereby granted, free of charge, to any person obtaining a
|
|
# copy of this software and associated documentation files (the "Software"),
|
|
# to deal in the Software without restriction, including without limitation
|
|
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
# and/or sell copies of the Software, and to permit persons to whom the
|
|
# Software is furnished to do so, subject to the following conditions:
|
|
#
|
|
# The above copyright notice and this permission notice (including the next
|
|
# paragraph) shall be included in all copies or substantial portions of the
|
|
# Software.
|
|
#
|
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
|
# IN THE SOFTWARE.
|
|
#
|
|
|
|
use strict;
|
|
use warnings;
|
|
use 5.010;
|
|
|
|
use Getopt::Std;
|
|
|
|
chomp(my $igt_root = `pwd -P`);
|
|
my $wsim = "$igt_root/benchmarks/gem_wsim";
|
|
my $wrk_root = "$igt_root/benchmarks/wsim";
|
|
my $tracepl = "$igt_root/scripts/trace.pl";
|
|
my $tolerance = 0.01;
|
|
my $client_target_s = 10;
|
|
my $idle_tolerance_pct = 2.0;
|
|
my $verbose = 0;
|
|
my $gt2 = 0;
|
|
my $show_cmds = 0;
|
|
my $realtime_target = 0;
|
|
my $wps_target = 0;
|
|
my $wps_target_param = 0;
|
|
my $multi_mode = 0;
|
|
my @multi_workloads;
|
|
my $w_direct;
|
|
my $balancer;
|
|
my $nop;
|
|
my %opts;
|
|
|
|
my @balancers = ( 'rr', 'rand', 'qd', 'qdr', 'qdavg', 'rt', 'rtr', 'rtavg',
|
|
'context', 'busy', 'busy-avg', 'i915' );
|
|
my %bal_skip_H = ( 'rr' => 1, 'rand' => 1, 'context' => 1, , 'busy' => 1,
|
|
'busy-avg' => 1, 'i915' => 1 );
|
|
my %bal_skip_R = ( 'i915' => 1 );
|
|
my %bal_skip_G = ( 'i915' => 1 );
|
|
|
|
my @workloads = (
|
|
'media_load_balance_17i7.wsim',
|
|
'media_load_balance_19.wsim',
|
|
'media_load_balance_4k12u7.wsim',
|
|
'media_load_balance_fhd26u7.wsim',
|
|
'media_load_balance_hd01.wsim',
|
|
'media_load_balance_hd06mp2.wsim',
|
|
'media_load_balance_hd12.wsim',
|
|
'media_load_balance_hd17i4.wsim',
|
|
'media_1n2_480p.wsim',
|
|
'media_1n3_480p.wsim',
|
|
'media_1n4_480p.wsim',
|
|
'media_1n5_480p.wsim',
|
|
'media_1n2_asy.wsim',
|
|
'media_1n3_asy.wsim',
|
|
'media_1n4_asy.wsim',
|
|
'media_1n5_asy.wsim',
|
|
'media_mfe2_480p.wsim',
|
|
'media_mfe3_480p.wsim',
|
|
'media_mfe4_480p.wsim',
|
|
'media_nn_1080p.wsim',
|
|
'media_nn_480p.wsim',
|
|
);
|
|
|
|
sub show_cmd
|
|
{
|
|
my ($cmd) = @_;
|
|
|
|
say "\n+++ $cmd" if $show_cmds;
|
|
}
|
|
|
|
sub calibrate_nop
|
|
{
|
|
my ($delay, $nop);
|
|
my $cmd = "$wsim";
|
|
|
|
show_cmd($cmd);
|
|
open WSIM, "$cmd |" or die;
|
|
while (<WSIM>) {
|
|
chomp;
|
|
if (/Nop calibration for (\d+)us delay is (\d+)./) {
|
|
$delay = $1;
|
|
$nop = $2;
|
|
}
|
|
|
|
}
|
|
close WSIM;
|
|
|
|
die unless $nop;
|
|
|
|
return $nop
|
|
}
|
|
|
|
sub can_balance_workload
|
|
{
|
|
my ($wrk) = @_;
|
|
my $res = 0;
|
|
|
|
open WRK, "$wrk_root/$wrk" or die;
|
|
while (<WRK>) {
|
|
chomp;
|
|
if (/\.VCS\./) {
|
|
$res = 1;
|
|
last;
|
|
}
|
|
}
|
|
close WRK;
|
|
|
|
return $res;
|
|
}
|
|
|
|
sub add_wps_arg
|
|
{
|
|
my (@args) = @_;
|
|
my $period;
|
|
|
|
return @args if $realtime_target <= 0;
|
|
|
|
$period = int(1000000 / $realtime_target);
|
|
push @args, '-a';
|
|
push @args, 'p.$period';
|
|
|
|
return @args;
|
|
}
|
|
|
|
sub run_workload
|
|
{
|
|
my (@args) = @_;
|
|
my ($time, $wps, $cmd);
|
|
my @ret;
|
|
|
|
@args = add_wps_arg(@args);
|
|
push @args, '-2' if $gt2;
|
|
|
|
unshift @args, $wsim;
|
|
$cmd = join ' ', @args;
|
|
show_cmd($cmd);
|
|
|
|
open WSIM, "$cmd |" or die;
|
|
while (<WSIM>) {
|
|
chomp;
|
|
if (/^(\d+\.\d+)s elapsed \((\d+\.?\d+) workloads\/s\)$/) {
|
|
$time = $1;
|
|
$wps = $2;
|
|
} elsif (/(\d+)\: \d+\.\d+s elapsed \(\d+ cycles, (\d+\.?\d+) workloads\/s\)/) {
|
|
$ret[$1] = $2;
|
|
}
|
|
}
|
|
close WSIM;
|
|
|
|
return ($time, $wps, \@ret);
|
|
}
|
|
|
|
sub dump_cmd
|
|
{
|
|
my ($cmd, $file) = @_;
|
|
|
|
show_cmd("$cmd > $file");
|
|
|
|
open FOUT, '>', $file or die;
|
|
open TIN, "$cmd |" or die;
|
|
while (<TIN>) {
|
|
print FOUT $_;
|
|
}
|
|
close TIN;
|
|
close FOUT;
|
|
}
|
|
|
|
sub trace_workload
|
|
{
|
|
my ($wrk, $b, $r, $c) = @_;
|
|
my @args = ($tracepl, '--trace', $wsim, '-q', '-n', $nop, '-r', $r, '-c', $c);
|
|
my $min_batches = 16 + $r * $c / 2;
|
|
my @skip_engine;
|
|
my %engines;
|
|
my ($cmd, $file);
|
|
|
|
push @args, '-2' if $gt2;
|
|
|
|
unless ($b eq '<none>') {
|
|
push @args, '-R';
|
|
push @args, split /\s+/, $b;
|
|
}
|
|
|
|
if (defined $w_direct) {
|
|
push @args, split /\s+/, $wrk;
|
|
} else {
|
|
push @args, '-w';
|
|
push @args, $wrk_root . '/' . $wrk;
|
|
}
|
|
|
|
show_cmd(join ' ', @args);
|
|
if (-e 'perf.data') {
|
|
unlink 'perf.data' or die;
|
|
}
|
|
system(@args) == 0 or die;
|
|
|
|
$cmd = "perf script | $tracepl";
|
|
show_cmd($cmd);
|
|
open CMD, "$cmd |" or die;
|
|
while (<CMD>) {
|
|
chomp;
|
|
if (/Ring(\S+): (\d+) batches.*?(\d+\.?\d+)% idle,/) {
|
|
if ($2 >= $min_batches) {
|
|
$engines{$1} = $3;
|
|
} else {
|
|
push @skip_engine, $1;
|
|
}
|
|
} elsif (/GPU: (\d+\.?\d+)% idle/) {
|
|
$engines{'gpu'} = $1;
|
|
}
|
|
}
|
|
close CMD;
|
|
|
|
$wrk =~ s/$wrk_root//g;
|
|
$wrk =~ s/\.wsim//g;
|
|
$wrk =~ s/-w/W/g;
|
|
$wrk =~ s/[ -]/_/g;
|
|
$wrk =~ s/\//-/g;
|
|
$b =~ s/[ <>]/_/g;
|
|
$file = "${wrk}_${b}_-r${r}_-c${c}";
|
|
|
|
dump_cmd('perf script', "${file}.trace");
|
|
|
|
$cmd = "perf script | $tracepl --html -x ctxsave -s -c ";
|
|
$cmd .= join ' ', map("-i $_", @skip_engine);
|
|
|
|
dump_cmd($cmd, "${file}.html");
|
|
|
|
return \%engines;
|
|
}
|
|
|
|
sub calibrate_workload
|
|
{
|
|
my ($wrk) = @_;
|
|
my $tol = $tolerance;
|
|
my $loops = 0;
|
|
my $error;
|
|
my $r;
|
|
|
|
$r = $realtime_target > 0 ? $realtime_target * $client_target_s : 23;
|
|
for (;;) {
|
|
my @args = ('-n', $nop, '-r', $r);
|
|
my ($time, $wps);
|
|
|
|
if (defined $w_direct) {
|
|
push @args, split /\s+/, $wrk;
|
|
} else {
|
|
push @args, '-w';
|
|
push @args, $wrk_root . '/' . $wrk;
|
|
}
|
|
|
|
($time, $wps) = run_workload(@args);
|
|
|
|
$wps = $r / $time if $w_direct;
|
|
$error = abs($time - $client_target_s) / $client_target_s;
|
|
|
|
last if $error <= $tol;
|
|
|
|
$r = int($wps * $client_target_s);
|
|
$loops = $loops + 1;
|
|
if ($loops >= 3) {
|
|
$tol = $tol * (1.2 + ($tol));
|
|
$loops = 0;
|
|
}
|
|
last if $tol > 0.2;
|
|
}
|
|
|
|
return ($r, $error);
|
|
}
|
|
|
|
sub find_saturation_point
|
|
{
|
|
my ($wrk, $rr, $verbose, @args) = @_;
|
|
my ($last_wps, $c, $swps, $wwps);
|
|
my $target = $realtime_target > 0 ? $realtime_target : $wps_target;
|
|
my $r = $rr;
|
|
my $wcnt;
|
|
my $maxc;
|
|
my $max = 0;
|
|
|
|
push @args, '-v' if $multi_mode and $w_direct;
|
|
|
|
if (defined $w_direct) {
|
|
push @args, split /\s+/, $wrk;
|
|
$wcnt = () = $wrk =~ /-[wW]/gi;
|
|
|
|
} else {
|
|
push @args, '-w';
|
|
push @args, $wrk_root . '/' . $wrk;
|
|
$wcnt = 1;
|
|
}
|
|
|
|
for ($c = 1; ; $c = $c + 1) {
|
|
my ($time, $wps);
|
|
my @args_ = (@args, ('-r', $r, '-c', $c));
|
|
|
|
($time, $wps, $wwps) = run_workload(@args_);
|
|
|
|
say " $c clients is $wps wps." if $verbose;
|
|
|
|
if ($c > 1) {
|
|
my $delta;
|
|
|
|
if ($target <= 0) {
|
|
if ($wps > $max) {
|
|
$max = $wps;
|
|
$maxc = $c;
|
|
}
|
|
$delta = ($wps - $last_wps) / $last_wps;
|
|
if ($delta > 0) {
|
|
last if $delta < $tolerance;
|
|
} else {
|
|
$delta = ($wps - $max) / $max;
|
|
last if abs($delta) >= $tolerance;
|
|
}
|
|
} else {
|
|
$delta = ($wps / $c - $target) / $target;
|
|
last if $delta < 0 and abs($delta) >= $tolerance;
|
|
}
|
|
$r = int($rr * ($client_target_s / $time));
|
|
} elsif ($c == 1) {
|
|
$swps = $wps;
|
|
return ($c, $wps, $swps, $wwps) if $wcnt > 1 or
|
|
$multi_mode or
|
|
($wps_target_param < 0 and
|
|
$wps_target == 0);
|
|
}
|
|
|
|
$last_wps = $wps;
|
|
}
|
|
|
|
if ($target <= 0) {
|
|
return ($maxc, $max, $swps, $wwps);
|
|
} else {
|
|
return ($c - 1, $last_wps, $swps, $wwps);
|
|
}
|
|
}
|
|
|
|
getopts('hv2xmn:b:W:B:r:t:i:R:T:w:', \%opts);
|
|
|
|
if (defined $opts{'h'}) {
|
|
print <<ENDHELP;
|
|
Supported options:
|
|
|
|
-h Help text.
|
|
-v Be verbose.
|
|
-x Show external commands.
|
|
-2 Run gem_wsim in GT2 mode.
|
|
-n num Nop calibration.
|
|
-b str Balancer to pre-select.
|
|
Skips balancer auto-selection.
|
|
Passed straight the gem_wsim so use like -b "-b qd -R"
|
|
-W a,b,c Override the default list of workloads.
|
|
-B a,b,c Override the default list of balancers.
|
|
-r sec Target workload duration.
|
|
-t pct Calibration tolerance.
|
|
-i pct Engine idleness tolerance.
|
|
-R wps Run workloads in the real-time mode at wps rate.
|
|
-T wps Calibrate up to wps/client target instead of GPU saturation.
|
|
Negative values set the target based on the single client
|
|
performance where target = single-client-wps / -N.
|
|
-w str Pass-through to gem_wsim. Overrides normal workload selection.
|
|
-m Multi-workload mode. All selected workloads will be run in
|
|
parallel and overal score will be relative to when run
|
|
individually.
|
|
ENDHELP
|
|
exit 0;
|
|
}
|
|
|
|
$verbose = 1 if defined $opts{'v'};
|
|
$gt2 = 1 if defined $opts{'2'};
|
|
$show_cmds = 1 if defined $opts{'x'};
|
|
$multi_mode = 1 if defined $opts{'m'};
|
|
if (defined $opts{'b'}) {
|
|
die unless substr($opts{'b'}, 0, 2) eq '-b';
|
|
$balancer = $opts{'b'};
|
|
}
|
|
if (defined $opts{'B'}) {
|
|
@balancers = split /,/, $opts{'B'};
|
|
} else {
|
|
unshift @balancers, '';
|
|
}
|
|
@workloads = split /,/, $opts{'W'} if defined $opts{'W'};
|
|
$client_target_s = $opts{'r'} if defined $opts{'r'};
|
|
$tolerance = $opts{'t'} / 100.0 if defined $opts{'t'};
|
|
$idle_tolerance_pct = $opts{'i'} if defined $opts{'i'};
|
|
$realtime_target = $opts{'R'} if defined $opts{'R'};
|
|
$wps_target = $opts{'T'} if defined $opts{'T'};
|
|
$wps_target_param = $wps_target;
|
|
$w_direct = $opts{'w'} if defined $opts{'w'};
|
|
|
|
if ($multi_mode) {
|
|
die if $w_direct; # Not supported
|
|
@multi_workloads = @workloads;
|
|
}
|
|
|
|
@workloads = ($w_direct) if defined $w_direct;
|
|
|
|
say "Workloads:";
|
|
print map { " $_\n" } @workloads;
|
|
print "Balancers: ";
|
|
say map { "$_," } @balancers;
|
|
say "Target workload duration is ${client_target_s}s.";
|
|
say "Calibration tolerance is $tolerance.";
|
|
say "Real-time mode at ${realtime_target} wps." if $realtime_target > 0;
|
|
say "Wps target is ${wps_target} wps." if $wps_target > 0;
|
|
say "Multi-workload mode." if $multi_mode;
|
|
$nop = $opts{'n'};
|
|
$nop = calibrate_nop() unless $nop;
|
|
say "Nop calibration is $nop.";
|
|
|
|
goto VERIFY if defined $balancer;
|
|
|
|
my (%best_bal, %best_bid);
|
|
my %results;
|
|
my %scores;
|
|
my %wscores;
|
|
my %cscores;
|
|
my %cwscores;
|
|
my %mscores;
|
|
my %mwscores;
|
|
|
|
sub add_points
|
|
{
|
|
my ($wps, $scores, $wscores) = @_;
|
|
my ($min, $max, $spread);
|
|
my @sorted;
|
|
|
|
@sorted = sort { $b <=> $a } values %{$wps};
|
|
$max = $sorted[0];
|
|
$min = $sorted[-1];
|
|
$spread = $max - $min;
|
|
die if $spread < 0;
|
|
|
|
foreach my $w (keys %{$wps}) {
|
|
my ($score, $wscore);
|
|
|
|
unless (exists $scores->{$w}) {
|
|
$scores->{$w} = 0;
|
|
$wscores->{$w} = 0;
|
|
}
|
|
|
|
$score = $wps->{$w} / $max;
|
|
$scores->{$w} = $scores->{$w} + $score;
|
|
$wscore = $score * $spread / $max;
|
|
$wscores->{$w} = $wscores->{$w} + $wscore;
|
|
}
|
|
}
|
|
|
|
my @saturation_workloads = $multi_mode ? @multi_workloads : @workloads;
|
|
my %allwps;
|
|
my $widx = 0;
|
|
|
|
push @saturation_workloads, '-w ' . join ' -w ', map("$wrk_root/$_", @workloads)
|
|
if $multi_mode;
|
|
|
|
foreach my $wrk (@saturation_workloads) {
|
|
my @args = ( "-n $nop");
|
|
my ($r, $error, $should_b, $best);
|
|
my (%wps, %cwps, %mwps);
|
|
my @sorted;
|
|
my $range;
|
|
|
|
$w_direct = $wrk if $multi_mode and $widx == $#saturation_workloads;
|
|
|
|
$should_b = 1;
|
|
$should_b = can_balance_workload($wrk) unless defined $w_direct;
|
|
|
|
print "\nEvaluating '$wrk'...";
|
|
|
|
($r, $error) = calibrate_workload($wrk);
|
|
say " ${client_target_s}s is $r workloads. (error=$error)";
|
|
|
|
say " Finding saturation points for '$wrk'...";
|
|
|
|
BAL: foreach my $bal (@balancers) {
|
|
GBAL: foreach my $G ('', '-G', '-d', '-G -d') {
|
|
foreach my $H ('', '-H') {
|
|
my @xargs;
|
|
my ($w, $c, $s, $bwwps);
|
|
my $bid;
|
|
|
|
if ($bal ne '') {
|
|
next GBAL if $G =~ '-G' and exists $bal_skip_G{$bal};
|
|
|
|
push @xargs, "-b $bal";
|
|
push @xargs, '-R' unless exists $bal_skip_R{$bal};
|
|
push @xargs, $G if $G ne '';
|
|
push @xargs, $H if $H ne '';
|
|
$bid = join ' ', @xargs;
|
|
print " $bal balancer ('$bid'): ";
|
|
} else {
|
|
$bid = '<none>';
|
|
print " No balancing: ";
|
|
}
|
|
|
|
$wps_target = 0 if $wps_target_param < 0;
|
|
|
|
($c, $w, $s, $bwwps) =
|
|
find_saturation_point($wrk, $r, 0,
|
|
(@args, @xargs));
|
|
|
|
if ($wps_target_param < 0) {
|
|
$wps_target = $s / -$wps_target_param;
|
|
|
|
($c, $w, $s, $bwwps) =
|
|
find_saturation_point($wrk, $r,
|
|
0,
|
|
(@args,
|
|
@xargs));
|
|
}
|
|
|
|
if ($multi_mode and $w_direct) {
|
|
my $widx;
|
|
|
|
die unless scalar(@multi_workloads) ==
|
|
scalar(@{$bwwps});
|
|
die unless scalar(@multi_workloads) ==
|
|
scalar(keys %allwps);
|
|
|
|
# Total of all workload wps from the
|
|
# mixed run.
|
|
$w = 0;
|
|
foreach $widx (0..$#{$bwwps}) {
|
|
$w += $bwwps->[$widx];
|
|
}
|
|
|
|
# Total of all workload wps from when
|
|
# ran individually with the best
|
|
# balancer.
|
|
my $tot = 0;
|
|
foreach my $wrk (@multi_workloads) {
|
|
$tot += $allwps{$wrk}->{$best_bid{$wrk}};
|
|
}
|
|
|
|
# Normalize mixed sum with sum of
|
|
# individual runs.
|
|
$w *= 100;
|
|
$w /= $tot;
|
|
|
|
# Second metric is average of each
|
|
# workload wps normalized by their
|
|
# individual run performance with the
|
|
# best balancer.
|
|
$s = 0;
|
|
$widx = 0;
|
|
foreach my $wrk (@multi_workloads) {
|
|
$s += 100 * $bwwps->[$widx] /
|
|
$allwps{$wrk}->{$best_bid{$wrk}};
|
|
$widx++;
|
|
}
|
|
$s /= scalar(@multi_workloads);
|
|
|
|
say sprintf('Aggregate (normalized) %.2f%%; fairness %.2f%%',
|
|
$w, $s);
|
|
} else {
|
|
$allwps{$wrk} = \%wps;
|
|
}
|
|
|
|
$wps{$bid} = $w;
|
|
$cwps{$bid} = $s;
|
|
|
|
if ($realtime_target > 0 || $wps_target_param > 0) {
|
|
$mwps{$bid} = $w * $c;
|
|
} else {
|
|
$mwps{$bid} = $w + $s;
|
|
}
|
|
|
|
say "$c clients ($w wps, $s wps single client, score=$mwps{$bid})."
|
|
unless $multi_mode and $w_direct;
|
|
|
|
last BAL unless $should_b;
|
|
next BAL if $bal eq '';
|
|
next GBAL if exists $bal_skip_H{$bal};
|
|
}
|
|
}
|
|
}
|
|
|
|
$widx++;
|
|
|
|
@sorted = sort { $mwps{$b} <=> $mwps{$a} } keys %mwps;
|
|
$best_bid{$wrk} = $sorted[0];
|
|
@sorted = sort { $b <=> $a } values %mwps;
|
|
$range = 1 - $sorted[-1] / $sorted[0];
|
|
$best_bal{$wrk} = $sorted[0];
|
|
|
|
next if $multi_mode and not $w_direct;
|
|
|
|
say " Best balancer is '$best_bid{$wrk}' (range=$range).";
|
|
|
|
|
|
$results{$wrk} = \%mwps;
|
|
|
|
add_points(\%wps, \%scores, \%wscores);
|
|
add_points(\%mwps, \%mscores, \%mwscores);
|
|
add_points(\%cwps, \%cscores, \%cwscores);
|
|
}
|
|
|
|
sub dump_scoreboard
|
|
{
|
|
my ($n, $h) = @_;
|
|
my ($i, $str, $balancer);
|
|
my ($max, $range);
|
|
my @sorted;
|
|
|
|
@sorted = sort { $b <=> $a } values %{$h};
|
|
$max = $sorted[0];
|
|
$range = 1 - $sorted[-1] / $max;
|
|
$str = "$n rank (range=$range):";
|
|
say "\n$str";
|
|
say '=' x length($str);
|
|
$i = 1;
|
|
foreach my $w (sort { $h->{$b} <=> $h->{$a} } keys %{$h}) {
|
|
my $score;
|
|
|
|
$balancer = $w if $i == 1;
|
|
$score = $h->{$w} / $max;
|
|
|
|
say " $i: '$w' ($score)";
|
|
|
|
$i = $i + 1;
|
|
}
|
|
|
|
return $balancer;
|
|
}
|
|
|
|
dump_scoreboard($multi_mode ? 'Throughput' : 'Total wps', \%scores);
|
|
dump_scoreboard('Total weighted wps', \%wscores) unless $multi_mode;
|
|
dump_scoreboard($multi_mode ? 'Fairness' : 'Per client wps', \%cscores);
|
|
dump_scoreboard('Per client weighted wps', \%cwscores) unless $multi_mode;
|
|
$balancer = dump_scoreboard($multi_mode ? 'Combined' : 'Combined wps', \%mscores);
|
|
$balancer = dump_scoreboard('Combined weighted wps', \%mwscores) unless $multi_mode;
|
|
|
|
VERIFY:
|
|
|
|
my %problem_wrk;
|
|
|
|
die unless defined $balancer;
|
|
|
|
say "\nBalancer is '$balancer'.";
|
|
say "Idleness tolerance is $idle_tolerance_pct%.";
|
|
|
|
if ($multi_mode) {
|
|
$w_direct = '-w ' . join ' -w ', map("$wrk_root/$_", @workloads);
|
|
@workloads = ($w_direct);
|
|
}
|
|
|
|
foreach my $wrk (@workloads) {
|
|
my @args = ( "-n $nop" );
|
|
my ($r, $error, $c, $wps, $swps);
|
|
my $saturated = 0;
|
|
my $result = 'Pass';
|
|
my $vcs2 = $gt2 ? '1:0' : '2:1';
|
|
my %problem;
|
|
my $engines;
|
|
|
|
next if not defined $w_direct and not can_balance_workload($wrk);
|
|
|
|
push @args, $balancer unless $balancer eq '<none>';
|
|
|
|
if (scalar(keys %results)) {
|
|
$r = $results{$wrk}->{$balancer} / $best_bal{$wrk} * 100.0;
|
|
} else {
|
|
$r = '---';
|
|
}
|
|
say " \nProfiling '$wrk' ($r% of best)...";
|
|
|
|
($r, $error) = calibrate_workload($wrk);
|
|
say " ${client_target_s}s is $r workloads. (error=$error)";
|
|
|
|
($c, $wps, $swps) = find_saturation_point($wrk, $r, $verbose, @args);
|
|
say " Saturation at $c clients ($wps workloads/s).";
|
|
push @args, "-c $c";
|
|
|
|
$engines = trace_workload($wrk, $balancer, $r, $c);
|
|
|
|
foreach my $key (keys %{$engines}) {
|
|
next if $key eq 'gpu';
|
|
$saturated = $saturated + 1
|
|
if $engines->{$key} < $idle_tolerance_pct;
|
|
}
|
|
|
|
if ($saturated == 0) {
|
|
# Not a single saturated engine
|
|
$result = 'FAIL';
|
|
} elsif (not exists $engines->{'2:0'} or not exists $engines->{$vcs2}) {
|
|
# VCS1 and VCS2 not present in a balancing workload
|
|
$result = 'FAIL';
|
|
} elsif ($saturated == 1 and
|
|
($engines->{'2:0'} < $idle_tolerance_pct or
|
|
$engines->{$vcs2} < $idle_tolerance_pct)) {
|
|
# Only one VCS saturated
|
|
$result = 'WARN';
|
|
}
|
|
|
|
$result = 'WARN' if $engines->{'gpu'} > $idle_tolerance_pct;
|
|
|
|
if ($result ne 'Pass') {
|
|
$problem{'c'} = $c;
|
|
$problem{'r'} = $r;
|
|
$problem{'stats'} = $engines;
|
|
$problem_wrk{$wrk} = \%problem;
|
|
}
|
|
|
|
print " $result [";
|
|
print map " $_: $engines->{$_}%,", sort keys %{$engines};
|
|
say " ]";
|
|
}
|
|
|
|
say "\nProblematic workloads were:" if scalar(keys %problem_wrk) > 0;
|
|
foreach my $wrk (sort keys %problem_wrk) {
|
|
my $problem = $problem_wrk{$wrk};
|
|
|
|
print " $wrk -c $problem->{'c'} -r $problem->{'r'} [";
|
|
print map " $_: $problem->{'stats'}->{$_}%,",
|
|
sort keys %{$problem->{'stats'}};
|
|
say " ]";
|
|
}
|