• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) Huawei Technologies Co., Ltd. 2023. All rights reserved.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "gpu_data_plugin.h"
17 #include <ctime>
18 #include <numeric>
19 #include "common.h"
20 #include "gpu_plugin_result.pbencoder.h"
21 
22 namespace {
23 using namespace OHOS::Developtools::Profiler;
24 const std::string GPU_PATH = "/sys/class/devfreq/gpufreq/gpu_scene_aware/utilisation";
25 constexpr uint32_t RET_COUNT = 50;
26 constexpr uint32_t SAMPLE_INTERVAL = 10;
27 constexpr uint32_t SAMPLE_INTERVAL_COMPATIBLE = 500;
28 } // namespace
29 
Start(const uint8_t * configData,uint32_t configSize)30 int GpuDataPlugin::Start(const uint8_t* configData, uint32_t configSize)
31 {
32     CHECK_TRUE(protoConfig_.ParseFromArray(configData, configSize) > 0, RET_FAIL,
33                "%s:parseFromArray failed!", __func__);
34 
35     if (protoConfig_.pid() > 0) {
36         pid_ = protoConfig_.pid();
37     }
38 
39     file_.open(GPU_PATH);
40     auto args = GetCmdArgs(protoConfig_);
41     if (!file_.is_open()) {
42         int ret = COMMON::PluginWriteToHisysevent("gpu_plugin", "sh", args, RET_FAIL, "failed");
43         PROFILER_LOG_ERROR(LOG_CORE, "%s:failed to open(%s), hisysevent report gpu_plugin ret: %d",
44             __func__, GPU_PATH.c_str(), ret);
45         return RET_FAIL;
46     }
47     CHECK_NOTNULL(resultWriter_, -1, "GPUDataPlugin: Writer is no set!");
48     CHECK_NOTNULL(resultWriter_->write, -1, "GPUDataPlugin: Writer.write is no set!");
49     CHECK_NOTNULL(resultWriter_->flush, -1, "GPUDataPlugin: Writer.flush is no set!");
50     running_ = true;
51     if (protoConfig_.report_gpu_data_array()) {
52         writeThread_ = std::thread([this] { this->ReadGpuDataArray(); });
53     } else {
54         writeThread_ = std::thread([this] { this->ReadGpuData(); });
55     }
56     int ret = COMMON::PluginWriteToHisysevent("gpu_plugin", "sh", args, RET_SUCC, "success");
57     PROFILER_LOG_INFO(LOG_CORE, "%s:start success! hisysevent report gpu_plugin result: %d", __func__, ret);
58     return RET_SUCC;
59 }
60 
GetCmdArgs(const GpuConfig & traceConfig)61 std::string GpuDataPlugin::GetCmdArgs(const GpuConfig& traceConfig)
62 {
63     std::string args;
64     args += "pid: " + std::to_string(traceConfig.pid()) + ", report_gpu_info: ";
65     args += (traceConfig.report_gpu_info() ? "true" : "false");
66     return args;
67 }
68 
ReadGpuDataArray()69 void GpuDataPlugin::ReadGpuDataArray()
70 {
71     PROFILER_LOG_INFO(LOG_CORE, "GPUDataPlugin: Read GPU data start");
72     CHECK_NOTNULL(resultWriter_, NO_RETVAL, "%s: resultWriter_ is nullptr", __func__);
73     std::vector<std::pair<uint64_t, int>> vectGpuData = {};
74     uint32_t nCount = 0;
75     while (running_) {
76         int retGpu = ReadFile();
77         if (retGpu != RET_FAIL) {
78             uint64_t bootTime = GetBootTime();
79             vectGpuData.emplace_back(std::make_pair(bootTime, retGpu));
80             nCount++;
81         }
82         if (nCount == RET_COUNT) {
83             FlushGpuData(vectGpuData);
84             nCount = 0;
85             vectGpuData.clear();
86         }
87         std::this_thread::sleep_for(std::chrono::milliseconds(SAMPLE_INTERVAL));
88     }
89     if (vectGpuData.size() > 0) {
90         FlushGpuData(vectGpuData);
91     }
92     PROFILER_LOG_INFO(LOG_CORE, "GPUDataPlugin: Read data end");
93 }
94 
ReadGpuData()95 void GpuDataPlugin::ReadGpuData()
96 {
97     PROFILER_LOG_INFO(LOG_CORE, "GPUDataPlugin: Read GPU data start");
98     CHECK_NOTNULL(resultWriter_, NO_RETVAL, "%s: resultWriter_ is nullptr", __func__);
99     while (running_) {
100         if (resultWriter_->isProtobufSerialize) {
101             GpuData dataProto;
102             WriteGpuDataInfo(dataProto);
103             if (dataProto.ByteSizeLong() > 0) {
104                 buffer_.resize(dataProto.ByteSizeLong());
105                 dataProto.SerializeToArray(buffer_.data(), buffer_.size());
106                 resultWriter_->write(resultWriter_, buffer_.data(), buffer_.size());
107                 resultWriter_->flush(resultWriter_);
108             }
109         } else {
110             ProtoEncoder::GpuData dataProto(resultWriter_->startReport(resultWriter_));
111             WriteGpuDataInfo(dataProto);
112             int messageLen = dataProto.Finish();
113             resultWriter_->finishReport(resultWriter_, messageLen);
114             resultWriter_->flush(resultWriter_);
115         }
116         std::this_thread::sleep_for(std::chrono::milliseconds(SAMPLE_INTERVAL_COMPATIBLE));
117     }
118     PROFILER_LOG_INFO(LOG_CORE, "GPUDataPlugin: Read data end");
119 }
120 
FlushGpuData(std::vector<std::pair<uint64_t,int>> & vectGpuData)121 void GpuDataPlugin::FlushGpuData(std::vector<std::pair<uint64_t, int>>& vectGpuData)
122 {
123     if (resultWriter_->isProtobufSerialize) {
124         GpuData dataProto;
125         WriteGpuDataInfoExt(dataProto, vectGpuData);
126         if (dataProto.ByteSizeLong() > 0) {
127             buffer_.resize(dataProto.ByteSizeLong());
128             dataProto.SerializeToArray(buffer_.data(), buffer_.size());
129             resultWriter_->write(resultWriter_, buffer_.data(), buffer_.size());
130             resultWriter_->flush(resultWriter_);
131         }
132     } else {
133         ProtoEncoder::GpuData dataProto(resultWriter_->startReport(resultWriter_));
134         WriteGpuDataInfoExt(dataProto, vectGpuData);
135         int messageLen = dataProto.Finish();
136         resultWriter_->finishReport(resultWriter_, messageLen);
137         resultWriter_->flush(resultWriter_);
138     }
139 }
140 
Stop()141 int GpuDataPlugin::Stop()
142 {
143     running_ = false;
144     if (writeThread_.joinable()) {
145         writeThread_.join();
146     }
147     PROFILER_LOG_INFO(LOG_CORE, "GPUDataPlugin:stop thread success!");
148     file_.close();
149     PROFILER_LOG_INFO(LOG_CORE, "GPUDataPlugin: stop success!");
150     return 0;
151 }
152 
ReadFile()153 int GpuDataPlugin::ReadFile()
154 {
155     file_.clear();
156     file_.seekg(0);
157     std::string line;
158     std::getline(file_, line);
159     if (line == "") {
160         return RET_FAIL;
161     }
162     for (char charac : line) {
163         if (!isdigit(charac)) {
164             PROFILER_LOG_ERROR(LOG_CORE, "invalid file content for (%s)", GPU_PATH.c_str());
165             return RET_FAIL;
166         }
167     }
168     return stoi(line);
169 }
170 
GetBootTime()171 uint64_t GpuDataPlugin::GetBootTime()
172 {
173     constexpr uint64_t nanoSeconds = 1000000000;
174     struct timespec ts;
175     int result = clock_gettime(CLOCK_BOOTTIME, &ts);
176     if (result == -1) {
177         PROFILER_LOG_ERROR(LOG_CORE, "clock_gettime failed");
178         return 0;
179     }
180     uint64_t bootTime = (static_cast<uint64_t>(ts.tv_sec) * nanoSeconds + static_cast<uint64_t>(ts.tv_nsec)) / 1000000;
181     return bootTime;
182 }
183 
184 template <typename T>
WriteGpuDataInfoExt(T & gpuData,std::vector<std::pair<uint64_t,int>> & vectGpuData)185 void GpuDataPlugin::WriteGpuDataInfoExt(T& gpuData, std::vector<std::pair<uint64_t, int>>& vectGpuData)
186 {
187     gpuData.set_boottime(0);
188     gpuData.set_gpu_utilisation(0);
189     for (auto& gpuDataInfo : vectGpuData) {
190         auto* gpuDataExt = gpuData.add_gpu_data_array();
191         gpuDataExt->set_boottime(gpuDataInfo.first);
192         gpuDataExt->set_gpu_utilisation(gpuDataInfo.second);
193     }
194 }
195 
196 template <typename T>
WriteGpuDataInfo(T & gpuData)197 void GpuDataPlugin::WriteGpuDataInfo(T& gpuData)
198 {
199     int ret = ReadFile();
200     if (ret == RET_FAIL) {
201         return;
202     }
203     constexpr uint64_t nanoSeconds = 1000000000;
204     struct timespec ts;
205     int result = clock_gettime(CLOCK_BOOTTIME, &ts);
206     if (result == -1) {
207         PROFILER_LOG_ERROR(LOG_CORE, "clock_gettime failed");
208         return;
209     }
210     uint64_t boottime = (static_cast<uint64_t>(ts.tv_sec) * nanoSeconds + static_cast<uint64_t>(ts.tv_nsec)) / 1000000;
211     gpuData.set_boottime(boottime);
212     gpuData.set_gpu_utilisation(static_cast<uint64_t>(ret));
213 }
214 
SetWriter(WriterStruct * writer)215 int GpuDataPlugin::SetWriter(WriterStruct* writer)
216 {
217     resultWriter_ = writer;
218     return 0;
219 }
220