text: /*
   *  Copyright (c) 2004-present, Facebook, Inc.
   *  All rights reserved.
   *
   *  This source code is licensed under the BSD-style license found in the
   *  LICENSE file in the root directory of this source tree. An additional grant
   *  of patent rights can be found in the PATENTS file in the same directory.
   *
   */
  
  #include "fboss/agent/hw/sai/switch/SaiBufferManager.h"
  
  #include "fboss/agent/FbossError.h"
  #include "fboss/agent/Platform.h"
  #include "fboss/agent/hw/sai/store/SaiStore.h"
  #include "fboss/agent/hw/sai/switch/SaiManagerTable.h"
  #include "fboss/agent/hw/sai/switch/SaiSwitchManager.h"
  #include "fboss/agent/hw/switch_asics/HwAsic.h"
  #include "fboss/agent/platforms/sai/SaiPlatform.h"
  #include "fboss/agent/state/PortQueue.h"
  
  namespace facebook::fboss {
  
  SaiBufferManager::SaiBufferManager(
      SaiManagerTable* managerTable,
      const SaiPlatform* platform)
      : managerTable_(managerTable), platform_(platform) {}
  
  void SaiBufferManager::setupEgressBufferPool() {
    if (egressBufferPoolHandle_) {
      return;
    }
    egressBufferPoolHandle_ = std::make_unique<SaiBufferPoolHandle>();
    auto& store = SaiStore::getInstance()->get<SaiBufferPoolTraits>();
    auto mmuSize = platform_->getAsic()->getMMUSizeBytes();
    SaiBufferPoolTraits::CreateAttributes c{
        SAI_BUFFER_POOL_TYPE_EGRESS,
        mmuSize,
        SAI_BUFFER_POOL_THRESHOLD_MODE_DYNAMIC};
    egressBufferPoolHandle_->bufferPool =
        store.setObject(SAI_BUFFER_POOL_TYPE_EGRESS, c);
  }
  
  void SaiBufferManager::updateStats() {
    if (egressBufferPoolHandle_) {
      egressBufferPoolHandle_->bufferPool->updateStats();
      auto counters = egressBufferPoolHandle_->bufferPool->getStats();
      deviceWatermarkBytes_ = counters[SAI_BUFFER_POOL_STAT_WATERMARK_BYTES];
      publishDeviceWatermark(deviceWatermarkBytes_);
    }
  }
  
  SaiBufferProfileTraits::CreateAttributes SaiBufferManager::profileCreateAttrs(
      const PortQueue& queue) const {
    SaiBufferProfileTraits::Attributes::PoolId pool{
        egressBufferPoolHandle_->bufferPool->adapterKey()};
    uint64_t resBytes =
        queue.getReservedBytes() ? queue.getReservedBytes().value() : 0;
    SaiBufferProfileTraits::Attributes::ReservedBytes reservedBytes{resBytes};
    SaiBufferProfileTraits::Attributes::ThresholdMode mode{
        SAI_BUFFER_PROFILE_THRESHOLD_MODE_DYNAMIC};
    // TODO convert scaling factor to sai values
    int8_t dynThresh = queue.getScalingFactor()
        ? static_cast<int>(queue.getScalingFactor().value())
        : 0;
    SaiBufferProfileTraits::Attributes::SharedDynamicThreshold dynamicThresh{
        static_cast<int8_t>(dynThresh)};
    // TODO: handle static threshold
    SaiBufferProfileTraits::Attributes::SharedStaticThreshold staticThresh{0};
    return SaiBufferProfileTraits::CreateAttributes{
        pool, reservedBytes, mode, dynamicThresh, staticThresh};
  }
  
  std::shared_ptr<SaiBufferProfile> SaiBufferManager::getOrCreateProfile(
      const PortQueue& queue) {
    setupEgressBufferPool();
    auto c = profileCreateAttrs(queue);
    return bufferProfiles_
        .refOrEmplace(c, c, c, managerTable_->switchManager().getSwitchSaiId())
        .first;
  }
  
  } // namespace facebook::fboss
  