LCOV - code coverage report
Current view: top level - adcore/common - bound_queue_memory.h (source / functions) Coverage Total Hit
Test: coverage.info Lines: 93.3 % 89 83
Test Date: 2026-07-28 10:54:24 Functions: 100.0 % 34 34

            Line data    Source code
       1              : /**
       2              :  * Copyright (c) 2025 Huawei Technologies Co., Ltd.
       3              :  * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
       4              :  * CANN Open Software License Agreement Version 2.0 (the "License").
       5              :  * Please refer to the License for details. You may not use this file except in compliance with the License.
       6              :  * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
       7              :  * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
       8              :  * See LICENSE in the root of the software repository for the full text of the License.
       9              :  */
      10              : 
      11              : #ifndef ADX_COMMON_UTILS_BOUND_QUEUE_MEMORY_H
      12              : #define ADX_COMMON_UTILS_BOUND_QUEUE_MEMORY_H
      13              : #include <condition_variable>
      14              : #include <fstream>
      15              : #include <queue>
      16              : #include <mutex>
      17              : #include <sys/sysinfo.h>
      18              : #include "hdc_log.h"
      19              : 
      20              : namespace Adx {
      21              : constexpr float ADX_QUEUE_FULL_SIZE = 0.85f;
      22              : constexpr const char* MEM_USAGE_V1 = "/sys/fs/cgroup/memory/memory.usage_in_bytes";
      23              : constexpr const char* MEM_USAGE_V2 = "/sys/fs/cgroup/memory.current";
      24              : constexpr const char* MEM_LIMIT_V1 = "/sys/fs/cgroup/memory/memory.limit_in_bytes";
      25              : constexpr const char* MEM_LIMIT_V2 = "/sys/fs/cgroup/memory.max";
      26              : 
      27              : template<typename T>
      28              : class BoundQueueMemory {
      29              : public:
      30           33 :     explicit BoundQueueMemory () : quit_(false), memLimit_(InitMemLimit()) {
      31           33 :         memUsageV1_.open(MEM_USAGE_V1);
      32           33 :         memUsageV2_.open(MEM_USAGE_V2);
      33           33 :     }
      34           52 :     virtual ~BoundQueueMemory() {
      35           27 :         memUsageV1_.close();
      36           27 :         memUsageV2_.close();
      37           79 :     }
      38           73 :     bool Push(T &value)
      39              :     {
      40           73 :         std::unique_lock<std::mutex> lk(mtx_);
      41          146 :         cvPop_.wait(lk, [this] { return !this->IsFullUnlocked() || this->quit_;});
      42           73 :         if (this->quit_) {
      43            1 :             return false;
      44              :         }
      45           72 :         dataQueue_.push(value);
      46           72 :         cvPush_.notify_all();
      47           72 :         return true;
      48           73 :     }
      49              : 
      50           69 :     bool Pop(T &value)
      51              :     {
      52           69 :         std::unique_lock<std::mutex> lk(mtx_);
      53          201 :         cvPush_.wait(lk, [this] { return !this->IsEmptyUnlocked() || this->quit_; });
      54           69 :         if (!this->IsEmptyUnlocked()) {
      55            9 :             value = this->dataQueue_.front();
      56            9 :             this->dataQueue_.pop();
      57            9 :             cvPop_.notify_all();
      58            9 :             return true;
      59              :         }
      60              : 
      61           60 :         return false;
      62           69 :     }
      63              : 
      64           85 :     bool IsEmpty() const
      65              :     {
      66           85 :         std::lock_guard<std::mutex> lk(mtx_);
      67          170 :         return IsEmptyUnlocked();
      68           85 :     }
      69              : 
      70           13 :     bool IsFull() const
      71              :     {
      72           13 :         std::lock_guard<std::mutex> lk(mtx_);
      73           26 :         return IsFullUnlocked();
      74           13 :     }
      75              : 
      76           88 :     void Init()
      77              :     {
      78           88 :         std::lock_guard<std::mutex> lk(mtx_);
      79           88 :         quit_ = false;
      80           88 :         std::queue<T>().swap(dataQueue_);
      81           88 :     }
      82              : 
      83           91 :     void Quit()
      84              :     {
      85           91 :         std::lock_guard<std::mutex> lk(mtx_);
      86           91 :         quit_ = true;
      87           91 :         cvPush_.notify_all();
      88           91 :         cvPop_.notify_all();
      89           91 :     }
      90              : 
      91            4 :     uint32_t Size() const
      92              :     {
      93            4 :         std::lock_guard<std::mutex> lk(mtx_);
      94            8 :         return dataQueue_.size();
      95            4 :     }
      96              : 
      97           62 :     void SetPath(std::string path)
      98              :     {
      99           62 :         path_ = path;
     100           62 :     }
     101              : 
     102              : private:
     103          286 :     bool IsEmptyUnlocked() const
     104              :     {
     105          286 :         return dataQueue_.empty();
     106              :     }
     107              : 
     108           86 :     bool IsFullUnlocked() const
     109              :     {
     110              :         struct sysinfo info;
     111           86 :         const size_t queueSize = 60;
     112           86 :         int32_t ret = sysinfo(&info);
     113           86 :         if (ret != EN_OK) {
     114            1 :             IDE_LOGW("Can not get memory, sysinfo return: %d", ret);
     115            1 :             return dataQueue_.size() >= queueSize;
     116              :         }
     117              :         // if in memory-limited container, make sure that memory usage in container is less than 85%
     118           85 :         if (memLimit_ > 0 && memLimit_ < info.totalram) {
     119            0 :             uint64_t memUsage = ReadMemory(memUsageV1_, memUsageV2_);
     120            0 :             if (memUsage == 0) {
     121            0 :                 IDE_LOGW("Can not read memory usage from cgroup.");
     122            0 :                 return dataQueue_.size() >= queueSize;
     123              :             }
     124            0 :             return (memUsage > ADX_QUEUE_FULL_SIZE * memLimit_) && dataQueue_.size() > queueSize;
     125              :         }
     126           85 :         return (info.freeram < (info.totalram * (1 - ADX_QUEUE_FULL_SIZE))) && dataQueue_.size() > queueSize;
     127              :     }
     128              : 
     129           33 :     uint64_t InitMemLimit() const {
     130           33 :         std::ifstream memLimitV1(MEM_LIMIT_V1);
     131           33 :         std::ifstream memLimitV2(MEM_LIMIT_V2);
     132           33 :         uint64_t ret = ReadMemory(memLimitV1, memLimitV2);
     133           33 :         memLimitV1.close();
     134           33 :         memLimitV2.close();
     135           33 :         return ret;
     136           33 :     }
     137           66 :     uint64_t ReadLongLong(std::ifstream &f) const {
     138           66 :         if (!f.is_open()) {
     139           33 :             return 0;
     140              :         }
     141              :         uint64_t v;
     142           33 :         if (f >> v) {
     143           33 :             f.clear();
     144           33 :             f.seekg(0);
     145           33 :             return v;
     146              :         }
     147            0 :         return 0;
     148              :     }
     149              : 
     150           33 :     uint64_t ReadMemory(std::ifstream &f1, std::ifstream &f2) const {
     151           33 :         uint64_t value = ReadLongLong(f2);
     152           33 :         if (value == 0) {
     153           33 :             value = ReadLongLong(f1);
     154              :         }
     155           33 :         return value;
     156              :     }
     157              :     mutable bool quit_;
     158              :     mutable std::mutex mtx_;
     159              :     std::queue<T> dataQueue_;
     160              :     std::condition_variable cvPop_;
     161              :     std::condition_variable cvPush_;
     162              :     std::string path_;
     163              :     mutable std::ifstream memUsageV1_;
     164              :     mutable std::ifstream memUsageV2_;
     165              :     uint64_t memLimit_;
     166              : };
     167              : }
     168              : #endif
        

Generated by: LCOV version 2.0-1