-
-
Notifications
You must be signed in to change notification settings - Fork 853
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
cleanup projects and environment variables #2812
Conversation
@@ -43,21 +43,21 @@ public void Shuffle3() | |||
// | |||
// | Method | Job | EnvironmentVariables | Count | Mean | Error | StdDev | Median | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated | | |||
// |--------------------- |------------------- |-------------------------------------------------- |------ |----------:|---------:|---------:|----------:|------:|--------:|------:|------:|------:|----------:| | |||
// | Shuffle3 | 1. No HwIntrinsics | COMPlus_EnableHWIntrinsic=0,COMPlus_FeatureSIMD=0 | 96 | 48.46 ns | 1.034 ns | 2.438 ns | 47.46 ns | 1.00 | 0.00 | - | - | - | - | | |||
// | Shuffle3 | 1. No HwIntrinsics | DOTNET_EnableHWIntrinsic=0,DOTNET_FeatureSIMD=0 | 96 | 48.46 ns | 1.034 ns | 2.438 ns | 47.46 ns | 1.00 | 0.00 | - | - | - | - | |
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.
.net 6 onwards, DOTNET_ is preferred over COMPlus_ dotnet/runtime@fbdcec9 it first uses DOTNET_, and then COMPlus_ as a legacy fallback.
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.
Thanks for the updates. I’m in Europe on holiday just now so cannot review the changes properly but will do so when I’m back in Australia (3 days)
Looks like .NET 9 introduces a bunch of new required fixes. A good thing but also a chore. |
.net9 work can be a separate pr from this one. |
reverted, here is the history: https://github.com/SixLabors/ImageSharp/commits/522843cf11e6f965a3ad8f82304a573dd44222ff/. it fixes all CA warnings, passes all CI jobs with .net8, but fails all CI jobs with .net9 due to ONE test failure:
https://github.com/kasperk81/ImageSharp/actions/runs/11124894544 it doesn't show in github action logs had to run it locally. @adamsitnik @eerhardt this is either .net9 regression with ReadExactly or a fix but it doesn't repro in .net8 as you can see in this github run https://github.com/kasperk81/ImageSharp/actions/runs/11124894544. unfortunately i don't have a simple repro. |
@kasperk81 - can you log an issue in dotnet/runtime? |
Hey @kasperk81 Did you ever raise that issue? I'm wondering whether there is a zlib implementation change in .NET 9 which might be responsible for the differences given the test input image has damaged compression. |
@JimBobSquarePants i didn't get a chance to isolate a repro to report something actionable upstream. it's off by 0.0018% can we adjust the tolerance for VerifySimilarity? i haven't checked how much it differs net8.0, i.e. slightly less than 0.0018% or exactly 0%? |
I'll pull down your branch and compare the output. It's likely we can simply adjust that tolerance. |
I was right about the zlib changes. The underlying library .NET uses has changed. It actually decodes an extra 2 pixels in the busted image! https://learn.microsoft.com/en-us/dotnet/core/whats-new/dotnet-9/libraries#compression-with-zlib-ng |
@@ -1,4 +1,7 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<RuleSet Name="ImageSharp" ToolsVersion="17.0"> | |||
<Include Path="..\shared-infrastructure\sixlabors.ruleset" Action="Default" /> | |||
<Rules AnalyzerId="Microsoft.CodeAnalysis.CSharp.NetAnalyzers" RuleNamespace="Microsoft.CodeAnalysis.CSharp.NetAnalyzers"> | |||
<Rule Id="CA2022" Action="Info" /> |
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.
For my learning, why was this analyzer downgraded from the default Warning
to Info
? The issues that this analyzer flags are typically bugs when reading from Streams.
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.
The warnings were in areas of our code where it wasn’t really applicable. Our decoders are designed to handle degenerate images and in each warning instance we had pre-allocated an empty buffer to read to. If we don’t get a full read then those buffers remain partially unfillled and the decoding process will return when we look for the next chunk.
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.
Hmm, I'm wondering if we have a missed use case / bug in our analyzer then. Do you happen to have a link to example code that it flagged? Maybe it just couldn't understand the pattern.
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 don't think the analyzer will ever be possible to follow the code well enough here.
Take this for example. In ReadFrame
in the GIF decoder we attempt to read a local color palette from a stream. The analyzer will warn us that we might not get the full read though.
stream.Read(this.currentLocalColorTable.GetSpan()[..length]); |
In this instance we simply do not care as the following method ReadFrameColors
reads and checks the next byte. If it's invalid then we do nothing.
ImageSharp/src/ImageSharp/Formats/Gif/GifDecoderCore.cs
Lines 533 to 534 in 2d7cf48
int minCodeSize = stream.ReadByte(); | |
if (LzwDecoder.IsValidMinCodeSize(minCodeSize)) |
We also do a sense check and break when performing the next iteration to find additional frames so the decoder will quit after decoding as much information as possible.
ImageSharp/src/ImageSharp/Formats/Gif/GifDecoderCore.cs
Lines 155 to 156 in 2d7cf48
nextFlag = stream.ReadByte(); | |
if (nextFlag == -1) |
So, our code is safe, we could perhaps break earlier but we would end up complicating the code in order to do so. Info
will work in our scenarios as it will prompt us to check the code but not inhibit our ability to work.
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.
Taking a quick look, I believe the reason why the code is safe is because BufferedReadStream
guarantees it will fill out the entire passed in buffer on each call to .Read
.
ImageSharp/src/ImageSharp/IO/BufferedReadStream.cs
Lines 176 to 195 in 2d7cf48
public override int Read(Span<byte> buffer) | |
{ | |
this.cancellationToken.ThrowIfCancellationRequested(); | |
// Too big for our buffer. Read directly from the stream. | |
int count = buffer.Length; | |
if (count > this.BufferSize) | |
{ | |
return this.ReadToBufferDirectSlow(buffer); | |
} | |
// Too big for remaining buffer but less than entire buffer length | |
// Copy to buffer then read from there. | |
if ((uint)this.readBufferIndex > (uint)(this.BufferSize - count)) | |
{ | |
return this.ReadToBufferViaCopySlow(buffer); | |
} | |
return this.ReadToBufferViaCopyFast(buffer); | |
} |
ReadToBufferDirectSlow
and ReadToBufferViaCopySlow
read from the underlying stream in a loop until it fills the buffer or hits the end of the stream.
ImageSharp/src/ImageSharp/IO/BufferedReadStream.cs
Lines 347 to 357 in 2d7cf48
// Read doesn't always guarantee the full returned length so read a byte | |
// at a time until we get either our count or hit the end of the stream. | |
int count = buffer.Length; | |
int n = 0; | |
int i; | |
do | |
{ | |
i = baseStream.Read(buffer[n..count]); | |
n += i; | |
} | |
while (n < count && i > 0); |
ImageSharp/src/ImageSharp/IO/BufferedReadStream.cs
Lines 320 to 326 in 2d7cf48
private int ReadToBufferViaCopySlow(Span<byte> buffer) | |
{ | |
// Refill our buffer then copy. | |
this.FillReadBuffer(); | |
return this.ReadToBufferViaCopyFast(buffer); | |
} |
ImageSharp/src/ImageSharp/IO/BufferedReadStream.cs
Lines 270 to 288 in 2d7cf48
private void FillReadBuffer() | |
{ | |
this.cancellationToken.ThrowIfCancellationRequested(); | |
Stream baseStream = this.BaseStream; | |
if (this.readerPosition != baseStream.Position) | |
{ | |
baseStream.Seek(this.readerPosition, SeekOrigin.Begin); | |
} | |
// Read doesn't always guarantee the full returned length so read a byte | |
// at a time until we get either our count or hit the end of the stream. | |
int n = 0; | |
int i; | |
do | |
{ | |
i = baseStream.Read(this.readBuffer, n, this.BufferSize - n); | |
n += i; | |
} | |
while (n < this.BufferSize && i > 0); |
cleanup projects and use modern environment variables.