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