github.com/maruel/nin@v0.0.0-20220112143044-f35891e3ce7e/src/build_log_perftest.cc (about)

     1  // Copyright 2012 Google Inc. All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  #include <stdio.h>
    16  #include <stdlib.h>
    17  
    18  #include "build_log.h"
    19  #include "graph.h"
    20  #include "manifest_parser.h"
    21  #include "state.h"
    22  #include "util.h"
    23  #include "metrics.h"
    24  
    25  #ifndef _WIN32
    26  #include <unistd.h>
    27  #endif
    28  
    29  using namespace std;
    30  
    31  const char kTestFilename[] = "BuildLogPerfTest-tempfile";
    32  
    33  struct NoDeadPaths : public BuildLogUser {
    34    virtual bool IsPathDead(StringPiece) const { return false; }
    35  };
    36  
    37  bool WriteTestData(string* err) {
    38    BuildLog log;
    39  
    40    NoDeadPaths no_dead_paths;
    41    if (!log.OpenForWrite(kTestFilename, no_dead_paths, err))
    42      return false;
    43  
    44    /*
    45    A histogram of command lengths in chromium. For example, 407 builds,
    46    1.4% of all builds, had commands longer than 32 bytes but shorter than 64.
    47         32    407   1.4%
    48         64    183   0.6%
    49        128   1461   5.1%
    50        256    791   2.8%
    51        512   1314   4.6%
    52       1024   6114  21.3%
    53       2048  11759  41.0%
    54       4096   2056   7.2%
    55       8192   4567  15.9%
    56      16384     13   0.0%
    57      32768      4   0.0%
    58      65536      5   0.0%
    59    The average command length is 4.1 kB and there were 28674 commands in total,
    60    which makes for a total log size of ~120 MB (also counting output filenames).
    61  
    62    Based on this, write 30000 many 4 kB long command lines.
    63    */
    64  
    65    // ManifestParser is the only object allowed to create Rules.
    66    const size_t kRuleSize = 4000;
    67    string long_rule_command = "gcc ";
    68    for (int i = 0; long_rule_command.size() < kRuleSize; ++i) {
    69      char buf[80];
    70      sprintf(buf, "-I../../and/arbitrary/but/fairly/long/path/suffixed/%d ", i);
    71      long_rule_command += buf;
    72    }
    73    long_rule_command += "$in -o $out\n";
    74  
    75    State state;
    76    ManifestParser parser(&state, NULL);
    77    if (!parser.ParseTest("rule cxx\n  command = " + long_rule_command, err))
    78      return false;
    79  
    80    // Create build edges. Using ManifestParser is as fast as using the State api
    81    // for edge creation, so just use that.
    82    const int kNumCommands = 30000;
    83    string build_rules;
    84    for (int i = 0; i < kNumCommands; ++i) {
    85      char buf[80];
    86      sprintf(buf, "build input%d.o: cxx input%d.cc\n", i, i);
    87      build_rules += buf;
    88    }
    89  
    90    if (!parser.ParseTest(build_rules, err))
    91      return false;
    92  
    93    for (int i = 0; i < kNumCommands; ++i) {
    94      log.RecordCommand(state.edges_[i],
    95                        /*start_time=*/100 * i,
    96                        /*end_time=*/100 * i + 1,
    97                        /*mtime=*/0);
    98    }
    99  
   100    return true;
   101  }
   102  
   103  int main() {
   104    vector<int> times;
   105    string err;
   106  
   107    if (!WriteTestData(&err)) {
   108      fprintf(stderr, "Failed to write test data: %s\n", err.c_str());
   109      return 1;
   110    }
   111  
   112    {
   113      // Read once to warm up disk cache.
   114      BuildLog log;
   115      if (log.Load(kTestFilename, &err) == LOAD_ERROR) {
   116        fprintf(stderr, "Failed to read test data: %s\n", err.c_str());
   117        return 1;
   118      }
   119    }
   120    const int kNumRepetitions = 5;
   121    for (int i = 0; i < kNumRepetitions; ++i) {
   122      int64_t start = GetTimeMillis();
   123      BuildLog log;
   124      if (log.Load(kTestFilename, &err) == LOAD_ERROR) {
   125        fprintf(stderr, "Failed to read test data: %s\n", err.c_str());
   126        return 1;
   127      }
   128      int delta = (int)(GetTimeMillis() - start);
   129      printf("%dms\n", delta);
   130      times.push_back(delta);
   131    }
   132  
   133    int min = times[0];
   134    int max = times[0];
   135    float total = 0;
   136    for (size_t i = 0; i < times.size(); ++i) {
   137      total += times[i];
   138      if (times[i] < min)
   139        min = times[i];
   140      else if (times[i] > max)
   141        max = times[i];
   142    }
   143  
   144    printf("min %dms  max %dms  avg %.1fms\n",
   145           min, max, total / times.size());
   146  
   147    unlink(kTestFilename);
   148  
   149    return 0;
   150  }