13f085823Sopenharmony_ci/* 23f085823Sopenharmony_ci * Copyright (c) 2021 Huawei Device Co., Ltd. 33f085823Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 43f085823Sopenharmony_ci * you may not use this file except in compliance with the License. 53f085823Sopenharmony_ci * You may obtain a copy of the License at 63f085823Sopenharmony_ci * 73f085823Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 83f085823Sopenharmony_ci * 93f085823Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 103f085823Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 113f085823Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 123f085823Sopenharmony_ci * See the License for the specific language governing permissions and 133f085823Sopenharmony_ci * limitations under the License. 143f085823Sopenharmony_ci */ 153f085823Sopenharmony_ci 163f085823Sopenharmony_ci#include <perf.h> 173f085823Sopenharmony_ci#include <gtest/gtest-message.h> 183f085823Sopenharmony_ci#include <gtest/gtest-test-part.h> 193f085823Sopenharmony_ci#include <gtest/gtest.h> 203f085823Sopenharmony_ci#include <istream> 213f085823Sopenharmony_ci#include <libxml/globals.h> 223f085823Sopenharmony_ci#include <libxml/xmlstring.h> 233f085823Sopenharmony_ci#include <list> 243f085823Sopenharmony_ci#include <map> 253f085823Sopenharmony_ci#include <securec.h> 263f085823Sopenharmony_ci#include <type_traits> 273f085823Sopenharmony_ci#include <string> 283f085823Sopenharmony_ci 293f085823Sopenharmony_ci#include <sstream> 303f085823Sopenharmony_ci#include <libxml/parser.h> 313f085823Sopenharmony_ciusing namespace std; 323f085823Sopenharmony_ci 333f085823Sopenharmony_cinamespace OHOS { 343f085823Sopenharmony_cinamespace TestAW { 353f085823Sopenharmony_ci 363f085823Sopenharmony_ci#define ERR_MSG(...) fprintf(stderr, __VA_ARGS__) 373f085823Sopenharmony_ci#define INF_MSG(...) fprintf(stdout, __VA_ARGS__) 383f085823Sopenharmony_ci#define DBG_MSG(...) fprintf(stdout, __VA_ARGS__) 393f085823Sopenharmony_ci 403f085823Sopenharmony_ci#define ID_LARGER_IS_BETTER true 413f085823Sopenharmony_ci#define ID_SMALLER_IS_BETTER false 423f085823Sopenharmony_ci 433f085823Sopenharmony_cinamespace { 443f085823Sopenharmony_ci const auto XML_TAG_ROOT = "configuration"; 453f085823Sopenharmony_ci const auto XML_TAG_DATETIME = "datetime"; 463f085823Sopenharmony_ci const auto XML_TAG_URL = "url"; 473f085823Sopenharmony_ci const auto XML_TAG_CASENAME = "name"; 483f085823Sopenharmony_ci const int ID_PROPERTY_LENGTH = 64; 493f085823Sopenharmony_ci} 503f085823Sopenharmony_ci 513f085823Sopenharmony_ci// BaseLineManager 523f085823Sopenharmony_ciBaseLineManager::BaseLineManager() 533f085823Sopenharmony_ci : m_bNoBaseline(false) 543f085823Sopenharmony_ci{ 553f085823Sopenharmony_ci} 563f085823Sopenharmony_ci 573f085823Sopenharmony_ciBaseLineManager::BaseLineManager(const string path) 583f085823Sopenharmony_ci : m_bNoBaseline(false) 593f085823Sopenharmony_ci{ 603f085823Sopenharmony_ci LoadConfig(path); 613f085823Sopenharmony_ci} 623f085823Sopenharmony_ci 633f085823Sopenharmony_ciBaseLineManager::~BaseLineManager() 643f085823Sopenharmony_ci{ 653f085823Sopenharmony_ci if (m_bNoBaseline) { 663f085823Sopenharmony_ci ERR_MSG("[ WARNING ] no baseline loaded, please manual check output value is OK.\n"); 673f085823Sopenharmony_ci } 683f085823Sopenharmony_ci} 693f085823Sopenharmony_ci 703f085823Sopenharmony_ci// parser configuration file in json format. 713f085823Sopenharmony_cibool BaseLineManager::LoadConfig(const string path) 723f085823Sopenharmony_ci{ 733f085823Sopenharmony_ci m_bNoBaseline = false; 743f085823Sopenharmony_ci if (!ReadXmlFile(path)) { 753f085823Sopenharmony_ci ERR_MSG("[ WARNING ] failed to load config from %s\n", path.c_str()); 763f085823Sopenharmony_ci m_bNoBaseline = true; 773f085823Sopenharmony_ci return false; 783f085823Sopenharmony_ci } 793f085823Sopenharmony_ci 803f085823Sopenharmony_ci INF_MSG("[ PERF ] Load BaseLines from: %s\n", path.c_str()); 813f085823Sopenharmony_ci return true; 823f085823Sopenharmony_ci} 833f085823Sopenharmony_ci 843f085823Sopenharmony_civoid ParseProperties(const xmlNode currNode, map<string, string>& properties) 853f085823Sopenharmony_ci{ 863f085823Sopenharmony_ci for (auto attrs = currNode.properties; attrs != nullptr; attrs = attrs->next) { 873f085823Sopenharmony_ci auto name = attrs->name; 883f085823Sopenharmony_ci if (name == nullptr) { 893f085823Sopenharmony_ci continue; 903f085823Sopenharmony_ci } 913f085823Sopenharmony_ci auto value = xmlGetProp(&currNode, name); 923f085823Sopenharmony_ci if (value == nullptr) { 933f085823Sopenharmony_ci continue; 943f085823Sopenharmony_ci } 953f085823Sopenharmony_ci string propName(reinterpret_cast<const char*>(name)); 963f085823Sopenharmony_ci string propValue(reinterpret_cast<char*>(value)); 973f085823Sopenharmony_ci properties[propName] = std::move(propValue); 983f085823Sopenharmony_ci xmlFree(value); 993f085823Sopenharmony_ci } 1003f085823Sopenharmony_ci} 1013f085823Sopenharmony_ci 1023f085823Sopenharmony_cibool BaseLineManager::ReadXmlFile(string baselinePath) 1033f085823Sopenharmony_ci{ 1043f085823Sopenharmony_ci xmlDocPtr ptrXmlDoc = xmlReadFile(baselinePath.c_str(), nullptr, XML_PARSE_NOBLANKS); 1053f085823Sopenharmony_ci if (ptrXmlDoc == nullptr) { 1063f085823Sopenharmony_ci return false; 1073f085823Sopenharmony_ci } 1083f085823Sopenharmony_ci 1093f085823Sopenharmony_ci xmlNodePtr ptrRootNode = xmlDocGetRootElement(ptrXmlDoc); 1103f085823Sopenharmony_ci if (ptrRootNode == nullptr || ptrRootNode->name == nullptr || 1113f085823Sopenharmony_ci xmlStrcmp(ptrRootNode->name, reinterpret_cast<const xmlChar*>(XML_TAG_ROOT))) { 1123f085823Sopenharmony_ci xmlFreeDoc(ptrXmlDoc); 1133f085823Sopenharmony_ci return false; 1143f085823Sopenharmony_ci } 1153f085823Sopenharmony_ci 1163f085823Sopenharmony_ci map<string, string> properties; 1173f085823Sopenharmony_ci ParseProperties(*ptrRootNode, properties); 1183f085823Sopenharmony_ci if (properties.count(XML_TAG_DATETIME) == 1) { 1193f085823Sopenharmony_ci m_bastCfg.date = properties[XML_TAG_DATETIME]; 1203f085823Sopenharmony_ci } 1213f085823Sopenharmony_ci if (properties.count(XML_TAG_URL) == 1) { 1223f085823Sopenharmony_ci m_bastCfg.date = properties[XML_TAG_URL]; 1233f085823Sopenharmony_ci } 1243f085823Sopenharmony_ci 1253f085823Sopenharmony_ci xmlNodePtr currNodePtr = ptrRootNode->xmlChildrenNode; 1263f085823Sopenharmony_ci for (; currNodePtr != nullptr; currNodePtr = currNodePtr->next) { 1273f085823Sopenharmony_ci if (currNodePtr->name == nullptr || currNodePtr->type == XML_COMMENT_NODE) { 1283f085823Sopenharmony_ci xmlFreeDoc(ptrXmlDoc); 1293f085823Sopenharmony_ci return false; 1303f085823Sopenharmony_ci } 1313f085823Sopenharmony_ci 1323f085823Sopenharmony_ci map<string, string> properties_temp; 1333f085823Sopenharmony_ci ParseProperties(*currNodePtr, properties_temp); 1343f085823Sopenharmony_ci m_bastCfg.items.push_back(properties_temp); 1353f085823Sopenharmony_ci } 1363f085823Sopenharmony_ci 1373f085823Sopenharmony_ci xmlFreeDoc(ptrXmlDoc); 1383f085823Sopenharmony_ci return true; 1393f085823Sopenharmony_ci} 1403f085823Sopenharmony_ci 1413f085823Sopenharmony_cibool BaseLineManager::IsNoBaseline() 1423f085823Sopenharmony_ci{ 1433f085823Sopenharmony_ci return m_bNoBaseline; 1443f085823Sopenharmony_ci} 1453f085823Sopenharmony_ci 1463f085823Sopenharmony_cidouble BaseLineManager::StrtoDouble(const string& str) 1473f085823Sopenharmony_ci{ 1483f085823Sopenharmony_ci istringstream iss(str); 1493f085823Sopenharmony_ci double num; 1503f085823Sopenharmony_ci iss >> num; 1513f085823Sopenharmony_ci return num; 1523f085823Sopenharmony_ci} 1533f085823Sopenharmony_ci 1543f085823Sopenharmony_cibool BaseLineManager::GetExtraValueDouble(const string testcaseName, const string extra, double &value) 1553f085823Sopenharmony_ci{ 1563f085823Sopenharmony_ci if (testcaseName == "" || extra == "") { 1573f085823Sopenharmony_ci DBG_MSG("[ ERROR ] invalid arguments: testcaseName=%s, extra=%s\n", testcaseName.c_str(), extra.c_str()); 1583f085823Sopenharmony_ci return false; 1593f085823Sopenharmony_ci } 1603f085823Sopenharmony_ci 1613f085823Sopenharmony_ci for (auto iter = m_bastCfg.items.begin(); iter != m_bastCfg.items.end(); iter++) { 1623f085823Sopenharmony_ci map<string, string> properties = *iter; 1633f085823Sopenharmony_ci if (properties.count(XML_TAG_CASENAME) == 1 && properties[XML_TAG_CASENAME] == testcaseName) { 1643f085823Sopenharmony_ci if (properties.count(extra) == 1) { 1653f085823Sopenharmony_ci value = StrtoDouble(properties[extra]); 1663f085823Sopenharmony_ci } 1673f085823Sopenharmony_ci break; 1683f085823Sopenharmony_ci } 1693f085823Sopenharmony_ci } 1703f085823Sopenharmony_ci 1713f085823Sopenharmony_ci return true; 1723f085823Sopenharmony_ci} 1733f085823Sopenharmony_ci 1743f085823Sopenharmony_ci// GtestPerfTestCase 1753f085823Sopenharmony_ciGtestPerfTestCase::GtestPerfTestCase(BaseLineManager* pManager, 1763f085823Sopenharmony_ci testing::Test *tester, 1773f085823Sopenharmony_ci int caseVersion, 1783f085823Sopenharmony_ci std::string testClassName, 1793f085823Sopenharmony_ci std::string testInterfaceName) 1803f085823Sopenharmony_ci{ 1813f085823Sopenharmony_ci m_pManager = pManager; 1823f085823Sopenharmony_ci m_pTester = tester; 1833f085823Sopenharmony_ci m_dCaseVersion = caseVersion; 1843f085823Sopenharmony_ci m_strCaseName = ""; 1853f085823Sopenharmony_ci m_strTestClassName = testClassName; 1863f085823Sopenharmony_ci m_strTestInterfaceName = testInterfaceName; 1873f085823Sopenharmony_ci 1883f085823Sopenharmony_ci // get test case name from GTEST API. 1893f085823Sopenharmony_ci // should be use tester->XXX() instead of this. 1903f085823Sopenharmony_ci if (tester != nullptr && ::testing::UnitTest::GetInstance() != nullptr) { 1913f085823Sopenharmony_ci m_strCaseName = string(::testing::UnitTest::GetInstance()->current_test_info()->name()); 1923f085823Sopenharmony_ci } 1933f085823Sopenharmony_ci 1943f085823Sopenharmony_ci // start initialize. 1953f085823Sopenharmony_ci Initialize(); 1963f085823Sopenharmony_ci} 1973f085823Sopenharmony_ci 1983f085823Sopenharmony_cibool GtestPerfTestCase::SetBaseLine(string testcaseName) 1993f085823Sopenharmony_ci{ 2003f085823Sopenharmony_ci if (testcaseName == "") { 2013f085823Sopenharmony_ci return false; 2023f085823Sopenharmony_ci } 2033f085823Sopenharmony_ci 2043f085823Sopenharmony_ci m_strCaseName = testcaseName; 2053f085823Sopenharmony_ci 2063f085823Sopenharmony_ci return Initialize(); 2073f085823Sopenharmony_ci} 2083f085823Sopenharmony_ci 2093f085823Sopenharmony_civoid GtestPerfTestCase::ResetValues() 2103f085823Sopenharmony_ci{ 2113f085823Sopenharmony_ci m_bHasBaseLine = false; 2123f085823Sopenharmony_ci m_dbBaseLine = -1.0; 2133f085823Sopenharmony_ci m_bHasLastValue = false; 2143f085823Sopenharmony_ci m_dbLastValue = -1.0; 2153f085823Sopenharmony_ci m_bHasFloatRange = false; 2163f085823Sopenharmony_ci m_dbFloatRange = -1.0; 2173f085823Sopenharmony_ci 2183f085823Sopenharmony_ci m_bTestResult = false; 2193f085823Sopenharmony_ci m_dbTestResult = -1.0; 2203f085823Sopenharmony_ci} 2213f085823Sopenharmony_ci 2223f085823Sopenharmony_cibool GtestPerfTestCase::Initialize() 2233f085823Sopenharmony_ci{ 2243f085823Sopenharmony_ci // clear all values. 2253f085823Sopenharmony_ci ResetValues(); 2263f085823Sopenharmony_ci if (m_strCaseName == "" || m_pManager == nullptr) { 2273f085823Sopenharmony_ci return false; 2283f085823Sopenharmony_ci } 2293f085823Sopenharmony_ci 2303f085823Sopenharmony_ci // get baseline value 2313f085823Sopenharmony_ci m_bHasBaseLine = m_pManager->GetExtraValueDouble(m_strCaseName, "baseline", m_dbBaseLine); 2323f085823Sopenharmony_ci if (!m_bHasBaseLine) { 2333f085823Sopenharmony_ci return false; 2343f085823Sopenharmony_ci } 2353f085823Sopenharmony_ci 2363f085823Sopenharmony_ci // get last test value from config. 2373f085823Sopenharmony_ci m_bHasLastValue = m_pManager->GetExtraValueDouble(m_strCaseName, "lastvalue", m_dbLastValue); 2383f085823Sopenharmony_ci 2393f085823Sopenharmony_ci // get float range value from config. 2403f085823Sopenharmony_ci m_bHasFloatRange = m_pManager->GetExtraValueDouble(m_strCaseName, "floatrange", m_dbFloatRange); 2413f085823Sopenharmony_ci // check values is valid, and update them. 2423f085823Sopenharmony_ci if (m_bHasFloatRange && (m_dbFloatRange < 0 || m_dbFloatRange >= 1)) { 2433f085823Sopenharmony_ci DBG_MSG("[ ERROR ] %s has invalid float range: %f.\n", m_strCaseName.c_str(), m_dbFloatRange); 2443f085823Sopenharmony_ci m_bHasFloatRange = false; 2453f085823Sopenharmony_ci } 2463f085823Sopenharmony_ci 2473f085823Sopenharmony_ci if (!m_bHasFloatRange) { 2483f085823Sopenharmony_ci m_dbFloatRange = 0.0; 2493f085823Sopenharmony_ci } 2503f085823Sopenharmony_ci 2513f085823Sopenharmony_ci if (!m_bHasLastValue) { 2523f085823Sopenharmony_ci m_dbLastValue = m_dbBaseLine; 2533f085823Sopenharmony_ci } 2543f085823Sopenharmony_ci 2553f085823Sopenharmony_ci return true; 2563f085823Sopenharmony_ci} 2573f085823Sopenharmony_ci 2583f085823Sopenharmony_ci// return true if testValue >= baseline value 2593f085823Sopenharmony_cibool GtestPerfTestCase::ExpectLarger(double testValue) 2603f085823Sopenharmony_ci{ 2613f085823Sopenharmony_ci return ExpectValue(testValue, ID_LARGER_IS_BETTER); 2623f085823Sopenharmony_ci} 2633f085823Sopenharmony_ci 2643f085823Sopenharmony_ci// return true if testValue <= baseline value 2653f085823Sopenharmony_cibool GtestPerfTestCase::ExpectSmaller(double testValue) 2663f085823Sopenharmony_ci{ 2673f085823Sopenharmony_ci return ExpectValue(testValue, ID_SMALLER_IS_BETTER); 2683f085823Sopenharmony_ci} 2693f085823Sopenharmony_ci 2703f085823Sopenharmony_cibool GtestPerfTestCase::ExpectValue(double testValue, bool isLargerBetter) 2713f085823Sopenharmony_ci{ 2723f085823Sopenharmony_ci if (m_strCaseName == "") { 2733f085823Sopenharmony_ci ERR_MSG("[ ERROR ] failed to get testcase name.\n"); 2743f085823Sopenharmony_ci return false; 2753f085823Sopenharmony_ci } 2763f085823Sopenharmony_ci 2773f085823Sopenharmony_ci m_bTestResult = false; 2783f085823Sopenharmony_ci m_dbTestResult = testValue; 2793f085823Sopenharmony_ci 2803f085823Sopenharmony_ci // check pass or failed. 2813f085823Sopenharmony_ci if (m_pManager != nullptr && m_pManager->IsNoBaseline()) { 2823f085823Sopenharmony_ci // no baseline.json is loaded at startup. 2833f085823Sopenharmony_ci // set result to TRUE, please check testValue manually. 2843f085823Sopenharmony_ci m_bTestResult = true; 2853f085823Sopenharmony_ci EXPECT_TRUE(m_bTestResult); 2863f085823Sopenharmony_ci } else if (!m_bHasBaseLine) { 2873f085823Sopenharmony_ci ERR_MSG("[ ERROR ] %s has NO baseline.\n", m_strCaseName.c_str()); 2883f085823Sopenharmony_ci EXPECT_TRUE(m_bHasBaseLine); 2893f085823Sopenharmony_ci } else { 2903f085823Sopenharmony_ci double baseValue = -1; 2913f085823Sopenharmony_ci if (isLargerBetter) { 2923f085823Sopenharmony_ci baseValue = (m_dbLastValue >= m_dbBaseLine) ? m_dbLastValue : m_dbBaseLine; 2933f085823Sopenharmony_ci EXPECT_GE(testValue, (baseValue * (1.0 - m_dbFloatRange))); 2943f085823Sopenharmony_ci m_bTestResult = (testValue >= (baseValue * (1.0 - m_dbFloatRange))) ? true : false; 2953f085823Sopenharmony_ci } else { 2963f085823Sopenharmony_ci baseValue = (m_dbLastValue <= m_dbBaseLine) ? m_dbLastValue : m_dbBaseLine; 2973f085823Sopenharmony_ci EXPECT_LE(testValue, (baseValue * (1.0 + m_dbFloatRange))); 2983f085823Sopenharmony_ci m_bTestResult = (testValue <= (baseValue * (1.0 + m_dbFloatRange))) ? true : false; 2993f085823Sopenharmony_ci } 3003f085823Sopenharmony_ci } 3013f085823Sopenharmony_ci 3023f085823Sopenharmony_ci // save result. 3033f085823Sopenharmony_ci SaveResult(testValue); 3043f085823Sopenharmony_ci 3053f085823Sopenharmony_ci return m_bTestResult; 3063f085823Sopenharmony_ci} 3073f085823Sopenharmony_ci 3083f085823Sopenharmony_cibool GtestPerfTestCase::SaveResult(double testValue) 3093f085823Sopenharmony_ci{ 3103f085823Sopenharmony_ci char buffer[ID_PROPERTY_LENGTH] = {0}; 3113f085823Sopenharmony_ci 3123f085823Sopenharmony_ci if (m_pTester == nullptr) { 3133f085823Sopenharmony_ci ERR_MSG("[ ERROR ] m_pTester is nullptr.\n"); 3143f085823Sopenharmony_ci return false; 3153f085823Sopenharmony_ci } 3163f085823Sopenharmony_ci 3173f085823Sopenharmony_ci INF_MSG("[ PERF ] %s: baseline:%f, test_result: %f\n", m_strCaseName.c_str(), m_dbBaseLine, testValue); 3183f085823Sopenharmony_ci 3193f085823Sopenharmony_ci (void)memset_s(buffer, sizeof(buffer), 0, sizeof(buffer)); 3203f085823Sopenharmony_ci if (snprintf_s(buffer, sizeof(buffer), sizeof(buffer) - 1, "%g", m_dbBaseLine) > 0) { 3213f085823Sopenharmony_ci m_pTester->RecordProperty("baseline", buffer); 3223f085823Sopenharmony_ci } 3233f085823Sopenharmony_ci 3243f085823Sopenharmony_ci (void)memset_s(buffer, sizeof(buffer), 0, sizeof(buffer)); 3253f085823Sopenharmony_ci if (snprintf_s(buffer, sizeof(buffer), sizeof(buffer) - 1, "%d", m_dCaseVersion) > 0) { 3263f085823Sopenharmony_ci m_pTester->RecordProperty("tc_version", buffer); 3273f085823Sopenharmony_ci } 3283f085823Sopenharmony_ci 3293f085823Sopenharmony_ci (void)memset_s(buffer, sizeof(buffer), 0, sizeof(buffer)); 3303f085823Sopenharmony_ci if (snprintf_s(buffer, sizeof(buffer), sizeof(buffer) - 1, "%g", m_dbLastValue) > 0) { 3313f085823Sopenharmony_ci m_pTester->RecordProperty("lastvalue", m_bHasLastValue ? buffer : ""); 3323f085823Sopenharmony_ci } 3333f085823Sopenharmony_ci 3343f085823Sopenharmony_ci (void)memset_s(buffer, sizeof(buffer), 0, sizeof(buffer)); 3353f085823Sopenharmony_ci if (snprintf_s(buffer, sizeof(buffer), sizeof(buffer) - 1, "%g", testValue) > 0) { 3363f085823Sopenharmony_ci m_pTester->RecordProperty("value", buffer); 3373f085823Sopenharmony_ci } 3383f085823Sopenharmony_ci 3393f085823Sopenharmony_ci m_pTester->RecordProperty("category", "performance"); 3403f085823Sopenharmony_ci m_pTester->RecordProperty("test_class", m_strTestClassName.c_str()); 3413f085823Sopenharmony_ci m_pTester->RecordProperty("test_interface", m_strTestInterfaceName.c_str()); 3423f085823Sopenharmony_ci 3433f085823Sopenharmony_ci return true; 3443f085823Sopenharmony_ci} 3453f085823Sopenharmony_ci} // namespace TestAW 3463f085823Sopenharmony_ci} // namespace OHOS 347