зеркало из https://github.com/microsoft/StorScore.git
410 строки
9.4 KiB
Batchfile
410 строки
9.4 KiB
Batchfile
@rem = ' vim: set filetype=perl: ';
|
|
@rem = ' --*-Perl-*-- ';
|
|
@rem = q(
|
|
@echo off
|
|
setlocal
|
|
set PATH=%~dp0\perl\bin;%~dp0\bin;%PATH%
|
|
where perl.exe >NUL 2>&1
|
|
if %ERRORLEVEL% NEQ 0 (
|
|
echo %~n0 requires Perl. Please install one of these:
|
|
echo ActiveState Perl: http://www.activestate.com/activeperl
|
|
echo Strawberry Perl: http://strawberryperl.com/
|
|
exit /B 1
|
|
)
|
|
for /F "tokens=4" %%I IN ('powercfg -getactivescheme') DO set ORIG_SCHEME=%%I
|
|
powercfg -setactive SCHEME_MIN
|
|
start /B /WAIT /HIGH perl "%~f0" %*
|
|
set PERL_ERROR_LEVEL=%ERRORLEVEL%
|
|
powercfg -setactive %ORIG_SCHEME%
|
|
exit /B %PERL_ERROR_LEVEL%
|
|
);
|
|
|
|
# StorScore
|
|
#
|
|
# Copyright (c) Microsoft Corporation
|
|
#
|
|
# All rights reserved.
|
|
#
|
|
# MIT License
|
|
#
|
|
# 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 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 English;
|
|
use Win32;
|
|
use Time::Seconds;
|
|
use POSIX 'strftime';
|
|
use Carp;
|
|
#$SIG{ __DIE__ } = sub { Carp::confess( @_ ) };
|
|
|
|
use FindBin;
|
|
use lib "$FindBin::Bin";
|
|
use lib "$FindBin::Bin\\lib";
|
|
|
|
use Util;
|
|
use CommandLine;
|
|
use Target;
|
|
use PreconditionRunner;
|
|
use SmartCtlRunner;
|
|
use Recipe;
|
|
use DiskSpdRunner;
|
|
use SqlioRunner;
|
|
use LogmanRunner;
|
|
use Power;
|
|
use WmicRunner;
|
|
use SharedVariables;
|
|
|
|
check_system_compatibility();
|
|
|
|
mkdir( $results_dir ) unless( -d $results_dir );
|
|
|
|
# See SharedVariables.pm
|
|
our $cmd_line = CommandLine->new( argv => \@ARGV );
|
|
our $target = Target->new( cmd_line => $cmd_line );
|
|
|
|
my $recipe_file = $cmd_line->recipe;
|
|
|
|
unless( defined $recipe_file )
|
|
{
|
|
if( $target->is_ssd )
|
|
{
|
|
$recipe_file = 'recipes\\turkey_test.rcp';
|
|
}
|
|
else
|
|
{
|
|
$recipe_file = 'recipes\\corners.rcp';
|
|
}
|
|
}
|
|
|
|
my $output_dir = "$results_dir\\";
|
|
|
|
$output_dir .= $cmd_line->test_id_prefix
|
|
if defined $cmd_line->test_id_prefix;
|
|
|
|
if( defined $cmd_line->test_id )
|
|
{
|
|
$output_dir .= $cmd_line->test_id;
|
|
}
|
|
else
|
|
{
|
|
# If no test_id was given, construct a sensible default
|
|
my $prefix =
|
|
make_legal_filename(
|
|
get_drive_model( $target->physical_drive ) );
|
|
|
|
$output_dir .=
|
|
"$prefix-" . strftime( "%Y-%m-%d_%H-%M-%S", localtime );
|
|
}
|
|
|
|
print "Targeting " . uc( $target->type ) . ": " . $target->model . "\n";
|
|
|
|
my $recipe = Recipe->new(
|
|
file_name => $recipe_file,
|
|
output_dir => $output_dir,
|
|
target => $target,
|
|
cmd_line => $cmd_line
|
|
);
|
|
|
|
my $num_steps = $recipe->get_num_steps();
|
|
my $num_tests = $recipe->get_num_test_steps();
|
|
|
|
die "Empty recipe. Nothing to do.\n" unless $num_steps > 0;
|
|
|
|
print "Loaded " . $recipe_file;
|
|
print " ($num_tests tests, $num_steps steps)\n\n";
|
|
|
|
$recipe->warn_expected_run_time();
|
|
|
|
detect_scep_and_warn();
|
|
|
|
if( $target->is_ssd )
|
|
{
|
|
if( $target->supports_smart and
|
|
$target->is_sata and
|
|
!$target->is_6Gbps_sata )
|
|
{
|
|
my $msg;
|
|
|
|
$msg .= "\tWarning!\n";
|
|
$msg .= "\tSSD target is not 6Gb/s SATA III.\n";
|
|
$msg .= "\tThroughput will be limited.\n\n";
|
|
|
|
warn $msg;
|
|
}
|
|
}
|
|
|
|
if( $target->do_purge )
|
|
{
|
|
my $msg;
|
|
|
|
$msg .= "\tWarning!\n";
|
|
$msg .= "\tThis will destroy \\\\.\\PHYSICALDRIVE";
|
|
$msg .= $target->physical_drive . "\n\n";
|
|
|
|
warn $msg;
|
|
}
|
|
else
|
|
{
|
|
if( $target->is_existing_file_or_volume )
|
|
{
|
|
my $msg;
|
|
|
|
$msg .= "\tWarning!\n";
|
|
$msg .= "\tTarget is an existing file/volume.\n";
|
|
$msg .= "\tCan not purge without destroying target.\n";
|
|
$msg .= "\tPurge steps will be skipped.\n\n";
|
|
|
|
warn $msg;
|
|
}
|
|
|
|
if( $target->is_ssd )
|
|
{
|
|
my $msg;
|
|
|
|
$msg .= "\tWarning!\n";
|
|
$msg .= "\tCan not eliminate SSD history effect without purge.\n";
|
|
$msg .= "\tFor best results target a physical drive and purge.\n\n";
|
|
|
|
warn $msg;
|
|
}
|
|
|
|
if( defined $target->file_name and
|
|
( $target->do_initialize or $recipe->contains_writes ) )
|
|
{
|
|
unless( -w $target->file_name or $pretend )
|
|
{
|
|
die "Target is not writable\n"
|
|
}
|
|
|
|
my $msg;
|
|
|
|
$msg .= "\tWarning!\n";
|
|
$msg .= "\tThis will destroy ";
|
|
$msg .= $target->file_name . "\n\n";
|
|
|
|
warn $msg;
|
|
}
|
|
}
|
|
|
|
exit 0 unless should_proceed();
|
|
|
|
die "Results subdirectory $output_dir already exists!\n"
|
|
if -e $output_dir;
|
|
|
|
my $overall_start = time();
|
|
|
|
mkdir( $output_dir );
|
|
|
|
if( $cmd_line->collect_smart )
|
|
{
|
|
if( $target->supports_smart )
|
|
{
|
|
print "Collecting SMART counters via SmartCtl.\n";
|
|
}
|
|
else
|
|
{
|
|
warn "SmartCtl missing or broken. SMART capture disabled.\n";
|
|
}
|
|
}
|
|
|
|
my $power;
|
|
|
|
if( $cmd_line->collect_power )
|
|
{
|
|
$power = Power->new( output_dir => $output_dir );
|
|
|
|
if( $power->is_functional() )
|
|
{
|
|
print "Collecting system power via IPMI.\n";
|
|
}
|
|
else
|
|
{
|
|
warn "Ipmiutil missing or broken. Power measurement disabled.\n";
|
|
undef $power;
|
|
}
|
|
}
|
|
|
|
if( defined $cmd_line->purge and not $cmd_line->purge )
|
|
{
|
|
print "Will skip purging as requested.\n";
|
|
}
|
|
|
|
if( defined $cmd_line->initialize and not $cmd_line->initialize )
|
|
{
|
|
print "Will skip initialization as requested.\n";
|
|
}
|
|
|
|
if( defined $cmd_line->precondition and not $cmd_line->precondition )
|
|
{
|
|
print "Will skip preconditioning as requested.\n";
|
|
}
|
|
|
|
my $wmic_runner = WmicRunner->new(
|
|
target => $target,
|
|
output_dir => $output_dir
|
|
);
|
|
|
|
$wmic_runner->collect( 'wmic.txt' );
|
|
|
|
my $smartctl_runner = undef;
|
|
|
|
if( $cmd_line->collect_smart and $target->supports_smart )
|
|
{
|
|
$smartctl_runner = SmartCtlRunner->new(
|
|
physical_drive => $target->physical_drive,
|
|
);
|
|
|
|
$smartctl_runner->collect(
|
|
file_name => "smart.txt",
|
|
output_dir => $output_dir,
|
|
do_identify => 1
|
|
)
|
|
}
|
|
|
|
my $logman_runner = LogmanRunner->new(
|
|
target => $target,
|
|
cmd_line => $cmd_line,
|
|
output_dir => $output_dir
|
|
)
|
|
if $cmd_line->collect_logman;
|
|
|
|
my %iogen_args = (
|
|
target => $target,
|
|
cmd_line => $cmd_line,
|
|
output_dir => $output_dir
|
|
);
|
|
|
|
my $iogen;
|
|
|
|
$iogen = SqlioRunner->new( %iogen_args )
|
|
if $cmd_line->io_generator =~ 'sqlio';
|
|
|
|
$iogen = DiskSpdRunner->new( %iogen_args )
|
|
if $cmd_line->io_generator =~ 'diskspd';
|
|
|
|
print "Testing...\n";
|
|
|
|
$recipe->run(
|
|
io_generator => $iogen,
|
|
smartctl_runner => $smartctl_runner,
|
|
logman_runner => $logman_runner,
|
|
power => $power
|
|
);
|
|
|
|
if( $cmd_line->auto_upload and defined $cmd_line->results_share )
|
|
{
|
|
print "Attempting upload to results share...";
|
|
|
|
my $upload_start = time();
|
|
my $success = upload_results();
|
|
my $dstr = seconds_to_human( time() - $upload_start );
|
|
|
|
print "success!" if $success;
|
|
print "failed!" if not $success;
|
|
|
|
print " (took $dstr)\n";
|
|
}
|
|
|
|
my $dstr = seconds_to_human( time() - $overall_start );
|
|
print( "Done (took $dstr)\n" );
|
|
|
|
exit( 0 );
|
|
|
|
sub upload_results
|
|
{
|
|
my $src = $output_dir;
|
|
my $share = $cmd_line->results_share;
|
|
my $dst = $output_dir =~ s/.*results/$share\\results/r;
|
|
my $user = $cmd_line->results_share_user;
|
|
my $pass = $cmd_line->results_share_pass;
|
|
|
|
my $nu_cmd = "net use $share";
|
|
$nu_cmd .= " $pass" if defined $pass;
|
|
$nu_cmd .= " /USER:$user" if defined $user;
|
|
|
|
my $failed = execute_task( $nu_cmd, quiet => 1 );
|
|
return 0 if $failed;
|
|
|
|
my $success =
|
|
execute_task(
|
|
"ROBOCOPY /E /R:10 /W:5 $src $dst",
|
|
quiet => 1
|
|
);
|
|
|
|
return 0 unless $success;
|
|
|
|
$failed = execute_task( "net use $share /DELETE /Y", quiet => 1 );
|
|
return 0 if $failed;
|
|
|
|
return 1;
|
|
}
|
|
|
|
sub check_system_compatibility
|
|
{
|
|
unless( is_windows_x64() )
|
|
{
|
|
warn "\n$script_name requires a 64-bit version of Windows\n\n";
|
|
exit( -1 );
|
|
}
|
|
|
|
# False positive on Server 2012 R2?
|
|
unless( is_vc_runtime_present( '12.0', 'x86' ) )
|
|
{
|
|
warn <<"MSG";
|
|
|
|
$script_name requires the x86 Visual C++ Redistributable Packages
|
|
for Visual Studio 2013. Please install vcredist_x86.exe from:
|
|
http://www.microsoft.com/en-us/download/details.aspx?id=40784
|
|
|
|
MSG
|
|
exit( -1 );
|
|
}
|
|
|
|
# False positive on Server 2012 R2?
|
|
unless( is_vc_runtime_present( '12.0', 'x64' ) )
|
|
{
|
|
warn <<"MSG";
|
|
|
|
$script_name requires the x64 Visual C++ Redistributable Packages
|
|
for Visual Studio 2013. Please install vcredist_x64.exe from:
|
|
http://www.microsoft.com/en-us/download/details.aspx?id=40784
|
|
|
|
MSG
|
|
exit( -1 );
|
|
}
|
|
|
|
unless( Win32::IsAdminUser() )
|
|
{
|
|
warn "\n$script_name: must run as Administrator\n\n";
|
|
exit( -1 );
|
|
}
|
|
}
|
|
|
|
BEGIN
|
|
{
|
|
# unbuffer STDERR and STDOUT
|
|
select STDERR;
|
|
$OUTPUT_AUTOFLUSH = 1;
|
|
|
|
select STDOUT;
|
|
$OUTPUT_AUTOFLUSH = 1;
|
|
}
|