Merge "More benchmark tweaks" into sc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
5c681088e4
@@ -86,12 +86,9 @@ void SkiaMemoryTracer::processElement() {
|
||||
}
|
||||
}
|
||||
|
||||
// if we don't have a resource name then we don't know how to label the
|
||||
// data and should abort.
|
||||
// if we don't have a pretty name then use the dumpName
|
||||
if (resourceName == nullptr) {
|
||||
mCurrentElement.clear();
|
||||
mCurrentValues.clear();
|
||||
return;
|
||||
resourceName = mCurrentElement.c_str();
|
||||
}
|
||||
|
||||
auto result = mResults.find(resourceName);
|
||||
@@ -157,6 +154,14 @@ void SkiaMemoryTracer::logOutput(String8& log) {
|
||||
}
|
||||
}
|
||||
|
||||
size_t SkiaMemoryTracer::total() {
|
||||
processElement();
|
||||
if (!strcmp("bytes", mTotalSize.units)) {
|
||||
return mTotalSize.value;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SkiaMemoryTracer::logTotals(String8& log) {
|
||||
TraceValue total = convertUnits(mTotalSize);
|
||||
TraceValue purgeable = convertUnits(mPurgeableSize);
|
||||
|
||||
@@ -37,6 +37,7 @@ public:
|
||||
bool hasOutput();
|
||||
void logOutput(String8& log);
|
||||
void logTotals(String8& log);
|
||||
size_t total();
|
||||
|
||||
void dumpNumericValue(const char* dumpName, const char* valueName, const char* units,
|
||||
uint64_t value) override;
|
||||
|
||||
@@ -130,27 +130,43 @@ void CacheManager::trimStaleResources() {
|
||||
mGrContext->purgeResourcesNotUsedInMs(std::chrono::seconds(30));
|
||||
}
|
||||
|
||||
void CacheManager::getMemoryUsage(size_t* cpuUsage, size_t* gpuUsage) {
|
||||
*cpuUsage = 0;
|
||||
*gpuUsage = 0;
|
||||
if (!mGrContext) {
|
||||
return;
|
||||
}
|
||||
|
||||
skiapipeline::SkiaMemoryTracer cpuTracer("category", true);
|
||||
SkGraphics::DumpMemoryStatistics(&cpuTracer);
|
||||
*cpuUsage += cpuTracer.total();
|
||||
|
||||
skiapipeline::SkiaMemoryTracer gpuTracer("category", true);
|
||||
mGrContext->dumpMemoryStatistics(&gpuTracer);
|
||||
*gpuUsage += gpuTracer.total();
|
||||
}
|
||||
|
||||
void CacheManager::dumpMemoryUsage(String8& log, const RenderState* renderState) {
|
||||
if (!mGrContext) {
|
||||
log.appendFormat("No valid cache instance.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
log.appendFormat("Font Cache (CPU):\n");
|
||||
log.appendFormat(" Size: %.2f kB \n", SkGraphics::GetFontCacheUsed() / 1024.0f);
|
||||
log.appendFormat(" Glyph Count: %d \n", SkGraphics::GetFontCacheCountUsed());
|
||||
|
||||
std::vector<skiapipeline::ResourcePair> cpuResourceMap = {
|
||||
{"skia/sk_resource_cache/bitmap_", "Bitmaps"},
|
||||
{"skia/sk_resource_cache/rrect-blur_", "Masks"},
|
||||
{"skia/sk_resource_cache/rects-blur_", "Masks"},
|
||||
{"skia/sk_resource_cache/tessellated", "Shadows"},
|
||||
{"skia/sk_glyph_cache", "Glyph Cache"},
|
||||
};
|
||||
skiapipeline::SkiaMemoryTracer cpuTracer(cpuResourceMap, false);
|
||||
SkGraphics::DumpMemoryStatistics(&cpuTracer);
|
||||
if (cpuTracer.hasOutput()) {
|
||||
log.appendFormat("CPU Caches:\n");
|
||||
cpuTracer.logOutput(log);
|
||||
log.appendFormat(" Glyph Count: %d \n", SkGraphics::GetFontCacheCountUsed());
|
||||
log.appendFormat("Total CPU memory usage:\n");
|
||||
cpuTracer.logTotals(log);
|
||||
}
|
||||
|
||||
skiapipeline::SkiaMemoryTracer gpuTracer("category", true);
|
||||
|
||||
@@ -47,6 +47,7 @@ public:
|
||||
void trimMemory(TrimMemoryMode mode);
|
||||
void trimStaleResources();
|
||||
void dumpMemoryUsage(String8& log, const RenderState* renderState = nullptr);
|
||||
void getMemoryUsage(size_t* cpuUsage, size_t* gpuUsage);
|
||||
|
||||
size_t getCacheSize() const { return mMaxResourceBytes; }
|
||||
size_t getBackgroundCacheSize() const { return mBackgroundResourceBytes; }
|
||||
|
||||
@@ -195,6 +195,17 @@ void RenderProxy::trimMemory(int level) {
|
||||
}
|
||||
}
|
||||
|
||||
void RenderProxy::purgeCaches() {
|
||||
if (RenderThread::hasInstance()) {
|
||||
RenderThread& thread = RenderThread::getInstance();
|
||||
thread.queue().post([&thread]() {
|
||||
if (thread.getGrContext()) {
|
||||
thread.cacheManager().trimMemory(CacheManager::TrimMemoryMode::Complete);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void RenderProxy::overrideProperty(const char* name, const char* value) {
|
||||
// expensive, but block here since name/value pointers owned by caller
|
||||
RenderThread::getInstance().queue().runSync(
|
||||
@@ -256,6 +267,13 @@ void RenderProxy::dumpGraphicsMemory(int fd, bool includeProfileData) {
|
||||
}
|
||||
}
|
||||
|
||||
void RenderProxy::getMemoryUsage(size_t* cpuUsage, size_t* gpuUsage) {
|
||||
if (RenderThread::hasInstance()) {
|
||||
auto& thread = RenderThread::getInstance();
|
||||
thread.queue().runSync([&]() { thread.getMemoryUsage(cpuUsage, gpuUsage); });
|
||||
}
|
||||
}
|
||||
|
||||
void RenderProxy::setProcessStatsBuffer(int fd) {
|
||||
auto& rt = RenderThread::getInstance();
|
||||
rt.queue().post([&rt, fd = dup(fd)]() {
|
||||
|
||||
@@ -98,6 +98,7 @@ public:
|
||||
|
||||
void destroyHardwareResources();
|
||||
static void trimMemory(int level);
|
||||
static void purgeCaches();
|
||||
static void overrideProperty(const char* name, const char* value);
|
||||
|
||||
void fence();
|
||||
@@ -110,6 +111,7 @@ public:
|
||||
void resetProfileInfo();
|
||||
uint32_t frameTimePercentile(int p);
|
||||
static void dumpGraphicsMemory(int fd, bool includeProfileData = true);
|
||||
static void getMemoryUsage(size_t* cpuUsage, size_t* gpuUsage);
|
||||
|
||||
static void rotateProcessStatsBuffer();
|
||||
static void setProcessStatsBuffer(int fd);
|
||||
|
||||
@@ -323,6 +323,10 @@ void RenderThread::dumpGraphicsMemory(int fd, bool includeProfileData) {
|
||||
dprintf(fd, "\nPipeline=%s\n%s\n", pipelineToString(), cachesOutput.string());
|
||||
}
|
||||
|
||||
void RenderThread::getMemoryUsage(size_t* cpuUsage, size_t* gpuUsage) {
|
||||
mCacheManager->getMemoryUsage(cpuUsage, gpuUsage);
|
||||
}
|
||||
|
||||
Readback& RenderThread::readback() {
|
||||
if (!mReadback) {
|
||||
mReadback = new Readback(*this);
|
||||
|
||||
@@ -151,6 +151,7 @@ public:
|
||||
|
||||
sk_sp<Bitmap> allocateHardwareBitmap(SkBitmap& skBitmap);
|
||||
void dumpGraphicsMemory(int fd, bool includeProfileData);
|
||||
void getMemoryUsage(size_t* cpuUsage, size_t* gpuUsage);
|
||||
|
||||
void requireGlContext();
|
||||
void requireVkContext();
|
||||
|
||||
@@ -40,6 +40,7 @@ public:
|
||||
int reportFrametimeWeight = 0;
|
||||
bool renderOffscreen = true;
|
||||
bool reportGpuMemoryUsage = false;
|
||||
bool reportGpuMemoryUsageVerbose = false;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
|
||||
@@ -28,6 +28,20 @@
|
||||
#include <log/log.h>
|
||||
#include <ui/PixelFormat.h>
|
||||
|
||||
// These are unstable internal APIs in google-benchmark. We should just implement our own variant
|
||||
// of these instead, but this was quicker. Disabled-by-default to avoid any breakages when
|
||||
// google-benchmark updates if they change anything
|
||||
#if 0
|
||||
#define USE_SKETCHY_INTERNAL_STATS
|
||||
namespace benchmark {
|
||||
std::vector<BenchmarkReporter::Run> ComputeStats(
|
||||
const std::vector<BenchmarkReporter::Run> &reports);
|
||||
double StatisticsMean(const std::vector<double>& v);
|
||||
double StatisticsMedian(const std::vector<double>& v);
|
||||
double StatisticsStdDev(const std::vector<double>& v);
|
||||
}
|
||||
#endif
|
||||
|
||||
using namespace android;
|
||||
using namespace android::uirenderer;
|
||||
using namespace android::uirenderer::renderthread;
|
||||
@@ -66,6 +80,7 @@ using BenchmarkResults = std::vector<benchmark::BenchmarkReporter::Run>;
|
||||
|
||||
void outputBenchmarkReport(const TestScene::Info& info, const TestScene::Options& opts,
|
||||
double durationInS, int repetationIndex, BenchmarkResults* reports) {
|
||||
using namespace benchmark;
|
||||
benchmark::BenchmarkReporter::Run report;
|
||||
report.repetitions = opts.repeatCount;
|
||||
report.repetition_index = repetationIndex;
|
||||
@@ -73,12 +88,22 @@ void outputBenchmarkReport(const TestScene::Info& info, const TestScene::Options
|
||||
report.iterations = static_cast<int64_t>(opts.frameCount);
|
||||
report.real_accumulated_time = durationInS;
|
||||
report.cpu_accumulated_time = durationInS;
|
||||
report.counters["items_per_second"] = opts.frameCount / durationInS;
|
||||
report.counters["FPS"] = opts.frameCount / durationInS;
|
||||
if (opts.reportGpuMemoryUsage) {
|
||||
size_t cpuUsage, gpuUsage;
|
||||
RenderProxy::getMemoryUsage(&cpuUsage, &gpuUsage);
|
||||
report.counters["Rendering RAM"] = Counter{static_cast<double>(cpuUsage + gpuUsage),
|
||||
Counter::kDefaults, Counter::kIs1024};
|
||||
}
|
||||
reports->push_back(report);
|
||||
}
|
||||
|
||||
static void doRun(const TestScene::Info& info, const TestScene::Options& opts, int repetitionIndex,
|
||||
BenchmarkResults* reports) {
|
||||
if (opts.reportGpuMemoryUsage) {
|
||||
// If we're reporting GPU memory usage we need to first start with a clean slate
|
||||
RenderProxy::purgeCaches();
|
||||
}
|
||||
Properties::forceDrawFrame = true;
|
||||
TestContext testContext;
|
||||
testContext.setRenderOffscreen(opts.renderOffscreen);
|
||||
@@ -162,11 +187,6 @@ static void doRun(const TestScene::Info& info, const TestScene::Options& opts, i
|
||||
|
||||
void run(const TestScene::Info& info, const TestScene::Options& opts,
|
||||
benchmark::BenchmarkReporter* reporter) {
|
||||
if (opts.reportGpuMemoryUsage) {
|
||||
// If we're reporting GPU memory usage we need to first start with a clean slate
|
||||
// All repetitions of the same test will share a single memory usage report
|
||||
RenderProxy::trimMemory(100);
|
||||
}
|
||||
BenchmarkResults results;
|
||||
for (int i = 0; i < opts.repeatCount; i++) {
|
||||
doRun(info, opts, i, reporter ? &results : nullptr);
|
||||
@@ -174,10 +194,21 @@ void run(const TestScene::Info& info, const TestScene::Options& opts,
|
||||
if (reporter) {
|
||||
reporter->ReportRuns(results);
|
||||
if (results.size() > 1) {
|
||||
// TODO: Report summary
|
||||
#ifdef USE_SKETCHY_INTERNAL_STATS
|
||||
std::vector<benchmark::internal::Statistics> stats;
|
||||
stats.reserve(3);
|
||||
stats.emplace_back("mean", benchmark::StatisticsMean);
|
||||
stats.emplace_back("median", benchmark::StatisticsMedian);
|
||||
stats.emplace_back("stddev", benchmark::StatisticsStdDev);
|
||||
for (auto& it : results) {
|
||||
it.statistics = &stats;
|
||||
}
|
||||
auto summary = benchmark::ComputeStats(results);
|
||||
reporter->ReportRuns(summary);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
if (opts.reportGpuMemoryUsage) {
|
||||
if (opts.reportGpuMemoryUsageVerbose) {
|
||||
RenderProxy::dumpGraphicsMemory(STDOUT_FILENO, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ OPTIONS:
|
||||
--benchmark_format Set output format. Possible values are tabular, json, csv
|
||||
--renderer=TYPE Sets the render pipeline to use. May be skiagl or skiavk
|
||||
--skip-leak-check Skips the memory leak check
|
||||
--report-gpu-memory Dumps the GPU memory usage after each test run
|
||||
--report-gpu-memory[=verbose] Dumps the GPU memory usage after each test run
|
||||
)");
|
||||
}
|
||||
|
||||
@@ -142,7 +142,7 @@ static bool setBenchmarkFormat(const char* format) {
|
||||
} else if (!strcmp(format, "json")) {
|
||||
gBenchmarkReporter.reset(new benchmark::JSONReporter());
|
||||
} else {
|
||||
fprintf(stderr, "Unknown format '%s'", format);
|
||||
fprintf(stderr, "Unknown format '%s'\n", format);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -154,7 +154,7 @@ static bool setRenderer(const char* renderer) {
|
||||
} else if (!strcmp(renderer, "skiavk")) {
|
||||
Properties::overrideRenderPipelineType(RenderPipelineType::SkiaVulkan);
|
||||
} else {
|
||||
fprintf(stderr, "Unknown format '%s'", renderer);
|
||||
fprintf(stderr, "Unknown format '%s'\n", renderer);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -191,7 +191,7 @@ static const struct option LONG_OPTIONS[] = {
|
||||
{"offscreen", no_argument, nullptr, LongOpts::Offscreen},
|
||||
{"renderer", required_argument, nullptr, LongOpts::Renderer},
|
||||
{"skip-leak-check", no_argument, nullptr, LongOpts::SkipLeakCheck},
|
||||
{"report-gpu-memory", no_argument, nullptr, LongOpts::ReportGpuMemory},
|
||||
{"report-gpu-memory", optional_argument, nullptr, LongOpts::ReportGpuMemory},
|
||||
{0, 0, 0, 0}};
|
||||
|
||||
static const char* SHORT_OPTIONS = "c:r:h";
|
||||
@@ -296,6 +296,14 @@ void parseOptions(int argc, char* argv[]) {
|
||||
|
||||
case LongOpts::ReportGpuMemory:
|
||||
gOpts.reportGpuMemoryUsage = true;
|
||||
if (optarg) {
|
||||
if (!strcmp("verbose", optarg)) {
|
||||
gOpts.reportGpuMemoryUsageVerbose = true;
|
||||
} else {
|
||||
fprintf(stderr, "Invalid report gpu memory option '%s'\n", optarg);
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
@@ -313,7 +321,7 @@ void parseOptions(int argc, char* argv[]) {
|
||||
}
|
||||
|
||||
if (error) {
|
||||
fprintf(stderr, "Try 'hwuitest --help' for more information.\n");
|
||||
fprintf(stderr, "Try '%s --help' for more information.\n", argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user