1 /* 2 * Copyright (c) 2025 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 <thread> 17 #include <chrono> 18 #include <fstream> 19 #include <sstream> 20 #include <vector> 21 #include "list_swipe_fps_collection.h" 22 23 namespace OHOS::perftest { 24 using namespace std; 25 const string TRACE_FILE_NAME = "/data/local/tmp/perftest_fps.ftrace"; 26 const string HITRACE_START_COMMAND = "hitrace -b 204800 --overwrite --trace_begin graphic nweb ace"; 27 const string HITRACE_FINISH_COMMAND = "hitrace --trace_finish -o " + TRACE_FILE_NAME; 28 const string REMOVE_TRACE_FILE = "rm -f " + TRACE_FILE_NAME; 29 const string SWIPE_START_STATE = "SWIPE_START"; 30 const string SWIPE_FINISH_STATE = "SWIPE_FINISH"; 31 const string SWIPE_INVALID_STATE = "SWIPE_INVALID"; 32 const string DO_COMPOSITION_TAG = "H:RSMainThread::DoComposition"; 33 const string APP_LIST_FLING_TAG = "H:APP_LIST_FLING"; 34 const string WEB_LIST_FLING_TAG = "H:WEB_LIST_FLING"; 35 const string APP_SWIPER_SCROLL_TAG = "H:APP_SWIPER_SCROLL"; 36 const string APP_SWIPER_FLING_TAG = "H:APP_SWIPER_FLING"; 37 StartCollection(ApiCallErr & error)38 void ListSwipeFpsCollection::StartCollection(ApiCallErr &error) 39 { 40 string executeRes; 41 ExecuteCommand(HITRACE_FINISH_COMMAND, executeRes); 42 ExecuteCommand(REMOVE_TRACE_FILE, executeRes); 43 if (!ExecuteCommand(HITRACE_START_COMMAND, executeRes)) { 44 error = ApiCallErr(ERR_DATA_COLLECTION_FAILED, "Start list swipe fps measure failed"); 45 return; 46 } 47 if (executeRes.find("OpenRecording done.") == string::npos) { 48 error = ApiCallErr(ERR_DATA_COLLECTION_FAILED, "Start list swipe fps measure failed"); 49 } 50 } 51 StopCollectionAndGetResult(ApiCallErr & error)52 double ListSwipeFpsCollection::StopCollectionAndGetResult(ApiCallErr &error) 53 { 54 string executeRes; 55 if (!ExecuteCommand(HITRACE_FINISH_COMMAND, executeRes)) { 56 error = ApiCallErr(ERR_DATA_COLLECTION_FAILED, "Stop list swipe fps measure failed"); 57 return INVALID_VALUE; 58 } 59 if (executeRes.find("Trace Closed.") == string::npos) { 60 error = ApiCallErr(ERR_DATA_COLLECTION_FAILED, "Stop list swipe fps measure failed"); 61 return INVALID_VALUE; 62 } 63 pid_ = GetPidByBundleName(bundleName_); 64 if (pid_ == -1) { 65 error = ApiCallErr(ERR_DATA_COLLECTION_FAILED, "The process does not exist when fps trace parse"); 66 return INVALID_VALUE; 67 } 68 return ParseFpsByTrace(error); 69 } 70 ParseFpsByTrace(ApiCallErr & error)71 double ListSwipeFpsCollection::ParseFpsByTrace(ApiCallErr &error) 72 { 73 ifstream file(TRACE_FILE_NAME); 74 if (!file.is_open()) { 75 error = ApiCallErr(ERR_DATA_COLLECTION_FAILED, "Get list swipe trace failed"); 76 return INVALID_VALUE; 77 } 78 double startTime = INITIAL_VALUE; 79 double endTime = INITIAL_VALUE; 80 int32_t frameCount = ZERO; 81 string line; 82 while (getline(file, line)) { 83 const vector<string> tokens = SplitString(line, ' '); 84 int32_t stateIndex = 0; 85 if (line.find(APP_LIST_FLING_TAG) != string::npos) { 86 if (GetSwipeState(tokens, APP_LIST_FLING_TAG, stateIndex) == SWIPE_START_STATE) { 87 LOG_D("App list fling start"); 88 startTime = GetTime(tokens, stateIndex - TWO); 89 } else if (GetSwipeState(tokens, APP_LIST_FLING_TAG, stateIndex) == SWIPE_FINISH_STATE) { 90 LOG_D("App list fling finish"); 91 endTime = GetTime(tokens, stateIndex - TWO); 92 } 93 } else if (line.find(WEB_LIST_FLING_TAG) != string::npos) { 94 if (GetSwipeState(tokens, WEB_LIST_FLING_TAG, stateIndex) == SWIPE_START_STATE) { 95 LOG_D("Web list fling start"); 96 startTime = GetTime(tokens, stateIndex - TWO); 97 } else if (GetSwipeState(tokens, WEB_LIST_FLING_TAG, stateIndex) == SWIPE_FINISH_STATE) { 98 LOG_D("Web list fling finish"); 99 endTime = GetTime(tokens, stateIndex - TWO); 100 } 101 } else if (line.find(APP_SWIPER_SCROLL_TAG) != string::npos && 102 GetSwipeState(tokens, APP_SWIPER_SCROLL_TAG, stateIndex) == SWIPE_START_STATE) { 103 LOG_D("Swiper scroll start"); 104 startTime = GetTime(tokens, stateIndex - TWO); 105 } else if (line.find(APP_SWIPER_FLING_TAG) != string::npos && startTime > INITIAL_VALUE && 106 GetSwipeState(tokens, APP_SWIPER_FLING_TAG, stateIndex) == SWIPE_FINISH_STATE) { 107 LOG_D("Swiper scroll finish"); 108 endTime = GetTime(tokens, stateIndex - TWO); 109 } else if (line.find(DO_COMPOSITION_TAG) != string::npos && startTime > INITIAL_VALUE) { 110 frameCount++; 111 } 112 if (startTime > INITIAL_VALUE && endTime > INITIAL_VALUE && frameCount != ZERO) { 113 file.close(); 114 return frameCount / (endTime - startTime); 115 } 116 } 117 file.close(); 118 return INVALID_VALUE; 119 } 120 GetSwipeState(const vector<string> & tokens,const string traceTag,int32_t & stateIndex)121 string ListSwipeFpsCollection::GetSwipeState(const vector<string> &tokens, const string traceTag, 122 int32_t &stateIndex) 123 { 124 string token = ""; 125 for (int32_t index = ZERO; index < tokens.size(); index++) { 126 if (tokens[index].find(traceTag) != string::npos) { 127 token = tokens[index]; 128 stateIndex = index; 129 break; 130 } 131 } 132 vector<string> tagInfos = SplitString(token, '|'); 133 if (tagInfos.size() > TWO && tagInfos[INDEX_TWO] == traceTag && tagInfos[INDEX_ONE] == to_string(pid_)) { 134 switch (tagInfos[INDEX_ZERO][INDEX_ZERO]) { 135 case 'S': 136 return SWIPE_START_STATE; 137 case 'F': 138 return SWIPE_FINISH_STATE; 139 default: 140 return SWIPE_INVALID_STATE; 141 } 142 } 143 return SWIPE_INVALID_STATE; 144 } 145 GetTime(const vector<string> & tokens,const int32_t timeIndex)146 double ListSwipeFpsCollection::GetTime(const vector<string> &tokens, const int32_t timeIndex) 147 { 148 double time = INITIAL_VALUE; 149 if (timeIndex < 0) { 150 return time; 151 } 152 string token = tokens[timeIndex]; 153 if (token.size() == 0) { 154 return time; 155 } 156 string timeStr = token.substr(0, token.size() - 1); 157 istringstream iss(timeStr); 158 if ((iss >> time) && iss.eof()) { 159 return time; 160 } 161 return time; 162 } 163 SplitString(const string line,const char delimiter)164 vector<string> ListSwipeFpsCollection::SplitString(const string line, const char delimiter) 165 { 166 stringstream ss(line); 167 vector<std::string> tokens; 168 string token; 169 while (getline(ss, token, delimiter)) { 170 if (!token.empty()) { 171 tokens.push_back(token); 172 } 173 } 174 return tokens; 175 } 176 }