116c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck/*
216c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck * Copyright (C) 2015 The Android Open Source Project
316c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck *
416c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck * Licensed under the Apache License, Version 2.0 (the "License");
516c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck * you may not use this file except in compliance with the License.
616c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck * You may obtain a copy of the License at
716c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck *
816c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck *      http://www.apache.org/licenses/LICENSE-2.0
916c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck *
1016c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck * Unless required by applicable law or agreed to in writing, software
1116c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck * distributed under the License is distributed on an "AS IS" BASIS,
1216c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1316c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck * See the License for the specific language governing permissions and
1416c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck * limitations under the License.
1516c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck */
1616c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck
1716c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck#include "AnimationContext.h"
1816c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck#include "RenderNode.h"
1927e58b4f54d693ff1db7ab2edb5d47ca296c1278Chris Craik#include "tests/common/TestContext.h"
2027e58b4f54d693ff1db7ab2edb5d47ca296c1278Chris Craik#include "tests/common/TestScene.h"
218160f20b0aca8c6595d4b385d673f59b6bcd16a4Chris Craik#include "tests/common/scenes/TestSceneBase.h"
2216c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck#include "renderthread/RenderProxy.h"
2316c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck#include "renderthread/RenderTask.h"
2416c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck
25f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck#include <benchmark/benchmark.h>
2616c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck#include <gui/Surface.h>
2796bf5985d5a360568832fd26b6d5b44236c9343eMark Salyzyn#include <log/log.h>
2816c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck#include <ui/PixelFormat.h>
2916c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck
3016c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reckusing namespace android;
3116c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reckusing namespace android::uirenderer;
3216c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reckusing namespace android::uirenderer::renderthread;
3316c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reckusing namespace android::uirenderer::test;
3416c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck
3516c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reckclass ContextFactory : public IContextFactory {
3616c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reckpublic:
3716c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    virtual AnimationContext* createAnimationContext(renderthread::TimeLord& clock) override {
3816c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        return new AnimationContext(clock);
3916c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    }
4016c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck};
4116c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck
42682573c84b7c21dc8ce4a2375da3961147442c4aJohn Recktemplate<class T>
43682573c84b7c21dc8ce4a2375da3961147442c4aJohn Reckclass ModifiedMovingAverage {
44682573c84b7c21dc8ce4a2375da3961147442c4aJohn Reckpublic:
45d53e3bed1ca4a14b2a86d53eaef6969bd043176eChih-Hung Hsieh    explicit ModifiedMovingAverage(int weight) : mWeight(weight) {}
46682573c84b7c21dc8ce4a2375da3961147442c4aJohn Reck
47682573c84b7c21dc8ce4a2375da3961147442c4aJohn Reck    T add(T today) {
48682573c84b7c21dc8ce4a2375da3961147442c4aJohn Reck        if (!mHasValue) {
49682573c84b7c21dc8ce4a2375da3961147442c4aJohn Reck            mAverage = today;
50682573c84b7c21dc8ce4a2375da3961147442c4aJohn Reck        } else {
51682573c84b7c21dc8ce4a2375da3961147442c4aJohn Reck            mAverage = (((mWeight - 1) * mAverage) + today) / mWeight;
52682573c84b7c21dc8ce4a2375da3961147442c4aJohn Reck        }
53682573c84b7c21dc8ce4a2375da3961147442c4aJohn Reck        return mAverage;
54682573c84b7c21dc8ce4a2375da3961147442c4aJohn Reck    }
55682573c84b7c21dc8ce4a2375da3961147442c4aJohn Reck
56682573c84b7c21dc8ce4a2375da3961147442c4aJohn Reck    T average() {
57682573c84b7c21dc8ce4a2375da3961147442c4aJohn Reck        return mAverage;
58682573c84b7c21dc8ce4a2375da3961147442c4aJohn Reck    }
59682573c84b7c21dc8ce4a2375da3961147442c4aJohn Reck
60682573c84b7c21dc8ce4a2375da3961147442c4aJohn Reckprivate:
61682573c84b7c21dc8ce4a2375da3961147442c4aJohn Reck    bool mHasValue = false;
62682573c84b7c21dc8ce4a2375da3961147442c4aJohn Reck    int mWeight;
63682573c84b7c21dc8ce4a2375da3961147442c4aJohn Reck    T mAverage;
64682573c84b7c21dc8ce4a2375da3961147442c4aJohn Reck};
65682573c84b7c21dc8ce4a2375da3961147442c4aJohn Reck
66f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reckvoid outputBenchmarkReport(const TestScene::Info& info, const TestScene::Options& opts,
67f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck        benchmark::BenchmarkReporter* reporter, RenderProxy* proxy,
68f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck        double durationInS) {
69f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck    using namespace benchmark;
70f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck
71f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck    struct ReportInfo {
72f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck        int percentile;
73f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck        const char* suffix;
74f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck    };
75f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck
76f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck    static std::array<ReportInfo, 4> REPORTS = {
77f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck        ReportInfo { 50, "_50th" },
78f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck        ReportInfo { 90, "_90th" },
79f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck        ReportInfo { 95, "_95th" },
80f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck        ReportInfo { 99, "_99th" },
81f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck    };
82f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck
83f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck    // Although a vector is used, it must stay with only a single element
84f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck    // otherwise the BenchmarkReporter will automatically compute
85f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck    // mean and stddev which doesn't make sense for our usage
86f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck    std::vector<BenchmarkReporter::Run> reports;
87f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck    BenchmarkReporter::Run report;
88f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck    report.benchmark_name = info.name;
89f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck    report.iterations = static_cast<int64_t>(opts.count);
90f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck    report.real_accumulated_time = durationInS;
91f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck    report.cpu_accumulated_time = durationInS;
92f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck    report.items_per_second = opts.count / durationInS;
93f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck    reports.push_back(report);
94f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck    reporter->ReportRuns(reports);
95f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck
96f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck    // Pretend the percentiles are single-iteration runs of the test
97f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck    // If rendering offscreen skip this as it's fps that's more interesting
98f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck    // in that test case than percentiles.
99f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck    if (!opts.renderOffscreen) {
100f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck        for (auto& ri : REPORTS) {
101f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck            reports[0].benchmark_name = info.name;
102f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck            reports[0].benchmark_name += ri.suffix;
103f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck            durationInS = proxy->frameTimePercentile(ri.percentile) / 1000.0;
104f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck            reports[0].real_accumulated_time = durationInS;
105f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck            reports[0].cpu_accumulated_time = durationInS;
106f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck            reports[0].iterations = 1;
107f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck            reports[0].items_per_second = 0;
108f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck            reporter->ReportRuns(reports);
109f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck        }
110f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck    }
111f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck}
112f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck
113f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reckvoid run(const TestScene::Info& info, const TestScene::Options& opts,
114f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck        benchmark::BenchmarkReporter* reporter) {
11516c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    // Switch to the real display
11616c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    gDisplay = getBuiltInDisplay();
11716c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck
11816c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    std::unique_ptr<TestScene> scene(info.createScene(opts));
11916c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck
120a5c73e3839129e0079b370bd2723bc0fc4aa6387sergeyv    Properties::forceDrawFrame = true;
12116c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    TestContext testContext;
122f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck    testContext.setRenderOffscreen(opts.renderOffscreen);
12316c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck
12416c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    // create the native surface
12516c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    const int width = gDisplay.w;
12616c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    const int height = gDisplay.h;
12716c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    sp<Surface> surface = testContext.surface();
12816c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck
12916c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    sp<RenderNode> rootNode = TestUtils::createNode(0, 0, width, height,
13006152cdd06da50762716cd455dcf7ab0117f25b0Stan Iliev            [&scene, width, height](RenderProperties& props, Canvas& canvas) {
13116c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        props.setClipToBounds(false);
13216c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        scene->createContent(width, height, canvas);
13316c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    });
13416c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck
13516c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    ContextFactory factory;
13616c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    std::unique_ptr<RenderProxy> proxy(new RenderProxy(false,
13716c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck            rootNode.get(), &factory));
13816c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    proxy->loadSystemProperties();
13916c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    proxy->initialize(surface);
14016c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    float lightX = width / 2.0;
141ab1080c4d075b008cebdd9a2031ebbd51f9c2729John Reck    proxy->setup(dp(800.0f), 255 * 0.075, 255 * 0.15);
14216c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    proxy->setLightCenter((Vector3){lightX, dp(-200.0f), dp(800.0f)});
14316c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck
14416c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    // Do a few cold runs then reset the stats so that the caches are all hot
145f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck    int warmupFrameCount = 5;
146f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck    if (opts.renderOffscreen) {
147f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck        // Do a few more warmups to try and boost the clocks up
148f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck        warmupFrameCount = 10;
149f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck    }
150f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck    for (int i = 0; i < warmupFrameCount; i++) {
15116c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        testContext.waitForVsync();
15216c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        nsecs_t vsync = systemTime(CLOCK_MONOTONIC);
15316c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        UiFrameInfoBuilder(proxy->frameInfo()).setVsync(vsync, vsync);
1542de950d5a8b47c7b4648ada1b1260ce4b7342798John Reck        proxy->syncAndDrawFrame();
15516c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    }
156682573c84b7c21dc8ce4a2375da3961147442c4aJohn Reck
15716c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    proxy->resetProfileInfo();
158682573c84b7c21dc8ce4a2375da3961147442c4aJohn Reck    proxy->fence();
159682573c84b7c21dc8ce4a2375da3961147442c4aJohn Reck
160682573c84b7c21dc8ce4a2375da3961147442c4aJohn Reck    ModifiedMovingAverage<double> avgMs(opts.reportFrametimeWeight);
16116c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck
162f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck    nsecs_t start = systemTime(CLOCK_MONOTONIC);
16316c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    for (int i = 0; i < opts.count; i++) {
16416c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        testContext.waitForVsync();
16516c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck        nsecs_t vsync = systemTime(CLOCK_MONOTONIC);
166682573c84b7c21dc8ce4a2375da3961147442c4aJohn Reck        {
167682573c84b7c21dc8ce4a2375da3961147442c4aJohn Reck            ATRACE_NAME("UI-Draw Frame");
168682573c84b7c21dc8ce4a2375da3961147442c4aJohn Reck            UiFrameInfoBuilder(proxy->frameInfo()).setVsync(vsync, vsync);
169682573c84b7c21dc8ce4a2375da3961147442c4aJohn Reck            scene->doFrame(i);
1702de950d5a8b47c7b4648ada1b1260ce4b7342798John Reck            proxy->syncAndDrawFrame();
171682573c84b7c21dc8ce4a2375da3961147442c4aJohn Reck        }
172682573c84b7c21dc8ce4a2375da3961147442c4aJohn Reck        if (opts.reportFrametimeWeight) {
1732705c983f5e3299e1481fd98a80fc78bce927527Chris Craik            proxy->fence();
1742705c983f5e3299e1481fd98a80fc78bce927527Chris Craik            nsecs_t done = systemTime(CLOCK_MONOTONIC);
175682573c84b7c21dc8ce4a2375da3961147442c4aJohn Reck            avgMs.add((done - vsync) / 1000000.0);
176682573c84b7c21dc8ce4a2375da3961147442c4aJohn Reck            if (i % 10 == 9) {
177682573c84b7c21dc8ce4a2375da3961147442c4aJohn Reck                printf("Average frametime %.3fms\n", avgMs.average());
178682573c84b7c21dc8ce4a2375da3961147442c4aJohn Reck            }
179682573c84b7c21dc8ce4a2375da3961147442c4aJohn Reck        }
18016c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck    }
181f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck    proxy->fence();
182f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck    nsecs_t end = systemTime(CLOCK_MONOTONIC);
18316c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck
184f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck    if (reporter) {
185f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck        outputBenchmarkReport(info, opts, reporter, proxy.get(),
186f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck                (end - start) / (double) s2ns(1));
187f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck    } else {
188f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck        proxy->dumpProfileInfo(STDOUT_FILENO, DumpFlags::JankStats);
189f1480761c1a83aecd09cdd473ec797a41d1a2f3fJohn Reck    }
19016c9d6a92e1b86d448c00c52a1630f3e71e6df76John Reck}
191