1b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor/* 2b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor * Copyright (C) 2010 The Android Open Source Project 3b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor * 4b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor * Licensed under the Apache License, Version 2.0 (the "License"); 5b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor * you may not use this file except in compliance with the License. 6b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor * You may obtain a copy of the License at 7b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor * 8b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor * http://www.apache.org/licenses/LICENSE-2.0 9b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor * 10b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor * Unless required by applicable law or agreed to in writing, software 11b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor * distributed under the License is distributed on an "AS IS" BASIS, 12b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor * See the License for the specific language governing permissions and 14b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor * limitations under the License. 15b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor */ 16b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor 17b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor#include <assert.h> 18b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor#include <ctype.h> 19b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor#include <dirent.h> 20b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor#include <fcntl.h> 21b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor#include <stdio.h> 22b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor#include <stdlib.h> 23b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor#include <string.h> 24b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor#include <sys/stat.h> 25b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor#include <sys/time.h> 26b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor#include <sys/types.h> 27b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor#include <time.h> 28b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor#include <unistd.h> 29b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor 30b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor// This program is as dumb as possible -- it reads a whole bunch of data 31b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor// from /proc and reports when it changes. It's up to analysis tools to 32b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor// actually parse the data. This program only does enough parsing to split 33b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor// large files (/proc/stat, /proc/yaffs) into individual values. 34b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor// 35b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor// The output format is a repeating series of observed differences: 36b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor// 37b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor// T + <beforetime.stamp> 38b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor// /proc/<new_filename> + <contents of newly discovered file> 39b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor// /proc/<changed_filename> = <contents of changed file> 40b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor// /proc/<deleted_filename> - 41b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor// /proc/<filename>:<label> = <part of a multiline file> 42b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor// T - <aftertime.stamp> 43b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor// 44b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor// 45b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor// Files read: 46b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor// 47b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor// /proc/*/stat - for all running/selected processes 48b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor// /proc/*/wchan - for all running/selected processes 49b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor// /proc/binder/stats - per line: "/proc/binder/stats:BC_REPLY" 50b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor// /proc/diskstats - per device: "/proc/diskstats:mmcblk0" 51b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor// /proc/net/dev - per interface: "/proc/net/dev:rmnet0" 52b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor// /proc/stat - per line: "/proc/stat:intr" 53b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor// /proc/yaffs - per device/line: "/proc/yaffs:userdata:nBlockErasures" 54b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor// /sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state 55b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor// - per line: "/sys/.../time_in_state:245000" 56b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor 57b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnorstruct data { 58b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor char *name; // filename, plus ":var" for many-valued files 59b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor char *value; // text to be reported when it changes 60b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor}; 61b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor 62376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor// Like memcpy, but replaces spaces and unprintables with '_'. 63376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnorstatic void unspace(char *dest, const char *src, int len) { 64376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor while (len-- > 0) { 65376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor char ch = *src++; 66376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor *dest++ = isgraph(ch) ? ch : '_'; 67376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor } 68376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor} 69376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor 70b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor// Set data->name and data->value to malloc'd strings with the 71b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor// filename and contents of the file. Trims trailing whitespace. 72b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnorstatic void read_data(struct data *data, const char *filename) { 73b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor char buf[4096]; 74b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor data->name = strdup(filename); 75b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor int fd = open(filename, O_RDONLY); 76b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor if (fd < 0) { 77b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor data->value = NULL; 78b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor return; 79b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor } 80b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor 81b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor int len = read(fd, buf, sizeof(buf)); 82b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor if (len < 0) { 83b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor perror(filename); 84b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor close(fd); 85b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor data->value = NULL; 86b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor return; 87b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor } 88b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor 89b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor close(fd); 90b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor while (len > 0 && isspace(buf[len - 1])) --len; 91b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor data->value = malloc(len + 1); 92b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor memcpy(data->value, buf, len); 93b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor data->value[len] = '\0'; 94b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor} 95b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor 96376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor// Read a name/value file and write data entries for each line. 97b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor// Returns the number of entries written (always <= stats_count). 98b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor// 99b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor// delimiter: used to split each line into name and value 100b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor// terminator: if non-NULL, processing stops after this string 101b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor// skip_words: skip this many words at the start of each line 102376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnorstatic int read_lines( 103b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor const char *filename, 104b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor char delimiter, const char *terminator, int skip_words, 105376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor struct data *stats, int stats_count) { 106376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor char buf[8192]; 107376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor int fd = open(filename, O_RDONLY); 108b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor if (fd < 0) return 0; 109b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor 110b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor int len = read(fd, buf, sizeof(buf) - 1); 111b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor if (len < 0) { 112376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor perror(filename); 113b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor close(fd); 114b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor return 0; 115b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor } 116b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor buf[len] = '\0'; 117b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor close(fd); 118b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor 119376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor if (terminator != NULL) { 120376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor char *end = strstr(buf, terminator); 121376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor if (end != NULL) *end = '\0'; 122376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor } 123376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor 124376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor int filename_len = strlen(filename); 125b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor int num = 0; 126b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor char *line; 127b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor for (line = strtok(buf, "\n"); 128b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor line != NULL && num < stats_count; 129b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor line = strtok(NULL, "\n")) { 130376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor // Line format: <sp>name<delim><sp>value 131376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor 132b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor int i; 133376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor while (isspace(*line)) ++line; 134b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor for (i = 0; i < skip_words; ++i) { 135b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor while (isgraph(*line)) ++line; 136b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor while (isspace(*line)) ++line; 137b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor } 138b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor 139376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor char *name_end = strchr(line, delimiter); 140b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor if (name_end == NULL) continue; 141b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor 142376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor // Key format: <filename>:<name> 143b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor struct data *data = &stats[num++]; 144376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor data->name = malloc(filename_len + 1 + (name_end - line) + 1); 145376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor unspace(data->name, filename, filename_len); 146376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor data->name[filename_len] = ':'; 147376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor unspace(data->name + filename_len + 1, line, name_end - line); 148376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor data->name[filename_len + 1 + (name_end - line)] = '\0'; 149b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor 150376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor char *value = name_end + 1; 151b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor while (isspace(*value)) ++value; 152b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor data->value = strdup(value); 153b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor } 154b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor 155b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor return num; 156b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor} 157b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor 158b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor// Read /proc/yaffs and write data entries for each line. 159b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor// Returns the number of entries written (always <= stats_count). 160b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnorstatic int read_proc_yaffs(struct data *stats, int stats_count) { 161b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor char buf[8192]; 162b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor int fd = open("/proc/yaffs", O_RDONLY); 163b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor if (fd < 0) return 0; 164b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor 165b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor int len = read(fd, buf, sizeof(buf) - 1); 166b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor if (len < 0) { 167b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor perror("/proc/yaffs"); 168b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor close(fd); 169b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor return 0; 170b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor } 171b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor buf[len] = '\0'; 172b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor close(fd); 173b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor 174b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor int num = 0, device_len = 0; 175b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor char *line, *device = NULL; 176b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor for (line = strtok(buf, "\n"); 177b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor line != NULL && num < stats_count; 178b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor line = strtok(NULL, "\n")) { 179b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor if (strncmp(line, "Device ", 7) == 0) { 180b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor device = strchr(line, '"'); 181b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor if (device != NULL) { 182b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor char *end = strchr(++device, '"'); 183b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor if (end != NULL) *end = '\0'; 184b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor device_len = strlen(device); 185b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor } 186b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor continue; 187b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor } 188b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor if (device == NULL) continue; 189b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor 190b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor char *name_end = line + strcspn(line, " ."); 191b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor if (name_end == line || *name_end == '\0') continue; 192b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor 193b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor struct data *data = &stats[num++]; 194b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor data->name = malloc(12 + device_len + 1 + (name_end - line) + 1); 195376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor memcpy(data->name, "/proc/yaffs:", 12); 196376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor unspace(data->name + 12, device, device_len); 197376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor data->name[12 + device_len] = ':'; 198376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor unspace(data->name + 12 + device_len + 1, line, name_end - line); 199b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor data->name[12 + device_len + 1 + (name_end - line)] = '\0'; 200b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor 201b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor char *value = name_end; 202b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor while (*value == '.' || isspace(*value)) ++value; 203b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor data->value = strdup(value); 204b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor } 205b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor 206b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor return num; 207b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor} 208b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor 209b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor// Compare two "struct data" records by their name. 210b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnorstatic int compare_data(const void *a, const void *b) { 211b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor const struct data *data_a = (const struct data *) a; 212b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor const struct data *data_b = (const struct data *) b; 213b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor return strcmp(data_a->name, data_b->name); 214b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor} 215b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor 216b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor// Return a malloc'd array of "struct data" read from all over /proc. 217b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor// The array is sorted by name and terminated by a record with name == NULL. 218376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnorstatic struct data *read_stats(char *names[], int name_count) { 219376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor static int bad[4096]; // Cache pids known not to match patterns 220376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor static size_t bad_count = 0; 221376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor 222b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor int pids[4096]; 223b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor size_t pid_count = 0; 224b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor 225b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor DIR *proc_dir = opendir("/proc"); 226b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor if (proc_dir == NULL) { 227b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor perror("Can't scan /proc"); 228b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor exit(1); 229b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor } 230b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor 231376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor size_t bad_pos = 0; 232b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor char filename[1024]; 233b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor struct dirent *proc_entry; 234b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor while ((proc_entry = readdir(proc_dir))) { 235b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor int pid = atoi(proc_entry->d_name); 236376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor if (pid <= 0) continue; 237376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor 238376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor if (name_count > 0) { 239376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor while (bad_pos < bad_count && bad[bad_pos] < pid) ++bad_pos; 240376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor if (bad_pos < bad_count && bad[bad_pos] == pid) continue; 241376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor 242376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor char cmdline[4096]; 243376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor sprintf(filename, "/proc/%d/cmdline", pid); 244376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor int fd = open(filename, O_RDONLY); 245376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor if (fd < 0) { 246376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor perror(filename); 247376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor continue; 248376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor } 249376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor 250376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor int len = read(fd, cmdline, sizeof(cmdline) - 1); 251376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor if (len < 0) { 252376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor perror(filename); 253376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor close(fd); 254376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor continue; 255376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor } 256376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor 257376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor close(fd); 258376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor cmdline[len] = '\0'; 259376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor int n; 260376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor for (n = 0; n < name_count && !strstr(cmdline, names[n]); ++n); 261376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor 262376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor if (n == name_count) { 263376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor // Insertion sort -- pids mostly increase so this makes sense 264376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor if (bad_count < sizeof(bad) / sizeof(bad[0])) { 265376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor int pos = bad_count++; 266376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor while (pos > 0 && bad[pos - 1] > pid) { 267376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor bad[pos] = bad[pos - 1]; 268376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor --pos; 269376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor } 270376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor bad[pos] = pid; 271376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor } 272376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor continue; 273b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor } 274376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor } 275376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor 276376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor if (pid_count >= sizeof(pids) / sizeof(pids[0])) { 277376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor fprintf(stderr, "warning: >%d processes\n", pid_count); 278376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor } else { 279b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor pids[pid_count++] = pid; 280b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor } 281b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor } 282b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor closedir(proc_dir); 283b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor 284376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor size_t i, stats_count = pid_count * 2 + 200; // 200 for stat, yaffs, etc. 285b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor struct data *stats = malloc((stats_count + 1) * sizeof(struct data)); 286b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor struct data *next = stats; 287b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor for (i = 0; i < pid_count; i++) { 288376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor assert(pids[i] > 0); 289b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor sprintf(filename, "/proc/%d/stat", pids[i]); 290b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor read_data(next++, filename); 291b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor sprintf(filename, "/proc/%d/wchan", pids[i]); 292b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor read_data(next++, filename); 293b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor } 294b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor 295376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor struct data *end = stats + stats_count; 296b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor next += read_proc_yaffs(next, stats + stats_count - next); 297b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor next += read_lines("/proc/net/dev", ':', NULL, 0, next, end - next); 298b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor next += read_lines("/proc/stat", ' ', NULL, 0, next, end - next); 299b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor next += read_lines("/proc/binder/stats", ':', "\nproc ", 0, next, end - next); 300b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor next += read_lines("/proc/diskstats", ' ', NULL, 2, next, end - next); 301376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor next += read_lines( 302376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state", 303b478656a6fbd88c7e1f3682d899126807ab8c1b3Dan Egnor ' ', NULL, 0, next, end - next); 304b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor 305b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor assert(next < stats + stats_count); 306b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor next->name = NULL; 307b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor next->value = NULL; 308b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor qsort(stats, next - stats, sizeof(struct data), compare_data); 309b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor return stats; 310b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor} 311b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor 312b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor// Print stats which have changed from one sorted array to the next. 313b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnorstatic void diff_stats(struct data *old_stats, struct data *new_stats) { 314b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor while (old_stats->name != NULL || new_stats->name != NULL) { 315b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor int compare; 316b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor if (old_stats->name == NULL) { 317b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor compare = 1; 318b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor } else if (new_stats->name == NULL) { 319b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor compare = -1; 320b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor } else { 321b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor compare = compare_data(old_stats, new_stats); 322b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor } 323b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor 324b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor if (compare < 0) { 325b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor // old_stats no longer present 326b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor if (old_stats->value != NULL) { 327b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor printf("%s -\n", old_stats->name); 328b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor } 329b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor ++old_stats; 330b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor } else if (compare > 0) { 331b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor // new_stats is new 332b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor if (new_stats->value != NULL) { 333b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor printf("%s + %s\n", new_stats->name, new_stats->value); 334b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor } 335b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor ++new_stats; 336b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor } else { 337b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor // changed 338b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor if (new_stats->value == NULL) { 339b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor if (old_stats->value != NULL) { 340b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor printf("%s -\n", old_stats->name); 341b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor } 342b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor } else if (old_stats->value == NULL) { 343b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor printf("%s + %s\n", new_stats->name, new_stats->value); 344b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor } else if (strcmp(old_stats->value, new_stats->value)) { 345b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor printf("%s = %s\n", new_stats->name, new_stats->value); 346b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor } 347b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor ++old_stats; 348b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor ++new_stats; 349b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor } 350b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor } 351b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor} 352b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor 353b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor// Free a "struct data" array and all the strings within it. 354b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnorstatic void free_stats(struct data *stats) { 355b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor int i; 356b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor for (i = 0; stats[i].name != NULL; ++i) { 357b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor free(stats[i].name); 358b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor free(stats[i].value); 359b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor } 360b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor free(stats); 361b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor} 362b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor 363b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnorint main(int argc, char *argv[]) { 364376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor if (argc < 2) { 365b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor fprintf(stderr, 366376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor "usage: procstatlog poll_interval [procname ...] > procstat.log\n\n" 367376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor "\n" 368b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor "Scans process status every poll_interval seconds (e.g. 0.1)\n" 369b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor "and writes data from /proc/stat, /proc/*/stat files, and\n" 370b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor "other /proc status files every time something changes.\n" 371376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor "\n" 372376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor "Scans all processes by default. Listing some process name\n" 373376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor "substrings will limit scanning and reduce overhead.\n" 374376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor "\n" 375b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor "Data is logged continuously until the program is killed.\n"); 376b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor return 2; 377b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor } 378b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor 379b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor long poll_usec = (long) (atof(argv[1]) * 1000000l); 380b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor if (poll_usec <= 0) { 381b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor fprintf(stderr, "illegal poll interval: %s\n", argv[1]); 382b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor return 2; 383b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor } 384b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor 385b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor struct data *old_stats = malloc(sizeof(struct data)); 386b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor old_stats->name = NULL; 387b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor old_stats->value = NULL; 388b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor while (1) { 389b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor struct timeval before, after; 390b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor gettimeofday(&before, NULL); 391b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor printf("T + %ld.%06ld\n", before.tv_sec, before.tv_usec); 392b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor 393376b3009a0d438a16fb7d6c27e19839cd1bb3f1fDan Egnor struct data *new_stats = read_stats(argv + 2, argc - 2); 394b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor diff_stats(old_stats, new_stats); 395b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor free_stats(old_stats); 396b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor old_stats = new_stats; 397b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor gettimeofday(&after, NULL); 398b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor printf("T - %ld.%06ld\n", after.tv_sec, after.tv_usec); 399b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor 400b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor long elapsed_usec = (long) after.tv_usec - before.tv_usec; 401b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor elapsed_usec += 1000000l * (after.tv_sec - before.tv_sec); 402b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor if (poll_usec > elapsed_usec) usleep(poll_usec - elapsed_usec); 403b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor } 404b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor 405b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor return 0; 406b897e9f6cdd0b229bddb5eb9439f87ac744bae42Dan Egnor} 407