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#include <fstream>
16#include <string>
17#include <iostream>
18#include <regex>
19#include <cmath>
20#include "include/stalling_rate_trace.h"
21#include "include/sp_log.h"
22
23namespace OHOS {
24namespace SmartPerf {
25double StallingRateTrace::StallingRateResult(std::string file)
26{
27    double stalligRate = 0;
28    char realPath[PATH_MAX] = {0x00};
29    if ((realpath(file.c_str(), realPath) == nullptr)) {
30        std::cout << "" << std::endl;
31    }
32    infile.open(realPath);
33    if (infile.fail()) {
34        LOGI("StallingRateTrace open file(%s) fialed ", file.c_str());
35        return stalligRate;
36    }
37    stalligRate = SmartPerf::StallingRateTrace::CalculateTime();
38    infile.close();
39    return stalligRate;
40}
41
42double StallingRateTrace::CalculateTime()
43{
44    frameLossRate = 0;
45    frameLossTime = 0;
46    swiperFrameLossRate = 0;
47    appFrameLossRate = 0;
48    tabsFrameLossRate = 0;
49    frameLossSwiperTime = 0;
50    frameLossTabsTime = 0;
51    std::string signS = "S|";
52    std::string signF = "F|";
53    std::string line;
54    while (getline(infile, line)) {
55        AppList(line, signS, signF);
56        AppSwiperScroll(line, signS, signF);
57        APPTabs(line, signS, signF);
58    }
59    CalcFrameRate();
60    JudgFrameRate();
61    MultiLaneFrameRate();
62    return frameLossRate;
63}
64
65void StallingRateTrace::CalcFrameRate()
66{
67    if (appListDynamicStartTime != 0 && appListDynamicFinishTime != 0) {
68        appFrameLossRate = (frameLossTime / (appListDynamicFinishTime - appListDynamicStartTime) * oneThousand);
69    } else {
70        appFrameLossRate = -1;
71    }
72    LOGI("result.appFrameLossRate: (%s)", std::to_string(appFrameLossRate).c_str());
73
74    if (swiperDynamicFinishTime != 0 && swiperDynamicStartTime != 0) {
75        swiperFrameLossRate = (frameLossSwiperTime / (swiperDynamicFinishTime - swiperDynamicStartTime) * oneThousand);
76    } else {
77        swiperFrameLossRate = -1;
78    }
79    LOGI("result.swiperFrameLossRate: (%s)", std::to_string(swiperFrameLossRate).c_str());
80
81    if (appTabsDynamicStartTime != 0 && appTabsDynamicFinishTime != 0) {
82        tabsFrameLossRate = (frameLossTabsTime / (appTabsDynamicFinishTime - appTabsDynamicStartTime) * oneThousand);
83    } else {
84        tabsFrameLossRate = -1;
85    }
86    LOGI("result.tabsFrameLossRate: (%s)", std::to_string(tabsFrameLossRate).c_str());
87}
88
89void StallingRateTrace::JudgFrameRate()
90{
91    auto hasDynamic = [](bool finishTime, bool startTime) {
92        return finishTime != 0 || startTime != 0;
93    };
94
95    bool appListDynamicExists = hasDynamic(appListDynamicFinishTime, appListDynamicStartTime);
96    bool swiperDynamicExists = hasDynamic(swiperDynamicFinishTime, swiperDynamicStartTime);
97    bool tabsDynamicExists = hasDynamic(appTabsDynamicFinishTime, appTabsDynamicStartTime);
98
99    if (!appListDynamicExists) {
100        LOGI("no app list Dynamic");
101        frameLossRate = swiperDynamicExists ? swiperFrameLossRate :
102                        tabsDynamicExists ? tabsFrameLossRate : -1;
103    } else if (!swiperDynamicExists) {
104        LOGI("no swiper Dynamic");
105        frameLossRate = appListDynamicExists ? appFrameLossRate :
106                        tabsDynamicExists ? tabsFrameLossRate : -1;
107    } else if (!tabsDynamicExists) {
108        LOGI("no tabs Dynamic");
109        frameLossRate = appListDynamicExists ? appFrameLossRate :
110                        swiperDynamicExists ? swiperFrameLossRate : -1;
111    } else {
112        frameLossRate = -1;
113    }
114}
115
116void StallingRateTrace::MultiLaneFrameRate()
117{
118    if (appFrameLossRate == 0) {
119        LOGI("no app list hitchTime");
120        if (swiperFrameLossRate > 0) {
121            frameLossRate = swiperFrameLossRate;
122        } else if (tabsFrameLossRate > 0) {
123            frameLossRate = tabsFrameLossRate;
124        } else {
125            frameLossRate = 0;
126        }
127    } else if (swiperFrameLossRate == 0) {
128        LOGI("no swiper list hitchTime");
129        if (appFrameLossRate > 0) {
130            frameLossRate = appFrameLossRate;
131        } else if (tabsFrameLossRate > 0) {
132            frameLossRate = tabsFrameLossRate;
133        } else {
134            frameLossRate = 0;
135        }
136    } else if (tabsFrameLossRate == 0) {
137        LOGI("no tabs list hitchTime");
138        if (appFrameLossRate > 0) {
139            frameLossRate = appFrameLossRate;
140        } else if (swiperFrameLossRate > 0) {
141            frameLossRate = swiperFrameLossRate;
142        }
143    }
144    AddMultiLaneFrameRate();
145}
146
147void StallingRateTrace::AddMultiLaneFrameRate()
148{
149    if (appFrameLossRate > 0 && swiperFrameLossRate > 0) {
150        //app and swiper hitchTime 1
151        if (appListDynamicStartTime < swiperDynamicStartTime) {
152            frameLossRate = appFrameLossRate;
153        } else {
154            frameLossRate = swiperFrameLossRate;
155        }
156    } else if (appFrameLossRate > 0 && tabsFrameLossRate > 0) {
157        //app and tabs hitchTime 2
158        if (appListDynamicStartTime < appTabsDynamicStartTime) {
159            frameLossRate = appFrameLossRate;
160        } else {
161            frameLossRate = appTabsDynamicStartTime;
162        }
163    } else if (tabsFrameLossRate > 0 && swiperFrameLossRate > 0) {
164        //tabs and swiper hitchTime 3
165        if (appTabsDynamicStartTime < swiperDynamicStartTime) {
166            frameLossRate = tabsFrameLossRate;
167        } else {
168            frameLossRate = swiperFrameLossRate;
169        }
170    }
171}
172
173
174void StallingRateTrace::AppList(const std::string &line, const std::string &signS, const std::string &signF)
175{
176    if (line.find("H:LAUNCHER_APP_LAUNCH_FROM_ICON,") != std::string::npos ||
177        line.find("H:APP_LIST_FLING,") != std::string::npos ||
178        line.find("H:WEB_LIST_FLING") != std::string::npos ||
179        line.find("H:ABILITY_OR_PAGE_SWITCH,") != std::string::npos ||
180        line.find("H:APP_TRANSITION_TO_OTHER_APP,") != std::string::npos ||
181        line.find("H:LAUNCHER_APP_LAUNCH_FROM_DOCK,") != std::string::npos ||
182        line.find("H:LAUNCHER_APP_LAUNCH_FROM_APPCENTER,") != std::string::npos) {
183        if (listFlag) {
184            LOGI("AppList line start: (%s)", line.c_str());
185            appListDynamicFinishTime = GetTimes(line, signF);
186            LOGI("appListDynamicFinishTime: (%s)", std::to_string(appListDynamicFinishTime).c_str());
187            listFlag = false;
188        } else {
189            LOGI("AppList line finish: (%s)", line.c_str());
190            appListDynamicStartTime = GetTimes(line, signS);
191            LOGI("appListDynamicStartTime: (%s)", std::to_string(appListDynamicStartTime).c_str());
192            listFlag = true;
193            frameLossTime = 0;
194        }
195    }
196    if (listFlag) {
197        GetRsHardWareRate(nowFrameRate, line, SWIM_APPLIST);
198        if (upperScreenFlag) {
199            if (line.find("|H:Present Fence ") != std::string::npos) {
200                fenceId = GetFenceId(line);
201                LOGI("fenceId: (%d)", fenceId);
202            }
203            std::string waitFenceId = "|H:Waiting for Present Fence " + std::to_string(fenceId);
204            if (line.find(waitFenceId) != std::string::npos) {
205                nowTime = std::stod(SmartPerf::StallingRateTrace::GetOnScreenTimeStart(line));
206                GetFrameLossTime(nowTime, lastTime, roundTime, frameLossTime);
207                LOGI("frameLossTime: (%s)", std::to_string(frameLossTime).c_str());
208                lastTime = nowTime;
209                upperScreenFlag = false;
210            }
211        }
212    }
213}
214
215void StallingRateTrace::GetFrameLossTime(double curTime, double prevTime, double drawTime, double &totalFrameLossTime)
216{
217    if ((curTime - prevTime) > drawTime && prevTime != 0) {
218        double diffTime = (curTime - prevTime) - drawTime;
219        LOGI("diffTime: (%s)", std::to_string(diffTime).c_str());
220        totalFrameLossTime += diffTime;
221        LOGI("totalFrameLossTime: (%s)", std::to_string(totalFrameLossTime).c_str());
222    }
223}
224
225void StallingRateTrace::GetRsHardWareRate(double curFrameRate, const std::string &line, SWIM_TYPE type)
226{
227    if (line.find("H:RSHardwareThread::CommitAndReleaseLayers") != std::string::npos) {
228        switch (type) {
229            case SWIM_APPLIST:
230                upperScreenFlag = true;
231                break;
232            case SWIM_APPSWIPER:
233                upperScreenSwiperFlag = true;
234                break;
235            case SWIM_APPTABS:
236                upperScreenTabsFlag = true;
237                break;
238            default:
239                break;
240        }
241        curFrameRate = GetFrameRate(line);
242        LOGI("curFrameRate1: (%s)", std::to_string(curFrameRate).c_str());
243        if (curFrameRate != 0) {
244            UpdateRoundTime(curFrameRate, type);
245        }
246    } else if (line.find("H:RSHardwareThread::PerformSetActiveMode setting active mode") != std::string::npos) {
247        switch (type) {
248            case SWIM_APPLIST:
249                upperScreenFlag = true;
250                break;
251            case SWIM_APPSWIPER:
252                upperScreenSwiperFlag = true;
253                break;
254            case SWIM_APPTABS:
255                upperScreenTabsFlag = true;
256                break;
257            default:
258                break;
259        }
260        curFrameRate = GetFrameRate(line);
261        LOGI("curFrameRate2: (%s)", std::to_string(curFrameRate).c_str());
262        if (curFrameRate != 0) {
263            UpdateRoundTime(curFrameRate, type);
264        }
265    }
266}
267
268void StallingRateTrace::UpdateRoundTime(double curFrameRate, SWIM_TYPE type)
269{
270    const double kadunNum = 1.5;
271    const double num = 1;
272    if (curFrameRate != 0) {
273        switch (type) {
274            case SWIM_APPLIST:
275                roundTime = (num / curFrameRate) * kadunNum;
276                break;
277            case SWIM_APPSWIPER:
278                roundSwiperTime = (num / curFrameRate) * kadunNum;
279                break;
280            case SWIM_APPTABS:
281                roundTabsTime = (num / curFrameRate) * kadunNum;
282                break;
283            default:
284                break;
285        }
286    }
287}
288
289void StallingRateTrace::AppSwiperScroll(const std::string &line, const std::string &signS, const std::string &signF)
290{
291    if (line.find("H:APP_SWIPER_NO_ANIMATION_SWITCH") != std::string::npos ||
292        line.find("H:APP_SWITCH_FRAME_ANIMATION") != std::string::npos ||
293        line.find("H:APP_SWIPER_SCROLL,") != std::string::npos) {
294        if (swiperScrollFlag == 0) {
295            LOGI("AppSwiperScroll line start: (%s)", line.c_str());
296            swiperDynamicStartTime = GetTimes(line, signS);
297            LOGI("swiperDynamicStartTime: (%s)", std::to_string(swiperDynamicStartTime).c_str());
298            frameLossSwiperTime = 0;
299            swiperScrollFlag = 1;
300            swiperFlag = true;
301        }
302    }
303    if (line.find("H:APP_SWIPER_FLING,") != std::string::npos ||
304        line.find("H:APP_SWIPER_NO_ANIMATION_SWITCH") != std::string::npos ||
305        line.find("H:APP_SWITCH_FRAME_ANIMATION") != std::string::npos) {
306        if (swiperFlingFlag == 1) {
307            LOGI("AppSwiper FinishTime line: (%s)", line.c_str());
308            swiperDynamicFinishTime = GetTimes(line, signF);
309            LOGI("swiperDynamicFinishTime: (%s)", std::to_string(swiperDynamicFinishTime).c_str());
310            swiperFlag = false;
311        }
312        if (swiperDynamicFinishTime == 0) {
313            swiperFlingFlag = 0;
314        }
315        swiperFlingFlag++;
316    }
317    if (swiperFlag) {
318        GetRsHardWareRate(nowSwiperFrameRate, line, SWIM_APPSWIPER);
319        if (upperScreenSwiperFlag) {
320            if (line.find("|H:Present Fence ") != std::string::npos) {
321                fenceIdSwiper = GetFenceId(line);
322                LOGI("fenceIdSwiper: (%d)", fenceIdSwiper);
323            }
324            std::string waitFenceId = "|H:Waiting for Present Fence " + std::to_string(fenceIdSwiper);
325            if (line.find(waitFenceId) != std::string::npos) {
326                nowSwiperTime = std::stod(SmartPerf::StallingRateTrace::GetOnScreenTimeStart(line));
327                LOGI("nowSwiperTime: (%s)", std::to_string(nowSwiperTime).c_str());
328                GetFrameLossTime(nowSwiperTime, lastSwiperTime, roundSwiperTime, frameLossSwiperTime);
329                LOGI("frameLossSwiperTime: (%s)", std::to_string(frameLossSwiperTime).c_str());
330                lastSwiperTime = nowSwiperTime;
331                upperScreenSwiperFlag = false;
332            }
333        }
334    }
335}
336
337void StallingRateTrace::APPTabs(const std::string &line, const std::string &signS, const std::string &signF)
338{
339    static const std::string appTabsNoAnimation = "H:APP_TABS_NO_ANIMATION_SWITCH";
340    static const std::string appTabsFrameAnimation = "H:APP_TABS_FRAME_ANIMATION";
341    static const std::string appTabsScroll = "H:APP_TABS_SCROLL,";
342
343    if (line.find(appTabsNoAnimation) != std::string::npos ||
344        line.find(appTabsFrameAnimation) != std::string::npos ||
345        line.find(appTabsScroll) != std::string::npos) {
346        if (tabsFlag) {
347            LOGI("APPTabs line start: (%s)", line.c_str());
348            appTabsDynamicFinishTime = GetTimes(line, signF);
349            LOGI("appTabsDynamicFinishTime: (%s)", std::to_string(appTabsDynamicFinishTime).c_str());
350            tabsFlag = false;
351        } else {
352            LOGI("APPTabs line finish: (%s)", line.c_str());
353            appTabsDynamicStartTime = GetTimes(line, signS);
354            LOGI("appTabsDynamicStartTime: (%s)", std::to_string(appTabsDynamicStartTime).c_str());
355            tabsFlag = true;
356            frameLossTabsTime = 0;
357        }
358    }
359    if (tabsFlag) {
360        GetRsHardWareRate(nowTabsFrameRate, line, SWIM_APPTABS);
361        if (upperScreenTabsFlag) {
362            if (line.find("|H:Present Fence ") != std::string::npos) {
363                fenceIdTabs = GetFenceId(line);
364                LOGI("fenceIdTabs: (%s)", std::to_string(fenceIdTabs).c_str());
365            }
366            std::string waitFenceId = "|H:Waiting for Present Fence " + std::to_string(fenceIdTabs);
367            if (line.find(waitFenceId) != std::string::npos) {
368                nowTabsTime = std::stod(SmartPerf::StallingRateTrace::GetOnScreenTimeStart(line));
369                LOGI("nowTabsTime: (%s)", std::to_string(nowTabsTime).c_str());
370                LOGI("lastTabsTime: (%s)", std::to_string(lastTabsTime).c_str());
371                LOGI("roundTabsTime: (%s)", std::to_string(roundTabsTime).c_str());
372                GetFrameLossTime(nowTabsTime, lastTabsTime, roundTabsTime, frameLossTabsTime);
373                LOGI("app tabs frameLossTabsTime: (%s)", std::to_string(frameLossTabsTime).c_str());
374                lastTabsTime = nowTabsTime;
375                upperScreenTabsFlag = false;
376            }
377        }
378    }
379}
380
381double StallingRateTrace::GetFrameRate(const std::string &line) const
382{
383    double rate = 0;
384    std::string delimiter = "rate: ";
385    if (line.find("now:") != std::string::npos && line.find("rate:") != std::string::npos) {
386        std::string delimiter1 = ", now:";
387        size_t pos1 = line.find(delimiter);
388        std::string result1 = line.substr(pos1 + delimiter.length());
389        size_t pos2 = line.find(delimiter1);
390        std::string result2 = result1.substr(0, pos2);
391        rate = std::stod(result2.c_str());
392    }
393    if (line.find("rate:") != std::string::npos) {
394        size_t pos = line.find(delimiter);
395        std::string result = line.substr(pos + delimiter.length());
396        rate = std::stod(result.c_str());
397    }
398    return rate;
399}
400
401int StallingRateTrace::GetFenceId(const std::string &line) const
402{
403    std::string delimiter = "H:Present Fence ";
404    size_t pos = line.find(delimiter);
405    std::string result = line.substr(pos + delimiter.length());
406    int presentFenceId = std::atoi(result.c_str());
407    return presentFenceId;
408}
409
410std::string StallingRateTrace::GetOnScreenTimeStart(const std::string &line) const
411{
412    std::string startTime = "0";
413    size_t subNum = 7;
414    size_t positionFirst = line.find("....");
415    size_t positionSecond = line.find(":");
416    startTime = line.substr(positionFirst + subNum, positionSecond - positionFirst - subNum);
417    return startTime;
418}
419
420double StallingRateTrace::GetTimes(const std::string &line, const std::string &sign) const
421{
422    size_t positionFirst = line.find("....");
423    size_t positionSecond = line.find(":");
424    if (positionFirst != std::string::npos && positionSecond != std::string::npos) {
425        if (line.find(sign) != std::string::npos) {
426            size_t subNum = 7;
427            return std::stod(line.substr(positionFirst + subNum, positionSecond - positionFirst - subNum));
428        }
429    }
430    return 0.0;
431}
432}
433}
434