-
-
Notifications
You must be signed in to change notification settings - Fork 500
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adding TransferSpeedColumn configuration to display bits/bytes + binary/decimal prefixes #904
base: main
Are you sure you want to change the base?
Adding TransferSpeedColumn configuration to display bits/bytes + binary/decimal prefixes #904
Conversation
3317902
to
496a971
Compare
@patriksvensson @phil-scott-78 Could I kindly ask for your thoughts and feedback on these changes whenever you have some time to take a look? I'd be more than happy to discuss the changes in further details, and I would be glad to know if there is anything I can do to help get these changes included. Thank you! |
@microsoft-github-policy-service agree |
Hey @tpill90, looks like an interesting, well drafted PR - are you still around to help me get this reviewed/merged? (assuming I might need your help, although perhaps we get lucky with a straight merge...). I assume you'd like this for https://github.com/tpill90/steam-lancache-prefill ? (which looks awesome btw)? Update |
I like this PR @tpill90 and have started reviewing it. Solid code. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Initial review feedback and suggested changes here: tpill90#1
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Brain dump of my review comments below.
I used to dread this kind of thing when contributing @tpill90, but the review is a sign that I feel your contribution is worth spending time on, and getting it over the line.
I'm not 'the boss' and you don't need to silently accept everything I say in this, rather, we are peers, your coding skills are probably superior to mine, and we hash out the details until we are both happy. Truly excellent library code is what we want. Feel free to disagree with anything I say, but provide an explanation when you do, so I can consider the merits.
Your fork/branch is really old, I'd suggest you rebase (as I can't actually compile it - I've been working off a recent main fork with your commits cherry-picked).
Noted your comment about testing TransferSpeedColumn
- I'll need to give it some thought.
public double Bytes { get; } | ||
public double Bits => Bytes * 8; | ||
|
||
public readonly FileSizeBase Base = FileSizeBase.Binary; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should probably default this to Decimal, to maintain backward compatibility with existing users of Spectre.Console (if we feel it should be Binary OOTB, I'll need to discuss this with the other maintainers first)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had to do some more testing to remember why I ended up picking Binary as the default here. Spectre.Console was actually already doing its transfer rates in binary, it was just displaying the incorrect unit.
I did some testing with my 300mbit internet connection, and tested how the transfer rate is being displayed in the nuget version of the library, and compared it against the default of FileSizeBase.Binary
in my PR. Both versions display the transfer rate as "36" which roughly corresponds to the conversion of 300mbit
to 35.7628MiB
. Give or take a little since network connections aren't perfectly flat.
Now if I rerun my PR version using FileSizeBase.Decimal
then I get around 38 MB/s, which matches the conversion of 300mbit
to 37.5MB
. Again, fluctuating network transfers make it a bit off, but its in the correct ballpark.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Really good stuff 👏
I want to check with the other maintainers before we commit this, as whilst you've identified a bug in the current main branch, changing the default to Binary will break any output validation (that relies on the suffix) our existing users may have. Equally, I know the converse is true, ie. a default of Decimal means the suffix remains the same, but the calculated speed will change (although I strongly suspect this is less likely to be a 'breaking change').
Would you be kind enough to offer your opinion @patriksvensson, on the above?
/// <summary> | ||
/// Gets or sets the <see cref="FileSizeBase"/> to use. | ||
/// </summary> | ||
public FileSizeBase Base { get; set; } = FileSizeBase.Binary; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Careful, this needs to align to the same default value hardcoded in FileSize
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note to self - final decision whether to standardise on Binary or Decimal is pending input from the other Spectre.Console maintainers (which has been asked above, in another review comment).
[InlineData(512, 1024, "0.5/1.0 KiB")] | ||
[InlineData(1024, 1024, "1.0 KiB")] | ||
[InlineData(1024 * 512, 5 * 1024 * 1024, "0.5/5.0 MiB")] | ||
[InlineData(5 * 1024 * 1024, 5 * 1024 * 1024, "5.0 MiB")] | ||
public void Should_Return_Correct_Value(double value, double total, string expected) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FileSizeTests
are fantastic - it exercises Decimal/Binary/Bits Y/Bits N combinations. We should have a similar structure for DownloadedColumnTests
I think ie. we need three more test methods (but see my review comment a few lines down for the implication of this).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note to self - better explained the implications further down, here: #904 (comment)
[InlineData(512, 1024, "0.5/1.0 KiB")] | ||
[InlineData(1024, 1024, "1.0 KiB")] | ||
[InlineData(1024 * 512, 5 * 1024 * 1024, "0.5/5.0 MiB")] | ||
[InlineData(5 * 1024 * 1024, 5 * 1024 * 1024, "5.0 MiB")] | ||
public void Should_Return_Correct_Value(double value, double total, string expected) | ||
{ | ||
// Given | ||
var fixture = new ProgressColumnFixture<DownloadedColumn>(value, total); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having the new FileSize
embedded inside the DownloadedColumn.Render
means that we cannot configure the Fixture for Decimal/Binary/Bits Y/Bits N combinations - we need a better way to do this (this same issue will affect Spectre.Console users when they come to use the DownloadedColumn).
I'm wondering if we should create a FileSizeSettings
class, that has the following properties on it (stolen from TransferSpeedColumn):
/// <summary>
/// Gets or sets the <see cref="FileSizeBase"/> to use.
/// </summary>
public FileSizeBase Base { get; set; } = FileSizeBase.Binary;
/// <summary>
/// Gets or sets a value indicating whether or not to display the transfer speed in bits.
/// </summary>
public bool DisplayBits { get; set; }
and somehow FileSizeSettings
can be set on both DownloadedColumn
and TransferSpeedColumn
, both by the Spectre.Console user and also when using ProgressColumnFixture
Other suggestions/ideas welcome.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I'm tracking here. Wouldn't it just be as simple as:
.Columns(new ProgressColumn[]
{
new DownloadedColumn() { Base = FileSizeBase.Decimal },
new TransferSpeedColumn { Base = FileSizeBase.Decimal }
})
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apologies, I didn't explain myself very well. See the following test:
public void Should_Return_Correct_Value(double value, double total, string expected)
{
// Given
var fixture = new ProgressColumnFixture<DownloadedColumn>(value, total);
fixture.Column.Culture = CultureInfo.InvariantCulture;
ProgressColumnFixture
is actually creating the DownloadedColumn
object within it's own constructor, see here:
public T Column { get; }
public ProgressTask Task { get; set; }
public ProgressColumnFixture(double completed, double total)
{
Column = new T(); // <---- HERE
Task = new ProgressTask(1, "Foo", total);
So currently, the unit tests cannot set properties like you suggest here:
new DownloadedColumn() { Base = FileSizeBase.Decimal },
new TransferSpeedColumn { Base = FileSizeBase.Decimal }
I think we need the ability to pass in an already instantiated ProgressColumn
into the ProgressColumnFixture
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see what you're saying now. I just ended up doing them like this, which was already in line with what the original tests were doing with setting the Culture.
var fixture = new ProgressColumnFixture<DownloadedColumn>(value, total);
fixture.Column.Culture = CultureInfo.InvariantCulture;
fixture.Column.Base = FileSizeBase.Binary;
fixture.Column.ShowBits = false;
I could certainly refactor it out to have the column be passed in if needed.
…both bytes/bits, as well as using binary/decimal prefix definitions.
b2da746
to
9181f9b
Compare
There is no rush/pressure @tpill90 with this. Just to say I will be happy to progress the PR as and when you are ready. It won't be one that languishes. In the meantime, be well 👏. |
Hey Frank, I apologize for not getting a chance to look at it yet. I'm going to try to get to it today. Thanks for your help on this |
I'll look at your comments/changes soon @tpill90 👏 |
src/Spectre.Console/Live/Progress/Columns/TransferSpeedColumn.cs
Outdated
Show resolved
Hide resolved
/// <summary> | ||
/// Gets or sets the <see cref="FileSizeBase"/> to use. | ||
/// </summary> | ||
public FileSizeBase Base { get; set; } = FileSizeBase.Binary; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note to self - default value TBD by Spectre.Console maintainers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I vote for Binary
I pushed up another commit which should take care of the latest comments you've left on the review @FrankRay78 . A follow up question, what documentation should I be updating with this PR? I'll gladly update it, I just was waiting for things to get closer to being merged before going through all of it 😄 |
I've been thinking about documentation. Strictly speaking, the xml comments on things like the ShowBits property will end up in the auto generated API reference, however I notice the Progress page code example doesn't include the Download progress column, see: https://spectreconsole.net/live/progress I think it might be enough to just add that into the example, so it becomes obvious to casual readers that such a thing exists. |
Context
Currently the
TransferSpeedColumn
is displaying the transfer speed using the binary/IEC definition of a kilobyte/megabyte/gigabyte (1024x)Typically, network transfer speeds are specified using the decimal definition (1000x), for example Ethernet (10/100/1000BASE-T), or internet connection speeds (100mbit = 100,000,000,000)
https://en.wikipedia.org/wiki/Binary_prefix#Data_transmission_and_clock_rates
Describe the solution you'd like
I would like to propose adding the ability to configure which binary prefix (1000x or 1024x) is used for display, as well as configuring to display either bits/s or bytes/s. This would allow developers to be able to tweak formatting to better match their use case.
The default display format would be to continue to use the current format, 1024x , as to ensure that there are no unexpected changes to the existing behavior when updating to a newer version of the package.
Using a data transfer rate of 1,000,000 bytes, the expected output for each configurablee option would be as follows :
Testing
These changes have been in use for about a month now in my projects steam-lancache-prefill and battlenet-lancache-prefill, and have been able to be tested and proven to be working, as well as being able to smooth over any unexpected edge cases.
Example output of the change :
Related commit, where changes started to be used
Please upvote 👍 this pull request if you are interested in it.