virtual void bulkAddObject()

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());
                }
            }
        }
    }