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
29using namespace std;
30
31const char kTestFilename[] = "BuildLogPerfTest-tempfile";
32
33struct NoDeadPaths : public BuildLogUser {
34 virtual bool IsPathDead(StringPiece) const { return false; }
35};
36
37bool 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
103int 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
147 unlink(kTestFilename);
148
149 return 0;
150}
151