-
Notifications
You must be signed in to change notification settings - Fork 543
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
[ResponsePublisher] add pipeline support #2511
Changes from 2 commits
d176722
dfd360d
235bbde
8a35189
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -90,7 +90,10 @@ void RecordResponse(const std::string &response_channel, const std::string &key, | |
|
||
} // namespace | ||
|
||
ResponsePublisher::ResponsePublisher() : m_db("APPL_STATE_DB", 0) | ||
ResponsePublisher::ResponsePublisher(bool buffered) : | ||
m_db(std::make_unique<swss::DBConnector>("APPL_STATE_DB", 0)), | ||
m_pipe(std::make_unique<swss::RedisPipeline>(m_db.get())), | ||
m_buffered(buffered) | ||
{ | ||
} | ||
|
||
|
@@ -107,17 +110,14 @@ void ResponsePublisher::publish(const std::string &table, const std::string &key | |
} | ||
|
||
std::string response_channel = "APPL_DB_" + table + "_RESPONSE_CHANNEL"; | ||
if (m_notifiers.find(table) == m_notifiers.end()) | ||
{ | ||
m_notifiers[table] = std::make_unique<swss::NotificationProducer>(&m_db, response_channel); | ||
} | ||
swss::NotificationProducer notificationProducer{m_pipe.get(), response_channel, m_buffered}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @qiluo-msft I find it cheap, just arguments copy. It might be cheaper then a hash table lookup, depending on hash function and a load factor, so without it it takes a bit more deterministic time. In my testing old and new implementation show the same result (measured published responses/sec), probably bound to redis IO anyway. |
||
|
||
auto intent_attrs_copy = intent_attrs; | ||
// Add error message as the first field-value-pair. | ||
swss::FieldValueTuple err_str("err_str", PrependedComponent(status) + status.message()); | ||
intent_attrs_copy.insert(intent_attrs_copy.begin(), err_str); | ||
// Sends the response to the notification channel. | ||
m_notifiers[table]->send(status.codeStr(), key, intent_attrs_copy); | ||
notificationProducer.send(status.codeStr(), key, intent_attrs_copy); | ||
RecordResponse(response_channel, key, intent_attrs_copy, status.codeStr()); | ||
} | ||
|
||
|
@@ -140,17 +140,14 @@ void ResponsePublisher::publish(const std::string &table, const std::string &key | |
void ResponsePublisher::writeToDB(const std::string &table, const std::string &key, | ||
const std::vector<swss::FieldValueTuple> &values, const std::string &op, bool replace) | ||
{ | ||
if (m_tables.find(table) == m_tables.end()) | ||
{ | ||
m_tables[table] = std::make_unique<swss::Table>(&m_db, table); | ||
} | ||
swss::Table applStateTable{m_pipe.get(), table, m_buffered}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @qiluo-msft Same as above #2511 (comment) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I assume the argument is "arguments copy". Seem the constructor is not just arguments copy. For example: There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @qiluo-msft So it's one find with an integer key + arguments copy vs 2 finds with string keys. static void BM_newResponsePublisher(benchmark::State& state) {
ResponsePublisher publisher{};
for (auto _ : state) {
publisher.publish("SOME_TABLE", "SOME_KEY", {}, ReturnCode(SAI_STATUS_SUCCESS));
}
}
static void BM_oldResponsePublisher(benchmark::State& state) {
old::ResponsePublisher publisher{};
for (auto _ : state) {
publisher.publish("SOME_TABLE", "SOME_KEY", {}, ReturnCode(SAI_STATUS_SUCCESS));
}
} Compiled with:
Full code is here - https://github.com/stepanblyschak/sonic-swss/blob/response-publisher-benchmarks/benchmarks/main.cpp
Most of the time it is IO bound of course, but I constantly get a little bit better result with new implementation every time a run the benchmark. So, the caching makes it even a little bit worse and the new implementation is 3.16 % faster. Please note, that both don't use redis pipeline as the new implementation will clearly be a winner by a couple of times. |
||
|
||
auto attrs = values; | ||
if (op == SET_COMMAND) | ||
{ | ||
if (replace) | ||
{ | ||
m_tables[table]->del(key); | ||
applStateTable.del(key); | ||
} | ||
if (!values.size()) | ||
{ | ||
|
@@ -160,9 +157,9 @@ void ResponsePublisher::writeToDB(const std::string &table, const std::string &k | |
// Write to DB only if the key does not exist or non-NULL attributes are | ||
// being written to the entry. | ||
std::vector<swss::FieldValueTuple> fv; | ||
if (!m_tables[table]->get(key, fv)) | ||
if (!applStateTable.get(key, fv)) | ||
{ | ||
m_tables[table]->set(key, attrs); | ||
applStateTable.set(key, attrs); | ||
RecordDBWrite(table, key, attrs, op); | ||
return; | ||
} | ||
|
@@ -179,13 +176,23 @@ void ResponsePublisher::writeToDB(const std::string &table, const std::string &k | |
} | ||
if (attrs.size()) | ||
{ | ||
m_tables[table]->set(key, attrs); | ||
applStateTable.set(key, attrs); | ||
RecordDBWrite(table, key, attrs, op); | ||
} | ||
} | ||
else if (op == DEL_COMMAND) | ||
{ | ||
m_tables[table]->del(key); | ||
applStateTable.del(key); | ||
RecordDBWrite(table, key, {}, op); | ||
} | ||
} | ||
|
||
void ResponsePublisher::flush() | ||
{ | ||
m_pipe->flush(); | ||
} | ||
|
||
void ResponsePublisher::setBuffered(bool buffered) | ||
{ | ||
m_buffered = buffered; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You are assuming m_pipe initialized after m_db. The sequence is tricky. Suggest move m_pipe to function body. #Closed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@qiluo-msft Same reply sonic-net/sonic-swss-common#708 (comment)