@@ -222,6 +222,7 @@ our $intervalChildCpuTime = 0; # since last updata
222222our $defaultChunkSize ;
223223our $defaultInterval ;
224224our %childRetryCounts ;
225+ our @large_files ;
225226
226227our $cwd = getcwd();
227228chomp ($cwd );
@@ -255,7 +256,8 @@ my %geninfo_opts = ("test-name|t=s" => \$test_name,
255256 " derive-func-data" => \$opt_derive_func_data ,
256257 " external|e" => \$lcovutil::opt_external ,
257258 " no-external" => \$lcovutil::opt_no_external ,
258- " compat=s" => \$lcovutil::geninfo_opt_compat ,);
259+ " compat=s" => \$lcovutil::geninfo_opt_compat ,
260+ ' large-file=s' => \@large_files );
259261
260262# Parse command line options
261263if (!lcovutil::parseOptions(\%lcovutil::geninfo_rc_opts , \%geninfo_opts ,
@@ -268,6 +270,12 @@ $buildDirSearchPath =
268270 SearchPath-> new(' build directory' , @lcovutil::build_directory );
269271@gcov_tool = @lcovutil::rc_gcov_tool unless @gcov_tool ;
270272
273+ eval {
274+ map { qr ($_ ) } @large_files ;
275+ };
276+ die (" invalid 'large-file' regexp: $@ " )
277+ if ($@ );
278+
271279# Check regexp
272280if (defined ($lcovutil::rc_adjust_src_path )) {
273281 my ($pattern , $replace ) = split (/ \s *=>\s */ , $lcovutil::rc_adjust_src_path );
@@ -1065,7 +1073,7 @@ sub _process_one_chunk($$$$)
10651073
10661074 # "name" will be .gcno if "$initial" else will be $gcda
10671075 my $name = defined ($gcda_file ) ? $gcda_file : $gcno_file ;
1068- info(1, " Processing $name%s \n " , defined ($pid ) ? " in child $pid " : " " );
1076+ info(1, " Processing $name%s \n " , defined ($pid ) ? " in child $pid " : " " . " \n " );
10691077 my $context = MessageContext-> new(" capturing from $name " );
10701078
10711079 # multiple gcda files may refer to the same source - so generate the
@@ -1181,6 +1189,19 @@ sub _merge_one_child($$$)
11811189 $lcovutil::max_fork_fails != 0) ||
11821190 $lcovutil::verbose );
11831191 print (STDERR $childErr );
1192+ # look for spaceout message in the gcov log
1193+ if (0 == $signal &&
1194+ 0 != $childstatus &&
1195+ 0 != $lcovutil::max_fork_fails &&
1196+ lcovutil::is_ignored($lcovutil::ERROR_FORK ) &&
1197+ grep (
1198+ { / (std::bad_alloc|annot allocate memory|out of memory|integretity check failed for compressed file)/
1199+ } ($childLog , $childErr ))
1200+ ) {
1201+
1202+ # pretend it was killed so we retry
1203+ $signal = POSIX::SIGKILL;
1204+ }
11841205 my $data = Storable::retrieve($dumped )
11851206 if (-f $dumped && 0 == $childstatus );
11861207 # note that $data will not be defined (no data dumped) if there was
@@ -1298,15 +1319,26 @@ sub gen_info(@)
12981319 $chunkSize = 1;
12991320 }
13001321 my @worklist ;
1301- my $chunk = [];
1322+ my $serialChunk = [1, []];
1323+ my $chunk = [0, []]; # [isSerial, [fileList]]
13021324 foreach my $j (@$filelist ) {
1303- push (@$chunk , $j );
1304- if (scalar (@$chunk ) == $chunkSize ) {
1325+ my $filename = $j -> [0] . $lcovutil::dirseparator . $j -> [1];
1326+ if (grep ({ $filename =~ $_ } @main::large_files )) {
1327+ lcovutil::info(1, " large file: $filename \n " );
1328+ push (@{$serialChunk -> [1]}, $j );
1329+ next ;
1330+ }
1331+ push (@{$chunk -> [1]}, $j );
1332+ if (scalar (@{$chunk -> [1]}) == $chunkSize ) {
13051333 push (@worklist , $chunk );
1306- $chunk = [];
1334+ $chunk = [0, [] ];
13071335 }
13081336 } # foreach DATA_FILE
1309- push (@worklist , $chunk ) if @$chunk ;
1337+ push (@worklist , $chunk ) if @{$chunk -> [1]};
1338+ # serial chunk is at the top of the stack - so serial processing
1339+ # happens before we fork multiple processes
1340+ push (@worklist , $serialChunk )
1341+ if (@{$serialChunk -> [1]});
13101342
13111343 # Process all files in list
13121344 my $currentParallel = 0;
@@ -1342,7 +1374,8 @@ sub gen_info(@)
13421374 my $chunk = pop (@worklist );
13431375 ++$processedChunks ;
13441376
1345- if (1 < $lcovutil::maxParallelism ) {
1377+ if (1 < $lcovutil::maxParallelism &&
1378+ 1 != $chunk -> [0]) {
13461379
13471380 my $currentSize = 0;
13481381 if (0 != $lcovutil::maxMemory ) {
@@ -1410,8 +1443,8 @@ sub gen_info(@)
14101443 my ($stdout , $stderr , $code ) = Capture::Tiny::capture {
14111444 eval {
14121445 $childInfo =
1413- _process_one_chunk($chunk , $processedChunks ,
1414- $childInfo , $$ );
1446+ _process_one_chunk($chunk -> [1] ,
1447+ $processedChunks , $childInfo , $$ );
14151448 };
14161449 if ($@ ) {
14171450 $status = 1; # error
@@ -1458,12 +1491,14 @@ sub gen_info(@)
14581491 # there is no childInfo data
14591492 $data =
14601493 Storable::store(
1461- [$single_file ? $childInfo : undef ,
1462- $buildDirCounts ,
1463- [$files_created , scalar (@$chunk ), $then ],
1464- lcovutil::compute_update($currentState )
1465- ],
1466- $dumpf ) if defined ($childInfo );
1494+ [$single_file ? $childInfo : undef ,
1495+ $buildDirCounts ,
1496+ [$files_created , scalar (@{$chunk -> [1]}),
1497+ $then
1498+ ],
1499+ lcovutil::compute_update($currentState )
1500+ ],
1501+ $dumpf ) if defined ($childInfo );
14671502 };
14681503 if ($@ || (defined ($childInfo ) && !defined ($data ))) {
14691504 lcovutil::ignorable_error($lcovutil::ERROR_PARALLEL ,
@@ -1477,12 +1512,24 @@ sub gen_info(@)
14771512 }
14781513 } else {
14791514 # not parallel..
1515+ my $saveParallel = $lcovutil::maxParallelism ;
1516+ $lcovutil::maxParallelism = 1;
1517+ if ($chunk -> [0]) {
1518+ my $num = scalar (@{$chunk -> [1]});
1519+ lcovutil::info(" Processing $num file" .
1520+ ($num == 1 ? ' ' : ' s' ) .
1521+ " from chunk 0 serially\n " );
1522+ }
14801523 my $now = Time::HiRes::gettimeofday();
14811524 $trace_data =
1482- _process_one_chunk($chunk , $processedChunks , $trace_data ,
1483- undef );
1484- $processedFiles += scalar (@$chunk );
1525+ _process_one_chunk($chunk -> [1], $processedChunks ,
1526+ $trace_data , undef );
1527+ $processedFiles += scalar (@{$chunk -> [1]});
1528+ if ($chunk -> [0]) {
1529+ lcovutil::info(" Finished processing chunk 0\n " );
1530+ }
14851531 my $then = Time::HiRes::gettimeofday();
1532+ $lcovutil::maxParallelism = $saveParallel ;
14861533 $lcovutil::profileData {process }{$processedChunks } =
14871534 $then - $now ;
14881535 }
@@ -1975,7 +2022,8 @@ sub compute_internal_directories(@)
19752022 my $t = Cwd::realpath($top );
19762023 die (" expected directory found '$t '" ) unless -d $t ;
19772024 unless (exists ($visited {$t })) {
1978- lcovutil::info(" internal: target '$t ' of link '$top '\n " );
2025+ lcovutil::info(1,
2026+ " internal directory: target '$t ' of link '$top '\n " );
19792027 $visited {$t } = $top ;
19802028 push (@dirstack , $t );
19812029 push (@lcovutil::internal_dirs , $t )
@@ -2836,11 +2884,22 @@ sub process_intermediate($$$$)
28362884 (0 != $rc ||
28372885 $lcovutil::verbose ));
28382886
2887+ my $gcovOutGlobPattern =
2888+ " $tempdir /*.gcov $tempdir /.*.gcov $tempdir /*.gcov.json.gz $tempdir /.*gcov.json.gz" ;
2889+
28392890 if (0 != $rc ) {
28402891 if (check_gcov_fail($err , $file )) {
28412892 return ;
28422893 }
28432894 $errmsg = " GCOV failed for $file " ;
2895+ # can parse the error log to see if it spaced out - then return
2896+ # code so parent can catch it
2897+ if ($err =~ / out of memory allocating/ ) {
2898+ lcovutil::info(" spaceout calling gcov for '$data_file '\n " );
2899+ $errmsg .= ' out of memory' ;
2900+ $errorType = $lcovutil::ERROR_CHILD
2901+ if 1 != $lcovutil::maxParallelism ;
2902+ }
28442903 goto err;
28452904 }
28462905
@@ -2853,22 +2912,32 @@ sub process_intermediate($$$$)
28532912 # 'meson' build system likes to use "." as leading character in generated
28542913 # files. Seems an unfortunate decision.
28552914 my $start = Time::HiRes::gettimeofday();
2856- for my $gcov_filename (
2857- glob (
2858- " $tempdir /*.gcov $tempdir /.*.gcov $tempdir /*.gcov.json.gz $tempdir /.*gcov.json.gz"
2859- )
2860- ) {
2861- if ($gcov_filename =~ / \. gcov\. json/ ) {
2862- read_intermediate_json($gcov_filename , \%data , \$json_basedir );
2863- $json_format = 1;
2864- } else {
2865- read_intermediate_text($gcov_filename , \%data );
2866- }
2867- if ($lcovutil::preserve_intermediates ) {
2868- File::Copy::move($gcov_filename , $fdir ) or
2869- die (" cannot rename $gcov_filename : $! " );
2870- } else {
2871- unlink ($gcov_filename );
2915+ for my $gcov_filename (glob ($gcovOutGlobPattern )) {
2916+ eval {
2917+ if ($gcov_filename =~ / \. gcov\. json/ ) {
2918+ read_intermediate_json($gcov_filename , \%data , \$json_basedir );
2919+ $json_format = 1;
2920+ } else {
2921+ read_intermediate_text($gcov_filename , \%data );
2922+ }
2923+ if ($lcovutil::preserve_intermediates ) {
2924+ File::Copy::move($gcov_filename , $fdir ) or
2925+ die (" cannot rename $gcov_filename : $! " );
2926+ } else {
2927+ unlink ($gcov_filename );
2928+ }
2929+ };
2930+ if ($@ ) {
2931+ if (1 != $lcovutil::maxParallelism &&
2932+ $@ =~ / (integrity check failed|cannot start)/ ) {
2933+ # looks like we ran out of memory..
2934+ # maybe need new error type ERROR_MEMORY
2935+ # $errorType = $lcovutil::ERROR_GCOV;
2936+ $errmsg = $@ ;
2937+ goto err;
2938+ } else {
2939+ die (" read_intermediate failed: $@ " );
2940+ }
28722941 }
28732942 }
28742943 my $end = Time::HiRes::gettimeofday();
@@ -2915,6 +2984,7 @@ sub process_intermediate($$$$)
29152984 return $trace ;
29162985
29172986 err:
2987+ unlink (glob ($gcovOutGlobPattern )); # clean up - in case gcov died
29182988 ignorable_error($errorType , " $errmsg !" );
29192989 return undef ;
29202990}
0 commit comments