219 lines
7 KiB
C
219 lines
7 KiB
C
#include <stdio.h>
|
|
#include <ctype.h>
|
|
#include <string.h>
|
|
#include "global.h"
|
|
#include "procstat.h"
|
|
#include "devnames.h"
|
|
|
|
static ProcStats ps;
|
|
int use_proc_diskstats;
|
|
|
|
void pstat_init(struct pstat *pst, int nslice, float update_interval) {
|
|
pst->nslice = nslice;
|
|
ALLOC_VEC(pst->slices, nslice);
|
|
pst->cur_slice = 0;
|
|
pst->total = 0;
|
|
pst->update_interval = update_interval;
|
|
}
|
|
|
|
float pstat_current(struct pstat *pst) {
|
|
int idx = pst->cur_slice ? pst->cur_slice-1 : pst->nslice-1;
|
|
return pst->slices[idx]/pst->update_interval;
|
|
}
|
|
|
|
void pstat_add(struct pstat *pst, unsigned long v) {
|
|
pst->slices[pst->cur_slice] += v;
|
|
}
|
|
|
|
void pstat_advance(struct pstat *pst) {
|
|
unsigned long v = pst->slices[pst->cur_slice];
|
|
if (pst->total)
|
|
pst->slices[pst->cur_slice] -= pst->total;
|
|
else pst->slices[pst->cur_slice] = 0;
|
|
pst->total = v;
|
|
if (++pst->cur_slice >= pst->nslice) pst->cur_slice = 0;
|
|
pst->slices[pst->cur_slice] = 0;
|
|
}
|
|
|
|
float pstat_meanval(struct pstat *pst) {
|
|
unsigned long sum = 0;
|
|
int i;
|
|
for (i = 0; i < pst->nslice; ++i) sum += pst->slices[i];
|
|
return sum / pst->update_interval / (pst->nslice-1);
|
|
}
|
|
|
|
float get_read_throughput() {
|
|
return pstat_current(&ps.disk_read) / 2048.; /* 2048 because we log sector counts */
|
|
}
|
|
|
|
float get_write_throughput() {
|
|
return pstat_current(&ps.disk_write) / 2048.;
|
|
}
|
|
|
|
float get_swapin_throughput() {
|
|
return pstat_current(&ps.swap_in) / 2048.;
|
|
}
|
|
|
|
float get_swapout_throughput() {
|
|
return pstat_current(&ps.swap_out) / 2048.;
|
|
}
|
|
|
|
float get_read_mean_throughput() {
|
|
return pstat_meanval(&ps.disk_read) / 2048.;
|
|
}
|
|
|
|
float get_write_mean_throughput() {
|
|
return pstat_meanval(&ps.disk_write) / 2048.;
|
|
}
|
|
|
|
void update_stats() {
|
|
FILE *f;
|
|
char line[1024];
|
|
char hdname[200];
|
|
int readok = 0;
|
|
const char *proc_fname;
|
|
if (!use_proc_diskstats) proc_fname = "/proc/partitions";
|
|
else proc_fname = "/proc/diskstats";
|
|
|
|
f = fopen(proc_fname, "r");
|
|
if (!f) { perror(proc_fname); return; }
|
|
while (fgets(line, sizeof(line), f)) {
|
|
int major, minor;
|
|
unsigned long nr, nw;
|
|
const char *fmt = use_proc_diskstats ?
|
|
"%d %d %200s %*d %*d %lu %*d %*d %*d %lu" :
|
|
"%d %d %*u %200s %*d %*d %lu %*d %*d %*d %lu";
|
|
if (sscanf(line, fmt, &major, &minor, hdname, &nr, &nw) == 5 ||
|
|
(use_proc_diskstats && is_partition(major,minor) &&
|
|
/* .. kernel 2.5 uses a different format for partitions and disc */
|
|
sscanf(line, "%d %d %200s %*d %lu %*d %lu", &major, &minor, hdname, &nr, &nw) == 5)) {
|
|
DiskList *dl;
|
|
if (readok == 0) readok = 1;
|
|
if ((dl=find_dev(major,minor))) {
|
|
dl->touched_r = (dl->nr - nr) ? 10 : dl->touched_r;
|
|
dl->touched_w = (dl->nw - nw) ? 10 : dl->touched_w;
|
|
dl->nr = nr; dl->nw = nw;
|
|
if (is_displayed(dl->hd_id,dl->part_id) &&
|
|
((dl->part_id && (!find_id(dl->hd_id, 0) || !is_displayed(dl->hd_id, 0))) || /* partition without host disk */
|
|
(dl->part_id == 0))) /* disk */
|
|
{
|
|
if (!Prefs.debug_disk_rd) {
|
|
pstat_add(&ps.disk_read, nr);
|
|
} else {
|
|
static int cntr = 0; cntr+=(rand()%30) == 0 ? Prefs.debug_disk_rd : 0;
|
|
pstat_add(&ps.disk_read, nr + cntr);
|
|
}
|
|
if (!Prefs.debug_disk_wr) {
|
|
pstat_add(&ps.disk_write, nw);
|
|
} else {
|
|
static int cntw = 0; cntw+=(rand()%30) == 0 ? Prefs.debug_disk_wr : 0;
|
|
pstat_add(&ps.disk_write, nw + cntw);
|
|
}
|
|
readok = 2;
|
|
}
|
|
}
|
|
/* if (in_our_disk || find_dev(major,minor))*/ {
|
|
strlist *sl;
|
|
for (sl = swap_list(); sl; sl=sl->next) {
|
|
if (strcmp(stripdev(hdname), stripdev(sl->s)) == 0) {
|
|
if (!Prefs.debug_swapio) {
|
|
pstat_add(&ps.swap_in, nr);
|
|
pstat_add(&ps.swap_out, nw);
|
|
} else {
|
|
static int cnt = 0; cnt+=Prefs.debug_swapio;
|
|
pstat_add(&ps.swap_in, nr + cnt);
|
|
pstat_add(&ps.swap_out, nw + cnt);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
fclose(f);
|
|
pstat_advance(&ps.disk_read);pstat_advance(&ps.disk_write);
|
|
pstat_advance(&ps.swap_in);pstat_advance(&ps.swap_out);
|
|
if (readok == 0) { fprintf(stderr, "warning: could not find any info in %s (kernel too old?)\n", proc_fname); exit(1); }
|
|
else if (readok == 1) { ONLY_ONCE(fprintf(stderr, "warning: could not find any monitored disc in %s\n", proc_fname)); }
|
|
BLAHBLAH(1,printf("swap: %5.2f,%5.2f disc: %5.2f,%5.2f MB/s\n",
|
|
get_swapin_throughput(), get_swapout_throughput(),
|
|
get_read_throughput(), get_write_throughput()));
|
|
}
|
|
|
|
void init_stats(float update_interval) {
|
|
char s[512];
|
|
FILE *f;
|
|
|
|
pstat_init(&ps.swap_in, (int)(0.5/update_interval)+1, update_interval);
|
|
pstat_init(&ps.swap_out, (int)(0.5/update_interval)+1, update_interval);
|
|
pstat_init(&ps.disk_read, (int)(0.5/update_interval)+1, update_interval);
|
|
pstat_init(&ps.disk_write, (int)(0.5/update_interval)+1, update_interval);
|
|
f = fopen("/proc/swaps","r");
|
|
//if (!f) { perror("/proc/swaps"); exit(1); }
|
|
if (f) {
|
|
while (fgets(s, 512, f)) {
|
|
char *s2 = strchr(s,' ');
|
|
if (s2 && s2 != s && strncmp(s, "/dev/", 5) == 0) {
|
|
*s2 = 0;
|
|
add_swap(s);
|
|
BLAHBLAH(1,printf("found swap partition: %s\n", swap_list()->s));
|
|
}
|
|
}
|
|
fclose(f);
|
|
}
|
|
if (!swap_list()) {
|
|
fprintf(stderr, "Warning: no swap partition found in /proc/swaps !!\n");
|
|
}
|
|
if ((f=fopen("/proc/diskstats","r"))) {
|
|
use_proc_diskstats = 1; fclose(f);
|
|
}
|
|
else { use_proc_diskstats = 0; }
|
|
BLAHBLAH(1,printf("using %s for disc statistics\n", use_proc_diskstats ? "/proc/diskstats" : "/proc/partitions"));
|
|
}
|
|
|
|
|
|
|
|
/* hello I am brain-dead */
|
|
void scan_all_hd(int add_partitions) {
|
|
char s[512];
|
|
FILE *f = NULL;
|
|
/* find mounted partitions */
|
|
if (add_partitions && (f = fopen("/etc/mtab","r"))) {
|
|
while (fgets(s,512,f)) {
|
|
char partname[512], mountpoint[512];
|
|
mountpoint[0] = 0;
|
|
if (sscanf(s,"%500s %500s", partname, mountpoint)>=1) {
|
|
char *p = strchr(mountpoint, '/');
|
|
//printf("add_device_by_name(%s, %s)\n", partname, p);
|
|
add_device_by_name(partname, p);
|
|
}
|
|
}
|
|
}
|
|
if (f) fclose(f);
|
|
|
|
/* second try .. look for hard drives listed in proc/partitions (and only hard-drives .. their partitions
|
|
are supposed to be listed in mtab) */
|
|
if ((f = fopen("/proc/partitions","r"))) {
|
|
while (fgets(s,512,f)) {
|
|
unsigned major, minor;
|
|
char name[512]; name[0] = 0;
|
|
if (sscanf(s,"%d %d %*d %500s", &major, &minor, name)==3) {
|
|
int hd_id, part_id;
|
|
/* on n'ajoute que les disques dont au moins une partoche etait dans mtab */
|
|
if (device_info(major,minor,NULL,&hd_id,&part_id) != 0 && part_id == 0 && find_id(hd_id,-1)) {
|
|
add_device_by_id(major,minor,NULL);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (f) fclose(f);
|
|
/* for (c = 'a'; c <= 'z'; ++c) {
|
|
snprintf(s,512,"/proc/ide/hd%c/media",c);
|
|
if ((f = fopen(s,"r")) && fgets(s, 512, f) && strcmp(s, "disk\n")==0) {
|
|
snprintf(s, 512, "/dev/hd%c",c);
|
|
add_device(s, NULL);
|
|
}
|
|
if (f) fclose(f);
|
|
}*/
|
|
}
|