1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 // The bootio tool provides options to collect I/O stats for processes during boot. 18 19 #include <vector> 20 #include <getopt.h> 21 #include <unistd.h> 22 #include <android-base/file.h> 23 #include <android-base/logging.h> 24 #include <android-base/strings.h> 25 #include <log/log.h> 26 27 #include "bootio_collector.h" 28 29 namespace android { 30 31 #define LOG_ROOT "/data/misc/bootio" 32 #define LOG_START_FILE LOG_ROOT"/start" 33 #define SELF_IO "/proc/self/io" 34 35 static const int LOG_TIMEOUT_INDEX = 0; 36 static const int LOG_SAMPLES_INDEX = 1; 37 static const int LOG_MAX_TIMEOUT = 120; 38 static const int LOG_MAX_SAMPLES = 30; 39 40 void ShowHelp(const char *cmd) { 41 fprintf(stderr, "Usage: %s [options]\n", cmd); 42 fprintf(stderr, 43 "options include:\n" 44 " -h, --help Show this help\n" 45 " -p, --print Dump the boot io data to the console\n" 46 "\nNo options will start data collection process.\n"); 47 } 48 49 void PrintBootIo() { 50 printf("Boot I/O:\n"); 51 printf("------------\n"); 52 std::unique_ptr <BootioCollector> collector(new BootioCollector(LOG_ROOT)); 53 if (collector.get() == NULL) { 54 LOG(ERROR) << "Failed to create data collector"; 55 return; 56 } 57 collector->Print(); 58 } 59 60 void StartDataCollection() { 61 if (access(SELF_IO, F_OK) == -1) { 62 LOG(ERROR) << "Kernel doesn't support I/O profiling."; 63 printf("Kernel doesn't support I/O profiling."); 64 return; 65 } 66 67 int timeout = 0; 68 int samples = 0; 69 70 std::string start; 71 android::base::ReadFileToString(LOG_START_FILE, &start); 72 73 if (!start.empty()) { 74 std::vector <std::string> components = android::base::Split(start, " "); 75 if (components.size() != 2) { 76 LOG(ERROR) << "Invalid value in start file." << start; 77 return; 78 } 79 timeout = atoi(components.at(LOG_TIMEOUT_INDEX).c_str()); 80 samples = atoi(components.at(LOG_SAMPLES_INDEX).c_str()); 81 } else { 82 LOG(INFO) << "No profiling requested. Exiting"; 83 printf("Boot I/O: no profiling requested. Exiting.\n"); 84 return; 85 } 86 if (timeout <= 0 || samples <= 0) { 87 LOG(ERROR) << "Boot I/O: failed to parse string:" << start; 88 printf("Boot I/O: failed to parse string: %s\n", start.c_str()); 89 return; 90 } 91 if (samples > timeout || samples > LOG_MAX_SAMPLES || timeout > LOG_MAX_TIMEOUT) { 92 LOG(ERROR) << "Bad values for bootio. timeout=" << timeout << 93 " samples=" << samples << " Max timeout=" << LOG_MAX_TIMEOUT << 94 " Max samples=" << LOG_MAX_SAMPLES; 95 return; 96 } 97 LOG(INFO) << "Boot I/O: collecting data. samples=" << samples << "timeout=" << timeout; 98 printf("Boot I/O: collecting data\ntimeout=%d, samples=%d\n", 99 timeout, samples); 100 std::unique_ptr <BootioCollector> collector(new BootioCollector(LOG_ROOT)); 101 if (collector.get() == NULL) { 102 LOG(ERROR) << "Failed to create data collector"; 103 return; 104 } 105 collector->StartDataCollection(timeout, samples); 106 } 107 108 } 109 110 int main(int argc, char **argv) { 111 android::base::InitLogging(argv); 112 113 LOG(INFO) << "Bootio started"; 114 115 int optionIndex = 0; 116 static const struct option longOptions[] = { 117 {"help", no_argument, NULL, 'h'}, 118 {"print", no_argument, NULL, 'p'}, 119 {NULL, 0, NULL, 0} 120 }; 121 122 int opt = 0; 123 bool startCollection = true; 124 while ((opt = getopt_long(argc, argv, "hlpr:", longOptions, &optionIndex)) != -1) { 125 switch (opt) { 126 case 0: { 127 const std::string option_name = longOptions[optionIndex].name; 128 LOG(ERROR) << "Invalid option: " << option_name; 129 break; 130 } 131 132 case 'h': { 133 android::ShowHelp(argv[0]); 134 startCollection = false; 135 break; 136 } 137 138 case 'p': { 139 android::PrintBootIo(); 140 startCollection = false; 141 break; 142 } 143 144 default: { 145 DCHECK_EQ(opt, '?'); 146 147 // |optopt| is an external variable set by getopt representing 148 // the value of the invalid option. 149 LOG(ERROR) << "Invalid option: " << optopt; 150 android::ShowHelp(argv[0]); 151 return EXIT_FAILURE; 152 } 153 } 154 } 155 156 if (startCollection) { 157 android::StartDataCollection(); 158 } 159 160 return 0; 161 } 162 163