Skip to content
This repository was archived by the owner on Jun 15, 2023. It is now read-only.

Commit 1e9124b

Browse files
committed
Add a BuildLog loading perftest.
1 parent 3b0e78a commit 1e9124b

File tree

3 files changed

+146
-3
lines changed

3 files changed

+146
-3
lines changed

configure.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -313,13 +313,17 @@ def binary(name):
313313
all_targets += ninja_test
314314

315315

316-
n.comment('Perftest executable.')
316+
n.comment('Perftest executables.')
317317
objs = cxx('parser_perftest')
318318
parser_perftest = n.build(binary('parser_perftest'), 'link', objs,
319319
implicit=ninja_lib,
320320
variables=[('libs', '-L$builddir -lninja')])
321+
objs = cxx('build_log_perftest')
322+
build_log_perftest = n.build(binary('build_log_perftest'), 'link', objs,
323+
implicit=ninja_lib,
324+
variables=[('libs', '-L$builddir -lninja')])
321325
n.newline()
322-
all_targets += parser_perftest
326+
all_targets += parser_perftest + build_log_perftest
323327

324328
n.comment('Generate a graph using the "graph" tool.')
325329
n.rule('gendot',

src/build_log_perftest.cc

+139
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
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 "parsers.h"
21+
#include "state.h"
22+
#include "util.h"
23+
24+
const char kTestFilename[] = "BuildLogPerfTest-tempfile";
25+
26+
bool WriteTestData(string* err) {
27+
BuildLog log;
28+
29+
if (!log.OpenForWrite(kTestFilename, err))
30+
return false;
31+
32+
/*
33+
A histogram of command lengths in chromium. For example, 407 builds,
34+
1.4% of all builds, had commands longer than 32 bytes but shorter than 64.
35+
32 407 1.4%
36+
64 183 0.6%
37+
128 1461 5.1%
38+
256 791 2.8%
39+
512 1314 4.6%
40+
1024 6114 21.3%
41+
2048 11759 41.0%
42+
4096 2056 7.2%
43+
8192 4567 15.9%
44+
16384 13 0.0%
45+
32768 4 0.0%
46+
65536 5 0.0%
47+
The average command length is 4.1 kB and there were 28674 commands in total,
48+
which makes for a total log size of ~120 MB (also counting output filenames).
49+
50+
Based on this, write 30000 many 4 kB long command lines.
51+
*/
52+
53+
// ManifestParser is the only object allowed to create Rules.
54+
const size_t kRuleSize = 4000;
55+
string long_rule_command = "gcc ";
56+
for (int i = 0; long_rule_command.size() < kRuleSize; ++i) {
57+
char buf[80];
58+
sprintf(buf, "-I../../and/arbitrary/but/fairly/long/path/suffixed/%d ", i);
59+
long_rule_command += buf;
60+
}
61+
long_rule_command += "$in -o $out\n";
62+
63+
State state;
64+
ManifestParser parser(&state, NULL);
65+
if (!parser.ParseTest("rule cxx\n command = " + long_rule_command, err))
66+
return false;
67+
68+
// Create build edges. Using ManifestParser is as fast as using the State api
69+
// for edge creation, so just use that.
70+
const int kNumCommands = 30000;
71+
string build_rules;
72+
for (int i = 0; i < kNumCommands; ++i) {
73+
char buf[80];
74+
sprintf(buf, "build input%d.o: cxx input%d.cc\n", i, i);
75+
build_rules += buf;
76+
}
77+
78+
if (!parser.ParseTest(build_rules, err))
79+
return false;
80+
81+
for (int i = 0; i < kNumCommands; ++i) {
82+
log.RecordCommand(state.edges_[i],
83+
/*start_time=*/100 * i,
84+
/*end_time=*/100 * i + 1,
85+
/*restat_mtime=*/0);
86+
}
87+
88+
return true;
89+
}
90+
91+
int main() {
92+
vector<int> times;
93+
string err;
94+
95+
if (!WriteTestData(&err)) {
96+
fprintf(stderr, "Failed to write test data: %s\n", err.c_str());
97+
return 1;
98+
}
99+
100+
{
101+
// Read once to warm up disk cache.
102+
BuildLog log;
103+
if (!log.Load(kTestFilename, &err)) {
104+
fprintf(stderr, "Failed to read test data: %s\n", err.c_str());
105+
return 1;
106+
}
107+
}
108+
const int kNumRepetitions = 5;
109+
for (int i = 0; i < kNumRepetitions; ++i) {
110+
int64_t start = GetTimeMillis();
111+
BuildLog log;
112+
if (!log.Load(kTestFilename, &err)) {
113+
fprintf(stderr, "Failed to read test data: %s\n", err.c_str());
114+
return 1;
115+
}
116+
int delta = (int)(GetTimeMillis() - start);
117+
printf("%dms\n", delta);
118+
times.push_back(delta);
119+
}
120+
121+
int min = times[0];
122+
int max = times[0];
123+
float total = 0;
124+
for (size_t i = 0; i < times.size(); ++i) {
125+
total += times[i];
126+
if (times[i] < min)
127+
min = times[i];
128+
else if (times[i] > max)
129+
max = times[i];
130+
}
131+
132+
printf("min %dms max %dms avg %.1fms\n",
133+
min, max, total / times.size());
134+
135+
unlink(kTestFilename);
136+
137+
return 0;
138+
}
139+

src/build_log_test.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
#include <unistd.h>
2929
#endif
3030

31-
static const char kTestFilename[] = "BuildLogTest-tempfile";
31+
const char kTestFilename[] = "BuildLogTest-tempfile";
3232

3333
struct BuildLogTest : public StateTestWithBuiltinRules {
3434
virtual void SetUp() {

0 commit comments

Comments
 (0)