19ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor/* 29ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor * Copyright (C) 2010 The Android Open Source Project 39ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor * 49ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor * Licensed under the Apache License, Version 2.0 (the "License"); 59ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor * you may not use this file except in compliance with the License. 69ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor * You may obtain a copy of the License at 79ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor * 89ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor * http://www.apache.org/licenses/LICENSE-2.0 99ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor * 109ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor * Unless required by applicable law or agreed to in writing, software 119ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor * distributed under the License is distributed on an "AS IS" BASIS, 129ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor * See the License for the specific language governing permissions and 149ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor * limitations under the License. 159ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor */ 169ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor 179ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor#include <assert.h> 189ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor#include <ctype.h> 199ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor#include <dirent.h> 209ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor#include <fcntl.h> 219ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor#include <stdio.h> 229ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor#include <stdlib.h> 239ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor#include <string.h> 249ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor#include <sys/stat.h> 259ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor#include <sys/time.h> 269ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor#include <sys/types.h> 279ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor#include <time.h> 289ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor#include <unistd.h> 299ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor 309ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor// This program is as dumb as possible -- it reads a whole bunch of data 319ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor// from /proc and reports when it changes. It's up to analysis tools to 329ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor// actually parse the data. This program only does enough parsing to split 339ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor// large files (/proc/stat, /proc/yaffs) into individual values. 349ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor// 359ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor// The output format is a repeating series of observed differences: 369ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor// 379ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor// T + <beforetime.stamp> 389ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor// /proc/<new_filename> + <contents of newly discovered file> 399ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor// /proc/<changed_filename> = <contents of changed file> 409ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor// /proc/<deleted_filename> - 419ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor// /proc/<filename>:<label> = <part of a multiline file> 429ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor// T - <aftertime.stamp> 439ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor// 449ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor// 459ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor// Files read: 469ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor// 47bbb8304e20da95f79b76df1a5b905503c8988457Dan Egnor// /proc/*/stat - for all running/selected processes 48bbb8304e20da95f79b76df1a5b905503c8988457Dan Egnor// /proc/*/wchan - for all running/selected processes 49bbb8304e20da95f79b76df1a5b905503c8988457Dan Egnor// /proc/binder/stats - per line: "/proc/binder/stats:BC_REPLY" 50bbb8304e20da95f79b76df1a5b905503c8988457Dan Egnor// /proc/diskstats - per device: "/proc/diskstats:mmcblk0" 51bbb8304e20da95f79b76df1a5b905503c8988457Dan Egnor// /proc/net/dev - per interface: "/proc/net/dev:rmnet0" 52bbb8304e20da95f79b76df1a5b905503c8988457Dan Egnor// /proc/stat - per line: "/proc/stat:intr" 53bbb8304e20da95f79b76df1a5b905503c8988457Dan Egnor// /proc/yaffs - per device/line: "/proc/yaffs:userdata:nBlockErasures" 54bbb8304e20da95f79b76df1a5b905503c8988457Dan Egnor// /sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state 55bbb8304e20da95f79b76df1a5b905503c8988457Dan Egnor// - per line: "/sys/.../time_in_state:245000" 569ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor 579ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnorstruct data { 589ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor char *name; // filename, plus ":var" for many-valued files 599ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor char *value; // text to be reported when it changes 609ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor}; 619ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor 62c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor// Like memcpy, but replaces spaces and unprintables with '_'. 63c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnorstatic void unspace(char *dest, const char *src, int len) { 64c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor while (len-- > 0) { 65c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor char ch = *src++; 66c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor *dest++ = isgraph(ch) ? ch : '_'; 67c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor } 68c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor} 69c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor 709ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor// Set data->name and data->value to malloc'd strings with the 719ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor// filename and contents of the file. Trims trailing whitespace. 729ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnorstatic void read_data(struct data *data, const char *filename) { 739ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor char buf[4096]; 749ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor data->name = strdup(filename); 759ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor int fd = open(filename, O_RDONLY); 769ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor if (fd < 0) { 779ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor data->value = NULL; 789ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor return; 799ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor } 809ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor 819ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor int len = read(fd, buf, sizeof(buf)); 829ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor if (len < 0) { 839ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor perror(filename); 849ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor close(fd); 859ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor data->value = NULL; 869ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor return; 879ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor } 889ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor 899ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor close(fd); 909ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor while (len > 0 && isspace(buf[len - 1])) --len; 919ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor data->value = malloc(len + 1); 929ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor memcpy(data->value, buf, len); 939ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor data->value[len] = '\0'; 949ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor} 959ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor 96c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor// Read a name/value file and write data entries for each line. 979ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor// Returns the number of entries written (always <= stats_count). 98bbb8304e20da95f79b76df1a5b905503c8988457Dan Egnor// 99bbb8304e20da95f79b76df1a5b905503c8988457Dan Egnor// delimiter: used to split each line into name and value 100bbb8304e20da95f79b76df1a5b905503c8988457Dan Egnor// terminator: if non-NULL, processing stops after this string 101bbb8304e20da95f79b76df1a5b905503c8988457Dan Egnor// skip_words: skip this many words at the start of each line 102c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnorstatic int read_lines( 103bbb8304e20da95f79b76df1a5b905503c8988457Dan Egnor const char *filename, 104bbb8304e20da95f79b76df1a5b905503c8988457Dan Egnor char delimiter, const char *terminator, int skip_words, 105c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor struct data *stats, int stats_count) { 106c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor char buf[8192]; 107c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor int fd = open(filename, O_RDONLY); 1089ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor if (fd < 0) return 0; 1099ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor 1109ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor int len = read(fd, buf, sizeof(buf) - 1); 1119ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor if (len < 0) { 112c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor perror(filename); 1139ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor close(fd); 1149ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor return 0; 1159ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor } 1169ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor buf[len] = '\0'; 1179ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor close(fd); 1189ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor 119c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor if (terminator != NULL) { 120c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor char *end = strstr(buf, terminator); 121c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor if (end != NULL) *end = '\0'; 122c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor } 123c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor 124c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor int filename_len = strlen(filename); 1259ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor int num = 0; 1269ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor char *line; 1279ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor for (line = strtok(buf, "\n"); 1289ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor line != NULL && num < stats_count; 1299ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor line = strtok(NULL, "\n")) { 130c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor // Line format: <sp>name<delim><sp>value 131c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor 132bbb8304e20da95f79b76df1a5b905503c8988457Dan Egnor int i; 133c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor while (isspace(*line)) ++line; 134bbb8304e20da95f79b76df1a5b905503c8988457Dan Egnor for (i = 0; i < skip_words; ++i) { 135bbb8304e20da95f79b76df1a5b905503c8988457Dan Egnor while (isgraph(*line)) ++line; 136bbb8304e20da95f79b76df1a5b905503c8988457Dan Egnor while (isspace(*line)) ++line; 137bbb8304e20da95f79b76df1a5b905503c8988457Dan Egnor } 138bbb8304e20da95f79b76df1a5b905503c8988457Dan Egnor 139c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor char *name_end = strchr(line, delimiter); 1409ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor if (name_end == NULL) continue; 1419ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor 142c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor // Key format: <filename>:<name> 1439ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor struct data *data = &stats[num++]; 144c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor data->name = malloc(filename_len + 1 + (name_end - line) + 1); 145c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor unspace(data->name, filename, filename_len); 146c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor data->name[filename_len] = ':'; 147c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor unspace(data->name + filename_len + 1, line, name_end - line); 148c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor data->name[filename_len + 1 + (name_end - line)] = '\0'; 1499ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor 150c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor char *value = name_end + 1; 1519ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor while (isspace(*value)) ++value; 1529ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor data->value = strdup(value); 1539ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor } 1549ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor 1559ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor return num; 1569ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor} 1579ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor 1589ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor// Read /proc/yaffs and write data entries for each line. 1599ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor// Returns the number of entries written (always <= stats_count). 1609ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnorstatic int read_proc_yaffs(struct data *stats, int stats_count) { 1619ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor char buf[8192]; 1629ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor int fd = open("/proc/yaffs", O_RDONLY); 1639ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor if (fd < 0) return 0; 1649ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor 1659ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor int len = read(fd, buf, sizeof(buf) - 1); 1669ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor if (len < 0) { 1679ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor perror("/proc/yaffs"); 1689ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor close(fd); 1699ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor return 0; 1709ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor } 1719ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor buf[len] = '\0'; 1729ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor close(fd); 1739ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor 1749ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor int num = 0, device_len = 0; 1759ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor char *line, *device = NULL; 1769ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor for (line = strtok(buf, "\n"); 1779ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor line != NULL && num < stats_count; 1789ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor line = strtok(NULL, "\n")) { 1799ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor if (strncmp(line, "Device ", 7) == 0) { 1809ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor device = strchr(line, '"'); 1819ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor if (device != NULL) { 1829ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor char *end = strchr(++device, '"'); 1839ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor if (end != NULL) *end = '\0'; 1849ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor device_len = strlen(device); 1859ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor } 1869ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor continue; 1879ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor } 1889ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor if (device == NULL) continue; 1899ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor 1909ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor char *name_end = line + strcspn(line, " ."); 1919ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor if (name_end == line || *name_end == '\0') continue; 1929ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor 1939ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor struct data *data = &stats[num++]; 1949ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor data->name = malloc(12 + device_len + 1 + (name_end - line) + 1); 195c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor memcpy(data->name, "/proc/yaffs:", 12); 196c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor unspace(data->name + 12, device, device_len); 197c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor data->name[12 + device_len] = ':'; 198c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor unspace(data->name + 12 + device_len + 1, line, name_end - line); 1999ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor data->name[12 + device_len + 1 + (name_end - line)] = '\0'; 2009ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor 2019ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor char *value = name_end; 2029ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor while (*value == '.' || isspace(*value)) ++value; 2039ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor data->value = strdup(value); 2049ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor } 2059ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor 2069ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor return num; 2079ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor} 2089ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor 2099ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor// Compare two "struct data" records by their name. 2109ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnorstatic int compare_data(const void *a, const void *b) { 2119ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor const struct data *data_a = (const struct data *) a; 2129ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor const struct data *data_b = (const struct data *) b; 2139ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor return strcmp(data_a->name, data_b->name); 2149ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor} 2159ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor 2169ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor// Return a malloc'd array of "struct data" read from all over /proc. 2179ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor// The array is sorted by name and terminated by a record with name == NULL. 218c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnorstatic struct data *read_stats(char *names[], int name_count) { 219c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor static int bad[4096]; // Cache pids known not to match patterns 220c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor static size_t bad_count = 0; 221c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor 2229ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor int pids[4096]; 2239ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor size_t pid_count = 0; 2249ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor 2259ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor DIR *proc_dir = opendir("/proc"); 2269ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor if (proc_dir == NULL) { 2279ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor perror("Can't scan /proc"); 2289ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor exit(1); 2299ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor } 2309ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor 231c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor size_t bad_pos = 0; 2329ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor char filename[1024]; 2339ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor struct dirent *proc_entry; 2349ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor while ((proc_entry = readdir(proc_dir))) { 2359ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor int pid = atoi(proc_entry->d_name); 236c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor if (pid <= 0) continue; 237c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor 238c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor if (name_count > 0) { 239c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor while (bad_pos < bad_count && bad[bad_pos] < pid) ++bad_pos; 240c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor if (bad_pos < bad_count && bad[bad_pos] == pid) continue; 241c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor 242c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor char cmdline[4096]; 243c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor sprintf(filename, "/proc/%d/cmdline", pid); 244c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor int fd = open(filename, O_RDONLY); 245c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor if (fd < 0) { 246c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor perror(filename); 247c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor continue; 248c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor } 249c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor 250c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor int len = read(fd, cmdline, sizeof(cmdline) - 1); 251c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor if (len < 0) { 252c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor perror(filename); 253c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor close(fd); 254c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor continue; 255c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor } 256c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor 257c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor close(fd); 258c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor cmdline[len] = '\0'; 259c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor int n; 260c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor for (n = 0; n < name_count && !strstr(cmdline, names[n]); ++n); 261c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor 262c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor if (n == name_count) { 263c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor // Insertion sort -- pids mostly increase so this makes sense 264c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor if (bad_count < sizeof(bad) / sizeof(bad[0])) { 265c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor int pos = bad_count++; 266c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor while (pos > 0 && bad[pos - 1] > pid) { 267c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor bad[pos] = bad[pos - 1]; 268c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor --pos; 269c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor } 270c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor bad[pos] = pid; 271c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor } 272c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor continue; 2739ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor } 274c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor } 275c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor 276c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor if (pid_count >= sizeof(pids) / sizeof(pids[0])) { 2779295b85ec3b4eb30e8fdd524a810033ae2aec633Marcus Oakland fprintf(stderr, "warning: >%zu processes\n", pid_count); 278c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor } else { 2799ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor pids[pid_count++] = pid; 2809ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor } 2819ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor } 2829ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor closedir(proc_dir); 2839ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor 284c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor size_t i, stats_count = pid_count * 2 + 200; // 200 for stat, yaffs, etc. 2859ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor struct data *stats = malloc((stats_count + 1) * sizeof(struct data)); 2869ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor struct data *next = stats; 2879ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor for (i = 0; i < pid_count; i++) { 288c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor assert(pids[i] > 0); 2899ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor sprintf(filename, "/proc/%d/stat", pids[i]); 2909ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor read_data(next++, filename); 2919ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor sprintf(filename, "/proc/%d/wchan", pids[i]); 2929ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor read_data(next++, filename); 2939ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor } 2949ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor 295c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor struct data *end = stats + stats_count; 2969ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor next += read_proc_yaffs(next, stats + stats_count - next); 297bbb8304e20da95f79b76df1a5b905503c8988457Dan Egnor next += read_lines("/proc/net/dev", ':', NULL, 0, next, end - next); 298bbb8304e20da95f79b76df1a5b905503c8988457Dan Egnor next += read_lines("/proc/stat", ' ', NULL, 0, next, end - next); 299bbb8304e20da95f79b76df1a5b905503c8988457Dan Egnor next += read_lines("/proc/binder/stats", ':', "\nproc ", 0, next, end - next); 300bbb8304e20da95f79b76df1a5b905503c8988457Dan Egnor next += read_lines("/proc/diskstats", ' ', NULL, 2, next, end - next); 301c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor next += read_lines( 302c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state", 303bbb8304e20da95f79b76df1a5b905503c8988457Dan Egnor ' ', NULL, 0, next, end - next); 3049ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor 3059ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor assert(next < stats + stats_count); 3069ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor next->name = NULL; 3079ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor next->value = NULL; 3089ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor qsort(stats, next - stats, sizeof(struct data), compare_data); 3099ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor return stats; 3109ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor} 3119ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor 3129ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor// Print stats which have changed from one sorted array to the next. 3139ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnorstatic void diff_stats(struct data *old_stats, struct data *new_stats) { 3149ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor while (old_stats->name != NULL || new_stats->name != NULL) { 3159ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor int compare; 3169ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor if (old_stats->name == NULL) { 3179ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor compare = 1; 3189ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor } else if (new_stats->name == NULL) { 3199ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor compare = -1; 3209ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor } else { 3219ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor compare = compare_data(old_stats, new_stats); 3229ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor } 3239ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor 3249ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor if (compare < 0) { 3259ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor // old_stats no longer present 3269ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor if (old_stats->value != NULL) { 3279ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor printf("%s -\n", old_stats->name); 3289ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor } 3299ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor ++old_stats; 3309ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor } else if (compare > 0) { 3319ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor // new_stats is new 3329ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor if (new_stats->value != NULL) { 3339ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor printf("%s + %s\n", new_stats->name, new_stats->value); 3349ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor } 3359ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor ++new_stats; 3369ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor } else { 3379ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor // changed 3389ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor if (new_stats->value == NULL) { 3399ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor if (old_stats->value != NULL) { 3409ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor printf("%s -\n", old_stats->name); 3419ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor } 3429ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor } else if (old_stats->value == NULL) { 3439ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor printf("%s + %s\n", new_stats->name, new_stats->value); 3449ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor } else if (strcmp(old_stats->value, new_stats->value)) { 3459ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor printf("%s = %s\n", new_stats->name, new_stats->value); 3469ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor } 3479ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor ++old_stats; 3489ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor ++new_stats; 3499ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor } 3509ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor } 3519ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor} 3529ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor 3539ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor// Free a "struct data" array and all the strings within it. 3549ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnorstatic void free_stats(struct data *stats) { 3559ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor int i; 3569ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor for (i = 0; stats[i].name != NULL; ++i) { 3579ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor free(stats[i].name); 3589ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor free(stats[i].value); 3599ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor } 3609ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor free(stats); 3619ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor} 3629ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor 3639ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnorint main(int argc, char *argv[]) { 364c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor if (argc < 2) { 3659ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor fprintf(stderr, 366c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor "usage: procstatlog poll_interval [procname ...] > procstat.log\n\n" 367c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor "\n" 3689ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor "Scans process status every poll_interval seconds (e.g. 0.1)\n" 3699ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor "and writes data from /proc/stat, /proc/*/stat files, and\n" 3709ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor "other /proc status files every time something changes.\n" 371c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor "\n" 372c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor "Scans all processes by default. Listing some process name\n" 373c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor "substrings will limit scanning and reduce overhead.\n" 374c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor "\n" 3759ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor "Data is logged continuously until the program is killed.\n"); 3769ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor return 2; 3779ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor } 3789ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor 3799ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor long poll_usec = (long) (atof(argv[1]) * 1000000l); 3809ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor if (poll_usec <= 0) { 3819ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor fprintf(stderr, "illegal poll interval: %s\n", argv[1]); 3829ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor return 2; 3839ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor } 3849ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor 3859ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor struct data *old_stats = malloc(sizeof(struct data)); 3869ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor old_stats->name = NULL; 3879ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor old_stats->value = NULL; 3889ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor while (1) { 3899ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor struct timeval before, after; 3909ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor gettimeofday(&before, NULL); 3919ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor printf("T + %ld.%06ld\n", before.tv_sec, before.tv_usec); 3929ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor 393c58e5db92595ceb241125a84c4aee02b33c521ffDan Egnor struct data *new_stats = read_stats(argv + 2, argc - 2); 3949ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor diff_stats(old_stats, new_stats); 3959ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor free_stats(old_stats); 3969ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor old_stats = new_stats; 3979ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor gettimeofday(&after, NULL); 3989ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor printf("T - %ld.%06ld\n", after.tv_sec, after.tv_usec); 3999ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor 4009ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor long elapsed_usec = (long) after.tv_usec - before.tv_usec; 4019ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor elapsed_usec += 1000000l * (after.tv_sec - before.tv_sec); 4029ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor if (poll_usec > elapsed_usec) usleep(poll_usec - elapsed_usec); 4039ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor } 4049ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor 4059ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor return 0; 4069ba812360baf977f9fa02f8e031f6f8fba6a4380Dan Egnor} 407