/// <summary> /// Sync the MinidumpDiagnostics binary and the engine config files to #head. /// </summary> /// <returns>true if all the files synced without issue, false otherwise.</returns> /// <remarks>As MinidumpDiagnostics is synced to #head, it requires the engine config files that match to run properly.</remarks> private static bool SyncMinidumpDiagnostics() { // Use the latest MinidumpDiagnostics from the main branch. CrashReporterProcessServicer.StatusReporter.AlertOnLowDisk(Config.Default.DepotRoot, Config.Default.DiskSpaceAlertPercent); string UserString = "-u " + Config.Default.P4User; string ClientString = "-c " + Config.Default.P4Client; string SyncBinariesString = Path.Combine(Config.Default.DepotRoot, Config.Default.SyncBinariesFromDepot); using (var MDDSyncProc = new LaunchProcess(PerforceExePath, null, CrashReporterProcessServicer.WriteP4, UserString, ClientString, "sync", SyncBinariesString)) { if( MDDSyncProc.WaitForExit( SyncTimeoutSeconds * 1000 ) == EWaitResult.TimedOut ) { CrashReporterProcessServicer.WriteFailure("Failed to sync MinidumpDiagnostics " + SyncBinariesString); return false; } } string SyncConfigString = Path.Combine(Config.Default.DepotRoot, Config.Default.SyncConfigFromDepot); using (var ConfigSyncProc = new LaunchProcess(PerforceExePath, null, CrashReporterProcessServicer.WriteP4, UserString, ClientString, "sync", SyncConfigString)) { if (ConfigSyncProc.WaitForExit(SyncTimeoutSeconds * 1000) == EWaitResult.TimedOut) { CrashReporterProcessServicer.WriteFailure("Failed to sync config files " + SyncConfigString); return false; } } string SyncThirdPartyString = Path.Combine(Config.Default.DepotRoot, Config.Default.SyncThirdPartyFromDepot); // Required by Perforce using (var MiscSyncProc = new LaunchProcess(PerforceExePath, null, CrashReporterProcessServicer.WriteP4, UserString, ClientString, "sync", SyncThirdPartyString)) { if (MiscSyncProc.WaitForExit(SyncTimeoutSeconds * 1000) == EWaitResult.TimedOut) { CrashReporterProcessServicer.WriteFailure("Failed to sync OpenSSL files " + SyncThirdPartyString); return false; } } return true; }
/// <summary> /// Builds MDD command line args, waits for a MDD task slot, runs MDD and blocks for the result. Writes diag text into DiagnosticsPath folder if successful. /// </summary> /// <param name="DiagnosticsPath">Path of the minidump file</param> /// <param name="Context">The crash context</param> /// <param name="ProcessorIndex">Processor thread index for logging purposes</param> /// <returns>True, if successful</returns> public bool Run(string DiagnosticsPath, FGenericCrashContext Context, int ProcessorIndex) { // Use the latest MinidumpDiagnostics from the main branch. CrashReporterProcessServicer.StatusReporter.AlertOnLowDisk(Config.Default.DepotRoot, Config.Default.DiskSpaceAlertPercent); string Win64BinariesDirectory = Path.Combine(Config.Default.DepotRoot, Config.Default.MDDBinariesFolderInDepot); #if DEBUG // Note: the debug executable must be built locally or synced from Perforce manually string MinidumpDiagnosticsName = Path.Combine(Win64BinariesDirectory, "MinidumpDiagnostics-Win64-Debug.exe"); #else string MinidumpDiagnosticsName = Path.Combine(Win64BinariesDirectory, "MinidumpDiagnostics.exe"); #endif // Don't purge logs // TODO: make this clear to logs once a day or something (without letting MDD check on every run!) string PurgeLogsDays = "-1"; FEngineVersion EngineVersion = new FEngineVersion(Context.PrimaryCrashProperties.EngineVersion); // Pass Windows variants (Win32/64) to MinidumpDiagnostics string PlatformVariant = Context.PrimaryCrashProperties.PlatformName; if (PlatformVariant != null && Context.PrimaryCrashProperties.PlatformFullName != null && PlatformVariant.ToUpper().Contains("WINDOWS")) { if (Context.PrimaryCrashProperties.PlatformFullName.Contains("Win32") || Context.PrimaryCrashProperties.PlatformFullName.Contains("32b")) { PlatformVariant = "Win32"; } else if (Context.PrimaryCrashProperties.PlatformFullName.Contains("Win64") || Context.PrimaryCrashProperties.PlatformFullName.Contains("64b")) { PlatformVariant = "Win64"; } } // Build the absolute log file path for MinidumpDiagnostics string BaseFolder = CrashReporterProcessServicer.SymbolicatorLogFolder; string SubFolder = DateTime.UtcNow.ToString("yyyy_MM_dd"); string Folder = Path.Combine(BaseFolder, SubFolder); string AbsLogPath = Path.Combine(Folder, Context.GetAsFilename() + ".log"); Directory.CreateDirectory(Folder); List<string> MinidumpDiagnosticsParams = new List<string> ( new string[] { "\""+DiagnosticsPath+"\"", "-BranchName=" + EngineVersion.Branch, // Backward compatibility "-BuiltFromCL=" + EngineVersion.Changelist, // Backward compatibility "-GameName=" + Context.PrimaryCrashProperties.GameName, "-EngineVersion=" + Context.PrimaryCrashProperties.EngineVersion, "-BuildVersion=" + (string.IsNullOrWhiteSpace(Context.PrimaryCrashProperties.BuildVersion) ? string.Format("{0}-CL-{1}", EngineVersion.Branch, EngineVersion.Changelist).Replace('/', '+') : Context.PrimaryCrashProperties.BuildVersion), "-PlatformName=" + Context.PrimaryCrashProperties.PlatformName, "-PlatformVariantName=" + PlatformVariant, "-bUsePDBCache=true", "-PDBCacheDepotRoot=" + Config.Default.DepotRoot, "-PDBCachePath=" + Config.Default.MDDPDBCachePath, "-PDBCacheSizeGB=" + Config.Default.MDDPDBCacheSizeGB, "-PDBCacheMinFreeSpaceGB=" + Config.Default.MDDPDBCacheMinFreeSpaceGB, "-PDBCacheFileDeleteDays=" + Config.Default.MDDPDBCacheFileDeleteDays, "-MutexPDBCache", "-PDBCacheLock=CrashReportProcessPDBCacheLock", "-NoTrimCallstack", "-SyncSymbols", "-NoP4Symbols", "-ForceUsePDBCache", "-MutexSourceSync", "-SourceSyncLock=CrashReportProcessSourceSyncLock", "-SyncMicrosoftSymbols", "-unattended", "-AbsLog=" + AbsLogPath, "-DepotIndex=" + Config.Default.DepotIndex, "-P4User="******"-P4Client=" + Config.Default.P4Client, "-ini:Engine:[LogFiles]:PurgeLogsDays=" + PurgeLogsDays + ",[LogFiles]:MaxLogFilesOnDisk=-1", "-LOGTIMESINCESTART" } ); LaunchProcess.CaptureMessageDelegate CaptureMessageDelegate = null; if (Environment.UserInteractive) { CaptureMessageDelegate = CrashReporterProcessServicer.WriteMDD; } else { MinidumpDiagnosticsParams.AddRange ( new[] { "-buildmachine", "-forcelogflush" } ); // Write some debugging message. CrashReporterProcessServicer.WriteMDD(MinidumpDiagnosticsName + " Params: " + String.Join(" ", MinidumpDiagnosticsParams)); } Task<bool> NewSymbolicatorTask = Task.FromResult(false); Stopwatch WaitSW = Stopwatch.StartNew(); Double WaitForLockTime = 0.0; lock (Tasks) { int TaskIdx = Task.WaitAny(Tasks); Tasks[TaskIdx] = NewSymbolicatorTask = Task<bool>.Factory.StartNew(() => { LaunchProcess ReportParser = new LaunchProcess(MinidumpDiagnosticsName, Path.GetDirectoryName(MinidumpDiagnosticsName), CaptureMessageDelegate, MinidumpDiagnosticsParams.ToArray()); return ReportParser.WaitForExit(Config.Default.MDDTimeoutMinutes*1000*60) == EWaitResult.Ok; }); WaitForLockTime = WaitSW.Elapsed.TotalSeconds; } NewSymbolicatorTask.Wait(); Double TotalMDDTime = WaitSW.Elapsed.TotalSeconds; CrashReporterProcessServicer.WriteEvent(string.Format("PROC-{0} ", ProcessorIndex) + string.Format("Symbolicator.Run: Thread blocked for {0:N1}s then MDD ran for {1:N1}s", WaitForLockTime, TotalMDDTime - WaitForLockTime)); return NewSymbolicatorTask.Result; }