Add benchmark for loading modules at startup.

This will let us track startup times, and inform decisions on whether
it's worth keeping the Rehydrator system or not.

Change-Id: I4fc52a4d88380d4e396c9fe1138335320eed084d
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/585148
Commit-Queue: Brian Osman <brianosman@google.com>
Auto-Submit: John Stiles <johnstiles@google.com>
Reviewed-by: Brian Osman <brianosman@google.com>
Commit-Queue: John Stiles <johnstiles@google.com>
diff --git a/bench/SkSLBench.cpp b/bench/SkSLBench.cpp
index 2086fc38..e2f15d5 100644
--- a/bench/SkSLBench.cpp
+++ b/bench/SkSLBench.cpp
@@ -12,6 +12,7 @@
 #include "src/gpu/ganesh/GrRecordingContextPriv.h"
 #include "src/gpu/ganesh/mock/GrMockCaps.h"
 #include "src/sksl/SkSLCompiler.h"
+#include "src/sksl/SkSLModuleLoader.h"
 #include "src/sksl/SkSLParser.h"
 #include "src/sksl/codegen/SkSLVMCodeGenerator.h"
 #include "src/sksl/ir/SkSLProgram.h"
@@ -569,3 +570,61 @@
     int compilerComputeBinarySize = std::size(SKSL_INCLUDE_sksl_compute);
     bench(log, "sksl_binary_size_compute", compilerComputeBinarySize);
 }
+
+class SkSLModuleLoaderBench : public Benchmark {
+public:
+    SkSLModuleLoaderBench(const char* name, std::vector<SkSL::ProgramKind> moduleList)
+            : fName(name), fModuleList(std::move(moduleList)) {}
+
+    const char* onGetName() override {
+        return fName;
+    }
+
+    bool isSuitableFor(Backend backend) override {
+        return backend == kNonRendering_Backend;
+    }
+
+    int calculateLoops(int defaultLoops) const override {
+        return 1;
+    }
+
+    void onPreDraw(SkCanvas*) override {
+        SkSL::ModuleLoader::Get().unloadModules();
+    }
+
+    void onDraw(int loops, SkCanvas*) override {
+        SkASSERT(loops == 1);
+        GrShaderCaps caps;
+        SkSL::Compiler compiler(&caps);
+        for (SkSL::ProgramKind kind : fModuleList) {
+            compiler.moduleForProgramKind(kind);
+        }
+    }
+
+    const char* fName;
+    std::vector<SkSL::ProgramKind> fModuleList;
+};
+
+DEF_BENCH(return new SkSLModuleLoaderBench("sksl_module_loader_ganesh",
+                                           {
+                                                   SkSL::ProgramKind::kVertex,
+                                                   SkSL::ProgramKind::kFragment,
+                                                   SkSL::ProgramKind::kRuntimeColorFilter,
+                                                   SkSL::ProgramKind::kRuntimeShader,
+                                                   SkSL::ProgramKind::kRuntimeBlender,
+                                                   SkSL::ProgramKind::kPrivateRuntimeShader,
+                                                   SkSL::ProgramKind::kCompute,
+                                           });)
+
+DEF_BENCH(return new SkSLModuleLoaderBench("sksl_module_loader_graphite",
+                                           {
+                                                   SkSL::ProgramKind::kVertex,
+                                                   SkSL::ProgramKind::kFragment,
+                                                   SkSL::ProgramKind::kRuntimeColorFilter,
+                                                   SkSL::ProgramKind::kRuntimeShader,
+                                                   SkSL::ProgramKind::kRuntimeBlender,
+                                                   SkSL::ProgramKind::kPrivateRuntimeShader,
+                                                   SkSL::ProgramKind::kCompute,
+                                                   SkSL::ProgramKind::kGraphiteVertex,
+                                                   SkSL::ProgramKind::kGraphiteFragment,
+                                           });)
diff --git a/src/sksl/SkSLModuleLoader.cpp b/src/sksl/SkSLModuleLoader.cpp
index ea840ad..c44ba3b 100644
--- a/src/sksl/SkSLModuleLoader.cpp
+++ b/src/sksl/SkSLModuleLoader.cpp
@@ -157,6 +157,18 @@
     fModuleLoader.fMutex.release();
 }
 
+void ModuleLoader::unloadModules() {
+    fModuleLoader.fSharedModule           = ParsedModule{};
+    fModuleLoader.fGPUModule              = ParsedModule{};
+    fModuleLoader.fVertexModule           = ParsedModule{};
+    fModuleLoader.fFragmentModule         = ParsedModule{};
+    fModuleLoader.fComputeModule          = ParsedModule{};
+    fModuleLoader.fGraphiteVertexModule   = ParsedModule{};
+    fModuleLoader.fGraphiteFragmentModule = ParsedModule{};
+    fModuleLoader.fPublicModule           = ParsedModule{};
+    fModuleLoader.fRuntimeShaderModule    = ParsedModule{};
+}
+
 ModuleLoader::Impl::Impl() {
     this->makeRootSymbolTable();
 }
diff --git a/src/sksl/SkSLModuleLoader.h b/src/sksl/SkSLModuleLoader.h
index 3877665..5a5dc35 100644
--- a/src/sksl/SkSLModuleLoader.h
+++ b/src/sksl/SkSLModuleLoader.h
@@ -58,6 +58,9 @@
 
     const ParsedModule& loadPublicModule(SkSL::Compiler* compiler);
     const ParsedModule& loadPrivateRTShaderModule(SkSL::Compiler* compiler);
+
+    // This unloads every module. It's useful primarily for benchmarking purposes.
+    void unloadModules();
 };
 
 }  // namespace SkSL