1 /*
2  * Copyright (C) 2024 Huawei Device Co., Ltd.
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 "chrono"
17 #include "string"
18 #include "thread"
19 #include "fstream"
20 #include <iostream>
21 #include <dlfcn.h>
22 #include "include/sp_log.h"
23 #include "include/GpuCounter.h"
24 #include "include/GpuCounterCallback.h"
25 
26 namespace OHOS {
27     namespace SmartPerf {
ItemData()28         std::map<std::string, std::string> GpuCounter::ItemData()
29         {
30             return std::map<std::string, std::string>();
31         }
GetSoHandle()32         void* GpuCounter::GetSoHandle()
33         {
34             char soFilePathChar[PATH_MAX] = {0x00};
35             if ((realpath(PLUGIN_SO_PATH.c_str(), soFilePathChar) == nullptr)) {
36                 LOGE("%s is not exist.", PLUGIN_SO_PATH.c_str());
37                 return nullptr;
38             }
39 
40             void* handle = dlopen(soFilePathChar, RTLD_LAZY);
41             if (!handle) {
42                 LOGI("open GpuCounterPlugin so file error.");
43                 return nullptr;
44             }
45 
46             return handle;
47         }
StartCollect(GcCollectType type)48         void GpuCounter::StartCollect(GcCollectType type)
49         {
50             std::unique_ptr<GpuCounterCallback> gpuCounterCallback = std::make_unique<GpuCounterCallbackImpl>();
51 
52             const int duration = 1000;
53 
54             void* handle = GetSoHandle();
55             if (!handle) {
56                 return;
57             }
58 
59             typedef GpuCounterPlugin *(*GetGpuCounterPlugin)();
60             GetGpuCounterPlugin startGetGpuPerfInfo = (GetGpuCounterPlugin)dlsym(handle, CREATE_PLUGIN.c_str());
61 
62             if (type == GC_START && gcStatus == GC_INIT) {
63                 gpuCounterData.clear();
64                 gpuCounterRealtimeData.clear();
65                 int ret = startGetGpuPerfInfo()->StartGetGpuPerfInfo(duration, std::move(gpuCounterCallback));
66                 if (ret == 0) {
67                     gcStatus = GC_RUNNING;
68                     LOGI("GpuCounter collect start.");
69                 } else {
70                     LOGE("GpuCounter call gameService error, ret = %d", ret);
71                 }
72             } else if (type == GC_RESTART && gcStatus == GC_RUNNING) {
73                 int ret = startGetGpuPerfInfo()->StartGetGpuPerfInfo(duration, std::move(gpuCounterCallback));
74                 if (ret == 0) {
75                     LOGI("GpuCounter recollect start.");
76                 } else {
77                     LOGE("GpuCounter call gameService error, ret = %d", ret);
78                 }
79             } else {
80                 LOGE("GpuCounter state error, type: %d, state: %d", type, gcStatus);
81             }
82         }
83 
SaveData(std::string path)84         void GpuCounter::SaveData(std::string path)
85         {
86             if (gcStatus != GC_RUNNING || gpuCounterData.size() <= 0) {
87                 return;
88             }
89             LOGI("GpuCounter collect stop.");
90             char gpuCounterDataDirChar[PATH_MAX] = {0x00};
91             if (realpath(path.c_str(), gpuCounterDataDirChar) == nullptr) {
92                 LOGE("data dir %s is nullptr", path.c_str());
93                 return;
94             }
95             std::string gpuCounterDataPath = std::string(gpuCounterDataDirChar) + "/gpu_counter.csv";
96             std::ofstream outFile;
97             std::mutex mtx;
98             mtx.lock();
99             outFile.open(gpuCounterDataPath.c_str(), std::ios::out | std::ios::trunc);
100             if (!outFile.is_open()) {
101                 LOGE("open GpuCounter data file failed.");
102                 return;
103             }
104             std::string title = "startTime,"
105                 "duration,"
106                 "gpuActive,"
107                 "drawCalls,"
108                 "primitives,"
109                 "vertexCounts,"
110                 "totalInstruments,"
111                 "gpuLoadPercentage,"
112                 "vertexLoadPercentage,"
113                 "fragmentLoadPercentage,"
114                 "computeLoadPercentage,"
115                 "textureLoadPercentage,"
116                 "memoryReadBandwidth,"
117                 "memoryWriteBandwidth,"
118                 "memoryBandwidthPercentage\r";
119             outFile << title << std::endl;
120             for (unsigned int i = 0; i < gpuCounterSaveReportData.size() - 1; i++) {
121                 outFile << gpuCounterSaveReportData[i] << std::endl;
122             }
123             outFile.close();
124             mtx.unlock();
125         }
126 
GetGpuCounterData()127         std::vector<std::string> &GpuCounter::GetGpuCounterData()
128         {
129             return gpuCounterData;
130         }
131 
GetGpuCounterSaveReportData()132         std::vector<std::string> &GpuCounter::GetGpuCounterSaveReportData()
133         {
134             return gpuCounterSaveReportData;
135         }
136 
GetRealtimeDataLock()137         std::mutex &GpuCounter::GetRealtimeDataLock()
138         {
139             return realtimeDataLock;
140         }
141 
GetGpuCounterRealtimeData()142         std::string &GpuCounter::GetGpuCounterRealtimeData()
143         {
144             return gpuCounterRealtimeData;
145         }
AddGpuCounterRealtimeData(std::string dataString)146         void GpuCounter::AddGpuCounterRealtimeData(std::string dataString)
147         {
148             gpuCounterRealtimeData += dataString;
149         }
150 
GetGpuRealtimeData(std::map<std::string, std::string> &dataMap)151         void GpuCounter::GetGpuRealtimeData(std::map<std::string, std::string> &dataMap)
152         {
153             if (gpuCounterRealtimeData.size() > 0) {
154                 std::map<std::string, std::string> gpuCounterRealtimeDataMap;
155                 gpuCounterRealtimeDataMap["gpuCounterData"] = gpuCounterRealtimeData;
156                 realtimeDataLock.lock();
157                 dataMap.insert(gpuCounterRealtimeDataMap.begin(), gpuCounterRealtimeDataMap.end());
158                 realtimeDataLock.unlock();
159                 gpuCounterRealtimeData.clear();
160             }
161         }
162 
StopCollect()163         void GpuCounter::StopCollect()
164         {
165             if (gcStatus != GC_RUNNING) {
166                 return;
167             }
168 
169             void* handle = GetSoHandle();
170             if (!handle) {
171                 return;
172             }
173 
174             typedef GpuCounterPlugin *(*GetGpuCounterPlugin)();
175             GetGpuCounterPlugin startGetGpuPerfInfo = (GetGpuCounterPlugin)dlsym(handle, CREATE_PLUGIN.c_str());
176 
177             int ret = startGetGpuPerfInfo()->StopGetGpuPerfInfo();
178             if (ret == 0) {
179                 gcStatus = GC_INIT;
180                 LOGI("GpuCounter collect finish.");
181             }
182         }
183     }
184 }