| OLD | NEW | 
|---|
| 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be | 
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. | 
| 4 | 4 | 
| 5 #include "chrome/browser/chromeos/boot_times_loader.h" | 5 #include "chrome/browser/chromeos/boot_times_loader.h" | 
| 6 | 6 | 
| 7 #include <vector> | 7 #include <vector> | 
| 8 | 8 | 
| 9 #include "base/command_line.h" | 9 #include "base/command_line.h" | 
| 10 #include "base/file_path.h" | 10 #include "base/file_path.h" | 
| 11 #include "base/file_util.h" | 11 #include "base/file_util.h" | 
| 12 #include "base/message_loop.h" | 12 #include "base/message_loop.h" | 
| 13 #include "base/process_util.h" | 13 #include "base/process_util.h" | 
| 14 #include "base/string_util.h" | 14 #include "base/string_util.h" | 
| 15 #include "base/thread.h" | 15 #include "base/thread.h" | 
| 16 #include "chrome/browser/browser_process.h" | 16 #include "chrome/browser/browser_process.h" | 
| 17 #include "chrome/browser/chrome_thread.h" | 17 #include "chrome/browser/chrome_thread.h" | 
| 18 #include "chrome/common/chrome_switches.h" | 18 #include "chrome/common/chrome_switches.h" | 
| 19 | 19 | 
|  | 20 namespace { | 
|  | 21 | 
|  | 22 typedef struct Stats { | 
|  | 23   std::string uptime; | 
|  | 24   std::string disk; | 
|  | 25 | 
|  | 26   Stats() : uptime(std::string()), disk(std::string()) {} | 
|  | 27 }; | 
|  | 28 | 
|  | 29 } | 
|  | 30 | 
| 20 namespace chromeos { | 31 namespace chromeos { | 
| 21 | 32 | 
| 22 // File uptime logs are located in. | 33 // File uptime logs are located in. | 
| 23 static const char kLogPath[] = "/tmp"; | 34 static const char kLogPath[] = "/tmp"; | 
| 24 | 35 // Prefix for the time measurement files. | 
|  | 36 static const char kUptimePrefix[] = "uptime-"; | 
|  | 37 // Prefix for the disk usage files. | 
|  | 38 static const char kDiskPrefix[] = "disk-"; | 
|  | 39 // Name of the time that Chrome's main() is called. | 
|  | 40 static const char kChromeMain[] = "chrome-main"; | 
| 25 // Delay in milliseconds between file read attempts. | 41 // Delay in milliseconds between file read attempts. | 
| 26 static const int64 kReadAttemptDelayMs = 500; | 42 static const int64 kReadAttemptDelayMs = 250; | 
| 27 | 43 | 
| 28 BootTimesLoader::BootTimesLoader() : backend_(new Backend()) { | 44 BootTimesLoader::BootTimesLoader() : backend_(new Backend()) { | 
| 29 } | 45 } | 
| 30 | 46 | 
| 31 BootTimesLoader::Handle BootTimesLoader::GetBootTimes( | 47 BootTimesLoader::Handle BootTimesLoader::GetBootTimes( | 
| 32     CancelableRequestConsumerBase* consumer, | 48     CancelableRequestConsumerBase* consumer, | 
| 33     BootTimesLoader::GetBootTimesCallback* callback) { | 49     BootTimesLoader::GetBootTimesCallback* callback) { | 
| 34   if (!g_browser_process->file_thread()) { | 50   if (!g_browser_process->file_thread()) { | 
| 35     // This should only happen if Chrome is shutting down, so we don't do | 51     // This should only happen if Chrome is shutting down, so we don't do | 
| 36     // anything. | 52     // anything. | 
| (...skipping 11 matching lines...) Expand all  Loading... | 
| 48       new CancelableRequest<GetBootTimesCallback>(callback)); | 64       new CancelableRequest<GetBootTimesCallback>(callback)); | 
| 49   AddRequest(request, consumer); | 65   AddRequest(request, consumer); | 
| 50 | 66 | 
| 51   ChromeThread::PostTask( | 67   ChromeThread::PostTask( | 
| 52       ChromeThread::FILE, | 68       ChromeThread::FILE, | 
| 53       FROM_HERE, | 69       FROM_HERE, | 
| 54       NewRunnableMethod(backend_.get(), &Backend::GetBootTimes, request)); | 70       NewRunnableMethod(backend_.get(), &Backend::GetBootTimes, request)); | 
| 55   return request->handle(); | 71   return request->handle(); | 
| 56 } | 72 } | 
| 57 | 73 | 
| 58 // Executes command within a shell, allowing IO redirection. Searches |  | 
| 59 // for a whitespace delimited string prefixed by prefix in the output and |  | 
| 60 // returns it. |  | 
| 61 static std::string ExecuteInShell( |  | 
| 62     const std::string& command, const std::string& prefix) { |  | 
| 63   std::vector<std::string> args; |  | 
| 64   args.push_back("/bin/sh"); |  | 
| 65   args.push_back("-c"); |  | 
| 66   args.push_back(command); |  | 
| 67   CommandLine cmd(args); |  | 
| 68   std::string out; |  | 
| 69 |  | 
| 70   if (base::GetAppOutput(cmd, &out)) { |  | 
| 71     size_t index = out.find(prefix); |  | 
| 72     if (index != std::string::npos) { |  | 
| 73       size_t value_index = index + prefix.size(); |  | 
| 74       size_t whitespace_index = out.find(' ', value_index); |  | 
| 75       size_t chars_left = std::string::npos; |  | 
| 76       if (whitespace_index == std::string::npos) |  | 
| 77         whitespace_index = out.find('\n', value_index); |  | 
| 78       if (whitespace_index != std::string::npos) |  | 
| 79         chars_left = whitespace_index - value_index; |  | 
| 80       return out.substr(value_index, chars_left); |  | 
| 81     } |  | 
| 82   } |  | 
| 83   return std::string(); |  | 
| 84 } |  | 
| 85 |  | 
| 86 // Extracts the uptime value from files located in /tmp, returning the | 74 // Extracts the uptime value from files located in /tmp, returning the | 
| 87 // value as a double in value. | 75 // value as a double in value. | 
| 88 static bool GetUptime(const std::string& log, double* value) { | 76 static bool GetTime(const std::string& log, double* value) { | 
| 89   FilePath log_dir(kLogPath); | 77   FilePath log_dir(kLogPath); | 
| 90   FilePath log_file = log_dir.Append(log); | 78   FilePath log_file = log_dir.Append(log); | 
| 91   std::string contents; | 79   std::string contents; | 
| 92   *value = 0.0; | 80   *value = 0.0; | 
| 93   if (file_util::ReadFileToString(log_file, &contents)) { | 81   if (file_util::ReadFileToString(log_file, &contents)) { | 
| 94     size_t space_index = contents.find(' '); | 82     size_t space_index = contents.find(' '); | 
| 95     size_t chars_left = | 83     size_t chars_left = | 
| 96         space_index != std::string::npos ? space_index : std::string::npos; | 84         space_index != std::string::npos ? space_index : std::string::npos; | 
| 97     std::string value_string = contents.substr(0, chars_left); | 85     std::string value_string = contents.substr(0, chars_left); | 
| 98     return StringToDouble(value_string, value); | 86     return StringToDouble(value_string, value); | 
| 99   } | 87   } | 
| 100   return false; | 88   return false; | 
| 101 } | 89 } | 
| 102 | 90 | 
| 103 void BootTimesLoader::Backend::GetBootTimes( | 91 void BootTimesLoader::Backend::GetBootTimes( | 
| 104     scoped_refptr<GetBootTimesRequest> request) { | 92     scoped_refptr<GetBootTimesRequest> request) { | 
| 105   const char* kInitialTSCCommand = "dmesg | grep 'Initial TSC value:'"; | 93   const char* kFirmwareBootTime = "firmware-boot-time"; | 
| 106   const char* kInitialTSCPrefix = "TSC value: "; | 94   const char* kPreStartup = "pre-startup"; | 
| 107   const char* kClockSpeedCommand = "dmesg | grep -e 'Detected.*processor'"; | 95   const char* kChromeExec = "chrome-exec"; | 
| 108   const char* kClockSpeedPrefix = "Detected "; | 96   const char* kChromeMain = "chrome-main"; | 
| 109   const char* kPreStartup = "uptime-pre-startup"; | 97   const char* kXStarted = "x-started"; | 
| 110   const char* kChromeExec = "uptime-chrome-exec"; | 98   const char* kLoginPromptReady = "login-prompt-ready"; | 
| 111   const char* kChromeMain = "uptime-chrome-main"; | 99   std::string uptime_prefix = kUptimePrefix; | 
| 112   const char* kXStarted = "uptime-x-started"; |  | 
| 113   const char* kLoginPromptReady = "uptime-login-prompt-ready"; |  | 
| 114 | 100 | 
| 115   if (request->canceled()) | 101   if (request->canceled()) | 
| 116     return; | 102     return; | 
| 117 | 103 | 
| 118   // Wait until login_prompt_ready is output by reposting. | 104   // Wait until login_prompt_ready is output by reposting. | 
| 119   FilePath log_dir(kLogPath); | 105   FilePath log_dir(kLogPath); | 
| 120   FilePath log_file = log_dir.Append(kLoginPromptReady); | 106   FilePath log_file = log_dir.Append(kLoginPromptReady); | 
| 121   if (!file_util::PathExists(log_file)) { | 107   if (!file_util::PathExists(log_file)) { | 
| 122     ChromeThread::PostDelayedTask( | 108     ChromeThread::PostDelayedTask( | 
| 123         ChromeThread::FILE, | 109         ChromeThread::FILE, | 
| 124         FROM_HERE, | 110         FROM_HERE, | 
| 125         NewRunnableMethod(this, &Backend::GetBootTimes, request), | 111         NewRunnableMethod(this, &Backend::GetBootTimes, request), | 
| 126         kReadAttemptDelayMs); | 112         kReadAttemptDelayMs); | 
| 127     return; | 113     return; | 
| 128   } | 114   } | 
| 129 | 115 | 
| 130   BootTimes boot_times; | 116   BootTimes boot_times; | 
| 131   std::string tsc_value = ExecuteInShell(kInitialTSCCommand, kInitialTSCPrefix); | 117 | 
| 132   std::string speed_value = | 118   GetTime(kFirmwareBootTime, &boot_times.firmware); | 
| 133       ExecuteInShell(kClockSpeedCommand, kClockSpeedPrefix); | 119   GetTime(uptime_prefix + kPreStartup, &boot_times.pre_startup); | 
| 134   boot_times.firmware = 0; | 120   GetTime(uptime_prefix + kXStarted, &boot_times.x_started); | 
| 135   if (!tsc_value.empty() && !speed_value.empty()) { | 121   GetTime(uptime_prefix + kChromeExec, &boot_times.chrome_exec); | 
| 136     int64 tsc = 0; | 122   GetTime(uptime_prefix + kChromeMain, &boot_times.chrome_main); | 
| 137     double speed = 0; | 123   GetTime(uptime_prefix + kLoginPromptReady, &boot_times.login_prompt_ready); | 
| 138     if (StringToInt64(tsc_value, &tsc) && |  | 
| 139         StringToDouble(speed_value, &speed) && |  | 
| 140         speed > 0) { |  | 
| 141       boot_times.firmware = static_cast<double>(tsc) / (speed * 1000000); |  | 
| 142     } |  | 
| 143   } |  | 
| 144   GetUptime(kPreStartup, &boot_times.pre_startup); |  | 
| 145   GetUptime(kXStarted, &boot_times.x_started); |  | 
| 146   GetUptime(kChromeExec, &boot_times.chrome_exec); |  | 
| 147   GetUptime(kChromeMain, &boot_times.chrome_main); |  | 
| 148   GetUptime(kLoginPromptReady, &boot_times.login_prompt_ready); |  | 
| 149 | 124 | 
| 150   request->ForwardResult( | 125   request->ForwardResult( | 
| 151       GetBootTimesCallback::TupleType(request->handle(), boot_times)); | 126       GetBootTimesCallback::TupleType(request->handle(), boot_times)); | 
| 152 } | 127 } | 
| 153 | 128 | 
|  | 129 static void RecordStatsDelayed( | 
|  | 130     const std::string& name, | 
|  | 131     const std::string& uptime, | 
|  | 132     const std::string& disk) { | 
|  | 133   const FilePath log_path(kLogPath); | 
|  | 134   std::string disk_prefix = kDiskPrefix; | 
|  | 135   const FilePath uptime_output = | 
|  | 136       log_path.Append(FilePath(kUptimePrefix + name)); | 
|  | 137   const FilePath disk_output = log_path.Append(FilePath(kDiskPrefix + name)); | 
|  | 138 | 
|  | 139   // Write out the files, ensuring that they don't exist already. | 
|  | 140   if (!file_util::PathExists(uptime_output)) | 
|  | 141     file_util::WriteFile(uptime_output, uptime.data(), uptime.size()); | 
|  | 142   if (!file_util::PathExists(disk_output)) | 
|  | 143     file_util::WriteFile(disk_output, disk.data(), disk.size()); | 
|  | 144 } | 
|  | 145 | 
|  | 146 static void RecordStats( | 
|  | 147     const std::string& name, const Stats& stats) { | 
|  | 148   ChromeThread::PostTask( | 
|  | 149       ChromeThread::FILE, FROM_HERE, | 
|  | 150       NewRunnableFunction(RecordStatsDelayed, name, stats.uptime, stats.disk)); | 
|  | 151 } | 
|  | 152 | 
|  | 153 static Stats GetCurrentStats() { | 
|  | 154   const FilePath kProcUptime("/proc/uptime"); | 
|  | 155   const FilePath kDiskStat("/sys/block/sda/stat"); | 
|  | 156   Stats stats; | 
|  | 157 | 
|  | 158   file_util::ReadFileToString(kProcUptime, &stats.uptime); | 
|  | 159   file_util::ReadFileToString(kDiskStat, &stats.disk); | 
|  | 160   return stats; | 
|  | 161 } | 
|  | 162 | 
|  | 163 // static | 
|  | 164 void BootTimesLoader::RecordCurrentStats(const std::string& name) { | 
|  | 165   Stats stats = GetCurrentStats(); | 
|  | 166   RecordStats(name, stats); | 
|  | 167 } | 
|  | 168 | 
|  | 169 // Used to hold the stats at main(). | 
|  | 170 static Stats chrome_main_stats_; | 
|  | 171 | 
|  | 172 void BootTimesLoader::SaveChromeMainStats() { | 
|  | 173   chrome_main_stats_ = GetCurrentStats(); | 
|  | 174 } | 
|  | 175 | 
|  | 176 void BootTimesLoader::RecordChromeMainStats() { | 
|  | 177   RecordStats(kChromeMain, chrome_main_stats_); | 
|  | 178 } | 
|  | 179 | 
| 154 }  // namespace chromeos | 180 }  // namespace chromeos | 
| OLD | NEW | 
|---|