@@ -222,6 +222,7 @@ our $intervalChildCpuTime = 0; # since last updata
222
222
our $defaultChunkSize ;
223
223
our $defaultInterval ;
224
224
our %childRetryCounts ;
225
+ our @large_files ;
225
226
226
227
our $cwd = getcwd();
227
228
chomp ($cwd );
@@ -255,7 +256,8 @@ my %geninfo_opts = ("test-name|t=s" => \$test_name,
255
256
" derive-func-data" => \$opt_derive_func_data ,
256
257
" external|e" => \$lcovutil::opt_external ,
257
258
" 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 );
259
261
260
262
# Parse command line options
261
263
if (!lcovutil::parseOptions(\%lcovutil::geninfo_rc_opts , \%geninfo_opts ,
@@ -268,6 +270,12 @@ $buildDirSearchPath =
268
270
SearchPath-> new(' build directory' , @lcovutil::build_directory );
269
271
@gcov_tool = @lcovutil::rc_gcov_tool unless @gcov_tool ;
270
272
273
+ eval {
274
+ map { qr ($_ ) } @large_files ;
275
+ };
276
+ die (" invalid 'large-file' regexp: $@ " )
277
+ if ($@ );
278
+
271
279
# Check regexp
272
280
if (defined ($lcovutil::rc_adjust_src_path )) {
273
281
my ($pattern , $replace ) = split (/ \s *=>\s */ , $lcovutil::rc_adjust_src_path );
@@ -1065,7 +1073,7 @@ sub _process_one_chunk($$$$)
1065
1073
1066
1074
# "name" will be .gcno if "$initial" else will be $gcda
1067
1075
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 " );
1069
1077
my $context = MessageContext-> new(" capturing from $name " );
1070
1078
1071
1079
# multiple gcda files may refer to the same source - so generate the
@@ -1181,6 +1189,19 @@ sub _merge_one_child($$$)
1181
1189
$lcovutil::max_fork_fails != 0) ||
1182
1190
$lcovutil::verbose );
1183
1191
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
+ }
1184
1205
my $data = Storable::retrieve($dumped )
1185
1206
if (-f $dumped && 0 == $childstatus );
1186
1207
# note that $data will not be defined (no data dumped) if there was
@@ -1298,15 +1319,26 @@ sub gen_info(@)
1298
1319
$chunkSize = 1;
1299
1320
}
1300
1321
my @worklist ;
1301
- my $chunk = [];
1322
+ my $serialChunk = [1, []];
1323
+ my $chunk = [0, []]; # [isSerial, [fileList]]
1302
1324
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 ) {
1305
1333
push (@worklist , $chunk );
1306
- $chunk = [];
1334
+ $chunk = [0, [] ];
1307
1335
}
1308
1336
} # 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]});
1310
1342
1311
1343
# Process all files in list
1312
1344
my $currentParallel = 0;
@@ -1342,7 +1374,8 @@ sub gen_info(@)
1342
1374
my $chunk = pop (@worklist );
1343
1375
++$processedChunks ;
1344
1376
1345
- if (1 < $lcovutil::maxParallelism ) {
1377
+ if (1 < $lcovutil::maxParallelism &&
1378
+ 1 != $chunk -> [0]) {
1346
1379
1347
1380
my $currentSize = 0;
1348
1381
if (0 != $lcovutil::maxMemory ) {
@@ -1410,8 +1443,8 @@ sub gen_info(@)
1410
1443
my ($stdout , $stderr , $code ) = Capture::Tiny::capture {
1411
1444
eval {
1412
1445
$childInfo =
1413
- _process_one_chunk($chunk , $processedChunks ,
1414
- $childInfo , $$ );
1446
+ _process_one_chunk($chunk -> [1] ,
1447
+ $processedChunks , $childInfo , $$ );
1415
1448
};
1416
1449
if ($@ ) {
1417
1450
$status = 1; # error
@@ -1458,12 +1491,14 @@ sub gen_info(@)
1458
1491
# there is no childInfo data
1459
1492
$data =
1460
1493
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 );
1467
1502
};
1468
1503
if ($@ || (defined ($childInfo ) && !defined ($data ))) {
1469
1504
lcovutil::ignorable_error($lcovutil::ERROR_PARALLEL ,
@@ -1477,12 +1512,24 @@ sub gen_info(@)
1477
1512
}
1478
1513
} else {
1479
1514
# 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
+ }
1480
1523
my $now = Time::HiRes::gettimeofday();
1481
1524
$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
+ }
1485
1531
my $then = Time::HiRes::gettimeofday();
1532
+ $lcovutil::maxParallelism = $saveParallel ;
1486
1533
$lcovutil::profileData {process }{$processedChunks } =
1487
1534
$then - $now ;
1488
1535
}
@@ -1975,7 +2022,8 @@ sub compute_internal_directories(@)
1975
2022
my $t = Cwd::realpath($top );
1976
2023
die (" expected directory found '$t '" ) unless -d $t ;
1977
2024
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 " );
1979
2027
$visited {$t } = $top ;
1980
2028
push (@dirstack , $t );
1981
2029
push (@lcovutil::internal_dirs , $t )
@@ -2836,11 +2884,22 @@ sub process_intermediate($$$$)
2836
2884
(0 != $rc ||
2837
2885
$lcovutil::verbose ));
2838
2886
2887
+ my $gcovOutGlobPattern =
2888
+ " $tempdir /*.gcov $tempdir /.*.gcov $tempdir /*.gcov.json.gz $tempdir /.*gcov.json.gz" ;
2889
+
2839
2890
if (0 != $rc ) {
2840
2891
if (check_gcov_fail($err , $file )) {
2841
2892
return ;
2842
2893
}
2843
2894
$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
+ }
2844
2903
goto err;
2845
2904
}
2846
2905
@@ -2853,22 +2912,32 @@ sub process_intermediate($$$$)
2853
2912
# 'meson' build system likes to use "." as leading character in generated
2854
2913
# files. Seems an unfortunate decision.
2855
2914
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
+ }
2872
2941
}
2873
2942
}
2874
2943
my $end = Time::HiRes::gettimeofday();
@@ -2915,6 +2984,7 @@ sub process_intermediate($$$$)
2915
2984
return $trace ;
2916
2985
2917
2986
err:
2987
+ unlink (glob ($gcovOutGlobPattern )); # clean up - in case gcov died
2918
2988
ignorable_error($errorType , " $errmsg !" );
2919
2989
return undef ;
2920
2990
}
0 commit comments