bootchart: fix bootchart can not be triggered problem
bootchart uses a file on the data partition to decide if it should collect data for bootchart, but the data partition will be mounted by the mount_all command in the "on fs" section, and it will be only added into the action queue when command "trigger fs" is executed, but that's after the bootchart_init action (late_init). This change makes bootchart_init a builtin command of init, and make it executed as the first command of "on post-fs" section which will be triggered after the "on fs" section. This change also refactors the bootchart code to all be in bootchart.cpp. Change-Id: Ia74aa34ca5b785f51fcffdd383075a549b2a99d9 Signed-off-by: Yongqin Liu <yongqin.liu@linaro.org>
This commit is contained in:
parent
ed318bff41
commit
a197ff12dd
|
@ -4,12 +4,6 @@ LOCAL_PATH:= $(call my-dir)
|
|||
|
||||
# --
|
||||
|
||||
ifeq ($(strip $(INIT_BOOTCHART)),true)
|
||||
init_options += -DBOOTCHART=1
|
||||
else
|
||||
init_options += -DBOOTCHART=0
|
||||
endif
|
||||
|
||||
ifneq (,$(filter userdebug eng,$(TARGET_BUILD_VARIANT)))
|
||||
init_options += -DALLOW_LOCAL_PROP_OVERRIDE=1 -DALLOW_DISABLE_SELINUX=1
|
||||
else
|
||||
|
|
|
@ -1,37 +1,31 @@
|
|||
This version of init contains code to perform "bootcharting", i.e. generating log
|
||||
files that can be later processed by the tools provided by www.bootchart.org.
|
||||
|
||||
To activate it, you need to define build 'init' with the INIT_BOOTCHART environment
|
||||
variable defined to 'true', for example:
|
||||
|
||||
touch system/init/init.c
|
||||
m INIT_BOOTCHART=true
|
||||
|
||||
On the emulator, use the new -bootchart <timeout> option to boot with bootcharting
|
||||
activated for <timeout> seconds.
|
||||
|
||||
Otherwise, flash your device, and start it. Then create a file on the /data partition
|
||||
with a command like the following:
|
||||
|
||||
adb shell 'echo $TIMEOUT > /data/bootchart-start'
|
||||
adb shell 'echo $TIMEOUT > /data/bootchart/start'
|
||||
|
||||
Where the value of $TIMEOUT corresponds to the wanted bootcharted period in seconds;
|
||||
for example, to bootchart for 2 minutes, do:
|
||||
|
||||
adb shell 'echo 120 > /data/bootchart-start'
|
||||
adb shell 'echo 120 > /data/bootchart/start'
|
||||
|
||||
Reboot your device, bootcharting will begin and stop after the period you gave.
|
||||
You can also stop the bootcharting at any moment by doing the following:
|
||||
|
||||
adb shell 'echo 1 > /data/bootchart-stop'
|
||||
adb shell 'echo 1 > /data/bootchart/stop'
|
||||
|
||||
Note that /data/bootchart-stop is deleted automatically by init at the end of the
|
||||
bootcharting. This is not the case of /data/bootchart-start, so don't forget to delete it
|
||||
Note that /data/bootchart/stop is deleted automatically by init at the end of the
|
||||
bootcharting. This is not the case of /data/bootchart/start, so don't forget to delete it
|
||||
when you're done collecting data:
|
||||
|
||||
adb shell rm /data/bootchart-start
|
||||
adb shell rm /data/bootchart/start
|
||||
|
||||
The log files are placed in /data/bootchart/. you must run the script tools/grab-bootchart.sh
|
||||
The log files are placed in /data/bootchart/. You must run the script tools/grab-bootchart.sh
|
||||
which will use ADB to retrieve them and create a bootchart.tgz file that can be used with
|
||||
the bootchart parser/renderer, or even uploaded directly to the form located at:
|
||||
|
||||
|
@ -47,6 +41,6 @@ NOTE: the bootchart.org webform doesn't seem to work at the moment, you can gene
|
|||
|
||||
technical note:
|
||||
|
||||
this implementation of bootcharting does use the 'bootchartd' script provided by
|
||||
This implementation of bootcharting does not use the 'bootchartd' script provided by
|
||||
www.bootchart.org, but a C re-implementation that is directly compiled into our init
|
||||
program.
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
*/
|
||||
|
||||
#include "bootchart.h"
|
||||
#include "keywords.h"
|
||||
#include "log.h"
|
||||
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
|
@ -32,6 +34,10 @@
|
|||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define BOOTCHART_POLLING_MS 200 /* polling period in ms */
|
||||
#define BOOTCHART_DEFAULT_TIME_SEC (2*60) /* default polling time in seconds */
|
||||
#define BOOTCHART_MAX_TIME_SEC (10*60) /* max polling time in seconds */
|
||||
|
||||
#define VERSION "0.8"
|
||||
#define SAMPLE_PERIOD 0.2
|
||||
#define LOG_ROOT "/data/bootchart"
|
||||
|
@ -41,8 +47,23 @@
|
|||
#define LOG_HEADER LOG_ROOT"/header"
|
||||
#define LOG_ACCT LOG_ROOT"/kernel_pacct"
|
||||
|
||||
#define LOG_STARTFILE "/data/bootchart-start"
|
||||
#define LOG_STOPFILE "/data/bootchart-stop"
|
||||
#define LOG_STARTFILE LOG_ROOT"/start"
|
||||
#define LOG_STOPFILE LOG_ROOT"/stop"
|
||||
|
||||
#define FILE_BUFF_SIZE 65536
|
||||
|
||||
struct FileBuff {
|
||||
int count;
|
||||
int fd;
|
||||
char data[FILE_BUFF_SIZE];
|
||||
};
|
||||
|
||||
static long long last_bootchart_time;
|
||||
static int g_remaining_samples;
|
||||
|
||||
static FileBuff log_stat[1];
|
||||
static FileBuff log_procs[1];
|
||||
static FileBuff log_disks[1];
|
||||
|
||||
static int
|
||||
proc_read(const char* filename, char* buff, size_t buffsize)
|
||||
|
@ -57,19 +78,11 @@ proc_read(const char* filename, char* buff, size_t buffsize)
|
|||
return len;
|
||||
}
|
||||
|
||||
#define FILE_BUFF_SIZE 65536
|
||||
|
||||
struct FileBuff {
|
||||
int count;
|
||||
int fd;
|
||||
char data[FILE_BUFF_SIZE];
|
||||
};
|
||||
|
||||
static void
|
||||
file_buff_open( FileBuff* buff, const char* path )
|
||||
{
|
||||
buff->count = 0;
|
||||
buff->fd = open(path, O_WRONLY|O_CREAT|O_TRUNC, 0755);
|
||||
buff->fd = open(path, O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC, 0755);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -248,9 +261,19 @@ do_log_procs(FileBuff* log)
|
|||
do_log_ln(log);
|
||||
}
|
||||
|
||||
static FileBuff log_stat[1];
|
||||
static FileBuff log_procs[1];
|
||||
static FileBuff log_disks[1];
|
||||
int do_bootchart_init(int nargs, char **args)
|
||||
{
|
||||
g_remaining_samples = bootchart_init();
|
||||
if (g_remaining_samples < 0) {
|
||||
ERROR("bootcharting init failure\n");
|
||||
} else if (g_remaining_samples > 0) {
|
||||
NOTICE("bootcharting started (will run for %d ms)\n", g_remaining_samples*BOOTCHART_POLLING_MS);
|
||||
} else {
|
||||
NOTICE("bootcharting ignored\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* called to setup bootcharting */
|
||||
int bootchart_init( void )
|
||||
|
@ -307,14 +330,13 @@ int bootchart_init( void )
|
|||
return count;
|
||||
}
|
||||
|
||||
/* called each time you want to perform a bootchart sampling op */
|
||||
int bootchart_step( void )
|
||||
static int bootchart_step( void )
|
||||
{
|
||||
do_log_file(log_stat, "/proc/stat");
|
||||
do_log_file(log_disks, "/proc/diskstats");
|
||||
do_log_procs(log_procs);
|
||||
|
||||
/* we stop when /data/bootchart-stop contains 1 */
|
||||
/* we stop when /data/bootchart/stop contains 1 */
|
||||
{
|
||||
char buff[2];
|
||||
if (proc_read(LOG_STOPFILE,buff,sizeof(buff)) > 0 && buff[0] == '1') {
|
||||
|
@ -325,6 +347,42 @@ int bootchart_step( void )
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* called to get time (in ms) used by bootchart */
|
||||
static long long bootchart_gettime() {
|
||||
return 10LL*get_uptime_jiffies();
|
||||
}
|
||||
|
||||
/* called each time you want to perform a bootchart sampling op */
|
||||
void bootchart_sample(int* timeout) {
|
||||
if (g_remaining_samples > 0) {
|
||||
long long current_time;
|
||||
int elapsed_time, remaining_time;
|
||||
|
||||
current_time = bootchart_gettime();
|
||||
elapsed_time = current_time - last_bootchart_time;
|
||||
|
||||
if (elapsed_time >= BOOTCHART_POLLING_MS) {
|
||||
/* count missed samples */
|
||||
while (elapsed_time >= BOOTCHART_POLLING_MS) {
|
||||
elapsed_time -= BOOTCHART_POLLING_MS;
|
||||
g_remaining_samples--;
|
||||
}
|
||||
/* count may be negative, take a sample anyway */
|
||||
last_bootchart_time = current_time;
|
||||
if (bootchart_step() < 0 || g_remaining_samples <= 0) {
|
||||
bootchart_finish();
|
||||
g_remaining_samples = 0;
|
||||
}
|
||||
}
|
||||
if (g_remaining_samples > 0) {
|
||||
remaining_time = BOOTCHART_POLLING_MS - elapsed_time;
|
||||
if (*timeout < 0 || *timeout > remaining_time) {
|
||||
*timeout = remaining_time;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void bootchart_finish( void )
|
||||
{
|
||||
unlink( LOG_STOPFILE );
|
||||
|
@ -333,9 +391,3 @@ void bootchart_finish( void )
|
|||
file_buff_done(log_procs);
|
||||
acct(NULL);
|
||||
}
|
||||
|
||||
/* called to get time (in ms) used by bootchart */
|
||||
long long bootchart_gettime( void )
|
||||
{
|
||||
return 10LL*get_uptime_jiffies();
|
||||
}
|
||||
|
|
|
@ -17,13 +17,8 @@
|
|||
#ifndef _BOOTCHART_H
|
||||
#define _BOOTCHART_H
|
||||
|
||||
extern int bootchart_init(void);
|
||||
extern int bootchart_step(void);
|
||||
extern void bootchart_finish(void);
|
||||
extern long long bootchart_gettime(void);
|
||||
|
||||
#define BOOTCHART_POLLING_MS 200 /* polling period in ms */
|
||||
#define BOOTCHART_DEFAULT_TIME_SEC (2*60) /* default polling time in seconds */
|
||||
#define BOOTCHART_MAX_TIME_SEC (10*60) /* max polling time in seconds */
|
||||
int bootchart_init();
|
||||
void bootchart_sample(int* timeout);
|
||||
void bootchart_finish();
|
||||
|
||||
#endif /* _BOOTCHART_H */
|
||||
|
|
|
@ -63,9 +63,6 @@ struct selabel_handle *sehandle_prop;
|
|||
|
||||
static int property_triggers_enabled = 0;
|
||||
|
||||
static int bootchart_count;
|
||||
static long long bootchart_time = 0;
|
||||
|
||||
static char console[32];
|
||||
static char bootmode[32];
|
||||
static char hardware[32];
|
||||
|
@ -857,20 +854,6 @@ static int queue_property_triggers_action(int nargs, char **args)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int bootchart_init_action(int nargs, char **args)
|
||||
{
|
||||
bootchart_count = bootchart_init();
|
||||
if (bootchart_count < 0) {
|
||||
ERROR("bootcharting init failure\n");
|
||||
} else if (bootchart_count > 0) {
|
||||
NOTICE("bootcharting started (period=%d ms)\n", bootchart_count*BOOTCHART_POLLING_MS);
|
||||
} else {
|
||||
NOTICE("bootcharting ignored\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void selinux_init_all_handles(void)
|
||||
{
|
||||
sehandle = selinux_android_file_context_handle();
|
||||
|
@ -988,7 +971,7 @@ static void selinux_initialize(void)
|
|||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int fd_count = 0;
|
||||
size_t fd_count = 0;
|
||||
struct pollfd ufds[4];
|
||||
int property_set_fd_init = 0;
|
||||
int signal_fd_init = 0;
|
||||
|
@ -1087,13 +1070,7 @@ int main(int argc, char **argv)
|
|||
/* run all property triggers based on current state of the properties */
|
||||
queue_builtin_action(queue_property_triggers_action, "queue_property_triggers");
|
||||
|
||||
if (BOOTCHART) {
|
||||
queue_builtin_action(bootchart_init_action, "bootchart_init");
|
||||
}
|
||||
|
||||
for(;;) {
|
||||
int nr, i, timeout = -1;
|
||||
|
||||
for (;;) {
|
||||
execute_one_command();
|
||||
restart_processes();
|
||||
|
||||
|
@ -1119,6 +1096,7 @@ int main(int argc, char **argv)
|
|||
keychord_fd_init = 1;
|
||||
}
|
||||
|
||||
int timeout = -1;
|
||||
if (process_needs_restart) {
|
||||
timeout = (process_needs_restart - gettime()) * 1000;
|
||||
if (timeout < 0)
|
||||
|
@ -1129,48 +1107,22 @@ int main(int argc, char **argv)
|
|||
timeout = 0;
|
||||
}
|
||||
|
||||
if (BOOTCHART) {
|
||||
if (bootchart_count > 0) {
|
||||
long long current_time;
|
||||
int elapsed_time, remaining_time;
|
||||
bootchart_sample(&timeout);
|
||||
|
||||
current_time = bootchart_gettime();
|
||||
elapsed_time = current_time - bootchart_time;
|
||||
|
||||
if (elapsed_time >= BOOTCHART_POLLING_MS) {
|
||||
/* count missed samples */
|
||||
while (elapsed_time >= BOOTCHART_POLLING_MS) {
|
||||
elapsed_time -= BOOTCHART_POLLING_MS;
|
||||
bootchart_count--;
|
||||
}
|
||||
/* count may be negative, take a sample anyway */
|
||||
bootchart_time = current_time;
|
||||
if (bootchart_step() < 0 || bootchart_count <= 0) {
|
||||
bootchart_finish();
|
||||
bootchart_count = 0;
|
||||
}
|
||||
}
|
||||
if (bootchart_count > 0) {
|
||||
remaining_time = BOOTCHART_POLLING_MS - elapsed_time;
|
||||
if (timeout < 0 || timeout > remaining_time) {
|
||||
timeout = remaining_time;
|
||||
}
|
||||
}
|
||||
}
|
||||
int nr = poll(ufds, fd_count, timeout);
|
||||
if (nr <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nr = poll(ufds, fd_count, timeout);
|
||||
if (nr <= 0)
|
||||
continue;
|
||||
|
||||
for (i = 0; i < fd_count; i++) {
|
||||
for (size_t i = 0; i < fd_count; i++) {
|
||||
if (ufds[i].revents & POLLIN) {
|
||||
if (ufds[i].fd == get_property_set_fd())
|
||||
if (ufds[i].fd == get_property_set_fd()) {
|
||||
handle_property_set_fd();
|
||||
else if (ufds[i].fd == get_keychord_fd())
|
||||
} else if (ufds[i].fd == get_keychord_fd()) {
|
||||
handle_keychord();
|
||||
else if (ufds[i].fd == get_signal_fd())
|
||||
} else if (ufds[i].fd == get_signal_fd()) {
|
||||
handle_signal();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -115,6 +115,8 @@ void dump_parser_state() {
|
|||
static int lookup_keyword(const char *s)
|
||||
{
|
||||
switch (*s++) {
|
||||
case 'b':
|
||||
if (!strcmp(s, "ootchart_init")) return K_bootchart_init;
|
||||
case 'c':
|
||||
if (!strcmp(s, "opy")) return K_copy;
|
||||
if (!strcmp(s, "apability")) return K_capability;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#ifndef KEYWORD
|
||||
int do_bootchart_init(int nargs, char **args);
|
||||
int do_chroot(int nargs, char **args);
|
||||
int do_chdir(int nargs, char **args);
|
||||
int do_class_start(int nargs, char **args);
|
||||
|
@ -105,6 +106,7 @@ enum {
|
|||
KEYWORD(load_persist_props, COMMAND, 0, do_load_persist_props)
|
||||
KEYWORD(load_all_props, COMMAND, 0, do_load_all_props)
|
||||
KEYWORD(ioprio, OPTION, 0, 0)
|
||||
KEYWORD(bootchart_init, COMMAND, 0, do_bootchart_init)
|
||||
#ifdef __MAKE_KEYWORD_ENUM__
|
||||
KEYWORD_COUNT,
|
||||
};
|
||||
|
|
|
@ -240,6 +240,11 @@ on post-fs-data
|
|||
# We restorecon /data in case the userdata partition has been reset.
|
||||
restorecon /data
|
||||
|
||||
# Start bootcharting as soon as possible after the data partition is
|
||||
# mounted to collect more data.
|
||||
mkdir /data/bootchart 0755 shell shell
|
||||
bootchart_init
|
||||
|
||||
# Avoid predictable entropy pool. Carry over entropy from previous boot.
|
||||
copy /data/system/entropy.dat /dev/urandom
|
||||
|
||||
|
|
Loading…
Reference in New Issue