Unverified Commit bcae7708 authored by Filipe Oliveira (Redis)'s avatar Filipe Oliveira (Redis) Committed by GitHub
Browse files

Optimize LREM, LPOS, LINSERT, LINDEX: Avoid N-1 sdslen() calls on listTypeEqual (#13529)

This is a very easy optimization, that avoids duplicate computation of
the object length for LREM, LPOS, LINSERT na LINDEX.

We can see that sdslen takes 7.7% of the total CPU cycles of the
benchmarks.

Function Stack | CPU Time: Total | CPU Time: Self | Module | Function
(Full) | Source File | Start Address
-- | -- | -- | -- | -- | -- | --
listTypeEqual | 15.50% | 2.346s | redis-server | listTypeEqual |
t_list.c | 0x845dd
sdslen | 7.70% | 2.300s | redis-server | sdslen | sds.h | 0x845e4

Preliminary data showcases 4% improvement in the achievable ops/sec of
LPOS in string elements, and 2% in int elements.
parent bf802b07
...@@ -2748,7 +2748,7 @@ robj *listTypeGet(listTypeEntry *entry); ...@@ -2748,7 +2748,7 @@ robj *listTypeGet(listTypeEntry *entry);
unsigned char *listTypeGetValue(listTypeEntry *entry, size_t *vlen, long long *lval); unsigned char *listTypeGetValue(listTypeEntry *entry, size_t *vlen, long long *lval);
void listTypeInsert(listTypeEntry *entry, robj *value, int where); void listTypeInsert(listTypeEntry *entry, robj *value, int where);
void listTypeReplace(listTypeEntry *entry, robj *value); void listTypeReplace(listTypeEntry *entry, robj *value);
int listTypeEqual(listTypeEntry *entry, robj *o); int listTypeEqual(listTypeEntry *entry, robj *o, size_t object_len);
void listTypeDelete(listTypeIterator *iter, listTypeEntry *entry); void listTypeDelete(listTypeIterator *iter, listTypeEntry *entry);
robj *listTypeDup(robj *o); robj *listTypeDup(robj *o);
void listTypeDelRange(robj *o, long start, long stop); void listTypeDelRange(robj *o, long start, long stop);
......
...@@ -383,12 +383,12 @@ int listTypeReplaceAtIndex(robj *o, int index, robj *value) { ...@@ -383,12 +383,12 @@ int listTypeReplaceAtIndex(robj *o, int index, robj *value) {
} }
/* Compare the given object with the entry at the current position. */ /* Compare the given object with the entry at the current position. */
int listTypeEqual(listTypeEntry *entry, robj *o) { int listTypeEqual(listTypeEntry *entry, robj *o, size_t object_len) {
serverAssertWithInfo(NULL,o,sdsEncodedObject(o)); serverAssertWithInfo(NULL,o,sdsEncodedObject(o));
if (entry->li->encoding == OBJ_ENCODING_QUICKLIST) { if (entry->li->encoding == OBJ_ENCODING_QUICKLIST) {
return quicklistCompare(&entry->entry,o->ptr,sdslen(o->ptr)); return quicklistCompare(&entry->entry,o->ptr,object_len);
} else if (entry->li->encoding == OBJ_ENCODING_LISTPACK) { } else if (entry->li->encoding == OBJ_ENCODING_LISTPACK) {
return lpCompare(entry->lpe,o->ptr,sdslen(o->ptr)); return lpCompare(entry->lpe,o->ptr,object_len);
} else { } else {
serverPanic("Unknown list encoding"); serverPanic("Unknown list encoding");
} }
...@@ -538,8 +538,9 @@ void linsertCommand(client *c) { ...@@ -538,8 +538,9 @@ void linsertCommand(client *c) {
/* Seek pivot from head to tail */ /* Seek pivot from head to tail */
iter = listTypeInitIterator(subject,0,LIST_TAIL); iter = listTypeInitIterator(subject,0,LIST_TAIL);
const size_t object_len = sdslen(c->argv[3]->ptr);
while (listTypeNext(iter,&entry)) { while (listTypeNext(iter,&entry)) {
if (listTypeEqual(&entry,c->argv[3])) { if (listTypeEqual(&entry,c->argv[3],object_len)) {
listTypeInsert(&entry,c->argv[4],where); listTypeInsert(&entry,c->argv[4],where);
inserted = 1; inserted = 1;
break; break;
...@@ -999,8 +1000,9 @@ void lposCommand(client *c) { ...@@ -999,8 +1000,9 @@ void lposCommand(client *c) {
listTypeEntry entry; listTypeEntry entry;
long llen = listTypeLength(o); long llen = listTypeLength(o);
long index = 0, matches = 0, matchindex = -1, arraylen = 0; long index = 0, matches = 0, matchindex = -1, arraylen = 0;
const size_t ele_len = sdslen(ele->ptr);
while (listTypeNext(li,&entry) && (maxlen == 0 || index < maxlen)) { while (listTypeNext(li,&entry) && (maxlen == 0 || index < maxlen)) {
if (listTypeEqual(&entry,ele)) { if (listTypeEqual(&entry,ele,ele_len)) {
matches++; matches++;
matchindex = (direction == LIST_TAIL) ? index : llen - index - 1; matchindex = (direction == LIST_TAIL) ? index : llen - index - 1;
if (matches >= rank) { if (matches >= rank) {
...@@ -1052,8 +1054,9 @@ void lremCommand(client *c) { ...@@ -1052,8 +1054,9 @@ void lremCommand(client *c) {
} }
listTypeEntry entry; listTypeEntry entry;
const size_t object_len = sdslen(c->argv[3]->ptr);
while (listTypeNext(li,&entry)) { while (listTypeNext(li,&entry)) {
if (listTypeEqual(&entry,obj)) { if (listTypeEqual(&entry,obj,object_len)) {
listTypeDelete(li, &entry); listTypeDelete(li, &entry);
server.dirty++; server.dirty++;
removed++; removed++;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment