Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hotfix conversion of float/double #49

Merged
merged 8 commits into from
Mar 13, 2024
Merged

Hotfix conversion of float/double #49

merged 8 commits into from
Mar 13, 2024

Conversation

mycroes
Copy link
Owner

@mycroes mycroes commented Feb 12, 2024

Fix conversion of single float/double values to their PLC format. The assumption that the runtime would treat Action<float> similarly to Action<int> is apparently invalid, as can also be witnessed from SharpLab.

@mycroes mycroes requested a review from gfoidl February 12, 2024 11:09
Copy link
Collaborator

@gfoidl gfoidl left a comment

Choose a reason for hiding this comment

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

The assumption that the runtime would treat Action similarly to Action is apparently invalid

Because for value types specialized code for the generics is created, with each optimized. Thus there may be differences.

Also on sharplab you can choose between x64, x86 and the old .NET Fx.

@@ -3,7 +3,7 @@

namespace Sally7.ValueConversion
{
public delegate int ConvertToS7<TValue>(TValue? value, int length, Span<byte> output);
public delegate int ConvertToS7<TValue>(in TValue? value, int length, Span<byte> output);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is the in actually needed?
For small TValue (roughly 2x CPU register-size) this is actually a de-optimization, as the value has to be passed via stack rather than cpu's registers (as w/o in).

For value types the generic constraint : struct would guarantee the readonly-ness here too (copy by value).
If arrays need to be passed in, then I'd use ReadOnlySpan instead.

Copy link
Owner Author

Choose a reason for hiding this comment

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

Depends on what you'd call needed. I could add separate float/double handling (under the assumption that'll work as expected in that case), but apparently there's a difference in how the framework treats floats vs ints, while I would expect that it would just pass 4 bytes around in the same way. The same also applies for double vs long.

So maybe it's a good idea to split float / double regardless since it removes the downsides, but it was definitely broken in the previous state.

Copy link
Collaborator

Choose a reason for hiding this comment

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

For .NET 6+ I'd throw away the delegate and use an approach that is based on generic math (i.e. static abstract interface members).

  • no problems with endianess (I believe that's the root issue here)
  • superb perf (delegates aren't as optimized as struct's generic specialization)
  • easy to extend

When we have some time with this I can look at the weekend into that approach.

Copy link
Owner Author

Choose a reason for hiding this comment

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

Your help is always greatly appreciated! I think main problem here is that the conversion also supports strings and arrays, so I'm not sure we can handle all in a uniform fashion. But perhaps it's a good idea to differentiate anyway. I must admit I haven't applied static abstract interface members anywhere yet, even though I was hugely looking forward to its implementation before .NET 6. Guess I've been too busy lately 😉

Copy link
Collaborator

@gfoidl gfoidl Feb 12, 2024

Choose a reason for hiding this comment

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

OK, when the test pass here let's go ahead and merge this.
I'll create an issue that reminds me on working with the static abstract interfaces for this. For strings and arrays I don't see a problem -- when there's a PR for this I hope you see why there shouldn't be a problem.

--> #50

Copy link
Owner Author

Choose a reason for hiding this comment

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

I actually already released this as 0.14.4. The hotfix branch doesn't cleanly merge into main though, because I did some work on main that's not yet released. Like I said, been a bit too busy, will try to prepare a release of main sooner rather than later.

@@ -48,14 +48,14 @@ public static Delegate GetConverter<TValue>()
throw new NotImplementedException();
}

private static int ConvertFromLong(long value, int length, Span<byte> output)
private static int ConvertFromLong(in long value, int length, Span<byte> output)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Same (and on other places).

Copy link
Owner Author

Choose a reason for hiding this comment

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

Yeah these all follow ConvertToS7<TValue>, so they align with the delegate definition.

@mycroes mycroes merged commit f2caba4 into main Mar 13, 2024
3 checks passed
@mycroes mycroes deleted the hotfix/conversion branch March 13, 2024 20:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants