Imported Upstream version 1.7.1
[platform/upstream/ninja.git] / src / build_log_perftest.cc
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, kDupeEdgeActionWarn);
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