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 23 namespace OHOS { 24 namespace SmartPerf { GpuCounterCallbackImpl()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 JoinSocketDataPercentFunction(uint32_t itemFirst,int32_t durationFirst,uint32_t itemSecond,int32_t durationSecond) const49 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 JoinSocketDataValue(GpuPerfInfo * newData)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 JoinSocketDataPercent(GpuPerfInfo * newData)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 JoinSocketData(GpuPerfInfo * newData)87 void GpuCounterCallbackImpl::JoinSocketData(GpuPerfInfo *newData) 88 { 89 JoinSocketDataValue(newData); 90 JoinSocketDataPercent(newData); 91 92 realtimeGpuPerfInfoData.duration += newData->duration; 93 } 94 SplitSocketDataValueFunction(uint32_t value,int32_t interval,int32_t duration) const95 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 SplitSocketDataValue(int32_t interval)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 129 gpuCounterInstance.AddGpuCounterRealtimeData(std::to_string( 130 realtimeGpuPerfInfoData.gpuActive - gpuActiveTargetValue) + "_"); 131 gpuCounterInstance.AddGpuCounterRealtimeData(std::to_string( 132 realtimeGpuPerfInfoData.drawCalls - drawCallsTargetValue) + "_"); 133 gpuCounterInstance.AddGpuCounterRealtimeData(std::to_string( 134 realtimeGpuPerfInfoData.primitives - primitivesTargetValue) + "_"); 135 gpuCounterInstance.AddGpuCounterRealtimeData(std::to_string( 136 realtimeGpuPerfInfoData.vertexCounts - vertexCountsTargetValue) + "_"); 137 gpuCounterInstance.AddGpuCounterRealtimeData(std::to_string( 138 realtimeGpuPerfInfoData.totalInstruments - totalInstrumentsTargetValue) + "_"); 139 gpuCounterInstance.AddGpuCounterRealtimeData(std::to_string( 140 realtimeGpuPerfInfoData.memoryReadBandwidth - memoryReadBandwidthTargetValue) + "_"); 141 gpuCounterInstance.AddGpuCounterRealtimeData(std::to_string( 142 realtimeGpuPerfInfoData.memoryWriteBandwidth - memoryWriteBandwidthTargetValue) + "_"); 143 144 realtimeGpuPerfInfoData.gpuActive = gpuActiveTargetValue; 145 realtimeGpuPerfInfoData.drawCalls = drawCallsTargetValue; 146 realtimeGpuPerfInfoData.primitives = primitivesTargetValue; 147 realtimeGpuPerfInfoData.vertexCounts = vertexCountsTargetValue; 148 realtimeGpuPerfInfoData.totalInstruments = totalInstrumentsTargetValue; 149 realtimeGpuPerfInfoData.memoryReadBandwidth = memoryReadBandwidthTargetValue; 150 realtimeGpuPerfInfoData.memoryWriteBandwidth = memoryWriteBandwidthTargetValue; 151 } 152 SplitSocketDataPercent()153 void GpuCounterCallbackImpl::SplitSocketDataPercent() 154 { 155 GpuCounter &gpuCounterInstance = GpuCounter::GetInstance(); 156 157 gpuCounterInstance.AddGpuCounterRealtimeData( 158 std::to_string(realtimeGpuPerfInfoData.gpuLoadPercentage) + "_"); 159 gpuCounterInstance.AddGpuCounterRealtimeData( 160 std::to_string(realtimeGpuPerfInfoData.vertexLoadPercentage) + "_"); 161 gpuCounterInstance.AddGpuCounterRealtimeData( 162 std::to_string(realtimeGpuPerfInfoData.fragmentLoadPercentage) + "_"); 163 gpuCounterInstance.AddGpuCounterRealtimeData( 164 std::to_string(realtimeGpuPerfInfoData.computeLoadPercentage) + "_"); 165 gpuCounterInstance.AddGpuCounterRealtimeData( 166 std::to_string(realtimeGpuPerfInfoData.textureLoadPercentage) + ";"); 167 } 168 SplitSocketData()169 void GpuCounterCallbackImpl::SplitSocketData() 170 { 171 int32_t interval = realtimeGpuPerfInfoData.duration - maxDuration; 172 SplitSocketDataValue(interval); 173 SplitSocketDataPercent(); 174 realtimeGpuPerfInfoData.duration = interval; 175 } 176 GetRealTime(GpuPerfInfo * newData)177 void GpuCounterCallbackImpl::GetRealTime(GpuPerfInfo *newData) 178 { 179 if (newData == nullptr) { 180 WLOGE("GetRealTime newData is nullptr"); 181 return; 182 } 183 184 GpuCounter &gpuCounterInstance = GpuCounter::GetInstance(); 185 186 JoinSocketData(newData); 187 if ((realtimeGpuPerfInfoData.duration == 0) || (newData->duration == 0)) { 188 WLOGE("Invalid duration found: realtime = %d, newData = %d", 189 realtimeGpuPerfInfoData.duration, newData->duration); 190 return; 191 } 192 gpuCounterInstance.GetRealtimeDataLock().lock(); 193 while (realtimeGpuPerfInfoData.duration >= maxDuration) { 194 SplitSocketData(); 195 } 196 gpuCounterInstance.GetRealtimeDataLock().unlock(); 197 } 198 GetGpuPerfInfoItem(const GpuPerfInfo * itemData) const199 std::string GpuCounterCallbackImpl::GetGpuPerfInfoItem(const GpuPerfInfo *itemData) const 200 { 201 std::ostringstream oss; 202 if (itemData == nullptr) { 203 WLOGE("GpuCounter get itemData is nullptr"); 204 return ""; 205 } 206 oss << itemData->startTime << "," 207 << itemData->duration << "," 208 << itemData->gpuActive << "," 209 << itemData->drawCalls << "," 210 << itemData->primitives << "," 211 << itemData->vertexCounts << "," 212 << itemData->totalInstruments << "," 213 << itemData->gpuLoadPercentage << "," 214 << itemData->vertexLoadPercentage << "," 215 << itemData->fragmentLoadPercentage << "," 216 << itemData->computeLoadPercentage << "," 217 << itemData->textureLoadPercentage << "," 218 << itemData->memoryReadBandwidth << "," 219 << itemData->memoryWriteBandwidth << "," 220 << itemData->memoryBandwidthPercentage << ","; 221 return oss.str(); 222 } 223 OnGpuData(std::vector<GpuPerfInfo> & gpuPerfInfos)224 int GpuCounterCallbackImpl::OnGpuData(std::vector <GpuPerfInfo> &gpuPerfInfos) 225 { 226 if (gpuPerfInfos.empty()) { 227 WLOGE("Receive gpuPerfInfos is empty!"); 228 return -1; 229 } 230 231 GpuCounter &gpuCounterInstance = GpuCounter::GetInstance(); 232 233 for (auto gpuPerfInfo : gpuPerfInfos) { 234 unsigned int gpuCounterBackSize = gpuCounter.size(); 235 gpuCounter.push_back(gpuPerfInfo); 236 unsigned int gpuCounterSize = gpuCounter.size(); 237 if (gpuCounterSize <= gpuCounterBackSize) { 238 WLOGE("gpuCounter data len error!"); 239 return -1; 240 } 241 GpuPerfInfo *newData = &gpuCounter[gpuCounterSize - 1]; 242 GpuPerfInfo *backData = &gpuCounter[gpuCounterSize - 2]; 243 if (newData == nullptr || backData == nullptr) { 244 WLOGE("gpuCounter data pointer is null!"); 245 return -1; 246 } 247 long long durationTime = newData->startTime - backData->startTime; 248 249 // 如果两次数据间隔过短,则舍弃新数据 250 if (durationTime < collectInterval) { 251 WLOGE("Start time(%lld, %lld) make duration time(%lld) too short", 252 newData->startTime, backData->startTime, durationTime); 253 gpuCounter.pop_back(); 254 continue; 255 } 256 backData->duration = durationTime; 257 std::string gpuPerfInfoItemStr = GetGpuPerfInfoItem(backData); 258 gpuCounterInstance.GetGpuCounterData().push_back(gpuPerfInfoItemStr); 259 gpuCounterInstance.GetGpuCounterSaveReportData().push_back(gpuPerfInfoItemStr); 260 GetRealTime(backData); 261 } 262 263 if (gpuPerfInfos[0].remainTime <= restartTime) { 264 gpuCounterInstance.StartCollect(GpuCounter::GC_RESTART); 265 } 266 return 0; 267 } 268 } 269 }