Loading init/bootchart.cpp +126 −153 Original line number Diff line number Diff line Loading @@ -15,7 +15,7 @@ */ #include "bootchart.h" #include "log.h" #include "property_service.h" #include <dirent.h> Loading @@ -29,39 +29,40 @@ #include <time.h> #include <unistd.h> #include <chrono> #include <condition_variable> #include <memory> #include <mutex> #include <string> #include <thread> #include <vector> #include <android-base/file.h> #include <android-base/logging.h> #include <android-base/stringprintf.h> using android::base::StringPrintf; using namespace std::chrono_literals; static constexpr const char* LOG_STAT = "/data/bootchart/proc_stat.log"; static constexpr const char* LOG_PROC = "/data/bootchart/proc_ps.log"; static constexpr const char* LOG_DISK = "/data/bootchart/proc_diskstats.log"; static constexpr const char* LOG_HEADER = "/data/bootchart/header"; // Polling period in ms. static constexpr int BOOTCHART_POLLING_MS = 200; static long long g_last_bootchart_time; static std::thread* g_bootcharting_thread; static bool g_bootcharting = false; static FILE* g_stat_log; static FILE* g_proc_log; static FILE* g_disk_log; static std::mutex g_bootcharting_finished_mutex; static std::condition_variable g_bootcharting_finished_cv; static bool g_bootcharting_finished; static long long get_uptime_jiffies() { std::string uptime; if (!android::base::ReadFileToString("/proc/uptime", &uptime)) { return 0; } if (!android::base::ReadFileToString("/proc/uptime", &uptime)) return 0; return 100LL * strtod(uptime.c_str(), NULL); } static std::unique_ptr<FILE, decltype(&fclose)> fopen_unique(const char* filename, const char* mode) { std::unique_ptr<FILE, decltype(&fclose)> result(fopen(filename, mode), fclose); if (!result) PLOG(ERROR) << "bootchart: failed to open " << filename; return result; } static void log_header() { char date[32]; time_t now_t = time(NULL); Loading @@ -69,30 +70,23 @@ static void log_header() { strftime(date, sizeof(date), "%F %T", &now); utsname uts; if (uname(&uts) == -1) { return; } if (uname(&uts) == -1) return; std::string fingerprint = property_get("ro.build.fingerprint"); if (fingerprint.empty()) { return; } if (fingerprint.empty()) return; std::string kernel_cmdline; android::base::ReadFileToString("/proc/cmdline", &kernel_cmdline); FILE* out = fopen(LOG_HEADER, "we"); if (out == NULL) { return; } fprintf(out, "version = Android init 0.8\n"); fprintf(out, "title = Boot chart for Android (%s)\n", date); fprintf(out, "system.uname = %s %s %s %s\n", uts.sysname, uts.release, uts.version, uts.machine); fprintf(out, "system.release = %s\n", fingerprint.c_str()); auto fp = fopen_unique("/data/bootchart/header", "we"); if (!fp) return; fprintf(&*fp, "version = Android init 0.8\n"); fprintf(&*fp, "title = Boot chart for Android (%s)\n", date); fprintf(&*fp, "system.uname = %s %s %s %s\n", uts.sysname, uts.release, uts.version, uts.machine); fprintf(&*fp, "system.release = %s\n", fingerprint.c_str()); // TODO: use /proc/cpuinfo "model name" line for x86, "Processor" line for arm. fprintf(out, "system.cpu = %s\n", uts.machine); fprintf(out, "system.kernel.options = %s\n", kernel_cmdline.c_str()); fclose(out); fprintf(&*fp, "system.cpu = %s\n", uts.machine); fprintf(&*fp, "system.kernel.options = %s\n", kernel_cmdline.c_str()); } static void log_uptime(FILE* log) { Loading @@ -108,8 +102,8 @@ static void log_file(FILE* log, const char* procfile) { } } static void log_processes() { log_uptime(g_proc_log); static void log_processes(FILE* log) { log_uptime(log); std::unique_ptr<DIR, int(*)(DIR*)> dir(opendir("/proc"), closedir); struct dirent* entry; Loading @@ -135,91 +129,70 @@ static void log_processes() { stat.replace(open + 1, close - open - 1, full_name); } } fputs(stat.c_str(), g_proc_log); fputs(stat.c_str(), log); } } fputc('\n', g_proc_log); fputc('\n', log); } static int do_bootchart_start() { // We don't care about the content, but we do care that /data/bootchart/enabled actually exists. std::string start; if (!android::base::ReadFileToString("/data/bootchart/enabled", &start)) { LOG(VERBOSE) << "Not bootcharting"; return 0; } static void bootchart_thread_main() { LOG(INFO) << "Bootcharting started"; // Open log files. std::unique_ptr<FILE, decltype(&fclose)> stat_log(fopen(LOG_STAT, "we"), fclose); if (!stat_log) { PLOG(ERROR) << "Bootcharting couldn't open " << LOG_STAT; return -1; } std::unique_ptr<FILE, decltype(&fclose)> proc_log(fopen(LOG_PROC, "we"), fclose); if (!proc_log) { PLOG(ERROR) << "Bootcharting couldn't open " << LOG_PROC; return -1; } std::unique_ptr<FILE, decltype(&fclose)> disk_log(fopen(LOG_DISK, "we"), fclose); if (!disk_log) { PLOG(ERROR) << "Bootcharting couldn't open " << LOG_DISK; return -1; } auto stat_log = fopen_unique("/data/bootchart/proc_stat.log", "we"); if (!stat_log) return; auto proc_log = fopen_unique("/data/bootchart/proc_ps.log", "we"); if (!proc_log) return; auto disk_log = fopen_unique("/data/bootchart/proc_diskstats.log", "we"); if (!disk_log) return; LOG(INFO) << "Bootcharting started"; g_stat_log = stat_log.release(); g_proc_log = proc_log.release(); g_disk_log = disk_log.release(); g_bootcharting = true; log_header(); return 0; while (true) { { std::unique_lock<std::mutex> lock(g_bootcharting_finished_mutex); g_bootcharting_finished_cv.wait_for(lock, 200ms); if (g_bootcharting_finished) break; } static void do_bootchart_step() { log_file(g_stat_log, "/proc/stat"); log_file(g_disk_log, "/proc/diskstats"); log_processes(); log_file(&*stat_log, "/proc/stat"); log_file(&*disk_log, "/proc/diskstats"); log_processes(&*proc_log); } static int do_bootchart_stop() { if (!g_bootcharting) return 0; LOG(INFO) << "Bootcharting finished"; g_bootcharting = false; fclose(g_stat_log); fclose(g_disk_log); fclose(g_proc_log); return 0; } int do_bootchart(const std::vector<std::string>& args) { if (args[1] == "start") return do_bootchart_start(); return do_bootchart_stop(); static int do_bootchart_start() { // We don't care about the content, but we do care that /data/bootchart/enabled actually exists. std::string start; if (!android::base::ReadFileToString("/data/bootchart/enabled", &start)) { LOG(VERBOSE) << "Not bootcharting"; return 0; } void bootchart_sample(int* timeout) { // Do we have any more bootcharting to do? if (!g_bootcharting) return; g_bootcharting_thread = new std::thread(bootchart_thread_main); return 0; } long long current_time = 10LL * get_uptime_jiffies(); int elapsed_time = current_time - g_last_bootchart_time; static int do_bootchart_stop() { if (!g_bootcharting_thread) return 0; if (elapsed_time >= BOOTCHART_POLLING_MS) { while (elapsed_time >= BOOTCHART_POLLING_MS) { elapsed_time -= BOOTCHART_POLLING_MS; // Tell the worker thread it's time to quit. { std::lock_guard<std::mutex> lock(g_bootcharting_finished_mutex); g_bootcharting_finished = true; g_bootcharting_finished_cv.notify_one(); } g_last_bootchart_time = current_time; do_bootchart_step(); g_bootcharting_thread->join(); delete g_bootcharting_thread; g_bootcharting_thread = nullptr; return 0; } // Schedule another? if (g_bootcharting) { int remaining_time = BOOTCHART_POLLING_MS - elapsed_time; if (*timeout < 0 || *timeout > remaining_time) { *timeout = remaining_time; } } int do_bootchart(const std::vector<std::string>& args) { if (args[1] == "start") return do_bootchart_start(); return do_bootchart_stop(); } init/bootchart.h +0 −1 Original line number Diff line number Diff line Loading @@ -21,6 +21,5 @@ #include <vector> int do_bootchart(const std::vector<std::string>& args); void bootchart_sample(int* timeout); #endif /* _BOOTCHART_H */ init/init.cpp +0 −2 Original line number Diff line number Diff line Loading @@ -850,8 +850,6 @@ int main(int argc, char** argv) { // If there's more work to do, wake up again immediately. if (am.HasMoreCommands()) epoll_timeout_ms = 0; bootchart_sample(&epoll_timeout_ms); epoll_event ev; int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, epoll_timeout_ms)); if (nr == -1) { Loading Loading
init/bootchart.cpp +126 −153 Original line number Diff line number Diff line Loading @@ -15,7 +15,7 @@ */ #include "bootchart.h" #include "log.h" #include "property_service.h" #include <dirent.h> Loading @@ -29,39 +29,40 @@ #include <time.h> #include <unistd.h> #include <chrono> #include <condition_variable> #include <memory> #include <mutex> #include <string> #include <thread> #include <vector> #include <android-base/file.h> #include <android-base/logging.h> #include <android-base/stringprintf.h> using android::base::StringPrintf; using namespace std::chrono_literals; static constexpr const char* LOG_STAT = "/data/bootchart/proc_stat.log"; static constexpr const char* LOG_PROC = "/data/bootchart/proc_ps.log"; static constexpr const char* LOG_DISK = "/data/bootchart/proc_diskstats.log"; static constexpr const char* LOG_HEADER = "/data/bootchart/header"; // Polling period in ms. static constexpr int BOOTCHART_POLLING_MS = 200; static long long g_last_bootchart_time; static std::thread* g_bootcharting_thread; static bool g_bootcharting = false; static FILE* g_stat_log; static FILE* g_proc_log; static FILE* g_disk_log; static std::mutex g_bootcharting_finished_mutex; static std::condition_variable g_bootcharting_finished_cv; static bool g_bootcharting_finished; static long long get_uptime_jiffies() { std::string uptime; if (!android::base::ReadFileToString("/proc/uptime", &uptime)) { return 0; } if (!android::base::ReadFileToString("/proc/uptime", &uptime)) return 0; return 100LL * strtod(uptime.c_str(), NULL); } static std::unique_ptr<FILE, decltype(&fclose)> fopen_unique(const char* filename, const char* mode) { std::unique_ptr<FILE, decltype(&fclose)> result(fopen(filename, mode), fclose); if (!result) PLOG(ERROR) << "bootchart: failed to open " << filename; return result; } static void log_header() { char date[32]; time_t now_t = time(NULL); Loading @@ -69,30 +70,23 @@ static void log_header() { strftime(date, sizeof(date), "%F %T", &now); utsname uts; if (uname(&uts) == -1) { return; } if (uname(&uts) == -1) return; std::string fingerprint = property_get("ro.build.fingerprint"); if (fingerprint.empty()) { return; } if (fingerprint.empty()) return; std::string kernel_cmdline; android::base::ReadFileToString("/proc/cmdline", &kernel_cmdline); FILE* out = fopen(LOG_HEADER, "we"); if (out == NULL) { return; } fprintf(out, "version = Android init 0.8\n"); fprintf(out, "title = Boot chart for Android (%s)\n", date); fprintf(out, "system.uname = %s %s %s %s\n", uts.sysname, uts.release, uts.version, uts.machine); fprintf(out, "system.release = %s\n", fingerprint.c_str()); auto fp = fopen_unique("/data/bootchart/header", "we"); if (!fp) return; fprintf(&*fp, "version = Android init 0.8\n"); fprintf(&*fp, "title = Boot chart for Android (%s)\n", date); fprintf(&*fp, "system.uname = %s %s %s %s\n", uts.sysname, uts.release, uts.version, uts.machine); fprintf(&*fp, "system.release = %s\n", fingerprint.c_str()); // TODO: use /proc/cpuinfo "model name" line for x86, "Processor" line for arm. fprintf(out, "system.cpu = %s\n", uts.machine); fprintf(out, "system.kernel.options = %s\n", kernel_cmdline.c_str()); fclose(out); fprintf(&*fp, "system.cpu = %s\n", uts.machine); fprintf(&*fp, "system.kernel.options = %s\n", kernel_cmdline.c_str()); } static void log_uptime(FILE* log) { Loading @@ -108,8 +102,8 @@ static void log_file(FILE* log, const char* procfile) { } } static void log_processes() { log_uptime(g_proc_log); static void log_processes(FILE* log) { log_uptime(log); std::unique_ptr<DIR, int(*)(DIR*)> dir(opendir("/proc"), closedir); struct dirent* entry; Loading @@ -135,91 +129,70 @@ static void log_processes() { stat.replace(open + 1, close - open - 1, full_name); } } fputs(stat.c_str(), g_proc_log); fputs(stat.c_str(), log); } } fputc('\n', g_proc_log); fputc('\n', log); } static int do_bootchart_start() { // We don't care about the content, but we do care that /data/bootchart/enabled actually exists. std::string start; if (!android::base::ReadFileToString("/data/bootchart/enabled", &start)) { LOG(VERBOSE) << "Not bootcharting"; return 0; } static void bootchart_thread_main() { LOG(INFO) << "Bootcharting started"; // Open log files. std::unique_ptr<FILE, decltype(&fclose)> stat_log(fopen(LOG_STAT, "we"), fclose); if (!stat_log) { PLOG(ERROR) << "Bootcharting couldn't open " << LOG_STAT; return -1; } std::unique_ptr<FILE, decltype(&fclose)> proc_log(fopen(LOG_PROC, "we"), fclose); if (!proc_log) { PLOG(ERROR) << "Bootcharting couldn't open " << LOG_PROC; return -1; } std::unique_ptr<FILE, decltype(&fclose)> disk_log(fopen(LOG_DISK, "we"), fclose); if (!disk_log) { PLOG(ERROR) << "Bootcharting couldn't open " << LOG_DISK; return -1; } auto stat_log = fopen_unique("/data/bootchart/proc_stat.log", "we"); if (!stat_log) return; auto proc_log = fopen_unique("/data/bootchart/proc_ps.log", "we"); if (!proc_log) return; auto disk_log = fopen_unique("/data/bootchart/proc_diskstats.log", "we"); if (!disk_log) return; LOG(INFO) << "Bootcharting started"; g_stat_log = stat_log.release(); g_proc_log = proc_log.release(); g_disk_log = disk_log.release(); g_bootcharting = true; log_header(); return 0; while (true) { { std::unique_lock<std::mutex> lock(g_bootcharting_finished_mutex); g_bootcharting_finished_cv.wait_for(lock, 200ms); if (g_bootcharting_finished) break; } static void do_bootchart_step() { log_file(g_stat_log, "/proc/stat"); log_file(g_disk_log, "/proc/diskstats"); log_processes(); log_file(&*stat_log, "/proc/stat"); log_file(&*disk_log, "/proc/diskstats"); log_processes(&*proc_log); } static int do_bootchart_stop() { if (!g_bootcharting) return 0; LOG(INFO) << "Bootcharting finished"; g_bootcharting = false; fclose(g_stat_log); fclose(g_disk_log); fclose(g_proc_log); return 0; } int do_bootchart(const std::vector<std::string>& args) { if (args[1] == "start") return do_bootchart_start(); return do_bootchart_stop(); static int do_bootchart_start() { // We don't care about the content, but we do care that /data/bootchart/enabled actually exists. std::string start; if (!android::base::ReadFileToString("/data/bootchart/enabled", &start)) { LOG(VERBOSE) << "Not bootcharting"; return 0; } void bootchart_sample(int* timeout) { // Do we have any more bootcharting to do? if (!g_bootcharting) return; g_bootcharting_thread = new std::thread(bootchart_thread_main); return 0; } long long current_time = 10LL * get_uptime_jiffies(); int elapsed_time = current_time - g_last_bootchart_time; static int do_bootchart_stop() { if (!g_bootcharting_thread) return 0; if (elapsed_time >= BOOTCHART_POLLING_MS) { while (elapsed_time >= BOOTCHART_POLLING_MS) { elapsed_time -= BOOTCHART_POLLING_MS; // Tell the worker thread it's time to quit. { std::lock_guard<std::mutex> lock(g_bootcharting_finished_mutex); g_bootcharting_finished = true; g_bootcharting_finished_cv.notify_one(); } g_last_bootchart_time = current_time; do_bootchart_step(); g_bootcharting_thread->join(); delete g_bootcharting_thread; g_bootcharting_thread = nullptr; return 0; } // Schedule another? if (g_bootcharting) { int remaining_time = BOOTCHART_POLLING_MS - elapsed_time; if (*timeout < 0 || *timeout > remaining_time) { *timeout = remaining_time; } } int do_bootchart(const std::vector<std::string>& args) { if (args[1] == "start") return do_bootchart_start(); return do_bootchart_stop(); }
init/bootchart.h +0 −1 Original line number Diff line number Diff line Loading @@ -21,6 +21,5 @@ #include <vector> int do_bootchart(const std::vector<std::string>& args); void bootchart_sample(int* timeout); #endif /* _BOOTCHART_H */
init/init.cpp +0 −2 Original line number Diff line number Diff line Loading @@ -850,8 +850,6 @@ int main(int argc, char** argv) { // If there's more work to do, wake up again immediately. if (am.HasMoreCommands()) epoll_timeout_ms = 0; bootchart_sample(&epoll_timeout_ms); epoll_event ev; int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, epoll_timeout_ms)); if (nr == -1) { Loading