14514f5e3Sopenharmony_ci/*
24514f5e3Sopenharmony_ci * Copyright (c) 2024 Huawei Device Co., Ltd.
34514f5e3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
44514f5e3Sopenharmony_ci * you may not use this file except in compliance with the License.
54514f5e3Sopenharmony_ci * You may obtain a copy of the License at
64514f5e3Sopenharmony_ci *
74514f5e3Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
84514f5e3Sopenharmony_ci *
94514f5e3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
104514f5e3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
114514f5e3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
124514f5e3Sopenharmony_ci * See the License for the specific language governing permissions and
134514f5e3Sopenharmony_ci * limitations under the License.
144514f5e3Sopenharmony_ci */
154514f5e3Sopenharmony_ci
164514f5e3Sopenharmony_ci#ifndef ECMASCRIPT_JIT_JIT_DFX_H
174514f5e3Sopenharmony_ci#define ECMASCRIPT_JIT_JIT_DFX_H
184514f5e3Sopenharmony_ci
194514f5e3Sopenharmony_ci#include <fstream>
204514f5e3Sopenharmony_ci#include <map>
214514f5e3Sopenharmony_ci#include <atomic>
224514f5e3Sopenharmony_ci
234514f5e3Sopenharmony_ci#include "ecmascript/log.h"
244514f5e3Sopenharmony_ci#include "ecmascript/mem/c_string.h"
254514f5e3Sopenharmony_ci
264514f5e3Sopenharmony_cinamespace panda::ecmascript {
274514f5e3Sopenharmony_ciusing Clock = std::chrono::high_resolution_clock;
284514f5e3Sopenharmony_ciusing Duration = std::chrono::duration<uint64_t, std::nano>;
294514f5e3Sopenharmony_ci
304514f5e3Sopenharmony_cistruct JitEventParams {
314514f5e3Sopenharmony_ci    std::atomic<int> totalBaselineJitTimes_;
324514f5e3Sopenharmony_ci    std::atomic<int> totalFastoptJitTimes_;
334514f5e3Sopenharmony_ci    std::atomic<int> jitDeoptTimes_;
344514f5e3Sopenharmony_ci    std::atomic<int> longtimeLockTimes_;
354514f5e3Sopenharmony_ci    std::atomic<int> singleTimeOnMainThread_;
364514f5e3Sopenharmony_ci    std::atomic<int> totalTimeOnMainThread_;
374514f5e3Sopenharmony_ci    std::atomic<int> singleTimeOnJitThread_;
384514f5e3Sopenharmony_ci    std::atomic<int> totalTimeOnJitThread_;
394514f5e3Sopenharmony_ci    std::atomic<int> totalLockHoldingTime_;
404514f5e3Sopenharmony_ci    std::atomic<int> maxLockHoldingTime_;
414514f5e3Sopenharmony_ci    Clock::time_point start_;
424514f5e3Sopenharmony_ci    Clock::time_point blockUIEventstart_;
434514f5e3Sopenharmony_ci
444514f5e3Sopenharmony_ci    JitEventParams() : totalBaselineJitTimes_(0), totalFastoptJitTimes_(0), jitDeoptTimes_(0),
454514f5e3Sopenharmony_ci        longtimeLockTimes_(0), singleTimeOnMainThread_(0), totalTimeOnMainThread_(0),
464514f5e3Sopenharmony_ci        singleTimeOnJitThread_(0), totalTimeOnJitThread_(0), totalLockHoldingTime_(0),
474514f5e3Sopenharmony_ci        maxLockHoldingTime_(0), start_(Clock::now()), blockUIEventstart_(Clock::now()) {}
484514f5e3Sopenharmony_ci};
494514f5e3Sopenharmony_ci
504514f5e3Sopenharmony_ciclass Method;
514514f5e3Sopenharmony_ciclass JitDfx {
524514f5e3Sopenharmony_cipublic:
534514f5e3Sopenharmony_ci    using ThreadId = uint32_t;
544514f5e3Sopenharmony_ci    static JitDfx *GetInstance();
554514f5e3Sopenharmony_ci    void Init(const JSRuntimeOptions &options, std::string &bundleName);
564514f5e3Sopenharmony_ci    void EnableDump();
574514f5e3Sopenharmony_ci    bool IsEnableDump() const
584514f5e3Sopenharmony_ci    {
594514f5e3Sopenharmony_ci        return isEnableDump_;
604514f5e3Sopenharmony_ci    }
614514f5e3Sopenharmony_ci
624514f5e3Sopenharmony_ci    std::ostream &GetLogFileStream();
634514f5e3Sopenharmony_ci
644514f5e3Sopenharmony_ci    void DumpBytecodeInst(Method *method);
654514f5e3Sopenharmony_ci    void TraceJitCode(Method *method, bool isEntry);
664514f5e3Sopenharmony_ci
674514f5e3Sopenharmony_ci    void SetBundleName(CString bundleName)
684514f5e3Sopenharmony_ci    {
694514f5e3Sopenharmony_ci        bundleName_ = bundleName;
704514f5e3Sopenharmony_ci    }
714514f5e3Sopenharmony_ci
724514f5e3Sopenharmony_ci    CString GetBundleName() const
734514f5e3Sopenharmony_ci    {
744514f5e3Sopenharmony_ci        return bundleName_;
754514f5e3Sopenharmony_ci    }
764514f5e3Sopenharmony_ci
774514f5e3Sopenharmony_ci    void SetPidNumber(ThreadId number)
784514f5e3Sopenharmony_ci    {
794514f5e3Sopenharmony_ci        pidNum_ = number;
804514f5e3Sopenharmony_ci    }
814514f5e3Sopenharmony_ci
824514f5e3Sopenharmony_ci    ThreadId GetPidNumber() const
834514f5e3Sopenharmony_ci    {
844514f5e3Sopenharmony_ci        return pidNum_;
854514f5e3Sopenharmony_ci    }
864514f5e3Sopenharmony_ci
874514f5e3Sopenharmony_ci    void RecordSpentTimeAndPrintStatsLogInJsThread(int time)
884514f5e3Sopenharmony_ci    {
894514f5e3Sopenharmony_ci        SetTotalTimeOnMainThread(time);
904514f5e3Sopenharmony_ci        PrintJitStatsLog();
914514f5e3Sopenharmony_ci    }
924514f5e3Sopenharmony_ci
934514f5e3Sopenharmony_ci    void RecordSpentTimeAndPrintStatsLogInJitThread(int compilerTime, CString methodName, bool isBaselineJit,
944514f5e3Sopenharmony_ci        int mainThreadCompileTime)
954514f5e3Sopenharmony_ci    {
964514f5e3Sopenharmony_ci        SetTotalTimeOnJitThread(compilerTime);
974514f5e3Sopenharmony_ci        if (ReportBlockUIEvent(mainThreadCompileTime)) {
984514f5e3Sopenharmony_ci            SetBlockUIEventInfo(methodName, isBaselineJit, mainThreadCompileTime, compilerTime);
994514f5e3Sopenharmony_ci        }
1004514f5e3Sopenharmony_ci        PrintJitStatsLog();
1014514f5e3Sopenharmony_ci    }
1024514f5e3Sopenharmony_ci
1034514f5e3Sopenharmony_ci    void SetTotalTimeOnMainThread(int time)
1044514f5e3Sopenharmony_ci    {
1054514f5e3Sopenharmony_ci        jitEventParams.totalTimeOnMainThread_.fetch_add(time);
1064514f5e3Sopenharmony_ci    }
1074514f5e3Sopenharmony_ci
1084514f5e3Sopenharmony_ci    int GetTotalTimeOnMainThread() const
1094514f5e3Sopenharmony_ci    {
1104514f5e3Sopenharmony_ci        return jitEventParams.totalTimeOnMainThread_.load() / CONVERT_TO_MILLISECOND;
1114514f5e3Sopenharmony_ci    }
1124514f5e3Sopenharmony_ci
1134514f5e3Sopenharmony_ci    void SetSingleTimeOnMainThread(int time)
1144514f5e3Sopenharmony_ci    {
1154514f5e3Sopenharmony_ci        jitEventParams.singleTimeOnMainThread_.store(time);
1164514f5e3Sopenharmony_ci    }
1174514f5e3Sopenharmony_ci
1184514f5e3Sopenharmony_ci    int GetSingleTimeOnMainThread() const
1194514f5e3Sopenharmony_ci    {
1204514f5e3Sopenharmony_ci        return jitEventParams.singleTimeOnMainThread_.load() / CONVERT_TO_MILLISECOND;
1214514f5e3Sopenharmony_ci    }
1224514f5e3Sopenharmony_ci
1234514f5e3Sopenharmony_ci    void SetTotalTimeOnJitThread(int time)
1244514f5e3Sopenharmony_ci    {
1254514f5e3Sopenharmony_ci        jitEventParams.totalTimeOnJitThread_.fetch_add(time);
1264514f5e3Sopenharmony_ci    }
1274514f5e3Sopenharmony_ci
1284514f5e3Sopenharmony_ci    int GetTotalTimeOnJitThread() const
1294514f5e3Sopenharmony_ci    {
1304514f5e3Sopenharmony_ci        return jitEventParams.totalTimeOnJitThread_.load() / CONVERT_TO_MILLISECOND;
1314514f5e3Sopenharmony_ci    }
1324514f5e3Sopenharmony_ci
1334514f5e3Sopenharmony_ci    void SetSingleTimeOnJitThread(int time)
1344514f5e3Sopenharmony_ci    {
1354514f5e3Sopenharmony_ci        jitEventParams.singleTimeOnJitThread_.store(time);
1364514f5e3Sopenharmony_ci    }
1374514f5e3Sopenharmony_ci
1384514f5e3Sopenharmony_ci    int GetSingleTimeOnJitThread() const
1394514f5e3Sopenharmony_ci    {
1404514f5e3Sopenharmony_ci        return jitEventParams.singleTimeOnJitThread_.load() / CONVERT_TO_MILLISECOND;
1414514f5e3Sopenharmony_ci    }
1424514f5e3Sopenharmony_ci
1434514f5e3Sopenharmony_ci    void SetTriggerCount(bool isBaselineJit)
1444514f5e3Sopenharmony_ci    {
1454514f5e3Sopenharmony_ci        if (isBaselineJit) {
1464514f5e3Sopenharmony_ci            jitEventParams.totalBaselineJitTimes_.fetch_add(1);
1474514f5e3Sopenharmony_ci        } else {
1484514f5e3Sopenharmony_ci            jitEventParams.totalFastoptJitTimes_.fetch_add(1);
1494514f5e3Sopenharmony_ci        }
1504514f5e3Sopenharmony_ci    }
1514514f5e3Sopenharmony_ci
1524514f5e3Sopenharmony_ci    int GetTotalBaselineJitCount() const
1534514f5e3Sopenharmony_ci    {
1544514f5e3Sopenharmony_ci        return jitEventParams.totalBaselineJitTimes_.load();
1554514f5e3Sopenharmony_ci    }
1564514f5e3Sopenharmony_ci
1574514f5e3Sopenharmony_ci    int GetTotalFastoptJitCount() const
1584514f5e3Sopenharmony_ci    {
1594514f5e3Sopenharmony_ci        return jitEventParams.totalFastoptJitTimes_.load();
1604514f5e3Sopenharmony_ci    }
1614514f5e3Sopenharmony_ci
1624514f5e3Sopenharmony_ci    void SetIsBaselineJit(bool isBaselineJit)
1634514f5e3Sopenharmony_ci    {
1644514f5e3Sopenharmony_ci        isBaselineJit_ = isBaselineJit;
1654514f5e3Sopenharmony_ci    }
1664514f5e3Sopenharmony_ci
1674514f5e3Sopenharmony_ci    bool GetIsBaselineJit() const
1684514f5e3Sopenharmony_ci    {
1694514f5e3Sopenharmony_ci        return isBaselineJit_;
1704514f5e3Sopenharmony_ci    }
1714514f5e3Sopenharmony_ci
1724514f5e3Sopenharmony_ci    void SetMethodInfo(CString method)
1734514f5e3Sopenharmony_ci    {
1744514f5e3Sopenharmony_ci        methodInfo_ = method;
1754514f5e3Sopenharmony_ci    }
1764514f5e3Sopenharmony_ci
1774514f5e3Sopenharmony_ci    CString GetMethodInfo() const
1784514f5e3Sopenharmony_ci    {
1794514f5e3Sopenharmony_ci        return methodInfo_;
1804514f5e3Sopenharmony_ci    }
1814514f5e3Sopenharmony_ci
1824514f5e3Sopenharmony_ci    void SetLockHoldingTime(int time)
1834514f5e3Sopenharmony_ci    {
1844514f5e3Sopenharmony_ci        jitEventParams.totalLockHoldingTime_.fetch_add(time);
1854514f5e3Sopenharmony_ci        if (time > jitEventParams.maxLockHoldingTime_.load()) {
1864514f5e3Sopenharmony_ci            jitEventParams.maxLockHoldingTime_.store(time);
1874514f5e3Sopenharmony_ci        }
1884514f5e3Sopenharmony_ci        if (time > HOLD_LOCK_LIMIT) {
1894514f5e3Sopenharmony_ci            jitEventParams.longtimeLockTimes_.fetch_add(1);
1904514f5e3Sopenharmony_ci        }
1914514f5e3Sopenharmony_ci    }
1924514f5e3Sopenharmony_ci
1934514f5e3Sopenharmony_ci    int GetTotalLockHoldingTime() const
1944514f5e3Sopenharmony_ci    {
1954514f5e3Sopenharmony_ci        return jitEventParams.totalLockHoldingTime_.load() / CONVERT_TO_MILLISECOND;
1964514f5e3Sopenharmony_ci    }
1974514f5e3Sopenharmony_ci
1984514f5e3Sopenharmony_ci    int GetMaxLockHoldingTime() const
1994514f5e3Sopenharmony_ci    {
2004514f5e3Sopenharmony_ci        return jitEventParams.maxLockHoldingTime_.load() / CONVERT_TO_MILLISECOND;
2014514f5e3Sopenharmony_ci    }
2024514f5e3Sopenharmony_ci
2034514f5e3Sopenharmony_ci    int GetLongtimeLockCount() const
2044514f5e3Sopenharmony_ci    {
2054514f5e3Sopenharmony_ci        return jitEventParams.longtimeLockTimes_.load();
2064514f5e3Sopenharmony_ci    }
2074514f5e3Sopenharmony_ci
2084514f5e3Sopenharmony_ci    void SetJitDeoptCount()
2094514f5e3Sopenharmony_ci    {
2104514f5e3Sopenharmony_ci        jitEventParams.jitDeoptTimes_.fetch_add(1);
2114514f5e3Sopenharmony_ci    }
2124514f5e3Sopenharmony_ci
2134514f5e3Sopenharmony_ci    int GetJitDeoptCount() const
2144514f5e3Sopenharmony_ci    {
2154514f5e3Sopenharmony_ci        return jitEventParams.jitDeoptTimes_.load();
2164514f5e3Sopenharmony_ci    }
2174514f5e3Sopenharmony_ci
2184514f5e3Sopenharmony_ci    void ResetCompilerTime()
2194514f5e3Sopenharmony_ci    {
2204514f5e3Sopenharmony_ci        jitEventParams.start_ = Clock::now();
2214514f5e3Sopenharmony_ci    }
2224514f5e3Sopenharmony_ci
2234514f5e3Sopenharmony_ci    void ResetBlockUIEventTime()
2244514f5e3Sopenharmony_ci    {
2254514f5e3Sopenharmony_ci        jitEventParams.blockUIEventstart_ = Clock::now();
2264514f5e3Sopenharmony_ci    }
2274514f5e3Sopenharmony_ci
2284514f5e3Sopenharmony_ci    bool ReportBlockUIEvent(int time)
2294514f5e3Sopenharmony_ci    {
2304514f5e3Sopenharmony_ci        return std::chrono::duration_cast<std::chrono::seconds>(Clock::now() -
2314514f5e3Sopenharmony_ci            jitEventParams.blockUIEventstart_).count() >= MIN_SEND_INTERVAL && (time >= MAX_OCCUPY_MAIN_THREAD_TIME);
2324514f5e3Sopenharmony_ci    }
2334514f5e3Sopenharmony_ci
2344514f5e3Sopenharmony_ci    void SetBlockUIEventInfo(CString info, bool isBaselineJit, int mainThreadTime, int jitThreadTime)
2354514f5e3Sopenharmony_ci    {
2364514f5e3Sopenharmony_ci        SetMethodInfo(info);
2374514f5e3Sopenharmony_ci        SetIsBaselineJit(isBaselineJit);
2384514f5e3Sopenharmony_ci        SetSingleTimeOnMainThread(mainThreadTime);
2394514f5e3Sopenharmony_ci        SetSingleTimeOnJitThread(jitThreadTime);
2404514f5e3Sopenharmony_ci        PrintJitBlockUILog();
2414514f5e3Sopenharmony_ci    }
2424514f5e3Sopenharmony_ci
2434514f5e3Sopenharmony_ci    void PrintJitStatsLog();
2444514f5e3Sopenharmony_ci    void PrintJitBlockUILog();
2454514f5e3Sopenharmony_ci
2464514f5e3Sopenharmony_ciprivate:
2474514f5e3Sopenharmony_ci    void OpenLogFile(uint32_t threadId);
2484514f5e3Sopenharmony_ci    void InitializeRecord();
2494514f5e3Sopenharmony_ci    void InitializeBlockUIRecord();
2504514f5e3Sopenharmony_ci    void SendJitStatsEvent() const;
2514514f5e3Sopenharmony_ci    void SendJitBlockUIEvent() const;
2524514f5e3Sopenharmony_ci    bool checkUploadConditions() const
2534514f5e3Sopenharmony_ci    {
2544514f5e3Sopenharmony_ci        return std::chrono::duration_cast<std::chrono::seconds>(Clock::now() - jitEventParams.start_).count() >=
2554514f5e3Sopenharmony_ci            MIN_SEND_INTERVAL && (jitEventParams.totalBaselineJitTimes_.load() +
2564514f5e3Sopenharmony_ci            jitEventParams.totalFastoptJitTimes_.load()) >= MAX_TRIGGER_TIMES;
2574514f5e3Sopenharmony_ci    }
2584514f5e3Sopenharmony_ci
2594514f5e3Sopenharmony_ci    static JitDfx instance;
2604514f5e3Sopenharmony_ci    bool isEnableDump_ {false};
2614514f5e3Sopenharmony_ci    bool isBaselineJit_ {true};
2624514f5e3Sopenharmony_ci    std::map<uint32_t, std::ofstream> logFiles_;
2634514f5e3Sopenharmony_ci    static thread_local uint32_t prefixOffset_;
2644514f5e3Sopenharmony_ci
2654514f5e3Sopenharmony_ci    CString bundleName_ = "";
2664514f5e3Sopenharmony_ci    CString methodInfo_ = "";
2674514f5e3Sopenharmony_ci    ThreadId pidNum_ {0};
2684514f5e3Sopenharmony_ci    JitEventParams jitEventParams;
2694514f5e3Sopenharmony_ci    static constexpr int MAX_TRIGGER_TIMES = 100;
2704514f5e3Sopenharmony_ci    static constexpr int MIN_SEND_INTERVAL = 60; // seconds
2714514f5e3Sopenharmony_ci    static constexpr int HOLD_LOCK_LIMIT = 1000; // microseconds
2724514f5e3Sopenharmony_ci    static constexpr int MAX_OCCUPY_MAIN_THREAD_TIME = 3000; // microseconds
2734514f5e3Sopenharmony_ci    static constexpr int CONVERT_TO_MILLISECOND = 1000;
2744514f5e3Sopenharmony_ci};
2754514f5e3Sopenharmony_ci}  // namespace panda::ecmascript
2764514f5e3Sopenharmony_ci#endif  // ECMASCRIPT_JIT_JIT_DFX_H
277