1/* 2 * Copyright (c) 2021 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 "ecmascript/dfx/cpu_profiler/sampling_processor.h" 17 18#include <csignal> 19#include <sys/time.h> 20#include <unistd.h> 21 22#include "ecmascript/dfx/cpu_profiler/samples_record.h" 23#if defined(ENABLE_FFRT_INTERFACES) 24#include "c/executor_task.h" 25#endif 26 27namespace panda::ecmascript { 28const int USEC_PER_SEC = 1000 * 1000; 29const int NSEC_PER_USEC = 1000; 30SamplingProcessor::~SamplingProcessor() {} 31 32void *SamplingProcessor::Run(void *arg) 33{ 34 LOG_ECMA(INFO) << "SamplingProcessor::Run start"; 35 RunParams params = *reinterpret_cast<RunParams *>(arg); 36 SamplesRecord *generator = params.generator_; 37 uint32_t interval = params.interval_; 38 pthread_t jsThreadId = params.tid_; 39 pthread_t samplingThreadId = pthread_self(); 40 pthread_setname_np(samplingThreadId, "SamplingThread"); 41 uint64_t startTime = generator->GetThreadStartTime(); 42 uint64_t endTime = startTime; 43 generator->AddStartTraceEvent(); 44 while (generator->GetIsStart()) { 45 startTime = GetMicrosecondsTimeStamp(); 46 int64_t ts = static_cast<int64_t>(interval) - static_cast<int64_t>(startTime - endTime); 47 endTime = startTime; 48 if (ts > 0) { 49 usleep(ts); 50 endTime = GetMicrosecondsTimeStamp(); 51 } 52#if defined(ENABLE_FFRT_INTERFACES) 53 // When the ffrt is disabled for js thread, including main thread and worker thread, 54 // then the taskHandle is a nullptr 55 if (params.taskHandle_ != nullptr) { 56 // When the ffrt task is not running on any threads (hang), 57 // the tid returned by ffrt_task_get_tid will be zero 58 pthread_t tid = ffrt_task_get_tid(params.taskHandle_); 59 if (tid != 0 && jsThreadId != tid) { 60 jsThreadId = tid; 61 } 62 if (tid == 0) { 63 // The samplesQueue_ may not be empty due to the call of PostNapiFrame 64 SamplingProcessor::AddSample(generator); 65 generator->AddTraceEvent(false); 66 continue; 67 } 68 } 69#endif // defined(ENABLE_FFRT_INTERFACES) 70 if (pthread_kill(jsThreadId, SIGPROF) != 0) { 71 LOG(ERROR, RUNTIME) << "pthread_kill signal failed"; 72 return nullptr; 73 } 74 if (generator->SemWait(0) != 0) { 75 LOG_ECMA(ERROR) << "sem_[0] wait failed"; 76 return nullptr; 77 } 78 if (generator->GetMethodNodeCount() + generator->GetframeStackLength() >= MAX_NODE_COUNT) { 79 LOG_ECMA(ERROR) << "SamplingProcessor::Run, exceed MAX_NODE_COUNT"; 80 break; 81 } 82 SamplingProcessor::AddSample(generator); 83 generator->AddTraceEvent(false); 84 } 85 generator->SetThreadStopTime(); 86 generator->AddTraceEvent(true); 87 return PostSemAndLogEnd(generator, samplingThreadId); 88} 89 90void SamplingProcessor::AddSample(SamplesRecord *generator) 91{ 92 if (generator->samplesQueue_->IsEmpty()) { 93 uint64_t sampleTimeStamp = SamplingProcessor::GetMicrosecondsTimeStamp(); 94 generator->AddEmptyStackSample(sampleTimeStamp); 95 } else { 96 while (!generator->samplesQueue_->IsEmpty()) { 97 FrameStackAndInfo *frame = generator->samplesQueue_->PopFrame(); 98 generator->AddSample(frame); 99 } 100 } 101} 102 103void *SamplingProcessor::PostSemAndLogEnd(SamplesRecord *generator, pthread_t tid) 104{ 105 pthread_setname_np(tid, "OS_GC_Thread"); 106 if (generator->SemPost(1) != 0) { 107 LOG_ECMA(ERROR) << "sem_[1] post failed, errno = " << errno; 108 return nullptr; 109 } 110 LOG_ECMA(INFO) << "SamplingProcessor::Run end"; 111 return nullptr; 112} 113 114uint64_t SamplingProcessor::GetMicrosecondsTimeStamp() 115{ 116 struct timespec time; 117 clock_gettime(CLOCK_MONOTONIC, &time); 118 return time.tv_sec * USEC_PER_SEC + time.tv_nsec / NSEC_PER_USEC; 119} 120} // namespace panda::ecmascript 121