Ninja
build_log_perftest.cc
Go to the documentation of this file.
00001 // Copyright 2012 Google Inc. All Rights Reserved.
00002 //
00003 // Licensed under the Apache License, Version 2.0 (the "License");
00004 // you may not use this file except in compliance with the License.
00005 // You may obtain a copy of the License at
00006 //
00007 //     http://www.apache.org/licenses/LICENSE-2.0
00008 //
00009 // Unless required by applicable law or agreed to in writing, software
00010 // distributed under the License is distributed on an "AS IS" BASIS,
00011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00012 // See the License for the specific language governing permissions and
00013 // limitations under the License.
00014 
00015 #include <stdio.h>
00016 #include <stdlib.h>
00017 
00018 #include "build_log.h"
00019 #include "graph.h"
00020 #include "manifest_parser.h"
00021 #include "state.h"
00022 #include "util.h"
00023 #include "metrics.h"
00024 
00025 #ifndef _WIN32
00026 #include <unistd.h>
00027 #endif
00028 
00029 const char kTestFilename[] = "BuildLogPerfTest-tempfile";
00030 
00031 bool WriteTestData(string* err) {
00032   BuildLog log;
00033 
00034   if (!log.OpenForWrite(kTestFilename, err))
00035     return false;
00036 
00037   /*
00038   A histogram of command lengths in chromium. For example, 407 builds,
00039   1.4% of all builds, had commands longer than 32 bytes but shorter than 64.
00040        32    407   1.4%
00041        64    183   0.6%
00042       128   1461   5.1%
00043       256    791   2.8%
00044       512   1314   4.6%
00045      1024   6114  21.3%
00046      2048  11759  41.0%
00047      4096   2056   7.2%
00048      8192   4567  15.9%
00049     16384     13   0.0%
00050     32768      4   0.0%
00051     65536      5   0.0%
00052   The average command length is 4.1 kB and there were 28674 commands in total,
00053   which makes for a total log size of ~120 MB (also counting output filenames).
00054 
00055   Based on this, write 30000 many 4 kB long command lines.
00056   */
00057 
00058   // ManifestParser is the only object allowed to create Rules.
00059   const size_t kRuleSize = 4000;
00060   string long_rule_command = "gcc ";
00061   for (int i = 0; long_rule_command.size() < kRuleSize; ++i) {
00062     char buf[80];
00063     sprintf(buf, "-I../../and/arbitrary/but/fairly/long/path/suffixed/%d ", i);
00064     long_rule_command += buf;
00065   }
00066   long_rule_command += "$in -o $out\n";
00067 
00068   State state;
00069   ManifestParser parser(&state, NULL);
00070   if (!parser.ParseTest("rule cxx\n  command = " + long_rule_command, err))
00071     return false;
00072 
00073   // Create build edges. Using ManifestParser is as fast as using the State api
00074   // for edge creation, so just use that.
00075   const int kNumCommands = 30000;
00076   string build_rules;
00077   for (int i = 0; i < kNumCommands; ++i) {
00078     char buf[80];
00079     sprintf(buf, "build input%d.o: cxx input%d.cc\n", i, i);
00080     build_rules += buf;
00081   }
00082 
00083   if (!parser.ParseTest(build_rules, err))
00084     return false;
00085 
00086   for (int i = 0; i < kNumCommands; ++i) {
00087     log.RecordCommand(state.edges_[i],
00088                       /*start_time=*/100 * i,
00089                       /*end_time=*/100 * i + 1,
00090                       /*restat_mtime=*/0);
00091   }
00092 
00093   return true;
00094 }
00095 
00096 int main() {
00097   vector<int> times;
00098   string err;
00099 
00100   if (!WriteTestData(&err)) {
00101     fprintf(stderr, "Failed to write test data: %s\n", err.c_str());
00102     return 1;
00103   }
00104 
00105   {
00106     // Read once to warm up disk cache.
00107     BuildLog log;
00108     if (!log.Load(kTestFilename, &err)) {
00109       fprintf(stderr, "Failed to read test data: %s\n", err.c_str());
00110       return 1;
00111     }
00112   }
00113   const int kNumRepetitions = 5;
00114   for (int i = 0; i < kNumRepetitions; ++i) {
00115     int64_t start = GetTimeMillis();
00116     BuildLog log;
00117     if (!log.Load(kTestFilename, &err)) {
00118       fprintf(stderr, "Failed to read test data: %s\n", err.c_str());
00119       return 1;
00120     }
00121     int delta = (int)(GetTimeMillis() - start);
00122     printf("%dms\n", delta);
00123     times.push_back(delta);
00124   }
00125 
00126   int min = times[0];
00127   int max = times[0];
00128   float total = 0;
00129   for (size_t i = 0; i < times.size(); ++i) {
00130     total += times[i];
00131     if (times[i] < min)
00132       min = times[i];
00133     else if (times[i] > max)
00134       max = times[i];
00135   }
00136 
00137   printf("min %dms  max %dms  avg %.1fms\n",
00138          min, max, total / times.size());
00139 
00140   unlink(kTestFilename);
00141 
00142   return 0;
00143 }
00144