Skip to content

Commit a106198

Browse files
Optimize addReplyBulk on sds/int encoded strings: 2.2% to 4% reduction of CPU Time on GET high pipeline use-cases (#13644)
### Summary By profing 1KiB 100% GET's use-case, on high pipeline use-cases, we can see that addReplyBulk and it's inner calls takes 8.30% of the CPU cycles. This PR reduces from 2.2% to 4% the CPU time spent on addReplyBulk. Specifically for GET use-cases, we saw an improvement from 2.7% to 9.1% on the achievable ops/sec ### Improvement By reducing the duplicate work we can improve by around 2.7% on sds encoded strings, and around 9% on int encoded strings. This PR does the following: - Avoid duplicate sdslen on addReplyBulk() for sds enconded objects - Avoid duplicate sdigits10() call on int incoded objects on addReplyBulk() - avoid final "\r\n" addReplyProto() in the OBJ_ENCODING_INT type on addReplyBulk Altogether this improvements results in the following improvement on the achievable ops/sec : Encoding | unstable (commit 9906daf) | this PR | % improvement -- | -- | -- | -- 1KiB Values string SDS encoded | 1478081.88 | 1517635.38 | 2.7% Values string "1" OBJ_ENCODING_INT | 1521139.36 | 1658876.59 | 9.1% ### CPU Time: Total of addReplyBulk Encoding | unstable (commit 9906daf) | this PR | reduction of CPU Time: Total -- | -- | -- | -- 1KiB Values string SDS encoded | 8.30% | 6.10% | 2.2% Values string "1" OBJ_ENCODING_INT | 7.20% | 3.20% | 4.0% ### To reproduce Run redis with unix socket enabled ``` taskset -c 0 /root/redis/src/redis-server --unixsocket /tmp/1.socket --save '' --enable-debug-command local ``` #### 1KiB Values string SDS encoded Load data ``` taskset -c 2-5 memtier_benchmark --ratio 1:0 -n allkeys --key-pattern P:P --key-maximum 1000000 --hide-histogram --pipeline 10 -S /tmp/1.socket ``` Benchmark ``` taskset -c 2-6 memtier_benchmark --ratio 0:1 -c 1 -t 5 --test-time 60 --hide-histogram -d 1000 --pipeline 500 -S /tmp/1.socket --key-maximum 1000000 --json-out-file results.json ``` #### Values string "1" OBJ_ENCODING_INT Load data ``` $ taskset -c 2-5 memtier_benchmark --command "SET __key__ 1" -n allkeys --command-key-pattern P --key-maximum 1000000 --hide-histogram -c 1 -t 1 --pipeline 100 -S /tmp/1.socket # confirm we have the expected reply and format $ redis-cli get memtier-1 "1" $ redis-cli debug object memtier-1 Value at:0x7f14cec57570 refcount:2147483647 encoding:int serializedlength:2 lru:2861503 lru_seconds_idle:8 ``` Benchmark ``` taskset -c 2-6 memtier_benchmark --ratio 0:1 -c 1 -t 5 --test-time 60 --hide-histogram -d 1000 --pipeline 500 -S /tmp/1.socket --key-maximum 1000000 --json-out-file results.json ```
1 parent 05b99c8 commit a106198

1 file changed

Lines changed: 20 additions & 3 deletions

File tree

src/networking.c

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1078,9 +1078,26 @@ void addReplyBulkLen(client *c, robj *obj) {
10781078

10791079
/* Add a Redis Object as a bulk reply */
10801080
void addReplyBulk(client *c, robj *obj) {
1081-
addReplyBulkLen(c,obj);
1082-
addReply(c,obj);
1083-
addReplyProto(c,"\r\n",2);
1081+
if (prepareClientToWrite(c) != C_OK) return;
1082+
1083+
if (sdsEncodedObject(obj)) {
1084+
const size_t len = sdslen(obj->ptr);
1085+
_addReplyLongLongBulk(c, len);
1086+
_addReplyToBufferOrList(c,obj->ptr,len);
1087+
_addReplyToBufferOrList(c,"\r\n",2);
1088+
} else if (obj->encoding == OBJ_ENCODING_INT) {
1089+
/* For integer encoded strings we just convert it into a string
1090+
* using our optimized function, and attach the resulting string
1091+
* to the output buffer. */
1092+
char buf[34];
1093+
size_t len = ll2string(buf,sizeof(buf),(long)obj->ptr);
1094+
buf[len+1] = '\r';
1095+
buf[len+2] = '\n';
1096+
_addReplyLongLongBulk(c, len);
1097+
_addReplyToBufferOrList(c,buf,len+2);
1098+
} else {
1099+
serverPanic("Wrong obj->encoding in addReply()");
1100+
}
10841101
}
10851102

10861103
/* Add a C buffer as bulk reply */

0 commit comments

Comments
 (0)