Skip to content

Commit

Permalink
Merge b92ec15 into 31c8f3a
Browse files Browse the repository at this point in the history
  • Loading branch information
erthalion committed Feb 8, 2021
2 parents 31c8f3a + b92ec15 commit 594d5b5
Show file tree
Hide file tree
Showing 4 changed files with 153 additions and 3 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ on:

jobs:
tests:
runs-on: ubuntu-latest
runs-on: ubuntu-18.04
env:
PG: ${{ matrix.postgres-version }}
strategy:
Expand Down
19 changes: 17 additions & 2 deletions bg_mon.c
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,9 @@ static struct evbuffer *prepare_statistics_output(struct timeval time, system_st
cpu_stat c = s.cpu;
meminfo m = s.mem;
load_avg la = s.load_avg;
pressure *p_cpu = s.p_cpu;
pressure *p_memory = s.p_memory;
pressure *p_io = s.p_io;

bool is_first = true;
size_t i;
Expand All @@ -298,8 +301,20 @@ static struct evbuffer *prepare_statistics_output(struct timeval time, system_st
evbuffer_add_printf(evb, "[%4.6g, %4.6g, %4.6g],\"cpu\":{\"user\":", la.run_1min, la.run_5min, la.run_15min);
evbuffer_add_printf(evb, "%2.1f,\"nice\": %2.1f,\"system\":%2.1f,", c.utime_diff, c.ntime_diff, c.stime_diff);
evbuffer_add_printf(evb, "\"idle\":%2.1f,\"iowait\":%2.1f,\"steal\":%2.1f", c.idle_diff, c.iowait_diff, c.steal_diff);
evbuffer_add_printf(evb, "},\"ctxt\":%lu,\"processes\":{\"running\":%lu,\"blocked\":", s.ctxt_diff, s.procs_running);
evbuffer_add_printf(evb, " %lu},\"memory\":{\"total\":%lu,\"free\":%lu,", s.procs_blocked, m.total, m.free);
evbuffer_add_printf(evb, "},\"ctxt\":%lu,\"processes\":{\"running\":%lu,\"blocked\": %lu}", s.ctxt_diff, s.procs_running, s.procs_blocked);

if (s.pressure) {
evbuffer_add_printf(evb, ",\"pressure\":{\"cpu\":[%4.6g, %4.6g, %4.6g, %4.6g],",
p_cpu[0].avg10, p_cpu[0].avg60, p_cpu[0].avg300, p_cpu[0].total);
evbuffer_add_printf(evb, "\"memory\":{\"some\":[%4.6g, %4.6g, %4.6g, %4.6g],\"full\":[%4.6g, %4.6g, %4.6g, %4.6g]},",
p_memory[0].avg10, p_memory[0].avg60, p_memory[0].avg300, p_memory[0].total,
p_memory[1].avg10, p_memory[1].avg60, p_memory[1].avg300, p_memory[1].total);
evbuffer_add_printf(evb, "\"io\":{\"some\":[%4.6g, %4.6g, %4.6g, %4.6g],\"full\":[%4.6g, %4.6g, %4.6g, %4.6g]}}",
p_io[0].avg10, p_io[0].avg60, p_io[0].avg300, p_io[0].total,
p_io[1].avg10, p_io[1].avg60, p_io[1].avg300, p_io[1].total);
}

evbuffer_add_printf(evb, ",\"memory\":{\"total\":%lu,\"free\":%lu,", m.total, m.free);
evbuffer_add_printf(evb, "\"buffers\":%lu,\"cached\":%lu,\"dirty\":%lu", m.buffers, m.cached, m.dirty);

if (m.overcommit.memory == 2) {
Expand Down
85 changes: 85 additions & 0 deletions system_stats.c
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
#include <sys/utsname.h>
#include <unistd.h>
#include <sys/stat.h>

#include "system_stats.h"

#define PROC_OVERCOMMIT "/proc/sys/vm/overcommit_"
#define PROC_PRESSURE "/proc/pressure/"

extern char *cpu_cgroup_mount;
static char *cpu_cgroup = NULL;
Expand Down Expand Up @@ -47,6 +49,78 @@ static int proc_read_int(const char *name)
return ret;
}

/*
* Test if Linux Pressure Stall Information is available. Starting from linux
* kernel 4.20 it should manifest itself via /proc/pressure directory in procfs
* with cpu,memory,io files.
*/
static bool pressure_available()
{
struct stat sb;
int res;

res = stat("/proc/pressure", &sb);
return (res != -1) && S_ISDIR(sb.st_mode);
}

/*
* Pressure stall information for specified resource. PSI format for Memory and
* IO:
*
* some avg10=0.00 avg60=0.00 avg300=0.00 total=0
* full avg10=0.00 avg60=0.00 avg300=0.00 total=0
*
* For CPU only "some" line is present.
*
* The result returned via pressure array passed as the first argument.
*/
static void read_pressure(pressure *result, pressure_res resource)
{
FILE *f;

switch (resource)
{
case CPU:
f = fopen(PROC_PRESSURE "cpu", "r");
break;
case MEMORY:
f = fopen(PROC_PRESSURE "memory", "r");
break;
case IO:
f = fopen(PROC_PRESSURE "io", "r");
break;
default:
return;
}

if (f != NULL) {
char type[PTYPE_SIZE];
pressure p = {0, };

/* There could be either one or two lines */
for (int i = 0; i < 2; i++)
{
if (fscanf(f, "%s avg10=%f avg60=%f avg300=%f total=%f",
type, &p.avg10, &p.avg60, &p.avg300, &p.total) != 5)
break;

if (strncmp(type, "some", 4) == 0)
p.type = SOME;

if (strncmp(type, "full", 4) == 0)
p.type = FULL;

/* Undefined should not happen, but check just in case */
if (p.type == UNDEFINED)
break;

result[i] = p;
}

fclose(f);
}
}

static load_avg read_load_avg(void)
{
load_avg ret = {0, };
Expand Down Expand Up @@ -355,6 +429,17 @@ system_stat get_system_stats(void)
if (system_stats.uptime == 0)
system_stats.uptime = system_stats.cpu.uptime0;
system_stats.load_avg = read_load_avg();

if (pressure_available())
{
system_stats.pressure = true;
read_pressure((pressure *) &system_stats.p_cpu, CPU);
read_pressure((pressure *) &system_stats.p_memory, MEMORY);
read_pressure((pressure *) &system_stats.p_io, IO);
}
else
system_stats.pressure = false;

system_stats.mem = read_meminfo();
system_stats.sysname = sysname;
system_stats.hostname = get_hostname();
Expand Down
50 changes: 50 additions & 0 deletions system_stats.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,50 @@ typedef struct {
float run_15min;
} load_avg;

#define PTYPE_SIZE 4

/*
* The PSI feature identifies and quantifies the disruptions caused by resource
* contention and the time impact it has on complex workloads or even entire
* systems. This information is exposed in time shares, the ratios (in %) are
* tracked as recent trends over ten, sixty, three hundred second windows.
* Total time is exposed as well in us (1.0E-6 seconds).
*
* Monitored resources are cpu, memory or io. Pressure types:
*
* - "some" indicates the share of time in which at least some tasks are
* stalled on a given resource, but the CPU is still doing productive work.
*
* - "full" indicates the share of time in which all non-idle tasks are stalled
* on a given resource simultaneously. In this state actual CPU cycles are
* going to waste, and a workload that spends extended time in this state is
* considered to be thrashing.
*
* Pressure for CPU contains only type "some", while Memory and IO have both
* types.
*/
typedef enum pressure_type
{
UNDEFINED = 0,
SOME,
FULL,
} pressure_type;

typedef enum pressure_res
{
CPU = 0,
MEMORY,
IO,
} pressure_res;

typedef struct {
pressure_type type;
float avg10;
float avg60;
float avg300;
float total;
} pressure;

typedef struct {
int memory;
int ratio;
Expand Down Expand Up @@ -90,6 +134,12 @@ typedef struct {
cpu_stat cpu;
load_avg load_avg;
meminfo mem;
bool pressure; /* tells if PSI information is available */
pressure p_cpu[2]; /* PSI for CPU. Only of type "some" is used, but
for consistensy with other resources defined as
two elements array. */
pressure p_memory[2]; /* PSI for Memory (pair "some", "full") */
pressure p_io[2]; /* PSI for IO (pair "some", "full") */
char *sysname;
char *hostname;
} system_stat;
Expand Down

0 comments on commit 594d5b5

Please sign in to comment.