资讯动态

dumpsys meminfo中GL和EGL的统计来源

发布时间:2026/10/28 1:15:22 来源:尧图企业网站定制
GPU memory 信息统计主要追溯Android手机高通和mtk关于EGL和GL的统计差异。1从dumpsys meminfo pid日志输出的地方追溯static jboolean android_os_Debug_getDirtyPagesPid(JNIEnv *env, jobject clazz, jint pid, jobject object) { bool foundSwapPss; stats_t stats[_NUM_HEAP]; memset(stats, 0, sizeof(stats)); if (!load_maps(pid, stats, foundSwapPss)) { return JNI_FALSE; } struct graphics_memory_pss graphics_mem; if (read_memtrack_memory(pid, graphics_mem) 0) { stats[HEAP_GRAPHICS].pss graphics_mem.graphics; stats[HEAP_GRAPHICS].privateDirty graphics_mem.graphics; stats[HEAP_GRAPHICS].rss graphics_mem.graphics; stats[HEAP_GL].pss graphics_mem.gl; stats[HEAP_GL].privateDirty graphics_mem.gl; stats[HEAP_GL].rss graphics_mem.gl; stats[HEAP_OTHER_MEMTRACK].pss graphics_mem.other; stats[HEAP_OTHER_MEMTRACK].privateDirty graphics_mem.other; stats[HEAP_OTHER_MEMTRACK].rss graphics_mem.other; }可以看到graphics_mem是入参和出参应该是在read_memtrack_memory里填充了该结构体。而且该函数也在本文件里static int read_memtrack_memory(int pid, struct graphics_memory_pss* graphics_mem) { struct memtrack_proc* p memtrack_proc_new(); if (p NULL) { ALOGW(failed to create memtrack_proc); return -1; } int err read_memtrack_memory(p, pid, graphics_mem); memtrack_proc_destroy(p); return err; }首先new了一个memtrack_proc的对象并在read_memtrack_memory做实际填充。static int read_memtrack_memory(struct memtrack_proc* p, int pid, struct graphics_memory_pss* graphics_mem) { int err memtrack_proc_get(p, pid); if (err ! 0) { // The memtrack HAL may not be available, do not log to avoid flooding // logcat. return err; } ssize_t pss memtrack_proc_graphics_pss(p); if (pss 0) { ALOGW(failed to get graphics pss: %zd, pss); return pss; } graphics_mem-graphics pss / 1024; pss memtrack_proc_gl_pss(p); if (pss 0) { ALOGW(failed to get gl pss: %zd, pss); return pss; } graphics_mem-gl pss / 1024; pss memtrack_proc_other_pss(p); if (pss 0) { ALOGW(failed to get other pss: %zd, pss); return pss; } graphics_mem-other pss / 1024; return 0; }可以看到graphics_mem的各项都是通过memtrack_proc * p来填充的。所以进一步去找memtrack_proc_new、memtrack_proc_get等的函数。2追溯到libmemtrackmemtrack_proc *memtrack_proc_new(void) { return new memtrack_proc(); } ---------------------------------------------------------------------- int memtrack_proc_get(memtrack_proc *p, pid_t pid) { if (!p) { return -EINVAL; } p-pid pid; for (int i 0; i kMemtrackTypes.size(); i) { int ret memtrack_proc_get_type(p-types[i], pid, kMemtrackTypes[i]); if (ret ! 0) return ret; } return memtrack_proc_sanity_check(p); }可以看到实际上是根据pid去kMemtrackTypes里找到对应的信息填充到memtrack_proc * p。在memtrack_proc_get_type里从memtrack_proxy_service-getMemory里获取得records在for循环里复制到本地也就是t-records里。static int memtrack_proc_get_type(memtrack_proc_type *t, pid_t pid, MemtrackType type) { int err 0; std::shared_ptrIMemtrack memtrack_proxy_service get_memtrack_proxy_service(); if (!memtrack_proxy_service) { return -1; } std::vectorMemtrackRecord records; auto status memtrack_proxy_service-getMemory(pid, type, records); if (!status.isOk()) { return -1; } t-records.resize(records.size()); for (size_t i 0; i records.size(); i) { t-records[i].sizeInBytes records[i].sizeInBytes; t-records[i].flags records[i].flags; } return err; }上面看到主要是通过获取memtrack_proxy_service完成的代码中看到是使用binder通过service_manager获取得对应服务得memtrack_proxy_service。3找高通的memtrack serviceunicorn:/ # ps -A | grep track nobody 1230 1 2143168 2908 binder_wait_for_work 0 S vendor.qti.hardware.memtrack-service找到对应得代码位于pangu_8450-s-combine/device/qcom/vendor-com/memtrack/// Android.bp cc_binary { name: vendor.qti.hardware.memtrack-service, relative_install_path: hw, init_rc: [memtrack_qti.rc], vintf_fragments: [memtrack_qti.xml], vendor: true, cflags: [ -Werror, -DLOG_TAG\memtrack\ ], shared_libs: [ libbase, liblog, libbinder_ndk, android.hardware.memtrack-V1-ndk_platform, ], srcs: [ service.cpp, memtrack.cpp, memtrack_kgsl.cpp, ], }可以看到上面调用的getMemory函数在memtrack.cpp的文件里。ndk::ScopedAStatus Memtrack::getMemory(int pid, MemtrackType type, std::vectorMemtrackRecord* _aidl_return) { if (pid 0) { return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT)); } if (type ! MemtrackType::OTHER type ! MemtrackType::GL type ! MemtrackType::GRAPHICS type ! MemtrackType::MULTIMEDIA type ! MemtrackType::CAMERA) { return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); } _aidl_return-clear(); if(type MemtrackType::GL || type MemtrackType::GRAPHICS) { getKgslMemory(pid, type, _aidl_return); } return ndk::ScopedAStatus::ok(); }在统计GL和GRAPHICSEGL时调用了getKgslMemory。int getKgslMemory(int pid, MemtrackType type, std::vectorMemtrackRecord *records) { char syspath[128]; size_t accounted_size 0; size_t unaccounted_size 0; FILE *fp; int ret; if (type MemtrackType::GL) { snprintf(syspath, sizeof(syspath), /sys/class/kgsl/kgsl/proc/%d/gpumem_mapped, pid); fp fopen(syspath, r); if (fp NULL) return -errno; ret fscanf(fp, %zu, accounted_size); if (ret ! 1) { fclose(fp); return -EINVAL; } fclose(fp); snprintf(syspath, sizeof(syspath), /sys/class/kgsl/kgsl/proc/%d/gpumem_unmapped, pid); fp fopen(syspath, r); if (fp NULL) { return -errno; } ret fscanf(fp, %zu, unaccounted_size); if (ret ! 1) { fclose(fp); return -EINVAL; } fclose(fp); if (accounted_size 0) { MemtrackRecord rec; rec.flags MemtrackRecord::FLAG_SMAPS_ACCOUNTED | MemtrackRecord::FLAG_NONSECURE | MemtrackRecord::FLAG_PRIVATE; rec.sizeInBytes accounted_size; records-push_back(rec); } if (unaccounted_size 0) { MemtrackRecord rec; rec.flags MemtrackRecord::FLAG_SMAPS_UNACCOUNTED | MemtrackRecord::FLAG_NONSECURE | MemtrackRecord::FLAG_PRIVATE; rec.sizeInBytes unaccounted_size; records-push_back(rec); } } else if (type MemtrackType::GRAPHICS) { snprintf(syspath, sizeof(syspath), /sys/class/kgsl/kgsl/proc/%d/imported_mem, pid); fp fopen(syspath, r); if (fp NULL) return -errno; ret fscanf(fp, %zu, unaccounted_size); if (ret ! 1) { fclose(fp); return -EINVAL; } fclose(fp); if (unaccounted_size 0) { MemtrackRecord rec; rec.flags MemtrackRecord::FLAG_SMAPS_UNACCOUNTED | MemtrackRecord::FLAG_NONSECURE | MemtrackRecord::FLAG_PRIVATE; rec.sizeInBytes unaccounted_size; records-push_back(rec); } } if (records !records-empty()) { for (auto v : *records) { ALOGI_IF(DEBUG, getKgslMemory: pid: %d type: %s flags: 0x%x size: %ld bytes, pid, aidl::android::hardware::memtrack::toString(type).c_str(), v.flags, v.sizeInBytes); } } return 0; }可以看到GL有两项分别读的是/sys/class/kgsl/kgsl/proc/%d/gpumem_unmapped和/sys/class/kgsl/kgsl/proc/%d/gpumem_mapped节点。EGL读的是/sys/class/kgsl/kgsl/proc/%d/imported_mem高通的这些节点显示的值需要除以1024就可以和dumpsys meminfo里的值对上。mtk的做了一些转化。4mtk平台memtrack代码相应的在mtk平台的service是android.hardware.memtrack-service.mediatek。具体代码位于vendor/mediatek/proprietary/hardware/memtrack/aidl/default/对应的memtrack.cpp里getMemory代码ndk::ScopedAStatus Memtrack::getMemory(int pid, MemtrackType type, std::vectorMemtrackRecord* _aidl_return) { MemtrackRecord records { .flags 0, .sizeInBytes 0}; int64_t size 0; if (pid 0) { return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_ILLEGAL_ARGUMENT)); } if (type ! MemtrackType::OTHER type ! MemtrackType::GL type ! MemtrackType::GRAPHICS type ! MemtrackType::MULTIMEDIA type ! MemtrackType::CAMERA) { return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_UNSUPPORTED_OPERATION)); } if (_aidl_return NULL) return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_NULL_POINTER)); _aidl_return-clear(); if (type MemtrackType::GL) { if (getMemory_GL(pid,size) false) return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_NONE)); records.flags MemtrackRecord::FLAG_SMAPS_UNACCOUNTED | MemtrackRecord::FLAG_PRIVATE | MemtrackRecord::FLAG_NONSECURE; records.sizeInBytes size; //ALOGD([memtrack] GL mtrack pid%d sizeInBytes%ld,pid ,records.sizeInBytes); } else if (type MemtrackType::GRAPHICS) { if (getMemory_GRAPHICS(pid,size) false) return ndk::ScopedAStatus(AStatus_fromExceptionCode(EX_NONE)); records.flags MemtrackRecord::FLAG_SMAPS_UNACCOUNTED | MemtrackRecord::FLAG_SHARED | MemtrackRecord::FLAG_SYSTEM | MemtrackRecord::FLAG_NONSECURE; records.sizeInBytes size; //ALOGD([memtrack] EGL mtrack pid%d sizeInBytes%ld,pid ,records.sizeInBytes); } _aidl_return-push_back(records); return ndk::ScopedAStatus::ok(); }mtk的获取方式不同获取EGL需要调用getMemory_GRAPHICS函数该函数先会调用getMemory_GRAPHICS_ion但是ion不使用了这个函数的节点没了所以是false因此会调用getMemory_GRAPHICS_dmaheap在该函数里读的是机诶但proc/dma_heap/rss_pid。用法如下// 先向节点写进程号 yunluo:/ # echo pid:1642 proc/dma_heap/rss_pid // 然后cat yunluo:/ # cat proc/dma_heap/rss_pid PID PSS(KB) RSS(KB) 1642 16464 87528 -----EGL memtrack data end --sum: userspace_pss:16464 KB rss:87528 KB --sum: kernel rss: 292696 KB pid table: pid:1642 name:android.youtube可以看到对比高通的实现这部分和高通的节点代表的信息可能不相同。相应的GL读取的是proc/mtk_mali/gpu_memory /proc/pvr/memtrack_stats节点没有。yunluo:/ # cat proc/mtk_mali/gpu_memory mali0 30200 kctx-0x000000006ed0677f 9356 1642 kctx-0x000000005bbd1ddd 1493 30419 kctx-0x000000002c633494 422 31933 kctx-0x00000000cd807c82 188 29166 kctx-0x00000000db2e73cb 2742 28704 kctx-0x000000003475a954 1173 4630 kctx-0x000000005c4e3f07 3170 1275 kctx-0x000000003c1ca778 3069 4541 kctx-0x00000000a0624d47 7370 4282 kctx-0x000000008dc89f66 1217 764看到1642的进程对应的gpu memory是9356页具体需要*PAGE_SIZE换算为37424KB.这两个数值和dumpsys meminfo是对的上的。5结论综上所述各平台厂商只有从hal的service开始出现不同。针对mtk gpu信息不准确的问题需要进一步看GPU驱动对EGL和GL的统计时暴露出来的节点具体代表的含义。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑