/* * Copyright 2023 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #define ATRACE_TAG ATRACE_TAG_GRAPHICS #include #include #include #include #ifdef MTK_QUEUE_FENCE_CHECK #define LAST_DURATION_THRESHOLD 3000 #define FENCE_TIME_THRESHOLD 100 #define REPORT_THRESHOLD 10000 #endif #ifdef MTK_SF_MBRAIN_SUPPORT #include #include #if defined(_LP64) #define MBRAIN_FILE_PATH "/system_ext/lib64/libmbrainSDK.so" #else // _LP64 #define MBRAIN_FILE_PATH "/system_ext/lib/libmbrainSDK.so" #endif // _LP64 #endif namespace android::gui { FenceMonitor::FenceMonitor(const char* name) : mName(name), mFencesQueued(0), mFencesSignaled(0) { #ifdef MTK_SF_MBRAIN_SUPPORT if (!initMbrain()) { ALOGD("Can't load libmbrainSDK"); } #endif #ifdef MTK_QUEUE_FENCE_CHECK // Surface may be deleted firest. To avoid reading the wrong fence name, make another backup. memset(mFenceName, '\0', sizeof(mFenceName)); if(name) { std::string tempFenceName = name; size_t n = tempFenceName.length() >= sizeof(mFenceName) ? sizeof(mFenceName) - 1 : tempFenceName.length(); strncpy(mFenceName, tempFenceName.c_str(), n); } #endif std::thread thread(&FenceMonitor::loop, this); pthread_setname_np(thread.native_handle(), mName); thread.detach(); } #ifdef MTK_QUEUE_FENCE_CHECK void FenceMonitor::queueFence(const sp& fence, nsecs_t duration, const char* surface) { #else void FenceMonitor::queueFence(const sp& fence) { #endif char message[64]; std::lock_guard lock(mMutex); if (fence->getSignalTime() != Fence::SIGNAL_TIME_PENDING) { snprintf(message, sizeof(message), "%s fence %u has signaled", mName, mFencesQueued); ATRACE_NAME(message); // Need an increment on both to make the trace number correct. mFencesQueued++; mFencesSignaled++; return; } snprintf(message, sizeof(message), "Trace %s fence %u", mName, mFencesQueued); ATRACE_NAME(message); #ifdef MTK_QUEUE_FENCE_CHECK mLastDuration = duration; memset(mSurfaceName, '\0', sizeof(mSurfaceName)); if(surface) { std::string tempSurfaceName = surface; size_t n = tempSurfaceName.length() >= sizeof(mSurfaceName) ? sizeof(mSurfaceName) - 1 : tempSurfaceName.length(); strncpy(mSurfaceName, tempSurfaceName.c_str(), n); } #endif mQueue.push_back(fence); mCondition.notify_one(); mFencesQueued++; ATRACE_INT(mName, int32_t(mQueue.size())); } void FenceMonitor::loop() { while (true) { threadLoop(); } } void FenceMonitor::threadLoop() { sp fence; uint32_t fenceNum; #ifdef MTK_QUEUE_FENCE_CHECK nsecs_t lastDuration; #endif { std::unique_lock lock(mMutex); while (mQueue.empty()) { mCondition.wait(lock); } fence = mQueue[0]; fenceNum = mFencesSignaled; #ifdef MTK_QUEUE_FENCE_CHECK lastDuration = ns2ms(mLastDuration); #endif } { char message[64]; snprintf(message, sizeof(message), "waiting for %s %u", mName, fenceNum); ATRACE_NAME(message); #ifdef MTK_QUEUE_FENCE_CHECK bool needReport = false; nsecs_t startTime = systemTime(); status_t result = fence->waitForever(message); nsecs_t waitFenceTime = ns2ms(systemTime() - startTime); #ifdef MTK_SF_MBRAIN_SUPPORT if(notifySurfaceFunc && mSurfaceName[0] != '\0' && mFenceName[0] != '\0') { notifySurfaceFunc(mSurfaceName, mFenceName, lastDuration, waitFenceTime); } #endif if ((lastDuration > LAST_DURATION_THRESHOLD || waitFenceTime > FENCE_TIME_THRESHOLD) && ns2ms(systemTime() - mLastReportTime) > REPORT_THRESHOLD) { needReport = true; } if (needReport) { mLastReportTime = systemTime(); std::string msg = "surfaceName: " + std::string(mSurfaceName) + ", fenceName: " + std::string(mFenceName) + ", lastDuration: " + std::to_string(lastDuration) + ", waitFenceTime: " + std::to_string(waitFenceTime); if (!strcmp(mFenceName, "GPU completion")) { msg = "QUEUE_BUFFER_TIMEOUT: " + msg; ALOGE("%s", msg.c_str()); ATRACE_NAME("QUEUE_BUFFER_TIMEOUT"); } else if (!strcmp(mFenceName, "HWC release")) { msg = "DEQUEUE_BUFFER_TIMEOUT: " + msg; ALOGE("%s", msg.c_str()); ATRACE_NAME("DEQUEUE_BUFFER_TIMEOUT"); } } #else status_t result = fence->waitForever(message); #endif if (result != OK) { ALOGE("Error waiting for fence: %d", result); } } { std::lock_guard lock(mMutex); mQueue.pop_front(); mFencesSignaled++; ATRACE_INT(mName, int32_t(mQueue.size())); } } #ifdef MTK_SF_MBRAIN_SUPPORT bool FenceMonitor::initMbrain() { char platform[PROPERTY_VALUE_MAX] = {0}; property_get("ro.board.platform", platform, ""); if (strcmp(platform, "mt6985") == 0 || strcmp(platform, "mt6897") == 0 || strcmp(platform, "mt6989") == 0 || strcmp(platform, "mt6878") == 0) { mMbrainHandle = dlopen(MBRAIN_FILE_PATH, RTLD_NOW | RTLD_LOCAL); if (mMbrainHandle != nullptr) { notifySurfaceFunc = reinterpret_cast(dlsym(mMbrainHandle, "NotifySurfaceInfoHook")); if (notifySurfaceFunc == nullptr) { ALOGE("Can't find NotifySurfaceInfoHook()"); } return true; } } return false; } FenceMonitor::~FenceMonitor() { if (mMbrainHandle != nullptr) { dlclose(mMbrainHandle); } } #endif } // namespace android::gui