From 8dd1136bfd5a9dc403dc24839de2cbd1fe5cd273 Mon Sep 17 00:00:00 2001 From: Pierre-Hugues Husson Date: Sat, 25 Nov 2023 08:15:28 -0500 Subject: [PATCH 2/3] Add MTK GED KPI support to fix broken Mediatek gpufreq Mediatek GPU scheduler likes to have the timestamps of the frames to be able to adjust DVFS. Technically this isn't completely needed, because it looks like DVFS can work once we started triggering /proc/ged. But now that the work is done, let's do it completely. In benchmarks on Poco X4 GT, before this patch result is 1500, after is 5700. If we disable the patch after enabling it without rebooting, it goes to 5400. So looks like GED KPI thingy does try to do a bit more than just standard DVFS. Thanks @sarthakroy2002 for the help and support (other people helped as well) Change-Id: Ic29a231ea8651efd598083611197aaa9e3c1fbbe --- libs/gui/Surface.cpp | 202 +++++++++++++++++++++++++++++++++ libs/gui/include/gui/Surface.h | 3 + 2 files changed, 205 insertions(+) diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp index 66e7ddd..32070fa 100644 --- a/libs/gui/Surface.cpp +++ b/libs/gui/Surface.cpp @@ -26,6 +26,9 @@ #include #include #include +#include +#include +#include #include @@ -50,6 +53,9 @@ #include #include #include +#include + +#include #include @@ -76,6 +82,37 @@ bool isInterceptorRegistrationOp(int op) { } } // namespace + // +#define GED_MAGIC 'g' +#define GED_BRIDGE_COMMAND_GPU_TIMESTAMP 103 +#define GED_IOWR(INDEX) _IOWR(GED_MAGIC, INDEX, GED_BRIDGE_PACKAGE) +#define GED_BRIDGE_IO_GPU_TIMESTAMP \ + GED_IOWR(GED_BRIDGE_COMMAND_GPU_TIMESTAMP) +typedef struct _GED_BRIDGE_PACKAGE { + unsigned int ui32FunctionID; + int i32Size; + void *pvParamIn; + int i32InBufferSize; + void *pvParamOut; + int i32OutBufferSize; +} GED_BRIDGE_PACKAGE; + +struct GED_BRIDGE_IN_GPU_TIMESTAMP { + int pid; + uint64_t ullWnd; + int32_t i32FrameID; + int fence_fd; + int QedBuffer_length; + int isSF; +}; + +struct GED_BRIDGE_OUT_GPU_TIMESTAMP { + int eError; + int is_ged_kpi_enabled; +}; + +static int doMtkGedKpi = -1; +static int ged_fd = -1; #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) Surface::ProducerDeathListenerProxy::ProducerDeathListenerProxy(wp surfaceListener) @@ -147,6 +184,47 @@ Surface::Surface(const sp& bufferProducer, bool controll mSwapIntervalZero = false; mMaxBufferCount = NUM_BUFFER_SLOTS; mSurfaceControlHandle = surfaceControlHandle; + + if (doMtkGedKpi == -1) { + doMtkGedKpi = android::base::GetIntProperty("persist.sys.phh.mtk_ged_kpi", 0); + } + + if (ged_fd == -1 && doMtkGedKpi == 1) { + ALOGE("Opening ged"); + ged_fd = open("/proc/ged", O_RDONLY); + ALOGE("Opening ged ret = %d", ged_fd); + { + struct GED_BRIDGE_IN_GPU_TIMESTAMP in = { + .pid = 0, + //.ullWnd = (uint64_t)(intptr_t)this, + .ullWnd = 0, + .i32FrameID = 0, + .fence_fd = 0, + .isSF = 0, + .QedBuffer_length = 0, + }; + struct GED_BRIDGE_OUT_GPU_TIMESTAMP out; + memset(&in, 0, sizeof(in)); + GED_BRIDGE_PACKAGE package = { + .ui32FunctionID = GED_BRIDGE_IO_GPU_TIMESTAMP, + .i32Size = sizeof(GED_BRIDGE_PACKAGE), + .pvParamIn = &in, + .i32InBufferSize = sizeof(in), + .pvParamOut = &out, + .i32OutBufferSize = sizeof(out), + }; + if (ged_fd >= 0) { + int ret = ioctl(ged_fd, GED_BRIDGE_IO_GPU_TIMESTAMP, &package); + ALOGE("First null timestamp ioctl returned %d %d %d", ret, out.eError, out.is_ged_kpi_enabled); + if (out.is_ged_kpi_enabled != 1) { + ALOGE("is_ged_kpi_enabled reported disabled"); + doMtkGedKpi = 0; + } + } else { + ALOGE("No /proc/ged"); + } + } + } } Surface::~Surface() { @@ -699,6 +777,36 @@ int Surface::dequeueBuffer(android_native_buffer_t** buffer, int* fenceFd) { } } + if (mGraphicBufferProducer != nullptr && ged_fd >= 0) { + uint64_t uniqueId; + mGraphicBufferProducer->getUniqueId(&uniqueId); + + const int32_t dupFenceFd = fence->isValid() ? fence->dup() : -1; + + struct GED_BRIDGE_IN_GPU_TIMESTAMP in = { + .pid = mPid, + .ullWnd = uniqueId, + .i32FrameID = static_cast(reinterpret_cast(gbuf->handle)) & 0x3fffffff, + .fence_fd = dupFenceFd, + .isSF = mIsSurfaceFlinger ? 1 : 0, + .QedBuffer_length = -2, + }; + struct GED_BRIDGE_OUT_GPU_TIMESTAMP out; + memset(&out, 0, sizeof(out)); + GED_BRIDGE_PACKAGE package = { + .ui32FunctionID = GED_BRIDGE_IO_GPU_TIMESTAMP, + .i32Size = sizeof(GED_BRIDGE_PACKAGE), + .pvParamIn = &in, + .i32InBufferSize = sizeof(in), + .pvParamOut = &out, + .i32OutBufferSize = sizeof(out), + }; + + int ret = ioctl(ged_fd, GED_BRIDGE_IO_GPU_TIMESTAMP, &package); + ALOGV("GPU timestamp ioctl returned %d %d %d %d", ret, out.eError, out.is_ged_kpi_enabled, in.i32FrameID); + + close(dupFenceFd); + } if (fence->isValid()) { *fenceFd = fence->dup(); if (*fenceFd == -1) { @@ -1187,6 +1295,60 @@ void Surface::onBufferQueuedLocked(int slot, sp fence, } mQueueBufferCondition.broadcast(); + if (mGraphicBufferProducer != nullptr && ged_fd >= 0) { + sp& gbuf(mSlots[slot].buffer); + uint64_t uniqueId; + mGraphicBufferProducer->getUniqueId(&uniqueId); + + const int32_t dupFenceFd = fence->isValid() ? fence->dup() : -1; + // onQueue + { + struct GED_BRIDGE_IN_GPU_TIMESTAMP in = { + .pid = mPid, + .ullWnd = uniqueId, + .i32FrameID = static_cast(reinterpret_cast(gbuf->handle)) & 0x3fffffff, + .fence_fd = dupFenceFd, + .isSF = mIsSurfaceFlinger ? 1 : 0, + .QedBuffer_length = static_cast(output.numPendingBuffers), + }; + struct GED_BRIDGE_OUT_GPU_TIMESTAMP out; + memset(&out, 0, sizeof(out)); + GED_BRIDGE_PACKAGE package = { + .ui32FunctionID = GED_BRIDGE_IO_GPU_TIMESTAMP, + .i32Size = sizeof(GED_BRIDGE_PACKAGE), + .pvParamIn = &in, + .i32InBufferSize = sizeof(in), + .pvParamOut = &out, + .i32OutBufferSize = sizeof(out), + }; + int ret = ioctl(ged_fd, GED_BRIDGE_IO_GPU_TIMESTAMP, &package); + ALOGV("GPU timestamp ioctl returned %d %d %d", ret, out.eError, in.i32FrameID); + } + // acquire + { + struct GED_BRIDGE_IN_GPU_TIMESTAMP in = { + .pid = mPid, + .isSF = mIsSurfaceFlinger ? 1 : 0, + .ullWnd = uniqueId, + .i32FrameID = static_cast(reinterpret_cast(gbuf->handle)) & 0x3fffffff, + .fence_fd = dupFenceFd, + .QedBuffer_length = -1, + }; + struct GED_BRIDGE_OUT_GPU_TIMESTAMP out; + memset(&out, 0, sizeof(out)); + GED_BRIDGE_PACKAGE package = { + .ui32FunctionID = GED_BRIDGE_IO_GPU_TIMESTAMP, + .i32Size = sizeof(GED_BRIDGE_PACKAGE), + .pvParamIn = &in, + .i32InBufferSize = sizeof(in), + .pvParamOut = &in, + .i32OutBufferSize = sizeof(out), + }; + int ret = ioctl(ged_fd, GED_BRIDGE_IO_GPU_TIMESTAMP, &package); + ALOGV("GPU timestamp ioctl returned %d %d %d", ret, out.eError, in.i32FrameID); + } + close(dupFenceFd); + } if (CC_UNLIKELY(atrace_is_tag_enabled(ATRACE_TAG_GRAPHICS))) { static gui::FenceMonitor gpuCompletionThread("GPU completion"); @@ -2111,6 +2273,46 @@ int Surface::connect(int api, const sp& listener, bool reportBu } #endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_PLATFORM_API_IMPROVEMENTS) } + + // For MTK GED KPI, we need to grab the Surface owner's PID + // and also know whether that owner is surfaceflinger + if (api == NATIVE_WINDOW_API_EGL && ged_fd >= 0) { + IPCThreadState *ipc = IPCThreadState::selfOrNull(); + const sp& token = IInterface::asBinder(mGraphicBufferProducer); + mPid = (token != NULL && NULL != token->localBinder()) + ? getpid() + : (ipc != nullptr)?ipc->getCallingPid():-1; + + // We've got caller PID. Now checking whether it is surfaceflinger + char cmdline[128]; + char path[128]; + snprintf(path, sizeof(path)-1, "/proc/%d/cmdline", mPid); + int fd = open(path, O_RDONLY); + read(fd, cmdline, sizeof(cmdline)-1); + // Normally cmdline is already \0-separated, but well + for(unsigned i=0; i mDequeuedSlots; + + pid_t mPid; + bool mIsSurfaceFlinger; }; } // namespace android -- 2.44.0