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

[Compatibility] Added INCRBYFLOAT command #699

Merged
merged 10 commits into from
Oct 10, 2024

Conversation

Vijay-Nirmal
Copy link
Contributor

@Vijay-Nirmal Vijay-Nirmal commented Oct 2, 2024

Adding INCRBYFLOAT command to garnet

  • Add INCRBYFLOAT command
  • Add Test cases
  • Add documentation

Question:

Do you guys have any optimal way to double to ASCII byte?

Below is a benchmark with 2 approaches.

DoubleToSpanWithMathAbsRound => Same code as the PR
DoubleToSpanWithDiyFp => Similar code as string.Format("{0:0.####}"). Below are the links to the code I used from .dotnet runtime repo
Number.DiyFp.cs
Number.Grisu3.cs - TryRunCounted
DoubleToSpanWithStringFormat => Using doubleValue.ToString("0.###############") and using buffer copy to move the value to input span
DoubleToSpanWithUtf8Formatter => Using Utf8Formatter
DoubleToSpanWithTryFormat => Using doubleValue.TryFormat(buffer, out var bytesWritten, "0.#################")

Method Value Mean Error StdDev Gen0 Allocated
DoubleToSpanWithMathAbsRound 10.23 32.27 ns 0.399 ns 0.333 ns - -
DoubleToSpanWithDiyFp 10.23 51.40 ns 0.619 ns 0.579 ns - -
DoubleToSpanWithStringFormat 10.23 121.94 ns 1.474 ns 1.307 ns 0.0017 32 B
DoubleToSpanWithUtf8Formatter 10.23 142.52 ns 2.637 ns 2.590 ns - -
DoubleToSpanWithTryFormat 10.23 122.79 ns 2.079 ns 1.843 ns - -
DoubleToSpanWithMathAbsRound 12.023642000155785 172.41 ns 3.402 ns 4.303 ns - -
DoubleToSpanWithDiyFp 12.023642000155785 51.86 ns 0.928 ns 0.868 ns - -
DoubleToSpanWithStringFormat 12.023642000155785 111.17 ns 2.158 ns 2.309 ns 0.0029 56 B
DoubleToSpanWithUtf8Formatter 12.023642000155785 188.86 ns 3.793 ns 3.895 ns - -
DoubleToSpanWithTryFormat 12.023642000155785 121.57 ns 1.504 ns 2.825 ns - -
DoubleToSpanWithMathAbsRound 85.98498198191919 161.47 ns 1.592 ns 1.330 ns - -
DoubleToSpanWithDiyFp 85.98498198191919 50.77 ns 0.834 ns 0.740 ns - -
DoubleToSpanWithStringFormat 85.98498198191919 107.39 ns 1.761 ns 1.647 ns 0.0029 56 B
DoubleToSpanWithUtf8Formatter 85.98498198191919 204.33 ns 1.950 ns 1.728 ns - -
DoubleToSpanWithTryFormat 85.98498198191919 111.06 ns 1.260 ns 1.052 ns - -
DoubleToSpanWithMathAbsRound 152.3645 59.95 ns 0.985 ns 0.922 ns - -
DoubleToSpanWithDiyFp 152.3645 58.23 ns 1.142 ns 1.269 ns - -
DoubleToSpanWithStringFormat 152.3645 128.90 ns 2.206 ns 1.956 ns 0.0019 40 B
DoubleToSpanWithUtf8Formatter 152.3645 220.70 ns 4.394 ns 5.557 ns - -
DoubleToSpanWithTryFormat 152.3645 136.13 ns 2.682 ns 3.193 ns - -
DoubleToSpanWithMathAbsRound 456621336.22 82.08 ns 1.669 ns 1.855 ns - -
DoubleToSpanWithDiyFp 456621336.22 44.48 ns 0.425 ns 0.355 ns - -
DoubleToSpanWithStringFormat 456621336.22 119.48 ns 1.382 ns 1.293 ns 0.0024 48 B
DoubleToSpanWithUtf8Formatter 456621336.22 248.25 ns 4.419 ns 4.134 ns - -
DoubleToSpanWithTryFormat 456621336.22 114.32 ns 2.104 ns 1.968 ns - -
DoubleToSpanWithMathAbsRound 9.874(...)2E+20 [21] 249.52 ns 4.870 ns 5.980 ns - -
DoubleToSpanWithDiyFp 9.874(...)2E+20 [21] 37.10 ns 0.761 ns 0.712 ns - -
DoubleToSpanWithStringFormat 9.874(...)2E+20 [21] 126.49 ns 1.706 ns 1.513 ns 0.0033 64 B
DoubleToSpanWithUtf8Formatter 9.874(...)2E+20 [21] 322.90 ns 2.100 ns 1.753 ns - -
DoubleToSpanWithTryFormat 9.874(...)2E+20 [21] 138.64 ns 2.705 ns 2.778 ns - -

Even though the dotnet runtime approach does better in most cases in the benchmark, I have not done it as part of this PR because of 2 reasons, 1) it has lots of code and 2) for smaller numbers it always performs worse. If you guys like dotnet's approach, I can change it quickly.

Let me know if you guys have any other ideas, I can implement and compare the performance.

@badrishc
Copy link
Contributor

badrishc commented Oct 4, 2024

@badrishc
Copy link
Contributor

badrishc commented Oct 4, 2024

Or, double.TryParse(ReadOnlySpan<byte> utf8Text, out double result). This also goes from byte[] to double.

@badrishc
Copy link
Contributor

badrishc commented Oct 4, 2024

@badrishc
Copy link
Contributor

badrishc commented Oct 4, 2024

might be best to just convert the double to the ROS with a sufficiently large buffer, to know how many bytes it uses. hopefully the conversion will not need to be repeated.

@Vijay-Nirmal
Copy link
Contributor Author

Vijay-Nirmal commented Oct 4, 2024

@badrishc I have added the benchmark results with Utf8Formatter. In my benchmark, it is the slowest option. I've shared below my benchmark method for using Utf8Formatter, please let me know if I made any mistake in my benchmark. Note: We can't use exponential notation.

[Benchmark]
public byte NumOfCharInDoubleWithUtf8Formatter()
{
    Span<byte> buffer = stackalloc byte[327];  // 309 (max digits) + 1 (dot) + 17 (precision)
    Utf8Formatter.TryFormat(Value, buffer, out var bytesWritten, new StandardFormat('f', 17));
    buffer = buffer.Slice(0, bytesWritten).TrimEnd((byte)'0').TrimEnd((byte)'.');
    return buffer[0];
}

@badrishc
Copy link
Contributor

badrishc commented Oct 5, 2024

NumOfCharInDoubleWithMathAbsRound seems better as high-perf scenarios might involve smaller doubles. cc @PaulusParssinen for thoughts on this.

libs/common/NumUtils.cs Outdated Show resolved Hide resolved
@badrishc
Copy link
Contributor

badrishc commented Oct 7, 2024

Nicely done PR, approved!

@badrishc
Copy link
Contributor

badrishc commented Oct 7, 2024

Please resolve the conflicts and we can move forward.

@badrishc
Copy link
Contributor

badrishc commented Oct 8, 2024

@Vijay-Nirmal - there seems to be a perf regression with this PR, for Increment:

BDN paramters: -f BDN.benchmark.Resp.RespParseStress.Increment

main:

Method Mean Error StdDev Allocated
Increment 34.80 us 0.354 us 0.314 us -

PR:

Method Mean Error StdDev Allocated
Increment 44.36 us 0.842 us 0.703 us -

Analysis

It seems this is related to the stackalloc of the larger sized buffer for doubles in the same method (NetworkIncrement). My suggestion is that we separate out NetworkIncrementByFloat into its own method. Separating it out will also eliminate a couple of condition checks in the critical path of INCR, which is more perf-sensitive than INCRBYFLOAT.

@badrishc badrishc self-requested a review October 8, 2024 16:29
Copy link
Contributor

@vazois vazois left a comment

Choose a reason for hiding this comment

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

Can you please add a slot verification test in ClusterSlotVeficationTests?

@Vijay-Nirmal
Copy link
Contributor Author

@badrishc Interesting, For Increment, isFloat will always be false. Then how come the stackalloc is impacting?

@badrishc Is there any thumb rule on when to add RespParseStress?

@vazois That a new things to me, I will add it, also same question Is there any thumb rule on when to add ClusterSlotVeficationTests?

I will do everything this weekend

@badrishc
Copy link
Contributor

badrishc commented Oct 8, 2024

@badrishc Interesting, For Increment, isFloat will always be false. Then how come the stackalloc is impacting?

I tried making MaximumFormatDoubleLength equal to MaximumFormatInt64Length and that seems to bring the perf back to closer to original levels, hence the suspicion.

@badrishc Is there any thumb rule on when to add RespParseStress?

Ideally for all "fast" commands we add so that we can track future perf regressions. However it is understandably extra work, so it is mostly on a case-by-case basis for now.

@vazois
Copy link
Contributor

vazois commented Oct 9, 2024

@badrishc Interesting, For Increment, isFloat will always be false. Then how come the stackalloc is impacting?

@badrishc Is there any thumb rule on when to add RespParseStress?

@vazois That a new things to me, I will add it, also same question Is there any thumb rule on when to add ClusterSlotVeficationTests?

I will do everything this weekend

I made some updates and additions in this PR (#709) for slot verification.
If you are adding a multi key command you can check how MSET and MGET is being tested. Single key commands should be easier to understand by check SET and GET redirection tests.
You can also check the description of this PR (#474) if you want to learn more about the redirection logic.

@Vijay-Nirmal
Copy link
Contributor Author

@badrishc Moved INCRBYFLOAT to a separate NetworkIncrementByFloat

@vazois #474 Has very good info, it will be good if we add the same info in Dev doc for slot migration.

@Vijay-Nirmal
Copy link
Contributor Author

@vazois Added ClusterSlotVeficationTests. Can you review and approve the PR?

@badrishc
Copy link
Contributor

badrishc commented Oct 9, 2024

Can you please add a slot verification test in ClusterSlotVeficationTests?

We will merge this PR now. Vijay - if you can add the ClusterSlotVerificationTest in a separate PR, that would be great.

@Vijay-Nirmal
Copy link
Contributor Author

@badrishc Already added ClusterSlotVerificationTest in this PR itself

@badrishc badrishc merged commit ace7cb6 into microsoft:main Oct 10, 2024
15 checks passed
@@ -387,7 +387,7 @@ Note that this list is subject to change as we continue to expand our API comman
| | GETSET | ➖ | |
| | [INCR](raw-string.md#incr) | ➕ | |
| | [INCRBY](raw-string.md#incrby) | ➕ | |
| | INCRBYFLOAT | ➖ | |
| | [INCRBYFLOAT](raw-string.md#incrbyfloat) | ➖ | |
Copy link
Contributor

@nightroman nightroman Oct 29, 2024

Choose a reason for hiding this comment

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

@Vijay-Nirmal Presumably "-" should have been changed to "+".

Currently INCRBYFLOAT may look like not implemented with the minus sign
https://microsoft.github.io/garnet/docs/commands/api-compatibility

Copy link
Contributor

Choose a reason for hiding this comment

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

This PR should fix this, if accepted #757

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.

4 participants