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 {
IsPathDeadNoDeadPaths32 virtual bool IsPathDead(StringPiece) const { return false; }
33 };
34
WriteTestData(string * err)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 /*mtime=*/0);
96 }
97
98 return true;
99 }
100
main()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
150