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 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 
148 
149  return 0;
150 }
const char kTestFilename[]
bool WriteTestData(string *err)
int main()
@ LOAD_ERROR
Definition: load_status.h:19
int64_t GetTimeMillis()
Get the current time as relative to some epoch.
Definition: metrics.cc:111
Definition: hash_map.h:26
Can answer questions about the manifest for the BuildLog.
Definition: build_log.h:32
Store a log of every command ran for every build.
Definition: build_log.h:45
LoadStatus Load(const std::string &path, std::string *err)
Load the on-disk log.
Definition: build_log.cc:208
bool OpenForWrite(const std::string &path, const BuildLogUser &user, std::string *err)
Prepares writing to the log file without actually opening it - that will happen when/if it's needed.
Definition: build_log.cc:77
bool RecordCommand(Edge *edge, int start_time, int end_time, TimeStamp mtime=0)
Definition: build_log.cc:90
Parses .ninja files.
bool ParseTest(const std::string &input, std::string *err)
Parse a text string of input. Used by tests.
virtual bool IsPathDead(StringPiece) const
Return if a given output is no longer part of the build manifest.
Global state (file status) for a single run.
Definition: state.h:95
std::vector< Edge * > edges_
All the edges of the graph.
Definition: state.h:138
StringPiece represents a slice of a string whose memory is managed externally.
Definition: string_piece.h:25
int platformAwareUnlink(const char *filename)
Definition: util.cc:1025
signed long long int64_t
A 64-bit integer type.
Definition: win32port.h:28