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