Ninja
build_log_perftest.cc
Go to the documentation of this file.
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 const char kTestFilename[] = "BuildLogPerfTest-tempfile";
30 
31 struct NoDeadPaths : public BuildLogUser {
32  virtual bool IsPathDead(StringPiece) const { return false; }
33 };
34 
35 bool WriteTestData(string* err) {
36  BuildLog log;
37 
38  NoDeadPaths no_dead_paths;
39  if (!log.OpenForWrite(kTestFilename, no_dead_paths, err))
40  return false;
41 
42  /*
43  A histogram of command lengths in chromium. For example, 407 builds,
44  1.4% of all builds, had commands longer than 32 bytes but shorter than 64.
45  32 407 1.4%
46  64 183 0.6%
47  128 1461 5.1%
48  256 791 2.8%
49  512 1314 4.6%
50  1024 6114 21.3%
51  2048 11759 41.0%
52  4096 2056 7.2%
53  8192 4567 15.9%
54  16384 13 0.0%
55  32768 4 0.0%
56  65536 5 0.0%
57  The average command length is 4.1 kB and there were 28674 commands in total,
58  which makes for a total log size of ~120 MB (also counting output filenames).
59 
60  Based on this, write 30000 many 4 kB long command lines.
61  */
62 
63  // ManifestParser is the only object allowed to create Rules.
64  const size_t kRuleSize = 4000;
65  string long_rule_command = "gcc ";
66  for (int i = 0; long_rule_command.size() < kRuleSize; ++i) {
67  char buf[80];
68  sprintf(buf, "-I../../and/arbitrary/but/fairly/long/path/suffixed/%d ", i);
69  long_rule_command += buf;
70  }
71  long_rule_command += "$in -o $out\n";
72 
73  State state;
74  ManifestParser parser(&state, NULL);
75  if (!parser.ParseTest("rule cxx\n command = " + long_rule_command, err))
76  return false;
77 
78  // Create build edges. Using ManifestParser is as fast as using the State api
79  // for edge creation, so just use that.
80  const int kNumCommands = 30000;
81  string build_rules;
82  for (int i = 0; i < kNumCommands; ++i) {
83  char buf[80];
84  sprintf(buf, "build input%d.o: cxx input%d.cc\n", i, i);
85  build_rules += buf;
86  }
87 
88  if (!parser.ParseTest(build_rules, err))
89  return false;
90 
91  for (int i = 0; i < kNumCommands; ++i) {
92  log.RecordCommand(state.edges_[i],
93  /*start_time=*/100 * i,
94  /*end_time=*/100 * i + 1,
95  /*restat_mtime=*/0);
96  }
97 
98  return true;
99 }
100 
101 int main() {
102  vector<int> times;
103  string err;
104 
105  if (!WriteTestData(&err)) {
106  fprintf(stderr, "Failed to write test data: %s\n", err.c_str());
107  return 1;
108  }
109 
110  {
111  // Read once to warm up disk cache.
112  BuildLog log;
113  if (!log.Load(kTestFilename, &err)) {
114  fprintf(stderr, "Failed to read test data: %s\n", err.c_str());
115  return 1;
116  }
117  }
118  const int kNumRepetitions = 5;
119  for (int i = 0; i < kNumRepetitions; ++i) {
120  int64_t start = GetTimeMillis();
121  BuildLog log;
122  if (!log.Load(kTestFilename, &err)) {
123  fprintf(stderr, "Failed to read test data: %s\n", err.c_str());
124  return 1;
125  }
126  int delta = (int)(GetTimeMillis() - start);
127  printf("%dms\n", delta);
128  times.push_back(delta);
129  }
130 
131  int min = times[0];
132  int max = times[0];
133  float total = 0;
134  for (size_t i = 0; i < times.size(); ++i) {
135  total += times[i];
136  if (times[i] < min)
137  min = times[i];
138  else if (times[i] > max)
139  max = times[i];
140  }
141 
142  printf("min %dms max %dms avg %.1fms\n",
143  min, max, total / times.size());
144 
145  unlink(kTestFilename);
146 
147  return 0;
148 }
149 
vector< Edge * > edges_
All the edges of the graph.
Definition: state.h:129
int main()
StringPiece represents a slice of a string whose memory is managed externally.
Definition: string_piece.h:27
int64_t GetTimeMillis()
Get the current time as relative to some epoch.
Definition: metrics.cc:124
Store a log of every command ran for every build.
Definition: build_log.h:42
signed long long int64_t
A 64-bit integer type.
Definition: win32port.h:21
Parses .ninja files.
bool OpenForWrite(const string &path, const BuildLogUser &user, string *err)
Definition: build_log.cc:111
bool WriteTestData(string *err)
virtual bool IsPathDead(StringPiece) const
Return if a given output no longer part of the build manifest.
const char kTestFilename[]
bool RecordCommand(Edge *edge, int start_time, int end_time, TimeStamp restat_mtime=0)
Definition: build_log.cc:140
Global state (file status, loaded rules) for a single run.
Definition: state.h:83
bool Load(const string &path, string *err)
Load the on-disk log.
Definition: build_log.cc:225
bool ParseTest(const string &input, string *err)
Parse a text string of input. Used by tests.
Can answer questions about the manifest for the BuildLog.
Definition: build_log.h:29