Home | History | Annotate | Download | only in bootio
      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