14514f5e3Sopenharmony_ci/*
24514f5e3Sopenharmony_ci * Copyright (c) 2021-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_DFX_CPU_PROFILER_CPU_PROFILER_H
174514f5e3Sopenharmony_ci#define ECMASCRIPT_DFX_CPU_PROFILER_CPU_PROFILER_H
184514f5e3Sopenharmony_ci
194514f5e3Sopenharmony_ci#include <csignal>
204514f5e3Sopenharmony_ci
214514f5e3Sopenharmony_ci
224514f5e3Sopenharmony_ci#include "ecmascript/dfx/cpu_profiler/samples_record.h"
234514f5e3Sopenharmony_ci#include "ecmascript/dfx/cpu_profiler/sampling_processor.h"
244514f5e3Sopenharmony_ci#include "ecmascript/debugger/js_debugger_manager.h"
254514f5e3Sopenharmony_ci#include "ecmascript/interpreter/frame_handler.h"
264514f5e3Sopenharmony_ci#include "ecmascript/js_thread.h"
274514f5e3Sopenharmony_ci
284514f5e3Sopenharmony_ci#include "ecmascript/platform/mutex.h"
294514f5e3Sopenharmony_ci
304514f5e3Sopenharmony_cinamespace panda::ecmascript {
314514f5e3Sopenharmony_ciconst int THRESHOLD_GROWTH_FACTORY = 2; // 2:TimeDelta Threshold Growth Factory
324514f5e3Sopenharmony_ciconst int THRESHOLD_FIXED_INCREMENT = 2000; // 2000:TimeDelta Threshold Fixed Increment
334514f5e3Sopenharmony_ciusing JSTaggedType = uint64_t;
344514f5e3Sopenharmony_ciusing JsDebuggerManager = tooling::JsDebuggerManager;
354514f5e3Sopenharmony_ciclass SamplesRecord;
364514f5e3Sopenharmony_ci
374514f5e3Sopenharmony_cistruct TaskInfo {
384514f5e3Sopenharmony_ci    const EcmaVM *vm_ { nullptr };
394514f5e3Sopenharmony_ci    void *taskHandle_ { nullptr };
404514f5e3Sopenharmony_ci};
414514f5e3Sopenharmony_ci
424514f5e3Sopenharmony_ciclass GcStateScope {
434514f5e3Sopenharmony_cipublic:
444514f5e3Sopenharmony_ci    inline explicit GcStateScope(JSThread *thread)
454514f5e3Sopenharmony_ci    {
464514f5e3Sopenharmony_ci        thread_ = thread;
474514f5e3Sopenharmony_ci        thread_->SetGcState(true);
484514f5e3Sopenharmony_ci    }
494514f5e3Sopenharmony_ci
504514f5e3Sopenharmony_ci    inline ~GcStateScope()
514514f5e3Sopenharmony_ci    {
524514f5e3Sopenharmony_ci        thread_->SetGcState(false);
534514f5e3Sopenharmony_ci    }
544514f5e3Sopenharmony_ciprivate:
554514f5e3Sopenharmony_ci    JSThread *thread_ = nullptr;
564514f5e3Sopenharmony_ci};
574514f5e3Sopenharmony_ci
584514f5e3Sopenharmony_ciclass SignalStateScope {
594514f5e3Sopenharmony_cipublic:
604514f5e3Sopenharmony_ci    inline explicit SignalStateScope(JsDebuggerManager *jsDebuggerManager)
614514f5e3Sopenharmony_ci    {
624514f5e3Sopenharmony_ci        jsDebuggerManager_ = jsDebuggerManager;
634514f5e3Sopenharmony_ci        jsDebuggerManager_->SetSignalState(true);
644514f5e3Sopenharmony_ci    }
654514f5e3Sopenharmony_ci
664514f5e3Sopenharmony_ci    inline ~SignalStateScope()
674514f5e3Sopenharmony_ci    {
684514f5e3Sopenharmony_ci        jsDebuggerManager_->SetSignalState(false);
694514f5e3Sopenharmony_ci    }
704514f5e3Sopenharmony_ciprivate:
714514f5e3Sopenharmony_ci    JsDebuggerManager *jsDebuggerManager_ = nullptr;
724514f5e3Sopenharmony_ci};
734514f5e3Sopenharmony_ci
744514f5e3Sopenharmony_ciclass RuntimeStateScope {
754514f5e3Sopenharmony_cipublic:
764514f5e3Sopenharmony_ci    inline explicit RuntimeStateScope(JSThread *thread)
774514f5e3Sopenharmony_ci    {
784514f5e3Sopenharmony_ci        thread_ = thread;
794514f5e3Sopenharmony_ci        oldState_ = thread_->GetRuntimeState();
804514f5e3Sopenharmony_ci        thread_->SetRuntimeState(true);
814514f5e3Sopenharmony_ci    }
824514f5e3Sopenharmony_ci
834514f5e3Sopenharmony_ci    inline ~RuntimeStateScope()
844514f5e3Sopenharmony_ci    {
854514f5e3Sopenharmony_ci        thread_->SetRuntimeState(oldState_);
864514f5e3Sopenharmony_ci    }
874514f5e3Sopenharmony_ciprivate:
884514f5e3Sopenharmony_ci    bool oldState_ = false;
894514f5e3Sopenharmony_ci    JSThread *thread_ = nullptr;
904514f5e3Sopenharmony_ci};
914514f5e3Sopenharmony_ci
924514f5e3Sopenharmony_ciclass CpuProfiler {
934514f5e3Sopenharmony_cipublic:
944514f5e3Sopenharmony_ci    static const int CPUPROFILER_DEFAULT_INTERVAL = 500; // 500:Default Sampling interval 500 microseconds
954514f5e3Sopenharmony_ci    static const int INTERVAL_OF_ACTIVE_SAMPLING = 300; // 300:interval of active sampling
964514f5e3Sopenharmony_ci    static const int INTERVAL_OF_INNER_START = 100; // 100:interval of inner start(stake in runtime) sampling
974514f5e3Sopenharmony_ci
984514f5e3Sopenharmony_ci    bool InHeaderOrTail(uint64_t pc, uint64_t entryBegin, uint64_t entryDuration, uint64_t headerSize,
994514f5e3Sopenharmony_ci                        uint64_t tailSize) const;
1004514f5e3Sopenharmony_ci    bool IsEntryFrameHeaderOrTail(JSThread *thread, uint64_t pc) const;
1014514f5e3Sopenharmony_ci    bool GetStackBeforeCallNapi(JSThread *thread);
1024514f5e3Sopenharmony_ci    void GetStackAfterCallNapi(JSThread *thread);
1034514f5e3Sopenharmony_ci    bool GetStackCallNapi(JSThread *thread, bool beforeCallNapi);
1044514f5e3Sopenharmony_ci#if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
1054514f5e3Sopenharmony_ci    // siginfo_t may be undefined on some platforms
1064514f5e3Sopenharmony_ci    static void GetStackSignalHandler(int signal, siginfo_t *siginfo, void *context);
1074514f5e3Sopenharmony_ci#endif
1084514f5e3Sopenharmony_ci
1094514f5e3Sopenharmony_ci    bool StartCpuProfilerForInfo();
1104514f5e3Sopenharmony_ci    bool StopCpuProfilerForInfo(std::unique_ptr<struct ProfileInfo> &profileInfo);
1114514f5e3Sopenharmony_ci    bool StartCpuProfilerForFile(const std::string &fileName);
1124514f5e3Sopenharmony_ci    bool StopCpuProfilerForFile();
1134514f5e3Sopenharmony_ci    void SetCpuSamplingInterval(int interval);
1144514f5e3Sopenharmony_ci    void SetBuildNapiStack(bool flag);
1154514f5e3Sopenharmony_ci    bool GetBuildNapiStack();
1164514f5e3Sopenharmony_ci    bool GetOutToFile();
1174514f5e3Sopenharmony_ci    explicit CpuProfiler(const EcmaVM *vm, const int interval = CPUPROFILER_DEFAULT_INTERVAL);
1184514f5e3Sopenharmony_ci    virtual ~CpuProfiler();
1194514f5e3Sopenharmony_ci
1204514f5e3Sopenharmony_ci    static CMap<pthread_t, struct TaskInfo> profilerMap_;
1214514f5e3Sopenharmony_ci    static EcmaVM *GetVmbyTid(pthread_t tid);
1224514f5e3Sopenharmony_ciprivate:
1234514f5e3Sopenharmony_ci    static Mutex synchronizationMutex_;
1244514f5e3Sopenharmony_ci
1254514f5e3Sopenharmony_ci    void GetStack(FrameIterator &it);
1264514f5e3Sopenharmony_ci    static uint64_t GetPcFromContext(void *context);
1274514f5e3Sopenharmony_ci    bool IsAddrAtStubOrAot(uint64_t pc) const;
1284514f5e3Sopenharmony_ci    bool CheckFileName(const std::string &fileName, std::string &absoluteFilePath) const;
1294514f5e3Sopenharmony_ci    bool RegisterGetStackSignal();
1304514f5e3Sopenharmony_ci
1314514f5e3Sopenharmony_ci    bool isProfiling_ = false;
1324514f5e3Sopenharmony_ci    bool outToFile_ = false;
1334514f5e3Sopenharmony_ci    std::string fileName_ = "";
1344514f5e3Sopenharmony_ci    SamplesRecord *generator_ = nullptr;
1354514f5e3Sopenharmony_ci    pthread_t tid_ = 0;
1364514f5e3Sopenharmony_ci    const EcmaVM *vm_ = nullptr;
1374514f5e3Sopenharmony_ci    uint32_t interval_ = 0;
1384514f5e3Sopenharmony_ci    uint64_t beforeCallNapiTimeStamp_ = 0;
1394514f5e3Sopenharmony_ci    std::atomic_bool isBuildNapiStack_ {false};
1404514f5e3Sopenharmony_ci    bool enableVMTag_ {false};
1414514f5e3Sopenharmony_ci    RunParams *params_ = nullptr;
1424514f5e3Sopenharmony_ci
1434514f5e3Sopenharmony_ci    friend class CpuProfilerFriendTest;
1444514f5e3Sopenharmony_ci};
1454514f5e3Sopenharmony_ci
1464514f5e3Sopenharmony_ciclass CallNapiScope {
1474514f5e3Sopenharmony_cipublic:
1484514f5e3Sopenharmony_ci    inline explicit CallNapiScope(CpuProfiler *profiler)
1494514f5e3Sopenharmony_ci    {
1504514f5e3Sopenharmony_ci        profiler_ = profiler;
1514514f5e3Sopenharmony_ci        profiler_->SetBuildNapiStack(true);
1524514f5e3Sopenharmony_ci    }
1534514f5e3Sopenharmony_ci
1544514f5e3Sopenharmony_ci    inline ~CallNapiScope()
1554514f5e3Sopenharmony_ci    {
1564514f5e3Sopenharmony_ci        profiler_->SetBuildNapiStack(false);
1574514f5e3Sopenharmony_ci    }
1584514f5e3Sopenharmony_ciprivate:
1594514f5e3Sopenharmony_ci    CpuProfiler *profiler_ {nullptr};
1604514f5e3Sopenharmony_ci};
1614514f5e3Sopenharmony_ci} // namespace panda::ecmascript
1624514f5e3Sopenharmony_ci#endif // ECMASCRIPT_DFX_CPU_PROFILER_CPU_PROFILER_H