Skip to content

Implement Project Parallelism in IlSpyCmd (Stacked PR #5)#3

Open
petercrabtree wants to merge 6 commits into
feature/multithread-ilspycmd-prepfrom
feature/multithread-ilspycmd
Open

Implement Project Parallelism in IlSpyCmd (Stacked PR #5)#3
petercrabtree wants to merge 6 commits into
feature/multithread-ilspycmd-prepfrom
feature/multithread-ilspycmd

Conversation

@petercrabtree
Copy link
Copy Markdown
Owner

@petercrabtree petercrabtree commented Jul 6, 2025

No description provided.

This comment was marked as outdated.

@petercrabtree petercrabtree marked this pull request as ready for review July 6, 2025 23:00
Copilot AI review requested due to automatic review settings July 6, 2025 23:00

This comment was marked as outdated.

@christophwille
Copy link
Copy Markdown

Given the big file changes - crlf issues or other reformatting going on?

Comment thread Directory.Packages.props
<PackageVersion Include="NuGet.Protocol" Version="6.13.2" />
<PackageVersion Include="PowerShellStandard.Library" Version="5.1.1" />
<PackageVersion Include="Shouldly" Version="4.3.0" />
<PackageVersion Include="Spectre.Console" Version="0.49.1" />
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added, thanks for catching that.

@petercrabtree petercrabtree force-pushed the feature/multithread-ilspycmd branch 5 times, most recently from c12d851 to bf0b7cb Compare August 25, 2025 01:46
@petercrabtree petercrabtree changed the base branch from dev/dev-env-clean to dev/dev-env-clean-no-bom August 25, 2025 02:00
@petercrabtree petercrabtree force-pushed the feature/multithread-ilspycmd branch from bf0b7cb to 51a789f Compare August 25, 2025 03:40
@petercrabtree petercrabtree force-pushed the dev/dev-env-clean-no-bom branch 2 times, most recently from 55ae0eb to 750b402 Compare August 25, 2025 03:48
@petercrabtree petercrabtree force-pushed the feature/multithread-ilspycmd branch 2 times, most recently from a735af4 to a777ed3 Compare August 26, 2025 01:56
@petercrabtree petercrabtree force-pushed the dev/dev-env-clean-no-bom branch from 750b402 to d0d159e Compare August 26, 2025 01:56
@petercrabtree petercrabtree force-pushed the feature/multithread-ilspycmd branch from a777ed3 to 0e8a76a Compare August 26, 2025 03:12
@petercrabtree petercrabtree force-pushed the dev/dev-env-clean-no-bom branch from d0d159e to 610123b Compare August 26, 2025 03:12
@petercrabtree petercrabtree force-pushed the feature/multithread-ilspycmd branch from 0e8a76a to 4128336 Compare August 26, 2025 04:34
@petercrabtree petercrabtree force-pushed the dev/dev-env-clean-no-bom branch from 610123b to 6d984e9 Compare August 26, 2025 04:34
@petercrabtree petercrabtree force-pushed the feature/multithread-ilspycmd branch 2 times, most recently from f9c7b73 to e93d99d Compare August 26, 2025 20:16
@petercrabtree petercrabtree force-pushed the dev/dev-env-clean-no-bom branch from 6d984e9 to aebe02a Compare August 26, 2025 20:16
@petercrabtree petercrabtree changed the title refactor: Cleanup and modernize IlspyCmd code refactor: Cleanup and modernize IlspyCmd code (Stacked PR #4) Aug 26, 2025
@petercrabtree petercrabtree changed the title refactor: Cleanup and modernize IlspyCmd code (Stacked PR #4) Implement Project Parallelism in IlSpyCmd (Stacked PR #5) Aug 26, 2025
@petercrabtree petercrabtree changed the base branch from dev/dev-env-clean-no-bom to feature/multithread-ilspycmd-prep August 26, 2025 20:20
@petercrabtree petercrabtree requested a review from Copilot August 26, 2025 20:23
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR implements project parallelism in IlSpyCmd, enabling concurrent decompilation of multiple assemblies with progress tracking and enhanced user experience.

  • Adds parallel processing support for decompiling multiple assemblies into a solution using configurable job limits
  • Integrates Spectre.Console for rich progress visualization with individual task tracking and overall progress indication
  • Improves performance through concurrent execution and optimized garbage collection settings

Reviewed Changes

Copilot reviewed 7 out of 16 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
doc/third-party-notices.txt Adds MIT license notice for Spectre.Console dependency
ILSpy.sln.DotSettings Updates ReSharper settings with migration flags
ICSharpCode.ILSpyCmd/packages.lock.json Locks new package versions for Spectre.Console and System.Threading.Channels
ICSharpCode.ILSpyCmd/IlspyCmdProgram.cs Main implementation of parallel decompilation with progress tracking
ICSharpCode.ILSpyCmd/ICSharpCode.ILSpyCmd.csproj Adds package references and enables server GC with adaptation mode
ICSharpCode.Decompiler/Solution/SolutionCreator.cs Adds exception handling around project reference fixing
Directory.Packages.props Defines package versions for new dependencies

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.


Decompile multiple assemblies into a single solution, using all available cores.
ilspycmd -p -o c:\decompiled -j 0 sample.dll sample2.dll sample3.dll sample4.dll
(or with max of 4 parallel jobs)
Copy link

Copilot AI Aug 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The indentation uses tabs instead of spaces, which is inconsistent with the rest of the codebase that uses spaces.

Suggested change
(or with max of 4 parallel jobs)
(or with max of 4 parallel jobs)

Copilot uses AI. Check for mistakes.
Comment on lines +590 to +591
double? _fractionDoneNow = value.TotalUnits == 0 ? null : (double)value.UnitsCompleted / value.TotalUnits;
var fractionDoneNow = _fractionDoneNow.Value;
Copy link

Copilot AI Aug 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Accessing .Value on a nullable double without null checking will throw an exception when value.TotalUnits == 0. The variable should be checked for null before accessing its value.

Suggested change
double? _fractionDoneNow = value.TotalUnits == 0 ? null : (double)value.UnitsCompleted / value.TotalUnits;
var fractionDoneNow = _fractionDoneNow.Value;
double fractionDoneNow = (double)value.UnitsCompleted / value.TotalUnits;

Copilot uses AI. Check for mistakes.
Comment on lines +645 to +650
static async ValueTask DecompileProjectAsync(
(string name, ProgressTask task, DecompilerSettings settings, string[] referencePaths, (bool IsSet, string Value) inputPDBFile, ConcurrentBag<ProjectItem> projects, string outputDirectory, ProgressTask projectTrackingTask) projectContext,
CancellationToken token,
IProgress<DecompilationProgress> progress)
{
var (file, progressTask, settings, referencePaths, inputPDBFile, projects, outputDirectory, projectTrackingTask) = projectContext;
Copy link

Copilot AI Aug 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tuple parameter with 8 elements is difficult to read and maintain. Consider creating a dedicated struct or class to encapsulate these parameters.

Suggested change
static async ValueTask DecompileProjectAsync(
(string name, ProgressTask task, DecompilerSettings settings, string[] referencePaths, (bool IsSet, string Value) inputPDBFile, ConcurrentBag<ProjectItem> projects, string outputDirectory, ProgressTask projectTrackingTask) projectContext,
CancellationToken token,
IProgress<DecompilationProgress> progress)
{
var (file, progressTask, settings, referencePaths, inputPDBFile, projects, outputDirectory, projectTrackingTask) = projectContext;
class ProjectContext
{
public string Name { get; }
public ProgressTask Task { get; }
public DecompilerSettings Settings { get; }
public string[] ReferencePaths { get; }
public (bool IsSet, string Value) InputPDBFile { get; }
public ConcurrentBag<ProjectItem> Projects { get; }
public string OutputDirectory { get; }
public ProgressTask ProjectTrackingTask { get; }
public ProjectContext(
string name,
ProgressTask task,
DecompilerSettings settings,
string[] referencePaths,
(bool IsSet, string Value) inputPDBFile,
ConcurrentBag<ProjectItem> projects,
string outputDirectory,
ProgressTask projectTrackingTask)
{
Name = name;
Task = task;
Settings = settings;
ReferencePaths = referencePaths;
InputPDBFile = inputPDBFile;
Projects = projects;
OutputDirectory = outputDirectory;
ProjectTrackingTask = projectTrackingTask;
}
}
static async ValueTask DecompileProjectAsync(
ProjectContext projectContext,
CancellationToken token,
IProgress<DecompilationProgress> progress)
{
var file = projectContext.Name;
var progressTask = projectContext.Task;
var settings = projectContext.Settings;
var referencePaths = projectContext.ReferencePaths;
var inputPDBFile = projectContext.InputPDBFile;
var projects = projectContext.Projects;
var outputDirectory = projectContext.OutputDirectory;
var projectTrackingTask = projectContext.ProjectTrackingTask;

Copilot uses AI. Check for mistakes.
projectId.Guid,
projectId.TypeGuid));

progressTask.StopTask(); // remove from the progress display
Copy link

Copilot AI Aug 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The progress task is stopped twice - once at line 629 after the parallel loop and again here at line 675. This could cause issues with the progress display.

Suggested change
progressTask.StopTask(); // remove from the progress display
// progressTask.StopTask(); // removed: already stopped after the parallel loop

Copilot uses AI. Check for mistakes.
@petercrabtree
Copy link
Copy Markdown
Owner Author

Given the big file changes - crlf issues or other reformatting going on?

Yes, this happens to be one of the roughest parts of using jj for source control, no autocrlf. Apologies for the long delay getting it fixed. You should be able to effectively see the actual changes now. @christophwille

@petercrabtree
Copy link
Copy Markdown
Owner Author

Note that this code is still somewhat rough (e.g. the review comments from copilot); I'm putting it here to give y'all an early peek, and to ensure it'll display correctly when I open a PR upstream.

@petercrabtree petercrabtree force-pushed the feature/multithread-ilspycmd-prep branch from b091a3f to 7f9cc0b Compare August 26, 2025 21:04
@petercrabtree petercrabtree force-pushed the feature/multithread-ilspycmd branch from e93d99d to 6507523 Compare August 26, 2025 21:04
@petercrabtree petercrabtree force-pushed the feature/multithread-ilspycmd-prep branch from 7f9cc0b to dca1a8b Compare August 26, 2025 21:10
@petercrabtree petercrabtree force-pushed the feature/multithread-ilspycmd branch 2 times, most recently from 8add1e2 to 3feb86b Compare August 26, 2025 21:24
@petercrabtree petercrabtree force-pushed the feature/multithread-ilspycmd-prep branch 2 times, most recently from 07922a9 to 1b2f04a Compare August 27, 2025 02:49
@petercrabtree petercrabtree force-pushed the feature/multithread-ilspycmd branch from 3feb86b to 0d4a5c9 Compare August 27, 2025 02:49
@petercrabtree petercrabtree force-pushed the feature/multithread-ilspycmd-prep branch from 1b2f04a to cf305a6 Compare August 29, 2025 00:09
@petercrabtree petercrabtree force-pushed the feature/multithread-ilspycmd branch 2 times, most recently from f4b15c1 to 2251205 Compare August 29, 2025 00:50
@petercrabtree petercrabtree force-pushed the feature/multithread-ilspycmd-prep branch from cf305a6 to 137f93e Compare August 29, 2025 00:50
petercrabtree and others added 6 commits August 28, 2025 20:56
Adds -j/--jobs option to control maximum degree of parallelism for project decompilation.
Uses Parallel.ForEach with ConcurrentBag to decompile multiple assemblies concurrently.
Defaults to single-threaded but allows 0 for Environment.ProcessorCount.
Adds Spectre.Console progress bars for visual feedback during solution decompilation.
Changes DecompileAsSolution to async DecompileAsSolutionAsync with progress tracking.
Adds better error handling with try/catch blocks in SolutionCreator.

style: Fix whitespace formatting

Adjusts indentation to follow consistent code style guidelines.
Enhances progress tracking by passing IProgress<DecompilationProgress> to individual project
decompilation operations, providing more granular feedback (progress on a project, not just overall progress).
Refines progress reporting in ILSpyCmd to provide more accurate and thread-safe updates:
- Add locking around progress callbacks to ensure thread safety
- Only increase overall progress (never decrease) to handle out-of-order callbacks
- Remove redundant progress increments and improve numerical stability
- Set ProgressIndicator on decompiler instead of passing as parameter
- Add elapsed time to ILSpyCmd progress Display
- Add progress reporting to solution creation
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@petercrabtree petercrabtree force-pushed the feature/multithread-ilspycmd branch from 2251205 to 1ae7be9 Compare August 29, 2025 00:59
@petercrabtree petercrabtree force-pushed the feature/multithread-ilspycmd-prep branch from 137f93e to 8103b3e Compare August 29, 2025 00:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants