diff options
| author | jsmall-nvidia <jsmall@nvidia.com> | 2019-10-24 21:14:12 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-10-24 21:14:12 -0400 |
| commit | 3c57c86cdb2ae301441cf26a5bbe137e0b3bd512 (patch) | |
| tree | 5d54121b3ca83790be8e89efc5fcd3faa1cc0134 /source | |
| parent | 89ddb50eaccc1b7b590dbde55032721762711fb2 (diff) | |
* Functionality to dump repo if there is a failure throught the -dump-repro-on-failure option (#1095)
* Small typo fix
Diffstat (limited to 'source')
| -rw-r--r-- | source/slang/slang-compiler.h | 3 | ||||
| -rw-r--r-- | source/slang/slang-diagnostic-defs.h | 3 | ||||
| -rw-r--r-- | source/slang/slang-options.cpp | 4 | ||||
| -rw-r--r-- | source/slang/slang-state-serialize.cpp | 74 | ||||
| -rw-r--r-- | source/slang/slang-state-serialize.h | 3 | ||||
| -rw-r--r-- | source/slang/slang.cpp | 39 |
6 files changed, 116 insertions, 10 deletions
diff --git a/source/slang/slang-compiler.h b/source/slang/slang-compiler.h index a5a1b7d93..1900342da 100644 --- a/source/slang/slang-compiler.h +++ b/source/slang/slang-compiler.h @@ -1728,6 +1728,9 @@ namespace Slang // If set, will dump the compilation state String dumpRepro; + /// If set, if a compilation failure occurs will attempt to save off a dump repro with a unique name + bool dumpReproOnError = false; + /// A blob holding the diagnostic output ComPtr<ISlangBlob> diagnosticOutputBlob; diff --git a/source/slang/slang-diagnostic-defs.h b/source/slang/slang-diagnostic-defs.h index 008b1ef04..3a708712b 100644 --- a/source/slang/slang-diagnostic-defs.h +++ b/source/slang/slang-diagnostic-defs.h @@ -108,7 +108,8 @@ DIAGNOSTIC( 70, Error, cannotMatchOutputFileToEntryPoint, "the output path '$ DIAGNOSTIC( 80, Error, duplicateOutputPathsForEntryPointAndTarget, "multiple output paths have been specified entry point '$0' on target '$1'") -DIAGNOSTIC( 81, Error, parametersAfterLoadReproIgnored, "Parameters after -load-repro [file] are ignored") +DIAGNOSTIC( 81, Error, parametersAfterLoadReproIgnored, "parameters after -load-repro [file] are ignored") +DIAGNOSTIC( 82, Error, unableToWriteReproFile, "unable to write repro file '%0'"); // // 1xxxx - Lexical anaylsis diff --git a/source/slang/slang-options.cpp b/source/slang/slang-options.cpp index c76993ca4..e9a8e7e04 100644 --- a/source/slang/slang-options.cpp +++ b/source/slang/slang-options.cpp @@ -498,6 +498,10 @@ struct OptionsParser SLANG_RETURN_ON_FAIL(tryReadCommandLineArgument(sink, arg, &argCursor, argEnd, requestImpl->dumpRepro)); spEnableReproCapture(asExternal(requestImpl)); } + else if (argStr == "-dump-repro-on-error") + { + requestImpl->dumpReproOnError = true; + } else if (argStr == "-extract-repro") { String reproName; diff --git a/source/slang/slang-state-serialize.cpp b/source/slang/slang-state-serialize.cpp index 2d40e78ef..4c2651475 100644 --- a/source/slang/slang-state-serialize.cpp +++ b/source/slang/slang-state-serialize.cpp @@ -3,6 +3,8 @@ #include "../core/slang-text-io.h" +#include "../core/slang-stream.h" + #include "../core/slang-math.h" #include "slang-source-loc.h" @@ -1166,8 +1168,6 @@ struct LoadContext case CompressedResult::CannotOpen: builder << "[cannot open]"; break; case CompressedResult::Fail: builder << "[fail]"; break; } - - } builder << "\n"; @@ -1177,4 +1177,74 @@ struct LoadContext return SLANG_OK; } +static SlangResult _findFirstSourcePath(EndToEndCompileRequest* request, String& outFilename) +{ + // We are going to look through all of the srcTranlationUnits, looking for the first filename + + auto frontEndReq = request->getFrontEndReq(); + const auto& srcTranslationUnits = frontEndReq->translationUnits; + + for (Index i = 0; i < srcTranslationUnits.getCount(); ++i) + { + TranslationUnitRequest* srcTranslationUnit = srcTranslationUnits[i]; + const auto& srcSourceFiles = srcTranslationUnit->getSourceFiles(); + + for (Index j = 0; j < srcSourceFiles.getCount(); ++j) + { + SourceFile* sourceFile = srcSourceFiles[j]; + + const PathInfo& pathInfo = sourceFile->getPathInfo(); + + if (pathInfo.foundPath.getLength()) + { + outFilename = pathInfo.foundPath; + return SLANG_OK; + } + } + } + return SLANG_FAIL; +} + +/* static */SlangResult StateSerializeUtil::findUniqueReproDumpStream(EndToEndCompileRequest* request, String& outFileName, RefPtr<Stream>& outStream) +{ + String sourcePath; + + if (SLANG_FAILED(_findFirstSourcePath(request, sourcePath))) + { + sourcePath = "unknown.slang"; + } + + String sourceFileName = Path::getFileName(sourcePath); + String sourceBaseName = Path::getFileNameWithoutExt(sourceFileName); + + // Okay we need a unique number to make sure the name is unique + const int maxTries = 100; + for (int triesCount = 0; triesCount < maxTries; ++triesCount) + { + // We could include the count in some way perhaps, but for now let's just go with ticks + auto tick = ProcessUtil::getClockTick(); + + StringBuilder builder; + builder << sourceBaseName << "-" << tick << ".slang-repro"; + + // We write out the file name tried even if it fails, as might be useful in reporting + outFileName = builder; + + // We could have clashes, as we use ticks, we should get to a point where the clashes stop + try + { + outStream = new FileStream(builder, FileMode::CreateNew, FileAccess::Write, FileShare::WriteOnly); + return SLANG_OK; + } + catch (IOException&) + { + } + + // TODO(JS): + // Might make sense to sleep here - but don't seem to have cross platform func for that yet. + } + + return SLANG_FAIL; +} + } // namespace Slang diff --git a/source/slang/slang-state-serialize.h b/source/slang/slang-state-serialize.h index 6de792097..d02bfae8c 100644 --- a/source/slang/slang-state-serialize.h +++ b/source/slang/slang-state-serialize.h @@ -180,6 +180,9 @@ struct StateSerializeUtil /// Given the repo file work out a suitable path static SlangResult calcDirectoryPathFromFilename(const String& filename, String& outPath); + + /// Given a request trys to determine a suitable dump file name, that is unique. + static SlangResult findUniqueReproDumpStream(EndToEndCompileRequest* request, String& outFileName, RefPtr<Stream>& outStream); }; } // namespace Slang diff --git a/source/slang/slang.cpp b/source/slang/slang.cpp index 3053b60c0..29b46c805 100644 --- a/source/slang/slang.cpp +++ b/source/slang/slang.cpp @@ -3214,7 +3214,8 @@ SLANG_API SlangResult spSetTypeNameForEntryPointExistentialTypeParam( SLANG_API SlangResult spCompile( SlangCompileRequest* request) { - auto req = Slang::asInternal(request); + using namespace Slang; + auto req = asInternal(request); SlangResult res = SLANG_FAIL; @@ -3233,19 +3234,19 @@ SLANG_API SlangResult spCompile( { res = req->executeActions(); } - catch (Slang::AbortCompilationException&) + catch (AbortCompilationException&) { // This situation indicates a fatal (but not necessarily internal) error // that forced compilation to terminate. There should already have been // a diagnostic produced, so we don't need to add one here. } - catch (Slang::Exception& e) + catch (Exception& e) { // The compiler failed due to an internal error that was detected. // We will print out information on the exception to help out the user // in either filing a bug, or locating what in their code created // a problem. - req->getSink()->diagnose(Slang::SourceLoc(), Slang::Diagnostics::compilationAbortedDueToException, typeid(e).name(), e.Message); + req->getSink()->diagnose(SourceLoc(), Diagnostics::compilationAbortedDueToException, typeid(e).name(), e.Message); } catch (...) { @@ -3253,7 +3254,7 @@ SLANG_API SlangResult spCompile( // `Exception`, so something really fishy is going on. We want to // let the user know that we messed up, so they know to blame Slang // and not some other component in their system. - req->getSink()->diagnose(Slang::SourceLoc(), Slang::Diagnostics::compilationAborted); + req->getSink()->diagnose(SourceLoc(), Diagnostics::compilationAborted); } req->mDiagnosticOutput = req->getSink()->outputBuffer.ProduceString(); @@ -3265,9 +3266,33 @@ SLANG_API SlangResult spCompile( } #endif - if (req->dumpRepro.getLength()) + // Repro dump handling { - SLANG_RETURN_ON_FAIL(Slang::StateSerializeUtil::saveState(req, req->dumpRepro)); + if (req->dumpRepro.getLength()) + { + SlangResult saveRes = StateSerializeUtil::saveState(req, req->dumpRepro); + if (SLANG_FAILED(saveRes)) + { + req->getSink()->diagnose(SourceLoc(), Diagnostics::unableToWriteReproFile, req->dumpRepro); + return saveRes; + } + } + else if (req->dumpReproOnError && SLANG_FAILED(res)) + { + String reproFileName; + SlangResult saveRes = SLANG_FAIL; + + RefPtr<Stream> stream; + if (SLANG_SUCCEEDED(StateSerializeUtil::findUniqueReproDumpStream(req, reproFileName, stream))) + { + saveRes = StateSerializeUtil::saveState(req, stream); + } + + if (SLANG_FAILED(saveRes)) + { + req->getSink()->diagnose(SourceLoc(), Diagnostics::unableToWriteReproFile, reproFileName); + } + } } return res; |
