in syncd/FlexCounter.cpp [851:1056]
virtual void bulkAddObject(
_In_ const std::vector<sai_object_id_t>& vids,
_In_ const std::vector<sai_object_id_t>& rids,
_In_ const std::vector<std::string>& idStrings,
_In_ const std::string &per_object_stats_mode)
{
SWSS_LOG_ENTER();
sai_stats_mode_t effective_stats_mode;
// TODO: use if const expression when c++17 is supported
if (HasStatsMode<CounterIdsType>::value)
{
// Bulk operation is not supported by the counter group.
SWSS_LOG_INFO("Counter group %s %s does not support bulk. Fallback to single call", m_name.c_str(), m_instanceId.c_str());
// Fall back to old way
for (size_t i = 0; i < vids.size(); i++)
{
auto rid = rids[i];
auto vid = vids[i];
addObject(vid, rid, idStrings, per_object_stats_mode);
}
return;
}
else
{
effective_stats_mode = m_groupStatsMode;
}
std::vector<StatType> allCounterIds, supportedIds;
for (const auto &str : idStrings)
{
StatType stat;
deserializeStat(str.c_str(), &stat);
{
allCounterIds.push_back(stat);
}
}
updateSupportedCounters(rids[0]/*it is not really used*/, allCounterIds, effective_stats_mode);
for (auto stat : allCounterIds)
{
if (isCounterSupported(stat))
{
supportedIds.push_back(stat);
}
}
if (supportedIds.empty())
{
SWSS_LOG_NOTICE("%s %s does not have supported counters", m_name.c_str(), m_instanceId.c_str());
return;
}
std::map<std::vector<StatType>, std::tuple<const std::string, uint32_t>> bulkUnsupportedCounters;
auto statsMode = m_groupStatsMode == SAI_STATS_MODE_READ ? SAI_STATS_MODE_BULK_READ : SAI_STATS_MODE_BULK_READ_AND_CLEAR;
auto checkAndUpdateBulkCapability = [&](const std::vector<StatType> &counter_ids, const std::string &prefix, uint32_t bulk_chunk_size)
{
BulkContextType ctx;
// Check bulk capabilities again
std::vector<StatType> supportedBulkIds;
sai_status_t status = SAI_STATUS_SUCCESS;
if (m_supportedBulkCounters.empty())
{
status = querySupportedCounters(rids[0], statsMode, m_supportedBulkCounters);
}
if (status == SAI_STATUS_SUCCESS && !m_supportedBulkCounters.empty())
{
for (auto stat : counter_ids)
{
if (m_supportedBulkCounters.count(stat) != 0)
{
supportedBulkIds.push_back(stat);
}
}
}
if (supportedBulkIds.size() < counter_ids.size())
{
// Bulk polling is unsupported for the whole group but single polling is supported
// Add all objects to m_objectIdsMap so that they will be polled using single API
for (size_t i = 0; i < vids.size(); i++)
{
auto rid = rids[i];
auto vid = vids[i];
std::vector<uint64_t> stats(counter_ids.size());
if (collectData(rid, counter_ids, effective_stats_mode, false, stats)) {
auto it_vid = m_objectIdsMap.find(vid);
if (it_vid != m_objectIdsMap.end())
{
// Remove and re-add if vid already exists
m_objectIdsMap.erase(it_vid);
}
auto counter_data = std::make_shared<CounterIds<StatType>>(rid, counter_ids);
m_objectIdsMap.emplace(vid, counter_data);
SWSS_LOG_INFO("Fallback to single call for object 0x%" PRIx64, vid);
} else {
SWSS_LOG_WARN("%s RID %s can't provide the statistic", m_name.c_str(), sai_serialize_object_id(rid).c_str());
}
}
return;
}
ctx.counter_ids = counter_ids;
addBulkStatsContext(vids, rids, counter_ids, ctx);
status = m_vendorSai->bulkGetStats(
SAI_NULL_OBJECT_ID,
m_objectType,
static_cast<uint32_t>(ctx.object_keys.size()),
ctx.object_keys.data(),
static_cast<uint32_t>(ctx.counter_ids.size()),
reinterpret_cast<const sai_stat_id_t *>(ctx.counter_ids.data()),
statsMode,
ctx.object_statuses.data(),
ctx.counters.data());
if (status == SAI_STATUS_SUCCESS)
{
auto bulkContext = getBulkStatsContext(counter_ids, prefix, bulk_chunk_size);
addBulkStatsContext(vids, rids, counter_ids, *bulkContext.get());
}
else
{
// Bulk is not supported for this counter prefix
// Append it to bulkUnsupportedCounters
std::tuple<const std::string, uint32_t> value(prefix, bulk_chunk_size);
bulkUnsupportedCounters.emplace(counter_ids, value);
SWSS_LOG_INFO("Counters starting with %s do not support bulk. Fallback to single call for these counters", prefix.c_str());
}
};
if (m_counterChunkSizeMapFromPrefix.empty())
{
std::sort(supportedIds.begin(), supportedIds.end());
checkAndUpdateBulkCapability(supportedIds, "default", default_bulk_chunk_size);
}
else
{
std::map<std::string, vector<StatType>> counter_prefix_map;
std::vector<StatType> default_partition;
createCounterBulkChunkSizePerPrefixPartition(supportedIds, counter_prefix_map, default_partition);
for (auto &counterPrefix : counter_prefix_map)
{
std::sort(counterPrefix.second.begin(), counterPrefix.second.end());
}
std::sort(default_partition.begin(), default_partition.end());
for (auto &counterPrefix : counter_prefix_map)
{
checkAndUpdateBulkCapability(counterPrefix.second, counterPrefix.first, m_counterChunkSizeMapFromPrefix[counterPrefix.first]);
}
checkAndUpdateBulkCapability(default_partition, "default", default_bulk_chunk_size);
}
if (!bulkUnsupportedCounters.empty())
{
SWSS_LOG_NOTICE("Partial counters do not support bulk. Re-check bulk capability for each object");
for (auto &it : bulkUnsupportedCounters)
{
std::vector<sai_object_id_t> bulkSupportedRIDs;
std::vector<sai_object_id_t> bulkSupportedVIDs;
for (size_t i = 0; i < vids.size(); i++)
{
auto rid = rids[i];
auto vid = vids[i];
std::vector<uint64_t> stats(it.first.size());
if (checkBulkCapability(vid, rid, it.first))
{
bulkSupportedVIDs.push_back(vid);
bulkSupportedRIDs.push_back(rid);
}
else if (!double_confirm_supported_counters || collectData(rid, it.first, effective_stats_mode, false, stats))
{
SWSS_LOG_INFO("Fallback to single call for object 0x%" PRIx64, vid);
auto it_vid = m_objectIdsMap.find(vid);
if (it_vid != m_objectIdsMap.end())
{
// Remove and re-add if vid already exists
m_objectIdsMap.erase(it_vid);
}
auto counter_data = std::make_shared<CounterIds<StatType>>(rid, supportedIds);
m_objectIdsMap.emplace(vid, counter_data);
}
else
{
SWSS_LOG_WARN("%s RID %s can't provide the statistic", m_name.c_str(), sai_serialize_object_id(rid).c_str());
}
}
if (!bulkSupportedVIDs.empty() && !bulkSupportedRIDs.empty())
{
auto bulkContext = getBulkStatsContext(it.first, get<0>(it.second), get<1>(it.second));
addBulkStatsContext(bulkSupportedVIDs, bulkSupportedRIDs, it.first, *bulkContext.get());
}
}
}
}