Improve RGB Min Max evaluation performance by using 2 or 3 comparison… - #50622

Merged
safern merged 5 commits into
dotnet:mainfrom
amd:rgbMinMax
Apr 6, 2021
Merged

Improve RGB Min Max evaluation performance by using 2 or 3 comparison…#50622
safern merged 5 commits into
dotnet:mainfrom
amd:rgbMinMax

Conversation

@L2

@L2L2 commented Apr 1, 2021

Copy link
Copy Markdown
Contributor

Fixes: #46153

…s instead of 4

  • Replaces 2 calls each to Math.Min and Math.Max (a total of 4 required
    comparisons) with a single call to MinMaxRgb (at least 2 required
    comparisons and at worst 3).

…s instead of 4
* Replaces 2 calls each to Math.Min and Math.Max (a total of 4 required
comparisons) with a single call to MinMaxRgb (at least 2 required
comparisons and at worst 3).
@ghost

ghost commented Apr 1, 2021

Copy link
Copy Markdown

Tagging subscribers to this area: @safern, @tarekgh
See info in area-owners.md if you want to be subscribed.

Issue Details

…s instead of 4

  • Replaces 2 calls each to Math.Min and Math.Max (a total of 4 required
    comparisons) with a single call to MinMaxRgb (at least 2 required
    comparisons and at worst 3).
Author:L2
Assignees:-
Labels:

area-System.Drawing

Milestone:-

@L2

L2 commented Apr 1, 2021

Copy link
Copy Markdown
ContributorAuthor

dotnet/performance microbenchmarks filtered with System.Drawing.Tests.Perf_Color*:

Base = .NET6 Before this changeset
Diff = .NET6 After this changeset

No Slower results for the provided threshold = 2% and noise filter = 25ns.

Fasterbase/diffBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetHue1.231756.531432.47
System.Drawing.Tests.Perf_Color.GetBrightness1.091544.741415.17
System.Drawing.Tests.Perf_Color.GetSaturation1.091602.511476.70

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void MinMaxRgb(out int min, out int max, int r, int g, int b)
{
if (b < g) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Move trailing braces to their own lines for consistency with existing .NET code.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks, updated.

@danmoseley

Copy link
Copy Markdown
Contributor

Do we have sufficient functional test coverage?

@L2

L2 commented Apr 2, 2021

Copy link
Copy Markdown
ContributorAuthor

Do we have sufficient functional test coverage?

Thanks @danmoseley . There were a couple of test cases missing which I've just added:

All Possible Cases:

label for existing testcase
(1)r == g == b
(2)r == g < b
(3)r == g > b
(4)r < g == b
(missing)r < g < b
r < g > b
(5)where [r == b]
(missing)where [r > b]
(missing)where [r < b]
(7)r > g == b
r > g < b
(6)where [r == b]
(missing)where [r > b]
(missing)where [r < b]
(missing)r > g > b

Existing Test Coverage:

test labelcase
(1)[InlineData(0, 0, 0, 0f)]
[InlineData(255, 255, 255, 1f)]
(7)[InlineData(255, 0, 0, 0.5f)]
(5)[InlineData(0, 255, 0, 0.5f)]
(2)[InlineData(0, 0, 255, 0.5f)]
(3)[InlineData(255, 255, 0, 0.5f)]
(6)[InlineData(255, 0, 255, 0.5f)]
(4)[InlineData(0, 255, 255, 0.5f)]
[InlineData(51, 255, 255, 0.6f)]
[InlineData(255, 51, 255, 0.6f)]
[InlineData(255, 255, 51, 0.6f)]
[InlineData(255, 51, 51, 0.6f)]
[InlineData(51, 255, 51, 0.6f)]
[InlineData(51, 51, 255, 0.6f)]
[InlineData(51, 51, 51, 0.2f)]

For:

public void GetBrightness(int r, int g, int b, float expected)
{
Assert.Equal(expected, Color.FromArgb(r, g, b).GetBrightness());
}

@L2

L2 commented Apr 2, 2021

Copy link
Copy Markdown
ContributorAuthor

Also I wasn't sure if I should put this new method in Math.cs and make it a general use case to find the min and max of three values so I've left it inside Color.cs for now.

@danmoseley

Copy link
Copy Markdown
Contributor

wasn't sure if I should put this new method in Math.cs

Drawing wouldn't be able to use anything from Math unless it was public: the libraries can only use each other's public surface. And to make new public API involves a review process, which would include consideration of how broadly useful the API would be. So I think it is in the right place.

Comment on lines +498 to +501
if (r < g)
max = g;
else
max = r;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We could simplify this to use ? assignment?

Suggested change
if(r<g)
max=g;
else
max=r;
max=r<g?g:r;

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks, updated.

Comment on lines +514 to +517
if (g < r)
min = g;
else
min = r;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Ditto:

Suggested change
if(g<r)
min=g;
else
min=r;
min=g<r?g:r;

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks, updated.

Comment on lines +531 to +532
int min, max;
MinMaxRgb(out min, out max, r, g, b);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
intmin,max;
MinMaxRgb(outmin,outmax,r,g,b);
MinMaxRgb(outintmin,outintmax,r,g,b);

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks, updated.

Comment on lines +544 to +545
int min, max;
MinMaxRgb(out min, out max, r, g, b);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
intmin,max;
MinMaxRgb(outmin,outmax,r,g,b);
MinMaxRgb(outintmin,outintmax,r,g,b);

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks, updated.

Comment on lines +571 to +572
int min, max;
MinMaxRgb(out min, out max, r, g, b);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
intmin,max;
MinMaxRgb(outmin,outmax,r,g,b);
MinMaxRgb(outintmin,outintmax,r,g,b);

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks, updated.

@safernsafern left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Other than small style improvements, looks good. Thanks!

@L2

L2 commented Apr 2, 2021

Copy link
Copy Markdown
ContributorAuthor

Other than small style improvements, looks good. Thanks!

Thanks @safern , I've updated it with the requested changes.

@ghost

ghost commented Apr 2, 2021

Copy link
Copy Markdown

Hello @safern!

Because this pull request has the auto-merge label, I will be glad to assist with helping to merge this pull request once all check-in policies pass.

p.s. you can customize the way I help with merging this pull request, such as holding this pull request until a specific person approves. Simply @mention me (@msftbot) and give me an instruction to get started! Learn more here.

Comment on lines +491 to +519
private void MinMaxRgb(out int min, out int max, int r, int g, int b)
{
if (b < g)
{
if (b < r)
{
min = b;
max = r < g ? g : r;
}
else
{
min = r;
max = g;
}
}
else
{
if (r < b)
{
max = b;
min = g < r ? g : r;
}
else
{
max = r;
min = g;
}
}
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This can be simplified to instead be:

Suggested change
privatevoidMinMaxRgb(outintmin,outintmax,intr,intg,intb)
{
if(b<g)
{
if(b<r)
{
min=b;
max=r<g?g:r;
}
else
{
min=r;
max=g;
}
}
else
{
if(r<b)
{
max=b;
min=g<r?g:r;
}
else
{
max=r;
min=g;
}
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
privatestaticvoidMinMaxRgb(outintmin,outintmax,intr,intg,intb)
{
if(r>g)
{
max=r;
min=g;
}
else
{
max=g;
min=r;
}
if(b>max)
{
max=b;
}
elseif(b<min)
{
min=b;
}
}

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks @stephentoub , I ran the perf_color microbenchmarks against 1) before this PR changeset, 2) the current PR's changeset, 3) proposed simplification

**.NET6 Before VS .NET6 with current PR changeset: Run1** summary: better: 3, geomean: 1.151 total diff: 3

No Slower results for the provided threshold = 2% and noise filter = 25ns.

Fasterbase/diffBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetBrightness1.231549.961259.50
System.Drawing.Tests.Perf_Color.GetHue1.181753.241484.57
System.Drawing.Tests.Perf_Color.GetSaturation1.051451.591383.79
**.NET6 Before VS .NET6 with current PR changeset: Run2** summary: better: 3, geomean: 1.208 total diff: 3

No Slower results for the provided threshold = 2% and noise filter = 25ns.

Fasterbase/diffBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetBrightness1.231543.191259.71
System.Drawing.Tests.Perf_Color.GetSaturation1.221682.031384.17
System.Drawing.Tests.Perf_Color.GetHue1.181758.681485.53
**.NET6 Before VS .NET6 with current PR changeset: Run3** summary: better: 3, geomean: 1.189 total diff: 3

No Slower results for the provided threshold = 2% and noise filter = 25ns.

Fasterbase/diffBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetSaturation1.221682.421384.03
System.Drawing.Tests.Perf_Color.GetBrightness1.191497.181259.28
System.Drawing.Tests.Perf_Color.GetHue1.161725.251483.41


**.NET6 Before VS .NET6 with proposed simplification: Run1** summary: better: 2, geomean: 1.123 total diff: 2

No Slower results for the provided threshold = 2% and noise filter = 25ns.

Fasterbase/diffBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetBrightness1.131549.961375.52
System.Drawing.Tests.Perf_Color.GetHue1.121753.241565.75
**.NET6 Before VS .NET6 with proposed simplification: Run2** summary: better: 3, geomean: 1.135 total diff: 3

No Slower results for the provided threshold = 2% and noise filter = 25ns.

Fasterbase/diffBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetSaturation1.161682.031448.45
System.Drawing.Tests.Perf_Color.GetHue1.121758.681566.17
System.Drawing.Tests.Perf_Color.GetBrightness1.121543.191375.17
**.NET6 Before VS .NET6 with proposed simplification: Run3** summary: better: 2, geomean: 1.132 worse: 1, geomean: 1.050 total diff: 3
Slowerdiff/baseBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetBrightness1.051497.181572.36
Fasterbase/diffBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetSaturation1.161682.421446.59
System.Drawing.Tests.Perf_Color.GetHue1.101725.251565.42
---------------------- ----------------------

Some of the benchmarks seem to get a bit slower on average after the simplification. I think what is happening may be two causes:

  1. There are paths with an extra store (we store max & min in the first conditional and then if the second conditional is taken one of these is overwritten).
  2. Just my guess, but processor pipelining with branch prediction may find it easier to go through each of the conditionals in the current implementation as there are no dependencies. The simplification introduces a dependency on the second conditional as it needs the values from the first? Just a guess here.

I will follow yours and @safern 's recommendation on which to keep. Thanks again.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I didn't look at the disassembly but there might be an aliasing complication also, if the JIT compiler has to account for the possibility that min and max refer to the same location. Although perhaps it can disprove that after inlining.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I actually see them get faster on my machine. Regardless, though, I'd rather keep the code smaller, especially with it triplicated due to the aggressive inlining.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

One more possible improvement - using local valiables instead of out parameters:

privatestaticvoidMinMaxRgb(outintmin,outintmax,intr,intg,intb){intminLoc,maxLoc;if(r>g){maxLoc=r;minLoc=g;}else{maxLoc=g;minLoc=r;}if(b>maxLoc){maxLoc=b;}elseif(b<minLoc){minLoc=b;}max=maxLoc;min=minLoc;}

@L2L2Apr 5, 2021

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I actually see them get faster on my machine. Regardless, though, I'd rather keep the code smaller, especially with it triplicated due to the aggressive inlining.

Sounds good @stephentoub , I've updated it with the requested changes. (I'm not sure how crediting works in this project as this is my second pull request, so I've added your username to the commit details as the originator of the simplification).

One more possible improvement - using local valiables instead of out parameters:

Thanks @hypeartist, I'm wondering if these local variables will be eliminated due to inlining, so performance will be about the same?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm not sure how crediting works in this project as this is my second pull request, so I've added your username to the commit details as the originator of the simplification

Thanks, but not necessary... I comment on a lot of PRs :)

* Credit for this simplification: stephentoub
@ghostghost removed the auto-merge label Apr 5, 2021
@danmoseley

Copy link
Copy Markdown
Contributor

Thanks for the contribution @L2 - perhaps you'd like to pick up something else?

thaystg added a commit to thaystg/runtime that referenced this pull request Apr 6, 2021
…shim_mono
# By Aaron Robinson (10) and others
# Via GitHub
* upstream/main: (108 commits)
[mbr] Add Apple sample (dotnet#50740)
make EstablishProxyTunnelAsync throw on failure status code from proxy (dotnet#50763)
Improve RGB Min Max evaluation performance by using 2 or 3 comparison… (dotnet#50622)
[mono] More domain cleanups (dotnet#50479)
Fix Crossgen2 of PlatformDefaultMemberFunction methods and calls. (dotnet#50754)
Disable EventSource generator in design-time builds (dotnet#50741)
Fix X509 test failures on Android (dotnet#50301)
Do not confuse fgDispBasicBlocks in fgMorphBlocks (dotnet#50703)
Enforce 64KB event payload size limit on EventPipe (dotnet#50600)
Reorganize CoreCLR native build to reduce CMake reconfigures when the build system is untouched (dotnet#49906)
[mbr] Turn on hot reload for iOS, tvOS and MacCatalyst (dotnet#50458)
improve connection scavenge logic by doing zero-byte read (dotnet#50545)
Resolve call mdtokens when making tier 1 inline observations (dotnet#50675)
Annotate APIs in System.Private.Xml (dotnet#49682)
Support compiling against OpenSSL 3 headers
Change Configuration.Json to use a regular Dictionary. (dotnet#50611)
Remove unused BigNumFromBinary P/Invoke (dotnet#50670)
Make Ninja the default CMake generator on Windows for the repo (dotnet#49715)
[AppleAppBuilder] Entitlements to run tests on catalyst using the JIT (dotnet#50637)
[mono] Fix delegate invokes to dynamic methods in mixed mode. (dotnet#50547)
...
# Conflicts:
#	src/mono/dlls/mscordbi/CMakeLists.txt
@L2
L2 deleted the rgbMinMax branch April 6, 2021 15:05
@ghostghost locked as resolved and limited conversation to collaborators May 9, 2021
@karelzkarelz added this to the 6.0.0 milestone May 20, 2021
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Perf] Changes at 12/9/2020 1:20:52 PM

8 participants

@L2@danmoseley@iamcarbon@stephentoub@hypeartist@safern@KalleOlaviNiemitalo@karelz
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Improve RGB Min Max evaluation performance by using 2 or 3 comparison… - #50622

Merged
safern merged 5 commits into
dotnet:mainfrom
amd:rgbMinMax
Apr 6, 2021
Merged

Improve RGB Min Max evaluation performance by using 2 or 3 comparison…#50622
safern merged 5 commits into
dotnet:mainfrom
amd:rgbMinMax

Conversation

@L2

@L2L2 commented Apr 1, 2021

Copy link
Copy Markdown
Contributor

Fixes: #46153

…s instead of 4

  • Replaces 2 calls each to Math.Min and Math.Max (a total of 4 required
    comparisons) with a single call to MinMaxRgb (at least 2 required
    comparisons and at worst 3).

…s instead of 4
* Replaces 2 calls each to Math.Min and Math.Max (a total of 4 required
comparisons) with a single call to MinMaxRgb (at least 2 required
comparisons and at worst 3).
@ghost

ghost commented Apr 1, 2021

Copy link
Copy Markdown

Tagging subscribers to this area: @safern, @tarekgh
See info in area-owners.md if you want to be subscribed.

Issue Details

…s instead of 4

  • Replaces 2 calls each to Math.Min and Math.Max (a total of 4 required
    comparisons) with a single call to MinMaxRgb (at least 2 required
    comparisons and at worst 3).
Author:L2
Assignees:-
Labels:

area-System.Drawing

Milestone:-

@L2

L2 commented Apr 1, 2021

Copy link
Copy Markdown
ContributorAuthor

dotnet/performance microbenchmarks filtered with System.Drawing.Tests.Perf_Color*:

Base = .NET6 Before this changeset
Diff = .NET6 After this changeset

No Slower results for the provided threshold = 2% and noise filter = 25ns.

Fasterbase/diffBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetHue1.231756.531432.47
System.Drawing.Tests.Perf_Color.GetBrightness1.091544.741415.17
System.Drawing.Tests.Perf_Color.GetSaturation1.091602.511476.70

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void MinMaxRgb(out int min, out int max, int r, int g, int b)
{
if (b < g) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Move trailing braces to their own lines for consistency with existing .NET code.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks, updated.

@danmoseley

Copy link
Copy Markdown
Contributor

Do we have sufficient functional test coverage?

@L2

L2 commented Apr 2, 2021

Copy link
Copy Markdown
ContributorAuthor

Do we have sufficient functional test coverage?

Thanks @danmoseley . There were a couple of test cases missing which I've just added:

All Possible Cases:

label for existing testcase
(1)r == g == b
(2)r == g < b
(3)r == g > b
(4)r < g == b
(missing)r < g < b
r < g > b
(5)where [r == b]
(missing)where [r > b]
(missing)where [r < b]
(7)r > g == b
r > g < b
(6)where [r == b]
(missing)where [r > b]
(missing)where [r < b]
(missing)r > g > b

Existing Test Coverage:

test labelcase
(1)[InlineData(0, 0, 0, 0f)]
[InlineData(255, 255, 255, 1f)]
(7)[InlineData(255, 0, 0, 0.5f)]
(5)[InlineData(0, 255, 0, 0.5f)]
(2)[InlineData(0, 0, 255, 0.5f)]
(3)[InlineData(255, 255, 0, 0.5f)]
(6)[InlineData(255, 0, 255, 0.5f)]
(4)[InlineData(0, 255, 255, 0.5f)]
[InlineData(51, 255, 255, 0.6f)]
[InlineData(255, 51, 255, 0.6f)]
[InlineData(255, 255, 51, 0.6f)]
[InlineData(255, 51, 51, 0.6f)]
[InlineData(51, 255, 51, 0.6f)]
[InlineData(51, 51, 255, 0.6f)]
[InlineData(51, 51, 51, 0.2f)]

For:

public void GetBrightness(int r, int g, int b, float expected)
{
Assert.Equal(expected, Color.FromArgb(r, g, b).GetBrightness());
}

@L2

L2 commented Apr 2, 2021

Copy link
Copy Markdown
ContributorAuthor

Also I wasn't sure if I should put this new method in Math.cs and make it a general use case to find the min and max of three values so I've left it inside Color.cs for now.

@danmoseley

Copy link
Copy Markdown
Contributor

wasn't sure if I should put this new method in Math.cs

Drawing wouldn't be able to use anything from Math unless it was public: the libraries can only use each other's public surface. And to make new public API involves a review process, which would include consideration of how broadly useful the API would be. So I think it is in the right place.

Comment on lines +498 to +501
if (r < g)
max = g;
else
max = r;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We could simplify this to use ? assignment?

Suggested change
if(r<g)
max=g;
else
max=r;
max=r<g?g:r;

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks, updated.

Comment on lines +514 to +517
if (g < r)
min = g;
else
min = r;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Ditto:

Suggested change
if(g<r)
min=g;
else
min=r;
min=g<r?g:r;

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks, updated.

Comment on lines +531 to +532
int min, max;
MinMaxRgb(out min, out max, r, g, b);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
intmin,max;
MinMaxRgb(outmin,outmax,r,g,b);
MinMaxRgb(outintmin,outintmax,r,g,b);

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks, updated.

Comment on lines +544 to +545
int min, max;
MinMaxRgb(out min, out max, r, g, b);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
intmin,max;
MinMaxRgb(outmin,outmax,r,g,b);
MinMaxRgb(outintmin,outintmax,r,g,b);

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks, updated.

Comment on lines +571 to +572
int min, max;
MinMaxRgb(out min, out max, r, g, b);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
intmin,max;
MinMaxRgb(outmin,outmax,r,g,b);
MinMaxRgb(outintmin,outintmax,r,g,b);

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks, updated.

@safernsafern left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Other than small style improvements, looks good. Thanks!

@L2

L2 commented Apr 2, 2021

Copy link
Copy Markdown
ContributorAuthor

Other than small style improvements, looks good. Thanks!

Thanks @safern , I've updated it with the requested changes.

@ghost

ghost commented Apr 2, 2021

Copy link
Copy Markdown

Hello @safern!

Because this pull request has the auto-merge label, I will be glad to assist with helping to merge this pull request once all check-in policies pass.

p.s. you can customize the way I help with merging this pull request, such as holding this pull request until a specific person approves. Simply @mention me (@msftbot) and give me an instruction to get started! Learn more here.

Comment on lines +491 to +519
private void MinMaxRgb(out int min, out int max, int r, int g, int b)
{
if (b < g)
{
if (b < r)
{
min = b;
max = r < g ? g : r;
}
else
{
min = r;
max = g;
}
}
else
{
if (r < b)
{
max = b;
min = g < r ? g : r;
}
else
{
max = r;
min = g;
}
}
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This can be simplified to instead be:

Suggested change
privatevoidMinMaxRgb(outintmin,outintmax,intr,intg,intb)
{
if(b<g)
{
if(b<r)
{
min=b;
max=r<g?g:r;
}
else
{
min=r;
max=g;
}
}
else
{
if(r<b)
{
max=b;
min=g<r?g:r;
}
else
{
max=r;
min=g;
}
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
privatestaticvoidMinMaxRgb(outintmin,outintmax,intr,intg,intb)
{
if(r>g)
{
max=r;
min=g;
}
else
{
max=g;
min=r;
}
if(b>max)
{
max=b;
}
elseif(b<min)
{
min=b;
}
}

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks @stephentoub , I ran the perf_color microbenchmarks against 1) before this PR changeset, 2) the current PR's changeset, 3) proposed simplification

**.NET6 Before VS .NET6 with current PR changeset: Run1** summary: better: 3, geomean: 1.151 total diff: 3

No Slower results for the provided threshold = 2% and noise filter = 25ns.

Fasterbase/diffBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetBrightness1.231549.961259.50
System.Drawing.Tests.Perf_Color.GetHue1.181753.241484.57
System.Drawing.Tests.Perf_Color.GetSaturation1.051451.591383.79
**.NET6 Before VS .NET6 with current PR changeset: Run2** summary: better: 3, geomean: 1.208 total diff: 3

No Slower results for the provided threshold = 2% and noise filter = 25ns.

Fasterbase/diffBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetBrightness1.231543.191259.71
System.Drawing.Tests.Perf_Color.GetSaturation1.221682.031384.17
System.Drawing.Tests.Perf_Color.GetHue1.181758.681485.53
**.NET6 Before VS .NET6 with current PR changeset: Run3** summary: better: 3, geomean: 1.189 total diff: 3

No Slower results for the provided threshold = 2% and noise filter = 25ns.

Fasterbase/diffBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetSaturation1.221682.421384.03
System.Drawing.Tests.Perf_Color.GetBrightness1.191497.181259.28
System.Drawing.Tests.Perf_Color.GetHue1.161725.251483.41


**.NET6 Before VS .NET6 with proposed simplification: Run1** summary: better: 2, geomean: 1.123 total diff: 2

No Slower results for the provided threshold = 2% and noise filter = 25ns.

Fasterbase/diffBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetBrightness1.131549.961375.52
System.Drawing.Tests.Perf_Color.GetHue1.121753.241565.75
**.NET6 Before VS .NET6 with proposed simplification: Run2** summary: better: 3, geomean: 1.135 total diff: 3

No Slower results for the provided threshold = 2% and noise filter = 25ns.

Fasterbase/diffBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetSaturation1.161682.031448.45
System.Drawing.Tests.Perf_Color.GetHue1.121758.681566.17
System.Drawing.Tests.Perf_Color.GetBrightness1.121543.191375.17
**.NET6 Before VS .NET6 with proposed simplification: Run3** summary: better: 2, geomean: 1.132 worse: 1, geomean: 1.050 total diff: 3
Slowerdiff/baseBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetBrightness1.051497.181572.36
Fasterbase/diffBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetSaturation1.161682.421446.59
System.Drawing.Tests.Perf_Color.GetHue1.101725.251565.42
---------------------- ----------------------

Some of the benchmarks seem to get a bit slower on average after the simplification. I think what is happening may be two causes:

  1. There are paths with an extra store (we store max & min in the first conditional and then if the second conditional is taken one of these is overwritten).
  2. Just my guess, but processor pipelining with branch prediction may find it easier to go through each of the conditionals in the current implementation as there are no dependencies. The simplification introduces a dependency on the second conditional as it needs the values from the first? Just a guess here.

I will follow yours and @safern 's recommendation on which to keep. Thanks again.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I didn't look at the disassembly but there might be an aliasing complication also, if the JIT compiler has to account for the possibility that min and max refer to the same location. Although perhaps it can disprove that after inlining.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I actually see them get faster on my machine. Regardless, though, I'd rather keep the code smaller, especially with it triplicated due to the aggressive inlining.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

One more possible improvement - using local valiables instead of out parameters:

privatestaticvoidMinMaxRgb(outintmin,outintmax,intr,intg,intb){intminLoc,maxLoc;if(r>g){maxLoc=r;minLoc=g;}else{maxLoc=g;minLoc=r;}if(b>maxLoc){maxLoc=b;}elseif(b<minLoc){minLoc=b;}max=maxLoc;min=minLoc;}

@L2L2Apr 5, 2021

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I actually see them get faster on my machine. Regardless, though, I'd rather keep the code smaller, especially with it triplicated due to the aggressive inlining.

Sounds good @stephentoub , I've updated it with the requested changes. (I'm not sure how crediting works in this project as this is my second pull request, so I've added your username to the commit details as the originator of the simplification).

One more possible improvement - using local valiables instead of out parameters:

Thanks @hypeartist, I'm wondering if these local variables will be eliminated due to inlining, so performance will be about the same?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm not sure how crediting works in this project as this is my second pull request, so I've added your username to the commit details as the originator of the simplification

Thanks, but not necessary... I comment on a lot of PRs :)

* Credit for this simplification: stephentoub
@ghostghost removed the auto-merge label Apr 5, 2021
@danmoseley

Copy link
Copy Markdown
Contributor

Thanks for the contribution @L2 - perhaps you'd like to pick up something else?

thaystg added a commit to thaystg/runtime that referenced this pull request Apr 6, 2021
…shim_mono
# By Aaron Robinson (10) and others
# Via GitHub
* upstream/main: (108 commits)
[mbr] Add Apple sample (dotnet#50740)
make EstablishProxyTunnelAsync throw on failure status code from proxy (dotnet#50763)
Improve RGB Min Max evaluation performance by using 2 or 3 comparison… (dotnet#50622)
[mono] More domain cleanups (dotnet#50479)
Fix Crossgen2 of PlatformDefaultMemberFunction methods and calls. (dotnet#50754)
Disable EventSource generator in design-time builds (dotnet#50741)
Fix X509 test failures on Android (dotnet#50301)
Do not confuse fgDispBasicBlocks in fgMorphBlocks (dotnet#50703)
Enforce 64KB event payload size limit on EventPipe (dotnet#50600)
Reorganize CoreCLR native build to reduce CMake reconfigures when the build system is untouched (dotnet#49906)
[mbr] Turn on hot reload for iOS, tvOS and MacCatalyst (dotnet#50458)
improve connection scavenge logic by doing zero-byte read (dotnet#50545)
Resolve call mdtokens when making tier 1 inline observations (dotnet#50675)
Annotate APIs in System.Private.Xml (dotnet#49682)
Support compiling against OpenSSL 3 headers
Change Configuration.Json to use a regular Dictionary. (dotnet#50611)
Remove unused BigNumFromBinary P/Invoke (dotnet#50670)
Make Ninja the default CMake generator on Windows for the repo (dotnet#49715)
[AppleAppBuilder] Entitlements to run tests on catalyst using the JIT (dotnet#50637)
[mono] Fix delegate invokes to dynamic methods in mixed mode. (dotnet#50547)
...
# Conflicts:
#	src/mono/dlls/mscordbi/CMakeLists.txt
@L2
L2 deleted the rgbMinMax branch April 6, 2021 15:05
@ghostghost locked as resolved and limited conversation to collaborators May 9, 2021
@karelzkarelz added this to the 6.0.0 milestone May 20, 2021
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Perf] Changes at 12/9/2020 1:20:52 PM

8 participants

@L2@danmoseley@iamcarbon@stephentoub@hypeartist@safern@KalleOlaviNiemitalo@karelz
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Improve RGB Min Max evaluation performance by using 2 or 3 comparison… - #50622

Merged
safern merged 5 commits into
dotnet:mainfrom
amd:rgbMinMax
Apr 6, 2021
Merged

Improve RGB Min Max evaluation performance by using 2 or 3 comparison…#50622
safern merged 5 commits into
dotnet:mainfrom
amd:rgbMinMax

Conversation

@L2

@L2L2 commented Apr 1, 2021

Copy link
Copy Markdown
Contributor

Fixes: #46153

…s instead of 4

  • Replaces 2 calls each to Math.Min and Math.Max (a total of 4 required
    comparisons) with a single call to MinMaxRgb (at least 2 required
    comparisons and at worst 3).

…s instead of 4
* Replaces 2 calls each to Math.Min and Math.Max (a total of 4 required
comparisons) with a single call to MinMaxRgb (at least 2 required
comparisons and at worst 3).
@ghost

ghost commented Apr 1, 2021

Copy link
Copy Markdown

Tagging subscribers to this area: @safern, @tarekgh
See info in area-owners.md if you want to be subscribed.

Issue Details

…s instead of 4

  • Replaces 2 calls each to Math.Min and Math.Max (a total of 4 required
    comparisons) with a single call to MinMaxRgb (at least 2 required
    comparisons and at worst 3).
Author:L2
Assignees:-
Labels:

area-System.Drawing

Milestone:-

@L2

L2 commented Apr 1, 2021

Copy link
Copy Markdown
ContributorAuthor

dotnet/performance microbenchmarks filtered with System.Drawing.Tests.Perf_Color*:

Base = .NET6 Before this changeset
Diff = .NET6 After this changeset

No Slower results for the provided threshold = 2% and noise filter = 25ns.

Fasterbase/diffBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetHue1.231756.531432.47
System.Drawing.Tests.Perf_Color.GetBrightness1.091544.741415.17
System.Drawing.Tests.Perf_Color.GetSaturation1.091602.511476.70

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void MinMaxRgb(out int min, out int max, int r, int g, int b)
{
if (b < g) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Move trailing braces to their own lines for consistency with existing .NET code.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks, updated.

@danmoseley

Copy link
Copy Markdown
Contributor

Do we have sufficient functional test coverage?

@L2

L2 commented Apr 2, 2021

Copy link
Copy Markdown
ContributorAuthor

Do we have sufficient functional test coverage?

Thanks @danmoseley . There were a couple of test cases missing which I've just added:

All Possible Cases:

label for existing testcase
(1)r == g == b
(2)r == g < b
(3)r == g > b
(4)r < g == b
(missing)r < g < b
r < g > b
(5)where [r == b]
(missing)where [r > b]
(missing)where [r < b]
(7)r > g == b
r > g < b
(6)where [r == b]
(missing)where [r > b]
(missing)where [r < b]
(missing)r > g > b

Existing Test Coverage:

test labelcase
(1)[InlineData(0, 0, 0, 0f)]
[InlineData(255, 255, 255, 1f)]
(7)[InlineData(255, 0, 0, 0.5f)]
(5)[InlineData(0, 255, 0, 0.5f)]
(2)[InlineData(0, 0, 255, 0.5f)]
(3)[InlineData(255, 255, 0, 0.5f)]
(6)[InlineData(255, 0, 255, 0.5f)]
(4)[InlineData(0, 255, 255, 0.5f)]
[InlineData(51, 255, 255, 0.6f)]
[InlineData(255, 51, 255, 0.6f)]
[InlineData(255, 255, 51, 0.6f)]
[InlineData(255, 51, 51, 0.6f)]
[InlineData(51, 255, 51, 0.6f)]
[InlineData(51, 51, 255, 0.6f)]
[InlineData(51, 51, 51, 0.2f)]

For:

public void GetBrightness(int r, int g, int b, float expected)
{
Assert.Equal(expected, Color.FromArgb(r, g, b).GetBrightness());
}

@L2

L2 commented Apr 2, 2021

Copy link
Copy Markdown
ContributorAuthor

Also I wasn't sure if I should put this new method in Math.cs and make it a general use case to find the min and max of three values so I've left it inside Color.cs for now.

@danmoseley

Copy link
Copy Markdown
Contributor

wasn't sure if I should put this new method in Math.cs

Drawing wouldn't be able to use anything from Math unless it was public: the libraries can only use each other's public surface. And to make new public API involves a review process, which would include consideration of how broadly useful the API would be. So I think it is in the right place.

Comment on lines +498 to +501
if (r < g)
max = g;
else
max = r;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We could simplify this to use ? assignment?

Suggested change
if(r<g)
max=g;
else
max=r;
max=r<g?g:r;

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks, updated.

Comment on lines +514 to +517
if (g < r)
min = g;
else
min = r;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Ditto:

Suggested change
if(g<r)
min=g;
else
min=r;
min=g<r?g:r;

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks, updated.

Comment on lines +531 to +532
int min, max;
MinMaxRgb(out min, out max, r, g, b);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
intmin,max;
MinMaxRgb(outmin,outmax,r,g,b);
MinMaxRgb(outintmin,outintmax,r,g,b);

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks, updated.

Comment on lines +544 to +545
int min, max;
MinMaxRgb(out min, out max, r, g, b);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
intmin,max;
MinMaxRgb(outmin,outmax,r,g,b);
MinMaxRgb(outintmin,outintmax,r,g,b);

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks, updated.

Comment on lines +571 to +572
int min, max;
MinMaxRgb(out min, out max, r, g, b);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
intmin,max;
MinMaxRgb(outmin,outmax,r,g,b);
MinMaxRgb(outintmin,outintmax,r,g,b);

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks, updated.

@safernsafern left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Other than small style improvements, looks good. Thanks!

@L2

L2 commented Apr 2, 2021

Copy link
Copy Markdown
ContributorAuthor

Other than small style improvements, looks good. Thanks!

Thanks @safern , I've updated it with the requested changes.

@ghost

ghost commented Apr 2, 2021

Copy link
Copy Markdown

Hello @safern!

Because this pull request has the auto-merge label, I will be glad to assist with helping to merge this pull request once all check-in policies pass.

p.s. you can customize the way I help with merging this pull request, such as holding this pull request until a specific person approves. Simply @mention me (@msftbot) and give me an instruction to get started! Learn more here.

Comment on lines +491 to +519
private void MinMaxRgb(out int min, out int max, int r, int g, int b)
{
if (b < g)
{
if (b < r)
{
min = b;
max = r < g ? g : r;
}
else
{
min = r;
max = g;
}
}
else
{
if (r < b)
{
max = b;
min = g < r ? g : r;
}
else
{
max = r;
min = g;
}
}
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This can be simplified to instead be:

Suggested change
privatevoidMinMaxRgb(outintmin,outintmax,intr,intg,intb)
{
if(b<g)
{
if(b<r)
{
min=b;
max=r<g?g:r;
}
else
{
min=r;
max=g;
}
}
else
{
if(r<b)
{
max=b;
min=g<r?g:r;
}
else
{
max=r;
min=g;
}
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
privatestaticvoidMinMaxRgb(outintmin,outintmax,intr,intg,intb)
{
if(r>g)
{
max=r;
min=g;
}
else
{
max=g;
min=r;
}
if(b>max)
{
max=b;
}
elseif(b<min)
{
min=b;
}
}

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks @stephentoub , I ran the perf_color microbenchmarks against 1) before this PR changeset, 2) the current PR's changeset, 3) proposed simplification

**.NET6 Before VS .NET6 with current PR changeset: Run1** summary: better: 3, geomean: 1.151 total diff: 3

No Slower results for the provided threshold = 2% and noise filter = 25ns.

Fasterbase/diffBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetBrightness1.231549.961259.50
System.Drawing.Tests.Perf_Color.GetHue1.181753.241484.57
System.Drawing.Tests.Perf_Color.GetSaturation1.051451.591383.79
**.NET6 Before VS .NET6 with current PR changeset: Run2** summary: better: 3, geomean: 1.208 total diff: 3

No Slower results for the provided threshold = 2% and noise filter = 25ns.

Fasterbase/diffBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetBrightness1.231543.191259.71
System.Drawing.Tests.Perf_Color.GetSaturation1.221682.031384.17
System.Drawing.Tests.Perf_Color.GetHue1.181758.681485.53
**.NET6 Before VS .NET6 with current PR changeset: Run3** summary: better: 3, geomean: 1.189 total diff: 3

No Slower results for the provided threshold = 2% and noise filter = 25ns.

Fasterbase/diffBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetSaturation1.221682.421384.03
System.Drawing.Tests.Perf_Color.GetBrightness1.191497.181259.28
System.Drawing.Tests.Perf_Color.GetHue1.161725.251483.41


**.NET6 Before VS .NET6 with proposed simplification: Run1** summary: better: 2, geomean: 1.123 total diff: 2

No Slower results for the provided threshold = 2% and noise filter = 25ns.

Fasterbase/diffBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetBrightness1.131549.961375.52
System.Drawing.Tests.Perf_Color.GetHue1.121753.241565.75
**.NET6 Before VS .NET6 with proposed simplification: Run2** summary: better: 3, geomean: 1.135 total diff: 3

No Slower results for the provided threshold = 2% and noise filter = 25ns.

Fasterbase/diffBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetSaturation1.161682.031448.45
System.Drawing.Tests.Perf_Color.GetHue1.121758.681566.17
System.Drawing.Tests.Perf_Color.GetBrightness1.121543.191375.17
**.NET6 Before VS .NET6 with proposed simplification: Run3** summary: better: 2, geomean: 1.132 worse: 1, geomean: 1.050 total diff: 3
Slowerdiff/baseBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetBrightness1.051497.181572.36
Fasterbase/diffBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetSaturation1.161682.421446.59
System.Drawing.Tests.Perf_Color.GetHue1.101725.251565.42
---------------------- ----------------------

Some of the benchmarks seem to get a bit slower on average after the simplification. I think what is happening may be two causes:

  1. There are paths with an extra store (we store max & min in the first conditional and then if the second conditional is taken one of these is overwritten).
  2. Just my guess, but processor pipelining with branch prediction may find it easier to go through each of the conditionals in the current implementation as there are no dependencies. The simplification introduces a dependency on the second conditional as it needs the values from the first? Just a guess here.

I will follow yours and @safern 's recommendation on which to keep. Thanks again.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I didn't look at the disassembly but there might be an aliasing complication also, if the JIT compiler has to account for the possibility that min and max refer to the same location. Although perhaps it can disprove that after inlining.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I actually see them get faster on my machine. Regardless, though, I'd rather keep the code smaller, especially with it triplicated due to the aggressive inlining.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

One more possible improvement - using local valiables instead of out parameters:

privatestaticvoidMinMaxRgb(outintmin,outintmax,intr,intg,intb){intminLoc,maxLoc;if(r>g){maxLoc=r;minLoc=g;}else{maxLoc=g;minLoc=r;}if(b>maxLoc){maxLoc=b;}elseif(b<minLoc){minLoc=b;}max=maxLoc;min=minLoc;}

@L2L2Apr 5, 2021

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I actually see them get faster on my machine. Regardless, though, I'd rather keep the code smaller, especially with it triplicated due to the aggressive inlining.

Sounds good @stephentoub , I've updated it with the requested changes. (I'm not sure how crediting works in this project as this is my second pull request, so I've added your username to the commit details as the originator of the simplification).

One more possible improvement - using local valiables instead of out parameters:

Thanks @hypeartist, I'm wondering if these local variables will be eliminated due to inlining, so performance will be about the same?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm not sure how crediting works in this project as this is my second pull request, so I've added your username to the commit details as the originator of the simplification

Thanks, but not necessary... I comment on a lot of PRs :)

* Credit for this simplification: stephentoub
@ghostghost removed the auto-merge label Apr 5, 2021
@danmoseley

Copy link
Copy Markdown
Contributor

Thanks for the contribution @L2 - perhaps you'd like to pick up something else?

thaystg added a commit to thaystg/runtime that referenced this pull request Apr 6, 2021
…shim_mono
# By Aaron Robinson (10) and others
# Via GitHub
* upstream/main: (108 commits)
[mbr] Add Apple sample (dotnet#50740)
make EstablishProxyTunnelAsync throw on failure status code from proxy (dotnet#50763)
Improve RGB Min Max evaluation performance by using 2 or 3 comparison… (dotnet#50622)
[mono] More domain cleanups (dotnet#50479)
Fix Crossgen2 of PlatformDefaultMemberFunction methods and calls. (dotnet#50754)
Disable EventSource generator in design-time builds (dotnet#50741)
Fix X509 test failures on Android (dotnet#50301)
Do not confuse fgDispBasicBlocks in fgMorphBlocks (dotnet#50703)
Enforce 64KB event payload size limit on EventPipe (dotnet#50600)
Reorganize CoreCLR native build to reduce CMake reconfigures when the build system is untouched (dotnet#49906)
[mbr] Turn on hot reload for iOS, tvOS and MacCatalyst (dotnet#50458)
improve connection scavenge logic by doing zero-byte read (dotnet#50545)
Resolve call mdtokens when making tier 1 inline observations (dotnet#50675)
Annotate APIs in System.Private.Xml (dotnet#49682)
Support compiling against OpenSSL 3 headers
Change Configuration.Json to use a regular Dictionary. (dotnet#50611)
Remove unused BigNumFromBinary P/Invoke (dotnet#50670)
Make Ninja the default CMake generator on Windows for the repo (dotnet#49715)
[AppleAppBuilder] Entitlements to run tests on catalyst using the JIT (dotnet#50637)
[mono] Fix delegate invokes to dynamic methods in mixed mode. (dotnet#50547)
...
# Conflicts:
#	src/mono/dlls/mscordbi/CMakeLists.txt
@L2
L2 deleted the rgbMinMax branch April 6, 2021 15:05
@ghostghost locked as resolved and limited conversation to collaborators May 9, 2021
@karelzkarelz added this to the 6.0.0 milestone May 20, 2021
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Perf] Changes at 12/9/2020 1:20:52 PM

8 participants

@L2@danmoseley@iamcarbon@stephentoub@hypeartist@safern@KalleOlaviNiemitalo@karelz
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Improve RGB Min Max evaluation performance by using 2 or 3 comparison… - #50622

Merged
safern merged 5 commits into
dotnet:mainfrom
amd:rgbMinMax
Apr 6, 2021
Merged

Improve RGB Min Max evaluation performance by using 2 or 3 comparison…#50622
safern merged 5 commits into
dotnet:mainfrom
amd:rgbMinMax

Conversation

@L2

@L2L2 commented Apr 1, 2021

Copy link
Copy Markdown
Contributor

Fixes: #46153

…s instead of 4

  • Replaces 2 calls each to Math.Min and Math.Max (a total of 4 required
    comparisons) with a single call to MinMaxRgb (at least 2 required
    comparisons and at worst 3).

…s instead of 4
* Replaces 2 calls each to Math.Min and Math.Max (a total of 4 required
comparisons) with a single call to MinMaxRgb (at least 2 required
comparisons and at worst 3).
@ghost

ghost commented Apr 1, 2021

Copy link
Copy Markdown

Tagging subscribers to this area: @safern, @tarekgh
See info in area-owners.md if you want to be subscribed.

Issue Details

…s instead of 4

  • Replaces 2 calls each to Math.Min and Math.Max (a total of 4 required
    comparisons) with a single call to MinMaxRgb (at least 2 required
    comparisons and at worst 3).
Author:L2
Assignees:-
Labels:

area-System.Drawing

Milestone:-

@L2

L2 commented Apr 1, 2021

Copy link
Copy Markdown
ContributorAuthor

dotnet/performance microbenchmarks filtered with System.Drawing.Tests.Perf_Color*:

Base = .NET6 Before this changeset
Diff = .NET6 After this changeset

No Slower results for the provided threshold = 2% and noise filter = 25ns.

Fasterbase/diffBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetHue1.231756.531432.47
System.Drawing.Tests.Perf_Color.GetBrightness1.091544.741415.17
System.Drawing.Tests.Perf_Color.GetSaturation1.091602.511476.70

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void MinMaxRgb(out int min, out int max, int r, int g, int b)
{
if (b < g) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Move trailing braces to their own lines for consistency with existing .NET code.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks, updated.

@danmoseley

Copy link
Copy Markdown
Contributor

Do we have sufficient functional test coverage?

@L2

L2 commented Apr 2, 2021

Copy link
Copy Markdown
ContributorAuthor

Do we have sufficient functional test coverage?

Thanks @danmoseley . There were a couple of test cases missing which I've just added:

All Possible Cases:

label for existing testcase
(1)r == g == b
(2)r == g < b
(3)r == g > b
(4)r < g == b
(missing)r < g < b
r < g > b
(5)where [r == b]
(missing)where [r > b]
(missing)where [r < b]
(7)r > g == b
r > g < b
(6)where [r == b]
(missing)where [r > b]
(missing)where [r < b]
(missing)r > g > b

Existing Test Coverage:

test labelcase
(1)[InlineData(0, 0, 0, 0f)]
[InlineData(255, 255, 255, 1f)]
(7)[InlineData(255, 0, 0, 0.5f)]
(5)[InlineData(0, 255, 0, 0.5f)]
(2)[InlineData(0, 0, 255, 0.5f)]
(3)[InlineData(255, 255, 0, 0.5f)]
(6)[InlineData(255, 0, 255, 0.5f)]
(4)[InlineData(0, 255, 255, 0.5f)]
[InlineData(51, 255, 255, 0.6f)]
[InlineData(255, 51, 255, 0.6f)]
[InlineData(255, 255, 51, 0.6f)]
[InlineData(255, 51, 51, 0.6f)]
[InlineData(51, 255, 51, 0.6f)]
[InlineData(51, 51, 255, 0.6f)]
[InlineData(51, 51, 51, 0.2f)]

For:

public void GetBrightness(int r, int g, int b, float expected)
{
Assert.Equal(expected, Color.FromArgb(r, g, b).GetBrightness());
}

@L2

L2 commented Apr 2, 2021

Copy link
Copy Markdown
ContributorAuthor

Also I wasn't sure if I should put this new method in Math.cs and make it a general use case to find the min and max of three values so I've left it inside Color.cs for now.

@danmoseley

Copy link
Copy Markdown
Contributor

wasn't sure if I should put this new method in Math.cs

Drawing wouldn't be able to use anything from Math unless it was public: the libraries can only use each other's public surface. And to make new public API involves a review process, which would include consideration of how broadly useful the API would be. So I think it is in the right place.

Comment on lines +498 to +501
if (r < g)
max = g;
else
max = r;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We could simplify this to use ? assignment?

Suggested change
if(r<g)
max=g;
else
max=r;
max=r<g?g:r;

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks, updated.

Comment on lines +514 to +517
if (g < r)
min = g;
else
min = r;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Ditto:

Suggested change
if(g<r)
min=g;
else
min=r;
min=g<r?g:r;

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks, updated.

Comment on lines +531 to +532
int min, max;
MinMaxRgb(out min, out max, r, g, b);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
intmin,max;
MinMaxRgb(outmin,outmax,r,g,b);
MinMaxRgb(outintmin,outintmax,r,g,b);

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks, updated.

Comment on lines +544 to +545
int min, max;
MinMaxRgb(out min, out max, r, g, b);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
intmin,max;
MinMaxRgb(outmin,outmax,r,g,b);
MinMaxRgb(outintmin,outintmax,r,g,b);

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks, updated.

Comment on lines +571 to +572
int min, max;
MinMaxRgb(out min, out max, r, g, b);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
intmin,max;
MinMaxRgb(outmin,outmax,r,g,b);
MinMaxRgb(outintmin,outintmax,r,g,b);

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks, updated.

@safernsafern left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Other than small style improvements, looks good. Thanks!

@L2

L2 commented Apr 2, 2021

Copy link
Copy Markdown
ContributorAuthor

Other than small style improvements, looks good. Thanks!

Thanks @safern , I've updated it with the requested changes.

@ghost

ghost commented Apr 2, 2021

Copy link
Copy Markdown

Hello @safern!

Because this pull request has the auto-merge label, I will be glad to assist with helping to merge this pull request once all check-in policies pass.

p.s. you can customize the way I help with merging this pull request, such as holding this pull request until a specific person approves. Simply @mention me (@msftbot) and give me an instruction to get started! Learn more here.

Comment on lines +491 to +519
private void MinMaxRgb(out int min, out int max, int r, int g, int b)
{
if (b < g)
{
if (b < r)
{
min = b;
max = r < g ? g : r;
}
else
{
min = r;
max = g;
}
}
else
{
if (r < b)
{
max = b;
min = g < r ? g : r;
}
else
{
max = r;
min = g;
}
}
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This can be simplified to instead be:

Suggested change
privatevoidMinMaxRgb(outintmin,outintmax,intr,intg,intb)
{
if(b<g)
{
if(b<r)
{
min=b;
max=r<g?g:r;
}
else
{
min=r;
max=g;
}
}
else
{
if(r<b)
{
max=b;
min=g<r?g:r;
}
else
{
max=r;
min=g;
}
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
privatestaticvoidMinMaxRgb(outintmin,outintmax,intr,intg,intb)
{
if(r>g)
{
max=r;
min=g;
}
else
{
max=g;
min=r;
}
if(b>max)
{
max=b;
}
elseif(b<min)
{
min=b;
}
}

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks @stephentoub , I ran the perf_color microbenchmarks against 1) before this PR changeset, 2) the current PR's changeset, 3) proposed simplification

**.NET6 Before VS .NET6 with current PR changeset: Run1** summary: better: 3, geomean: 1.151 total diff: 3

No Slower results for the provided threshold = 2% and noise filter = 25ns.

Fasterbase/diffBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetBrightness1.231549.961259.50
System.Drawing.Tests.Perf_Color.GetHue1.181753.241484.57
System.Drawing.Tests.Perf_Color.GetSaturation1.051451.591383.79
**.NET6 Before VS .NET6 with current PR changeset: Run2** summary: better: 3, geomean: 1.208 total diff: 3

No Slower results for the provided threshold = 2% and noise filter = 25ns.

Fasterbase/diffBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetBrightness1.231543.191259.71
System.Drawing.Tests.Perf_Color.GetSaturation1.221682.031384.17
System.Drawing.Tests.Perf_Color.GetHue1.181758.681485.53
**.NET6 Before VS .NET6 with current PR changeset: Run3** summary: better: 3, geomean: 1.189 total diff: 3

No Slower results for the provided threshold = 2% and noise filter = 25ns.

Fasterbase/diffBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetSaturation1.221682.421384.03
System.Drawing.Tests.Perf_Color.GetBrightness1.191497.181259.28
System.Drawing.Tests.Perf_Color.GetHue1.161725.251483.41


**.NET6 Before VS .NET6 with proposed simplification: Run1** summary: better: 2, geomean: 1.123 total diff: 2

No Slower results for the provided threshold = 2% and noise filter = 25ns.

Fasterbase/diffBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetBrightness1.131549.961375.52
System.Drawing.Tests.Perf_Color.GetHue1.121753.241565.75
**.NET6 Before VS .NET6 with proposed simplification: Run2** summary: better: 3, geomean: 1.135 total diff: 3

No Slower results for the provided threshold = 2% and noise filter = 25ns.

Fasterbase/diffBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetSaturation1.161682.031448.45
System.Drawing.Tests.Perf_Color.GetHue1.121758.681566.17
System.Drawing.Tests.Perf_Color.GetBrightness1.121543.191375.17
**.NET6 Before VS .NET6 with proposed simplification: Run3** summary: better: 2, geomean: 1.132 worse: 1, geomean: 1.050 total diff: 3
Slowerdiff/baseBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetBrightness1.051497.181572.36
Fasterbase/diffBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetSaturation1.161682.421446.59
System.Drawing.Tests.Perf_Color.GetHue1.101725.251565.42
---------------------- ----------------------

Some of the benchmarks seem to get a bit slower on average after the simplification. I think what is happening may be two causes:

  1. There are paths with an extra store (we store max & min in the first conditional and then if the second conditional is taken one of these is overwritten).
  2. Just my guess, but processor pipelining with branch prediction may find it easier to go through each of the conditionals in the current implementation as there are no dependencies. The simplification introduces a dependency on the second conditional as it needs the values from the first? Just a guess here.

I will follow yours and @safern 's recommendation on which to keep. Thanks again.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I didn't look at the disassembly but there might be an aliasing complication also, if the JIT compiler has to account for the possibility that min and max refer to the same location. Although perhaps it can disprove that after inlining.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I actually see them get faster on my machine. Regardless, though, I'd rather keep the code smaller, especially with it triplicated due to the aggressive inlining.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

One more possible improvement - using local valiables instead of out parameters:

privatestaticvoidMinMaxRgb(outintmin,outintmax,intr,intg,intb){intminLoc,maxLoc;if(r>g){maxLoc=r;minLoc=g;}else{maxLoc=g;minLoc=r;}if(b>maxLoc){maxLoc=b;}elseif(b<minLoc){minLoc=b;}max=maxLoc;min=minLoc;}

@L2L2Apr 5, 2021

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I actually see them get faster on my machine. Regardless, though, I'd rather keep the code smaller, especially with it triplicated due to the aggressive inlining.

Sounds good @stephentoub , I've updated it with the requested changes. (I'm not sure how crediting works in this project as this is my second pull request, so I've added your username to the commit details as the originator of the simplification).

One more possible improvement - using local valiables instead of out parameters:

Thanks @hypeartist, I'm wondering if these local variables will be eliminated due to inlining, so performance will be about the same?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm not sure how crediting works in this project as this is my second pull request, so I've added your username to the commit details as the originator of the simplification

Thanks, but not necessary... I comment on a lot of PRs :)

* Credit for this simplification: stephentoub
@ghostghost removed the auto-merge label Apr 5, 2021
@danmoseley

Copy link
Copy Markdown
Contributor

Thanks for the contribution @L2 - perhaps you'd like to pick up something else?

thaystg added a commit to thaystg/runtime that referenced this pull request Apr 6, 2021
…shim_mono
# By Aaron Robinson (10) and others
# Via GitHub
* upstream/main: (108 commits)
[mbr] Add Apple sample (dotnet#50740)
make EstablishProxyTunnelAsync throw on failure status code from proxy (dotnet#50763)
Improve RGB Min Max evaluation performance by using 2 or 3 comparison… (dotnet#50622)
[mono] More domain cleanups (dotnet#50479)
Fix Crossgen2 of PlatformDefaultMemberFunction methods and calls. (dotnet#50754)
Disable EventSource generator in design-time builds (dotnet#50741)
Fix X509 test failures on Android (dotnet#50301)
Do not confuse fgDispBasicBlocks in fgMorphBlocks (dotnet#50703)
Enforce 64KB event payload size limit on EventPipe (dotnet#50600)
Reorganize CoreCLR native build to reduce CMake reconfigures when the build system is untouched (dotnet#49906)
[mbr] Turn on hot reload for iOS, tvOS and MacCatalyst (dotnet#50458)
improve connection scavenge logic by doing zero-byte read (dotnet#50545)
Resolve call mdtokens when making tier 1 inline observations (dotnet#50675)
Annotate APIs in System.Private.Xml (dotnet#49682)
Support compiling against OpenSSL 3 headers
Change Configuration.Json to use a regular Dictionary. (dotnet#50611)
Remove unused BigNumFromBinary P/Invoke (dotnet#50670)
Make Ninja the default CMake generator on Windows for the repo (dotnet#49715)
[AppleAppBuilder] Entitlements to run tests on catalyst using the JIT (dotnet#50637)
[mono] Fix delegate invokes to dynamic methods in mixed mode. (dotnet#50547)
...
# Conflicts:
#	src/mono/dlls/mscordbi/CMakeLists.txt
@L2
L2 deleted the rgbMinMax branch April 6, 2021 15:05
@ghostghost locked as resolved and limited conversation to collaborators May 9, 2021
@karelzkarelz added this to the 6.0.0 milestone May 20, 2021
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Perf] Changes at 12/9/2020 1:20:52 PM

8 participants

@L2@danmoseley@iamcarbon@stephentoub@hypeartist@safern@KalleOlaviNiemitalo@karelz
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Improve RGB Min Max evaluation performance by using 2 or 3 comparison… - #50622

Merged
safern merged 5 commits into
dotnet:mainfrom
amd:rgbMinMax
Apr 6, 2021
Merged

Improve RGB Min Max evaluation performance by using 2 or 3 comparison…#50622
safern merged 5 commits into
dotnet:mainfrom
amd:rgbMinMax

Conversation

@L2

@L2L2 commented Apr 1, 2021

Copy link
Copy Markdown
Contributor

Fixes: #46153

…s instead of 4

  • Replaces 2 calls each to Math.Min and Math.Max (a total of 4 required
    comparisons) with a single call to MinMaxRgb (at least 2 required
    comparisons and at worst 3).

…s instead of 4
* Replaces 2 calls each to Math.Min and Math.Max (a total of 4 required
comparisons) with a single call to MinMaxRgb (at least 2 required
comparisons and at worst 3).
@ghost

ghost commented Apr 1, 2021

Copy link
Copy Markdown

Tagging subscribers to this area: @safern, @tarekgh
See info in area-owners.md if you want to be subscribed.

Issue Details

…s instead of 4

  • Replaces 2 calls each to Math.Min and Math.Max (a total of 4 required
    comparisons) with a single call to MinMaxRgb (at least 2 required
    comparisons and at worst 3).
Author:L2
Assignees:-
Labels:

area-System.Drawing

Milestone:-

@L2

L2 commented Apr 1, 2021

Copy link
Copy Markdown
ContributorAuthor

dotnet/performance microbenchmarks filtered with System.Drawing.Tests.Perf_Color*:

Base = .NET6 Before this changeset
Diff = .NET6 After this changeset

No Slower results for the provided threshold = 2% and noise filter = 25ns.

Fasterbase/diffBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetHue1.231756.531432.47
System.Drawing.Tests.Perf_Color.GetBrightness1.091544.741415.17
System.Drawing.Tests.Perf_Color.GetSaturation1.091602.511476.70

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void MinMaxRgb(out int min, out int max, int r, int g, int b)
{
if (b < g) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Move trailing braces to their own lines for consistency with existing .NET code.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks, updated.

@danmoseley

Copy link
Copy Markdown
Contributor

Do we have sufficient functional test coverage?

@L2

L2 commented Apr 2, 2021

Copy link
Copy Markdown
ContributorAuthor

Do we have sufficient functional test coverage?

Thanks @danmoseley . There were a couple of test cases missing which I've just added:

All Possible Cases:

label for existing testcase
(1)r == g == b
(2)r == g < b
(3)r == g > b
(4)r < g == b
(missing)r < g < b
r < g > b
(5)where [r == b]
(missing)where [r > b]
(missing)where [r < b]
(7)r > g == b
r > g < b
(6)where [r == b]
(missing)where [r > b]
(missing)where [r < b]
(missing)r > g > b

Existing Test Coverage:

test labelcase
(1)[InlineData(0, 0, 0, 0f)]
[InlineData(255, 255, 255, 1f)]
(7)[InlineData(255, 0, 0, 0.5f)]
(5)[InlineData(0, 255, 0, 0.5f)]
(2)[InlineData(0, 0, 255, 0.5f)]
(3)[InlineData(255, 255, 0, 0.5f)]
(6)[InlineData(255, 0, 255, 0.5f)]
(4)[InlineData(0, 255, 255, 0.5f)]
[InlineData(51, 255, 255, 0.6f)]
[InlineData(255, 51, 255, 0.6f)]
[InlineData(255, 255, 51, 0.6f)]
[InlineData(255, 51, 51, 0.6f)]
[InlineData(51, 255, 51, 0.6f)]
[InlineData(51, 51, 255, 0.6f)]
[InlineData(51, 51, 51, 0.2f)]

For:

public void GetBrightness(int r, int g, int b, float expected)
{
Assert.Equal(expected, Color.FromArgb(r, g, b).GetBrightness());
}

@L2

L2 commented Apr 2, 2021

Copy link
Copy Markdown
ContributorAuthor

Also I wasn't sure if I should put this new method in Math.cs and make it a general use case to find the min and max of three values so I've left it inside Color.cs for now.

@danmoseley

Copy link
Copy Markdown
Contributor

wasn't sure if I should put this new method in Math.cs

Drawing wouldn't be able to use anything from Math unless it was public: the libraries can only use each other's public surface. And to make new public API involves a review process, which would include consideration of how broadly useful the API would be. So I think it is in the right place.

Comment on lines +498 to +501
if (r < g)
max = g;
else
max = r;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We could simplify this to use ? assignment?

Suggested change
if(r<g)
max=g;
else
max=r;
max=r<g?g:r;

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks, updated.

Comment on lines +514 to +517
if (g < r)
min = g;
else
min = r;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Ditto:

Suggested change
if(g<r)
min=g;
else
min=r;
min=g<r?g:r;

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks, updated.

Comment on lines +531 to +532
int min, max;
MinMaxRgb(out min, out max, r, g, b);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
intmin,max;
MinMaxRgb(outmin,outmax,r,g,b);
MinMaxRgb(outintmin,outintmax,r,g,b);

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks, updated.

Comment on lines +544 to +545
int min, max;
MinMaxRgb(out min, out max, r, g, b);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
intmin,max;
MinMaxRgb(outmin,outmax,r,g,b);
MinMaxRgb(outintmin,outintmax,r,g,b);

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks, updated.

Comment on lines +571 to +572
int min, max;
MinMaxRgb(out min, out max, r, g, b);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
intmin,max;
MinMaxRgb(outmin,outmax,r,g,b);
MinMaxRgb(outintmin,outintmax,r,g,b);

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks, updated.

@safernsafern left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Other than small style improvements, looks good. Thanks!

@L2

L2 commented Apr 2, 2021

Copy link
Copy Markdown
ContributorAuthor

Other than small style improvements, looks good. Thanks!

Thanks @safern , I've updated it with the requested changes.

@ghost

ghost commented Apr 2, 2021

Copy link
Copy Markdown

Hello @safern!

Because this pull request has the auto-merge label, I will be glad to assist with helping to merge this pull request once all check-in policies pass.

p.s. you can customize the way I help with merging this pull request, such as holding this pull request until a specific person approves. Simply @mention me (@msftbot) and give me an instruction to get started! Learn more here.

Comment on lines +491 to +519
private void MinMaxRgb(out int min, out int max, int r, int g, int b)
{
if (b < g)
{
if (b < r)
{
min = b;
max = r < g ? g : r;
}
else
{
min = r;
max = g;
}
}
else
{
if (r < b)
{
max = b;
min = g < r ? g : r;
}
else
{
max = r;
min = g;
}
}
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This can be simplified to instead be:

Suggested change
privatevoidMinMaxRgb(outintmin,outintmax,intr,intg,intb)
{
if(b<g)
{
if(b<r)
{
min=b;
max=r<g?g:r;
}
else
{
min=r;
max=g;
}
}
else
{
if(r<b)
{
max=b;
min=g<r?g:r;
}
else
{
max=r;
min=g;
}
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
privatestaticvoidMinMaxRgb(outintmin,outintmax,intr,intg,intb)
{
if(r>g)
{
max=r;
min=g;
}
else
{
max=g;
min=r;
}
if(b>max)
{
max=b;
}
elseif(b<min)
{
min=b;
}
}

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks @stephentoub , I ran the perf_color microbenchmarks against 1) before this PR changeset, 2) the current PR's changeset, 3) proposed simplification

**.NET6 Before VS .NET6 with current PR changeset: Run1** summary: better: 3, geomean: 1.151 total diff: 3

No Slower results for the provided threshold = 2% and noise filter = 25ns.

Fasterbase/diffBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetBrightness1.231549.961259.50
System.Drawing.Tests.Perf_Color.GetHue1.181753.241484.57
System.Drawing.Tests.Perf_Color.GetSaturation1.051451.591383.79
**.NET6 Before VS .NET6 with current PR changeset: Run2** summary: better: 3, geomean: 1.208 total diff: 3

No Slower results for the provided threshold = 2% and noise filter = 25ns.

Fasterbase/diffBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetBrightness1.231543.191259.71
System.Drawing.Tests.Perf_Color.GetSaturation1.221682.031384.17
System.Drawing.Tests.Perf_Color.GetHue1.181758.681485.53
**.NET6 Before VS .NET6 with current PR changeset: Run3** summary: better: 3, geomean: 1.189 total diff: 3

No Slower results for the provided threshold = 2% and noise filter = 25ns.

Fasterbase/diffBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetSaturation1.221682.421384.03
System.Drawing.Tests.Perf_Color.GetBrightness1.191497.181259.28
System.Drawing.Tests.Perf_Color.GetHue1.161725.251483.41


**.NET6 Before VS .NET6 with proposed simplification: Run1** summary: better: 2, geomean: 1.123 total diff: 2

No Slower results for the provided threshold = 2% and noise filter = 25ns.

Fasterbase/diffBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetBrightness1.131549.961375.52
System.Drawing.Tests.Perf_Color.GetHue1.121753.241565.75
**.NET6 Before VS .NET6 with proposed simplification: Run2** summary: better: 3, geomean: 1.135 total diff: 3

No Slower results for the provided threshold = 2% and noise filter = 25ns.

Fasterbase/diffBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetSaturation1.161682.031448.45
System.Drawing.Tests.Perf_Color.GetHue1.121758.681566.17
System.Drawing.Tests.Perf_Color.GetBrightness1.121543.191375.17
**.NET6 Before VS .NET6 with proposed simplification: Run3** summary: better: 2, geomean: 1.132 worse: 1, geomean: 1.050 total diff: 3
Slowerdiff/baseBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetBrightness1.051497.181572.36
Fasterbase/diffBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetSaturation1.161682.421446.59
System.Drawing.Tests.Perf_Color.GetHue1.101725.251565.42
---------------------- ----------------------

Some of the benchmarks seem to get a bit slower on average after the simplification. I think what is happening may be two causes:

  1. There are paths with an extra store (we store max & min in the first conditional and then if the second conditional is taken one of these is overwritten).
  2. Just my guess, but processor pipelining with branch prediction may find it easier to go through each of the conditionals in the current implementation as there are no dependencies. The simplification introduces a dependency on the second conditional as it needs the values from the first? Just a guess here.

I will follow yours and @safern 's recommendation on which to keep. Thanks again.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I didn't look at the disassembly but there might be an aliasing complication also, if the JIT compiler has to account for the possibility that min and max refer to the same location. Although perhaps it can disprove that after inlining.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I actually see them get faster on my machine. Regardless, though, I'd rather keep the code smaller, especially with it triplicated due to the aggressive inlining.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

One more possible improvement - using local valiables instead of out parameters:

privatestaticvoidMinMaxRgb(outintmin,outintmax,intr,intg,intb){intminLoc,maxLoc;if(r>g){maxLoc=r;minLoc=g;}else{maxLoc=g;minLoc=r;}if(b>maxLoc){maxLoc=b;}elseif(b<minLoc){minLoc=b;}max=maxLoc;min=minLoc;}

@L2L2Apr 5, 2021

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I actually see them get faster on my machine. Regardless, though, I'd rather keep the code smaller, especially with it triplicated due to the aggressive inlining.

Sounds good @stephentoub , I've updated it with the requested changes. (I'm not sure how crediting works in this project as this is my second pull request, so I've added your username to the commit details as the originator of the simplification).

One more possible improvement - using local valiables instead of out parameters:

Thanks @hypeartist, I'm wondering if these local variables will be eliminated due to inlining, so performance will be about the same?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm not sure how crediting works in this project as this is my second pull request, so I've added your username to the commit details as the originator of the simplification

Thanks, but not necessary... I comment on a lot of PRs :)

* Credit for this simplification: stephentoub
@ghostghost removed the auto-merge label Apr 5, 2021
@danmoseley

Copy link
Copy Markdown
Contributor

Thanks for the contribution @L2 - perhaps you'd like to pick up something else?

thaystg added a commit to thaystg/runtime that referenced this pull request Apr 6, 2021
…shim_mono
# By Aaron Robinson (10) and others
# Via GitHub
* upstream/main: (108 commits)
[mbr] Add Apple sample (dotnet#50740)
make EstablishProxyTunnelAsync throw on failure status code from proxy (dotnet#50763)
Improve RGB Min Max evaluation performance by using 2 or 3 comparison… (dotnet#50622)
[mono] More domain cleanups (dotnet#50479)
Fix Crossgen2 of PlatformDefaultMemberFunction methods and calls. (dotnet#50754)
Disable EventSource generator in design-time builds (dotnet#50741)
Fix X509 test failures on Android (dotnet#50301)
Do not confuse fgDispBasicBlocks in fgMorphBlocks (dotnet#50703)
Enforce 64KB event payload size limit on EventPipe (dotnet#50600)
Reorganize CoreCLR native build to reduce CMake reconfigures when the build system is untouched (dotnet#49906)
[mbr] Turn on hot reload for iOS, tvOS and MacCatalyst (dotnet#50458)
improve connection scavenge logic by doing zero-byte read (dotnet#50545)
Resolve call mdtokens when making tier 1 inline observations (dotnet#50675)
Annotate APIs in System.Private.Xml (dotnet#49682)
Support compiling against OpenSSL 3 headers
Change Configuration.Json to use a regular Dictionary. (dotnet#50611)
Remove unused BigNumFromBinary P/Invoke (dotnet#50670)
Make Ninja the default CMake generator on Windows for the repo (dotnet#49715)
[AppleAppBuilder] Entitlements to run tests on catalyst using the JIT (dotnet#50637)
[mono] Fix delegate invokes to dynamic methods in mixed mode. (dotnet#50547)
...
# Conflicts:
#	src/mono/dlls/mscordbi/CMakeLists.txt
@L2
L2 deleted the rgbMinMax branch April 6, 2021 15:05
@ghostghost locked as resolved and limited conversation to collaborators May 9, 2021
@karelzkarelz added this to the 6.0.0 milestone May 20, 2021
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Perf] Changes at 12/9/2020 1:20:52 PM

8 participants

@L2@danmoseley@iamcarbon@stephentoub@hypeartist@safern@KalleOlaviNiemitalo@karelz
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Improve RGB Min Max evaluation performance by using 2 or 3 comparison… - #50622

Merged
safern merged 5 commits into
dotnet:mainfrom
amd:rgbMinMax
Apr 6, 2021
Merged

Improve RGB Min Max evaluation performance by using 2 or 3 comparison…#50622
safern merged 5 commits into
dotnet:mainfrom
amd:rgbMinMax

Conversation

@L2

@L2L2 commented Apr 1, 2021

Copy link
Copy Markdown
Contributor

Fixes: #46153

…s instead of 4

  • Replaces 2 calls each to Math.Min and Math.Max (a total of 4 required
    comparisons) with a single call to MinMaxRgb (at least 2 required
    comparisons and at worst 3).

…s instead of 4
* Replaces 2 calls each to Math.Min and Math.Max (a total of 4 required
comparisons) with a single call to MinMaxRgb (at least 2 required
comparisons and at worst 3).
@ghost

ghost commented Apr 1, 2021

Copy link
Copy Markdown

Tagging subscribers to this area: @safern, @tarekgh
See info in area-owners.md if you want to be subscribed.

Issue Details

…s instead of 4

  • Replaces 2 calls each to Math.Min and Math.Max (a total of 4 required
    comparisons) with a single call to MinMaxRgb (at least 2 required
    comparisons and at worst 3).
Author:L2
Assignees:-
Labels:

area-System.Drawing

Milestone:-

@L2

L2 commented Apr 1, 2021

Copy link
Copy Markdown
ContributorAuthor

dotnet/performance microbenchmarks filtered with System.Drawing.Tests.Perf_Color*:

Base = .NET6 Before this changeset
Diff = .NET6 After this changeset

No Slower results for the provided threshold = 2% and noise filter = 25ns.

Fasterbase/diffBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetHue1.231756.531432.47
System.Drawing.Tests.Perf_Color.GetBrightness1.091544.741415.17
System.Drawing.Tests.Perf_Color.GetSaturation1.091602.511476.70

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void MinMaxRgb(out int min, out int max, int r, int g, int b)
{
if (b < g) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Move trailing braces to their own lines for consistency with existing .NET code.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks, updated.

@danmoseley

Copy link
Copy Markdown
Contributor

Do we have sufficient functional test coverage?

@L2

L2 commented Apr 2, 2021

Copy link
Copy Markdown
ContributorAuthor

Do we have sufficient functional test coverage?

Thanks @danmoseley . There were a couple of test cases missing which I've just added:

All Possible Cases:

label for existing testcase
(1)r == g == b
(2)r == g < b
(3)r == g > b
(4)r < g == b
(missing)r < g < b
r < g > b
(5)where [r == b]
(missing)where [r > b]
(missing)where [r < b]
(7)r > g == b
r > g < b
(6)where [r == b]
(missing)where [r > b]
(missing)where [r < b]
(missing)r > g > b

Existing Test Coverage:

test labelcase
(1)[InlineData(0, 0, 0, 0f)]
[InlineData(255, 255, 255, 1f)]
(7)[InlineData(255, 0, 0, 0.5f)]
(5)[InlineData(0, 255, 0, 0.5f)]
(2)[InlineData(0, 0, 255, 0.5f)]
(3)[InlineData(255, 255, 0, 0.5f)]
(6)[InlineData(255, 0, 255, 0.5f)]
(4)[InlineData(0, 255, 255, 0.5f)]
[InlineData(51, 255, 255, 0.6f)]
[InlineData(255, 51, 255, 0.6f)]
[InlineData(255, 255, 51, 0.6f)]
[InlineData(255, 51, 51, 0.6f)]
[InlineData(51, 255, 51, 0.6f)]
[InlineData(51, 51, 255, 0.6f)]
[InlineData(51, 51, 51, 0.2f)]

For:

public void GetBrightness(int r, int g, int b, float expected)
{
Assert.Equal(expected, Color.FromArgb(r, g, b).GetBrightness());
}

@L2

L2 commented Apr 2, 2021

Copy link
Copy Markdown
ContributorAuthor

Also I wasn't sure if I should put this new method in Math.cs and make it a general use case to find the min and max of three values so I've left it inside Color.cs for now.

@danmoseley

Copy link
Copy Markdown
Contributor

wasn't sure if I should put this new method in Math.cs

Drawing wouldn't be able to use anything from Math unless it was public: the libraries can only use each other's public surface. And to make new public API involves a review process, which would include consideration of how broadly useful the API would be. So I think it is in the right place.

Comment on lines +498 to +501
if (r < g)
max = g;
else
max = r;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We could simplify this to use ? assignment?

Suggested change
if(r<g)
max=g;
else
max=r;
max=r<g?g:r;

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks, updated.

Comment on lines +514 to +517
if (g < r)
min = g;
else
min = r;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Ditto:

Suggested change
if(g<r)
min=g;
else
min=r;
min=g<r?g:r;

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks, updated.

Comment on lines +531 to +532
int min, max;
MinMaxRgb(out min, out max, r, g, b);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
intmin,max;
MinMaxRgb(outmin,outmax,r,g,b);
MinMaxRgb(outintmin,outintmax,r,g,b);

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks, updated.

Comment on lines +544 to +545
int min, max;
MinMaxRgb(out min, out max, r, g, b);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
intmin,max;
MinMaxRgb(outmin,outmax,r,g,b);
MinMaxRgb(outintmin,outintmax,r,g,b);

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks, updated.

Comment on lines +571 to +572
int min, max;
MinMaxRgb(out min, out max, r, g, b);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
intmin,max;
MinMaxRgb(outmin,outmax,r,g,b);
MinMaxRgb(outintmin,outintmax,r,g,b);

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks, updated.

@safernsafern left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Other than small style improvements, looks good. Thanks!

@L2

L2 commented Apr 2, 2021

Copy link
Copy Markdown
ContributorAuthor

Other than small style improvements, looks good. Thanks!

Thanks @safern , I've updated it with the requested changes.

@ghost

ghost commented Apr 2, 2021

Copy link
Copy Markdown

Hello @safern!

Because this pull request has the auto-merge label, I will be glad to assist with helping to merge this pull request once all check-in policies pass.

p.s. you can customize the way I help with merging this pull request, such as holding this pull request until a specific person approves. Simply @mention me (@msftbot) and give me an instruction to get started! Learn more here.

Comment on lines +491 to +519
private void MinMaxRgb(out int min, out int max, int r, int g, int b)
{
if (b < g)
{
if (b < r)
{
min = b;
max = r < g ? g : r;
}
else
{
min = r;
max = g;
}
}
else
{
if (r < b)
{
max = b;
min = g < r ? g : r;
}
else
{
max = r;
min = g;
}
}
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This can be simplified to instead be:

Suggested change
privatevoidMinMaxRgb(outintmin,outintmax,intr,intg,intb)
{
if(b<g)
{
if(b<r)
{
min=b;
max=r<g?g:r;
}
else
{
min=r;
max=g;
}
}
else
{
if(r<b)
{
max=b;
min=g<r?g:r;
}
else
{
max=r;
min=g;
}
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
privatestaticvoidMinMaxRgb(outintmin,outintmax,intr,intg,intb)
{
if(r>g)
{
max=r;
min=g;
}
else
{
max=g;
min=r;
}
if(b>max)
{
max=b;
}
elseif(b<min)
{
min=b;
}
}

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks @stephentoub , I ran the perf_color microbenchmarks against 1) before this PR changeset, 2) the current PR's changeset, 3) proposed simplification

**.NET6 Before VS .NET6 with current PR changeset: Run1** summary: better: 3, geomean: 1.151 total diff: 3

No Slower results for the provided threshold = 2% and noise filter = 25ns.

Fasterbase/diffBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetBrightness1.231549.961259.50
System.Drawing.Tests.Perf_Color.GetHue1.181753.241484.57
System.Drawing.Tests.Perf_Color.GetSaturation1.051451.591383.79
**.NET6 Before VS .NET6 with current PR changeset: Run2** summary: better: 3, geomean: 1.208 total diff: 3

No Slower results for the provided threshold = 2% and noise filter = 25ns.

Fasterbase/diffBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetBrightness1.231543.191259.71
System.Drawing.Tests.Perf_Color.GetSaturation1.221682.031384.17
System.Drawing.Tests.Perf_Color.GetHue1.181758.681485.53
**.NET6 Before VS .NET6 with current PR changeset: Run3** summary: better: 3, geomean: 1.189 total diff: 3

No Slower results for the provided threshold = 2% and noise filter = 25ns.

Fasterbase/diffBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetSaturation1.221682.421384.03
System.Drawing.Tests.Perf_Color.GetBrightness1.191497.181259.28
System.Drawing.Tests.Perf_Color.GetHue1.161725.251483.41


**.NET6 Before VS .NET6 with proposed simplification: Run1** summary: better: 2, geomean: 1.123 total diff: 2

No Slower results for the provided threshold = 2% and noise filter = 25ns.

Fasterbase/diffBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetBrightness1.131549.961375.52
System.Drawing.Tests.Perf_Color.GetHue1.121753.241565.75
**.NET6 Before VS .NET6 with proposed simplification: Run2** summary: better: 3, geomean: 1.135 total diff: 3

No Slower results for the provided threshold = 2% and noise filter = 25ns.

Fasterbase/diffBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetSaturation1.161682.031448.45
System.Drawing.Tests.Perf_Color.GetHue1.121758.681566.17
System.Drawing.Tests.Perf_Color.GetBrightness1.121543.191375.17
**.NET6 Before VS .NET6 with proposed simplification: Run3** summary: better: 2, geomean: 1.132 worse: 1, geomean: 1.050 total diff: 3
Slowerdiff/baseBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetBrightness1.051497.181572.36
Fasterbase/diffBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetSaturation1.161682.421446.59
System.Drawing.Tests.Perf_Color.GetHue1.101725.251565.42
---------------------- ----------------------

Some of the benchmarks seem to get a bit slower on average after the simplification. I think what is happening may be two causes:

  1. There are paths with an extra store (we store max & min in the first conditional and then if the second conditional is taken one of these is overwritten).
  2. Just my guess, but processor pipelining with branch prediction may find it easier to go through each of the conditionals in the current implementation as there are no dependencies. The simplification introduces a dependency on the second conditional as it needs the values from the first? Just a guess here.

I will follow yours and @safern 's recommendation on which to keep. Thanks again.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I didn't look at the disassembly but there might be an aliasing complication also, if the JIT compiler has to account for the possibility that min and max refer to the same location. Although perhaps it can disprove that after inlining.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I actually see them get faster on my machine. Regardless, though, I'd rather keep the code smaller, especially with it triplicated due to the aggressive inlining.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

One more possible improvement - using local valiables instead of out parameters:

privatestaticvoidMinMaxRgb(outintmin,outintmax,intr,intg,intb){intminLoc,maxLoc;if(r>g){maxLoc=r;minLoc=g;}else{maxLoc=g;minLoc=r;}if(b>maxLoc){maxLoc=b;}elseif(b<minLoc){minLoc=b;}max=maxLoc;min=minLoc;}

@L2L2Apr 5, 2021

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I actually see them get faster on my machine. Regardless, though, I'd rather keep the code smaller, especially with it triplicated due to the aggressive inlining.

Sounds good @stephentoub , I've updated it with the requested changes. (I'm not sure how crediting works in this project as this is my second pull request, so I've added your username to the commit details as the originator of the simplification).

One more possible improvement - using local valiables instead of out parameters:

Thanks @hypeartist, I'm wondering if these local variables will be eliminated due to inlining, so performance will be about the same?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm not sure how crediting works in this project as this is my second pull request, so I've added your username to the commit details as the originator of the simplification

Thanks, but not necessary... I comment on a lot of PRs :)

* Credit for this simplification: stephentoub
@ghostghost removed the auto-merge label Apr 5, 2021
@danmoseley

Copy link
Copy Markdown
Contributor

Thanks for the contribution @L2 - perhaps you'd like to pick up something else?

thaystg added a commit to thaystg/runtime that referenced this pull request Apr 6, 2021
…shim_mono
# By Aaron Robinson (10) and others
# Via GitHub
* upstream/main: (108 commits)
[mbr] Add Apple sample (dotnet#50740)
make EstablishProxyTunnelAsync throw on failure status code from proxy (dotnet#50763)
Improve RGB Min Max evaluation performance by using 2 or 3 comparison… (dotnet#50622)
[mono] More domain cleanups (dotnet#50479)
Fix Crossgen2 of PlatformDefaultMemberFunction methods and calls. (dotnet#50754)
Disable EventSource generator in design-time builds (dotnet#50741)
Fix X509 test failures on Android (dotnet#50301)
Do not confuse fgDispBasicBlocks in fgMorphBlocks (dotnet#50703)
Enforce 64KB event payload size limit on EventPipe (dotnet#50600)
Reorganize CoreCLR native build to reduce CMake reconfigures when the build system is untouched (dotnet#49906)
[mbr] Turn on hot reload for iOS, tvOS and MacCatalyst (dotnet#50458)
improve connection scavenge logic by doing zero-byte read (dotnet#50545)
Resolve call mdtokens when making tier 1 inline observations (dotnet#50675)
Annotate APIs in System.Private.Xml (dotnet#49682)
Support compiling against OpenSSL 3 headers
Change Configuration.Json to use a regular Dictionary. (dotnet#50611)
Remove unused BigNumFromBinary P/Invoke (dotnet#50670)
Make Ninja the default CMake generator on Windows for the repo (dotnet#49715)
[AppleAppBuilder] Entitlements to run tests on catalyst using the JIT (dotnet#50637)
[mono] Fix delegate invokes to dynamic methods in mixed mode. (dotnet#50547)
...
# Conflicts:
#	src/mono/dlls/mscordbi/CMakeLists.txt
@L2
L2 deleted the rgbMinMax branch April 6, 2021 15:05
@ghostghost locked as resolved and limited conversation to collaborators May 9, 2021
@karelzkarelz added this to the 6.0.0 milestone May 20, 2021
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Perf] Changes at 12/9/2020 1:20:52 PM

8 participants

@L2@danmoseley@iamcarbon@stephentoub@hypeartist@safern@KalleOlaviNiemitalo@karelz
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Improve RGB Min Max evaluation performance by using 2 or 3 comparison… - #50622

Merged
safern merged 5 commits into
dotnet:mainfrom
amd:rgbMinMax
Apr 6, 2021
Merged

Improve RGB Min Max evaluation performance by using 2 or 3 comparison…#50622
safern merged 5 commits into
dotnet:mainfrom
amd:rgbMinMax

Conversation

@L2

@L2L2 commented Apr 1, 2021

Copy link
Copy Markdown
Contributor

Fixes: #46153

…s instead of 4

  • Replaces 2 calls each to Math.Min and Math.Max (a total of 4 required
    comparisons) with a single call to MinMaxRgb (at least 2 required
    comparisons and at worst 3).

…s instead of 4
* Replaces 2 calls each to Math.Min and Math.Max (a total of 4 required
comparisons) with a single call to MinMaxRgb (at least 2 required
comparisons and at worst 3).
@ghost

ghost commented Apr 1, 2021

Copy link
Copy Markdown

Tagging subscribers to this area: @safern, @tarekgh
See info in area-owners.md if you want to be subscribed.

Issue Details

…s instead of 4

  • Replaces 2 calls each to Math.Min and Math.Max (a total of 4 required
    comparisons) with a single call to MinMaxRgb (at least 2 required
    comparisons and at worst 3).
Author:L2
Assignees:-
Labels:

area-System.Drawing

Milestone:-

@L2

L2 commented Apr 1, 2021

Copy link
Copy Markdown
ContributorAuthor

dotnet/performance microbenchmarks filtered with System.Drawing.Tests.Perf_Color*:

Base = .NET6 Before this changeset
Diff = .NET6 After this changeset

No Slower results for the provided threshold = 2% and noise filter = 25ns.

Fasterbase/diffBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetHue1.231756.531432.47
System.Drawing.Tests.Perf_Color.GetBrightness1.091544.741415.17
System.Drawing.Tests.Perf_Color.GetSaturation1.091602.511476.70

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void MinMaxRgb(out int min, out int max, int r, int g, int b)
{
if (b < g) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Move trailing braces to their own lines for consistency with existing .NET code.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks, updated.

@danmoseley

Copy link
Copy Markdown
Contributor

Do we have sufficient functional test coverage?

@L2

L2 commented Apr 2, 2021

Copy link
Copy Markdown
ContributorAuthor

Do we have sufficient functional test coverage?

Thanks @danmoseley . There were a couple of test cases missing which I've just added:

All Possible Cases:

label for existing testcase
(1)r == g == b
(2)r == g < b
(3)r == g > b
(4)r < g == b
(missing)r < g < b
r < g > b
(5)where [r == b]
(missing)where [r > b]
(missing)where [r < b]
(7)r > g == b
r > g < b
(6)where [r == b]
(missing)where [r > b]
(missing)where [r < b]
(missing)r > g > b

Existing Test Coverage:

test labelcase
(1)[InlineData(0, 0, 0, 0f)]
[InlineData(255, 255, 255, 1f)]
(7)[InlineData(255, 0, 0, 0.5f)]
(5)[InlineData(0, 255, 0, 0.5f)]
(2)[InlineData(0, 0, 255, 0.5f)]
(3)[InlineData(255, 255, 0, 0.5f)]
(6)[InlineData(255, 0, 255, 0.5f)]
(4)[InlineData(0, 255, 255, 0.5f)]
[InlineData(51, 255, 255, 0.6f)]
[InlineData(255, 51, 255, 0.6f)]
[InlineData(255, 255, 51, 0.6f)]
[InlineData(255, 51, 51, 0.6f)]
[InlineData(51, 255, 51, 0.6f)]
[InlineData(51, 51, 255, 0.6f)]
[InlineData(51, 51, 51, 0.2f)]

For:

public void GetBrightness(int r, int g, int b, float expected)
{
Assert.Equal(expected, Color.FromArgb(r, g, b).GetBrightness());
}

@L2

L2 commented Apr 2, 2021

Copy link
Copy Markdown
ContributorAuthor

Also I wasn't sure if I should put this new method in Math.cs and make it a general use case to find the min and max of three values so I've left it inside Color.cs for now.

@danmoseley

Copy link
Copy Markdown
Contributor

wasn't sure if I should put this new method in Math.cs

Drawing wouldn't be able to use anything from Math unless it was public: the libraries can only use each other's public surface. And to make new public API involves a review process, which would include consideration of how broadly useful the API would be. So I think it is in the right place.

Comment on lines +498 to +501
if (r < g)
max = g;
else
max = r;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We could simplify this to use ? assignment?

Suggested change
if(r<g)
max=g;
else
max=r;
max=r<g?g:r;

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks, updated.

Comment on lines +514 to +517
if (g < r)
min = g;
else
min = r;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Ditto:

Suggested change
if(g<r)
min=g;
else
min=r;
min=g<r?g:r;

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks, updated.

Comment on lines +531 to +532
int min, max;
MinMaxRgb(out min, out max, r, g, b);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
intmin,max;
MinMaxRgb(outmin,outmax,r,g,b);
MinMaxRgb(outintmin,outintmax,r,g,b);

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks, updated.

Comment on lines +544 to +545
int min, max;
MinMaxRgb(out min, out max, r, g, b);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
intmin,max;
MinMaxRgb(outmin,outmax,r,g,b);
MinMaxRgb(outintmin,outintmax,r,g,b);

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks, updated.

Comment on lines +571 to +572
int min, max;
MinMaxRgb(out min, out max, r, g, b);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
intmin,max;
MinMaxRgb(outmin,outmax,r,g,b);
MinMaxRgb(outintmin,outintmax,r,g,b);

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks, updated.

@safernsafern left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Other than small style improvements, looks good. Thanks!

@L2

L2 commented Apr 2, 2021

Copy link
Copy Markdown
ContributorAuthor

Other than small style improvements, looks good. Thanks!

Thanks @safern , I've updated it with the requested changes.

@ghost

ghost commented Apr 2, 2021

Copy link
Copy Markdown

Hello @safern!

Because this pull request has the auto-merge label, I will be glad to assist with helping to merge this pull request once all check-in policies pass.

p.s. you can customize the way I help with merging this pull request, such as holding this pull request until a specific person approves. Simply @mention me (@msftbot) and give me an instruction to get started! Learn more here.

Comment on lines +491 to +519
private void MinMaxRgb(out int min, out int max, int r, int g, int b)
{
if (b < g)
{
if (b < r)
{
min = b;
max = r < g ? g : r;
}
else
{
min = r;
max = g;
}
}
else
{
if (r < b)
{
max = b;
min = g < r ? g : r;
}
else
{
max = r;
min = g;
}
}
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This can be simplified to instead be:

Suggested change
privatevoidMinMaxRgb(outintmin,outintmax,intr,intg,intb)
{
if(b<g)
{
if(b<r)
{
min=b;
max=r<g?g:r;
}
else
{
min=r;
max=g;
}
}
else
{
if(r<b)
{
max=b;
min=g<r?g:r;
}
else
{
max=r;
min=g;
}
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
privatestaticvoidMinMaxRgb(outintmin,outintmax,intr,intg,intb)
{
if(r>g)
{
max=r;
min=g;
}
else
{
max=g;
min=r;
}
if(b>max)
{
max=b;
}
elseif(b<min)
{
min=b;
}
}

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks @stephentoub , I ran the perf_color microbenchmarks against 1) before this PR changeset, 2) the current PR's changeset, 3) proposed simplification

**.NET6 Before VS .NET6 with current PR changeset: Run1** summary: better: 3, geomean: 1.151 total diff: 3

No Slower results for the provided threshold = 2% and noise filter = 25ns.

Fasterbase/diffBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetBrightness1.231549.961259.50
System.Drawing.Tests.Perf_Color.GetHue1.181753.241484.57
System.Drawing.Tests.Perf_Color.GetSaturation1.051451.591383.79
**.NET6 Before VS .NET6 with current PR changeset: Run2** summary: better: 3, geomean: 1.208 total diff: 3

No Slower results for the provided threshold = 2% and noise filter = 25ns.

Fasterbase/diffBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetBrightness1.231543.191259.71
System.Drawing.Tests.Perf_Color.GetSaturation1.221682.031384.17
System.Drawing.Tests.Perf_Color.GetHue1.181758.681485.53
**.NET6 Before VS .NET6 with current PR changeset: Run3** summary: better: 3, geomean: 1.189 total diff: 3

No Slower results for the provided threshold = 2% and noise filter = 25ns.

Fasterbase/diffBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetSaturation1.221682.421384.03
System.Drawing.Tests.Perf_Color.GetBrightness1.191497.181259.28
System.Drawing.Tests.Perf_Color.GetHue1.161725.251483.41


**.NET6 Before VS .NET6 with proposed simplification: Run1** summary: better: 2, geomean: 1.123 total diff: 2

No Slower results for the provided threshold = 2% and noise filter = 25ns.

Fasterbase/diffBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetBrightness1.131549.961375.52
System.Drawing.Tests.Perf_Color.GetHue1.121753.241565.75
**.NET6 Before VS .NET6 with proposed simplification: Run2** summary: better: 3, geomean: 1.135 total diff: 3

No Slower results for the provided threshold = 2% and noise filter = 25ns.

Fasterbase/diffBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetSaturation1.161682.031448.45
System.Drawing.Tests.Perf_Color.GetHue1.121758.681566.17
System.Drawing.Tests.Perf_Color.GetBrightness1.121543.191375.17
**.NET6 Before VS .NET6 with proposed simplification: Run3** summary: better: 2, geomean: 1.132 worse: 1, geomean: 1.050 total diff: 3
Slowerdiff/baseBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetBrightness1.051497.181572.36
Fasterbase/diffBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetSaturation1.161682.421446.59
System.Drawing.Tests.Perf_Color.GetHue1.101725.251565.42
---------------------- ----------------------

Some of the benchmarks seem to get a bit slower on average after the simplification. I think what is happening may be two causes:

  1. There are paths with an extra store (we store max & min in the first conditional and then if the second conditional is taken one of these is overwritten).
  2. Just my guess, but processor pipelining with branch prediction may find it easier to go through each of the conditionals in the current implementation as there are no dependencies. The simplification introduces a dependency on the second conditional as it needs the values from the first? Just a guess here.

I will follow yours and @safern 's recommendation on which to keep. Thanks again.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I didn't look at the disassembly but there might be an aliasing complication also, if the JIT compiler has to account for the possibility that min and max refer to the same location. Although perhaps it can disprove that after inlining.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I actually see them get faster on my machine. Regardless, though, I'd rather keep the code smaller, especially with it triplicated due to the aggressive inlining.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

One more possible improvement - using local valiables instead of out parameters:

privatestaticvoidMinMaxRgb(outintmin,outintmax,intr,intg,intb){intminLoc,maxLoc;if(r>g){maxLoc=r;minLoc=g;}else{maxLoc=g;minLoc=r;}if(b>maxLoc){maxLoc=b;}elseif(b<minLoc){minLoc=b;}max=maxLoc;min=minLoc;}

@L2L2Apr 5, 2021

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I actually see them get faster on my machine. Regardless, though, I'd rather keep the code smaller, especially with it triplicated due to the aggressive inlining.

Sounds good @stephentoub , I've updated it with the requested changes. (I'm not sure how crediting works in this project as this is my second pull request, so I've added your username to the commit details as the originator of the simplification).

One more possible improvement - using local valiables instead of out parameters:

Thanks @hypeartist, I'm wondering if these local variables will be eliminated due to inlining, so performance will be about the same?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm not sure how crediting works in this project as this is my second pull request, so I've added your username to the commit details as the originator of the simplification

Thanks, but not necessary... I comment on a lot of PRs :)

* Credit for this simplification: stephentoub
@ghostghost removed the auto-merge label Apr 5, 2021
@danmoseley

Copy link
Copy Markdown
Contributor

Thanks for the contribution @L2 - perhaps you'd like to pick up something else?

thaystg added a commit to thaystg/runtime that referenced this pull request Apr 6, 2021
…shim_mono
# By Aaron Robinson (10) and others
# Via GitHub
* upstream/main: (108 commits)
[mbr] Add Apple sample (dotnet#50740)
make EstablishProxyTunnelAsync throw on failure status code from proxy (dotnet#50763)
Improve RGB Min Max evaluation performance by using 2 or 3 comparison… (dotnet#50622)
[mono] More domain cleanups (dotnet#50479)
Fix Crossgen2 of PlatformDefaultMemberFunction methods and calls. (dotnet#50754)
Disable EventSource generator in design-time builds (dotnet#50741)
Fix X509 test failures on Android (dotnet#50301)
Do not confuse fgDispBasicBlocks in fgMorphBlocks (dotnet#50703)
Enforce 64KB event payload size limit on EventPipe (dotnet#50600)
Reorganize CoreCLR native build to reduce CMake reconfigures when the build system is untouched (dotnet#49906)
[mbr] Turn on hot reload for iOS, tvOS and MacCatalyst (dotnet#50458)
improve connection scavenge logic by doing zero-byte read (dotnet#50545)
Resolve call mdtokens when making tier 1 inline observations (dotnet#50675)
Annotate APIs in System.Private.Xml (dotnet#49682)
Support compiling against OpenSSL 3 headers
Change Configuration.Json to use a regular Dictionary. (dotnet#50611)
Remove unused BigNumFromBinary P/Invoke (dotnet#50670)
Make Ninja the default CMake generator on Windows for the repo (dotnet#49715)
[AppleAppBuilder] Entitlements to run tests on catalyst using the JIT (dotnet#50637)
[mono] Fix delegate invokes to dynamic methods in mixed mode. (dotnet#50547)
...
# Conflicts:
#	src/mono/dlls/mscordbi/CMakeLists.txt
@L2
L2 deleted the rgbMinMax branch April 6, 2021 15:05
@ghostghost locked as resolved and limited conversation to collaborators May 9, 2021
@karelzkarelz added this to the 6.0.0 milestone May 20, 2021
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Perf] Changes at 12/9/2020 1:20:52 PM

8 participants

@L2@danmoseley@iamcarbon@stephentoub@hypeartist@safern@KalleOlaviNiemitalo@karelz
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Improve RGB Min Max evaluation performance by using 2 or 3 comparison… - #50622

Merged
safern merged 5 commits into
dotnet:mainfrom
amd:rgbMinMax
Apr 6, 2021
Merged

Improve RGB Min Max evaluation performance by using 2 or 3 comparison…#50622
safern merged 5 commits into
dotnet:mainfrom
amd:rgbMinMax

Conversation

@L2

@L2L2 commented Apr 1, 2021

Copy link
Copy Markdown
Contributor

Fixes: #46153

…s instead of 4

  • Replaces 2 calls each to Math.Min and Math.Max (a total of 4 required
    comparisons) with a single call to MinMaxRgb (at least 2 required
    comparisons and at worst 3).

…s instead of 4
* Replaces 2 calls each to Math.Min and Math.Max (a total of 4 required
comparisons) with a single call to MinMaxRgb (at least 2 required
comparisons and at worst 3).
@ghost

ghost commented Apr 1, 2021

Copy link
Copy Markdown

Tagging subscribers to this area: @safern, @tarekgh
See info in area-owners.md if you want to be subscribed.

Issue Details

…s instead of 4

  • Replaces 2 calls each to Math.Min and Math.Max (a total of 4 required
    comparisons) with a single call to MinMaxRgb (at least 2 required
    comparisons and at worst 3).
Author:L2
Assignees:-
Labels:

area-System.Drawing

Milestone:-

@L2

L2 commented Apr 1, 2021

Copy link
Copy Markdown
ContributorAuthor

dotnet/performance microbenchmarks filtered with System.Drawing.Tests.Perf_Color*:

Base = .NET6 Before this changeset
Diff = .NET6 After this changeset

No Slower results for the provided threshold = 2% and noise filter = 25ns.

Fasterbase/diffBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetHue1.231756.531432.47
System.Drawing.Tests.Perf_Color.GetBrightness1.091544.741415.17
System.Drawing.Tests.Perf_Color.GetSaturation1.091602.511476.70

[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void MinMaxRgb(out int min, out int max, int r, int g, int b)
{
if (b < g) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Move trailing braces to their own lines for consistency with existing .NET code.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks, updated.

@danmoseley

Copy link
Copy Markdown
Contributor

Do we have sufficient functional test coverage?

@L2

L2 commented Apr 2, 2021

Copy link
Copy Markdown
ContributorAuthor

Do we have sufficient functional test coverage?

Thanks @danmoseley . There were a couple of test cases missing which I've just added:

All Possible Cases:

label for existing testcase
(1)r == g == b
(2)r == g < b
(3)r == g > b
(4)r < g == b
(missing)r < g < b
r < g > b
(5)where [r == b]
(missing)where [r > b]
(missing)where [r < b]
(7)r > g == b
r > g < b
(6)where [r == b]
(missing)where [r > b]
(missing)where [r < b]
(missing)r > g > b

Existing Test Coverage:

test labelcase
(1)[InlineData(0, 0, 0, 0f)]
[InlineData(255, 255, 255, 1f)]
(7)[InlineData(255, 0, 0, 0.5f)]
(5)[InlineData(0, 255, 0, 0.5f)]
(2)[InlineData(0, 0, 255, 0.5f)]
(3)[InlineData(255, 255, 0, 0.5f)]
(6)[InlineData(255, 0, 255, 0.5f)]
(4)[InlineData(0, 255, 255, 0.5f)]
[InlineData(51, 255, 255, 0.6f)]
[InlineData(255, 51, 255, 0.6f)]
[InlineData(255, 255, 51, 0.6f)]
[InlineData(255, 51, 51, 0.6f)]
[InlineData(51, 255, 51, 0.6f)]
[InlineData(51, 51, 255, 0.6f)]
[InlineData(51, 51, 51, 0.2f)]

For:

public void GetBrightness(int r, int g, int b, float expected)
{
Assert.Equal(expected, Color.FromArgb(r, g, b).GetBrightness());
}

@L2

L2 commented Apr 2, 2021

Copy link
Copy Markdown
ContributorAuthor

Also I wasn't sure if I should put this new method in Math.cs and make it a general use case to find the min and max of three values so I've left it inside Color.cs for now.

@danmoseley

Copy link
Copy Markdown
Contributor

wasn't sure if I should put this new method in Math.cs

Drawing wouldn't be able to use anything from Math unless it was public: the libraries can only use each other's public surface. And to make new public API involves a review process, which would include consideration of how broadly useful the API would be. So I think it is in the right place.

Comment on lines +498 to +501
if (r < g)
max = g;
else
max = r;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We could simplify this to use ? assignment?

Suggested change
if(r<g)
max=g;
else
max=r;
max=r<g?g:r;

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks, updated.

Comment on lines +514 to +517
if (g < r)
min = g;
else
min = r;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Ditto:

Suggested change
if(g<r)
min=g;
else
min=r;
min=g<r?g:r;

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks, updated.

Comment on lines +531 to +532
int min, max;
MinMaxRgb(out min, out max, r, g, b);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
intmin,max;
MinMaxRgb(outmin,outmax,r,g,b);
MinMaxRgb(outintmin,outintmax,r,g,b);

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks, updated.

Comment on lines +544 to +545
int min, max;
MinMaxRgb(out min, out max, r, g, b);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
intmin,max;
MinMaxRgb(outmin,outmax,r,g,b);
MinMaxRgb(outintmin,outintmax,r,g,b);

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks, updated.

Comment on lines +571 to +572
int min, max;
MinMaxRgb(out min, out max, r, g, b);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
intmin,max;
MinMaxRgb(outmin,outmax,r,g,b);
MinMaxRgb(outintmin,outintmax,r,g,b);

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks, updated.

@safernsafern left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Other than small style improvements, looks good. Thanks!

@L2

L2 commented Apr 2, 2021

Copy link
Copy Markdown
ContributorAuthor

Other than small style improvements, looks good. Thanks!

Thanks @safern , I've updated it with the requested changes.

@ghost

ghost commented Apr 2, 2021

Copy link
Copy Markdown

Hello @safern!

Because this pull request has the auto-merge label, I will be glad to assist with helping to merge this pull request once all check-in policies pass.

p.s. you can customize the way I help with merging this pull request, such as holding this pull request until a specific person approves. Simply @mention me (@msftbot) and give me an instruction to get started! Learn more here.

Comment on lines +491 to +519
private void MinMaxRgb(out int min, out int max, int r, int g, int b)
{
if (b < g)
{
if (b < r)
{
min = b;
max = r < g ? g : r;
}
else
{
min = r;
max = g;
}
}
else
{
if (r < b)
{
max = b;
min = g < r ? g : r;
}
else
{
max = r;
min = g;
}
}
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This can be simplified to instead be:

Suggested change
privatevoidMinMaxRgb(outintmin,outintmax,intr,intg,intb)
{
if(b<g)
{
if(b<r)
{
min=b;
max=r<g?g:r;
}
else
{
min=r;
max=g;
}
}
else
{
if(r<b)
{
max=b;
min=g<r?g:r;
}
else
{
max=r;
min=g;
}
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
privatestaticvoidMinMaxRgb(outintmin,outintmax,intr,intg,intb)
{
if(r>g)
{
max=r;
min=g;
}
else
{
max=g;
min=r;
}
if(b>max)
{
max=b;
}
elseif(b<min)
{
min=b;
}
}

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

Thanks @stephentoub , I ran the perf_color microbenchmarks against 1) before this PR changeset, 2) the current PR's changeset, 3) proposed simplification

**.NET6 Before VS .NET6 with current PR changeset: Run1** summary: better: 3, geomean: 1.151 total diff: 3

No Slower results for the provided threshold = 2% and noise filter = 25ns.

Fasterbase/diffBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetBrightness1.231549.961259.50
System.Drawing.Tests.Perf_Color.GetHue1.181753.241484.57
System.Drawing.Tests.Perf_Color.GetSaturation1.051451.591383.79
**.NET6 Before VS .NET6 with current PR changeset: Run2** summary: better: 3, geomean: 1.208 total diff: 3

No Slower results for the provided threshold = 2% and noise filter = 25ns.

Fasterbase/diffBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetBrightness1.231543.191259.71
System.Drawing.Tests.Perf_Color.GetSaturation1.221682.031384.17
System.Drawing.Tests.Perf_Color.GetHue1.181758.681485.53
**.NET6 Before VS .NET6 with current PR changeset: Run3** summary: better: 3, geomean: 1.189 total diff: 3

No Slower results for the provided threshold = 2% and noise filter = 25ns.

Fasterbase/diffBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetSaturation1.221682.421384.03
System.Drawing.Tests.Perf_Color.GetBrightness1.191497.181259.28
System.Drawing.Tests.Perf_Color.GetHue1.161725.251483.41


**.NET6 Before VS .NET6 with proposed simplification: Run1** summary: better: 2, geomean: 1.123 total diff: 2

No Slower results for the provided threshold = 2% and noise filter = 25ns.

Fasterbase/diffBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetBrightness1.131549.961375.52
System.Drawing.Tests.Perf_Color.GetHue1.121753.241565.75
**.NET6 Before VS .NET6 with proposed simplification: Run2** summary: better: 3, geomean: 1.135 total diff: 3

No Slower results for the provided threshold = 2% and noise filter = 25ns.

Fasterbase/diffBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetSaturation1.161682.031448.45
System.Drawing.Tests.Perf_Color.GetHue1.121758.681566.17
System.Drawing.Tests.Perf_Color.GetBrightness1.121543.191375.17
**.NET6 Before VS .NET6 with proposed simplification: Run3** summary: better: 2, geomean: 1.132 worse: 1, geomean: 1.050 total diff: 3
Slowerdiff/baseBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetBrightness1.051497.181572.36
Fasterbase/diffBase Median (ns)Diff Median (ns)Modality
System.Drawing.Tests.Perf_Color.GetSaturation1.161682.421446.59
System.Drawing.Tests.Perf_Color.GetHue1.101725.251565.42
---------------------- ----------------------

Some of the benchmarks seem to get a bit slower on average after the simplification. I think what is happening may be two causes:

  1. There are paths with an extra store (we store max & min in the first conditional and then if the second conditional is taken one of these is overwritten).
  2. Just my guess, but processor pipelining with branch prediction may find it easier to go through each of the conditionals in the current implementation as there are no dependencies. The simplification introduces a dependency on the second conditional as it needs the values from the first? Just a guess here.

I will follow yours and @safern 's recommendation on which to keep. Thanks again.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I didn't look at the disassembly but there might be an aliasing complication also, if the JIT compiler has to account for the possibility that min and max refer to the same location. Although perhaps it can disprove that after inlining.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I actually see them get faster on my machine. Regardless, though, I'd rather keep the code smaller, especially with it triplicated due to the aggressive inlining.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

One more possible improvement - using local valiables instead of out parameters:

privatestaticvoidMinMaxRgb(outintmin,outintmax,intr,intg,intb){intminLoc,maxLoc;if(r>g){maxLoc=r;minLoc=g;}else{maxLoc=g;minLoc=r;}if(b>maxLoc){maxLoc=b;}elseif(b<minLoc){minLoc=b;}max=maxLoc;min=minLoc;}

@L2L2Apr 5, 2021

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

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

I actually see them get faster on my machine. Regardless, though, I'd rather keep the code smaller, especially with it triplicated due to the aggressive inlining.

Sounds good @stephentoub , I've updated it with the requested changes. (I'm not sure how crediting works in this project as this is my second pull request, so I've added your username to the commit details as the originator of the simplification).

One more possible improvement - using local valiables instead of out parameters:

Thanks @hypeartist, I'm wondering if these local variables will be eliminated due to inlining, so performance will be about the same?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I'm not sure how crediting works in this project as this is my second pull request, so I've added your username to the commit details as the originator of the simplification

Thanks, but not necessary... I comment on a lot of PRs :)

* Credit for this simplification: stephentoub
@ghostghost removed the auto-merge label Apr 5, 2021
@danmoseley

Copy link
Copy Markdown
Contributor

Thanks for the contribution @L2 - perhaps you'd like to pick up something else?

thaystg added a commit to thaystg/runtime that referenced this pull request Apr 6, 2021
…shim_mono
# By Aaron Robinson (10) and others
# Via GitHub
* upstream/main: (108 commits)
[mbr] Add Apple sample (dotnet#50740)
make EstablishProxyTunnelAsync throw on failure status code from proxy (dotnet#50763)
Improve RGB Min Max evaluation performance by using 2 or 3 comparison… (dotnet#50622)
[mono] More domain cleanups (dotnet#50479)
Fix Crossgen2 of PlatformDefaultMemberFunction methods and calls. (dotnet#50754)
Disable EventSource generator in design-time builds (dotnet#50741)
Fix X509 test failures on Android (dotnet#50301)
Do not confuse fgDispBasicBlocks in fgMorphBlocks (dotnet#50703)
Enforce 64KB event payload size limit on EventPipe (dotnet#50600)
Reorganize CoreCLR native build to reduce CMake reconfigures when the build system is untouched (dotnet#49906)
[mbr] Turn on hot reload for iOS, tvOS and MacCatalyst (dotnet#50458)
improve connection scavenge logic by doing zero-byte read (dotnet#50545)
Resolve call mdtokens when making tier 1 inline observations (dotnet#50675)
Annotate APIs in System.Private.Xml (dotnet#49682)
Support compiling against OpenSSL 3 headers
Change Configuration.Json to use a regular Dictionary. (dotnet#50611)
Remove unused BigNumFromBinary P/Invoke (dotnet#50670)
Make Ninja the default CMake generator on Windows for the repo (dotnet#49715)
[AppleAppBuilder] Entitlements to run tests on catalyst using the JIT (dotnet#50637)
[mono] Fix delegate invokes to dynamic methods in mixed mode. (dotnet#50547)
...
# Conflicts:
#	src/mono/dlls/mscordbi/CMakeLists.txt
@L2
L2 deleted the rgbMinMax branch April 6, 2021 15:05
@ghostghost locked as resolved and limited conversation to collaborators May 9, 2021
@karelzkarelz added this to the 6.0.0 milestone May 20, 2021
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Perf] Changes at 12/9/2020 1:20:52 PM

8 participants

@L2@danmoseley@iamcarbon@stephentoub@hypeartist@safern@KalleOlaviNiemitalo@karelz