Edit

kc3-lang/angle/src/tests/perf_tests/CompilerPerf.cpp

Branch :

  • Show log

    Commit

  • Author : Olli Etuaho
    Date : 2018-02-06 16:39:29
    Hash : bfeed4dd
    Message : Add a compiler perf test shader to stress traversers Add a compiler perf test that's targeted at AST traversers. It triggers many traversers that mutate the AST and run multiple iterations particularly on the HLSL backend. BUG=angleproject:827 TEST=angle_perftests Change-Id: I75d89e8ae0fd7959f2c7fbb133c13ccde22abc37 Reviewed-on: https://chromium-review.googlesource.com/904622 Reviewed-by: Corentin Wallez <cwallez@chromium.org> Commit-Queue: Olli Etuaho <oetuaho@nvidia.com>

  • src/tests/perf_tests/CompilerPerf.cpp
  • //
    // Copyright 2018 The ANGLE Project Authors. All rights reserved.
    // Use of this source code is governed by a BSD-style license that can be
    // found in the LICENSE file.
    //
    // CompilerPerfTest:
    //   Performance test for the shader translator. The test initializes the compiler once and then
    //   compiles the same shader repeatedly. There are different variations of the tests using
    //   different shaders.
    //
    
    #include "ANGLEPerfTest.h"
    
    #include "GLSLANG/ShaderLang.h"
    #include "compiler/translator/Compiler.h"
    #include "compiler/translator/InitializeGlobals.h"
    #include "compiler/translator/PoolAlloc.h"
    
    namespace
    {
    
    const char *kSimpleESSL100FragSource = R"(
    precision mediump float;
    void main()
    {
        gl_FragColor = vec4(0, 1, 0, 1);
    }
    )";
    
    const char *kSimpleESSL100Id = "SimpleESSL100";
    
    const char *kSimpleESSL300FragSource = R"(#version 300 es
    precision highp float;
    out vec4 outColor;
    void main()
    {
        outColor = vec4(0, 1, 0, 1);
    }
    )";
    
    const char *kSimpleESSL300Id = "SimpleESSL300";
    
    const char *kRealWorldESSL100FragSource = R"(precision highp float;
    precision highp sampler2D;
    precision highp int;
    varying vec2 vPixelCoords; // in pixels
    uniform int uCircleCount;
    uniform sampler2D uCircleParameters;
    uniform sampler2D uBrushTex;
    void main(void)
    {
        float destAlpha = 0.0;
        for (int i = 0; i < 32; ++i)
        {
            vec4 parameterColor = texture2D(uCircleParameters,vec2(0.25, (float(i) + 0.5) / 32.0));
            vec2 center = parameterColor.xy;
            float circleRadius = parameterColor.z;
            float circleFlowAlpha = parameterColor.w;
            vec4 parameterColor2 = texture2D(uCircleParameters,vec2(0.75, (float(i) + 0.5) / 32.0));
            float circleRotation = parameterColor2.x;
            vec2 centerDiff = vPixelCoords - center;
            float radius = max(circleRadius, 0.5);
            float flowAlpha = (circleRadius < 0.5) ? circleFlowAlpha * circleRadius * circleRadius * 4.0: circleFlowAlpha;
            float antialiasMult = clamp((radius + 1.0 - length(centerDiff)) * 0.5, 0.0, 1.0);
            mat2 texRotation = mat2(cos(circleRotation), -sin(circleRotation), sin(circleRotation), cos(circleRotation));
            vec2 texCoords = texRotation * centerDiff / radius * 0.5 + 0.5;
            float texValue = texture2D(uBrushTex, texCoords).r;
            float circleAlpha = flowAlpha * antialiasMult * texValue;
            if (i < uCircleCount)
            {
                destAlpha = clamp(circleAlpha + (1.0 - circleAlpha) * destAlpha, 0.0, 1.0);
            }
        }
        gl_FragColor = vec4(0.0, 0.0, 0.0, destAlpha);
    })";
    
    const char *kRealWorldESSL100Id = "RealWorldESSL100";
    
    // This shader is intended to trigger many AST transformations, particularly on the HLSL backend.
    const char *kTrickyESSL300FragSource = R"(#version 300 es
    precision highp float;
    precision highp sampler2D;
    precision highp isampler2D;
    precision highp int;
    
    float globalF;
    
    uniform ivec4 uivec;
    uniform int ui;
    
    struct SS
    {
        int iField;
        float fField;
        vec2 f2Field;
        sampler2D sField;
        isampler2D isField;
    };
    uniform SS us;
    
    out vec4 my_FragColor;
    
    float[3] sideEffectArray()
    {
        globalF += 1.0;
        return float[3](globalF, globalF * 2.0, globalF * 3.0);
    }
    
    // This struct is unused and can be pruned.
    struct SUnused
    {
        vec2 fField;
    };
    
    void main()
    {
        struct S2
        {
            float fField;
        } s2;
        vec4 foo = vec4(ui);
        mat4 fooM = mat4(foo.x);
    
        // Some unused variables that can be pruned.
        float fUnused, fUnused2;
        ivec4 iUnused, iUnused2;
    
        globalF = us.fField;
        s2.fField = us.fField;
    
        float[3] fa = sideEffectArray();
    
        globalF -= us.fField;
        if (fa == sideEffectArray())
        {
            globalF += us.fField * sin(2.0);
        }
    
        // Switch with fall-through.
        switch (ui)
        {
          case 0:
            // Sequence operator and matrix and vector dynamic indexing.
            (globalF += 1.0, fooM[ui][ui] += fooM[ui - 1][uivec[ui] + 1]);
          case 1:
            // Built-in emulation.
            foo[3] = tanh(foo[1]);
          default:
            // Sequence operator and length of an array expression with side effects.
            foo[2] += (globalF -= 1.0, float((sideEffectArray()).length() * 2));
        }
        int i = 0;
        do
        {
            s2.fField = us.fField * us.f2Field.x;
            // Sequence operator and short-circuiting operator with side effects on the right hand side.
        } while ((++i, i < int(us.fField) && ++i <= ui || ++i < ui * 2 - 3));
        // Samplers in structures and integer texture sampling.
        foo += texture(us.sField, us.f2Field) + intBitsToFloat(texture(us.isField, us.f2Field + 4.0));
        my_FragColor = foo * s2.fField * globalF + fooM[ui];
    })";
    
    const char *kTrickyESSL300Id = "TrickyESSL300";
    
    struct CompilerPerfParameters final : public angle::CompilerParameters
    {
        CompilerPerfParameters(ShShaderOutput output,
                               const char *shaderSource,
                               const char *shaderSourceId)
            : angle::CompilerParameters(output), shaderSource(shaderSource)
        {
            testId = shaderSourceId;
            testId += "_";
            testId += angle::CompilerParameters::str();
        }
    
        const char *shaderSource;
        std::string testId;
    };
    
    std::ostream &operator<<(std::ostream &stream, const CompilerPerfParameters &p)
    {
        stream << p.testId;
        return stream;
    }
    
    class CompilerPerfTest : public ANGLEPerfTest,
                             public ::testing::WithParamInterface<CompilerPerfParameters>
    {
      public:
        CompilerPerfTest();
    
        void step() override;
    
        void SetUp() override;
        void TearDown() override;
    
      protected:
        void setTestShader(const char *str) { mTestShader = str; }
    
      private:
        const char *mTestShader;
    
        ShBuiltInResources mResources;
        TPoolAllocator mAllocator;
        sh::TCompiler *mTranslator;
    };
    
    CompilerPerfTest::CompilerPerfTest() : ANGLEPerfTest("CompilerPerf", GetParam().testId)
    {
    }
    
    void CompilerPerfTest::SetUp()
    {
        ANGLEPerfTest::SetUp();
    
        InitializePoolIndex();
        mAllocator.push();
        SetGlobalPoolAllocator(&mAllocator);
    
        const auto &params = GetParam();
    
        mTranslator = sh::ConstructCompiler(GL_FRAGMENT_SHADER, SH_WEBGL2_SPEC, params.output);
        sh::InitBuiltInResources(&mResources);
        mResources.FragmentPrecisionHigh = true;
        if (!mTranslator->Init(mResources))
        {
            SafeDelete(mTranslator);
        }
    
        setTestShader(params.shaderSource);
    }
    
    void CompilerPerfTest::TearDown()
    {
        SafeDelete(mTranslator);
    
        SetGlobalPoolAllocator(nullptr);
        mAllocator.pop();
    
        FreePoolIndex();
    
        ANGLEPerfTest::TearDown();
    }
    
    void CompilerPerfTest::step()
    {
        const char *shaderStrings[] = {mTestShader};
    
        ShCompileOptions compileOptions = SH_OBJECT_CODE | SH_VARIABLES |
                                          SH_INITIALIZE_UNINITIALIZED_LOCALS | SH_INIT_OUTPUT_VARIABLES;
    
        const int kNumIterationsPerStep = 10;
    
    #if !defined(NDEBUG)
        // Make sure that compilation succeeds and print the info log if it doesn't in debug mode.
        if (!mTranslator->compile(shaderStrings, 1, compileOptions))
        {
            std::cout << "Compiling perf test shader failed with log:\n"
                      << mTranslator->getInfoSink().info.c_str();
        }
    #endif
    
        for (unsigned int iteration = 0; iteration < kNumIterationsPerStep; ++iteration)
        {
            mTranslator->compile(shaderStrings, 1, compileOptions);
        }
    }
    
    TEST_P(CompilerPerfTest, Run)
    {
        run();
    }
    
    ANGLE_INSTANTIATE_TEST(
        CompilerPerfTest,
        CompilerPerfParameters(SH_HLSL_4_1_OUTPUT, kSimpleESSL100FragSource, kSimpleESSL100Id),
        CompilerPerfParameters(SH_HLSL_4_1_OUTPUT, kSimpleESSL300FragSource, kSimpleESSL300Id),
        CompilerPerfParameters(SH_HLSL_4_1_OUTPUT, kRealWorldESSL100FragSource, kRealWorldESSL100Id),
        CompilerPerfParameters(SH_HLSL_4_1_OUTPUT, kTrickyESSL300FragSource, kTrickyESSL300Id),
        CompilerPerfParameters(SH_GLSL_450_CORE_OUTPUT, kSimpleESSL100FragSource, kSimpleESSL100Id),
        CompilerPerfParameters(SH_GLSL_450_CORE_OUTPUT, kSimpleESSL300FragSource, kSimpleESSL300Id),
        CompilerPerfParameters(SH_GLSL_450_CORE_OUTPUT,
                               kRealWorldESSL100FragSource,
                               kRealWorldESSL100Id),
        CompilerPerfParameters(SH_GLSL_450_CORE_OUTPUT, kTrickyESSL300FragSource, kTrickyESSL300Id),
        CompilerPerfParameters(SH_ESSL_OUTPUT, kSimpleESSL100FragSource, kSimpleESSL100Id),
        CompilerPerfParameters(SH_ESSL_OUTPUT, kSimpleESSL300FragSource, kSimpleESSL300Id),
        CompilerPerfParameters(SH_ESSL_OUTPUT, kRealWorldESSL100FragSource, kRealWorldESSL100Id),
        CompilerPerfParameters(SH_ESSL_OUTPUT, kTrickyESSL300FragSource, kTrickyESSL300Id));
    
    }  // anonymous namespace