Replace ManifestParser::FileReader with general FileReader
[platform/upstream/ninja.git] / src / manifest_parser_perftest.cc
1 // Copyright 2014 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 // Tests manifest parser performance.  Expects to be run in ninja's root
16 // directory.
17
18 #include <numeric>
19
20 #include <errno.h>
21 #include <stdio.h>
22 #include <string.h>
23
24 #ifdef _WIN32
25 #include "getopt.h"
26 #include <direct.h>
27 #else
28 #include <getopt.h>
29 #include <unistd.h>
30 #endif
31
32 #include "disk_interface.h"
33 #include "graph.h"
34 #include "manifest_parser.h"
35 #include "metrics.h"
36 #include "state.h"
37 #include "util.h"
38
39 bool WriteFakeManifests(const string& dir, string* err) {
40   RealDiskInterface disk_interface;
41   TimeStamp mtime = disk_interface.Stat(dir + "/build.ninja", err);
42   if (mtime != 0)  // 0 means that the file doesn't exist yet.
43     return mtime != -1;
44
45   string command = "python misc/write_fake_manifests.py " + dir;
46   printf("Creating manifest data..."); fflush(stdout);
47   int exit_code = system(command.c_str());
48   printf("done.\n");
49   if (exit_code != 0)
50     *err = "Failed to run " + command;
51   return exit_code == 0;
52 }
53
54 int LoadManifests(bool measure_command_evaluation) {
55   string err;
56   RealDiskInterface disk_interface;
57   State state;
58   ManifestParser parser(&state, &disk_interface, kDupeEdgeActionWarn);
59   if (!parser.Load("build.ninja", &err)) {
60     fprintf(stderr, "Failed to read test data: %s\n", err.c_str());
61     exit(1);
62   }
63   // Doing an empty build involves reading the manifest and evaluating all
64   // commands required for the requested targets. So include command
65   // evaluation in the perftest by default.
66   int optimization_guard = 0;
67   if (measure_command_evaluation)
68     for (size_t i = 0; i < state.edges_.size(); ++i)
69       optimization_guard += state.edges_[i]->EvaluateCommand().size();
70   return optimization_guard;
71 }
72
73 int main(int argc, char* argv[]) {
74   bool measure_command_evaluation = true;
75   int opt;
76   while ((opt = getopt(argc, argv, const_cast<char*>("fh"))) != -1) {
77     switch (opt) {
78     case 'f':
79       measure_command_evaluation = false;
80       break;
81     case 'h':
82     default:
83       printf("usage: manifest_parser_perftest\n"
84 "\n"
85 "options:\n"
86 "  -f     only measure manifest load time, not command evaluation time\n"
87              );
88     return 1;
89     }
90   }
91
92   const char kManifestDir[] = "build/manifest_perftest";
93
94   string err;
95   if (!WriteFakeManifests(kManifestDir, &err)) {
96     fprintf(stderr, "Failed to write test data: %s\n", err.c_str());
97     return 1;
98   }
99
100   if (chdir(kManifestDir) < 0)
101     Fatal("chdir: %s", strerror(errno));
102
103   const int kNumRepetitions = 5;
104   vector<int> times;
105   for (int i = 0; i < kNumRepetitions; ++i) {
106     int64_t start = GetTimeMillis();
107     int optimization_guard = LoadManifests(measure_command_evaluation);
108     int delta = (int)(GetTimeMillis() - start);
109     printf("%dms (hash: %x)\n", delta, optimization_guard);
110     times.push_back(delta);
111   }
112
113   int min = *min_element(times.begin(), times.end());
114   int max = *max_element(times.begin(), times.end());
115   float total = accumulate(times.begin(), times.end(), 0.0f);
116   printf("min %dms  max %dms  avg %.1fms\n", min, max, total / times.size());
117 }