From 3387d59b49ca98521ae30110f9d83ff1d17fb365 Mon Sep 17 00:00:00 2001 From: matyhtf Date: Thu, 3 Sep 2020 12:56:55 +0800 Subject: [PATCH 1/3] Optimize table initialization performance --- core-tests/src/memory/table.cpp | 2 +- include/swoole_table.h | 22 ++++++++- src/memory/table.cc | 41 ++++++++-------- swoole_table.cc | 85 +++++++++++++++++++++++---------- 4 files changed, 100 insertions(+), 50 deletions(-) diff --git a/core-tests/src/memory/table.cpp b/core-tests/src/memory/table.cpp index f4283445415..ba647ef4b33 100644 --- a/core-tests/src/memory/table.cpp +++ b/core-tests/src/memory/table.cpp @@ -69,7 +69,7 @@ class table_t { bool set(const std::string &key, const row_t &value) { swTableRow *_rowlock = nullptr; - swTableRow *row = swTableRow_set(table, key.c_str(), key.length(), &_rowlock); + swTableRow *row = swTableRow_set(table, key.c_str(), key.length(), &_rowlock, nullptr); if (!row) { swTableRow_unlock(_rowlock); return false; diff --git a/include/swoole_table.h b/include/swoole_table.h index 4dbeb94d022..2856acd3bf5 100644 --- a/include/swoole_table.h +++ b/include/swoole_table.h @@ -29,6 +29,8 @@ #include #include +#define SW_TABLE_DEBUG 1 + typedef uint32_t swTable_string_length_t; struct swTableRow { @@ -62,6 +64,11 @@ enum swTableColumn_type { SW_TABLE_STRING, }; +enum swTable_flag { + SW_TABLE_FLAG_NEW_ROW = 1, + SW_TABLE_FLAG_CONFLICT = 1u << 1, +}; + struct swTableColumn { enum swTableColumn_type type; uint32_t size; @@ -112,6 +119,12 @@ struct swTable { pid_t create_pid; void *memory; + +#ifdef SW_TABLE_DEBUG + int conflict_count; + int insert_count; + int conflict_max_level; +#endif }; swTable *swTable_new(uint32_t rows_size, float conflict_proportion); @@ -119,7 +132,7 @@ size_t swTable_get_memory_size(swTable *table); int swTable_create(swTable *table); void swTable_free(swTable *table); bool swTableColumn_add(swTable *table, const std::string &name, enum swTableColumn_type type, size_t size); -swTableRow *swTableRow_set(swTable *table, const char *key, uint16_t keylen, swTableRow **rowlock); +swTableRow *swTableRow_set(swTable *table, const char *key, uint16_t keylen, swTableRow **rowlock, int *out_flags); swTableRow *swTableRow_get(swTable *table, const char *key, uint16_t keylen, swTableRow **rowlock); void swTable_iterator_rewind(swTable *table); @@ -204,8 +217,13 @@ static sw_inline void swTableRow_set_value(swTableRow *row, swTableColumn *col, swWarn("[key=%s,field=%s]string value is too long", row->key, col->name.c_str()); vlen = col->size - sizeof(swTable_string_length_t); } + if (value == nullptr) { + vlen = 0; + } memcpy(row->data + col->index, &vlen, sizeof(swTable_string_length_t)); - memcpy(row->data + col->index + sizeof(swTable_string_length_t), value, vlen); + if (vlen > 0) { + memcpy(row->data + col->index + sizeof(swTable_string_length_t), value, vlen); + } break; } } diff --git a/src/memory/table.cc b/src/memory/table.cc index 3db3e967da6..70266affe15 100644 --- a/src/memory/table.cc +++ b/src/memory/table.cc @@ -16,15 +16,8 @@ #include "swoole_table.h" -//#define SW_TABLE_DEBUG 1 #define SW_TABLE_USE_PHP_HASH -#ifdef SW_TABLE_DEBUG -static int conflict_count = 0; -static int insert_count = 0; -static int conflict_max_level = 0; -#endif - static inline void swTable_check_key_length(uint16_t *keylen) { if (*keylen >= SW_TABLE_KEY_SIZE) { *keylen = SW_TABLE_KEY_SIZE - 1; @@ -149,11 +142,11 @@ int swTable_create(swTable *table) { void swTable_free(swTable *table) { #ifdef SW_TABLE_DEBUG - printf("swoole_table: size=%d, conflict_count=%d, conflict_max_level=%d, insert_count=%d\n", + printf("swoole_table: size=%ld, conflict_count=%d, conflict_max_level=%d, insert_count=%d\n", table->size, - conflict_count, - conflict_max_level, - insert_count); + table->conflict_count, + table->conflict_max_level, + table->insert_count); #endif auto i = table->column_map->begin(); @@ -248,20 +241,24 @@ swTableRow *swTableRow_get(swTable *table, const char *key, uint16_t keylen, swT } static inline void swTableRow_init(swTable *table, swTableRow *new_row, const char *key, int keylen) { - sw_memset_zero(new_row, sizeof(swTableRow) + table->item_size); + sw_memset_zero(new_row, sizeof(swTableRow)); memcpy(new_row->key, key, keylen); new_row->key[keylen] = '\0'; new_row->key_len = keylen; new_row->active = 1; sw_atomic_fetch_add(&(table->row_num), 1); +#ifdef SW_TABLE_DEBUG + table->insert_count++; +#endif } -swTableRow *swTableRow_set(swTable *table, const char *key, uint16_t keylen, swTableRow **rowlock) { +swTableRow *swTableRow_set(swTable *table, const char *key, uint16_t keylen, swTableRow **rowlock, int *out_flags) { swTable_check_key_length(&keylen); swTableRow *row = swTable_hash(table, key, keylen); *rowlock = row; swTableRow_lock(row); + int _out_flags = 0; #ifdef SW_TABLE_DEBUG int _conflict_level = 0; @@ -274,34 +271,36 @@ swTableRow *swTableRow_set(swTable *table, const char *key, uint16_t keylen, swT } else if (row->next == nullptr) { table->lock.lock(&table->lock); swTableRow *new_row = (swTableRow *) table->pool->alloc(table->pool, 0); - #ifdef SW_TABLE_DEBUG - conflict_count++; - if (_conflict_level > conflict_max_level) { - conflict_max_level = _conflict_level; + table->conflict_count++; + if (_conflict_level > table->conflict_max_level) { + table->conflict_max_level = _conflict_level; } - #endif table->lock.unlock(&table->lock); if (!new_row) { return nullptr; } swTableRow_init(table, new_row, key, keylen); + _out_flags |= SW_TABLE_FLAG_NEW_ROW; row->next = new_row; row = new_row; break; } else { row = row->next; + _out_flags |= SW_TABLE_FLAG_CONFLICT; #ifdef SW_TABLE_DEBUG _conflict_level++; #endif } } } else { -#ifdef SW_TABLE_DEBUG - insert_count++; -#endif swTableRow_init(table, row, key, keylen); + _out_flags |= SW_TABLE_FLAG_NEW_ROW; + } + + if (out_flags) { + *out_flags = _out_flags; } return row; diff --git a/swoole_table.cc b/swoole_table.cc index a6b46effecf..479fe22cfa8 100644 --- a/swoole_table.cc +++ b/swoole_table.cc @@ -411,8 +411,9 @@ static PHP_METHOD(swoole_table, set) { php_swoole_fatal_error(E_WARNING, "key[%s] is too long", key); } + int out_flags; swTableRow *_rowlock = nullptr; - swTableRow *row = swTableRow_set(table, key, keylen, &_rowlock); + swTableRow *row = swTableRow_set(table, key, keylen, &_rowlock, &out_flags); if (!row) { swTableRow_unlock(_rowlock); php_swoole_error(E_WARNING, "failed to set('%*s'), unable to allocate memory", (int) keylen, key); @@ -420,30 +421,59 @@ static PHP_METHOD(swoole_table, set) { } HashTable *ht = Z_ARRVAL_P(array); - char *k; - uint32_t klen; - int ktype; - zval *zv; - swTableColumn *col; - - SW_HASHTABLE_FOREACH_START2(ht, k, klen, ktype, zv) { - col = swTableColumn_get(table, std::string(k, klen)); - if (k == nullptr || col == nullptr) { - continue; - } else if (col->type == SW_TABLE_STRING) { - zend_string *str = zval_get_string(zv); - swTableRow_set_value(row, col, ZSTR_VAL(str), ZSTR_LEN(str)); - zend_string_release(str); - } else if (col->type == SW_TABLE_FLOAT) { - double _value = zval_get_double(zv); - swTableRow_set_value(row, col, &_value, 0); - } else { - long _value = zval_get_long(zv); - swTableRow_set_value(row, col, &_value, 0); + + if (out_flags & SW_TABLE_FLAG_NEW_ROW) { + for (auto i = table->column_list->begin(); i != table->column_list->end(); i++) { + swTableColumn *col = *i; + zval *zv = zend_hash_str_find(ht, col->name.c_str(), col->name.length()); + if (zv == nullptr || ZVAL_IS_NULL(zv)) { + if (col->type == SW_TABLE_STRING) { + swTableRow_set_value(row, col, nullptr, 0); + } else if (col->type == SW_TABLE_FLOAT) { + double _value = 0; + swTableRow_set_value(row, col, &_value, 0); + } else { + long _value = zval_get_long(zv); + swTableRow_set_value(row, col, &_value, 0); + } + } else { + if (col->type == SW_TABLE_STRING) { + zend_string *str = zval_get_string(zv); + swTableRow_set_value(row, col, ZSTR_VAL(str), ZSTR_LEN(str)); + zend_string_release(str); + } else if (col->type == SW_TABLE_FLOAT) { + double _value = zval_get_double(zv); + swTableRow_set_value(row, col, &_value, 0); + } else { + long _value = zval_get_long(zv); + swTableRow_set_value(row, col, &_value, 0); + } + } + } + } else { + const char *k; + uint32_t klen; + int ktype; + zval *zv; + SW_HASHTABLE_FOREACH_START2(ht, k, klen, ktype, zv) { + swTableColumn *col = swTableColumn_get(table, std::string(k, klen)); + if (k == nullptr || col == nullptr) { + continue; + } else if (col->type == SW_TABLE_STRING) { + zend_string *str = zval_get_string(zv); + swTableRow_set_value(row, col, ZSTR_VAL(str), ZSTR_LEN(str)); + zend_string_release(str); + } else if (col->type == SW_TABLE_FLOAT) { + double _value = zval_get_double(zv); + swTableRow_set_value(row, col, &_value, 0); + } else { + long _value = zval_get_long(zv); + swTableRow_set_value(row, col, &_value, 0); + } } + (void) ktype; + SW_HASHTABLE_FOREACH_END(); } - (void) ktype; - SW_HASHTABLE_FOREACH_END(); swTableRow_unlock(_rowlock); RETURN_TRUE; } @@ -464,8 +494,9 @@ static PHP_METHOD(swoole_table, incr) { RETURN_FALSE; } + int out_flags; swTableRow *_rowlock = nullptr; - swTableRow *row = swTableRow_set(table, key, key_len, &_rowlock); + swTableRow *row = swTableRow_set(table, key, key_len, &_rowlock, &out_flags); if (!row) { swTableRow_unlock(_rowlock); php_swoole_fatal_error(E_WARNING, "unable to allocate memory"); @@ -517,8 +548,9 @@ static PHP_METHOD(swoole_table, decr) { RETURN_FALSE; } + int out_flags; swTableRow *_rowlock = nullptr; - swTableRow *row = swTableRow_set(table, key, key_len, &_rowlock); + swTableRow *row = swTableRow_set(table, key, key_len, &_rowlock, &out_flags); if (!row) { swTableRow_unlock(_rowlock); php_swoole_fatal_error(E_WARNING, "unable to allocate memory"); @@ -765,8 +797,9 @@ static PHP_METHOD(swoole_table_row, offsetSet) { zval *zprop_key = sw_zend_read_property_ex(swoole_table_row_ce, ZEND_THIS, SW_ZSTR_KNOWN(SW_ZEND_STR_KEY), 0); + int out_flags; swTableRow *_rowlock = nullptr; - swTableRow *row = swTableRow_set(table, Z_STRVAL_P(zprop_key), Z_STRLEN_P(zprop_key), &_rowlock); + swTableRow *row = swTableRow_set(table, Z_STRVAL_P(zprop_key), Z_STRLEN_P(zprop_key), &_rowlock, &out_flags); if (!row) { swTableRow_unlock(_rowlock); php_swoole_error(E_WARNING, "Unable to allocate memory"); From e79ba9818d72572ee14d44f63f813ebd32015b8c Mon Sep 17 00:00:00 2001 From: matyhtf Date: Thu, 3 Sep 2020 15:20:13 +0800 Subject: [PATCH 2/3] Optimize code --- include/swoole_table.h | 2 ++ src/memory/table.cc | 12 +++++++++++ swoole_table.cc | 47 ++++++++++++++++++++++++++---------------- 3 files changed, 43 insertions(+), 18 deletions(-) diff --git a/include/swoole_table.h b/include/swoole_table.h index 2856acd3bf5..b924a89a1a0 100644 --- a/include/swoole_table.h +++ b/include/swoole_table.h @@ -94,6 +94,8 @@ struct swTableColumn { break; } } + + void clear(swTableRow *row); }; struct swTable { diff --git a/src/memory/table.cc b/src/memory/table.cc index 70266affe15..fd7dcee5e3a 100644 --- a/src/memory/table.cc +++ b/src/memory/table.cc @@ -366,3 +366,15 @@ int swTableRow_del(swTable *table, const char *key, uint16_t keylen) { return SW_OK; } + +void swTableColumn::clear(swTableRow *row) { + if (type == SW_TABLE_STRING) { + swTableRow_set_value(row, this, nullptr, 0); + } else if (type == SW_TABLE_FLOAT) { + double _value = 0; + swTableRow_set_value(row, this, &_value, 0); + } else { + long _value = 0; + swTableRow_set_value(row, this, &_value, 0); + } +} diff --git a/swoole_table.cc b/swoole_table.cc index 479fe22cfa8..93e1bdcbd82 100644 --- a/swoole_table.cc +++ b/swoole_table.cc @@ -427,15 +427,7 @@ static PHP_METHOD(swoole_table, set) { swTableColumn *col = *i; zval *zv = zend_hash_str_find(ht, col->name.c_str(), col->name.length()); if (zv == nullptr || ZVAL_IS_NULL(zv)) { - if (col->type == SW_TABLE_STRING) { - swTableRow_set_value(row, col, nullptr, 0); - } else if (col->type == SW_TABLE_FLOAT) { - double _value = 0; - swTableRow_set_value(row, col, &_value, 0); - } else { - long _value = zval_get_long(zv); - swTableRow_set_value(row, col, &_value, 0); - } + col->clear(row); } else { if (col->type == SW_TABLE_STRING) { zend_string *str = zval_get_string(zv); @@ -508,7 +500,13 @@ static PHP_METHOD(swoole_table, incr) { swTableRow_unlock(_rowlock); php_swoole_fatal_error(E_WARNING, "column[%s] does not exist", col); RETURN_FALSE; - } else if (column->type == SW_TABLE_STRING) { + } + + if (out_flags & SW_TABLE_FLAG_NEW_ROW) { + column->clear(row); + } + + if (column->type == SW_TABLE_STRING) { swTableRow_unlock(_rowlock); php_swoole_fatal_error(E_WARNING, "can't execute 'incr' on a string type column"); RETURN_FALSE; @@ -562,7 +560,13 @@ static PHP_METHOD(swoole_table, decr) { swTableRow_unlock(_rowlock); php_swoole_fatal_error(E_WARNING, "column[%s] does not exist", col); RETURN_FALSE; - } else if (column->type == SW_TABLE_STRING) { + } + + if (out_flags & SW_TABLE_FLAG_NEW_ROW) { + column->clear(row); + } + + if (column->type == SW_TABLE_STRING) { swTableRow_unlock(_rowlock); php_swoole_fatal_error(E_WARNING, "can't execute 'decr' on a string type column"); RETURN_FALSE; @@ -806,22 +810,29 @@ static PHP_METHOD(swoole_table_row, offsetSet) { RETURN_FALSE; } - swTableColumn *col = swTableColumn_get(table, std::string(key, keylen)); - if (col == nullptr) { + if (out_flags & SW_TABLE_FLAG_NEW_ROW) { + for (auto i = table->column_list->begin(); i != table->column_list->end(); i++) { + (*i)->clear(row); + } + } + + swTableColumn *column = swTableColumn_get(table, std::string(key, keylen)); + if (column == nullptr) { swTableRow_unlock(_rowlock); php_swoole_fatal_error(E_WARNING, "column[%s] does not exist", key); RETURN_FALSE; } - if (col->type == SW_TABLE_STRING) { + + if (column->type == SW_TABLE_STRING) { zend_string *str = zval_get_string(value); - swTableRow_set_value(row, col, ZSTR_VAL(str), ZSTR_LEN(str)); + swTableRow_set_value(row, column, ZSTR_VAL(str), ZSTR_LEN(str)); zend_string_release(str); - } else if (col->type == SW_TABLE_FLOAT) { + } else if (column->type == SW_TABLE_FLOAT) { double _value = zval_get_double(value); - swTableRow_set_value(row, col, &_value, 0); + swTableRow_set_value(row, column, &_value, 0); } else { long _value = zval_get_long(value); - swTableRow_set_value(row, col, &_value, 0); + swTableRow_set_value(row, column, &_value, 0); } swTableRow_unlock(_rowlock); From 1ffe7589f4426dedba5baf0ca635de8b409774ad Mon Sep 17 00:00:00 2001 From: matyhtf Date: Thu, 3 Sep 2020 15:43:39 +0800 Subject: [PATCH 3/3] rename --- swoole_table.cc | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/swoole_table.cc b/swoole_table.cc index 93e1bdcbd82..efdb1ac07e2 100644 --- a/swoole_table.cc +++ b/swoole_table.cc @@ -122,13 +122,13 @@ static inline zend_object *php_swoole_table_create_object(zend_class_entry *ce) return &table->std; } -typedef struct { +struct TableRowObject { swTable *ptr; zend_object std; -} table_row_t; +}; -static inline table_row_t *php_swoole_table_row_fetch_object(zend_object *obj) { - return (table_row_t *) ((char *) obj - swoole_table_row_handlers.offset); +static inline TableRowObject *php_swoole_table_row_fetch_object(zend_object *obj) { + return (TableRowObject *) ((char *) obj - swoole_table_row_handlers.offset); } static inline swTable *php_swoole_table_row_get_ptr(zval *zobject) { @@ -152,7 +152,7 @@ static inline void php_swoole_table_row_free_object(zend_object *object) { } static inline zend_object *php_swoole_table_row_create_object(zend_class_entry *ce) { - table_row_t *table_row = (table_row_t *) zend_object_alloc(sizeof(table_row_t), ce); + TableRowObject *table_row = (TableRowObject *) zend_object_alloc(sizeof(TableRowObject), ce); zend_object_std_init(&table_row->std, ce); object_properties_init(&table_row->std, ce); table_row->std.handlers = &swoole_table_row_handlers; @@ -314,7 +314,7 @@ void php_swoole_table_minit(int module_number) { SW_SET_CLASS_CLONEABLE(swoole_table_row, sw_zend_class_clone_deny); SW_SET_CLASS_UNSET_PROPERTY_HANDLER(swoole_table_row, sw_zend_class_unset_property_deny); SW_SET_CLASS_CUSTOM_OBJECT( - swoole_table_row, php_swoole_table_row_create_object, php_swoole_table_row_free_object, table_row_t, std); + swoole_table_row, php_swoole_table_row_create_object, php_swoole_table_row_free_object, TableRowObject, std); zend_class_implements(swoole_table_row_ce, 1, zend_ce_arrayaccess); zend_declare_property_null(swoole_table_row_ce, ZEND_STRL("key"), ZEND_ACC_PUBLIC);