Mpdreamz / shellprogressbar

ShellProgressBar - display progress in your console application
MIT License
1.43k stars 134 forks source link

High Tick Count performance Issues #25

Closed xaruka closed 5 years ago

xaruka commented 5 years ago

When using a high amount for max ticks (i.e. 10k), the ticking itself requires a lot of cpu. The following code requires 40+ seconds on my machine even though its not really doing anything:

var progressBarOptions = new ProgressBarOptions()
{
    ProgressCharacter = '_'
};

using (var pbar = new ProgressBar(10000, "Test", progressBarOptions))
{
    for (var i = 0; i < pbar.MaxTicks; i++)
    {
        pbar.Tick();
    }
}

I didnt do any profiling but I assume its because of the redraw that occurs everytime ProgressBar.Tick() is called.

Since the realtime rendering uses a timer to update the rendering, i think it should be easily possible to implement. Maybe via an additional progress bar option or parameter to the progressbar constructor/tick function to disable redraw on tick - this would either require public access to the DisplayProgress method or it would force the use of the realtime update option.

dlech commented 5 years ago

What OS/.NET runtime are you using? I have found that performance on .NETCoreApp 2.1.2 on Linux x64 is so terrible, that the demo program here only updates about every 3 seconds after it has been running for a while. I've done some profiling and I think that it boils down to the locking used in the System.Console class is really bad and causes lots of spinlock waiting.

In researching this issue, I've noticed that there have been quite a few issues with locks on Linux causing performance issues in the dotnet/coreclr repository.

Maybe a possible solution here is to somehow get all calls to Console.* on a single thread. For example, we could make some kind of simple event loop that uses System.Collections.ConcurrentQueue for events.

dlech commented 5 years ago

It looks like the locking issues were just a problem in .NET Core 2.0 and were pretty much fixed in 2.1. There are still System.Console performance issue on .NET Core 2.1 unix platforms, but that is not really relevant to this issue.

Anyway, I've made a PR that addresses this issue.

dlech commented 5 years ago

FYI, there is a nuget package for testing here: https://github.com/dlech/shellprogressbar/releases/tag/4.0.1-dlech1

Nihlus commented 5 years ago

@dlech Have you considered uploading that package as an alternative on NuGet or MyGet? The official package suffers from a lot of issues that you have resolved.

dlech commented 5 years ago

I would like to give @Mpdreamz a chance to merge and release my changes before I go forking the project. If there still is no response in a few more weeks, I might consider it.

Mpdreamz commented 5 years ago

Will have a look tomorrow @dlech :+1:

Mpdreamz commented 5 years ago

There is an option to not use the timer at all as well see DisplayTimeInRealTime = false

https://github.com/Mpdreamz/shellprogressbar/blob/master/src/ShellProgressBar/ProgressBarOptions.cs#L29-L34

This works well especially if you have a high and frequently updating tick count.

Nihlus commented 5 years ago

Super, thanks both of you :D