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 <string>
17#include <sstream>
18#include "include/sp_log.h"
19#include "include/sp_utils.h"
20#include "include/GpuCounter.h"
21#include "include/GpuCounterCallback.h"
22
23namespace OHOS {
24    namespace SmartPerf {
25        GpuCounterCallbackImpl::GpuCounterCallbackImpl()
26        {
27            GpuPerfInfo firstData;
28            firstData.startTime = SPUtils::GetCurTime();
29            firstData.duration = 0;
30            firstData.gpuActive = 0;
31            firstData.drawCalls = 0;
32            firstData.primitives = 0;
33            firstData.vertexCounts = 0;
34            firstData.totalInstruments = 0;
35            firstData.gpuLoadPercentage = 0;
36            firstData.vertexLoadPercentage = 0;
37            firstData.fragmentLoadPercentage = 0;
38            firstData.computeLoadPercentage = 0;
39            firstData.textureLoadPercentage = 0;
40            firstData.memoryReadBandwidth = 0;
41            firstData.memoryWriteBandwidth = 0;
42            firstData.memoryBandwidthPercentage = 0;
43            firstData.remainTime = maxTime;
44            realtimeGpuPerfInfoData = firstData;
45            gpuCounter.push_back(firstData);
46        }
47
48
49        unsigned long long GpuCounterCallbackImpl::JoinSocketDataPercentFunction(uint32_t itemFirst,
50            int32_t durationFirst, uint32_t itemSecond, int32_t durationSecond) const
51        {
52            return (static_cast<unsigned long long>(itemFirst) * static_cast<unsigned long long>(durationFirst) +
53                static_cast<unsigned long long>(itemSecond) * static_cast<unsigned long long>(durationSecond)) /
54                (static_cast<unsigned long long>(durationFirst) + static_cast<unsigned long long>(durationSecond));
55        }
56
57        void GpuCounterCallbackImpl::JoinSocketDataValue(GpuPerfInfo *newData)
58        {
59            realtimeGpuPerfInfoData.gpuActive += newData->gpuActive;
60            realtimeGpuPerfInfoData.drawCalls += newData->drawCalls;
61            realtimeGpuPerfInfoData.primitives += newData->primitives;
62            realtimeGpuPerfInfoData.vertexCounts += newData->vertexCounts;
63            realtimeGpuPerfInfoData.totalInstruments += newData->totalInstruments;
64            realtimeGpuPerfInfoData.memoryReadBandwidth += newData->memoryReadBandwidth;
65            realtimeGpuPerfInfoData.memoryWriteBandwidth += newData->memoryWriteBandwidth;
66        }
67
68        void GpuCounterCallbackImpl::JoinSocketDataPercent(GpuPerfInfo *newData)
69        {
70            realtimeGpuPerfInfoData.gpuLoadPercentage = JoinSocketDataPercentFunction(
71                realtimeGpuPerfInfoData.gpuLoadPercentage, realtimeGpuPerfInfoData.duration,
72                newData->gpuLoadPercentage, newData->duration);
73            realtimeGpuPerfInfoData.vertexLoadPercentage = JoinSocketDataPercentFunction(
74                realtimeGpuPerfInfoData.vertexLoadPercentage, realtimeGpuPerfInfoData.duration,
75                newData->vertexLoadPercentage, newData->duration);
76            realtimeGpuPerfInfoData.fragmentLoadPercentage = JoinSocketDataPercentFunction(
77                realtimeGpuPerfInfoData.fragmentLoadPercentage, realtimeGpuPerfInfoData.duration,
78                newData->fragmentLoadPercentage, newData->duration);
79            realtimeGpuPerfInfoData.computeLoadPercentage = JoinSocketDataPercentFunction(
80                realtimeGpuPerfInfoData.computeLoadPercentage, realtimeGpuPerfInfoData.duration,
81                newData->computeLoadPercentage, newData->duration);
82            realtimeGpuPerfInfoData.textureLoadPercentage = JoinSocketDataPercentFunction(
83                realtimeGpuPerfInfoData.textureLoadPercentage, realtimeGpuPerfInfoData.duration,
84                newData->textureLoadPercentage, newData->duration);
85        }
86
87        void GpuCounterCallbackImpl::JoinSocketData(GpuPerfInfo *newData)
88        {
89            JoinSocketDataValue(newData);
90            JoinSocketDataPercent(newData);
91
92            realtimeGpuPerfInfoData.duration += newData->duration;
93        }
94
95        unsigned long long GpuCounterCallbackImpl::SplitSocketDataValueFunction(uint32_t value, int32_t interval,
96            int32_t duration) const
97        {
98            return static_cast<unsigned long long>(value) *
99                static_cast<unsigned long long>(interval) /
100                static_cast<unsigned long long>(duration);
101        }
102
103        void GpuCounterCallbackImpl::SplitSocketDataValue(int32_t interval)
104        {
105            GpuCounter &gpuCounterInstance = GpuCounter::GetInstance();
106
107            unsigned long long gpuActiveTargetValue = SplitSocketDataValueFunction(
108                realtimeGpuPerfInfoData.gpuActive, interval,
109                realtimeGpuPerfInfoData.duration);
110            unsigned long long drawCallsTargetValue = SplitSocketDataValueFunction(
111                realtimeGpuPerfInfoData.drawCalls, interval,
112                realtimeGpuPerfInfoData.duration);
113            unsigned long long primitivesTargetValue = SplitSocketDataValueFunction(
114                realtimeGpuPerfInfoData.primitives, interval,
115                realtimeGpuPerfInfoData.duration);
116            unsigned long long vertexCountsTargetValue = SplitSocketDataValueFunction(
117                realtimeGpuPerfInfoData.vertexCounts, interval,
118                realtimeGpuPerfInfoData.duration);
119            unsigned long long totalInstrumentsTargetValue = SplitSocketDataValueFunction(
120                realtimeGpuPerfInfoData.totalInstruments, interval,
121                realtimeGpuPerfInfoData.duration);
122            unsigned long long memoryReadBandwidthTargetValue = SplitSocketDataValueFunction(
123                realtimeGpuPerfInfoData.memoryReadBandwidth, interval,
124                realtimeGpuPerfInfoData.duration);
125            unsigned long long memoryWriteBandwidthTargetValue = SplitSocketDataValueFunction(
126                realtimeGpuPerfInfoData.memoryWriteBandwidth, interval,
127                realtimeGpuPerfInfoData.duration);
128            gpuCounterInstance.AddGpuCounterRealtimeData(std::to_string(
129                realtimeGpuPerfInfoData.gpuActive - gpuActiveTargetValue) + "_");
130            gpuCounterInstance.AddGpuCounterRealtimeData(std::to_string(
131                realtimeGpuPerfInfoData.drawCalls - drawCallsTargetValue) + "_");
132            gpuCounterInstance.AddGpuCounterRealtimeData(std::to_string(
133                realtimeGpuPerfInfoData.primitives - primitivesTargetValue) + "_");
134            gpuCounterInstance.AddGpuCounterRealtimeData(std::to_string(
135                realtimeGpuPerfInfoData.vertexCounts - vertexCountsTargetValue) + "_");
136            gpuCounterInstance.AddGpuCounterRealtimeData(std::to_string(
137                realtimeGpuPerfInfoData.totalInstruments - totalInstrumentsTargetValue) + "_");
138            gpuCounterInstance.AddGpuCounterRealtimeData(std::to_string(
139                realtimeGpuPerfInfoData.memoryReadBandwidth - memoryReadBandwidthTargetValue) + "_");
140            gpuCounterInstance.AddGpuCounterRealtimeData(std::to_string(
141                realtimeGpuPerfInfoData.memoryWriteBandwidth - memoryWriteBandwidthTargetValue) + "_");
142
143            realtimeGpuPerfInfoData.gpuActive = gpuActiveTargetValue;
144            realtimeGpuPerfInfoData.drawCalls = drawCallsTargetValue;
145            realtimeGpuPerfInfoData.primitives = primitivesTargetValue;
146            realtimeGpuPerfInfoData.vertexCounts = vertexCountsTargetValue;
147            realtimeGpuPerfInfoData.totalInstruments = totalInstrumentsTargetValue;
148            realtimeGpuPerfInfoData.memoryReadBandwidth = memoryReadBandwidthTargetValue;
149            realtimeGpuPerfInfoData.memoryWriteBandwidth = memoryWriteBandwidthTargetValue;
150        }
151
152        void GpuCounterCallbackImpl::SplitSocketDataPercent()
153        {
154            GpuCounter &gpuCounterInstance = GpuCounter::GetInstance();
155
156            gpuCounterInstance.AddGpuCounterRealtimeData(
157                std::to_string(realtimeGpuPerfInfoData.gpuLoadPercentage) + "_");
158            gpuCounterInstance.AddGpuCounterRealtimeData(
159                std::to_string(realtimeGpuPerfInfoData.vertexLoadPercentage) + "_");
160            gpuCounterInstance.AddGpuCounterRealtimeData(
161                std::to_string(realtimeGpuPerfInfoData.fragmentLoadPercentage) + "_");
162            gpuCounterInstance.AddGpuCounterRealtimeData(
163                std::to_string(realtimeGpuPerfInfoData.computeLoadPercentage) + "_");
164            gpuCounterInstance.AddGpuCounterRealtimeData(
165                std::to_string(realtimeGpuPerfInfoData.textureLoadPercentage) + ";");
166        }
167
168        void GpuCounterCallbackImpl::SplitSocketData()
169        {
170            int32_t interval = realtimeGpuPerfInfoData.duration - maxDuration;
171            SplitSocketDataValue(interval);
172            SplitSocketDataPercent();
173            realtimeGpuPerfInfoData.duration = interval;
174        }
175
176        void GpuCounterCallbackImpl::GetRealTime(GpuPerfInfo *newData)
177        {
178            GpuCounter &gpuCounterInstance = GpuCounter::GetInstance();
179
180            JoinSocketData(newData);
181            if ((realtimeGpuPerfInfoData.duration == 0) || (newData->duration == 0)) {
182                return;
183            }
184            gpuCounterInstance.GetRealtimeDataLock().lock();
185            while (realtimeGpuPerfInfoData.duration >= maxDuration) {
186                SplitSocketData();
187            }
188            gpuCounterInstance.GetRealtimeDataLock().unlock();
189        }
190
191        int GpuCounterCallbackImpl::OnGpuData(std::vector <GpuPerfInfo> &gpuPerfInfos)
192        {
193            GpuCounter &gpuCounterInstance = GpuCounter::GetInstance();
194
195            for (auto gpuPerfInfo : gpuPerfInfos) {
196                unsigned int gpuCounterBackSize = gpuCounter.size();
197                gpuCounter.push_back(gpuPerfInfo);
198                unsigned int gpuCounterSize = gpuCounter.size();
199                if (gpuCounterSize <= gpuCounterBackSize) {
200                    LOGE("gpuCounter data len error!");
201                    return -1;
202                }
203                GpuPerfInfo *newData = &gpuCounter[gpuCounterSize - 1];
204                GpuPerfInfo *backData = &gpuCounter[gpuCounterSize - 2];
205                long long durationTime = newData->startTime - backData->startTime;
206
207                // 如果两次数据间隔过短,则舍弃新数据
208                if (durationTime < collectInterval) {
209                    LOGE("Start time(%lld, %lld) make duration time(%lld) too short",
210                         newData->startTime, backData->startTime, durationTime);
211                    gpuCounter.pop_back();
212                    continue;
213                }
214
215                backData->duration = durationTime;
216
217                std::ostringstream oss;
218                oss << backData->startTime << ","
219                    << backData->duration << ","
220                    << backData->gpuActive << ","
221                    << backData->drawCalls << ","
222                    << backData->primitives << ","
223                    << backData->vertexCounts << ","
224                    << backData->totalInstruments << ","
225                    << backData->gpuLoadPercentage << ","
226                    << backData->vertexLoadPercentage << ","
227                    << backData->fragmentLoadPercentage << ","
228                    << backData->computeLoadPercentage << ","
229                    << backData->textureLoadPercentage << ","
230                    << backData->memoryReadBandwidth << ","
231                    << backData->memoryWriteBandwidth << ","
232                    << backData->memoryBandwidthPercentage << ",";
233                gpuCounterInstance.GetGpuCounterData().push_back(oss.str());
234                gpuCounterInstance.GetGpuCounterSaveReportData().push_back(oss.str());
235
236                GetRealTime(backData);
237            }
238
239            if (gpuPerfInfos[0].remainTime <= restartTime) {
240                LOGI("remain time to restart");
241                gpuCounterInstance.StartCollect(GpuCounter::GC_RESTART);
242            }
243            return 0;
244        }
245    }
246}