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

Implement build cmd in rust #56

Merged
merged 1 commit into from
Mar 5, 2024
Merged

Implement build cmd in rust #56

merged 1 commit into from
Mar 5, 2024

Conversation

bisho
Copy link
Member

@bisho bisho commented Nov 7, 2023

Build cmd in rust

Motivation / Description

The second cpu-intensive part of the request processing is building
the cmd.

Also instead of building dicts of flags we can use a single
flags object, which also simplifies the API of the lower
commands.

I chose to still built a single flags object, but we could
explore building one flags object per meta-command, as the
flags that they support differ, and it could lead to a more
type-safe low-level implementation.

Performance:

  • Initial (before all this patchsets):
    multithreaded: Overall: 110779.55 RPS / 9.03 us/req
    singlethreaded: Overall: 111545.63 RPS / 8.96 us/req

  • Rust only for response parsing
    multithreaded: Overall: 245898.34 RPS / 4.07 us/req
    singlethreaded: Overall: 246165.19 RPS / 4.06 us/req

  • Now (rust also for build_cmd)
    multithreaded: Overall: 319587.03 RPS / 3.13 us/req
    singlethreaded: Overall: 323101.77 RPS / 3.10 us/req

Speedscope:

  • Before: 1.18us
    Screenshot 2023-11-07 at 23 47 53

  • After: 456ns
    Screenshot 2023-11-07 at 23 45 56

@bisho bisho force-pushed the rust_parse_header branch from c4b711c to 309bcc3 Compare November 7, 2023 22:06
@bisho bisho marked this pull request as ready for review November 7, 2023 22:07
@bisho bisho requested a review from a team November 7, 2023 22:07
@bisho bisho changed the title rust build cmd Implement build cmd in rust Nov 7, 2023
Copy link

@thecadams thecadams left a comment

Choose a reason for hiding this comment

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

LG. Only minor concerns / questions, but nothing that would block shipping this. Really cool to see such optimization @bisho ! 🚀 ⏩

@@ -1186,7 +1183,7 @@ def test_delta_cmd(memcache_socket: MemcacheSocket, cache_client: CacheClient) -

cache_client.delta(key=Key("foo"), delta=1, refresh_ttl=60, no_reply=True)
memcache_socket.sendall.assert_called_once_with(
b"ma foo q D1 T60\r\n", with_noop=True
b"ma foo q T60 D1\r\n", with_noop=True

Choose a reason for hiding this comment

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

Looks like order on the wire doesn't matter for the flags, nothing here specifies a required order: https://github.com/memcached/memcached/blob/master/doc/protocol.txt#L116 so this seems ok 👍

Copy link
Member Author

Choose a reason for hiding this comment

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

Python 3.11 was in fact generating random order and we were running tests in python 3.8 with fixed seed to prevent that. The rust implementation guarantees ordering, not very important, but simplifies testing.

@@ -560,7 +557,7 @@ def test_get_cmd(memcache_socket: MemcacheSocket, cache_client: CacheClient) ->
)
assert_called_once_with_command(
memcache_socket.sendall,
b"mg lCV3WxKxtWrdY4s1+R710+9J b t l v h f R30 T300\r\n",
b"mg w7puw63Dp29k4o23 b t l v h f R30 T300\r\n",

Choose a reason for hiding this comment

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

Any undocumented implications of no longer base64 encoding unicode keys?

Looks like this will mean a new warmup & double storing cache fights during deploys, but should be ok if all documented.

Copy link
Member Author

@bisho bisho Nov 13, 2023

Choose a reason for hiding this comment

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

This is still base64. The change is that now we won't generate a blake2b hash blindly for any unicode, only for large keys.

I also didn't like how the Key() class ended looking before. It is a burden to: 1) not allow binary keys, forcing users to encode themselved. 2) mark unicode presence on keys (that was mostly never used).

Now we will allow bytes & any unicode and be able to encode it properly. Before it was expensive to check if something wasn't just ascii, required iterating each char thus the is_unicode flag, but with this rust implementation you just pass bytes to it, and if any char is not ascii it will b64 it and add the binary flag with minimal overhead. I very much like best this abstraction.

Regarding the compatibility, this will be a major since we also break the meta-commands api completely, with the new way of passing flags. I'll fix docs and document this behavior change. The high-level api is unaffected, so I hope most users don't see many problems to upgrade.

@bisho bisho force-pushed the rust_parse_header branch from 309bcc3 to 8358df9 Compare November 20, 2023 21:25
@bisho bisho force-pushed the rust_build_cmd branch 3 times, most recently from 3d6a61f to 7813cc8 Compare November 22, 2023 11:22
@bisho bisho force-pushed the rust_parse_header branch from 8358df9 to 77e4d37 Compare March 5, 2024 13:31
@bisho bisho force-pushed the rust_parse_header branch from 77e4d37 to 5d166c0 Compare March 5, 2024 14:09
@bisho bisho force-pushed the rust_parse_header branch from 5d166c0 to 38122e9 Compare March 5, 2024 14:12
@bisho bisho force-pushed the rust_parse_header branch from 38122e9 to dbdb536 Compare March 5, 2024 14:13
@bisho bisho force-pushed the rust_parse_header branch from dbdb536 to 9b4110f Compare March 5, 2024 14:15
@bisho bisho force-pushed the rust_parse_header branch from 9b4110f to 8a5b269 Compare March 5, 2024 14:18
@bisho bisho force-pushed the rust_parse_header branch from 8a5b269 to a6ab048 Compare March 5, 2024 14:20
@bisho bisho force-pushed the rust_parse_header branch from a6ab048 to 3e2585e Compare March 5, 2024 14:26
## Motivation / Description
The second cpu-intensive part of the request processing is building
the cmd.

Also instead of building dicts of flags we can use a single
flags object, which also simplifies the API of the lower
commands.

I chose to still built a single flags object, but we could
explore building one flags object per meta-command, as the
flags that they support differ, and it could lead to a more
type-safe low-level implementation.

## Performance:
* Initial:
multithreaded: Overall: 110779.55 RPS / 9.03 us/req
singlethreaded: Overall: 111545.63 RPS / 8.96 us/req

* Rust only for response parsing
multithreaded: Overall: 245898.34 RPS / 4.07 us/req
singlethreaded: Overall: 246165.19 RPS / 4.06 us/req

* Now (rust also for build_cmd)
multithreaded: Overall: 319587.03 RPS / 3.13 us/req
singlethreaded: Overall: 323101.77 RPS / 3.10 us/req
@bisho bisho changed the base branch from rust_parse_header to main March 5, 2024 16:58
@bisho bisho merged commit 9421fe1 into main Mar 5, 2024
4 checks passed
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