Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(18)

Side by Side Diff: tools/pnacl-llc/pnacl-llc.cpp

Issue 196793026: Add self-scheduling to threaded translation (vs static) (Closed) Base URL: http://git.chromium.org/native_client/pnacl-llvm.git@master
Patch Set: reinstate check Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « tools/pnacl-llc/ThreadedFunctionQueue.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 //===-- pnacl-llc.cpp - PNaCl-specific llc: pexe ---> nexe ---------------===// 1 //===-- pnacl-llc.cpp - PNaCl-specific llc: pexe ---> nexe ---------------===//
2 // 2 //
3 // The LLVM Compiler Infrastructure 3 // The LLVM Compiler Infrastructure
4 // 4 //
5 // This file is distributed under the University of Illinois Open Source 5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details. 6 // License. See LICENSE.TXT for details.
7 // 7 //
8 //===----------------------------------------------------------------------===// 8 //===----------------------------------------------------------------------===//
9 // 9 //
10 // pnacl-llc: the core of the PNaCl translator, compiling a pexe into a nexe. 10 // pnacl-llc: the core of the PNaCl translator, compiling a pexe into a nexe.
(...skipping 27 matching lines...) Expand all
38 #include "llvm/Support/PrettyStackTrace.h" 38 #include "llvm/Support/PrettyStackTrace.h"
39 #include "llvm/Support/Signals.h" 39 #include "llvm/Support/Signals.h"
40 #include "llvm/Support/SourceMgr.h" 40 #include "llvm/Support/SourceMgr.h"
41 #include "llvm/Support/StreamableMemoryObject.h" 41 #include "llvm/Support/StreamableMemoryObject.h"
42 #include "llvm/Support/TargetRegistry.h" 42 #include "llvm/Support/TargetRegistry.h"
43 #include "llvm/Support/TargetSelect.h" 43 #include "llvm/Support/TargetSelect.h"
44 #include "llvm/Support/ToolOutputFile.h" 44 #include "llvm/Support/ToolOutputFile.h"
45 #include "llvm/Target/TargetLibraryInfo.h" 45 #include "llvm/Target/TargetLibraryInfo.h"
46 #include "llvm/Target/TargetMachine.h" 46 #include "llvm/Target/TargetMachine.h"
47 #include "llvm/Transforms/NaCl.h" 47 #include "llvm/Transforms/NaCl.h"
48 #include "ThreadedFunctionQueue.h"
48 #include "ThreadedStreamingCache.h" 49 #include "ThreadedStreamingCache.h"
49 #include <pthread.h> 50 #include <pthread.h>
50 #include <memory> 51 #include <memory>
51 52
52
53 using namespace llvm; 53 using namespace llvm;
54 54
55 // NOTE: When __native_client__ is defined it means pnacl-llc is built as a 55 // NOTE: When __native_client__ is defined it means pnacl-llc is built as a
56 // sandboxed translator (from pnacl-llc.pexe to pnacl-llc.nexe). In this mode 56 // sandboxed translator (from pnacl-llc.pexe to pnacl-llc.nexe). In this mode
57 // it uses SRPC operations instead of direct OS intefaces. 57 // it uses SRPC operations instead of direct OS intefaces.
58 #if defined(__native_client__) 58 #if defined(__native_client__)
59 int srpc_main(int argc, char **argv); 59 int srpc_main(int argc, char **argv);
60 int getObjectFileFD(unsigned index); 60 int getObjectFileFD(unsigned index);
61 DataStreamer *getNaClBitcodeStreamer(); 61 DataStreamer *getNaClBitcodeStreamer();
62 62
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
124 124
125 cl::opt<bool> 125 cl::opt<bool>
126 DisableSimplifyLibCalls("disable-simplify-libcalls", 126 DisableSimplifyLibCalls("disable-simplify-libcalls",
127 cl::desc("Disable simplify-libcalls"), 127 cl::desc("Disable simplify-libcalls"),
128 cl::init(false)); 128 cl::init(false));
129 129
130 cl::opt<unsigned> 130 cl::opt<unsigned>
131 SplitModuleCount("split-module", 131 SplitModuleCount("split-module",
132 cl::desc("Split PNaCl module"), cl::init(1U)); 132 cl::desc("Split PNaCl module"), cl::init(1U));
133 133
134 enum SplitModuleSchedulerKind {
135 SplitModuleDynamic,
136 SplitModuleStatic
137 };
138
139 cl::opt<SplitModuleSchedulerKind>
140 SplitModuleSched(
141 "split-module-sched",
142 cl::desc("Choose thread scheduler for split module compilation."),
143 cl::values(
144 clEnumValN(SplitModuleDynamic, "dynamic",
145 "Dynamic thread scheduling (default)"),
146 clEnumValN(SplitModuleStatic, "static",
147 "Static thread scheduling"),
148 clEnumValEnd),
149 cl::init(SplitModuleDynamic));
150
134 /// Compile the module provided to pnacl-llc. The file name for reading the 151 /// Compile the module provided to pnacl-llc. The file name for reading the
135 /// module and other options are taken from globals populated by command-line 152 /// module and other options are taken from globals populated by command-line
136 /// option parsing. 153 /// option parsing.
137 static int compileModule(StringRef ProgramName); 154 static int compileModule(StringRef ProgramName);
138 155
139 #if !defined(__native_client__) 156 #if !defined(__native_client__)
140 // GetFileNameRoot - Helper function to get the basename of a filename. 157 // GetFileNameRoot - Helper function to get the basename of a filename.
141 static std::string 158 static std::string
142 GetFileNameRoot(StringRef InputFilename) { 159 GetFileNameRoot(StringRef InputFilename) {
143 std::string IFN = InputFilename; 160 std::string IFN = InputFilename;
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after
328 // Err.print is prettier, so use it for the non-sandboxed translator. 345 // Err.print is prettier, so use it for the non-sandboxed translator.
329 Err.print(ProgramName.data(), errs()); 346 Err.print(ProgramName.data(), errs());
330 return NULL; 347 return NULL;
331 #endif 348 #endif
332 } 349 }
333 return M; 350 return M;
334 } 351 }
335 352
336 static int runCompilePasses(Module *mod, 353 static int runCompilePasses(Module *mod,
337 unsigned ModuleIndex, 354 unsigned ModuleIndex,
355 ThreadedFunctionQueue *FuncQueue,
338 const Triple &TheTriple, 356 const Triple &TheTriple,
339 TargetMachine &Target, 357 TargetMachine &Target,
340 StringRef ProgramName, 358 StringRef ProgramName,
341 formatted_raw_ostream &FOS){ 359 formatted_raw_ostream &FOS){
342 // Add declarations for external functions required by PNaCl. The 360 // Add declarations for external functions required by PNaCl. The
343 // ResolvePNaClIntrinsics function pass running during streaming 361 // ResolvePNaClIntrinsics function pass running during streaming
344 // depends on these declarations being in the module. 362 // depends on these declarations being in the module.
345 OwningPtr<ModulePass> AddPNaClExternalDeclsPass( 363 OwningPtr<ModulePass> AddPNaClExternalDeclsPass(
346 createAddPNaClExternalDeclsPass()); 364 createAddPNaClExternalDeclsPass());
347 AddPNaClExternalDeclsPass->runOnModule(*mod); 365 AddPNaClExternalDeclsPass->runOnModule(*mod);
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
424 if (Target.addPassesToEmitFile(*PM, FOS, FileType, 442 if (Target.addPassesToEmitFile(*PM, FOS, FileType,
425 /* DisableVerify */ true)) { 443 /* DisableVerify */ true)) {
426 errs() << ProgramName 444 errs() << ProgramName
427 << ": target does not support generation of this file type!\n"; 445 << ": target does not support generation of this file type!\n";
428 return 1; 446 return 1;
429 } 447 }
430 448
431 if (LazyBitcode) { 449 if (LazyBitcode) {
432 FunctionPassManager* P = static_cast<FunctionPassManager*>(PM.get()); 450 FunctionPassManager* P = static_cast<FunctionPassManager*>(PM.get());
433 P->doInitialization(); 451 P->doInitialization();
434 unsigned FuncIndex = 0; 452 int FuncIndex = 0;
435 for (Module::iterator I = mod->begin(), E = mod->end(); I != E; ++I) { 453 switch (SplitModuleSched) {
436 if (FuncIndex++ % SplitModuleCount == ModuleIndex) { 454 case SplitModuleStatic:
437 P->run(*I); 455 for (Module::iterator I = mod->begin(), E = mod->end(); I != E; ++I) {
438 CheckABIVerifyErrors(ABIErrorReporter, "Function " + I->getName()); 456 if (FuncQueue->GrabFunctionStatic(FuncIndex, ModuleIndex)) {
439 I->Dematerialize(); 457 P->run(*I);
458 CheckABIVerifyErrors(ABIErrorReporter, "Function " + I->getName());
459 I->Dematerialize();
460 }
461 ++FuncIndex;
440 } 462 }
463 break;
464 case SplitModuleDynamic:
465 unsigned ChunkSize = 0;
466 for (Module::iterator I = mod->begin(), E = mod->end(); I != E; ) {
467 ChunkSize = FuncQueue->RecommendedChunkSize();
468 int NextIndex;
469 bool grabbed = FuncQueue->GrabFunctionDynamic(FuncIndex, ChunkSize,
470 NextIndex);
471 if (grabbed) {
472 while (FuncIndex < NextIndex && I != E) {
473 P->run(*I);
474 CheckABIVerifyErrors(ABIErrorReporter, "Function " + I->getName());
475 I->Dematerialize();
476 ++FuncIndex;
477 ++I;
478 }
479 } else {
480 // Currently the ResolvePNaClIntrinsics function pass may
481 // add more declarations as we iterate. Some threads may get
482 // "lucky" and not add the related declarations, so those
483 // threads would have an earlier endpoint than other
484 // threads. the final NextIndex established by another
485 // thread would then be out of the bounds of the current thread.
486 // TODO(jvoung): Ensure that all declarations are added up front
487 // and uniformly so that we don't need this I != E check.
488 while (FuncIndex < NextIndex && I != E) {
489 ++FuncIndex;
490 ++I;
491 }
492 }
493 }
494 break;
441 } 495 }
442 P->doFinalization(); 496 P->doFinalization();
443 } else { 497 } else {
444 static_cast<PassManager*>(PM.get())->run(*mod); 498 static_cast<PassManager*>(PM.get())->run(*mod);
445 } 499 }
446 return 0; 500 return 0;
447 } 501 }
448 502
449 503
450 static int compileSplitModule(const TargetOptions &Options, 504 static int compileSplitModule(const TargetOptions &Options,
451 const Triple &TheTriple, 505 const Triple &TheTriple,
452 const Target *TheTarget, 506 const Target *TheTarget,
453 const std::string &FeaturesStr, 507 const std::string &FeaturesStr,
454 CodeGenOpt::Level OLvl, 508 CodeGenOpt::Level OLvl,
455 const StringRef &ProgramName, 509 const StringRef &ProgramName,
456 Module *GlobalModule, 510 Module *GlobalModule,
457 StreamingMemoryObject *StreamingObject, 511 StreamingMemoryObject *StreamingObject,
458 unsigned ModuleIndex) { 512 unsigned ModuleIndex,
513 ThreadedFunctionQueue *FuncQueue) {
459 std::auto_ptr<TargetMachine> 514 std::auto_ptr<TargetMachine>
460 target(TheTarget->createTargetMachine(TheTriple.getTriple(), 515 target(TheTarget->createTargetMachine(TheTriple.getTriple(),
461 MCPU, FeaturesStr, Options, 516 MCPU, FeaturesStr, Options,
462 RelocModel, CMModel, OLvl)); 517 RelocModel, CMModel, OLvl));
463 assert(target.get() && "Could not allocate target machine!"); 518 assert(target.get() && "Could not allocate target machine!");
464 TargetMachine &Target = *target.get(); 519 TargetMachine &Target = *target.get();
465 // Override default to generate verbose assembly. 520 // Override default to generate verbose assembly.
466 Target.setAsmVerbosityDefault(true); 521 Target.setAsmVerbosityDefault(true);
467 if (RelaxAll) { 522 if (RelaxAll) {
468 if (FileType != TargetMachine::CGFT_ObjectFile) 523 if (FileType != TargetMachine::CGFT_ObjectFile)
(...skipping 19 matching lines...) Expand all
488 543
489 mod->setTargetTriple(Triple::normalize(UserDefinedTriple)); 544 mod->setTargetTriple(Triple::normalize(UserDefinedTriple));
490 { 545 {
491 #if !defined(__native_client__) 546 #if !defined(__native_client__)
492 // Figure out where we are going to send the output. 547 // Figure out where we are going to send the output.
493 std::string N(OutputFilename); 548 std::string N(OutputFilename);
494 raw_string_ostream OutFileName(N); 549 raw_string_ostream OutFileName(N);
495 if (ModuleIndex > 0) 550 if (ModuleIndex > 0)
496 OutFileName << ".module" << ModuleIndex; 551 OutFileName << ".module" << ModuleIndex;
497 OwningPtr<tool_output_file> Out 552 OwningPtr<tool_output_file> Out
498 (GetOutputStream(TheTarget->getName(), TheTriple.getOS(), 553 (GetOutputStream(TheTarget->getName(), TheTriple.getOS(),
499 OutFileName.str())); 554 OutFileName.str()));
500 if (!Out) return 1; 555 if (!Out) return 1;
501 formatted_raw_ostream FOS(Out->os()); 556 formatted_raw_ostream FOS(Out->os());
502 #else 557 #else
503 raw_fd_ostream ROS(getObjectFileFD(ModuleIndex), true); 558 raw_fd_ostream ROS(getObjectFileFD(ModuleIndex), true);
504 ROS.SetBufferSize(1 << 20); 559 ROS.SetBufferSize(1 << 20);
505 formatted_raw_ostream FOS(ROS); 560 formatted_raw_ostream FOS(ROS);
506 #endif 561 #endif
507 int ret = runCompilePasses(mod, ModuleIndex, TheTriple, Target, ProgramName, 562 int ret = runCompilePasses(mod, ModuleIndex, FuncQueue,
563 TheTriple, Target, ProgramName,
508 FOS); 564 FOS);
509 if (ret) 565 if (ret)
510 return ret; 566 return ret;
511 #if defined (__native_client__) 567 #if defined (__native_client__)
512 FOS.flush(); 568 FOS.flush();
513 ROS.flush(); 569 ROS.flush();
514 #else 570 #else
515 // Declare success. 571 // Declare success.
516 Out->keep(); 572 Out->keep();
517 #endif // __native_client__ 573 #endif // __native_client__
518 } 574 }
519 return 0; 575 return 0;
520 } 576 }
521 577
522 struct ThreadData { 578 struct ThreadData {
523 const TargetOptions *Options; 579 const TargetOptions *Options;
524 const Triple *TheTriple; 580 const Triple *TheTriple;
525 const Target *TheTarget; 581 const Target *TheTarget;
526 std::string FeaturesStr; 582 std::string FeaturesStr;
527 CodeGenOpt::Level OLvl; 583 CodeGenOpt::Level OLvl;
528 std::string ProgramName; 584 std::string ProgramName;
529 Module *GlobalModule; 585 Module *GlobalModule;
530 StreamingMemoryObject *StreamingObject; 586 StreamingMemoryObject *StreamingObject;
531 unsigned ModuleIndex; 587 unsigned ModuleIndex;
588 ThreadedFunctionQueue *FuncQueue;
532 }; 589 };
533 590
534 591
535 static void *runCompileThread(void *arg) { 592 static void *runCompileThread(void *arg) {
536 struct ThreadData *Data = static_cast<ThreadData *>(arg); 593 struct ThreadData *Data = static_cast<ThreadData *>(arg);
537 int ret = compileSplitModule(*Data->Options, 594 int ret = compileSplitModule(*Data->Options,
538 *Data->TheTriple, 595 *Data->TheTriple,
539 Data->TheTarget, 596 Data->TheTarget,
540 Data->FeaturesStr, 597 Data->FeaturesStr,
541 Data->OLvl, 598 Data->OLvl,
542 Data->ProgramName, 599 Data->ProgramName,
543 Data->GlobalModule, 600 Data->GlobalModule,
544 Data->StreamingObject, 601 Data->StreamingObject,
545 Data->ModuleIndex); 602 Data->ModuleIndex,
603 Data->FuncQueue);
546 return reinterpret_cast<void *>(static_cast<intptr_t>(ret)); 604 return reinterpret_cast<void *>(static_cast<intptr_t>(ret));
547 } 605 }
548 606
549 static int compileModule(StringRef ProgramName) { 607 static int compileModule(StringRef ProgramName) {
550 // Use a new context instead of the global context for the main module. It mus t 608 // Use a new context instead of the global context for the main module. It mus t
551 // outlive the module object, declared below. We do this because 609 // outlive the module object, declared below. We do this because
552 // lib/CodeGen/PseudoSourceValue.cpp gets a type from the global context and 610 // lib/CodeGen/PseudoSourceValue.cpp gets a type from the global context and
553 // races with any other use of the context. Rather than doing an invasive 611 // races with any other use of the context. Rather than doing an invasive
554 // plumbing change to fix it, we work around it by using a new context here 612 // plumbing change to fix it, we work around it by using a new context here
555 // and leaving PseudoSourceValue as the only user of the global context. 613 // and leaving PseudoSourceValue as the only user of the global context.
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
645 return 1; 703 return 1;
646 case ' ': break; 704 case ' ': break;
647 case '0': OLvl = CodeGenOpt::None; break; 705 case '0': OLvl = CodeGenOpt::None; break;
648 case '1': OLvl = CodeGenOpt::Less; break; 706 case '1': OLvl = CodeGenOpt::Less; break;
649 case '2': OLvl = CodeGenOpt::Default; break; 707 case '2': OLvl = CodeGenOpt::Default; break;
650 case '3': OLvl = CodeGenOpt::Aggressive; break; 708 case '3': OLvl = CodeGenOpt::Aggressive; break;
651 } 709 }
652 710
653 SmallVector<pthread_t, 4> Pthreads(SplitModuleCount); 711 SmallVector<pthread_t, 4> Pthreads(SplitModuleCount);
654 SmallVector<ThreadData, 4> ThreadDatas(SplitModuleCount); 712 SmallVector<ThreadData, 4> ThreadDatas(SplitModuleCount);
713 ThreadedFunctionQueue FuncQueue(mod.get(), SplitModuleCount);
655 714
656 if (SplitModuleCount == 1) { 715 if (SplitModuleCount == 1) {
716 // No need for dynamic scheduling with one thread.
717 SplitModuleSched = SplitModuleStatic;
657 return compileSplitModule(Options, TheTriple, TheTarget, FeaturesStr, 718 return compileSplitModule(Options, TheTriple, TheTarget, FeaturesStr,
658 OLvl, ProgramName, mod.get(), NULL, 0); 719 OLvl, ProgramName, mod.get(), NULL, 0,
720 &FuncQueue);
659 } 721 }
660 722
661 for(unsigned ModuleIndex = 0; ModuleIndex < SplitModuleCount; ++ModuleIndex) { 723 for(unsigned ModuleIndex = 0; ModuleIndex < SplitModuleCount; ++ModuleIndex) {
662 ThreadDatas[ModuleIndex].Options = &Options; 724 ThreadDatas[ModuleIndex].Options = &Options;
663 ThreadDatas[ModuleIndex].TheTriple = &TheTriple; 725 ThreadDatas[ModuleIndex].TheTriple = &TheTriple;
664 ThreadDatas[ModuleIndex].TheTarget = TheTarget; 726 ThreadDatas[ModuleIndex].TheTarget = TheTarget;
665 ThreadDatas[ModuleIndex].FeaturesStr = FeaturesStr; 727 ThreadDatas[ModuleIndex].FeaturesStr = FeaturesStr;
666 ThreadDatas[ModuleIndex].OLvl = OLvl; 728 ThreadDatas[ModuleIndex].OLvl = OLvl;
667 ThreadDatas[ModuleIndex].ProgramName = ProgramName.str(); 729 ThreadDatas[ModuleIndex].ProgramName = ProgramName.str();
668 ThreadDatas[ModuleIndex].GlobalModule = mod.get(); 730 ThreadDatas[ModuleIndex].GlobalModule = mod.get();
669 ThreadDatas[ModuleIndex].StreamingObject = StreamingObject.get(); 731 ThreadDatas[ModuleIndex].StreamingObject = StreamingObject.get();
670 ThreadDatas[ModuleIndex].ModuleIndex = ModuleIndex; 732 ThreadDatas[ModuleIndex].ModuleIndex = ModuleIndex;
733 ThreadDatas[ModuleIndex].FuncQueue = &FuncQueue;
671 if (pthread_create(&Pthreads[ModuleIndex], NULL, runCompileThread, 734 if (pthread_create(&Pthreads[ModuleIndex], NULL, runCompileThread,
672 &ThreadDatas[ModuleIndex])) { 735 &ThreadDatas[ModuleIndex])) {
673 report_fatal_error("Failed to create thread"); 736 report_fatal_error("Failed to create thread");
674 } 737 }
675 } 738 }
676 for(unsigned ModuleIndex = 0; ModuleIndex < SplitModuleCount; ++ModuleIndex) { 739 for(unsigned ModuleIndex = 0; ModuleIndex < SplitModuleCount; ++ModuleIndex) {
677 void *retval; 740 void *retval;
678 if (pthread_join(Pthreads[ModuleIndex], &retval)) 741 if (pthread_join(Pthreads[ModuleIndex], &retval))
679 report_fatal_error("Failed to join thread"); 742 report_fatal_error("Failed to join thread");
680 intptr_t ret = reinterpret_cast<intptr_t>(retval); 743 intptr_t ret = reinterpret_cast<intptr_t>(retval);
681 if (ret != 0) 744 if (ret != 0)
682 report_fatal_error("Thread returned nonzero"); 745 report_fatal_error("Thread returned nonzero");
683 } 746 }
684 return 0; 747 return 0;
685 } 748 }
686 749
687 int main(int argc, char **argv) { 750 int main(int argc, char **argv) {
688 #if defined(__native_client__) 751 #if defined(__native_client__)
689 return srpc_main(argc, argv); 752 return srpc_main(argc, argv);
690 #else 753 #else
691 return llc_main(argc, argv); 754 return llc_main(argc, argv);
692 #endif // __native_client__ 755 #endif // __native_client__
693 } 756 }
OLDNEW
« no previous file with comments | « tools/pnacl-llc/ThreadedFunctionQueue.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698