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