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
26namespace OHOS {
27    namespace SmartPerf {
28        std::map<std::string, std::string> GpuCounter::ItemData()
29        {
30            return std::map<std::string, std::string>();
31        }
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        }
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
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
127        std::vector<std::string> &GpuCounter::GetGpuCounterData()
128        {
129            return gpuCounterData;
130        }
131
132        std::vector<std::string> &GpuCounter::GetGpuCounterSaveReportData()
133        {
134            return gpuCounterSaveReportData;
135        }
136
137        std::mutex &GpuCounter::GetRealtimeDataLock()
138        {
139            return realtimeDataLock;
140        }
141
142        std::string &GpuCounter::GetGpuCounterRealtimeData()
143        {
144            return gpuCounterRealtimeData;
145        }
146        void GpuCounter::AddGpuCounterRealtimeData(std::string dataString)
147        {
148            gpuCounterRealtimeData += dataString;
149        }
150
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
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}