/* * 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 #include #include #include 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) { if (!gpuMem->isInitialized()) { ALOGE("Cannot initialize GpuMemTracer before GpuMem"); return; } mGpuMem = gpuMem; perfetto::TracingInitArgs args; args.backends = perfetto::kSystemBackend; perfetto::Tracing::Initialize(args); registerDataSource(); std::thread tracerThread(&GpuMemTracer::threadLoop, this, true); pthread_setname_np(tracerThread.native_handle(), "GpuMemTracerThread"); tracerThread.detach(); tracerThreadCount++; } void GpuMemTracer::initializeForTest(std::shared_ptr gpuMem) { mGpuMem = gpuMem; perfetto::TracingInitArgs args; args.backends = perfetto::kInProcessBackend; perfetto::Tracing::Initialize(args); registerDataSource(); std::thread tracerThread(&GpuMemTracer::threadLoop, this, false); pthread_setname_np(tracerThread.native_handle(), "GpuMemTracerThreadForTest"); tracerThread.detach(); tracerThreadCount++; } // Each tracing session can be used for a single block of Start -> Stop. std::unique_ptr GpuMemTracer::getTracingSessionForTest() { perfetto::TraceConfig cfg; cfg.set_duration_ms(500); cfg.add_buffers()->set_size_kb(1024); auto* ds_cfg = cfg.add_data_sources()->mutable_config(); ds_cfg->set_name(GpuMemTracer::kGpuMemDataSource); auto tracingSession = perfetto::Tracing::NewTrace(perfetto::kInProcessBackend); tracingSession->Setup(cfg); return tracingSession; } void GpuMemTracer::registerDataSource() { perfetto::DataSourceDescriptor dsd; dsd.set_name(kGpuMemDataSource); GpuMemDataSource::Register(dsd); } void GpuMemTracer::threadLoop(bool infiniteLoop) { do { { std::unique_lock lock(GpuMemTracer::sTraceMutex); while (!sTraceStarted) { sCondition.wait(lock); } } traceInitialCounters(); { std::lock_guard lock(GpuMemTracer::sTraceMutex); sTraceStarted = false; } } while (infiniteLoop); // Thread loop is exiting. Reduce the tracerThreadCount to reflect the number of active threads // in the wait loop. tracerThreadCount--; } void GpuMemTracer::traceInitialCounters() { if (!mGpuMem->isInitialized()) { // This should never happen. ALOGE("Cannot trace without GpuMem initialization"); return; } mGpuMem->traverseGpuMemTotals([](int64_t ts, uint32_t gpuId, uint32_t pid, uint64_t size) { GpuMemDataSource::Trace([&](GpuMemDataSource::TraceContext ctx) { auto packet = ctx.NewTracePacket(); packet->set_timestamp_clock_id(perfetto::protos::pbzero::BUILTIN_CLOCK_MONOTONIC); packet->set_timestamp(ts); 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