Minor R2RDump facelift w.r.t. diffing dump (#2184)
authorTomáš Rylek <trylek@microsoft.com>
Mon, 27 Jan 2020 13:04:51 +0000 (14:04 +0100)
committerGitHub <noreply@github.com>
Mon, 27 Jan 2020 13:04:51 +0000 (14:04 +0100)
Based on offline chat with JanV I added initial provisions to simplify
diffing Crossgen1- and 2-compiled SPC. In essence, the --diff option
newly ends up emitting two extra files with the ".r2rdump" extension
representing the methods common to the left and right R2R file. This
is formerly untrodden territory, I'm pioneering R2RDump usability for
this purpose.

Thanks

Tomas

src/coreclr/src/tools/r2rdump/R2RDiff.cs
src/coreclr/src/tools/r2rdump/R2RDump.cs

index 8f0e871..60b9c0e 100644 (file)
@@ -18,30 +18,30 @@ namespace R2RDump
     class R2RDiff
     {
         /// <summary>
-        /// Left R2R image for the diff.
+        /// Left dumper to use for the diff
         /// </summary>
-        private readonly ReadyToRunReader _leftFile;
+        private readonly Dumper _leftDumper;
 
         /// <summary>
-        /// Right R2R image for the diff.
+        /// Right dumper to use for the diff
         /// </summary>
-        private readonly ReadyToRunReader _rightFile;
+        private readonly Dumper _rightDumper;
 
         /// <summary>
-        /// Text writer to receive diff output.
+        /// Text writer to use for common output
         /// </summary>
         private readonly TextWriter _writer;
 
         /// <summary>
         /// Store the left and right file and output writer.
         /// </summary>
-        /// <param name="leftFile">Left R2R file</param>
-        /// <param name="rightFile">Right R2R file</param>
-        /// <param name="writer">Output writer to receive the diff</param>
-        public R2RDiff(ReadyToRunReader leftFile, ReadyToRunReader rightFile, TextWriter writer)
+        /// <param name="leftDumper">Dumper to use for the left diff output</param>
+        /// <param name="rightDumper">Dumper to use for the right diff output</param>
+        /// <param name="writer">Writer to use for output common to left / right side</param>
+        public R2RDiff(Dumper leftDumper, Dumper rightDumper, TextWriter writer)
         {
-            _leftFile = leftFile;
-            _rightFile = rightFile;
+            _leftDumper = leftDumper;
+            _rightDumper = rightDumper;
             _writer = writer;
         }
 
@@ -54,6 +54,11 @@ namespace R2RDump
             DiffPESections();
             DiffR2RSections();
             DiffR2RMethods();
+
+            HashSet<string> commonMethods = new HashSet<string>(_leftDumper.Reader.Methods.Select(method => method.SignatureString)
+                .Intersect(_rightDumper.Reader.Methods.Select(method => method.SignatureString)));
+            DumpCommonMethods(_leftDumper, commonMethods);
+            DumpCommonMethods(_rightDumper, commonMethods);
         }
 
         /// <summary>
@@ -61,8 +66,8 @@ namespace R2RDump
         /// </summary>
         private void DiffTitle()
         {
-            _writer.WriteLine($@"Left file:  {_leftFile.Filename} ({_leftFile.Image.Length} B)");
-            _writer.WriteLine($@"Right file: {_rightFile.Filename} ({_rightFile.Image.Length} B)");
+            _writer.WriteLine($@"Left file:  {_leftDumper.Reader.Filename} ({_leftDumper.Reader.Image.Length} B)");
+            _writer.WriteLine($@"Right file: {_rightDumper.Reader.Filename} ({_rightDumper.Reader.Image.Length} B)");
             _writer.WriteLine();
         }
 
@@ -71,7 +76,7 @@ namespace R2RDump
         /// </summary>
         private void DiffPESections()
         {
-            ShowDiff(GetPESectionMap(_leftFile), GetPESectionMap(_rightFile), "PE sections");
+            ShowDiff(GetPESectionMap(_leftDumper.Reader), GetPESectionMap(_rightDumper.Reader), "PE sections");
         }
 
         /// <summary>
@@ -79,7 +84,7 @@ namespace R2RDump
         /// </summary>
         private void DiffR2RSections()
         {
-            ShowDiff(GetR2RSectionMap(_leftFile), GetR2RSectionMap(_rightFile), "R2R sections");
+            ShowDiff(GetR2RSectionMap(_leftDumper.Reader), GetR2RSectionMap(_rightDumper.Reader), "R2R sections");
         }
 
         /// <summary>
@@ -87,7 +92,7 @@ namespace R2RDump
         /// </summary>
         private void DiffR2RMethods()
         {
-            ShowDiff(GetR2RMethodMap(_leftFile), GetR2RMethodMap(_rightFile), "R2R methods");
+            ShowDiff(GetR2RMethodMap(_leftDumper.Reader), GetR2RMethodMap(_rightDumper.Reader), "R2R methods");
         }
 
         /// <summary>
@@ -204,5 +209,24 @@ namespace R2RDump
 
             return methodMap;
         }
+
+        /// <summary>
+        /// Dump the subset of methods common to both sides of the diff to the given dumper.
+        /// </summary>
+        /// <param name="dumper">Output dumper to use</param>
+        /// <param name="signatureFilter">Set of common signatures of methods to dump</param>
+        private void DumpCommonMethods(Dumper dumper, HashSet<string> signatureFilter)
+        {
+            IEnumerable<ReadyToRunMethod> filteredMethods = dumper
+                .Reader
+                .Methods
+                .Where(method => signatureFilter.Contains(method.SignatureString))
+                .OrderBy(method => method.SignatureString);
+
+            foreach (ReadyToRunMethod method in filteredMethods)
+            {
+                dumper.DumpMethod(method);
+            }
+        }
     }
 }
index 5c52b52..dc9e910 100644 (file)
@@ -161,13 +161,19 @@ namespace R2RDump
         abstract internal void DumpBytes(int rva, uint size, string name = "Raw", bool convertToOffset = true);
         abstract internal void DumpSectionContents(ReadyToRunSection section);
         abstract internal void DumpQueryCount(string q, string title, int count);
+
+        public TextWriter Writer => _writer;
+
+        public DumpOptions Options => _options;
+
+        public ReadyToRunReader Reader => _r2r;
     }
 
     class R2RDump
     {
         private readonly DumpOptions _options;
-        private readonly TextWriter _writer;
         private readonly Dictionary<ReadyToRunSection.SectionType, bool> _selectedSections = new Dictionary<ReadyToRunSection.SectionType, bool>();
+        private TextWriter _writer;
         private Dumper _dumper;
 
         private R2RDump(DumpOptions options)
@@ -181,16 +187,6 @@ namespace R2RDump
                 _options.GC = true;
                 _options.SectionContents = true;
             }
-
-            // open output stream
-            if (_options.Out != null)
-            {
-                _writer = new StreamWriter(_options.Out.FullName, append: false, encoding: Encoding.ASCII);
-            }
-            else
-            {
-                _writer = Console.Out;
-            }
         }
 
         private static int ArgStringToInt(string arg)
@@ -478,7 +474,12 @@ namespace R2RDump
                     throw new ArgumentException("The option '--naked' is incompatible with '--raw'");
                 }
 
-                ReadyToRunReader previousReader = null;
+                Dumper previousDumper = null;
+                TextWriter globalWriter = null;
+                if (_options.Out != null)
+                {
+                    globalWriter = new StreamWriter(_options.Out.FullName);
+                }
 
                 foreach (FileInfo filename in _options.In)
                 {
@@ -497,6 +498,15 @@ namespace R2RDump
                         }
                     }
 
+                    if (!_options.Diff && globalWriter != null)
+                    {
+                        _writer = globalWriter;
+                    }
+                    else
+                    {
+                        string outFile = r2r.Filename + ".r2rdump";
+                        _writer = new StreamWriter(outFile, append: false, encoding: Encoding.ASCII);
+                    }
                     _dumper = new TextDumper(r2r, _writer, disassembler, _options);
 
                     if (!_options.Diff)
@@ -504,12 +514,12 @@ namespace R2RDump
                         // output the ReadyToRun info
                         Dump(r2r);
                     }
-                    else if (previousReader != null)
+                    else if (previousDumper != null)
                     {
-                        new R2RDiff(previousReader, r2r, _writer).Run();
+                        new R2RDiff(previousDumper, _dumper, globalWriter).Run();
                     }
 
-                    previousReader = r2r;
+                    previousDumper = _dumper;
                 }
             }
             catch (Exception e)