Skip to content

Commit 513524e

Browse files
authored
Optimize counter initialization by reducing the number of bulk counter poll calls and communication between swss/sairedis (#49)
<!-- Please make sure you have read and understood the contribution guildlines: https://github.com/Azure/SONiC/blob/gh-pages/CONTRIBUTING.md 1. Make sure your commit includes a signature generted with `git commit -s` 2. Make sure your commit title follows the correct format: [component]: description 3. Make sure your commit message contains enough details about the change and related tests 4. Make sure your pull request adds related reviewers, asignees, labels Please also provide the following information in this pull request: --> **What I did** Optimize counter initialization by reducing the number of bulk counter poll calls and communication between swss(orchagent)/sairedis(syncd) during initialization. Originally, `orchagent` notifies `syncd` to initialize the counter using an extended sairedis call `SAI_REDIS_SWITCH_ATTR_FLEX_COUNTER` for each SAI object with the object ID as the key, which means the number of the extended sairedis calls is identical as the number of objects. It takes time to finish all the extended sairedis calls. Now, for counter groups that have many objects (e.g., port, PG, queues, etc), `orchagent` notifies `syncd` to initialize the counter using a single extend sairedis call with many objects' ID as the key (format: `<key1>,<key2>,...<keyn>`). So, it takes much less time to initialize the counters because fewer extend sairedis calls are required. HLD sonic-net/SONiC#1862 Depends on sonic-net/sonic-sairedis#1527 **Why I did it** **How I verified it** Unit test (mock test) and regression. **Details if related** - In sairedis, the bulk counter is supported for all counter groups except `Buffer Pool Counter` and `DASH ENI counter`. - In swss, bulk counter for the following counter groups - priority group watermark - priority group drop - queue watermark - queue stat - PFC watchdog - WRED/ECN counter
1 parent b87da49 commit 513524e

11 files changed

Lines changed: 488 additions & 217 deletions

File tree

orchagent/bufferorch.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1858,6 +1858,7 @@ void BufferOrch::doTask()
18581858
continue;
18591859
consumer->drain();
18601860
}
1861+
gPortsOrch->flushCounters();
18611862
}
18621863

18631864
void BufferOrch::doTask(Consumer &consumer)
@@ -1921,4 +1922,6 @@ void BufferOrch::doTask(Consumer &consumer)
19211922
{
19221923
(this->*(m_bufferFlushHandlerMap[map_type_name]))(consumer);
19231924
}
1925+
1926+
gPortsOrch->flushCounters();
19241927
}

orchagent/flex_counter/flex_counter_manager.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
#include "schema.h"
66
#include "rediscommand.h"
77
#include "logger.h"
8-
#include "sai_serialize.h"
98

109
#include <macsecorch.h>
1110

@@ -20,14 +19,13 @@ using swss::ProducerTable;
2019

2120
extern sai_switch_api_t *sai_switch_api;
2221

23-
extern sai_object_id_t gSwitchId;
24-
2522
const string FLEX_COUNTER_ENABLE("enable");
2623
const string FLEX_COUNTER_DISABLE("disable");
2724

2825
const unordered_map<StatsMode, string> FlexCounterManager::stats_mode_lookup =
2926
{
3027
{ StatsMode::READ, STATS_MODE_READ },
28+
{ StatsMode::READ_AND_CLEAR, STATS_MODE_READ_AND_CLEAR },
3129
};
3230

3331
const unordered_map<bool, string> FlexCounterManager::status_lookup =
@@ -42,6 +40,8 @@ const unordered_map<CounterType, string> FlexCounterManager::counter_id_field_lo
4240
{ CounterType::SWITCH_DEBUG, SWITCH_DEBUG_COUNTER_ID_LIST },
4341
{ CounterType::PORT, PORT_COUNTER_ID_LIST },
4442
{ CounterType::QUEUE, QUEUE_COUNTER_ID_LIST },
43+
{ CounterType::QUEUE_ATTR, QUEUE_ATTR_ID_LIST },
44+
{ CounterType::PRIORITY_GROUP, PG_COUNTER_ID_LIST },
4545
{ CounterType::MACSEC_SA_ATTR, MACSEC_SA_ATTR_ID_LIST },
4646
{ CounterType::MACSEC_SA, MACSEC_SA_COUNTER_ID_LIST },
4747
{ CounterType::MACSEC_FLOW, MACSEC_FLOW_COUNTER_ID_LIST },
@@ -259,7 +259,7 @@ string FlexCounterManager::getFlexCounterTableKey(
259259

260260
// serializeCounterStats turns a set of stats into a format suitable for FLEX_COUNTER_DB.
261261
string FlexCounterManager::serializeCounterStats(
262-
const unordered_set<string>& counter_stats) const
262+
const unordered_set<string>& counter_stats)
263263
{
264264
SWSS_LOG_ENTER();
265265

orchagent/flex_counter/flex_counter_manager.h

Lines changed: 238 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,26 @@
99
#include "producertable.h"
1010
#include "table.h"
1111
#include <inttypes.h>
12+
#include <type_traits>
13+
#include "sai_serialize.h"
14+
#include "saihelper.h"
1215

1316
extern "C" {
1417
#include "sai.h"
1518
}
1619

1720
enum class StatsMode
1821
{
19-
READ
22+
READ,
23+
READ_AND_CLEAR
2024
};
2125

2226
enum class CounterType
2327
{
2428
PORT,
2529
QUEUE,
30+
QUEUE_ATTR,
31+
PRIORITY_GROUP,
2632
PORT_DEBUG,
2733
SWITCH_DEBUG,
2834
MACSEC_SA_ATTR,
@@ -35,13 +41,18 @@ enum class CounterType
3541
ENI
3642
};
3743

44+
extern bool gTraditionalFlexCounter;
45+
extern sai_object_id_t gSwitchId;
46+
47+
struct CachedObjects;
3848
// FlexCounterManager allows users to manage a group of flex counters.
3949
//
4050
// TODO: FlexCounterManager doesn't currently support the full range of
4151
// flex counter features. In particular, support for standard (i.e. non-debug)
4252
// counters and support for plugins needs to be added.
4353
class FlexCounterManager
4454
{
55+
friend struct CachedObjects;
4556
public:
4657
FlexCounterManager(
4758
const std::string& group_name,
@@ -69,12 +80,12 @@ class FlexCounterManager
6980
void enableFlexCounterGroup();
7081
void disableFlexCounterGroup();
7182

72-
void setCounterIdList(
83+
virtual void setCounterIdList(
7384
const sai_object_id_t object_id,
7485
const CounterType counter_type,
7586
const std::unordered_set<std::string>& counter_stats,
7687
const sai_object_id_t switch_id=SAI_NULL_OBJECT_ID);
77-
void clearCounterIdList(const sai_object_id_t object_id);
88+
virtual void clearCounterIdList(const sai_object_id_t object_id);
7889

7990
const std::string& getGroupName() const
8091
{
@@ -99,12 +110,9 @@ class FlexCounterManager
99110
protected:
100111
void applyGroupConfiguration();
101112

102-
private:
103113
std::string getFlexCounterTableKey(
104114
const std::string& group_name,
105115
const sai_object_id_t object_id) const;
106-
std::string serializeCounterStats(
107-
const std::unordered_set<std::string>& counter_stats) const;
108116

109117
std::string group_name;
110118
StatsMode stats_mode;
@@ -114,11 +122,235 @@ class FlexCounterManager
114122
std::unordered_map<sai_object_id_t, sai_object_id_t> installed_counters;
115123
bool is_gearbox;
116124

125+
static std::string serializeCounterStats(
126+
const std::unordered_set<std::string>& counter_stats);
127+
117128
static const std::unordered_map<StatsMode, std::string> stats_mode_lookup;
118129
static const std::unordered_map<bool, std::string> status_lookup;
119130
static const std::unordered_map<CounterType, std::string> counter_id_field_lookup;
120131
};
121132

133+
struct CachedObjects
134+
{
135+
CounterType pending_counter_type;
136+
sai_object_id_t pending_switch_id;
137+
std::unordered_set<std::string> pending_counter_stats;
138+
std::unordered_set<sai_object_id_t> pending_sai_objects;
139+
140+
bool try_cache(const sai_object_id_t object_id,
141+
const CounterType counter_type,
142+
const std::unordered_set<std::string>& counter_stats,
143+
sai_object_id_t switch_id)
144+
{
145+
if (pending_sai_objects.empty())
146+
{
147+
pending_counter_type = counter_type;
148+
pending_switch_id = switch_id;
149+
// Just to avoid recreating counter IDs
150+
if (pending_counter_stats != counter_stats)
151+
{
152+
pending_counter_stats = counter_stats;
153+
}
154+
}
155+
else if (counter_type != pending_counter_type ||
156+
switch_id != pending_switch_id ||
157+
counter_stats != pending_counter_stats)
158+
{
159+
return false;
160+
}
161+
162+
cache(object_id);
163+
164+
return true;
165+
}
166+
167+
bool is_cached(const sai_object_id_t object_id)
168+
{
169+
return pending_sai_objects.find(object_id) != pending_sai_objects.end();
170+
}
171+
172+
void flush(const std::string &group_name)
173+
{
174+
if (pending_sai_objects.empty())
175+
{
176+
return;
177+
}
178+
179+
auto counter_ids = FlexCounterManager::serializeCounterStats(pending_counter_stats);
180+
auto counter_type_it = FlexCounterManager::counter_id_field_lookup.find(pending_counter_type);
181+
182+
auto counter_keys = group_name + ":";
183+
for (const auto& oid: pending_sai_objects)
184+
{
185+
counter_keys += sai_serialize_object_id(oid) + ",";
186+
}
187+
counter_keys.pop_back();
188+
189+
startFlexCounterPolling(pending_switch_id, counter_keys, counter_ids, counter_type_it->second);
190+
191+
pending_sai_objects.clear();
192+
}
193+
194+
void cache(sai_object_id_t object_id)
195+
{
196+
pending_sai_objects.emplace(object_id);
197+
}
198+
};
199+
200+
class FlexCounterCachedManager : public FlexCounterManager
201+
{
202+
public:
203+
FlexCounterCachedManager(
204+
const std::string& group_name,
205+
const StatsMode stats_mode,
206+
const uint polling_interval,
207+
const bool enabled,
208+
swss::FieldValueTuple fv_plugin = std::make_pair("","")) :
209+
FlexCounterManager(group_name, stats_mode, polling_interval, enabled, fv_plugin)
210+
{
211+
}
212+
213+
virtual void flush()
214+
{
215+
}
216+
217+
protected:
218+
void flush(const std::string &group_name, struct CachedObjects &cached_objects)
219+
{
220+
cached_objects.flush(group_name);
221+
}
222+
223+
void setCounterIdList(
224+
struct CachedObjects &cached_objects,
225+
const sai_object_id_t object_id,
226+
const CounterType counter_type,
227+
const std::unordered_set<std::string>& counter_stats,
228+
const sai_object_id_t switch_id=SAI_NULL_OBJECT_ID)
229+
{
230+
if (gTraditionalFlexCounter)
231+
{
232+
// Unable to cache an object and initialize in bulk in traditional flex counter mode
233+
FlexCounterManager::setCounterIdList(object_id, counter_type, counter_stats, switch_id);
234+
return;
235+
}
236+
237+
auto effective_switch_id = switch_id == SAI_NULL_OBJECT_ID ? gSwitchId : switch_id;
238+
installed_counters[object_id] = effective_switch_id;
239+
if (cached_objects.try_cache(object_id, counter_type, counter_stats, effective_switch_id))
240+
{
241+
return;
242+
}
243+
else
244+
{
245+
flush(group_name, cached_objects);
246+
cached_objects.cache(object_id);
247+
}
248+
}
249+
250+
void clearCounterIdList(
251+
struct CachedObjects &cached_objects,
252+
const sai_object_id_t object_id)
253+
{
254+
auto search = cached_objects.pending_sai_objects.find(object_id);
255+
if (search == cached_objects.pending_sai_objects.end())
256+
{
257+
FlexCounterManager::clearCounterIdList(object_id);
258+
}
259+
else
260+
{
261+
installed_counters.erase(object_id);
262+
cached_objects.pending_sai_objects.erase(search);
263+
}
264+
}
265+
};
266+
267+
template <typename TagType, typename Enable=void>
268+
class FlexCounterTaggedCachedManager : public FlexCounterCachedManager
269+
{
270+
public:
271+
FlexCounterTaggedCachedManager(
272+
const std::string& group_name,
273+
const StatsMode stats_mode,
274+
const uint polling_interval,
275+
const bool enabled,
276+
swss::FieldValueTuple fv_plugin = std::make_pair("","")) :
277+
FlexCounterCachedManager(group_name, stats_mode, polling_interval, enabled, fv_plugin)
278+
{
279+
}
280+
281+
void flush()
282+
{
283+
FlexCounterCachedManager::flush(group_name, cached_objects);
284+
}
285+
286+
virtual void setCounterIdList(
287+
const sai_object_id_t object_id,
288+
const CounterType counter_type,
289+
const std::unordered_set<std::string>& counter_stats,
290+
const sai_object_id_t switch_id=SAI_NULL_OBJECT_ID)
291+
{
292+
FlexCounterCachedManager::setCounterIdList(cached_objects,
293+
object_id,
294+
counter_type,
295+
counter_stats);
296+
}
297+
298+
virtual void clearCounterIdList(
299+
const sai_object_id_t object_id)
300+
{
301+
FlexCounterCachedManager::clearCounterIdList(cached_objects, object_id);
302+
}
303+
304+
private:
305+
struct CachedObjects cached_objects;
306+
};
307+
308+
template <typename TagType>
309+
class FlexCounterTaggedCachedManager<TagType, typename std::enable_if_t<std::is_enum<TagType>::value>> : public FlexCounterCachedManager
310+
{
311+
public:
312+
FlexCounterTaggedCachedManager(
313+
const std::string& group_name,
314+
const StatsMode stats_mode,
315+
const uint polling_interval,
316+
const bool enabled,
317+
swss::FieldValueTuple fv_plugin = std::make_pair("","")) :
318+
FlexCounterCachedManager(group_name, stats_mode, polling_interval, enabled, fv_plugin)
319+
{
320+
}
321+
322+
void flush()
323+
{
324+
for(auto &it : cached_objects)
325+
{
326+
FlexCounterCachedManager::flush(group_name, it.second);
327+
}
328+
}
329+
330+
void setCounterIdList(
331+
const sai_object_id_t object_id,
332+
const CounterType counter_type,
333+
const std::unordered_set<std::string>& counter_stats,
334+
const TagType tag,
335+
const sai_object_id_t switch_id=SAI_NULL_OBJECT_ID)
336+
{
337+
FlexCounterCachedManager::setCounterIdList(cached_objects[tag],
338+
object_id,
339+
counter_type,
340+
counter_stats);
341+
}
342+
343+
void clearCounterIdList(
344+
const sai_object_id_t object_id,
345+
const TagType tag)
346+
{
347+
FlexCounterCachedManager::clearCounterIdList(cached_objects[tag], object_id);
348+
}
349+
350+
private:
351+
std::map<TagType, struct CachedObjects> cached_objects;
352+
};
353+
122354
class FlexManagerDirectory
123355
{
124356
public:

orchagent/flexcounterorch.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,7 @@ void FlexCounterOrch::doTask(Consumer &consumer)
271271
}
272272
}
273273

274+
gPortsOrch->flushCounters();
274275
setFlexCounterGroupOperation(flexCounterGroupMap[key], value);
275276

276277
if (gPortsOrch && gPortsOrch->isGearboxEnabled())

0 commit comments

Comments
 (0)