Home | History | Annotate | Download | only in testing
      1 // Copyright 2006-2008 The RE2 Authors.  All Rights Reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 // Benchmarks for regular expression implementations.
      6 
      7 #include "util/test.h"
      8 #include "re2/prog.h"
      9 #include "re2/re2.h"
     10 #include "re2/regexp.h"
     11 #include "util/pcre.h"
     12 #include "util/benchmark.h"
     13 
     14 namespace re2 {
     15 void Test();
     16 void MemoryUsage();
     17 }  // namespace re2
     18 
     19 typedef testing::MallocCounter MallocCounter;
     20 
     21 namespace re2 {
     22 
     23 void Test() {
     24   Regexp* re = Regexp::Parse("(\\d+)-(\\d+)-(\\d+)", Regexp::LikePerl, NULL);
     25   CHECK(re);
     26   Prog* prog = re->CompileToProg(0);
     27   CHECK(prog);
     28   CHECK(prog->IsOnePass());
     29   const char* text = "650-253-0001";
     30   StringPiece sp[4];
     31   CHECK(prog->SearchOnePass(text, text, Prog::kAnchored, Prog::kFullMatch, sp, 4));
     32   CHECK_EQ(sp[0], "650-253-0001");
     33   CHECK_EQ(sp[1], "650");
     34   CHECK_EQ(sp[2], "253");
     35   CHECK_EQ(sp[3], "0001");
     36   delete prog;
     37   re->Decref();
     38   LOG(INFO) << "test passed\n";
     39 }
     40 
     41 void MemoryUsage() {
     42   const char* regexp = "(\\d+)-(\\d+)-(\\d+)";
     43   const char* text = "650-253-0001";
     44   {
     45     MallocCounter mc(MallocCounter::THIS_THREAD_ONLY);
     46     Regexp* re = Regexp::Parse(regexp, Regexp::LikePerl, NULL);
     47     CHECK(re);
     48     // Can't pass mc.HeapGrowth() and mc.PeakHeapGrowth() to LOG(INFO) directly,
     49     // because LOG(INFO) might do a big allocation before they get evaluated.
     50     fprintf(stderr, "Regexp: %7lld bytes (peak=%lld)\n", mc.HeapGrowth(), mc.PeakHeapGrowth());
     51     mc.Reset();
     52 
     53     Prog* prog = re->CompileToProg(0);
     54     CHECK(prog);
     55     CHECK(prog->IsOnePass());
     56     fprintf(stderr, "Prog:   %7lld bytes (peak=%lld)\n", mc.HeapGrowth(), mc.PeakHeapGrowth());
     57     mc.Reset();
     58 
     59     StringPiece sp[4];
     60     CHECK(prog->SearchOnePass(text, text, Prog::kAnchored, Prog::kFullMatch, sp, 4));
     61     fprintf(stderr, "Search: %7lld bytes (peak=%lld)\n", mc.HeapGrowth(), mc.PeakHeapGrowth());
     62     delete prog;
     63     re->Decref();
     64   }
     65 
     66   {
     67     MallocCounter mc(MallocCounter::THIS_THREAD_ONLY);
     68 
     69     PCRE re(regexp, PCRE::UTF8);
     70     fprintf(stderr, "RE:     %7lld bytes (peak=%lld)\n", mc.HeapGrowth(), mc.PeakHeapGrowth());
     71     PCRE::FullMatch(text, re);
     72     fprintf(stderr, "RE:     %7lld bytes (peak=%lld)\n", mc.HeapGrowth(), mc.PeakHeapGrowth());
     73   }
     74 
     75   {
     76     MallocCounter mc(MallocCounter::THIS_THREAD_ONLY);
     77 
     78     PCRE* re = new PCRE(regexp, PCRE::UTF8);
     79     fprintf(stderr, "PCRE*:  %7lld bytes (peak=%lld)\n", mc.HeapGrowth(), mc.PeakHeapGrowth());
     80     PCRE::FullMatch(text, *re);
     81     fprintf(stderr, "PCRE*:  %7lld bytes (peak=%lld)\n", mc.HeapGrowth(), mc.PeakHeapGrowth());
     82     delete re;
     83   }
     84 
     85   {
     86     MallocCounter mc(MallocCounter::THIS_THREAD_ONLY);
     87 
     88     RE2 re(regexp);
     89     fprintf(stderr, "RE2:    %7lld bytes (peak=%lld)\n", mc.HeapGrowth(), mc.PeakHeapGrowth());
     90     RE2::FullMatch(text, re);
     91     fprintf(stderr, "RE2:    %7lld bytes (peak=%lld)\n", mc.HeapGrowth(), mc.PeakHeapGrowth());
     92   }
     93 
     94   fprintf(stderr, "sizeof: PCRE=%d RE2=%d Prog=%d Inst=%d\n",
     95           static_cast<int>(sizeof(PCRE)),
     96           static_cast<int>(sizeof(RE2)),
     97           static_cast<int>(sizeof(Prog)),
     98           static_cast<int>(sizeof(Prog::Inst)));
     99 }
    100 
    101 // Regular expression implementation wrappers.
    102 // Defined at bottom of file, but they are repetitive
    103 // and not interesting.
    104 
    105 typedef void SearchImpl(int iters, const char* regexp, const StringPiece& text,
    106              Prog::Anchor anchor, bool expect_match);
    107 
    108 SearchImpl SearchDFA, SearchNFA, SearchOnePass, SearchBitState,
    109            SearchPCRE, SearchRE2,
    110            SearchCachedDFA, SearchCachedNFA, SearchCachedOnePass, SearchCachedBitState,
    111            SearchCachedPCRE, SearchCachedRE2;
    112 
    113 typedef void ParseImpl(int iters, const char* regexp, const StringPiece& text);
    114 
    115 ParseImpl Parse1NFA, Parse1OnePass, Parse1BitState,
    116           Parse1PCRE, Parse1RE2,
    117           Parse1Backtrack,
    118           Parse1CachedNFA, Parse1CachedOnePass, Parse1CachedBitState,
    119           Parse1CachedPCRE, Parse1CachedRE2,
    120           Parse1CachedBacktrack;
    121 
    122 ParseImpl Parse3NFA, Parse3OnePass, Parse3BitState,
    123           Parse3PCRE, Parse3RE2,
    124           Parse3Backtrack,
    125           Parse3CachedNFA, Parse3CachedOnePass, Parse3CachedBitState,
    126           Parse3CachedPCRE, Parse3CachedRE2,
    127           Parse3CachedBacktrack;
    128 
    129 ParseImpl SearchParse2CachedPCRE, SearchParse2CachedRE2;
    130 
    131 ParseImpl SearchParse1CachedPCRE, SearchParse1CachedRE2;
    132 
    133 // Benchmark: failed search for regexp in random text.
    134 
    135 // Generate random text that won't contain the search string,
    136 // to test worst-case search behavior.
    137 void MakeText(string* text, int nbytes) {
    138   text->resize(nbytes);
    139   srand(0);
    140   for (int i = 0; i < nbytes; i++) {
    141     if (!rand()%30)
    142       (*text)[i] = '\n';
    143     else
    144       (*text)[i] = rand()%(0x7E + 1 - 0x20)+0x20;
    145   }
    146 }
    147 
    148 // Makes text of size nbytes, then calls run to search
    149 // the text for regexp iters times.
    150 void Search(int iters, int nbytes, const char* regexp, SearchImpl* search) {
    151   StopBenchmarkTiming();
    152   string s;
    153   MakeText(&s, nbytes);
    154   BenchmarkMemoryUsage();
    155   StartBenchmarkTiming();
    156   search(iters, regexp, s, Prog::kUnanchored, false);
    157   SetBenchmarkBytesProcessed(static_cast<int64>(iters)*nbytes);
    158 }
    159 
    160 // These two are easy because they start with an A,
    161 // giving the search loop something to memchr for.
    162 #define EASY0      "ABCDEFGHIJKLMNOPQRSTUVWXYZ$"
    163 #define EASY1      "A[AB]B[BC]C[CD]D[DE]E[EF]F[FG]G[GH]H[HI]I[IJ]J$"
    164 
    165 // This is a little harder, since it starts with a character class
    166 // and thus can't be memchr'ed.  Could look for ABC and work backward,
    167 // but no one does that.
    168 #define MEDIUM     "[XYZ]ABCDEFGHIJKLMNOPQRSTUVWXYZ$"
    169 
    170 // This is a fair amount harder, because of the leading [ -~]*.
    171 // A bad backtracking implementation will take O(text^2) time to
    172 // figure out there's no match.
    173 #define HARD       "[ -~]*ABCDEFGHIJKLMNOPQRSTUVWXYZ$"
    174 
    175 // This stresses engines that are trying to track parentheses.
    176 #define PARENS     "([ -~])*(A)(B)(C)(D)(E)(F)(G)(H)(I)(J)(K)(L)(M)" \
    177                    "(N)(O)(P)(Q)(R)(S)(T)(U)(V)(W)(X)(Y)(Z)$"
    178 
    179 void Search_Easy0_CachedDFA(int i, int n)     { Search(i, n, EASY0, SearchCachedDFA); }
    180 void Search_Easy0_CachedNFA(int i, int n)     { Search(i, n, EASY0, SearchCachedNFA); }
    181 void Search_Easy0_CachedPCRE(int i, int n)    { Search(i, n, EASY0, SearchCachedPCRE); }
    182 void Search_Easy0_CachedRE2(int i, int n)     { Search(i, n, EASY0, SearchCachedRE2); }
    183 
    184 BENCHMARK_RANGE(Search_Easy0_CachedDFA,     8, 16<<20)->ThreadRange(1, NumCPUs());
    185 BENCHMARK_RANGE(Search_Easy0_CachedNFA,     8, 256<<10)->ThreadRange(1, NumCPUs());
    186 #ifdef USEPCRE
    187 BENCHMARK_RANGE(Search_Easy0_CachedPCRE,    8, 16<<20)->ThreadRange(1, NumCPUs());
    188 #endif
    189 BENCHMARK_RANGE(Search_Easy0_CachedRE2,     8, 16<<20)->ThreadRange(1, NumCPUs());
    190 
    191 void Search_Easy1_CachedDFA(int i, int n)     { Search(i, n, EASY1, SearchCachedDFA); }
    192 void Search_Easy1_CachedNFA(int i, int n)     { Search(i, n, EASY1, SearchCachedNFA); }
    193 void Search_Easy1_CachedPCRE(int i, int n)    { Search(i, n, EASY1, SearchCachedPCRE); }
    194 void Search_Easy1_CachedRE2(int i, int n)     { Search(i, n, EASY1, SearchCachedRE2); }
    195 
    196 BENCHMARK_RANGE(Search_Easy1_CachedDFA,     8, 16<<20)->ThreadRange(1, NumCPUs());
    197 BENCHMARK_RANGE(Search_Easy1_CachedNFA,     8, 256<<10)->ThreadRange(1, NumCPUs());
    198 #ifdef USEPCRE
    199 BENCHMARK_RANGE(Search_Easy1_CachedPCRE,    8, 16<<20)->ThreadRange(1, NumCPUs());
    200 #endif
    201 BENCHMARK_RANGE(Search_Easy1_CachedRE2,     8, 16<<20)->ThreadRange(1, NumCPUs());
    202 
    203 void Search_Medium_CachedDFA(int i, int n)     { Search(i, n, MEDIUM, SearchCachedDFA); }
    204 void Search_Medium_CachedNFA(int i, int n)     { Search(i, n, MEDIUM, SearchCachedNFA); }
    205 void Search_Medium_CachedPCRE(int i, int n)    { Search(i, n, MEDIUM, SearchCachedPCRE); }
    206 void Search_Medium_CachedRE2(int i, int n)     { Search(i, n, MEDIUM, SearchCachedRE2); }
    207 
    208 BENCHMARK_RANGE(Search_Medium_CachedDFA,     8, 16<<20)->ThreadRange(1, NumCPUs());
    209 BENCHMARK_RANGE(Search_Medium_CachedNFA,     8, 256<<10)->ThreadRange(1, NumCPUs());
    210 #ifdef USEPCRE
    211 BENCHMARK_RANGE(Search_Medium_CachedPCRE,    8, 256<<10)->ThreadRange(1, NumCPUs());
    212 #endif
    213 BENCHMARK_RANGE(Search_Medium_CachedRE2,     8, 16<<20)->ThreadRange(1, NumCPUs());
    214 
    215 void Search_Hard_CachedDFA(int i, int n)     { Search(i, n, HARD, SearchCachedDFA); }
    216 void Search_Hard_CachedNFA(int i, int n)     { Search(i, n, HARD, SearchCachedNFA); }
    217 void Search_Hard_CachedPCRE(int i, int n)    { Search(i, n, HARD, SearchCachedPCRE); }
    218 void Search_Hard_CachedRE2(int i, int n)     { Search(i, n, HARD, SearchCachedRE2); }
    219 
    220 BENCHMARK_RANGE(Search_Hard_CachedDFA,     8, 16<<20)->ThreadRange(1, NumCPUs());
    221 BENCHMARK_RANGE(Search_Hard_CachedNFA,     8, 256<<10)->ThreadRange(1, NumCPUs());
    222 #ifdef USEPCRE
    223 BENCHMARK_RANGE(Search_Hard_CachedPCRE,    8, 4<<10)->ThreadRange(1, NumCPUs());
    224 #endif
    225 BENCHMARK_RANGE(Search_Hard_CachedRE2,     8, 16<<20)->ThreadRange(1, NumCPUs());
    226 
    227 void Search_Parens_CachedDFA(int i, int n)     { Search(i, n, PARENS, SearchCachedDFA); }
    228 void Search_Parens_CachedNFA(int i, int n)     { Search(i, n, PARENS, SearchCachedNFA); }
    229 void Search_Parens_CachedPCRE(int i, int n)    { Search(i, n, PARENS, SearchCachedPCRE); }
    230 void Search_Parens_CachedRE2(int i, int n)     { Search(i, n, PARENS, SearchCachedRE2); }
    231 
    232 BENCHMARK_RANGE(Search_Parens_CachedDFA,     8, 16<<20)->ThreadRange(1, NumCPUs());
    233 BENCHMARK_RANGE(Search_Parens_CachedNFA,     8, 256<<10)->ThreadRange(1, NumCPUs());
    234 #ifdef USEPCRE
    235 BENCHMARK_RANGE(Search_Parens_CachedPCRE,    8, 8)->ThreadRange(1, NumCPUs());
    236 #endif
    237 BENCHMARK_RANGE(Search_Parens_CachedRE2,     8, 16<<20)->ThreadRange(1, NumCPUs());
    238 
    239 void SearchBigFixed(int iters, int nbytes, SearchImpl* search) {
    240   StopBenchmarkTiming();
    241   string s;
    242   s.append(nbytes/2, 'x');
    243   string regexp = "^" + s + ".*$";
    244   string t;
    245   MakeText(&t, nbytes/2);
    246   s += t;
    247   BenchmarkMemoryUsage();
    248   StartBenchmarkTiming();
    249   search(iters, regexp.c_str(), s, Prog::kUnanchored, true);
    250   SetBenchmarkBytesProcessed(static_cast<int64>(iters)*nbytes);
    251 }
    252 
    253 void Search_BigFixed_CachedDFA(int i, int n)     { SearchBigFixed(i, n, SearchCachedDFA); }
    254 void Search_BigFixed_CachedNFA(int i, int n)     { SearchBigFixed(i, n, SearchCachedNFA); }
    255 void Search_BigFixed_CachedPCRE(int i, int n)    { SearchBigFixed(i, n, SearchCachedPCRE); }
    256 void Search_BigFixed_CachedRE2(int i, int n)     { SearchBigFixed(i, n, SearchCachedRE2); }
    257 
    258 BENCHMARK_RANGE(Search_BigFixed_CachedDFA,     8, 1<<20)->ThreadRange(1, NumCPUs());
    259 BENCHMARK_RANGE(Search_BigFixed_CachedNFA,     8, 32<<10)->ThreadRange(1, NumCPUs());
    260 #ifdef USEPCRE
    261 BENCHMARK_RANGE(Search_BigFixed_CachedPCRE,    8, 32<<10)->ThreadRange(1, NumCPUs());
    262 #endif
    263 BENCHMARK_RANGE(Search_BigFixed_CachedRE2,     8, 1<<20)->ThreadRange(1, NumCPUs());
    264 
    265 // Benchmark: FindAndConsume
    266 void FindAndConsume(int iters, int nbytes) {
    267   StopBenchmarkTiming();
    268   string s;
    269   MakeText(&s, nbytes);
    270   s.append("Hello World");
    271   StartBenchmarkTiming();
    272   RE2 re("((Hello World))");
    273   for (int i = 0; i < iters; i++) {
    274     StringPiece t = s;
    275     StringPiece u;
    276     CHECK(RE2::FindAndConsume(&t, re, &u));
    277     CHECK_EQ(u, "Hello World");
    278   }
    279   SetBenchmarkBytesProcessed(static_cast<int64>(iters)*nbytes);
    280 }
    281 
    282 BENCHMARK_RANGE(FindAndConsume, 8, 16<<20)->ThreadRange(1, NumCPUs());
    283 
    284 // Benchmark: successful anchored search.
    285 
    286 void SearchSuccess(int iters, int nbytes, const char* regexp, SearchImpl* search) {
    287   string s;
    288   MakeText(&s, nbytes);
    289   BenchmarkMemoryUsage();
    290   search(iters, regexp, s, Prog::kAnchored, true);
    291   SetBenchmarkBytesProcessed(static_cast<int64>(iters)*nbytes);
    292 }
    293 
    294 // Unambiguous search (RE2 can use OnePass).
    295 
    296 void Search_Success_DFA(int i, int n)     { SearchSuccess(i, n, ".*$", SearchDFA); }
    297 void Search_Success_OnePass(int i, int n) { SearchSuccess(i, n, ".*$", SearchOnePass); }
    298 void Search_Success_PCRE(int i, int n)    { SearchSuccess(i, n, ".*$", SearchPCRE); }
    299 void Search_Success_RE2(int i, int n)     { SearchSuccess(i, n, ".*$", SearchRE2); }
    300 
    301 BENCHMARK_RANGE(Search_Success_DFA,     8, 16<<20)->ThreadRange(1, NumCPUs());
    302 #ifdef USEPCRE
    303 BENCHMARK_RANGE(Search_Success_PCRE,    8, 16<<20)->ThreadRange(1, NumCPUs());
    304 #endif
    305 BENCHMARK_RANGE(Search_Success_RE2,     8, 16<<20)->ThreadRange(1, NumCPUs());
    306 BENCHMARK_RANGE(Search_Success_OnePass, 8, 2<<20)->ThreadRange(1, NumCPUs());
    307 
    308 void Search_Success_CachedDFA(int i, int n)     { SearchSuccess(i, n, ".*$", SearchCachedDFA); }
    309 void Search_Success_CachedOnePass(int i, int n) { SearchSuccess(i, n, ".*$", SearchCachedOnePass); }
    310 void Search_Success_CachedPCRE(int i, int n)    { SearchSuccess(i, n, ".*$", SearchCachedPCRE); }
    311 void Search_Success_CachedRE2(int i, int n)     { SearchSuccess(i, n, ".*$", SearchCachedRE2); }
    312 
    313 BENCHMARK_RANGE(Search_Success_CachedDFA,     8, 16<<20)->ThreadRange(1, NumCPUs());
    314 #ifdef USEPCRE
    315 BENCHMARK_RANGE(Search_Success_CachedPCRE,    8, 16<<20)->ThreadRange(1, NumCPUs());
    316 #endif
    317 BENCHMARK_RANGE(Search_Success_CachedRE2,     8, 16<<20)->ThreadRange(1, NumCPUs());
    318 BENCHMARK_RANGE(Search_Success_CachedOnePass, 8, 2<<20)->ThreadRange(1, NumCPUs());
    319 
    320 // Ambiguous search (RE2 cannot use OnePass).
    321 
    322 void Search_Success1_DFA(int i, int n)     { SearchSuccess(i, n, ".*.$", SearchDFA); }
    323 void Search_Success1_PCRE(int i, int n)    { SearchSuccess(i, n, ".*.$", SearchPCRE); }
    324 void Search_Success1_RE2(int i, int n)     { SearchSuccess(i, n, ".*.$", SearchRE2); }
    325 void Search_Success1_BitState(int i, int n)     { SearchSuccess(i, n, ".*.$", SearchBitState); }
    326 
    327 BENCHMARK_RANGE(Search_Success1_DFA,     8, 16<<20)->ThreadRange(1, NumCPUs());
    328 #ifdef USEPCRE
    329 BENCHMARK_RANGE(Search_Success1_PCRE,    8, 16<<20)->ThreadRange(1, NumCPUs());
    330 #endif
    331 BENCHMARK_RANGE(Search_Success1_RE2,     8, 16<<20)->ThreadRange(1, NumCPUs());
    332 BENCHMARK_RANGE(Search_Success1_BitState, 8, 2<<20)->ThreadRange(1, NumCPUs());
    333 
    334 void Search_Success1_Cached_DFA(int i, int n)     { SearchSuccess(i, n, ".*.$", SearchCachedDFA); }
    335 void Search_Success1_Cached_PCRE(int i, int n)    { SearchSuccess(i, n, ".*.$", SearchCachedPCRE); }
    336 void Search_Success1_Cached_RE2(int i, int n)     { SearchSuccess(i, n, ".*.$", SearchCachedRE2); }
    337 
    338 BENCHMARK_RANGE(Search_Success1_Cached_DFA,     8, 16<<20)->ThreadRange(1, NumCPUs());
    339 #ifdef USEPCRE
    340 BENCHMARK_RANGE(Search_Success1_Cached_PCRE,    8, 16<<20)->ThreadRange(1, NumCPUs());
    341 #endif
    342 BENCHMARK_RANGE(Search_Success1_Cached_RE2,     8, 16<<20)->ThreadRange(1, NumCPUs());
    343 
    344 // Benchmark: use regexp to find phone number.
    345 
    346 void SearchDigits(int iters, SearchImpl* search) {
    347   const char *text = "650-253-0001";
    348   int len = strlen(text);
    349   BenchmarkMemoryUsage();
    350   search(iters, "([0-9]+)-([0-9]+)-([0-9]+)",
    351          StringPiece(text, len), Prog::kAnchored, true);
    352   SetBenchmarkItemsProcessed(iters);
    353 }
    354 
    355 void Search_Digits_DFA(int i)         { SearchDigits(i, SearchDFA); }
    356 void Search_Digits_NFA(int i)         { SearchDigits(i, SearchNFA); }
    357 void Search_Digits_OnePass(int i)     { SearchDigits(i, SearchOnePass); }
    358 void Search_Digits_PCRE(int i)        { SearchDigits(i, SearchPCRE); }
    359 void Search_Digits_RE2(int i)         { SearchDigits(i, SearchRE2); }
    360 void Search_Digits_BitState(int i)         { SearchDigits(i, SearchBitState); }
    361 
    362 BENCHMARK(Search_Digits_DFA)->ThreadRange(1, NumCPUs());
    363 BENCHMARK(Search_Digits_NFA)->ThreadRange(1, NumCPUs());
    364 BENCHMARK(Search_Digits_OnePass)->ThreadRange(1, NumCPUs());
    365 #ifdef USEPCRE
    366 BENCHMARK(Search_Digits_PCRE)->ThreadRange(1, NumCPUs());
    367 #endif
    368 BENCHMARK(Search_Digits_RE2)->ThreadRange(1, NumCPUs());
    369 BENCHMARK(Search_Digits_BitState)->ThreadRange(1, NumCPUs());
    370 
    371 // Benchmark: use regexp to parse digit fields in phone number.
    372 
    373 void Parse3Digits(int iters,
    374                void (*parse3)(int, const char*, const StringPiece&)) {
    375   BenchmarkMemoryUsage();
    376   parse3(iters, "([0-9]+)-([0-9]+)-([0-9]+)", "650-253-0001");
    377   SetBenchmarkItemsProcessed(iters);
    378 }
    379 
    380 void Parse_Digits_NFA(int i)         { Parse3Digits(i, Parse3NFA); }
    381 void Parse_Digits_OnePass(int i)     { Parse3Digits(i, Parse3OnePass); }
    382 void Parse_Digits_PCRE(int i)        { Parse3Digits(i, Parse3PCRE); }
    383 void Parse_Digits_RE2(int i)         { Parse3Digits(i, Parse3RE2); }
    384 void Parse_Digits_Backtrack(int i)   { Parse3Digits(i, Parse3Backtrack); }
    385 void Parse_Digits_BitState(int i)   { Parse3Digits(i, Parse3BitState); }
    386 
    387 BENCHMARK(Parse_Digits_NFA)->ThreadRange(1, NumCPUs());
    388 BENCHMARK(Parse_Digits_OnePass)->ThreadRange(1, NumCPUs());
    389 #ifdef USEPCRE
    390 BENCHMARK(Parse_Digits_PCRE)->ThreadRange(1, NumCPUs());
    391 #endif
    392 BENCHMARK(Parse_Digits_RE2)->ThreadRange(1, NumCPUs());
    393 BENCHMARK(Parse_Digits_Backtrack)->ThreadRange(1, NumCPUs());
    394 BENCHMARK(Parse_Digits_BitState)->ThreadRange(1, NumCPUs());
    395 
    396 void Parse_CachedDigits_NFA(int i)         { Parse3Digits(i, Parse3CachedNFA); }
    397 void Parse_CachedDigits_OnePass(int i)     { Parse3Digits(i, Parse3CachedOnePass); }
    398 void Parse_CachedDigits_PCRE(int i)        { Parse3Digits(i, Parse3CachedPCRE); }
    399 void Parse_CachedDigits_RE2(int i)         { Parse3Digits(i, Parse3CachedRE2); }
    400 void Parse_CachedDigits_Backtrack(int i)   { Parse3Digits(i, Parse3CachedBacktrack); }
    401 void Parse_CachedDigits_BitState(int i)   { Parse3Digits(i, Parse3CachedBitState); }
    402 
    403 BENCHMARK(Parse_CachedDigits_NFA)->ThreadRange(1, NumCPUs());
    404 BENCHMARK(Parse_CachedDigits_OnePass)->ThreadRange(1, NumCPUs());
    405 #ifdef USEPCRE
    406 BENCHMARK(Parse_CachedDigits_PCRE)->ThreadRange(1, NumCPUs());
    407 #endif
    408 BENCHMARK(Parse_CachedDigits_Backtrack)->ThreadRange(1, NumCPUs());
    409 BENCHMARK(Parse_CachedDigits_RE2)->ThreadRange(1, NumCPUs());
    410 BENCHMARK(Parse_CachedDigits_BitState)->ThreadRange(1, NumCPUs());
    411 
    412 void Parse3DigitDs(int iters,
    413                void (*parse3)(int, const char*, const StringPiece&)) {
    414   BenchmarkMemoryUsage();
    415   parse3(iters, "(\\d+)-(\\d+)-(\\d+)", "650-253-0001");
    416   SetBenchmarkItemsProcessed(iters);
    417 }
    418 
    419 void Parse_DigitDs_NFA(int i)         { Parse3DigitDs(i, Parse3NFA); }
    420 void Parse_DigitDs_OnePass(int i)     { Parse3DigitDs(i, Parse3OnePass); }
    421 void Parse_DigitDs_PCRE(int i)        { Parse3DigitDs(i, Parse3PCRE); }
    422 void Parse_DigitDs_RE2(int i)         { Parse3DigitDs(i, Parse3RE2); }
    423 void Parse_DigitDs_Backtrack(int i)   { Parse3DigitDs(i, Parse3CachedBacktrack); }
    424 void Parse_DigitDs_BitState(int i)   { Parse3DigitDs(i, Parse3CachedBitState); }
    425 
    426 BENCHMARK(Parse_DigitDs_NFA)->ThreadRange(1, NumCPUs());
    427 BENCHMARK(Parse_DigitDs_OnePass)->ThreadRange(1, NumCPUs());
    428 #ifdef USEPCRE
    429 BENCHMARK(Parse_DigitDs_PCRE)->ThreadRange(1, NumCPUs());
    430 #endif
    431 BENCHMARK(Parse_DigitDs_RE2)->ThreadRange(1, NumCPUs());
    432 BENCHMARK(Parse_DigitDs_Backtrack)->ThreadRange(1, NumCPUs());
    433 BENCHMARK(Parse_DigitDs_BitState)->ThreadRange(1, NumCPUs());
    434 
    435 void Parse_CachedDigitDs_NFA(int i)         { Parse3DigitDs(i, Parse3CachedNFA); }
    436 void Parse_CachedDigitDs_OnePass(int i)     { Parse3DigitDs(i, Parse3CachedOnePass); }
    437 void Parse_CachedDigitDs_PCRE(int i)        { Parse3DigitDs(i, Parse3CachedPCRE); }
    438 void Parse_CachedDigitDs_RE2(int i)         { Parse3DigitDs(i, Parse3CachedRE2); }
    439 void Parse_CachedDigitDs_Backtrack(int i)   { Parse3DigitDs(i, Parse3CachedBacktrack); }
    440 void Parse_CachedDigitDs_BitState(int i)   { Parse3DigitDs(i, Parse3CachedBitState); }
    441 
    442 BENCHMARK(Parse_CachedDigitDs_NFA)->ThreadRange(1, NumCPUs());
    443 BENCHMARK(Parse_CachedDigitDs_OnePass)->ThreadRange(1, NumCPUs());
    444 #ifdef USEPCRE
    445 BENCHMARK(Parse_CachedDigitDs_PCRE)->ThreadRange(1, NumCPUs());
    446 #endif
    447 BENCHMARK(Parse_CachedDigitDs_Backtrack)->ThreadRange(1, NumCPUs());
    448 BENCHMARK(Parse_CachedDigitDs_RE2)->ThreadRange(1, NumCPUs());
    449 BENCHMARK(Parse_CachedDigitDs_BitState)->ThreadRange(1, NumCPUs());
    450 
    451 // Benchmark: splitting off leading number field.
    452 
    453 void Parse1Split(int iters,
    454               void (*parse1)(int, const char*, const StringPiece&)) {
    455   BenchmarkMemoryUsage();
    456   parse1(iters, "[0-9]+-(.*)", "650-253-0001");
    457   SetBenchmarkItemsProcessed(iters);
    458 }
    459 
    460 void Parse_Split_NFA(int i)         { Parse1Split(i, Parse1NFA); }
    461 void Parse_Split_OnePass(int i)     { Parse1Split(i, Parse1OnePass); }
    462 void Parse_Split_PCRE(int i)        { Parse1Split(i, Parse1PCRE); }
    463 void Parse_Split_RE2(int i)         { Parse1Split(i, Parse1RE2); }
    464 void Parse_Split_BitState(int i)         { Parse1Split(i, Parse1BitState); }
    465 
    466 BENCHMARK(Parse_Split_NFA)->ThreadRange(1, NumCPUs());
    467 BENCHMARK(Parse_Split_OnePass)->ThreadRange(1, NumCPUs());
    468 #ifdef USEPCRE
    469 BENCHMARK(Parse_Split_PCRE)->ThreadRange(1, NumCPUs());
    470 #endif
    471 BENCHMARK(Parse_Split_RE2)->ThreadRange(1, NumCPUs());
    472 BENCHMARK(Parse_Split_BitState)->ThreadRange(1, NumCPUs());
    473 
    474 void Parse_CachedSplit_NFA(int i)         { Parse1Split(i, Parse1CachedNFA); }
    475 void Parse_CachedSplit_OnePass(int i)     { Parse1Split(i, Parse1CachedOnePass); }
    476 void Parse_CachedSplit_PCRE(int i)        { Parse1Split(i, Parse1CachedPCRE); }
    477 void Parse_CachedSplit_RE2(int i)         { Parse1Split(i, Parse1CachedRE2); }
    478 void Parse_CachedSplit_BitState(int i)         { Parse1Split(i, Parse1CachedBitState); }
    479 
    480 BENCHMARK(Parse_CachedSplit_NFA)->ThreadRange(1, NumCPUs());
    481 BENCHMARK(Parse_CachedSplit_OnePass)->ThreadRange(1, NumCPUs());
    482 #ifdef USEPCRE
    483 BENCHMARK(Parse_CachedSplit_PCRE)->ThreadRange(1, NumCPUs());
    484 #endif
    485 BENCHMARK(Parse_CachedSplit_RE2)->ThreadRange(1, NumCPUs());
    486 BENCHMARK(Parse_CachedSplit_BitState)->ThreadRange(1, NumCPUs());
    487 
    488 // Benchmark: splitting off leading number field but harder (ambiguous regexp).
    489 
    490 void Parse1SplitHard(int iters,
    491                   void (*run)(int, const char*, const StringPiece&)) {
    492   BenchmarkMemoryUsage();
    493   run(iters, "[0-9]+.(.*)", "650-253-0001");
    494   SetBenchmarkItemsProcessed(iters);
    495 }
    496 
    497 void Parse_SplitHard_NFA(int i)         { Parse1SplitHard(i, Parse1NFA); }
    498 void Parse_SplitHard_PCRE(int i)        { Parse1SplitHard(i, Parse1PCRE); }
    499 void Parse_SplitHard_RE2(int i)         { Parse1SplitHard(i, Parse1RE2); }
    500 void Parse_SplitHard_BitState(int i)         { Parse1SplitHard(i, Parse1BitState); }
    501 
    502 #ifdef USEPCRE
    503 BENCHMARK(Parse_SplitHard_PCRE)->ThreadRange(1, NumCPUs());
    504 #endif
    505 BENCHMARK(Parse_SplitHard_RE2)->ThreadRange(1, NumCPUs());
    506 BENCHMARK(Parse_SplitHard_BitState)->ThreadRange(1, NumCPUs());
    507 BENCHMARK(Parse_SplitHard_NFA)->ThreadRange(1, NumCPUs());
    508 
    509 void Parse_CachedSplitHard_NFA(int i)       { Parse1SplitHard(i, Parse1CachedNFA); }
    510 void Parse_CachedSplitHard_PCRE(int i)      { Parse1SplitHard(i, Parse1CachedPCRE); }
    511 void Parse_CachedSplitHard_RE2(int i)       { Parse1SplitHard(i, Parse1CachedRE2); }
    512 void Parse_CachedSplitHard_BitState(int i)       { Parse1SplitHard(i, Parse1CachedBitState); }
    513 void Parse_CachedSplitHard_Backtrack(int i)       { Parse1SplitHard(i, Parse1CachedBacktrack); }
    514 
    515 #ifdef USEPCRE
    516 BENCHMARK(Parse_CachedSplitHard_PCRE)->ThreadRange(1, NumCPUs());
    517 #endif
    518 BENCHMARK(Parse_CachedSplitHard_RE2)->ThreadRange(1, NumCPUs());
    519 BENCHMARK(Parse_CachedSplitHard_BitState)->ThreadRange(1, NumCPUs());
    520 BENCHMARK(Parse_CachedSplitHard_NFA)->ThreadRange(1, NumCPUs());
    521 BENCHMARK(Parse_CachedSplitHard_Backtrack)->ThreadRange(1, NumCPUs());
    522 
    523 // Benchmark: Parse1SplitHard, big text, small match.
    524 
    525 void Parse1SplitBig1(int iters,
    526                   void (*run)(int, const char*, const StringPiece&)) {
    527   string s;
    528   s.append(100000, 'x');
    529   s.append("650-253-0001");
    530   BenchmarkMemoryUsage();
    531   run(iters, "[0-9]+.(.*)", s);
    532   SetBenchmarkItemsProcessed(iters);
    533 }
    534 
    535 void Parse_CachedSplitBig1_PCRE(int i)      { Parse1SplitBig1(i, SearchParse1CachedPCRE); }
    536 void Parse_CachedSplitBig1_RE2(int i)       { Parse1SplitBig1(i, SearchParse1CachedRE2); }
    537 
    538 #ifdef USEPCRE
    539 BENCHMARK(Parse_CachedSplitBig1_PCRE)->ThreadRange(1, NumCPUs());
    540 #endif
    541 BENCHMARK(Parse_CachedSplitBig1_RE2)->ThreadRange(1, NumCPUs());
    542 
    543 // Benchmark: Parse1SplitHard, big text, big match.
    544 
    545 void Parse1SplitBig2(int iters,
    546                   void (*run)(int, const char*, const StringPiece&)) {
    547   string s;
    548   s.append("650-253-");
    549   s.append(100000, '0');
    550   BenchmarkMemoryUsage();
    551   run(iters, "[0-9]+.(.*)", s);
    552   SetBenchmarkItemsProcessed(iters);
    553 }
    554 
    555 void Parse_CachedSplitBig2_PCRE(int i)      { Parse1SplitBig2(i, SearchParse1CachedPCRE); }
    556 void Parse_CachedSplitBig2_RE2(int i)       { Parse1SplitBig2(i, SearchParse1CachedRE2); }
    557 
    558 #ifdef USEPCRE
    559 BENCHMARK(Parse_CachedSplitBig2_PCRE)->ThreadRange(1, NumCPUs());
    560 #endif
    561 BENCHMARK(Parse_CachedSplitBig2_RE2)->ThreadRange(1, NumCPUs());
    562 
    563 // Benchmark: measure time required to parse (but not execute)
    564 // a simple regular expression.
    565 
    566 void ParseRegexp(int iters, const string& regexp) {
    567   for (int i = 0; i < iters; i++) {
    568     Regexp* re = Regexp::Parse(regexp, Regexp::LikePerl, NULL);
    569     CHECK(re);
    570     re->Decref();
    571   }
    572 }
    573 
    574 void SimplifyRegexp(int iters, const string& regexp) {
    575   for (int i = 0; i < iters; i++) {
    576     Regexp* re = Regexp::Parse(regexp, Regexp::LikePerl, NULL);
    577     CHECK(re);
    578     Regexp* sre = re->Simplify();
    579     CHECK(sre);
    580     sre->Decref();
    581     re->Decref();
    582   }
    583 }
    584 
    585 void NullWalkRegexp(int iters, const string& regexp) {
    586   Regexp* re = Regexp::Parse(regexp, Regexp::LikePerl, NULL);
    587   CHECK(re);
    588   for (int i = 0; i < iters; i++) {
    589     re->NullWalk();
    590   }
    591   re->Decref();
    592 }
    593 
    594 void SimplifyCompileRegexp(int iters, const string& regexp) {
    595   for (int i = 0; i < iters; i++) {
    596     Regexp* re = Regexp::Parse(regexp, Regexp::LikePerl, NULL);
    597     CHECK(re);
    598     Regexp* sre = re->Simplify();
    599     CHECK(sre);
    600     Prog* prog = sre->CompileToProg(0);
    601     CHECK(prog);
    602     delete prog;
    603     sre->Decref();
    604     re->Decref();
    605   }
    606 }
    607 
    608 void CompileRegexp(int iters, const string& regexp) {
    609   for (int i = 0; i < iters; i++) {
    610     Regexp* re = Regexp::Parse(regexp, Regexp::LikePerl, NULL);
    611     CHECK(re);
    612     Prog* prog = re->CompileToProg(0);
    613     CHECK(prog);
    614     delete prog;
    615     re->Decref();
    616   }
    617 }
    618 
    619 void CompileToProg(int iters, const string& regexp) {
    620   Regexp* re = Regexp::Parse(regexp, Regexp::LikePerl, NULL);
    621   CHECK(re);
    622   for (int i = 0; i < iters; i++) {
    623     Prog* prog = re->CompileToProg(0);
    624     CHECK(prog);
    625     delete prog;
    626   }
    627   re->Decref();
    628 }
    629 
    630 void CompileByteMap(int iters, const string& regexp) {
    631   Regexp* re = Regexp::Parse(regexp, Regexp::LikePerl, NULL);
    632   CHECK(re);
    633   Prog* prog = re->CompileToProg(0);
    634   CHECK(prog);
    635   for (int i = 0; i < iters; i++) {
    636     prog->ComputeByteMap();
    637   }
    638   delete prog;
    639   re->Decref();
    640 }
    641 
    642 void CompilePCRE(int iters, const string& regexp) {
    643   for (int i = 0; i < iters; i++) {
    644     PCRE re(regexp, PCRE::UTF8);
    645     CHECK_EQ(re.error(), "");
    646   }
    647 }
    648 
    649 void CompileRE2(int iters, const string& regexp) {
    650   for (int i = 0; i < iters; i++) {
    651     RE2 re(regexp);
    652     CHECK_EQ(re.error(), "");
    653   }
    654 }
    655 
    656 void RunBuild(int iters, const string& regexp, void (*run)(int, const string&)) {
    657   run(iters, regexp);
    658   SetBenchmarkItemsProcessed(iters);
    659 }
    660 
    661 }  // namespace re2
    662 
    663 DEFINE_string(compile_regexp, "(.*)-(\\d+)-of-(\\d+)", "regexp for compile benchmarks");
    664 
    665 namespace re2 {
    666 
    667 void BM_PCRE_Compile(int i)      { RunBuild(i, FLAGS_compile_regexp, CompilePCRE); }
    668 void BM_Regexp_Parse(int i)      { RunBuild(i, FLAGS_compile_regexp, ParseRegexp); }
    669 void BM_Regexp_Simplify(int i)   { RunBuild(i, FLAGS_compile_regexp, SimplifyRegexp); }
    670 void BM_CompileToProg(int i)     { RunBuild(i, FLAGS_compile_regexp, CompileToProg); }
    671 void BM_CompileByteMap(int i)     { RunBuild(i, FLAGS_compile_regexp, CompileByteMap); }
    672 void BM_Regexp_Compile(int i)    { RunBuild(i, FLAGS_compile_regexp, CompileRegexp); }
    673 void BM_Regexp_SimplifyCompile(int i)   { RunBuild(i, FLAGS_compile_regexp, SimplifyCompileRegexp); }
    674 void BM_Regexp_NullWalk(int i)   { RunBuild(i, FLAGS_compile_regexp, NullWalkRegexp); }
    675 void BM_RE2_Compile(int i)       { RunBuild(i, FLAGS_compile_regexp, CompileRE2); }
    676 
    677 #ifdef USEPCRE
    678 BENCHMARK(BM_PCRE_Compile)->ThreadRange(1, NumCPUs());
    679 #endif
    680 BENCHMARK(BM_Regexp_Parse)->ThreadRange(1, NumCPUs());
    681 BENCHMARK(BM_Regexp_Simplify)->ThreadRange(1, NumCPUs());
    682 BENCHMARK(BM_CompileToProg)->ThreadRange(1, NumCPUs());
    683 BENCHMARK(BM_CompileByteMap)->ThreadRange(1, NumCPUs());
    684 BENCHMARK(BM_Regexp_Compile)->ThreadRange(1, NumCPUs());
    685 BENCHMARK(BM_Regexp_SimplifyCompile)->ThreadRange(1, NumCPUs());
    686 BENCHMARK(BM_Regexp_NullWalk)->ThreadRange(1, NumCPUs());
    687 BENCHMARK(BM_RE2_Compile)->ThreadRange(1, NumCPUs());
    688 
    689 
    690 // Makes text of size nbytes, then calls run to search
    691 // the text for regexp iters times.
    692 void SearchPhone(int iters, int nbytes, ParseImpl* search) {
    693   StopBenchmarkTiming();
    694   string s;
    695   MakeText(&s, nbytes);
    696   s.append("(650) 253-0001");
    697   BenchmarkMemoryUsage();
    698   StartBenchmarkTiming();
    699   search(iters, "(\\d{3}-|\\(\\d{3}\\)\\s+)(\\d{3}-\\d{4})", s);
    700   SetBenchmarkBytesProcessed(static_cast<int64>(iters)*nbytes);
    701 }
    702 
    703 void SearchPhone_CachedPCRE(int i, int n) {
    704   SearchPhone(i, n, SearchParse2CachedPCRE);
    705 }
    706 void SearchPhone_CachedRE2(int i, int n) {
    707   SearchPhone(i, n, SearchParse2CachedRE2);
    708 }
    709 
    710 #ifdef USEPCRE
    711 BENCHMARK_RANGE(SearchPhone_CachedPCRE, 8, 16<<20)->ThreadRange(1, NumCPUs());
    712 #endif
    713 BENCHMARK_RANGE(SearchPhone_CachedRE2, 8, 16<<20)->ThreadRange(1, NumCPUs());
    714 
    715 /*
    716 TODO(rsc): Make this work again.
    717 
    718 // Generates and returns a string over binary alphabet {0,1} that contains
    719 // all possible binary sequences of length n as subsequences.  The obvious
    720 // brute force method would generate a string of length n * 2^n, but this
    721 // generates a string of length n + 2^n - 1 called a De Bruijn cycle.
    722 // See Knuth, The Art of Computer Programming, Vol 2, Exercise 3.2.2 #17.
    723 static string DeBruijnString(int n) {
    724   CHECK_LT(n, 8*sizeof(int));
    725   CHECK_GT(n, 0);
    726 
    727   vector<bool> did(1<<n);
    728   for (int i = 0; i < 1<<n; i++)
    729     did[i] = false;
    730 
    731   string s;
    732   for (int i = 0; i < n-1; i++)
    733     s.append("0");
    734   int bits = 0;
    735   int mask = (1<<n) - 1;
    736   for (int i = 0; i < (1<<n); i++) {
    737     bits <<= 1;
    738     bits &= mask;
    739     if (!did[bits|1]) {
    740       bits |= 1;
    741       s.append("1");
    742     } else {
    743       s.append("0");
    744     }
    745     CHECK(!did[bits]);
    746     did[bits] = true;
    747   }
    748   return s;
    749 }
    750 
    751 void CacheFill(int iters, int n, SearchImpl *srch) {
    752   string s = DeBruijnString(n+1);
    753   string t;
    754   for (int i = n+1; i < 20; i++) {
    755     t = s + s;
    756     swap(s, t);
    757   }
    758   srch(iters, StringPrintf("0[01]{%d}$", n).c_str(), s,
    759        Prog::kUnanchored, true);
    760   SetBenchmarkBytesProcessed(static_cast<int64>(iters)*s.size());
    761 }
    762 
    763 void CacheFillPCRE(int i, int n) { CacheFill(i, n, SearchCachedPCRE); }
    764 void CacheFillRE2(int i, int n)  { CacheFill(i, n, SearchCachedRE2); }
    765 void CacheFillNFA(int i, int n)  { CacheFill(i, n, SearchCachedNFA); }
    766 void CacheFillDFA(int i, int n)  { CacheFill(i, n, SearchCachedDFA); }
    767 
    768 // BENCHMARK_WITH_ARG uses __LINE__ to generate distinct identifiers
    769 // for the static BenchmarkRegisterer, which makes it unusable inside
    770 // a macro like DO24 below.  MY_BENCHMARK_WITH_ARG uses the argument a
    771 // to make the identifiers distinct (only possible when 'a' is a simple
    772 // expression like 2, not like 1+1).
    773 #define MY_BENCHMARK_WITH_ARG(n, a) \
    774   bool __benchmark_ ## n ## a =     \
    775     (new ::testing::Benchmark(#n, NewPermanentCallback(&n)))->ThreadRange(1, NumCPUs());
    776 
    777 #define DO24(A, B) \
    778   A(B, 1);    A(B, 2);    A(B, 3);    A(B, 4);    A(B, 5);    A(B, 6);  \
    779   A(B, 7);    A(B, 8);    A(B, 9);    A(B, 10);   A(B, 11);   A(B, 12); \
    780   A(B, 13);   A(B, 14);   A(B, 15);   A(B, 16);   A(B, 17);   A(B, 18); \
    781   A(B, 19);   A(B, 20);   A(B, 21);   A(B, 22);   A(B, 23);   A(B, 24);
    782 
    783 DO24(MY_BENCHMARK_WITH_ARG, CacheFillPCRE)
    784 DO24(MY_BENCHMARK_WITH_ARG, CacheFillNFA)
    785 DO24(MY_BENCHMARK_WITH_ARG, CacheFillRE2)
    786 DO24(MY_BENCHMARK_WITH_ARG, CacheFillDFA)
    787 
    788 #undef DO24
    789 #undef MY_BENCHMARK_WITH_ARG
    790 */
    791 
    792 ////////////////////////////////////////////////////////////////////////
    793 //
    794 // Implementation routines.  Sad that there are so many,
    795 // but all the interfaces are slightly different.
    796 
    797 // Runs implementation to search for regexp in text, iters times.
    798 // Expect_match says whether the regexp should be found.
    799 // Anchored says whether to run an anchored search.
    800 
    801 void SearchDFA(int iters, const char* regexp, const StringPiece& text,
    802             Prog::Anchor anchor, bool expect_match) {
    803   for (int i = 0; i < iters; i++) {
    804     Regexp* re = Regexp::Parse(regexp, Regexp::LikePerl, NULL);
    805     CHECK(re);
    806     Prog* prog = re->CompileToProg(0);
    807     CHECK(prog);
    808     bool failed = false;
    809     CHECK_EQ(prog->SearchDFA(text, NULL, anchor, Prog::kFirstMatch,
    810                              NULL, &failed, NULL),
    811              expect_match);
    812     CHECK(!failed);
    813     delete prog;
    814     re->Decref();
    815   }
    816 }
    817 
    818 void SearchNFA(int iters, const char* regexp, const StringPiece& text,
    819             Prog::Anchor anchor, bool expect_match) {
    820   for (int i = 0; i < iters; i++) {
    821     Regexp* re = Regexp::Parse(regexp, Regexp::LikePerl, NULL);
    822     CHECK(re);
    823     Prog* prog = re->CompileToProg(0);
    824     CHECK(prog);
    825     CHECK_EQ(prog->SearchNFA(text, NULL, anchor, Prog::kFirstMatch, NULL, 0),
    826              expect_match);
    827     delete prog;
    828     re->Decref();
    829   }
    830 }
    831 
    832 void SearchOnePass(int iters, const char* regexp, const StringPiece& text,
    833             Prog::Anchor anchor, bool expect_match) {
    834   for (int i = 0; i < iters; i++) {
    835     Regexp* re = Regexp::Parse(regexp, Regexp::LikePerl, NULL);
    836     CHECK(re);
    837     Prog* prog = re->CompileToProg(0);
    838     CHECK(prog);
    839     CHECK(prog->IsOnePass());
    840     CHECK_EQ(prog->SearchOnePass(text, text, anchor, Prog::kFirstMatch, NULL, 0),
    841              expect_match);
    842     delete prog;
    843     re->Decref();
    844   }
    845 }
    846 
    847 void SearchBitState(int iters, const char* regexp, const StringPiece& text,
    848             Prog::Anchor anchor, bool expect_match) {
    849   for (int i = 0; i < iters; i++) {
    850     Regexp* re = Regexp::Parse(regexp, Regexp::LikePerl, NULL);
    851     CHECK(re);
    852     Prog* prog = re->CompileToProg(0);
    853     CHECK(prog);
    854     CHECK_EQ(prog->SearchBitState(text, text, anchor, Prog::kFirstMatch, NULL, 0),
    855              expect_match);
    856     delete prog;
    857     re->Decref();
    858   }
    859 }
    860 
    861 void SearchPCRE(int iters, const char* regexp, const StringPiece& text,
    862                 Prog::Anchor anchor, bool expect_match) {
    863   for (int i = 0; i < iters; i++) {
    864     PCRE re(regexp, PCRE::UTF8);
    865     CHECK_EQ(re.error(), "");
    866     if (anchor == Prog::kAnchored)
    867       CHECK_EQ(PCRE::FullMatch(text, re), expect_match);
    868     else
    869       CHECK_EQ(PCRE::PartialMatch(text, re), expect_match);
    870   }
    871 }
    872 
    873 void SearchRE2(int iters, const char* regexp, const StringPiece& text,
    874                Prog::Anchor anchor, bool expect_match) {
    875   for (int i = 0; i < iters; i++) {
    876     RE2 re(regexp);
    877     CHECK_EQ(re.error(), "");
    878     if (anchor == Prog::kAnchored)
    879       CHECK_EQ(RE2::FullMatch(text, re), expect_match);
    880     else
    881       CHECK_EQ(RE2::PartialMatch(text, re), expect_match);
    882   }
    883 }
    884 
    885 // SearchCachedXXX is like SearchXXX but only does the
    886 // regexp parsing and compiling once.  This lets us measure
    887 // search time without the per-regexp overhead.
    888 
    889 void SearchCachedDFA(int iters, const char* regexp, const StringPiece& text,
    890                      Prog::Anchor anchor, bool expect_match) {
    891   Regexp* re = Regexp::Parse(regexp, Regexp::LikePerl, NULL);
    892   CHECK(re);
    893   Prog* prog = re->CompileToProg(1LL<<31);
    894   CHECK(prog);
    895   for (int i = 0; i < iters; i++) {
    896     bool failed = false;
    897     CHECK_EQ(prog->SearchDFA(text, NULL, anchor,
    898                              Prog::kFirstMatch, NULL, &failed, NULL),
    899              expect_match);
    900     CHECK(!failed);
    901   }
    902   delete prog;
    903   re->Decref();
    904 }
    905 
    906 void SearchCachedNFA(int iters, const char* regexp, const StringPiece& text,
    907                      Prog::Anchor anchor, bool expect_match) {
    908   Regexp* re = Regexp::Parse(regexp, Regexp::LikePerl, NULL);
    909   CHECK(re);
    910   Prog* prog = re->CompileToProg(0);
    911   CHECK(prog);
    912   for (int i = 0; i < iters; i++) {
    913     CHECK_EQ(prog->SearchNFA(text, NULL, anchor, Prog::kFirstMatch, NULL, 0),
    914              expect_match);
    915   }
    916   delete prog;
    917   re->Decref();
    918 }
    919 
    920 void SearchCachedOnePass(int iters, const char* regexp, const StringPiece& text,
    921                      Prog::Anchor anchor, bool expect_match) {
    922   Regexp* re = Regexp::Parse(regexp, Regexp::LikePerl, NULL);
    923   CHECK(re);
    924   Prog* prog = re->CompileToProg(0);
    925   CHECK(prog);
    926   CHECK(prog->IsOnePass());
    927   for (int i = 0; i < iters; i++)
    928     CHECK_EQ(prog->SearchOnePass(text, text, anchor, Prog::kFirstMatch, NULL, 0),
    929              expect_match);
    930   delete prog;
    931   re->Decref();
    932 }
    933 
    934 void SearchCachedBitState(int iters, const char* regexp, const StringPiece& text,
    935                      Prog::Anchor anchor, bool expect_match) {
    936   Regexp* re = Regexp::Parse(regexp, Regexp::LikePerl, NULL);
    937   CHECK(re);
    938   Prog* prog = re->CompileToProg(0);
    939   CHECK(prog);
    940   for (int i = 0; i < iters; i++)
    941     CHECK_EQ(prog->SearchBitState(text, text, anchor, Prog::kFirstMatch, NULL, 0),
    942              expect_match);
    943   delete prog;
    944   re->Decref();
    945 }
    946 
    947 void SearchCachedPCRE(int iters, const char* regexp, const StringPiece& text,
    948                      Prog::Anchor anchor, bool expect_match) {
    949   PCRE re(regexp, PCRE::UTF8);
    950   CHECK_EQ(re.error(), "");
    951   for (int i = 0; i < iters; i++) {
    952     if (anchor == Prog::kAnchored)
    953       CHECK_EQ(PCRE::FullMatch(text, re), expect_match);
    954     else
    955       CHECK_EQ(PCRE::PartialMatch(text, re), expect_match);
    956   }
    957 }
    958 
    959 void SearchCachedRE2(int iters, const char* regexp, const StringPiece& text,
    960                      Prog::Anchor anchor, bool expect_match) {
    961   RE2 re(regexp);
    962   CHECK_EQ(re.error(), "");
    963   for (int i = 0; i < iters; i++) {
    964     if (anchor == Prog::kAnchored)
    965       CHECK_EQ(RE2::FullMatch(text, re), expect_match);
    966     else
    967       CHECK_EQ(RE2::PartialMatch(text, re), expect_match);
    968   }
    969 }
    970 
    971 
    972 // Runs implementation to full match regexp against text,
    973 // extracting three submatches.  Expects match always.
    974 
    975 void Parse3NFA(int iters, const char* regexp, const StringPiece& text) {
    976   for (int i = 0; i < iters; i++) {
    977     Regexp* re = Regexp::Parse(regexp, Regexp::LikePerl, NULL);
    978     CHECK(re);
    979     Prog* prog = re->CompileToProg(0);
    980     CHECK(prog);
    981     StringPiece sp[4];  // 4 because sp[0] is whole match.
    982     CHECK(prog->SearchNFA(text, NULL, Prog::kAnchored, Prog::kFullMatch, sp, 4));
    983     delete prog;
    984     re->Decref();
    985   }
    986 }
    987 
    988 void Parse3OnePass(int iters, const char* regexp, const StringPiece& text) {
    989   for (int i = 0; i < iters; i++) {
    990     Regexp* re = Regexp::Parse(regexp, Regexp::LikePerl, NULL);
    991     CHECK(re);
    992     Prog* prog = re->CompileToProg(0);
    993     CHECK(prog);
    994     CHECK(prog->IsOnePass());
    995     StringPiece sp[4];  // 4 because sp[0] is whole match.
    996     CHECK(prog->SearchOnePass(text, text, Prog::kAnchored, Prog::kFullMatch, sp, 4));
    997     delete prog;
    998     re->Decref();
    999   }
   1000 }
   1001 
   1002 void Parse3BitState(int iters, const char* regexp, const StringPiece& text) {
   1003   for (int i = 0; i < iters; i++) {
   1004     Regexp* re = Regexp::Parse(regexp, Regexp::LikePerl, NULL);
   1005     CHECK(re);
   1006     Prog* prog = re->CompileToProg(0);
   1007     CHECK(prog);
   1008     StringPiece sp[4];  // 4 because sp[0] is whole match.
   1009     CHECK(prog->SearchBitState(text, text, Prog::kAnchored, Prog::kFullMatch, sp, 4));
   1010     delete prog;
   1011     re->Decref();
   1012   }
   1013 }
   1014 
   1015 void Parse3Backtrack(int iters, const char* regexp, const StringPiece& text) {
   1016   for (int i = 0; i < iters; i++) {
   1017     Regexp* re = Regexp::Parse(regexp, Regexp::LikePerl, NULL);
   1018     CHECK(re);
   1019     Prog* prog = re->CompileToProg(0);
   1020     CHECK(prog);
   1021     StringPiece sp[4];  // 4 because sp[0] is whole match.
   1022     CHECK(prog->UnsafeSearchBacktrack(text, text, Prog::kAnchored, Prog::kFullMatch, sp, 4));
   1023     delete prog;
   1024     re->Decref();
   1025   }
   1026 }
   1027 
   1028 void Parse3PCRE(int iters, const char* regexp, const StringPiece& text) {
   1029   for (int i = 0; i < iters; i++) {
   1030     PCRE re(regexp, PCRE::UTF8);
   1031     CHECK_EQ(re.error(), "");
   1032     StringPiece sp1, sp2, sp3;
   1033     CHECK(PCRE::FullMatch(text, re, &sp1, &sp2, &sp3));
   1034   }
   1035 }
   1036 
   1037 void Parse3RE2(int iters, const char* regexp, const StringPiece& text) {
   1038   for (int i = 0; i < iters; i++) {
   1039     RE2 re(regexp);
   1040     CHECK_EQ(re.error(), "");
   1041     StringPiece sp1, sp2, sp3;
   1042     CHECK(RE2::FullMatch(text, re, &sp1, &sp2, &sp3));
   1043   }
   1044 }
   1045 
   1046 void Parse3CachedNFA(int iters, const char* regexp, const StringPiece& text) {
   1047   Regexp* re = Regexp::Parse(regexp, Regexp::LikePerl, NULL);
   1048   CHECK(re);
   1049   Prog* prog = re->CompileToProg(0);
   1050   CHECK(prog);
   1051   StringPiece sp[4];  // 4 because sp[0] is whole match.
   1052   for (int i = 0; i < iters; i++) {
   1053     CHECK(prog->SearchNFA(text, NULL, Prog::kAnchored, Prog::kFullMatch, sp, 4));
   1054   }
   1055   delete prog;
   1056   re->Decref();
   1057 }
   1058 
   1059 void Parse3CachedOnePass(int iters, const char* regexp, const StringPiece& text) {
   1060   Regexp* re = Regexp::Parse(regexp, Regexp::LikePerl, NULL);
   1061   CHECK(re);
   1062   Prog* prog = re->CompileToProg(0);
   1063   CHECK(prog);
   1064   CHECK(prog->IsOnePass());
   1065   StringPiece sp[4];  // 4 because sp[0] is whole match.
   1066   for (int i = 0; i < iters; i++)
   1067     CHECK(prog->SearchOnePass(text, text, Prog::kAnchored, Prog::kFullMatch, sp, 4));
   1068   delete prog;
   1069   re->Decref();
   1070 }
   1071 
   1072 void Parse3CachedBitState(int iters, const char* regexp, const StringPiece& text) {
   1073   Regexp* re = Regexp::Parse(regexp, Regexp::LikePerl, NULL);
   1074   CHECK(re);
   1075   Prog* prog = re->CompileToProg(0);
   1076   CHECK(prog);
   1077   StringPiece sp[4];  // 4 because sp[0] is whole match.
   1078   for (int i = 0; i < iters; i++)
   1079     CHECK(prog->SearchBitState(text, text, Prog::kAnchored, Prog::kFullMatch, sp, 4));
   1080   delete prog;
   1081   re->Decref();
   1082 }
   1083 
   1084 void Parse3CachedBacktrack(int iters, const char* regexp, const StringPiece& text) {
   1085   Regexp* re = Regexp::Parse(regexp, Regexp::LikePerl, NULL);
   1086   CHECK(re);
   1087   Prog* prog = re->CompileToProg(0);
   1088   CHECK(prog);
   1089   StringPiece sp[4];  // 4 because sp[0] is whole match.
   1090   for (int i = 0; i < iters; i++)
   1091     CHECK(prog->UnsafeSearchBacktrack(text, text, Prog::kAnchored, Prog::kFullMatch, sp, 4));
   1092   delete prog;
   1093   re->Decref();
   1094 }
   1095 
   1096 void Parse3CachedPCRE(int iters, const char* regexp, const StringPiece& text) {
   1097   PCRE re(regexp, PCRE::UTF8);
   1098   CHECK_EQ(re.error(), "");
   1099   StringPiece sp1, sp2, sp3;
   1100   for (int i = 0; i < iters; i++) {
   1101     CHECK(PCRE::FullMatch(text, re, &sp1, &sp2, &sp3));
   1102   }
   1103 }
   1104 
   1105 void Parse3CachedRE2(int iters, const char* regexp, const StringPiece& text) {
   1106   RE2 re(regexp);
   1107   CHECK_EQ(re.error(), "");
   1108   StringPiece sp1, sp2, sp3;
   1109   for (int i = 0; i < iters; i++) {
   1110     CHECK(RE2::FullMatch(text, re, &sp1, &sp2, &sp3));
   1111   }
   1112 }
   1113 
   1114 
   1115 // Runs implementation to full match regexp against text,
   1116 // extracting three submatches.  Expects match always.
   1117 
   1118 void Parse1NFA(int iters, const char* regexp, const StringPiece& text) {
   1119   for (int i = 0; i < iters; i++) {
   1120     Regexp* re = Regexp::Parse(regexp, Regexp::LikePerl, NULL);
   1121     CHECK(re);
   1122     Prog* prog = re->CompileToProg(0);
   1123     CHECK(prog);
   1124     StringPiece sp[2];  // 2 because sp[0] is whole match.
   1125     CHECK(prog->SearchNFA(text, NULL, Prog::kAnchored, Prog::kFullMatch, sp, 2));
   1126     delete prog;
   1127     re->Decref();
   1128   }
   1129 }
   1130 
   1131 void Parse1OnePass(int iters, const char* regexp, const StringPiece& text) {
   1132   for (int i = 0; i < iters; i++) {
   1133     Regexp* re = Regexp::Parse(regexp, Regexp::LikePerl, NULL);
   1134     CHECK(re);
   1135     Prog* prog = re->CompileToProg(0);
   1136     CHECK(prog);
   1137     CHECK(prog->IsOnePass());
   1138     StringPiece sp[2];  // 2 because sp[0] is whole match.
   1139     CHECK(prog->SearchOnePass(text, text, Prog::kAnchored, Prog::kFullMatch, sp, 2));
   1140     delete prog;
   1141     re->Decref();
   1142   }
   1143 }
   1144 
   1145 void Parse1BitState(int iters, const char* regexp, const StringPiece& text) {
   1146   for (int i = 0; i < iters; i++) {
   1147     Regexp* re = Regexp::Parse(regexp, Regexp::LikePerl, NULL);
   1148     CHECK(re);
   1149     Prog* prog = re->CompileToProg(0);
   1150     CHECK(prog);
   1151     StringPiece sp[2];  // 2 because sp[0] is whole match.
   1152     CHECK(prog->SearchBitState(text, text, Prog::kAnchored, Prog::kFullMatch, sp, 2));
   1153     delete prog;
   1154     re->Decref();
   1155   }
   1156 }
   1157 
   1158 void Parse1PCRE(int iters, const char* regexp, const StringPiece& text) {
   1159   for (int i = 0; i < iters; i++) {
   1160     PCRE re(regexp, PCRE::UTF8);
   1161     CHECK_EQ(re.error(), "");
   1162     StringPiece sp1;
   1163     CHECK(PCRE::FullMatch(text, re, &sp1));
   1164   }
   1165 }
   1166 
   1167 void Parse1RE2(int iters, const char* regexp, const StringPiece& text) {
   1168   for (int i = 0; i < iters; i++) {
   1169     RE2 re(regexp);
   1170     CHECK_EQ(re.error(), "");
   1171     StringPiece sp1;
   1172     CHECK(RE2::FullMatch(text, re, &sp1));
   1173   }
   1174 }
   1175 
   1176 void Parse1CachedNFA(int iters, const char* regexp, const StringPiece& text) {
   1177   Regexp* re = Regexp::Parse(regexp, Regexp::LikePerl, NULL);
   1178   CHECK(re);
   1179   Prog* prog = re->CompileToProg(0);
   1180   CHECK(prog);
   1181   StringPiece sp[2];  // 2 because sp[0] is whole match.
   1182   for (int i = 0; i < iters; i++) {
   1183     CHECK(prog->SearchNFA(text, NULL, Prog::kAnchored, Prog::kFullMatch, sp, 2));
   1184   }
   1185   delete prog;
   1186   re->Decref();
   1187 }
   1188 
   1189 void Parse1CachedOnePass(int iters, const char* regexp, const StringPiece& text) {
   1190   Regexp* re = Regexp::Parse(regexp, Regexp::LikePerl, NULL);
   1191   CHECK(re);
   1192   Prog* prog = re->CompileToProg(0);
   1193   CHECK(prog);
   1194   CHECK(prog->IsOnePass());
   1195   StringPiece sp[2];  // 2 because sp[0] is whole match.
   1196   for (int i = 0; i < iters; i++)
   1197     CHECK(prog->SearchOnePass(text, text, Prog::kAnchored, Prog::kFullMatch, sp, 2));
   1198   delete prog;
   1199   re->Decref();
   1200 }
   1201 
   1202 void Parse1CachedBitState(int iters, const char* regexp, const StringPiece& text) {
   1203   Regexp* re = Regexp::Parse(regexp, Regexp::LikePerl, NULL);
   1204   CHECK(re);
   1205   Prog* prog = re->CompileToProg(0);
   1206   CHECK(prog);
   1207   StringPiece sp[2];  // 2 because sp[0] is whole match.
   1208   for (int i = 0; i < iters; i++)
   1209     CHECK(prog->SearchBitState(text, text, Prog::kAnchored, Prog::kFullMatch, sp, 2));
   1210   delete prog;
   1211   re->Decref();
   1212 }
   1213 
   1214 void Parse1CachedBacktrack(int iters, const char* regexp, const StringPiece& text) {
   1215   Regexp* re = Regexp::Parse(regexp, Regexp::LikePerl, NULL);
   1216   CHECK(re);
   1217   Prog* prog = re->CompileToProg(0);
   1218   CHECK(prog);
   1219   StringPiece sp[2];  // 2 because sp[0] is whole match.
   1220   for (int i = 0; i < iters; i++)
   1221     CHECK(prog->UnsafeSearchBacktrack(text, text, Prog::kAnchored, Prog::kFullMatch, sp, 2));
   1222   delete prog;
   1223   re->Decref();
   1224 }
   1225 
   1226 void Parse1CachedPCRE(int iters, const char* regexp, const StringPiece& text) {
   1227   PCRE re(regexp, PCRE::UTF8);
   1228   CHECK_EQ(re.error(), "");
   1229   StringPiece sp1;
   1230   for (int i = 0; i < iters; i++) {
   1231     CHECK(PCRE::FullMatch(text, re, &sp1));
   1232   }
   1233 }
   1234 
   1235 void Parse1CachedRE2(int iters, const char* regexp, const StringPiece& text) {
   1236   RE2 re(regexp);
   1237   CHECK_EQ(re.error(), "");
   1238   StringPiece sp1;
   1239   for (int i = 0; i < iters; i++) {
   1240     CHECK(RE2::FullMatch(text, re, &sp1));
   1241   }
   1242 }
   1243 
   1244 void SearchParse2CachedPCRE(int iters, const char* regexp,
   1245                             const StringPiece& text) {
   1246   PCRE re(regexp, PCRE::UTF8);
   1247   CHECK_EQ(re.error(), "");
   1248   for (int i = 0; i < iters; i++) {
   1249     StringPiece sp1, sp2;
   1250     CHECK(PCRE::PartialMatch(text, re, &sp1, &sp2));
   1251   }
   1252 }
   1253 
   1254 void SearchParse2CachedRE2(int iters, const char* regexp,
   1255                            const StringPiece& text) {
   1256   RE2 re(regexp);
   1257   CHECK_EQ(re.error(), "");
   1258   for (int i = 0; i < iters; i++) {
   1259     StringPiece sp1, sp2;
   1260     CHECK(RE2::PartialMatch(text, re, &sp1, &sp2));
   1261   }
   1262 }
   1263 
   1264 void SearchParse1CachedPCRE(int iters, const char* regexp,
   1265                             const StringPiece& text) {
   1266   PCRE re(regexp, PCRE::UTF8);
   1267   CHECK_EQ(re.error(), "");
   1268   for (int i = 0; i < iters; i++) {
   1269     StringPiece sp1;
   1270     CHECK(PCRE::PartialMatch(text, re, &sp1));
   1271   }
   1272 }
   1273 
   1274 void SearchParse1CachedRE2(int iters, const char* regexp,
   1275                            const StringPiece& text) {
   1276   RE2 re(regexp);
   1277   CHECK_EQ(re.error(), "");
   1278   for (int i = 0; i < iters; i++) {
   1279     StringPiece sp1;
   1280     CHECK(RE2::PartialMatch(text, re, &sp1));
   1281   }
   1282 }
   1283 
   1284 void EmptyPartialMatchPCRE(int n) {
   1285   PCRE re("");
   1286   for (int i = 0; i < n; i++) {
   1287     PCRE::PartialMatch("", re);
   1288   }
   1289 }
   1290 
   1291 void EmptyPartialMatchRE2(int n) {
   1292   RE2 re("");
   1293   for (int i = 0; i < n; i++) {
   1294     RE2::PartialMatch("", re);
   1295   }
   1296 }
   1297 #ifdef USEPCRE
   1298 BENCHMARK(EmptyPartialMatchPCRE)->ThreadRange(1, NumCPUs());
   1299 #endif
   1300 BENCHMARK(EmptyPartialMatchRE2)->ThreadRange(1, NumCPUs());
   1301 
   1302 void SimplePartialMatchPCRE(int n) {
   1303   PCRE re("abcdefg");
   1304   for (int i = 0; i < n; i++) {
   1305     PCRE::PartialMatch("abcdefg", re);
   1306   }
   1307 }
   1308 
   1309 void SimplePartialMatchRE2(int n) {
   1310   RE2 re("abcdefg");
   1311   for (int i = 0; i < n; i++) {
   1312     RE2::PartialMatch("abcdefg", re);
   1313   }
   1314 }
   1315 #ifdef USEPCRE
   1316 BENCHMARK(SimplePartialMatchPCRE)->ThreadRange(1, NumCPUs());
   1317 #endif
   1318 BENCHMARK(SimplePartialMatchRE2)->ThreadRange(1, NumCPUs());
   1319 
   1320 static string http_text =
   1321   "GET /asdfhjasdhfasdlfhasdflkjasdfkljasdhflaskdjhf"
   1322   "alksdjfhasdlkfhasdlkjfhasdljkfhadsjklf HTTP/1.1";
   1323 
   1324 void HTTPPartialMatchPCRE(int n) {
   1325   StringPiece a;
   1326   PCRE re("(?-s)^(?:GET|POST) +([^ ]+) HTTP");
   1327   for (int i = 0; i < n; i++) {
   1328     PCRE::PartialMatch(http_text, re, &a);
   1329   }
   1330 }
   1331 
   1332 void HTTPPartialMatchRE2(int n) {
   1333   StringPiece a;
   1334   RE2 re("(?-s)^(?:GET|POST) +([^ ]+) HTTP");
   1335   for (int i = 0; i < n; i++) {
   1336     RE2::PartialMatch(http_text, re, &a);
   1337   }
   1338 }
   1339 
   1340 #ifdef USEPCRE
   1341 BENCHMARK(HTTPPartialMatchPCRE)->ThreadRange(1, NumCPUs());
   1342 #endif
   1343 BENCHMARK(HTTPPartialMatchRE2)->ThreadRange(1, NumCPUs());
   1344 
   1345 static string http_smalltext =
   1346   "GET /abc HTTP/1.1";
   1347 
   1348 void SmallHTTPPartialMatchPCRE(int n) {
   1349   StringPiece a;
   1350   PCRE re("(?-s)^(?:GET|POST) +([^ ]+) HTTP");
   1351   for (int i = 0; i < n; i++) {
   1352     PCRE::PartialMatch(http_text, re, &a);
   1353   }
   1354 }
   1355 
   1356 void SmallHTTPPartialMatchRE2(int n) {
   1357   StringPiece a;
   1358   RE2 re("(?-s)^(?:GET|POST) +([^ ]+) HTTP");
   1359   for (int i = 0; i < n; i++) {
   1360     RE2::PartialMatch(http_text, re, &a);
   1361   }
   1362 }
   1363 
   1364 #ifdef USEPCRE
   1365 BENCHMARK(SmallHTTPPartialMatchPCRE)->ThreadRange(1, NumCPUs());
   1366 #endif
   1367 BENCHMARK(SmallHTTPPartialMatchRE2)->ThreadRange(1, NumCPUs());
   1368 
   1369 void DotMatchPCRE(int n) {
   1370   StringPiece a;
   1371   PCRE re("(?-s)^(.+)");
   1372   for (int i = 0; i < n; i++) {
   1373     PCRE::PartialMatch(http_text, re, &a);
   1374   }
   1375 }
   1376 
   1377 void DotMatchRE2(int n) {
   1378   StringPiece a;
   1379   RE2 re("(?-s)^(.+)");
   1380   for (int i = 0; i < n; i++) {
   1381     RE2::PartialMatch(http_text, re, &a);
   1382   }
   1383 }
   1384 
   1385 #ifdef USEPCRE
   1386 BENCHMARK(DotMatchPCRE)->ThreadRange(1, NumCPUs());
   1387 #endif
   1388 BENCHMARK(DotMatchRE2)->ThreadRange(1, NumCPUs());
   1389 
   1390 void ASCIIMatchPCRE(int n) {
   1391   StringPiece a;
   1392   PCRE re("(?-s)^([ -~]+)");
   1393   for (int i = 0; i < n; i++) {
   1394     PCRE::PartialMatch(http_text, re, &a);
   1395   }
   1396 }
   1397 
   1398 void ASCIIMatchRE2(int n) {
   1399   StringPiece a;
   1400   RE2 re("(?-s)^([ -~]+)");
   1401   for (int i = 0; i < n; i++) {
   1402     RE2::PartialMatch(http_text, re, &a);
   1403   }
   1404 }
   1405 
   1406 #ifdef USEPCRE
   1407 BENCHMARK(ASCIIMatchPCRE)->ThreadRange(1, NumCPUs());
   1408 #endif
   1409 BENCHMARK(ASCIIMatchRE2)->ThreadRange(1, NumCPUs());
   1410 
   1411 void FullMatchPCRE(int iter, int n, const char *regexp) {
   1412   StopBenchmarkTiming();
   1413   string s;
   1414   MakeText(&s, n);
   1415   s += "ABCDEFGHIJ";
   1416   BenchmarkMemoryUsage();
   1417   PCRE re(regexp);
   1418   StartBenchmarkTiming();
   1419   for (int i = 0; i < iter; i++)
   1420     CHECK(PCRE::FullMatch(s, re));
   1421   SetBenchmarkBytesProcessed(static_cast<int64>(iter)*n);
   1422 }
   1423 
   1424 void FullMatchRE2(int iter, int n, const char *regexp) {
   1425   StopBenchmarkTiming();
   1426   string s;
   1427   MakeText(&s, n);
   1428   s += "ABCDEFGHIJ";
   1429   BenchmarkMemoryUsage();
   1430   RE2 re(regexp, RE2::Latin1);
   1431   StartBenchmarkTiming();
   1432   for (int i = 0; i < iter; i++)
   1433     CHECK(RE2::FullMatch(s, re));
   1434   SetBenchmarkBytesProcessed(static_cast<int64>(iter)*n);
   1435 }
   1436 
   1437 void FullMatch_DotStar_CachedPCRE(int i, int n) { FullMatchPCRE(i, n, "(?s).*"); }
   1438 void FullMatch_DotStar_CachedRE2(int i, int n)  { FullMatchRE2(i, n, "(?s).*"); }
   1439 
   1440 void FullMatch_DotStarDollar_CachedPCRE(int i, int n) { FullMatchPCRE(i, n, "(?s).*$"); }
   1441 void FullMatch_DotStarDollar_CachedRE2(int i, int n)  { FullMatchRE2(i, n, "(?s).*$"); }
   1442 
   1443 void FullMatch_DotStarCapture_CachedPCRE(int i, int n) { FullMatchPCRE(i, n, "(?s)((.*)()()($))"); }
   1444 void FullMatch_DotStarCapture_CachedRE2(int i, int n)  { FullMatchRE2(i, n, "(?s)((.*)()()($))"); }
   1445 
   1446 #ifdef USEPCRE
   1447 BENCHMARK_RANGE(FullMatch_DotStar_CachedPCRE, 8, 2<<20);
   1448 #endif
   1449 BENCHMARK_RANGE(FullMatch_DotStar_CachedRE2,  8, 2<<20);
   1450 
   1451 #ifdef USEPCRE
   1452 BENCHMARK_RANGE(FullMatch_DotStarDollar_CachedPCRE, 8, 2<<20);
   1453 #endif
   1454 BENCHMARK_RANGE(FullMatch_DotStarDollar_CachedRE2,  8, 2<<20);
   1455 
   1456 #ifdef USEPCRE
   1457 BENCHMARK_RANGE(FullMatch_DotStarCapture_CachedPCRE, 8, 2<<20);
   1458 #endif
   1459 BENCHMARK_RANGE(FullMatch_DotStarCapture_CachedRE2,  8, 2<<20);
   1460 
   1461 }  // namespace re2
   1462