brintos

brintos / llvm-project-archived public Read only

0
0
Text · 10.2 KiB · 996eca4 Raw
290 lines · cpp
1#include "llvm/Support/Mustache.h"2#include "benchmark/benchmark.h"3#include "llvm/Support/JSON.h"4#include "llvm/Support/raw_ostream.h"5#include <string>6 7// A large, raw string with many characters that require HTML escaping.8static const std::string LongHtmlString = [] {9  std::string S;10  S.reserve(500000);11  for (int Idx = 0; Idx < 50000; ++Idx) {12    S += "<script>alert('xss');</script>";13  }14  return S;15}();16 17// A deep AND wide JSON object for testing traversal.18static const llvm::json::Value DeepJsonData = [] {19  llvm::json::Value Root = llvm::json::Object();20  llvm::json::Object *Current = Root.getAsObject();21  for (int i = 0; i < 50; ++i) { // 50 levels deep22    for (int j = 0; j < 100; ++j) {23      (*Current)["sibling_" + std::to_string(j)] = llvm::json::Value("noise");24    }25    std::string Key = "level_" + std::to_string(i);26    (*Current)[Key] = llvm::json::Object();27    Current = (*Current)[Key].getAsObject();28  }29  (*Current)["final_value"] = llvm::json::Value("Success!");30 31  llvm::json::Array Arr;32  for (int i = 0; i < 5000; ++i) { // 5,000 iterations33    Arr.push_back(llvm::json::Value(i));34  }35 36  llvm::json::Object NewRoot;37  NewRoot["deep_data"] = std::move(Root);38  NewRoot["loop_array"] = std::move(Arr);39  return llvm::json::Value(std::move(NewRoot));40}();41 42// A huge array for testing iteration performance.43static const llvm::json::Value HugeArrayData = [] {44  llvm::json::Array Arr;45  for (int i = 0; i < 100000; ++i) { // 100,000 array items46    Arr.push_back(llvm::json::Object(47        {{"id", llvm::json::Value(static_cast<long long>(i))},48         {"is_even", llvm::json::Value(i % 2 == 0)},49         {"data", llvm::json::Value("Item data for " + std::to_string(i))}}));50  }51  return llvm::json::Object({{"items", std::move(Arr)}});52}();53 54// The main template that includes a partial within a loop.55static const std::string ComplexPartialTemplate =56    "Header\n"57    "{{#items}}{{> item_partial}}{{/items}}\n"58    "Footer";59 60// The partial template is now more complex, rendering multiple fields and a61// conditional section.62static const std::string ItemPartialTemplate =63    "<div class=\"item\" id=\"{{id}}\">\n"64    " <p>{{data}}</p>\n"65    " {{#is_even}}<span>(Even)</span>{{/is_even}}\n"66    "</div>\n";67 68// A single large string to stress the output buffer.69static const llvm::json::Value LargeOutputData = llvm::json::Object({70    {"long_string",71     llvm::json::Value(std::string(1024 * 1024, 'A'))} // 1MB string72});73 74// --- Static Data (Templates) ---75 76static const std::string BulkEscapingTemplate = "{{content}}";77static const std::string BulkUnescapedTemplate = "{{{content}}}";78static const std::string BulkUnescapedAmpersandTemplate = "{{& content}}";79 80static const std::string DeepTraversalTemplate = [] {81  std::string LongKey =82      "deep_data.level_0.level_1.level_2.level_3.level_4.level_5."83      "level_6.level_7.level_8.level_9."84      "level_10.level_11.level_12.level_13.level_14.level_"85      "15.level_16.level_17.level_18.level_19."86      "level_20.level_21.level_22.level_23.level_24.level_"87      "25.level_26.level_27.level_28.level_29."88      "level_30.level_31.level_32.level_33.level_34.level_"89      "35.level_36.level_37.level_38.level_39."90      "level_40.level_41.level_42.level_43.level_44.level_"91      "45.level_46.level_47.level_48.level_49.final_value";92  return "{{#loop_array}}{{" + LongKey + "}}{{/loop_array}}";93}();94 95static const std::string DeeplyNestedRenderingTemplate = [] {96  std::string NestedTemplate = "{{#deep_data}}";97  for (int i = 0; i < 50; ++i) {98    NestedTemplate += "{{#level_" + std::to_string(i) + "}}";99  }100  NestedTemplate += "{{final_value}}";101  for (int i = 49; i >= 0; --i) {102    NestedTemplate += "{{/level_" + std::to_string(i) + "}}";103  }104  NestedTemplate += "{{/deep_data}}";105  return NestedTemplate;106}();107 108static const std::string HugeArrayIterationTemplate =109    "{{#items}}ID: {{id}}.{{/items}}";110 111static const std::string ComplexTemplateParsingTemplate = [] {112  std::string LargeTemplate;113  LargeTemplate.reserve(100000);114  for (int i = 0; i < 1000; ++i) {115    LargeTemplate += "{{var_" + std::to_string(i) +116                     "}}"117                     "{{#section_" +118                     std::to_string(i) + "}}Content{{/section_" +119                     std::to_string(i) +120                     "}}"121                     "{{!comment_" +122                     std::to_string(i) +123                     "}}"124                     "{{=<% %>=}}"125                     "<%var_tag_changed_to_percent_sign_" +126                     std::to_string(i) +127                     "%>"128                     "<%={{ }}=%>"129                     "{{^inverted_" +130                     std::to_string(i) + "}}Not Present{{/inverted_" +131                     std::to_string(i) + "}}";132  }133  return LargeTemplate;134}();135 136static const std::string SmallTemplateParsingTemplate =137    "{{level_0.sibling_99}}\n"138    "{{level_0.level_1.level_2.level_3.level_4.level_5.sibling_50}}\n"139    "{{level_0.level_1.level_2.level_3.level_4.level_5."140    "level_6.level_7.level_8.level_9."141    "level_10.level_11.level_12.level_13.level_14.level_"142    "15.level_16.level_17.level_18.level_19."143    "level_20.level_21.level_22.level_23.level_24.level_"144    "25.level_26.level_27.level_28.level_29."145    "level_30.level_31.level_32.level_33.level_34.level_"146    "35.level_36.level_37.level_38.level_39."147    "level_40.level_41.level_42.level_43.level_44.level_"148    "45.level_46.level_47.level_48.level_49.final_value}}\n";149 150static const std::string LargeOutputStringTemplate = "{{long_string}}";151 152// Tests the performance of rendering a large string with various escaping153// syntaxes.154static void BM_Mustache_StringRendering(benchmark::State &state,155                                        const std::string &TplStr) {156  llvm::BumpPtrAllocator Allocator;157  llvm::StringSaver Saver(Allocator);158  llvm::mustache::MustacheContext Ctx(Allocator, Saver);159 160  llvm::mustache::Template Tpl(TplStr, Ctx);161  llvm::json::Value Data =162      llvm::json::Object({{"content", llvm::json::Value(LongHtmlString)}});163  for (auto _ : state) {164    std::string Result;165    llvm::raw_string_ostream OS(Result);166    Tpl.render(Data, OS);167    benchmark::DoNotOptimize(Result);168  }169}170BENCHMARK_CAPTURE(BM_Mustache_StringRendering, Escaped, BulkEscapingTemplate);171BENCHMARK_CAPTURE(BM_Mustache_StringRendering, Unescaped_Triple,172                  BulkUnescapedTemplate);173BENCHMARK_CAPTURE(BM_Mustache_StringRendering, Unescaped_Ampersand,174                  BulkUnescapedAmpersandTemplate);175 176// Tests the "hot render" cost of repeatedly traversing a deep and wide177// JSON object.178static void BM_Mustache_DeepTraversal(benchmark::State &state) {179  llvm::BumpPtrAllocator Allocator;180  llvm::StringSaver Saver(Allocator);181  llvm::mustache::MustacheContext Ctx(Allocator, Saver);182 183  llvm::mustache::Template Tpl(DeepTraversalTemplate, Ctx);184  for (auto _ : state) {185    std::string Result;186    llvm::raw_string_ostream OS(Result);187    Tpl.render(DeepJsonData, OS);188    benchmark::DoNotOptimize(Result);189  }190}191BENCHMARK(BM_Mustache_DeepTraversal);192 193// Tests the "hot render" cost of pushing and popping a deep context stack.194static void BM_Mustache_DeeplyNestedRendering(benchmark::State &state) {195 196  llvm::BumpPtrAllocator Allocator;197  llvm::StringSaver Saver(Allocator);198  llvm::mustache::MustacheContext Ctx(Allocator, Saver);199 200  llvm::mustache::Template Tpl(DeeplyNestedRenderingTemplate, Ctx);201  for (auto _ : state) {202    std::string Result;203    llvm::raw_string_ostream OS(Result);204    Tpl.render(DeepJsonData, OS);205    benchmark::DoNotOptimize(Result);206  }207}208BENCHMARK(BM_Mustache_DeeplyNestedRendering);209 210// Tests the performance of the loop logic when iterating over a huge number of211// items.212static void BM_Mustache_HugeArrayIteration(benchmark::State &state) {213  llvm::BumpPtrAllocator Allocator;214  llvm::StringSaver Saver(Allocator);215  llvm::mustache::MustacheContext Ctx(Allocator, Saver);216 217  llvm::mustache::Template Tpl(HugeArrayIterationTemplate, Ctx);218  for (auto _ : state) {219    std::string Result;220    llvm::raw_string_ostream OS(Result);221    Tpl.render(HugeArrayData, OS);222    benchmark::DoNotOptimize(Result);223  }224}225BENCHMARK(BM_Mustache_HugeArrayIteration);226 227// Tests the performance of the parser on a large, "wide" template.228static void BM_Mustache_ComplexTemplateParsing(benchmark::State &state) {229  llvm::BumpPtrAllocator Allocator;230  llvm::StringSaver Saver(Allocator);231  llvm::mustache::MustacheContext Ctx(Allocator, Saver);232 233  for (auto _ : state) {234    llvm::mustache::Template Tpl(ComplexTemplateParsingTemplate, Ctx);235    benchmark::DoNotOptimize(Tpl);236  }237}238BENCHMARK(BM_Mustache_ComplexTemplateParsing);239 240// Tests the performance of the parser on a small, "deep" template.241static void BM_Mustache_SmallTemplateParsing(benchmark::State &state) {242  llvm::BumpPtrAllocator Allocator;243  llvm::StringSaver Saver(Allocator);244  llvm::mustache::MustacheContext Ctx(Allocator, Saver);245 246  for (auto _ : state) {247    llvm::mustache::Template Tpl(SmallTemplateParsingTemplate, Ctx);248    benchmark::DoNotOptimize(Tpl);249  }250}251BENCHMARK(BM_Mustache_SmallTemplateParsing);252 253// Tests the performance of rendering a template that includes a partial.254static void BM_Mustache_PartialsRendering(benchmark::State &state) {255  llvm::BumpPtrAllocator Allocator;256  llvm::StringSaver Saver(Allocator);257  llvm::mustache::MustacheContext Ctx(Allocator, Saver);258 259  llvm::mustache::Template Tpl(ComplexPartialTemplate, Ctx);260  Tpl.registerPartial("item_partial", ItemPartialTemplate);261  llvm::json::Value Data = HugeArrayData;262 263  for (auto _ : state) {264    std::string Result;265    llvm::raw_string_ostream OS(Result);266    Tpl.render(Data, OS);267    benchmark::DoNotOptimize(Result);268  }269}270BENCHMARK(BM_Mustache_PartialsRendering);271 272// Tests the performance of the underlying buffer management when generating a273// very large output.274static void BM_Mustache_LargeOutputString(benchmark::State &state) {275  llvm::BumpPtrAllocator Allocator;276  llvm::StringSaver Saver(Allocator);277  llvm::mustache::MustacheContext Ctx(Allocator, Saver);278 279  llvm::mustache::Template Tpl(LargeOutputStringTemplate, Ctx);280  for (auto _ : state) {281    std::string Result;282    llvm::raw_string_ostream OS(Result);283    Tpl.render(LargeOutputData, OS);284    benchmark::DoNotOptimize(Result);285  }286}287BENCHMARK(BM_Mustache_LargeOutputString);288 289BENCHMARK_MAIN();290