Skip to content

Commit 1325cdf

Browse files
authored
Add support for saiplayer bulk API and add performance timers (#666)
* [sairedis] Add PerformanceIntervalTimer class * [sairedis] Add deserialize tests * [sairedis] Add performance timer to route_entry bulk create * [sairedis] Add PerformanceIntervalTimer class to makefile * [saiplayer] Add support for bulk generic API and bulk route_entry * [vs] Add performance timer for route_entry create API * [syncd] Fix for ZeroMQSelectableChannel thread join * [syncd] Add performance timers to syncd route_entry create and db
1 parent 1d84b90 commit 1325cdf

11 files changed

+627
-45
lines changed

lib/inc/PerformanceIntervalTimer.h

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#pragma once
2+
3+
#include "swss/sal.h"
4+
5+
#include <chrono>
6+
#include <string>
7+
8+
namespace sairediscommon
9+
{
10+
class PerformanceIntervalTimer
11+
{
12+
public:
13+
14+
static constexpr unsigned int DEFAULT_LIMIT = 10000;
15+
16+
public:
17+
18+
PerformanceIntervalTimer(
19+
_In_ const char* msg,
20+
_In_ uint64_t limit = DEFAULT_LIMIT);
21+
22+
~PerformanceIntervalTimer() = default; // non virtual
23+
24+
public:
25+
26+
void start();
27+
28+
void stop();
29+
30+
void inc(
31+
_In_ uint64_t val = 1);
32+
33+
void reset();
34+
35+
public:
36+
37+
static bool m_enable;
38+
39+
private:
40+
41+
std::string m_msg;
42+
43+
std::chrono::time_point<std::chrono::high_resolution_clock> m_start;
44+
std::chrono::time_point<std::chrono::high_resolution_clock> m_stop;
45+
46+
uint64_t m_limit;
47+
uint64_t m_count;
48+
uint64_t m_calls;
49+
uint64_t m_total;
50+
};
51+
}

lib/src/Makefile.am

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ lib_LTLIBRARIES = libsairedis.la
1010

1111
noinst_LIBRARIES = libSaiRedis.a
1212
libSaiRedis_a_SOURCES = \
13+
PerformanceIntervalTimer.cpp \
1314
ZeroMQChannel.cpp \
1415
Channel.cpp \
1516
Context.cpp \

lib/src/PerformanceIntervalTimer.cpp

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
#include "PerformanceIntervalTimer.h"
2+
3+
#include "swss/logger.h"
4+
5+
using namespace sairediscommon;
6+
7+
bool PerformanceIntervalTimer::m_enable = true;
8+
9+
PerformanceIntervalTimer::PerformanceIntervalTimer(
10+
_In_ const char*msg,
11+
_In_ uint64_t limit):
12+
m_msg(msg),
13+
m_limit(limit)
14+
{
15+
SWSS_LOG_ENTER();
16+
17+
reset();
18+
}
19+
20+
void PerformanceIntervalTimer::start()
21+
{
22+
SWSS_LOG_ENTER();
23+
24+
m_start = std::chrono::high_resolution_clock::now();
25+
}
26+
27+
void PerformanceIntervalTimer::stop()
28+
{
29+
SWSS_LOG_ENTER();
30+
31+
m_stop = std::chrono::high_resolution_clock::now();
32+
}
33+
34+
void PerformanceIntervalTimer::inc(
35+
_In_ uint64_t val)
36+
{
37+
SWSS_LOG_ENTER();
38+
39+
m_count += val;
40+
41+
m_calls++;
42+
43+
m_total += std::chrono::duration_cast<std::chrono::nanoseconds>(m_stop-m_start).count();
44+
45+
if (m_count >= m_limit)
46+
{
47+
if (m_enable)
48+
{
49+
SWSS_LOG_NOTICE("%zu (calls %zu) %s op took: %zu ms", m_count, m_calls, m_msg.c_str(), m_total/1000000);
50+
}
51+
52+
reset();
53+
}
54+
}
55+
56+
void PerformanceIntervalTimer::reset()
57+
{
58+
SWSS_LOG_ENTER();
59+
60+
m_count = 0;
61+
m_calls = 0;
62+
m_total = 0;
63+
}

lib/src/RedisRemoteSaiInterface.cpp

+13-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "SkipRecordAttrContainer.h"
77
#include "SwitchContainer.h"
88
#include "ZeroMQChannel.h"
9+
#include "PerformanceIntervalTimer.h"
910

1011
#include "sairediscommon.h"
1112

@@ -16,6 +17,7 @@
1617

1718
using namespace sairedis;
1819
using namespace saimeta;
20+
using namespace sairediscommon;
1921
using namespace std::placeholders;
2022

2123
std::string joinFieldValues(
@@ -1541,6 +1543,10 @@ sai_status_t RedisRemoteSaiInterface::bulkCreate(
15411543

15421544
// TODO support mode
15431545

1546+
static PerformanceIntervalTimer timer("RedisRemoteSaiInterface::bulkCreate(route_entry)");
1547+
1548+
timer.start();
1549+
15441550
std::vector<std::string> serialized_object_ids;
15451551

15461552
// on create vid is put in db by syncd
@@ -1550,15 +1556,20 @@ sai_status_t RedisRemoteSaiInterface::bulkCreate(
15501556
serialized_object_ids.push_back(str_object_id);
15511557
}
15521558

1553-
return bulkCreate(
1559+
auto status = bulkCreate(
15541560
SAI_OBJECT_TYPE_ROUTE_ENTRY,
15551561
serialized_object_ids,
15561562
attr_count,
15571563
attr_list,
15581564
mode,
15591565
object_statuses);
1560-
}
15611566

1567+
timer.stop();
1568+
1569+
timer.inc(object_count);
1570+
1571+
return status;
1572+
}
15621573

15631574
sai_status_t RedisRemoteSaiInterface::bulkCreate(
15641575
_In_ uint32_t object_count,

lib/src/tests.cpp

+186
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ extern "C" {
66

77
#include "swss/logger.h"
88
#include "swss/table.h"
9+
#include "swss/tokenize.h"
910

1011
#include "meta/sai_serialize.h"
1112
#include "meta/SaiAttributeList.h"
@@ -104,6 +105,63 @@ void test_serialize_remove_route_entry(int n)
104105
std::cout << "ms: " << (double)us.count()/1000 << " / " << n << std::endl;
105106
}
106107

108+
void test_deserialize_route_entry_meta(int n)
109+
{
110+
SWSS_LOG_ENTER();
111+
112+
// meta key 123ms/10k
113+
auto s = serialize_route_entry();
114+
// auto s = sai_serialize_route_entry(get_route_entry());
115+
116+
std::cout << s << std::endl;
117+
118+
auto start = std::chrono::high_resolution_clock::now();
119+
120+
for (int i = 0; i < n; i++)
121+
{
122+
sai_object_meta_key_t mk;
123+
sai_deserialize_object_meta_key(s, mk);
124+
125+
//sai_route_entry_t route_entry;
126+
//sai_deserialize_route_entry(s, route_entry);
127+
}
128+
129+
auto end = std::chrono::high_resolution_clock::now();
130+
auto time = end - start;
131+
auto us = std::chrono::duration_cast<std::chrono::microseconds>(time);
132+
std::cout << "ms: " << (double)us.count()/1000 << " / " << n << std::endl;
133+
}
134+
135+
void test_deserialize_route_entry(int n)
136+
{
137+
SWSS_LOG_ENTER();
138+
139+
// 7.2 ms
140+
// 8.9 ms with try/catch
141+
// 13ms for entire object meta key
142+
143+
char buffer[1000];
144+
145+
sai_route_entry_t route_entry = get_route_entry();
146+
sai_serialize_route_entry(buffer, &route_entry);
147+
148+
auto s = std::string(buffer);
149+
150+
std::cout << s << std::endl;
151+
152+
auto start = std::chrono::high_resolution_clock::now();
153+
154+
for (int i = 0; i < n; i++)
155+
{
156+
sai_deserialize_route_entry(s.c_str(), &route_entry);
157+
}
158+
159+
auto end = std::chrono::high_resolution_clock::now();
160+
auto time = end - start;
161+
auto us = std::chrono::duration_cast<std::chrono::microseconds>(time);
162+
std::cout << "ms: " << (double)us.count()/1000 << " / " << n << std::endl;
163+
}
164+
107165
void test_serialize_remove_oid(int n)
108166
{
109167
SWSS_LOG_ENTER();
@@ -664,14 +722,142 @@ void test_ContextConfigContainer()
664722
auto ccc = ContextConfigContainer::loadFromFile("context_config.json");
665723
}
666724

725+
static std::vector<std::string> tokenize(
726+
_In_ std::string input,
727+
_In_ const std::string &delim)
728+
{
729+
SWSS_LOG_ENTER();
730+
731+
/*
732+
* input is modified so it can't be passed as reference
733+
*/
734+
735+
std::vector<std::string> tokens;
736+
737+
size_t pos = 0;
738+
739+
while ((pos = input.find(delim)) != std::string::npos)
740+
{
741+
std::string token = input.substr(0, pos);
742+
743+
input.erase(0, pos + delim.length());
744+
tokens.push_back(token);
745+
}
746+
747+
tokens.push_back(input);
748+
749+
return tokens;
750+
}
751+
752+
static sai_object_type_t deserialize_object_type(
753+
_In_ const std::string& s)
754+
{
755+
SWSS_LOG_ENTER();
756+
757+
sai_object_type_t object_type;
758+
759+
sai_deserialize_object_type(s, object_type);
760+
761+
return object_type;
762+
}
763+
764+
void test_tokenize_bulk_route_entry()
765+
{
766+
SWSS_LOG_ENTER();
767+
768+
auto header = "2020-09-24.21:06:54.045505|C|SAI_OBJECT_TYPE_ROUTE_ENTRY";
769+
auto route = "||{\"dest\":\"20c1:bb0:0:80::/64\",\"switch_id\":\"oid:0x21000000000000\",\"vr\":\"oid:0x3000000000022\"}|SAI_ROUTE_ENTRY_ATTR_NEXT_HOP_ID=oid:0x500000000066c";
770+
771+
std::string line = header;
772+
773+
int per = 100;
774+
775+
for (int i = 0; i < per; i++)
776+
{
777+
line += route;
778+
}
779+
780+
auto tstart = std::chrono::high_resolution_clock::now();
781+
782+
int n = 1000;
783+
784+
for (int c = 0; c < n; c++)
785+
{
786+
auto fields = tokenize(line, "||");
787+
788+
auto first = fields.at(0); // timestamp|action|objecttype
789+
790+
std::string str_object_type = swss::tokenize(first, '|').at(2);
791+
792+
sai_object_type_t object_type = deserialize_object_type(str_object_type);
793+
794+
std::vector<std::string> object_ids;
795+
796+
std::vector<std::shared_ptr<SaiAttributeList>> attributes;
797+
798+
for (size_t idx = 1; idx < fields.size(); ++idx)
799+
{
800+
// object_id|attr=value|...
801+
const std::string &joined = fields[idx];
802+
803+
auto split = swss::tokenize(joined, '|');
804+
805+
std::string str_object_id = split.front();
806+
807+
object_ids.push_back(str_object_id);
808+
809+
std::vector<swss::FieldValueTuple> entries; // attributes per object id
810+
811+
SWSS_LOG_DEBUG("processing: %s", joined.c_str());
812+
813+
for (size_t i = 1; i < split.size(); ++i)
814+
{
815+
const auto &item = split[i];
816+
817+
auto start = item.find_first_of("=");
818+
819+
auto field = item.substr(0, start);
820+
auto value = item.substr(start + 1);
821+
822+
swss::FieldValueTuple entry(field, value);
823+
824+
entries.push_back(entry);
825+
}
826+
827+
// since now we converted this to proper list, we can extract attributes
828+
829+
std::shared_ptr<SaiAttributeList> list =
830+
std::make_shared<SaiAttributeList>(object_type, entries, false);
831+
832+
attributes.push_back(list);
833+
}
834+
}
835+
836+
auto tend = std::chrono::high_resolution_clock::now();
837+
auto time = tend - tstart;
838+
auto us = std::chrono::duration_cast<std::chrono::microseconds>(time);
839+
840+
std::cout << "ms: " << (double)us.count()/1000.0 / n << " n " << n << " / per " << per << std::endl;
841+
std::cout << "s: " << (double)us.count()/1000000.0 << " for total routes: " <<( n * per) << std::endl;
842+
}
843+
667844
int main()
668845
{
669846
SWSS_LOG_ENTER();
670847

848+
std::cout << " * test tokenize bulk route entry" << std::endl;
849+
850+
test_tokenize_bulk_route_entry();
851+
671852
std::cout << " * test ContextConfigContainer" << std::endl;
672853

673854
test_ContextConfigContainer();
674855

856+
std::cout << " * test deserialize route_entry" << std::endl;
857+
858+
test_deserialize_route_entry_meta(10000);
859+
test_deserialize_route_entry(10000);
860+
675861
std::cout << " * test remove" << std::endl;
676862

677863
test_serialize_remove_route_entry(10000);

0 commit comments

Comments
 (0)