Pressure metrics (#43377)
This adds a slightly extended and improved version of the patch we had internally.
This commit is contained in:
+48
-26
@@ -6,6 +6,7 @@
|
||||
#include "extract-word.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
#include "log.h"
|
||||
#include "parse-util.h"
|
||||
#include "process-util.h"
|
||||
#include "procfs-util.h"
|
||||
@@ -127,12 +128,36 @@ static uint64_t calc_gcd64(uint64_t a, uint64_t b) {
|
||||
return a;
|
||||
}
|
||||
|
||||
nsec_t procfs_ticks_to_nsec(uint64_t ticks) {
|
||||
uint64_t ticks_per_second = sysconf_clock_ticks_cached(),
|
||||
gcd = calc_gcd64(NSEC_PER_SEC, ticks_per_second);
|
||||
|
||||
/* Reduce NSEC_PER_SEC/ticks_per_second first to avoid overflow of ticks * NSEC_PER_SEC, and split
|
||||
* the multiplication into whole and remainder parts, so that the result stays exact.
|
||||
*
|
||||
* Note that in most cases b == 1 and the second term is trivial. */
|
||||
uint64_t a = NSEC_PER_SEC / gcd,
|
||||
b = ticks_per_second / gcd;
|
||||
|
||||
return ticks / b * a + DIV_ROUND_UP(ticks % b * a, b);
|
||||
}
|
||||
|
||||
int procfs_cpu_get_usage(nsec_t *ret) {
|
||||
int r;
|
||||
|
||||
assert(ret);
|
||||
|
||||
ProcfsCpuTicks ticks;
|
||||
r = procfs_cpu_get_ticks(&ticks);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*ret = procfs_ticks_to_nsec(ticks.user + ticks.nice + ticks.system + ticks.irq + ticks.softirq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int procfs_cpu_get_ticks(ProcfsCpuTicks *ret) {
|
||||
_cleanup_free_ char *first_line = NULL;
|
||||
unsigned long user_ticks, nice_ticks, system_ticks, irq_ticks, softirq_ticks,
|
||||
guest_ticks = 0, guest_nice_ticks = 0;
|
||||
uint64_t sum, gcd, a, b;
|
||||
const char *p;
|
||||
int r;
|
||||
|
||||
assert(ret);
|
||||
@@ -141,33 +166,30 @@ int procfs_cpu_get_usage(nsec_t *ret) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
p = first_word(first_line, "cpu");
|
||||
const char *p = first_word(first_line, "cpu");
|
||||
if (!p)
|
||||
return -EINVAL;
|
||||
|
||||
if (sscanf(p, "%lu %lu %lu %*u %*u %lu %lu %*u %lu %lu",
|
||||
&user_ticks,
|
||||
&nice_ticks,
|
||||
&system_ticks,
|
||||
&irq_ticks,
|
||||
&softirq_ticks,
|
||||
&guest_ticks,
|
||||
&guest_nice_ticks) < 5) /* we only insist on the first five fields */
|
||||
/* All eight fields exist on any kernel we support: iowait was added in 2.5.41, steal in 2.6.11.
|
||||
* "guest" and "guest_nice" are not returned, the kernel already includes them in "user" and "nice".
|
||||
* Nevertheless, this file might be synthesized slopilly, so let's not require the last three fields.
|
||||
* We don't care about them in most cases anyway. */
|
||||
ProcfsCpuTicks t = {};
|
||||
r = sscanf(p, "%"SCNu64" %"SCNu64" %"SCNu64" %"SCNu64" %"SCNu64" %"SCNu64" %"SCNu64" %"SCNu64,
|
||||
&t.user,
|
||||
&t.nice,
|
||||
&t.system,
|
||||
&t.idle,
|
||||
&t.iowait,
|
||||
&t.irq,
|
||||
&t.softirq,
|
||||
&t.steal);
|
||||
if (r < 5)
|
||||
return -EINVAL;
|
||||
if (r < 8)
|
||||
log_once(LOG_INFO, "Short read (%d fields) from /proc/stat, continuing.", r);
|
||||
|
||||
uint64_t ticks_per_second = sysconf_clock_ticks_cached();
|
||||
|
||||
sum = (uint64_t) user_ticks + (uint64_t) nice_ticks + (uint64_t) system_ticks +
|
||||
(uint64_t) irq_ticks + (uint64_t) softirq_ticks +
|
||||
(uint64_t) guest_ticks + (uint64_t) guest_nice_ticks;
|
||||
|
||||
/* Let's reduce this fraction before we apply it to avoid overflows when converting this to μsec */
|
||||
gcd = calc_gcd64(NSEC_PER_SEC, ticks_per_second);
|
||||
|
||||
a = NSEC_PER_SEC / gcd;
|
||||
b = ticks_per_second / gcd;
|
||||
|
||||
*ret = DIV_ROUND_UP((nsec_t) sum * (nsec_t) a, (nsec_t) b);
|
||||
*ret = t;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,8 +9,22 @@ int procfs_get_threads_max(uint64_t *ret);
|
||||
int procfs_tasks_set_limit(uint64_t limit);
|
||||
int procfs_tasks_get_current(uint64_t *ret);
|
||||
|
||||
nsec_t procfs_ticks_to_nsec(uint64_t ticks);
|
||||
int procfs_cpu_get_usage(nsec_t *ret);
|
||||
|
||||
typedef struct ProcfsCpuTicks {
|
||||
uint64_t user;
|
||||
uint64_t nice;
|
||||
uint64_t system;
|
||||
uint64_t idle;
|
||||
uint64_t iowait;
|
||||
uint64_t irq;
|
||||
uint64_t softirq;
|
||||
uint64_t steal;
|
||||
} ProcfsCpuTicks;
|
||||
|
||||
int procfs_cpu_get_ticks(ProcfsCpuTicks *ret);
|
||||
|
||||
int procfs_memory_get(uint64_t *ret_total, uint64_t *ret_used);
|
||||
static inline int procfs_memory_get_used(uint64_t *ret) {
|
||||
return procfs_memory_get(NULL, ret);
|
||||
|
||||
@@ -19,7 +19,7 @@ int read_resource_pressure(const char *path, PressureType type, ResourcePressure
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
unsigned field_filled = 0;
|
||||
ResourcePressure rp = {};
|
||||
const char *t, *cline;
|
||||
const char *cline;
|
||||
char *word;
|
||||
int r;
|
||||
|
||||
@@ -27,12 +27,7 @@ int read_resource_pressure(const char *path, PressureType type, ResourcePressure
|
||||
assert(IN_SET(type, PRESSURE_TYPE_SOME, PRESSURE_TYPE_FULL));
|
||||
assert(ret);
|
||||
|
||||
if (type == PRESSURE_TYPE_SOME)
|
||||
t = "some";
|
||||
else if (type == PRESSURE_TYPE_FULL)
|
||||
t = "full";
|
||||
else
|
||||
return -EINVAL;
|
||||
const char *t = ASSERT_PTR(pressure_type_to_string(type));
|
||||
|
||||
r = fopen_unlocked(path, "re", &f);
|
||||
if (r < 0)
|
||||
@@ -131,6 +126,13 @@ static const char* const pressure_resource_table[_PRESSURE_RESOURCE_MAX] = {
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(pressure_resource, PressureResource);
|
||||
|
||||
static const char* const pressure_type_table[_PRESSURE_TYPE_MAX] = {
|
||||
[PRESSURE_TYPE_SOME] = "some",
|
||||
[PRESSURE_TYPE_FULL] = "full",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP(pressure_type, PressureType);
|
||||
|
||||
int is_pressure_supported(void) {
|
||||
static thread_local int cached = -1;
|
||||
int r;
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
typedef enum PressureType {
|
||||
PRESSURE_TYPE_SOME,
|
||||
PRESSURE_TYPE_FULL,
|
||||
_PRESSURE_TYPE_MAX,
|
||||
_PRESSURE_TYPE_INVALID = -EINVAL,
|
||||
} PressureType;
|
||||
|
||||
typedef enum PressureResource {
|
||||
@@ -50,6 +52,7 @@ static inline const PressureResourceInfo* pressure_resource_get_info(PressureRes
|
||||
}
|
||||
|
||||
DECLARE_STRING_TABLE_LOOKUP(pressure_resource, PressureResource);
|
||||
DECLARE_STRING_TABLE_LOOKUP(pressure_type, PressureType);
|
||||
|
||||
/* Default parameters for pressure watch logic in sd-event and PID 1 */
|
||||
#define PRESSURE_DEFAULT_TYPE "some"
|
||||
|
||||
Reference in New Issue
Block a user