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 : #include "aicpusd_period_statistic.h"
11 :
12 : #include <errno.h>
13 : #include <cstdio>
14 : #include "aicpusd_util.h"
15 : #include "aicpusd_drv_manager.h"
16 : namespace AicpuSchedule {
17 : namespace {
18 : // 循环一次100ms
19 : constexpr const uint64_t STATISTIC_LOOP_PERIOD = 100UL;
20 : constexpr const uint64_t SECOND_TO_MS = 1000UL;
21 : constexpr const uint64_t MS_TO_US = 1000UL;
22 : constexpr const uint64_t PROC_MEM_PERIOD = 10U;
23 : } // namespace
24 :
25 2 : AicpuSdPeriodStatistic::AicpuSdPeriodStatistic() : initFlag_(false), runningFlag_(false), deviceId_(0U), hostPid_(0U) {}
26 :
27 63 : AicpuSdPeriodStatistic& AicpuSdPeriodStatistic::GetInstance()
28 : {
29 63 : static AicpuSdPeriodStatistic instance;
30 63 : return instance;
31 : }
32 :
33 2 : AicpuSdPeriodStatistic::~AicpuSdPeriodStatistic() { StopStatistic(); }
34 :
35 26 : void AicpuSdPeriodStatistic::StopStatistic()
36 : {
37 26 : aicpusd_info("StopStatistic start");
38 26 : const std::lock_guard<std::mutex> lk(initMutex_);
39 26 : if (!initFlag_) {
40 24 : aicpusd_info("already uninit no need uninit");
41 24 : return;
42 : }
43 2 : runningFlag_ = false;
44 2 : initFlag_ = false;
45 2 : if (statThread_.joinable()) {
46 1 : statThread_.join();
47 : }
48 2 : aicpusd_info("StopStatistic finish");
49 26 : }
50 :
51 2 : void AicpuSdPeriodStatistic::DoStatistic() noexcept
52 : {
53 2 : if (SetThreadAffinity() != AICPU_SCHEDULE_OK) {
54 1 : aicpusd_run_warn("stat thread bind core nok.");
55 1 : return;
56 : }
57 1 : constexpr uint64_t procMemPeriod = PROC_MEM_PERIOD * SECOND_TO_MS / STATISTIC_LOOP_PERIOD;
58 1 : uint64_t loopCnt = 0UL;
59 11 : while (runningFlag_) {
60 10 : if (loopCnt % procMemPeriod == 0) {
61 1 : procMemInfo_.StatisticProcMemInfo();
62 : }
63 10 : loopCnt++;
64 10 : (void)usleep(STATISTIC_LOOP_PERIOD * MS_TO_US);
65 : }
66 1 : aicpusd_run_info("DoStatistic running over");
67 : }
68 :
69 24 : void AicpuSdPeriodStatistic::PrintOutStatisticInfo(const aicpu::AicpuRunMode runMode)
70 : {
71 24 : if (runMode == aicpu::AicpuRunMode::PROCESS_SOCKET_MODE || (AicpuUtil::IsFpga())) {
72 22 : aicpusd_info("socket mode no need this statistic");
73 22 : return;
74 : }
75 2 : procMemInfo_.PrintOutProcMemInfo(hostPid_);
76 : }
77 :
78 8 : void AicpuSdPeriodStatistic::InitStatistic(
79 : const uint32_t deviceId, const uint32_t hostPid, const aicpu::AicpuRunMode runMode)
80 : {
81 8 : if ((runMode == aicpu::AicpuRunMode::PROCESS_SOCKET_MODE) || (AicpuUtil::IsFpga())) {
82 5 : aicpusd_info("socket or fpga mode no need this statistic");
83 7 : return;
84 : }
85 3 : const std::lock_guard<std::mutex> lk(initMutex_);
86 3 : if (initFlag_) {
87 1 : aicpusd_info("already init before");
88 1 : return;
89 : }
90 2 : deviceId_ = deviceId;
91 2 : runningFlag_ = true;
92 2 : hostPid_ = hostPid;
93 2 : aicpusd_info("Start initializing statistics, deviceId:%u, hostPid:%u", deviceId_, hostPid_);
94 2 : if (!procMemInfo_.InitProcMemStatistic()) {
95 1 : aicpusd_err("InitProcMemStatistic failed");
96 1 : return;
97 : }
98 :
99 : try {
100 1 : statThread_ = std::thread(&AicpuSdPeriodStatistic::DoStatistic, this);
101 0 : } catch (std::exception& e) {
102 0 : aicpusd_err("create thread file:%s", e.what());
103 0 : return;
104 0 : }
105 1 : initFlag_ = true;
106 3 : }
107 :
108 2 : int32_t AicpuSdPeriodStatistic::SetThreadAffinity() const
109 : {
110 2 : std::vector<uint32_t> ccpuIds = AicpuDrvManager::GetInstance().GetCcpuList();
111 2 : if (ccpuIds.empty()) {
112 0 : aicpusd_run_info("ccpu list is empty no need bind core");
113 0 : return AICPU_SCHEDULE_OK;
114 : }
115 2 : const pthread_t threadId = pthread_self();
116 : cpu_set_t cpuset;
117 20 : for (const auto cpuId : ccpuIds) {
118 18 : CPU_SET(cpuId, &cpuset);
119 18 : aicpusd_info("prepare bind threadId=%lu to cpuId=%u", threadId, static_cast<uint32_t>(cpuId));
120 : }
121 2 : const int32_t ret = pthread_setaffinity_np(threadId, sizeof(cpu_set_t), &cpuset);
122 2 : if (ret != 0) {
123 1 : aicpusd_run_warn("aicpu bind tid by self, res[%d], reason[%s].", ret, strerror(errno));
124 1 : return AICPU_SCHEDULE_ERROR_INNER_ERROR;
125 : } else {
126 1 : aicpusd_run_info("aicpu bind by self success");
127 1 : return AICPU_SCHEDULE_OK;
128 : }
129 2 : }
130 : } // namespace AicpuSchedule
|