From 6badebd963d92f37b9c84997a4d1bcd642ec65bf Mon Sep 17 00:00:00 2001 From: Evgeny Mankov Date: Thu, 3 Oct 2019 16:00:52 +0300 Subject: [PATCH] [HIPIFY] Finishing with generation of hipify-perl + hipify-perl script is entirely generated by hipify-clang under an option -perl now + hipify-perl still has correctness gaps comparing to hipify-clang: they will be eliminated AMAP further --- bin/hipify-perl | 34 +++--- hipify-clang/src/CUDA2HIP_Perl.cpp | 179 +++++++++++++++++++++++++---- 2 files changed, 171 insertions(+), 42 deletions(-) diff --git a/bin/hipify-perl b/bin/hipify-perl index 609b0fc3f4..225bb08887 100755 --- a/bin/hipify-perl +++ b/bin/hipify-perl @@ -27,6 +27,8 @@ use Getopt::Long; my $whitelist = ""; my $fileName = ""; +my %ft; +my %Tkernels; GetOptions( "examine" => \$examine # Combines -no-output and -print-stats options. @@ -1600,12 +1602,11 @@ sub transformExternShared { no warnings qw/uninitialized/; my $k = 0; $k += s/extern\s+([\w\(\)]+)?\s*__shared__\s+([\w:<>\s]+)\s+(\w+)\s*\[\s*\]\s*;/HIP_DYNAMIC_SHARED($1 $2, $3)/g; - $ft{ 'extern_shared' } += $k; + $ft{'extern_shared'} += $k; } # CUDA Kernel Launch Syntax sub transformKernelLaunch { - my $TkernRef = @_; no warnings qw/uninitialized/; my $k = 0; @@ -1641,7 +1642,7 @@ sub transformKernelLaunch { if ($k) { $ft{'kernel_launch'} += $k; - @$TkernRef{$1} ++; + $Tkernels{$1}++; } } @@ -2299,7 +2300,6 @@ clearStats(\%tt, \@statNames); $Twarnings = 0; $TlineCount = 0; my %TwarningTags; -my %Tkernels; my $fileCount = @ARGV; while (@ARGV) { @@ -2323,42 +2323,36 @@ while (@ARGV) { open(INFILE,"<", $fileName) or die "error: could not open $fileName"; $OUTFILE = STDOUT; } - # Note : \b is used in perl to indicate the start of a word # Count of transforms in this file - my %ft; clearStats(\%ft, \@statNames); my $countIncludes = 0; my $countKeywords = 0; - my $warnings = 0; + my $warnings = 0; my %warningTags; my $lineCount = 0; undef $/; # Read whole file at once, so we can match newlines - while () - { - simpleSubstitutions(); - + while () { $countKeywords += m/__global__/; $countKeywords += m/__shared__/; - + simpleSubstitutions(); transformExternShared(); - transformKernelLaunch(\%Tkernels); - + transformKernelLaunch(); if ($print_stats) { - while (/(\bhip[A-Z]\w+\b)/g) { + while (/(\b(hip|HIP)([A-Z]|_)\w+\b)/g) { $convertedTags{$1}++; } } my $hasDeviceCode = $countKeywords + $ft{'device_function'}; unless ($quiet_warnings) { # Copy into array of lines, process line-by-line to show warnings - if ($hasDeviceCode or (/\bcu/) or (/\bCU_/) or (/\bCUDA_/) or (/<<<.*>>>/)) { + if ($hasDeviceCode or (/\bcu|CU/) or (/<<<.*>>>/)) { my @lines = split /\n/, $_; # Copy the whole file my $tmp = $_; my $line_num = 0; foreach (@lines) { - $line_num ++; + $line_num++; # Remove any whitelisted words foreach $w (@whitelist) { s/\b$w\b/ZAP/ @@ -2371,8 +2365,7 @@ while (@ARGV) { if (defined $tag) { $warnings++; $warningTags{$tag}++; - print STDERR " warning: $fileName:#$line_num : $_"; - print STDERR "\n"; + print STDERR " warning: $fileName:#$line_num : $_\n"; } $s = warnUnsupportedDeviceFunctions($line_num); $warnings += $s; @@ -2424,8 +2417,7 @@ if ($print_stats and ($fileCount > 1)) { foreach my $key (sort { $Tkernels{$b} <=> $Tkernels{$a} } keys %Tkernels) { printf STDERR " %s(%d)", $key, $Tkernels{$key}; } - print STDERR "\n"; - print STDERR "\n"; + print STDERR "\n\n"; } if ($print_stats) { foreach my $key (sort { $convertedTags{$b} <=> $convertedTags{$a} } keys %convertedTags) { diff --git a/hipify-clang/src/CUDA2HIP_Perl.cpp b/hipify-clang/src/CUDA2HIP_Perl.cpp index f101f9b8cb..675826824a 100644 --- a/hipify-clang/src/CUDA2HIP_Perl.cpp +++ b/hipify-clang/src/CUDA2HIP_Perl.cpp @@ -62,11 +62,15 @@ namespace perl { const std::string tab = " "; const std::string double_tab = tab + tab; const std::string triple_tab = double_tab + tab; + const std::string quad_tab = triple_tab + tab; + const std::string tab_5 = quad_tab + tab; + const std::string tab_6 = tab_5 + tab; const std::string sSub = "sub"; const std::string sReturn_0 = "return 0;\n"; const std::string sReturn_k = "return $k;\n"; const std::string sForeach = "foreach $func (\n"; - const std::string sMy_k = "my $k = 0;"; + const std::string sMy = "my "; + const std::string sMy_k = sMy + "$k = 0;"; const std::string sNoWarns = "no warnings qw/uninitialized/;"; const std::string sCudaDevice = "cudaDevice"; @@ -104,7 +108,10 @@ namespace perl { *streamPtr.get() << sCopyright << std::endl; *streamPtr.get() << "#usage hipify-perl [OPTIONS] INPUT_FILE" << std::endl << std::endl; *streamPtr.get() << "use Getopt::Long;" << std::endl; - *streamPtr.get() << "my $whitelist = \"\";" << std::endl << std::endl; + *streamPtr.get() << sMy << "$whitelist = \"\";" << std::endl; + *streamPtr.get() << sMy << "$fileName = \"\";" << std::endl; + *streamPtr.get() << sMy << "%ft;" << std::endl; + *streamPtr.get() << sMy << "%Tkernels;" << std::endl << std::endl; *streamPtr.get() << "GetOptions(" << std::endl; *streamPtr.get() << tab << " \"examine\" => \\$examine # Combines -no-output and -print-stats options." << std::endl; *streamPtr.get() << tab << ", \"inplace\" => \\$inplace # Modify input file inplace, replacing input with hipified output, save backup in .prehip file." << std::endl; @@ -128,18 +135,18 @@ namespace perl { void generateStatFunctions(std::unique_ptr& streamPtr) { *streamPtr.get() << std::endl << sSub << " totalStats" << " {" << std::endl; - *streamPtr.get() << tab << "my %count = %{ shift() };" << std::endl; - *streamPtr.get() << tab << "my $total = 0;" << std::endl; + *streamPtr.get() << tab << sMy << "%count = %{ shift() };" << std::endl; + *streamPtr.get() << tab << sMy << "$total = 0;" << std::endl; *streamPtr.get() << tab << "foreach $key (keys %count) {" << std::endl; *streamPtr.get() << double_tab << "$total += $count{$key};" << std::endl << tab << "}" << std::endl; *streamPtr.get() << tab << "return $total;" << std::endl << "};" << std::endl; *streamPtr.get() << std::endl << sSub << " printStats" << " {" << std::endl; - *streamPtr.get() << tab << "my $label = shift();" << std::endl; - *streamPtr.get() << tab << "my @statNames = @{ shift() };" << std::endl; - *streamPtr.get() << tab << "my %counts = %{ shift() };" << std::endl; - *streamPtr.get() << tab << "my $warnings = shift();" << std::endl; - *streamPtr.get() << tab << "my $loc = shift();" << std::endl; - *streamPtr.get() << tab << "my $total = totalStats(\\%counts);" << std::endl; + *streamPtr.get() << tab << sMy << "$label = shift();" << std::endl; + *streamPtr.get() << tab << sMy << "@statNames = @{ shift() };" << std::endl; + *streamPtr.get() << tab << sMy << "%counts = %{ shift() };" << std::endl; + *streamPtr.get() << tab << sMy << "$warnings = shift();" << std::endl; + *streamPtr.get() << tab << sMy << "$loc = shift();" << std::endl; + *streamPtr.get() << tab << sMy << "$total = totalStats(\\%counts);" << std::endl; *streamPtr.get() << tab << "printf STDERR \"%s %d CUDA->HIP refs ( \", $label, $total;" << std::endl; *streamPtr.get() << tab << "foreach $stat (@statNames) {" << std::endl; *streamPtr.get() << double_tab << "printf STDERR \"%s:%d \", $stat, $counts{$stat};" << std::endl; @@ -147,8 +154,8 @@ namespace perl { *streamPtr.get() << tab << "printf STDERR \")\\n warn:%d LOC:%d\", $warnings, $loc;" << std::endl << "}" << std::endl; for (int i = 0; i < 2; ++i) { *streamPtr.get() << std::endl << sSub << " " << (i ? "clearStats" : "addStats") << " {" << std::endl; - *streamPtr.get() << tab << "my $dest_ref = shift();" << std::endl; - *streamPtr.get() << tab << (i ? "my @statNames = @{ shift() };" : "my %adder = %{ shift() };") << std::endl; + *streamPtr.get() << tab << sMy << "$dest_ref = shift();" << std::endl; + *streamPtr.get() << tab << sMy << (i ? "@statNames = @{ shift() };" : "%adder = %{ shift() };") << std::endl; *streamPtr.get() << tab << "foreach " << (i ? "$stat(@statNames)" : "$key (keys %adder)") << " {" << std::endl; *streamPtr.get() << double_tab << "$dest_ref->" << (i ? "{$stat} = 0;" : "{$key} += $adder{$key};") << std::endl << tab << "}" << std::endl << "}" << std::endl; } @@ -186,13 +193,12 @@ namespace perl { *streamPtr.get() << tab << sNoWarns << std::endl; *streamPtr.get() << tab << sMy_k << std::endl; *streamPtr.get() << tab << "$k += s/extern\\s+([\\w\\(\\)]+)?\\s*__shared__\\s+([\\w:<>\\s]+)\\s+(\\w+)\\s*\\[\\s*\\]\\s*;/HIP_DYNAMIC_SHARED($1 $2, $3)/g;" << std::endl; - *streamPtr.get() << tab << "$ft{ 'extern_shared' } += $k;" << std::endl << "}" << std::endl; + *streamPtr.get() << tab << "$ft{'extern_shared'} += $k;" << std::endl << "}" << std::endl; } void generateKernelLaunch(std::unique_ptr& streamPtr) { *streamPtr.get() << std::endl << "# CUDA Kernel Launch Syntax" << std::endl; *streamPtr.get() << sSub << " transformKernelLaunch" << " {" << std::endl; - *streamPtr.get() << tab << "my $TkernRef = @_;" << std::endl; *streamPtr.get() << tab << sNoWarns << std::endl; *streamPtr.get() << tab << sMy_k << std::endl << std::endl; @@ -228,7 +234,7 @@ namespace perl { *streamPtr.get() << tab << "if ($k) {" << std::endl; *streamPtr.get() << double_tab << "$ft{'kernel_launch'} += $k;" << std::endl; - *streamPtr.get() << double_tab << "@$TkernRef{$1} ++;" << std::endl << tab << "}" << std::endl << "}" << std::endl; + *streamPtr.get() << double_tab << "$Tkernels{$1}++;" << std::endl << tab << "}" << std::endl << "}" << std::endl; } void generateHostFunctions(std::unique_ptr& streamPtr) { @@ -285,7 +291,7 @@ namespace perl { std::stringstream subCommon; std::string sCommon = tab + sMy_k + "\n" + tab + sForeach; subCountSupported << std::endl << sSub << " countSupportedDeviceFunctions" << " {" << std::endl << (countSupported ? sCommon : tab + sReturn_0); - subWarnUnsupported << std::endl << sSub << " warnUnsupportedDeviceFunctions" << " {" << std::endl << (countUnsupported ? tab + "my $line_num = shift;\n" + sCommon : tab + sReturn_0); + subWarnUnsupported << std::endl << sSub << " warnUnsupportedDeviceFunctions" << " {" << std::endl << (countUnsupported ? tab + sMy + "$line_num = shift;\n" + sCommon : tab + sReturn_0); if (countSupported) { subCountSupported << sSupported.str() << std::endl << tab << ")" << std::endl; } @@ -296,8 +302,8 @@ namespace perl { subCommon << tab << "{" << std::endl; subCommon << double_tab << "# match device function from the list, except those, which have a namespace prefix (aka somenamespace::umin(...));" << std::endl; subCommon << double_tab << "# function with only global namespace qualifier '::' (aka ::umin(...)) should be treated as a device function (and warned as well as without such qualifier);" << std::endl; - subCommon << double_tab << "my $mt_namespace = m/(\\w+)::($func)\\s*\\(\\s*.*\\s*\\)/g;" << std::endl; - subCommon << double_tab << "my $mt = m/($func)\\s*\\(\\s*.*\\s*\\)/g;" << std::endl; + subCommon << double_tab << sMy << "$mt_namespace = m/(\\w+)::($func)\\s*\\(\\s*.*\\s*\\)/g;" << std::endl; + subCommon << double_tab << sMy << "$mt = m/($func)\\s*\\(\\s*.*\\s*\\)/g;" << std::endl; subCommon << double_tab << "if ($mt && !$mt_namespace) {" << std::endl; subCommon << triple_tab << "$k += $mt;" << std::endl; } @@ -338,11 +344,16 @@ namespace perl { } std::unique_ptr streamPtr = std::unique_ptr(new std::ofstream(tmpFile.c_str(), std::ios_base::trunc)); generateHeader(streamPtr); - std::string sConv = "my $conversions = "; + std::string sConv = sMy + "$apiCalls = "; + unsigned int exclude[3] = { CONV_DEVICE_FUNC, CONV_EXTERN_SHARED, CONV_KERNEL_LAUNCH }; *streamPtr.get() << "@statNames = ("; - for (int i = 0; i < NUM_CONV_TYPES - 1; ++i) { + for (unsigned int i = 0; i < NUM_CONV_TYPES - 1; ++i) { *streamPtr.get() << "\"" << counterNames[i] << "\", "; - sConv += "$ft{'" + std::string(counterNames[i]) + "'} + "; + if (std::any_of(exclude, exclude + 3, [&i](unsigned int x) { return x == i; })) continue; + sConv += "$ft{'" + std::string(counterNames[i]) + "'}" + (i < NUM_CONV_TYPES - 2 ? " + " : ";"); + } + if (sConv.back() == ' ') { + sConv = sConv.substr(0, sConv.size() - 3) + ";"; } *streamPtr.get() << "\"" << counterNames[NUM_CONV_TYPES - 1] << "\");" << std::endl; generateStatFunctions(streamPtr); @@ -351,6 +362,132 @@ namespace perl { generateKernelLaunch(streamPtr); generateHostFunctions(streamPtr); generateDeviceFunctions(streamPtr); + *streamPtr.get() << std::endl << "# Count of transforms in all files" << std::endl; + *streamPtr.get() << sMy << "%tt;" << std::endl; + *streamPtr.get() << "clearStats(\\%tt, \\@statNames);" << std::endl; + *streamPtr.get() << "$Twarnings = 0;" << std::endl; + *streamPtr.get() << "$TlineCount = 0;" << std::endl; + *streamPtr.get() << sMy << "%TwarningTags;" << std::endl; + *streamPtr.get() << sMy << "$fileCount = @ARGV;" << std::endl << std::endl; + *streamPtr.get() << "while (@ARGV) {" << std::endl; + *streamPtr.get() << tab << "$fileName=shift (@ARGV);" << std::endl; + *streamPtr.get() << tab << "if ($inplace) {" << std::endl; + *streamPtr.get() << double_tab << sMy << "$file_prehip = \"$fileName\" . \".prehip\";" << std::endl; + *streamPtr.get() << double_tab << sMy << "$infile;" << std::endl; + *streamPtr.get() << double_tab << sMy << "$outfile;" << std::endl; + *streamPtr.get() << double_tab << "if (-e $file_prehip) {" << std::endl; + *streamPtr.get() << triple_tab << "$infile = $file_prehip;" << std::endl; + *streamPtr.get() << triple_tab << "$outfile = $fileName;" << std::endl; + *streamPtr.get() << double_tab << "} else {" << std::endl; + *streamPtr.get() << triple_tab << "system (\"cp $fileName $file_prehip\");" << std::endl; + *streamPtr.get() << triple_tab << "$infile = $file_prehip;" << std::endl; + *streamPtr.get() << triple_tab << "$outfile = $fileName;" << std::endl << double_tab << "}" << std::endl; + *streamPtr.get() << double_tab << "open(INFILE,\"<\", $infile) or die \"error: could not open $infile\";" << std::endl; + *streamPtr.get() << double_tab << "open(OUTFILE,\">\", $outfile) or die \"error: could not open $outfile\";" << std::endl; + *streamPtr.get() << double_tab << "$OUTFILE = OUTFILE;" << std::endl; + *streamPtr.get() << tab << "} else {" << std::endl; + *streamPtr.get() << double_tab << "open(INFILE,\"<\", $fileName) or die \"error: could not open $fileName\";" << std::endl; + *streamPtr.get() << double_tab << "$OUTFILE = STDOUT;" << std::endl << tab << "}" << std::endl; + *streamPtr.get() << tab << "# Count of transforms in this file" << std::endl; + *streamPtr.get() << tab << "clearStats(\\%ft, \\@statNames);" << std::endl; + *streamPtr.get() << tab << sMy << "$countIncludes = 0;" << std::endl; + *streamPtr.get() << tab << sMy << "$countKeywords = 0;" << std::endl; + *streamPtr.get() << tab << sMy << "$warnings = 0;" << std::endl; + *streamPtr.get() << tab << sMy << "%warningTags;" << std::endl; + *streamPtr.get() << tab << sMy << "$lineCount = 0;" << std::endl; + *streamPtr.get() << tab << "undef $/;" << std::endl; + *streamPtr.get() << tab << "# Read whole file at once, so we can match newlines" << std::endl; + *streamPtr.get() << tab << "while () {" << std::endl; + *streamPtr.get() << double_tab << "$countKeywords += m/__global__/;" << std::endl; + *streamPtr.get() << double_tab << "$countKeywords += m/__shared__/;" << std::endl; + *streamPtr.get() << double_tab << "simpleSubstitutions();" << std::endl; + *streamPtr.get() << double_tab << "transformExternShared();" << std::endl; + *streamPtr.get() << double_tab << "transformKernelLaunch();" << std::endl; + *streamPtr.get() << double_tab << "if ($print_stats) {" << std::endl; + *streamPtr.get() << triple_tab << "while (/(\\b(hip|HIP)([A-Z]|_)\\w+\\b)/g) {" << std::endl; + *streamPtr.get() << quad_tab << "$convertedTags{$1}++;" << std::endl; + *streamPtr.get() << triple_tab << "}" << std::endl; + *streamPtr.get() << double_tab << "}" << std::endl; + *streamPtr.get() << double_tab << sMy << "$hasDeviceCode = $countKeywords + $ft{'device_function'};" << std::endl; + *streamPtr.get() << double_tab << "unless ($quiet_warnings) {" << std::endl; + *streamPtr.get() << triple_tab << "# Copy into array of lines, process line-by-line to show warnings" << std::endl; + *streamPtr.get() << triple_tab << "if ($hasDeviceCode or (/\\bcu|CU/) or (/<<<.*>>>/)) {" << std::endl; + *streamPtr.get() << quad_tab << sMy << "@lines = split /\\n/, $_;" << std::endl; + *streamPtr.get() << quad_tab << "# Copy the whole file" << std::endl; + *streamPtr.get() << quad_tab << sMy << "$tmp = $_;" << std::endl; + *streamPtr.get() << quad_tab << sMy << "$line_num = 0;" << std::endl; + *streamPtr.get() << quad_tab << "foreach (@lines) {" << std::endl; + *streamPtr.get() << tab_5 << "$line_num++;" << std::endl; + *streamPtr.get() << tab_5 << "# Remove any whitelisted words" << std::endl; + *streamPtr.get() << tab_5 << "foreach $w (@whitelist) {" << std::endl; + *streamPtr.get() << tab_6 << "s/\\b$w\\b/ZAP/" << std::endl; + *streamPtr.get() << tab_5 << "}" << std::endl; + *streamPtr.get() << tab_5 << sMy << "$tag;" << std::endl; + *streamPtr.get() << tab_5 << "if ((/(\\bcuda[A-Z]\\w+)/) or (/<<<.*>>>/)) {" << std::endl; + *streamPtr.get() << tab_6 << "# Flag any remaining code that look like cuda API calls: may want to add these to hipify" << std::endl; + *streamPtr.get() << tab_6 << "$tag = (defined $1) ? $1 : \"Launch\";" << std::endl; + *streamPtr.get() << tab_5 << "}" << std::endl; + *streamPtr.get() << tab_5 << "if (defined $tag) {" << std::endl; + *streamPtr.get() << tab_6 << "$warnings++;" << std::endl; + *streamPtr.get() << tab_6 << "$warningTags{$tag}++;" << std::endl; + *streamPtr.get() << tab_6 << "print STDERR \" warning: $fileName:#$line_num : $_\\n\";" << std::endl; + *streamPtr.get() << tab_5 << "}" << std::endl; + *streamPtr.get() << tab_5 << "$s = warnUnsupportedDeviceFunctions($line_num);" << std::endl; + *streamPtr.get() << tab_5 << "$warnings += $s;" << std::endl; + *streamPtr.get() << quad_tab << "}" << std::endl; + *streamPtr.get() << quad_tab << "$_ = $tmp;" << std::endl; + *streamPtr.get() << triple_tab << "}" << std::endl; + *streamPtr.get() << double_tab << "}" << std::endl; + *streamPtr.get() << double_tab << "if ($hasDeviceCode > 0) {" << std::endl; + *streamPtr.get() << triple_tab << "$ft{'device_function'} += countSupportedDeviceFunctions();" << std::endl; + *streamPtr.get() << double_tab << "}" << std::endl; + *streamPtr.get() << double_tab << "transformHostFunctions();" << std::endl; + *streamPtr.get() << double_tab << "# TODO: would like to move this code outside loop but it uses $_ which contains the whole file" << std::endl; + *streamPtr.get() << double_tab << "unless ($no_output) {" << std::endl; + *streamPtr.get() << triple_tab << sConv << std::endl; + *streamPtr.get() << triple_tab << sMy << "$kernStuff = $hasDeviceCode + $ft{'" << counterNames[CONV_KERNEL_LAUNCH] << "'} + $ft{'" << counterNames[CONV_DEVICE_FUNC] << "'};" << std::endl; + *streamPtr.get() << triple_tab << sMy << "$totalCalls = $apiCalls + $kernStuff;" << std::endl; + *streamPtr.get() << triple_tab << "$is_dos = m/\\r\\n$/;" << std::endl; + *streamPtr.get() << triple_tab << "if ($totalCalls and ($countIncludes == 0) and ($kernStuff != 0)) {" << std::endl; + *streamPtr.get() << quad_tab << "# TODO: implement hipify-clang's logic with header files AMAP" << std::endl; + *streamPtr.get() << quad_tab << "print $OUTFILE '#include \"hip/hip_runtime.h\"' . ($is_dos ? \"\\r\\n\" : \"\\n\");" << std::endl; + *streamPtr.get() << triple_tab << "}" << std::endl; + *streamPtr.get() << triple_tab << "print $OUTFILE \"$_\";" << std::endl; + *streamPtr.get() << double_tab << "}" << std::endl; + *streamPtr.get() << double_tab << "$lineCount = $_ =~ tr/\\n//;" << std::endl; + *streamPtr.get() << tab << "}" << std::endl; + *streamPtr.get() << tab << sMy << "$totalConverted = totalStats(\\%ft);" << std::endl; + *streamPtr.get() << tab << "if (($totalConverted+$warnings) and $print_stats) {" << std::endl; + *streamPtr.get() << double_tab << "printStats(\" info: converted\", \\@statNames, \\%ft, $warnings, $lineCount);" << std::endl; + *streamPtr.get() << double_tab << "print STDERR \" in '$fileName'\\n\";" << std::endl; + *streamPtr.get() << tab << "}" << std::endl; + *streamPtr.get() << tab << "# Update totals for all files" << std::endl; + *streamPtr.get() << tab << "addStats(\\%tt, \\%ft);" << std::endl; + *streamPtr.get() << tab << "$Twarnings += $warnings;" << std::endl; + *streamPtr.get() << tab << "$TlineCount += $lineCount;" << std::endl; + *streamPtr.get() << tab << "foreach $key (keys %warningTags) {" << std::endl; + *streamPtr.get() << double_tab << "$TwarningTags{$key} += $warningTags{$key};" << std::endl; + *streamPtr.get() << tab << "}" << std::endl; + *streamPtr.get() << "}" << std::endl; + *streamPtr.get() << "# Print total stats for all files processed:" << std::endl; + *streamPtr.get() << "if ($print_stats and ($fileCount > 1)) {" << std::endl; + *streamPtr.get() << tab << "print STDERR \"\\n\";" << std::endl; + *streamPtr.get() << tab << "printStats(\" info: TOTAL-converted\", \\@statNames, \\%tt, $Twarnings, $TlineCount);" << std::endl; + *streamPtr.get() << tab << "print STDERR \"\\n\";" << std::endl; + *streamPtr.get() << tab << "foreach my $key (sort { $TwarningTags{$b} <=> $TwarningTags{$a} } keys %TwarningTags) {" << std::endl; + *streamPtr.get() << double_tab << "printf STDERR \" warning: unconverted %s : %d\\n\", $key, $TwarningTags{$key};" << std::endl; + *streamPtr.get() << tab << "}" << std::endl; + *streamPtr.get() << tab << sMy << "$kernelCnt = keys %Tkernels;" << std::endl; + *streamPtr.get() << tab << "printf STDERR \" kernels (%d total) : \", $kernelCnt;" << std::endl; + *streamPtr.get() << tab << "foreach my $key (sort { $Tkernels{$b} <=> $Tkernels{$a} } keys %Tkernels) {" << std::endl; + *streamPtr.get() << double_tab << "printf STDERR \" %s(%d)\", $key, $Tkernels{$key};" << std::endl; + *streamPtr.get() << tab << "}" << std::endl; + *streamPtr.get() << tab << "print STDERR \"\\n\\n\";" << std::endl; + *streamPtr.get() << "}" << std::endl; + *streamPtr.get() << "if ($print_stats) {" << std::endl; + *streamPtr.get() << tab << "foreach my $key (sort { $convertedTags{$b} <=> $convertedTags{$a} } keys %convertedTags) {" << std::endl; + *streamPtr.get() << double_tab << "printf STDERR \" %s %d\\n\", $key, $convertedTags{$key};" << std::endl; + *streamPtr.get() << tab << "}" << std::endl << "}" << std::endl; streamPtr.get()->flush(); bool ret = true; EC = sys::fs::copy_file(tmpFile, dstPerlMap);