library <stat>: input file buffer size must be dynamic
Since its introduction, our evolved /proc/stat API has
relied on a static buffer of 8192 bytes. This approach
is probably Ok for other /proc files but it would only
accommodate around 100 processors. If such a threshold
were exceeded then this interface could never succeed.
Now days 100 processors doesn't seem at all excessive.
So this commit trades that static buffer for a dynamic
self-tuning one. And since so much former top CPU code
was already rolled into this module, we just stole the
already proven top dynamic buffer management code too.
[ this also meant switching low level unbuffered I/O ]
[ calls to standard library buffered I/O calls. that ]
[ is exactly what <slabinfo> and <diskstats> employ. ]
Reference(s):
. 1st gen readstat introduction
commit a410e236ab
Signed-off-by: Jim Warner <james.warner@comcast.net>
This commit is contained in:
parent
282ee362f0
commit
ea930f6f9e
65
proc/stat.c
65
proc/stat.c
@ -38,6 +38,7 @@
|
|||||||
|
|
||||||
#define STAT_FILE "/proc/stat"
|
#define STAT_FILE "/proc/stat"
|
||||||
|
|
||||||
|
#define BUFFER_INCR 4096 // amount i/p buffer allocations grow
|
||||||
#define STACKS_INCR 32 // amount reap stack allocations grow
|
#define STACKS_INCR 32 // amount reap stack allocations grow
|
||||||
#define NEWOLD_INCR 32 // amount jiffs hist allocations grow
|
#define NEWOLD_INCR 32 // amount jiffs hist allocations grow
|
||||||
|
|
||||||
@ -118,7 +119,9 @@ struct reap_support {
|
|||||||
|
|
||||||
struct stat_info {
|
struct stat_info {
|
||||||
int refcount;
|
int refcount;
|
||||||
int stat_fd;
|
FILE *stat_fp;
|
||||||
|
char *stat_buf; // grows to accommodate all /proc/stat
|
||||||
|
int stat_buf_size; // current size for the above stat_buf
|
||||||
struct hist_sys sys_hist; // SYS type management
|
struct hist_sys sys_hist; // SYS type management
|
||||||
struct hist_tic cpu_hist; // TIC type management for cpu summary
|
struct hist_tic cpu_hist; // TIC type management for cpu summary
|
||||||
struct reap_support cpus; // TIC type management for real cpus
|
struct reap_support cpus; // TIC type management for real cpus
|
||||||
@ -568,9 +571,9 @@ static int stat_read_failed (
|
|||||||
struct stat_info *info)
|
struct stat_info *info)
|
||||||
{
|
{
|
||||||
struct hist_tic *sum_ptr, *cpu_ptr;
|
struct hist_tic *sum_ptr, *cpu_ptr;
|
||||||
char buf[8192], *bp, *b;
|
char *bp, *b;
|
||||||
int i, rc, size;
|
int i, rc, num, tot_read;
|
||||||
unsigned long long llnum = 0;
|
unsigned long long llnum;
|
||||||
|
|
||||||
if (info == NULL)
|
if (info == NULL)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@ -583,24 +586,36 @@ static int stat_read_failed (
|
|||||||
info->cpus.hist.n_inuse = 0;
|
info->cpus.hist.n_inuse = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (-1 == info->stat_fd && (info->stat_fd = open(STAT_FILE, O_RDONLY)) == -1)
|
if (!info->stat_fp
|
||||||
return -errno;
|
&& (!(info->stat_fp = fopen(STAT_FILE, "r"))))
|
||||||
if (lseek(info->stat_fd, 0L, SEEK_SET) == -1)
|
|
||||||
return -errno;
|
return -errno;
|
||||||
|
fflush(info->stat_fp);
|
||||||
|
rewind(info->stat_fp);
|
||||||
|
|
||||||
for (;;) {
|
#define maxSIZ info->stat_buf_size
|
||||||
if ((size = read(info->stat_fd, buf, sizeof(buf)-1)) < 0) {
|
#define curSIZ ( maxSIZ - tot_read )
|
||||||
if (errno == EINTR || errno == EAGAIN)
|
#define curPOS ( info->stat_buf + tot_read )
|
||||||
continue;
|
/* we slurp in the entire directory thus avoiding repeated calls to fread, |
|
||||||
return -errno;
|
especially in a massively parallel environment. additionally, each cpu |
|
||||||
}
|
line is then frozen in time rather than changing until we get around to |
|
||||||
|
accessing it. this helps to minimize (not eliminate) some distortions. | */
|
||||||
|
tot_read = errno = 0;
|
||||||
|
while ((0 < (num = fread(curPOS, 1, curSIZ, info->stat_fp)))) {
|
||||||
|
tot_read += num;
|
||||||
|
if (tot_read < maxSIZ)
|
||||||
break;
|
break;
|
||||||
}
|
maxSIZ += BUFFER_INCR;
|
||||||
if (size == 0) {
|
if (!(info->stat_buf = realloc(info->stat_buf, maxSIZ)))
|
||||||
return -EIO;
|
return -ENOMEM;
|
||||||
}
|
};
|
||||||
buf[size] = '\0';
|
#undef maxSIZ
|
||||||
bp = buf;
|
#undef curSIZ
|
||||||
|
#undef curPOS
|
||||||
|
|
||||||
|
if (!feof(info->stat_fp))
|
||||||
|
return -errno;
|
||||||
|
info->stat_buf[tot_read] = '\0';
|
||||||
|
bp = info->stat_buf;
|
||||||
|
|
||||||
sum_ptr = &info->cpu_hist;
|
sum_ptr = &info->cpu_hist;
|
||||||
// remember summary from last time around
|
// remember summary from last time around
|
||||||
@ -892,9 +907,12 @@ PROCPS_EXPORT int procps_stat_new (
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (!(p = calloc(1, sizeof(struct stat_info))))
|
if (!(p = calloc(1, sizeof(struct stat_info))))
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
if (!(p->stat_buf = calloc(1, BUFFER_INCR))) {
|
||||||
|
free(p);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
p->stat_buf_size = BUFFER_INCR;
|
||||||
p->refcount = 1;
|
p->refcount = 1;
|
||||||
p->stat_fd = -1;
|
|
||||||
|
|
||||||
p->results.cpus = &p->cpus.result;
|
p->results.cpus = &p->cpus.result;
|
||||||
p->results.nodes = &p->nodes.result;
|
p->results.nodes = &p->nodes.result;
|
||||||
@ -962,6 +980,11 @@ PROCPS_EXPORT int procps_stat_unref (
|
|||||||
(*info)->refcount--;
|
(*info)->refcount--;
|
||||||
|
|
||||||
if ((*info)->refcount < 1) {
|
if ((*info)->refcount < 1) {
|
||||||
|
if ((*info)->stat_fp)
|
||||||
|
fclose((*info)->stat_fp);
|
||||||
|
if ((*info)->stat_buf)
|
||||||
|
free((*info)->stat_buf);
|
||||||
|
|
||||||
if ((*info)->cpus.anchor)
|
if ((*info)->cpus.anchor)
|
||||||
free((*info)->cpus.anchor);
|
free((*info)->cpus.anchor);
|
||||||
if ((*info)->cpus.result.stacks)
|
if ((*info)->cpus.result.stacks)
|
||||||
|
Loading…
Reference in New Issue
Block a user