diff --git a/src/PerfView/OtherSources/Linux/LinuxPerfScriptEventParser.cs b/src/PerfView/OtherSources/Linux/LinuxPerfScriptEventParser.cs index 1bdf1aa..484d43a 100644 --- a/src/PerfView/OtherSources/Linux/LinuxPerfScriptEventParser.cs +++ b/src/PerfView/OtherSources/Linux/LinuxPerfScriptEventParser.cs @@ -114,7 +114,7 @@ namespace Diagnostics.Tracing.StackSources /// public void SetSymbolFile(string path) { - this.SetSymbolFile(new ZipArchive(new FileStream(path, FileMode.Open))); + this.SetSymbolFile(ZipFile.OpenRead(path)); } /// diff --git a/src/PerfView/OtherSources/Linux/LinuxPerfScriptStackSource.cs b/src/PerfView/OtherSources/Linux/LinuxPerfScriptStackSource.cs index 433bd46..13ed21f 100644 --- a/src/PerfView/OtherSources/Linux/LinuxPerfScriptStackSource.cs +++ b/src/PerfView/OtherSources/Linux/LinuxPerfScriptStackSource.cs @@ -396,7 +396,7 @@ namespace Diagnostics.Tracing.StackSources archive = null; if (path.EndsWith(".zip")) { - archive = new ZipArchive(new FileStream(path, FileMode.Open)); + archive = ZipFile.OpenRead(path); ZipArchiveEntry foundEntry = null; foreach (ZipArchiveEntry entry in archive.Entries) diff --git a/src/PerfView/PerfViewData.cs b/src/PerfView/PerfViewData.cs index aa5be02..ee1180e 100644 --- a/src/PerfView/PerfViewData.cs +++ b/src/PerfView/PerfViewData.cs @@ -4594,7 +4594,7 @@ namespace PerfView allocName = "Alloc >= 32768"; return allocName; } -#endregion + #endregion protected internal override void ConfigureStackWindow(string stackSourceName, StackWindow stackWindow) { @@ -5177,7 +5177,7 @@ namespace PerfView } public override ImageSource Icon { get { return GuiApp.MainWindow.Resources["FileBitmapImage"] as ImageSource; } } -#region private + #region private /// /// See if the log has events from VS providers. If so we should register the VS providers. /// @@ -5261,7 +5261,7 @@ namespace PerfView bool m_notifiedAboutLostEvents; bool m_notifiedAboutWin8; string m_extraTopStats; -#endregion + #endregion } class WTPerfViewFile : PerfViewFile @@ -5403,7 +5403,7 @@ namespace PerfView stackWindow.CallTreeTab.IsSelected = true; } -#region private + #region private [Flags] enum PageProtection { @@ -5471,7 +5471,7 @@ namespace PerfView return string.Format("", Details, Address, Size); } -#region private + #region private private void Insert(MemoryNode newNode) { @@ -5519,7 +5519,7 @@ namespace PerfView ulong.TryParse(attrValue, out ret); return ret; } -#endregion + #endregion } class VMMapStackSource : InternStackSource @@ -5623,7 +5623,7 @@ namespace PerfView StackSourceSample m_sample; } -#endregion + #endregion } class PdbScopePerfViewFile : PerfViewFile @@ -5825,7 +5825,7 @@ namespace PerfView } } -#region private + #region private protected internal void OpenDump(TextWriter log) { @@ -5973,7 +5973,7 @@ namespace PerfView internal protected GCHeapDump m_gcDump; string m_extraTopStats; -#endregion + #endregion } public partial class LinuxPerfViewData : PerfViewFile @@ -6060,10 +6060,10 @@ namespace PerfView advanced.AddChild(new PerfViewJitStats(this)); } - if(memory.Children.Count > 0) + if (memory.Children.Count > 0) m_Children.Add(memory); - if(advanced.Children.Count > 0) + if (advanced.Children.Count > 0) m_Children.Add(advanced); return null; @@ -6096,6 +6096,9 @@ namespace PerfView m_traceLog.Dispose(); m_traceLog = null; } + else if (m_noTraceLogInfo) + return null; + var dataFileName = FilePath; var options = new TraceLogOptions(); options.ConversionLog = log; @@ -6107,59 +6110,35 @@ namespace PerfView options.LocalSymbolsOnly = false; options.ShouldResolveSymbols = delegate (string moduleFilePath) { return false; }; // Don't resolve any symbols - // But if there is a directory called EtwManifests exists, look in there instead. - //var etwManifestDirPath = Path.Combine(Path.GetDirectoryName(dataFileName), "EtwManifests"); - //if (Directory.Exists(etwManifestDirPath)) - //options.ExplicitManifestDir = etwManifestDirPath; - - //UnZipIfNecessary(ref dataFileName, log); - - // If the etlx file exists, delete it so we can regenerate it. - // Generate the etlx file path / name. - string etlxFile = dataFileName + ".etlx"; - if (File.Exists(etlxFile)) + string etlxFile = CacheFiles.FindFile(dataFileName, ".etlx"); + if (!File.Exists(etlxFile) || File.GetLastWriteTimeUtc(etlxFile) < File.GetLastWriteTimeUtc(dataFileName)) { FileUtilities.ForceDelete(etlxFile); - } - - log.WriteLine("Creating ETLX file {0} from {1}", etlxFile, dataFileName); - - try - { - TraceLog.CreateFromLttngTextDataFile(dataFileName, etlxFile, options); - } - catch (Exception ex) - { - log.WriteLine("Exception encountered when building the tracelog."); - log.WriteLine(ex.ToString()); - m_traceLog = null; - return m_traceLog; + log.WriteLine("Creating ETLX file {0} from {1}", etlxFile, dataFileName); + try + { + TraceLog.CreateFromLttngTextDataFile(dataFileName, etlxFile, options); + } + catch (EndOfStreamException) // Throws this if there is no CTF Information + { + log.WriteLine("Trying to open CTF stream failed, no CTF information"); + Debug.Assert(m_traceLog == null); + m_noTraceLogInfo = true; + return m_traceLog; + } } var dataFileSize = "Unknown"; if (File.Exists(dataFileName)) dataFileSize = ((new System.IO.FileInfo(dataFileName)).Length / 1000000.0).ToString("n3") + " MB"; - log.WriteLine("ETL Size {0} ETLX Size {1:n3} MB", dataFileSize, (new System.IO.FileInfo(etlxFile)).Length / 1000000.0); - try - { - m_traceLog = new TraceLog(etlxFile); - - // Add some more parser that we would like. - //new ETWClrProfilerTraceEventParser(m_traceLog); - //new MicrosoftWindowsNDISPacketCaptureTraceEventParser(m_traceLog); - } - catch (Exception) - { - throw; - } - + // Open the ETLX file. + m_traceLog = new TraceLog(etlxFile); m_utcLastWriteAtOpen = File.GetLastWriteTimeUtc(FilePath); if (App.CommandLineArgs.UnsafePDBMatch) m_traceLog.CodeAddresses.UnsafePDBMatching = true; - if (m_traceLog.Truncated) // Warn about truncation. { GuiApp.MainWindow.Dispatcher.BeginInvoke((Action)delegate () @@ -6170,9 +6149,10 @@ namespace PerfView return m_traceLog; } -#region Private + #region Private TraceLog m_traceLog; -#endregion + bool m_noTraceLogInfo; + #endregion } /// @@ -6407,7 +6387,7 @@ namespace PerfView ConfigureAsEtwStackWindow(stackWindow, false, false); } -#region private + #region private /// /// Search for scenario data files matching a pattern, and add them to a dictionary. @@ -6549,7 +6529,7 @@ namespace PerfView return pathDict; } -#endregion + #endregion } /// diff --git a/src/PerfView/Properties/AssemblyInfo.cs b/src/PerfView/Properties/AssemblyInfo.cs index c506da6..a662871 100644 --- a/src/PerfView/Properties/AssemblyInfo.cs +++ b/src/PerfView/Properties/AssemblyInfo.cs @@ -52,5 +52,5 @@ using System.Windows; // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.9.17.0")] +[assembly: AssemblyFileVersion("1.9.18.0")] [assembly: InternalsVisibleTo("PerfViewTests")] \ No newline at end of file diff --git a/src/PerfView/SupportDlls/UsersGuide.htm b/src/PerfView/SupportDlls/UsersGuide.htm index a351a59..89eac64 100644 --- a/src/PerfView/SupportDlls/UsersGuide.htm +++ b/src/PerfView/SupportDlls/UsersGuide.htm @@ -8051,6 +8051,13 @@ -->
  • + Version 1.9.18 6/15/16 +
      +
    • + Fixed issue where .Trace.ZIP files without Lttng information would fail when viewing the CPU stacks with a file in use error. +
    • +
    +
  • Version 1.9.17 6/14/16
    • Fixes issue with out of memory when taking a .GCDump from a very large process dump. Improved the out of diff --git a/src/TraceEvent/CtfTraceEventSource.cs b/src/TraceEvent/CtfTraceEventSource.cs index e664209..1c7be68 100644 --- a/src/TraceEvent/CtfTraceEventSource.cs +++ b/src/TraceEvent/CtfTraceEventSource.cs @@ -45,52 +45,65 @@ namespace Microsoft.Diagnostics.Tracing { _filename = fileName; _zip = ZipFile.Open(fileName, ZipArchiveMode.Read); - - _channels = new List>(); - foreach (ZipArchiveEntry metadataArchive in _zip.Entries.Where(p => Path.GetFileName(p.FullName) == "metadata")) + bool success = false; + try { - CtfMetadataLegacyParser parser = new CtfMetadataLegacyParser(metadataArchive.Open()); - CtfMetadata metadata = new CtfMetadata(parser); - string path = Path.GetDirectoryName(metadataArchive.FullName); - _channels.AddRange(from entry in _zip.Entries - where Path.GetDirectoryName(entry.FullName) == path && Path.GetFileName(entry.FullName).StartsWith("channel") - select new Tuple(entry, metadata)); + _channels = new List>(); + foreach (ZipArchiveEntry metadataArchive in _zip.Entries.Where(p => Path.GetFileName(p.FullName) == "metadata")) + { + CtfMetadataLegacyParser parser = new CtfMetadataLegacyParser(metadataArchive.Open()); + CtfMetadata metadata = new CtfMetadata(parser); - pointerSize = Path.GetDirectoryName(metadataArchive.FullName).EndsWith("64-bit") ? 8 : 4; - } + string path = Path.GetDirectoryName(metadataArchive.FullName); + _channels.AddRange(from entry in _zip.Entries + where Path.GetDirectoryName(entry.FullName) == path && Path.GetFileName(entry.FullName).StartsWith("channel") + select new Tuple(entry, metadata)); + + pointerSize = Path.GetDirectoryName(metadataArchive.FullName).EndsWith("64-bit") ? 8 : 4; + } - IntPtr mem = Marshal.AllocHGlobal(sizeof(TraceEventNativeMethods.EVENT_RECORD)); - TraceEventNativeMethods.ZeroMemory(mem, sizeof(TraceEventNativeMethods.EVENT_RECORD)); - _header = (TraceEventNativeMethods.EVENT_RECORD*)mem; + IntPtr mem = Marshal.AllocHGlobal(sizeof(TraceEventNativeMethods.EVENT_RECORD)); + TraceEventNativeMethods.ZeroMemory(mem, sizeof(TraceEventNativeMethods.EVENT_RECORD)); + _header = (TraceEventNativeMethods.EVENT_RECORD*)mem; - int processors = (from entry in _channels - let filename = entry.Item1.FullName - let i = filename.LastIndexOf('_') - let processor = filename.Substring(i + 1) - select int.Parse(processor) - ).Max() + 1; + int processors = (from entry in _channels + let filename = entry.Item1.FullName + let i = filename.LastIndexOf('_') + let processor = filename.Substring(i + 1) + select int.Parse(processor) + ).Max() + 1; - numberOfProcessors = processors; + numberOfProcessors = processors; - // TODO: Need to cleanly separate clocks, but in practice there's only the one clock. - CtfClock clock = _channels.First().Item2.Clocks.First(); + // TODO: Need to cleanly separate clocks, but in practice there's only the one clock. + CtfClock clock = _channels.First().Item2.Clocks.First(); - long firstEventTimestamp = (long)new ChannelList(_channels).First().Current.Timestamp; + var channels = new ChannelList(_channels); + if (channels.Count() == 0) + throw new EndOfStreamException("No CTF Information found in ZIP file."); - _QPCFreq = (long)clock.Frequency; - sessionStartTimeQPC = firstEventTimestamp; - _syncTimeQPC = firstEventTimestamp; - _syncTimeUTC = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddSeconds((clock.Offset - 1) / clock.Frequency); + long firstEventTimestamp = (long)channels.First().Current.Timestamp; - _eventMapping = InitEventMap(); + _QPCFreq = (long)clock.Frequency; + sessionStartTimeQPC = firstEventTimestamp; + _syncTimeQPC = firstEventTimestamp; + _syncTimeUTC = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc).AddSeconds((clock.Offset - 1) / clock.Frequency); + _eventMapping = InitEventMap(); + success = true; #if DEBUG //// Uncomment for debug output. //_debugOut = File.CreateText("debug.txt"); //_debugOut.AutoFlush = true; #endif + } + finally + { + if (!success) + Dispose(); // This closes the ZIP file we opened. We don't want to leave it dangling. + } } private static Dictionary InitEventMap() @@ -577,7 +590,13 @@ namespace Microsoft.Diagnostics.Tracing protected override void Dispose(bool disposing) { if (disposing) - _zip.Dispose(); + { + if (_zip != null) + { + _zip.Dispose(); + _zip = null; + } + } // TODO //Marshal.FreeHGlobal(new IntPtr(_header));