protected IEnumerator <object> SnapshotIOTask() { ActivityIndicator.Item progress = null; IFuture previousSnapshot = null; while (true) { if ((SnapshotLoadQueue.Count <= 0) && (previousSnapshot != null)) { yield return(previousSnapshot); } if (SnapshotLoadQueue.Count <= 0) { SnapshotLoadState.Count = 0; if (progress != null) { progress.Dispose(); progress = null; } } var f = SnapshotLoadQueue.Dequeue(); using (f) yield return(f); var filename = f.Result; if (progress == null) { progress = Activities.AddItem("Loading snapshots"); } using (var fda = new FileDataAdapter( filename, FileMode.Open, FileAccess.Read, FileShare.Read, 1024 * 128 )) { var maximum = SnapshotLoadState.Count + Math.Max(0, SnapshotLoadQueue.Count) + 1; progress.Maximum = maximum; progress.Progress = Math.Min(maximum, SnapshotLoadState.Count); var fBytes = fda.ReadToEnd(); yield return(fBytes); var fText = Future.RunInThread( () => Encoding.ASCII.GetString(fBytes.Result) ); yield return(fText); var text = fText.Result; fBytes = null; fText = null; // Wait for the last snapshot load we triggered to finish if (previousSnapshot != null) { yield return(previousSnapshot); } previousSnapshot = Scheduler.Start( FinishLoadingSnapshot(filename, text), TaskExecutionPolicy.RunAsBackgroundTask ); text = null; } } }
public static IEnumerator <object> FromFile(string filename, IProgressListener progress) { progress.Status = "Loading diff..."; Future <string> fText; // We could stream the lines in from the IO thread while we parse them, but this // part of the load is usually pretty quick even on a regular hard disk, and // loading the whole diff at once eliminates some context switches using (var fda = new FileDataAdapter( filename, FileMode.Open, FileAccess.Read, FileShare.Read, 1024 * 128 )) { var fBytes = fda.ReadToEnd(); yield return(fBytes); fText = Future.RunInThread( () => Encoding.ASCII.GetString(fBytes.Result) ); yield return(fText); } yield return(fText); var lr = new LineReader(fText.Result); LineReader.Line line; progress.Status = "Parsing diff..."; var frames = new List <TracebackFrame>(); var moduleNames = new NameTable(StringComparer.Ordinal); var symbolTypes = new NameTable(StringComparer.Ordinal); var functionNames = new NameTable(StringComparer.Ordinal); var deltas = new List <DeltaInfo>(); var tracebacks = new Dictionary <UInt32, TracebackInfo>(); var regexes = new Regexes(); // Regex.Groups[string] does an inefficient lookup, so we do that lookup once here int groupModule = regexes.DiffModule.GroupNumberFromName("module"); int groupSymbolType = regexes.DiffModule.GroupNumberFromName("symbol_type"); int groupTraceId = regexes.BytesDelta.GroupNumberFromName("trace_id"); int groupType = regexes.BytesDelta.GroupNumberFromName("type"); int groupDeltaBytes = regexes.BytesDelta.GroupNumberFromName("delta_bytes"); int groupNewBytes = regexes.BytesDelta.GroupNumberFromName("new_bytes"); int groupOldBytes = regexes.BytesDelta.GroupNumberFromName("old_bytes"); int groupNewCount = regexes.BytesDelta.GroupNumberFromName("new_count"); int groupOldCount = regexes.CountDelta.GroupNumberFromName("old_count"); int groupCountDelta = regexes.CountDelta.GroupNumberFromName("delta_count"); int groupTracebackModule = regexes.TracebackFrame.GroupNumberFromName("module"); int groupTracebackFunction = regexes.TracebackFrame.GroupNumberFromName("function"); int groupTracebackOffset = regexes.TracebackFrame.GroupNumberFromName("offset"); int groupTracebackOffset2 = regexes.TracebackFrame.GroupNumberFromName("offset2"); int groupTracebackPath = regexes.TracebackFrame.GroupNumberFromName("path"); int groupTracebackLine = regexes.TracebackFrame.GroupNumberFromName("line"); var delay = new Sleep(0.01); int i = 0; while (lr.ReadLine(out line)) { retryFromHere: i += 1; if (i % ProgressInterval == 0) { progress.Maximum = lr.Length; progress.Progress = lr.Position; // Suspend processing for a bit yield return(delay); } Match m; if (regexes.DiffModule.TryMatch(ref line, out m)) { moduleNames.Add(m.Groups[groupModule].Value); } else if (regexes.BytesDelta.TryMatch(ref line, out m)) { var added = (m.Groups[groupType].Value == "+"); var traceId = UInt32.Parse(m.Groups[groupTraceId].Value, NumberStyles.HexNumber); var info = new DeltaInfo { BytesDelta = int.Parse(m.Groups[groupDeltaBytes].Value, NumberStyles.HexNumber) * (added ? 1 : -1), NewBytes = int.Parse(m.Groups[groupNewBytes].Value, NumberStyles.HexNumber), OldBytes = int.Parse(m.Groups[groupOldBytes].Value, NumberStyles.HexNumber), NewCount = int.Parse(m.Groups[groupNewCount].Value, NumberStyles.HexNumber), }; if (lr.ReadLine(out line)) { if (regexes.CountDelta.TryMatch(ref line, out m)) { info.OldCount = int.Parse(m.Groups[groupOldCount].Value, NumberStyles.HexNumber); info.CountDelta = int.Parse(m.Groups[groupCountDelta].Value, NumberStyles.HexNumber) * (added ? 1 : -1); } } bool readingLeadingWhitespace = true, doRetry = false; frames.Clear(); var itemModules = new NameTable(StringComparer.Ordinal); var itemFunctions = new NameTable(StringComparer.Ordinal); while (lr.ReadLine(out line)) { if (line.ToString().Trim().Length == 0) { if (readingLeadingWhitespace) { continue; } else { break; } } else if (regexes.TracebackFrame.TryMatch(ref line, out m)) { readingLeadingWhitespace = false; var moduleName = moduleNames[m.Groups[groupTracebackModule].Value]; itemModules.Add(moduleName); var functionName = functionNames[m.Groups[groupTracebackFunction].Value]; itemFunctions.Add(functionName); var frame = new TracebackFrame { Module = moduleName, Function = functionName, Offset = UInt32.Parse(m.Groups[groupTracebackOffset].Value, NumberStyles.HexNumber) }; if (m.Groups[groupTracebackOffset2].Success) { frame.Offset2 = UInt32.Parse(m.Groups[groupTracebackOffset2].Value, NumberStyles.HexNumber); } if (m.Groups[groupTracebackPath].Success) { frame.SourceFile = m.Groups[groupTracebackPath].Value; } if (m.Groups[groupTracebackLine].Success) { frame.SourceLine = int.Parse(m.Groups[groupTracebackLine].Value); } frames.Add(frame); } else { // We hit the beginning of a new allocation, so make sure it gets parsed doRetry = true; break; } } if (tracebacks.ContainsKey(traceId)) { info.Traceback = tracebacks[traceId]; Program.ErrorList.ReportError("Duplicate traceback for id {0}!", traceId); } else { var frameArray = ImmutableArrayPool <TracebackFrame> .Allocate(frames.Count); frames.CopyTo(frameArray.Array, frameArray.Offset); info.Traceback = tracebacks[traceId] = new TracebackInfo { TraceId = traceId, Frames = frameArray, Modules = itemModules, Functions = itemFunctions }; } deltas.Add(info); if (doRetry) { goto retryFromHere; } } else if (line.StartsWith("//")) { // Comment, ignore it } else if (line.StartsWith("Total increase") || line.StartsWith("Total decrease")) { // Ignore this too } else if (line.StartsWith(" ") && (line.EndsWith(".pdb"))) { // Symbol path for a module, ignore it } else { Program.ErrorList.ReportError("Unrecognized diff content: {0}", line.ToString()); } } var result = new HeapDiff( filename, moduleNames, functionNames, deltas, tracebacks ); yield return(new Result(result)); }
IEnumerator <object> SearchInFiles(SearchQuery search, BlockingQueue <string> filenames, IFuture completionFuture) { var searchedFiles = new HashSet <string>(StringComparer.Ordinal); var buffer = new List <SearchResult>(); var sb = new StringBuilder(); int numFiles = 0; using (Finally.Do(() => { SetSearchResults(buffer); lblStatus.Text = String.Format("{0} result(s) found.", buffer.Count); pbProgress.Style = ProgressBarStyle.Continuous; pbProgress.Value = 0; })) while (filenames.Count > 0 || !completionFuture.Completed) { var f = filenames.Dequeue(); yield return(f); var filename = f.Result as string; if (filename == null) { continue; } if (searchedFiles.Contains(filename)) { continue; } if (PendingSearchQuery != null) { break; } searchedFiles.Add(filename); int lineNumber = 0; var lineBuffer = new LineEntry[3]; var insertResult = (Action)(() => { var item = new SearchResult(); item.Filename = filename; item.LineNumber = lineBuffer[1].LineNumber; sb.Remove(0, sb.Length); for (int i = 0; i < 3; i++) { if (lineBuffer[i].Text != null) { var line = lineBuffer[i].Text; if (line.Length > 512) { line = line.Substring(0, 512); } sb.Append(line); } if (i < 2) { sb.Append("\r\n"); } } item.Context = sb.ToString(); buffer.Add(item); if ((buffer.Count % 250 == 0) || ((buffer.Count < 50) && (buffer.Count % 5 == 1))) { SetSearchResults(buffer); } }); var stepSearch = (Action)(() => { string currentLine = lineBuffer[1].Text; if ((currentLine != null) && search.Regex.IsMatch(currentLine)) { insertResult(); } }); var insertLine = (Action <LineEntry>)((line) => { lineBuffer[0] = lineBuffer[1]; lineBuffer[1] = lineBuffer[2]; lineBuffer[2] = line; stepSearch(); }); numFiles += 1; if (numFiles % 50 == 0) { lblStatus.Text = String.Format("Scanning '{0}'...", filename); if (completionFuture.Completed) { int totalNumFiles = numFiles + filenames.Count; int progress = (numFiles * 1000 / totalNumFiles); if (pbProgress.Value != progress) { pbProgress.Value = progress; } if (pbProgress.Style != ProgressBarStyle.Continuous) { pbProgress.Style = ProgressBarStyle.Continuous; } } } // Opening files is slow over network shares. FileDataAdapter adapter = null; var fAdapter = Future.RunInThread( () => new FileDataAdapter(filename, System.IO.FileMode.Open, System.IO.FileAccess.Read) ); yield return(fAdapter); if (fAdapter.Failed) { continue; } else { adapter = fAdapter.Result; } using (adapter) { var fEncoding = Future.RunInThread( () => DetectEncoding(adapter.BaseStream) ); yield return(fEncoding); Future <string> thisLine = null, nextLine = null; using (var reader = new AsyncTextReader(adapter, fEncoding.Result, SearchBufferSize)) while (true) { thisLine = nextLine; if (thisLine != null) { yield return(thisLine); } nextLine = reader.ReadLine(); if (thisLine == null) { continue; } lineNumber += 1; string line = thisLine.Result; insertLine(new LineEntry { Text = line, LineNumber = lineNumber }); if (line == null) { break; } if (PendingSearchQuery != null) { break; } if (lineNumber % 10000 == 5000) { var newStatus = String.Format("Scanning '{0}'... (line {1})", filename, lineNumber); if (lblStatus.Text != newStatus) { lblStatus.Text = newStatus; } } } } } }