Skip to content

Added C# implementation of System.Math.ScaleB and System.MathF.ScaleB…#42476

Merged
16 commits merged intodotnet:masterfrom
alexcovington:managed-scaleb
Jan 25, 2021
Merged

Added C# implementation of System.Math.ScaleB and System.MathF.ScaleB…#42476
16 commits merged intodotnet:masterfrom
alexcovington:managed-scaleb

Conversation

@alexcovington
Copy link
Contributor

@alexcovington alexcovington commented Sep 18, 2020

Implemented System.Math.ScaleB and System.MathF.ScaleB in managed C#, added test cases.

Submitting as a draft pull request first because I'm not quite sure where/how to integrate the tests I've written. System.Private.CoreLib does not have a test directory and I'm having trouble getting build.cmd to find the tests. Any feedback would be appreciated!

This is to address this issue regarding a performance difference in System.Math.ScaleB and System.MathF.ScaleB on Windows and Linux. This PR improves the speed of the function on both platforms and removes the previous bindings/unmanaged implementations.

Edit: updated description and added link to issue.

@dnfadmin
Copy link

dnfadmin commented Sep 18, 2020

CLA assistant check
All CLA requirements met.

@am11
Copy link
Member

am11 commented Sep 18, 2020

Existing tests are based on xunit framework and located at src/libraries/System.Runtime.Extensions/tests/System/Math{F}.cs.

From PowerShell, you can do:

# build the whole thing just once
$ cd runtime
$ ./build.cmd -c Release

# then switch to the 'test' directory of library of interest, in this case
$ cd src/libraries/System.Runtime.Extensions/tests/

# build and run tests using restored toolset
$ ../../../../.dotnet/dotnet build /t:Test -c Release
# at this point, can modify code in src/libraries/System.Private.CoreLib/src/System and just repeat the command
# on line above to rebuild src+test (and their dependencies) for this library and then run tests.

public static extern double Pow(double x, double y);

[MethodImpl(MethodImplOptions.InternalCall)]
public static extern double ScaleB(double x, int n);
Copy link
Member

Choose a reason for hiding this comment

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

Could you please delete it from the unmanaged runtime:

src/coreclr/src/classlibnative/float/floatdouble.cpp
src/coreclr/src/classlibnative/float/floatsingle.cpp
src/coreclr/src/classlibnative/inc/floatdouble.h
src/coreclr/src/classlibnative/inc/floatsingle.h
src/coreclr/src/vm/ecalllist.h
Everything that references scalbn and scalbnf under src/coreclr/src/pal

Copy link
Member

@am11 am11 Sep 18, 2020

Choose a reason for hiding this comment

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

Also, I think these lines can be deleted from mono:

NOHANDLES(ICALL(MATH_25, "ScaleB", ves_icall_System_Math_ScaleB))
NOHANDLES(ICALL(MATHF_27, "ScaleB", ves_icall_System_MathF_ScaleB))

Copy link
Member

Choose a reason for hiding this comment

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

@am11 icall-decl.h should be preserved, it's used by 6.x mono

Copy link
Member

Choose a reason for hiding this comment

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

Ah, ok I see. We can then just delete two lines in icall-def-netcore.h and leave icall-decl.h and sysmath.c. Updated my comment above.

@ghost
Copy link

ghost commented Sep 18, 2020

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

{
class MathTests
{
public struct ScaleBTest
Copy link
Contributor

Choose a reason for hiding this comment

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

Why are we not using xunit tests in System.Runtime.Tests?

Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is exactly what I was looking for before! I just missed it when I was looking for current tests. I'll just add my new test cases to the existing ScaleB tests.

@vargaz
Copy link
Contributor

vargaz commented Sep 23, 2020

The mono changes look ok to me.

@CoffeeFlux
Copy link
Contributor

For Mono, please wrap the corresponding icall implementations in #ifndef ENABLE_NETCORE. We want them around for framework Mono but not netcore.

ves_icall_System_Math_ScaleB (gdouble x, gint32 n)

#define log2 PAL_log2
#define log10 PAL_log10
#define pow PAL_pow
#define scalbn PAL_scalbn
Copy link
Member

@jkotas jkotas Sep 23, 2020

Choose a reason for hiding this comment

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

Could you please also delete src\coreclr\src\pal\tests\palsuite\c_runtime\scalbn and src\coreclr\src\pal\tests\palsuite\c_runtime\scalbnf

@danmoseley
Copy link
Member

What's next steps here?
cc @tannergooding

@tannergooding
Copy link
Member

What's next steps here?

I'll get this reviewed either today or tomorrow. I'm not aware of anything else that would be blocking.

It would likely be good to get perf numbers for x64, x86, ARM32, and ARM64. @DrewScoggins, is there currently an easy way to get these for a particular benchmark (aside from manually running them)?

throw new ArgumentException(SR.Format(SR.Argument_MinMaxValue, min, max));
}

public static double ScaleB(double x, int n)
Copy link
Member

Choose a reason for hiding this comment

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

Was this ported from an existing implementation?

Based on #40956 (comment), it sounds like its based on the MUSL implementation which is MIT (https://git.musl-libc.org/cgit/musl/tree/COPYRIGHT) and so we need a comment around here and also need to update the https://github.com/dotnet/runtime/blob/master/THIRD-PARTY-NOTICES.TXT.

CC. @richlander on if there is anything else required.

Copy link
Member

Choose a reason for hiding this comment

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

The MUSL implementation came from Sun's implementation, so we may need the notice for that too (or just have notice for the Sun's implementation if it was not changed for MUSL).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, this was based on the musl implementation. I added links to the source for each function and included both the musl and Sun license. Let me know if I missed or can add anything.

public static double ScaleB(double x, int n)
{
double y = x;
if (n > 1023)
Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is good to know. I tried reworking the logic to take this into consideration, roughly something like:

if (n <= 127 && n >= -126) {
    // n is in expected range, just compute and return result
} else {
    if (n > 127) {
        // Make adjustments
    }
    else if (n < -126) {
        // Make adjustments
    }
}

But I'm not seeing an improvement in perf. I can push if you'd like to take a look, but not sure it's worth it.

Copy link
Member

Choose a reason for hiding this comment

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

I can push if you'd like to take a look, but not sure it's worth it.

Right, I don't think in this particular case it is particular import, I just wanted to call it out as it might be relevant if additional work is done in this or related areas later.

Copy link
Member

Choose a reason for hiding this comment

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

I was thinking that if those edge cases were moved into their own method, this could become inlineable. But it doesn't seem to get inlined even then.

[InlineData( 2.71828183f, 2.71828183f, CrossPlatformMachineEpsilon * 10)] // value: (e) expected: (e)
[InlineData( 3.14159265f, 3.14159265f, CrossPlatformMachineEpsilon * 10)] // value: (pi) expected: (pi)
[InlineData( float.PositiveInfinity, float.PositiveInfinity, 0.0f)]
[InlineData(float.NegativeInfinity, float.PositiveInfinity, 0.0f)]
Copy link
Member

Choose a reason for hiding this comment

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

It looks like the diff for this file is bigger because the whitespace was stripped from the attributes.

It's probably a losing battle to try and fight with the formatter to keep the "columns" aligned, so I don't think it needs to be fixed; just wanted to call it out.

@DrewScoggins
Copy link
Member

DrewScoggins commented Oct 2, 2020

What's next steps here?

I'll get this reviewed either today or tomorrow. I'm not aware of anything else that would be blocking.

It would likely be good to get perf numbers for x64, x86, ARM32, and ARM64. @DrewScoggins, is there currently an easy way to get these for a particular benchmark (aside from manually running them)?

We already generate reports for the category subsets that are not Library and Runtime, but looking at the performance tests for this space, they are not in their own category. So what we can do is just generate a report that covers just the performance tests that we care about by name. We won't have this data for ARM32, as we don't have that hardware in the perf lab, but we should be able to generate the data for all of the other configs. Also this would be after the change already went in.

@tannergooding
Copy link
Member

Also this would be after the change already went in.

Right, I know (roughly) how to do that bit. I was interested if we had any way to kick of a perf run against the current PR and to pull that info out before merging, short of just checking it out and running the tests locally on my own hardware.

@ViktorHofer
Copy link
Member

// Auto-generated message

69e114c which was merged 12/7 removed the intermediate src/coreclr/src/ folder. This PR needs to be updated as it touches files in that directory which causes conflicts.

To update your commits you can use this bash script: https://gist.github.com/ViktorHofer/6d24f62abdcddb518b4966ead5ef3783. Feel free to use the comment section of the gist to improve the script for others.

@tannergooding
Copy link
Member

Is this currently blocked on anything and if so, can we help push it forward?

@alexcovington
Copy link
Contributor Author

@tannergooding My apologies, I think this slipped through the cracks on my end. I'll merge with master and push again.

@tannergooding
Copy link
Member

Thanks, and no worries! Just wanted to check in and see (and make sure I wasn't missing some action item on my end) 😄

return x;
}

public static float ScaleB(float x, int n)
Copy link
Member

Choose a reason for hiding this comment

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

Just noting, since this PR was opened, AMD open sourced their own libm implementation which includes scaleb: https://github.com/amd/aocl-libm-ose/blob/7193ff6fdf72ecd68df4e0e19262da84f1d95a3e/src/ref/scalbnf.c

It notably has a different algorithm and error handling logic (unnecessary in the C# implementation) but it might be worth comparing in the future to see which is better.

Copy link
Member

@tannergooding tannergooding left a comment

Choose a reason for hiding this comment

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

LGTM. This should be good to merge assuming @jkotas doesn't have any other feedback about the JIT side changes.

Copy link
Member

@jkotas jkotas left a comment

Choose a reason for hiding this comment

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

LGTM. Thank you!

@ghost
Copy link

ghost commented Jan 25, 2021

Hello @tannergooding!

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.

@ghost ghost merged commit 220bf97 into dotnet:master Jan 25, 2021
@tannergooding
Copy link
Member

Thanks again for the contribution @alexcovington!

@adamsitnik, @kunalspathak, @DrewScoggins we should validate this shows up as an improvement in perf triage.

@DrewScoggins
Copy link
Member

Here is the improvement on Ubuntu

DrewScoggins/performance-2#3838

Windows x64

DrewScoggins/performance-2#3857

Arm64

DrewScoggins/performance-2#3848

Windows x86

DrewScoggins/performance-2#3867

@ghost ghost locked as resolved and limited conversation to collaborators Mar 4, 2021
This pull request was closed.
Sign up for free to 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.