@@ -28,6 +28,7 @@ shared bool verbose; // output verbose logging
28
28
shared bool force; // always build everything (ignores timestamp checking)
29
29
shared bool dryRun; // / dont execute targets, just print command to be executed
30
30
__gshared int jobs; // Number of jobs to run in parallel
31
+ __gshared bool usePGO = false ;
31
32
32
33
__gshared string [string ] env;
33
34
__gshared string [][string ] flags;
@@ -37,6 +38,7 @@ __gshared TaskPool taskPool;
37
38
// / Array of build rules through which all other build rules can be reached
38
39
immutable rootRules = [
39
40
&dmdDefault,
41
+ &dmdPGO,
40
42
&autoTesterBuild,
41
43
&runDmdUnittest,
42
44
&clean,
@@ -96,6 +98,7 @@ Examples
96
98
./build.d unittest # runs internal unittests
97
99
./build.d clean # remove all generated files
98
100
./build.d generated/linux/release/64/dmd.conf
101
+ ./build.d dmd-pgo # builds dmd with PGO data, currently only LDC is supported
99
102
100
103
Important variables:
101
104
--------------------
@@ -163,10 +166,13 @@ Command-line parameters
163
166
if (! flags[" DFLAGS" ].canFind(" -color=off" ) &&
164
167
[env[" HOST_DMD_RUN" ], " -color=on" , " -h" ].tryRun().status == 0 )
165
168
flags[" DFLAGS" ] ~= " -color=on" ;
166
-
169
+ string defaultRule ()
170
+ {
171
+ return usePGO ? " dmd-pgo" : " dmd" ;
172
+ }
167
173
// default target
168
174
if (! args.length)
169
- args = [" dmd " ];
175
+ args = [defaultRule() ];
170
176
171
177
auto targets = predefinedTargets(args); // preprocess
172
178
@@ -475,17 +481,134 @@ alias dmdDefault = makeRule!((builder, rule) => builder
475
481
.description(" Build dmd" )
476
482
.deps([dmdExe(null , null , null ), dmdConf])
477
483
);
484
+ struct PGOState
485
+ {
486
+ // Does the host compiler actually support PGO, if not print a message
487
+ static bool checkPGO (string x)
488
+ {
489
+ switch (env[" HOST_DMD_KIND" ])
490
+ {
491
+ case " dmd" :
492
+ abortBuild(` DMD does not support PGO!` );
493
+ break ;
494
+ case " ldc" :
495
+ return true ;
496
+ break ;
497
+ case " gdc" :
498
+ abortBuild(` PGO (or AutoFDO) builds are not yet supported for gdc` );
499
+ break ;
500
+ default :
501
+ assert (false , " Unknown host compiler kind: " ~ env[" HOST_DMD_KIND" ]);
502
+ }
503
+ assert (0 );
504
+ }
505
+ this (string set)
506
+ {
507
+ hostKind = set;
508
+ profDirPath = buildPath(env[" G" ], " dmd_profdata" );
509
+ mkdirRecurse(profDirPath);
510
+ }
511
+ string profDirPath;
512
+ string hostKind;
513
+ string [] pgoGenerateFlags () const
514
+ {
515
+ switch (hostKind)
516
+ {
517
+ case " ldc" :
518
+ return [" -fprofile-instr-generate=" ~ pgoDataPath ~ " /data.%p.raw" ];
519
+ default :
520
+ return [" " ];
521
+ }
522
+ }
523
+ string [] pgoUseFlags () const
524
+ {
525
+ switch (hostKind)
526
+ {
527
+ case " ldc" :
528
+ return [" -fprofile-instr-use=" ~ buildPath(pgoDataPath(), " merged.data" )];
529
+ default :
530
+ return [" " ];
531
+ }
532
+ }
533
+ string pgoDataPath () const
534
+ {
535
+ return profDirPath;
536
+ }
537
+ }
538
+ // Compiles the test runner
539
+ alias testRunner = methodInit! (BuildRule, (rundBuilder, rundRule) => rundBuilder
540
+ .msg(" (DC) RUN.D" )
541
+ .sources([ testDir.buildPath( " run.d" ) ])
542
+ .target(env[" GENERATED" ].buildPath(" run" .exeName))
543
+ .command([ env[" HOST_DMD_RUN" ], " -of=" ~ rundRule.target, " -i" , " -I" ~ testDir] ~ rundRule.sources));
544
+
545
+
546
+ alias dmdPGO = makeRule! ((builder, rule) {
547
+ const dmdKind = env[" HOST_DMD_KIND" ];
548
+ PGOState pgoState = PGOState(dmdKind);
549
+
550
+ alias buildInstrumentedDmd = methodInit! (BuildRule, (rundBuilder, rundRule) => rundBuilder
551
+ .msg(" Built dmd with PGO instrumentation" )
552
+ .deps([dmdExe(null , pgoState.pgoGenerateFlags(), pgoState.pgoGenerateFlags()), dmdConf]));
553
+
554
+ alias genDmdData = methodInit! (BuildRule, (rundBuilder, rundRule) => rundBuilder
555
+ .msg(" Compiling dmd testsuite to generate PGO data" )
556
+ .sources([ testDir.buildPath( " run.d" ) ])
557
+ .deps([buildInstrumentedDmd, testRunner])
558
+ .commandFunction({
559
+ // Run dmd test suite to get data
560
+ const scope cmd = [ testRunner.targets[0 ], " compilable" , " -j" ~ jobs.to! string ];
561
+ log(" %-(%s %)" , cmd);
562
+ if (spawnProcess(cmd, null , Config.init, testDir).wait())
563
+ stderr.writeln(" dmd tests failed! This will not end the PGO build because some data may have been gathered" );
564
+ }));
565
+ alias genPhobosData = methodInit! (BuildRule, (rundBuilder, rundRule) => rundBuilder
566
+ .msg(" Compiling phobos testsuite to generate PGO data" )
567
+ .deps([buildInstrumentedDmd])
568
+ .commandFunction({
569
+ // Run phobos unittests
570
+ // TODO makefiles
571
+ // generated/linux/release/64/unittest/test_runner builds the unittests without running them.
572
+ const scope cmd = [" make" , " -C" , " ../phobos" , " -j" ~ jobs.to! string , " -fposix.mak" , " generated/linux/release/64/unittest/test_runner" , " DMD_DIR=" ~ dmdRepo];
573
+ log(" %-(%s %)" , cmd);
574
+ if (spawnProcess(cmd, null , Config.init, dmdRepo).wait())
575
+ stderr.writeln(" Phobos Tests failed! This will not end the PGO build because some data may have been gathered" );
576
+ }));
577
+ alias finalDataMerge = methodInit! (BuildRule, (rundBuilder, rundRule) => rundBuilder
578
+ .msg(" Merging PGO data" )
579
+ .deps([genDmdData])
580
+ .commandFunction({
581
+ // Run dmd test suite to get data
582
+ scope cmd = [" ldc-profdata" , " merge" , " --output=merged.data" ];
583
+ import std.file : dirEntries;
584
+ auto files = dirEntries(pgoState.pgoDataPath, " *.raw" , SpanMode.shallow).array;
585
+ files.each! (f => cmd ~= f);
586
+ log(" %-(%s %)" , cmd);
587
+ if (spawnProcess(cmd, null , Config.init, pgoState.pgoDataPath).wait())
588
+ abortBuild(" Merge failed" );
589
+ files.each! (f => remove(f));
590
+ }));
591
+ builder
592
+ .name(" dmd-pgo" )
593
+ .description(" Build dmd with PGO data collected from the dmd and phobos testsuites" )
594
+ .msg(" Build with collected PGO data" )
595
+ .condition(() => PGOState.checkPGO(dmdKind))
596
+ .deps([finalDataMerge])
597
+ .commandFunction({
598
+ auto addArgs = pgoState.pgoUseFlags ~ " -wi" ;
599
+ auto cmd = [env[" HOST_DMD_RUN" ], " -run" , " src/build.d" , " ENABLE_RELEASE=1" ,
600
+ " ENABLE_LTO=1" ,
601
+ " DFLAGS=" ~ joiner(addArgs, " " ).to! string , " --force" , " -j" ~ jobs.to! string ];
602
+ log(" %-(%s %)" , cmd);
603
+ if (spawnProcess(cmd, null , Config.init).wait())
604
+ abortBuild(" PGO Compilation failed" );
605
+ });
606
+ }
607
+ );
478
608
479
609
// / Run's the test suite (unittests & `run.d`)
480
610
alias runTests = makeRule! ((testBuilder, testRule)
481
611
{
482
- // Precompiles the test runner
483
- alias runner = methodInit! (BuildRule, (rundBuilder, rundRule) => rundBuilder
484
- .msg(" (DC) RUN.D" )
485
- .sources([ testDir.buildPath( " run.d" ) ])
486
- .target(env[" GENERATED" ].buildPath(" run" .exeName))
487
- .command([ env[" HOST_DMD_RUN" ], " -of=" ~ rundRule.target, " -i" , " -I" ~ testDir] ~ rundRule.sources));
488
-
489
612
// Reference header assumes Linux64
490
613
auto headerCheck = env[" OS" ] == " linux" && env[" MODEL" ] == " 64"
491
614
? [ runCxxHeadersTest ] : null ;
@@ -494,10 +617,10 @@ alias runTests = makeRule!((testBuilder, testRule)
494
617
.name(" test" )
495
618
.description(" Run the test suite using test/run.d" )
496
619
.msg(" (RUN) TEST" )
497
- .deps([dmdDefault, runDmdUnittest, runner ] ~ headerCheck)
620
+ .deps([dmdDefault, runDmdUnittest, testRunner ] ~ headerCheck)
498
621
.commandFunction({
499
622
// Use spawnProcess to avoid output redirection for `command`s
500
- const scope cmd = [ runner .targets[0 ], " -j" ~ jobs.to! string ];
623
+ const scope cmd = [ testRunner .targets[0 ], " -j" ~ jobs.to! string ];
501
624
log(" %-(%s %)" , cmd);
502
625
if (spawnProcess(cmd, null , Config.init, testDir).wait())
503
626
abortBuild(" Tests failed!" );
@@ -1261,6 +1384,23 @@ void processEnvironment()
1261
1384
assert (false , " Unknown host compiler kind: " ~ env[" HOST_DMD_KIND" ]);
1262
1385
}
1263
1386
}
1387
+ if (env.getNumberedBool(" ENABLE_PGO" ))
1388
+ {
1389
+ switch (env[" HOST_DMD_KIND" ])
1390
+ {
1391
+ case " dmd" :
1392
+ stderr.writeln(` DMD does not support PGO! Ignoring ENABLE_PGO flag` );
1393
+ break ;
1394
+ case " ldc" :
1395
+ usePGO = true ;
1396
+ break ;
1397
+ case " gdc" :
1398
+ stderr.writeln(` PGO (or AutoFDO) builds are not yet supported for gdc. Ignoring ENABLE_PGO flag` );
1399
+ break ;
1400
+ default :
1401
+ assert (false , " Unknown host compiler kind: " ~ env[" HOST_DMD_KIND" ]);
1402
+ }
1403
+ }
1264
1404
if (env.getNumberedBool(" ENABLE_UNITTEST" ))
1265
1405
{
1266
1406
dflags ~= [" -unittest" ];
0 commit comments