diff options
| author | 2020-06-18 11:28:12 -0700 | |
|---|---|---|
| committer | 2020-10-23 14:01:20 -0700 | |
| commit | bb66c98ac04dd08dc1d8b718af22a438ab194850 (patch) | |
| tree | 02e940b586549b9cfbcc5eb6d943468464235e3f | |
| parent | a3dae23fbe4c43c9d4754f8c0f24146acdbf91f5 (diff) | |
GpuMem perfetto producer
To overcome the problem of ftrace gpumem events not emitting anything
during MEC (with apps that do launch-time allocations), this change adds
a perfetto producer to emit initial counter values at the start of a
trace, so that the visualization won't so zero usage.
Test: adb shell perfetto --query | grep gpu.
Test: Take a perfetto trace with android.gpumem enabled
Bug: 157142645
Change-Id: I5c8278754549399ffa51e6e6fc2ca69b51976cb2
Merged-In: I5c8278754549399ffa51e6e6fc2ca69b51976cb2
| -rw-r--r-- | services/gpuservice/Android.bp | 1 | ||||
| -rw-r--r-- | services/gpuservice/GpuService.cpp | 10 | ||||
| -rw-r--r-- | services/gpuservice/GpuService.h | 4 | ||||
| -rw-r--r-- | services/gpuservice/gpumem/include/gpumem/GpuMem.h | 23 | ||||
| -rw-r--r-- | services/gpuservice/tracing/Android.bp | 41 | ||||
| -rw-r--r-- | services/gpuservice/tracing/GpuMemTracer.cpp | 101 | ||||
| -rw-r--r-- | services/gpuservice/tracing/include/tracing/GpuMemTracer.h | 60 |
7 files changed, 237 insertions, 3 deletions
diff --git a/services/gpuservice/Android.bp b/services/gpuservice/Android.bp index a75d6db11b..9a9bca1478 100644 --- a/services/gpuservice/Android.bp +++ b/services/gpuservice/Android.bp @@ -22,6 +22,7 @@ cc_defaults { "libcutils", "libgfxstats", "libgpumem", + "libgpumemtracer", "libgraphicsenv", "liblog", "libutils", diff --git a/services/gpuservice/GpuService.cpp b/services/gpuservice/GpuService.cpp index 84ae608148..52d5d4fc46 100644 --- a/services/gpuservice/GpuService.cpp +++ b/services/gpuservice/GpuService.cpp @@ -27,6 +27,7 @@ #include <gpumem/GpuMem.h> #include <gpustats/GpuStats.h> #include <private/android_filesystem_config.h> +#include <tracing/GpuMemTracer.h> #include <utils/String8.h> #include <utils/Trace.h> #include <vkjson.h> @@ -48,8 +49,13 @@ const String16 sDump("android.permission.DUMP"); const char* const GpuService::SERVICE_NAME = "gpu"; GpuService::GpuService() - : mGpuMem(std::make_unique<GpuMem>()), mGpuStats(std::make_unique<GpuStats>()) { - std::thread asyncInitThread([this]() { mGpuMem->initialize(); }); + : mGpuMem(std::make_shared<GpuMem>()), + mGpuStats(std::make_unique<GpuStats>()), + mGpuMemTracer(std::make_unique<GpuMemTracer>()) { + std::thread asyncInitThread([this]() { + mGpuMem->initialize(); + mGpuMemTracer->initialize(mGpuMem); + }); asyncInitThread.detach(); }; diff --git a/services/gpuservice/GpuService.h b/services/gpuservice/GpuService.h index 6797868f00..409084b656 100644 --- a/services/gpuservice/GpuService.h +++ b/services/gpuservice/GpuService.h @@ -30,6 +30,7 @@ namespace android { class GpuMem; class GpuStats; +class GpuMemTracer; class GpuService : public BnGpuService, public PriorityDumper { public: @@ -75,8 +76,9 @@ private: /* * Attributes */ - std::unique_ptr<GpuMem> mGpuMem; + std::shared_ptr<GpuMem> mGpuMem; std::unique_ptr<GpuStats> mGpuStats; + std::unique_ptr<GpuMemTracer> mGpuMemTracer; std::mutex mLock; std::string mDeveloperDriverPath; }; diff --git a/services/gpuservice/gpumem/include/gpumem/GpuMem.h b/services/gpuservice/gpumem/include/gpumem/GpuMem.h index ff8b4bc70a..49a9f95fd6 100644 --- a/services/gpuservice/gpumem/include/gpumem/GpuMem.h +++ b/services/gpuservice/gpumem/include/gpumem/GpuMem.h @@ -31,6 +31,29 @@ public: void initialize(); // dumpsys interface void dump(const Vector<String16>& args, std::string* result); + bool isInitialized() { return mInitialized.load(); } + + // Traverse the map and send each value read back to the callback function. + // Used for tracing. + template <typename lambda> + void traceGpuMemTotals(lambda tracerCallback) { + auto res = mGpuMemTotalMap.getFirstKey(); + if (!res.ok()) return; + uint64_t key = res.value(); + while (true) { + uint32_t gpu_id = key >> 32; + uint32_t pid = key; + + res = mGpuMemTotalMap.readValue(key); + if (!res.ok()) break; + uint64_t size = res.value(); + + tracerCallback(gpu_id, pid, size); + res = mGpuMemTotalMap.getNextKey(key); + if (!res.ok()) break; + key = res.value(); + } + } private: // Friend class for testing. diff --git a/services/gpuservice/tracing/Android.bp b/services/gpuservice/tracing/Android.bp new file mode 100644 index 0000000000..919fed3cec --- /dev/null +++ b/services/gpuservice/tracing/Android.bp @@ -0,0 +1,41 @@ +// Copyright 2020 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. + +cc_library_shared { + name: "libgpumemtracer", + srcs: [ + "GpuMemTracer.cpp", + ], + shared_libs: [ + "libgpumem", + "libbase", + "liblog", + "libutils", + ], + static_libs: [ + "libperfetto_client_experimental", + ], + export_include_dirs: ["include"], + export_static_lib_headers: [ + "libperfetto_client_experimental", + ], + cppflags: [ + "-Wall", + "-Werror", + "-Wformat", + "-Wthread-safety", + "-Wunused", + "-Wunreachable-code", + ], +} diff --git a/services/gpuservice/tracing/GpuMemTracer.cpp b/services/gpuservice/tracing/GpuMemTracer.cpp new file mode 100644 index 0000000000..c9bfa57a30 --- /dev/null +++ b/services/gpuservice/tracing/GpuMemTracer.cpp @@ -0,0 +1,101 @@ +/* + * Copyright 2020 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. + */ + +#undef LOG_TAG +#define LOG_TAG "GpuMemTracer" +#define ATRACE_TAG ATRACE_TAG_GRAPHICS + +#include "tracing/GpuMemTracer.h" + +#include <gpumem/GpuMem.h> +#include <perfetto/trace/android/gpu_mem_event.pbzero.h> +#include <unistd.h> +#include <utils/Timers.h> + +#include <algorithm> +#include <thread> + +PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS(android::GpuMemTracer::GpuMemDataSource); + +namespace android { + +std::mutex GpuMemTracer::sTraceMutex; +std::condition_variable GpuMemTracer::sCondition; +bool GpuMemTracer::sTraceStarted; + +void GpuMemTracer::initialize(std::shared_ptr<GpuMem> gpuMem) { + if (!gpuMem->isInitialized()) { + ALOGE("Cannot initialize GpuMemTracer before GpuMem"); + return; + } + mGpuMem = gpuMem; + perfetto::TracingInitArgs args; + args.backends = perfetto::kSystemBackend; + // TODO(b/160016498): Find a better way to wait for traced + // Sleep for 30 seconds to make sure the data source is registered only + // after traced starts. + sleep(30); + perfetto::Tracing::Initialize(args); + registerDataSource(); + std::thread tracerThread(&GpuMemTracer::threadLoop, this); + pthread_setname_np(tracerThread.native_handle(), "GpuMemTracerThread"); + tracerThread.detach(); +} + +void GpuMemTracer::registerDataSource() { + perfetto::DataSourceDescriptor dsd; + dsd.set_name(kGpuMemDataSource); + GpuMemDataSource::Register(dsd); +} + +void GpuMemTracer::threadLoop() { + while (true) { + { + std::unique_lock<std::mutex> lock(GpuMemTracer::sTraceMutex); + while (!sTraceStarted) { + sCondition.wait(lock); + } + } + traceInitialCounters(); + { + std::lock_guard<std::mutex> lock(GpuMemTracer::sTraceMutex); + sTraceStarted = false; + } + } +} + +void GpuMemTracer::traceInitialCounters() { + if (!mGpuMem->isInitialized()) { + // This should never happen. + ALOGE("Cannot trace without GpuMem initialization"); + return; + } + mGpuMem->traceGpuMemTotals([](uint32_t gpuId, uint32_t pid, uint64_t size) { + GpuMemDataSource::Trace([&](GpuMemDataSource::TraceContext ctx) { + auto packet = ctx.NewTracePacket(); + packet->set_timestamp(systemTime()); + auto* event = packet->set_gpu_mem_total_event(); + event->set_gpu_id(gpuId); + event->set_pid(pid); + event->set_size(size); + }); + }); + // Flush the TraceContext. The last packet in the above loop will go + // missing without this flush. + GpuMemDataSource::Trace([](GpuMemDataSource::TraceContext ctx) { ctx.Flush(); }); +} + +} // namespace android diff --git a/services/gpuservice/tracing/include/tracing/GpuMemTracer.h b/services/gpuservice/tracing/include/tracing/GpuMemTracer.h new file mode 100644 index 0000000000..40deb4c212 --- /dev/null +++ b/services/gpuservice/tracing/include/tracing/GpuMemTracer.h @@ -0,0 +1,60 @@ +/* + * Copyright 2020 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. + */ + +#pragma once + +#include <perfetto/tracing.h> + +#include <mutex> + +namespace android { + +class GpuMem; + +class GpuMemTracer { +public: + class GpuMemDataSource : public perfetto::DataSource<GpuMemDataSource> { + virtual void OnSetup(const SetupArgs&) override{}; + virtual void OnStart(const StartArgs&) override { + std::unique_lock<std::mutex> lock(GpuMemTracer::sTraceMutex); + sTraceStarted = true; + sCondition.notify_all(); + } + virtual void OnStop(const StopArgs&) override{}; + }; + + ~GpuMemTracer() = default; + + // Sets up the perfetto tracing backend and data source. + void initialize(std::shared_ptr<GpuMem>); + // Registers the data source with the perfetto backend. Called as part of initialize() + // and should not be called manually outside of tests. Public to allow for substituting a + // perfetto::kInProcessBackend in tests. + void registerDataSource(); + + static constexpr char kGpuMemDataSource[] = "android.gpu.memory"; + static std::condition_variable sCondition; + static std::mutex sTraceMutex; + static bool sTraceStarted; + +private: + void traceInitialCounters(); + void threadLoop(); + + std::shared_ptr<GpuMem> mGpuMem; +}; + +} // namespace android |