core: cache last CPU usage counter, before destorying a cgroup

It is useful for clients to be able to read the last CPU usage counter value of
a unit even if the unit is already terminated. Hence, before destroying a
cgroup's cgroup cache the last CPU usage counter and return it if the cgroup is
gone.
This commit is contained in:
Lennart Poettering 2016-08-18 20:58:10 +02:00
parent 8b3b6f588c
commit fe700f46ec
3 changed files with 37 additions and 3 deletions

View file

@ -1524,6 +1524,8 @@ void unit_prune_cgroup(Unit *u) {
if (!u->cgroup_path)
return;
(void) unit_get_cpu_usage(u, NULL); /* Cache the last CPU usage value before we destroy the cgroup */
is_root_slice = unit_has_name(u, SPECIAL_ROOT_SLICE);
r = cg_trim_everywhere(u->manager->cgroup_supported, u->cgroup_path, !is_root_slice);
@ -2044,7 +2046,21 @@ int unit_get_cpu_usage(Unit *u, nsec_t *ret) {
nsec_t ns;
int r;
assert(u);
/* Retrieve the current CPU usage counter. This will subtract the CPU counter taken when the unit was
* started. If the cgroup has been removed already, returns the last cached value. To cache the value, simply
* call this function with a NULL return value. */
r = unit_get_cpu_usage_raw(u, &ns);
if (r == -ENODATA && u->cpu_usage_last != NSEC_INFINITY) {
/* If we can't get the CPU usage anymore (because the cgroup was already removed, for example), use our
* cached value. */
if (ret)
*ret = u->cpu_usage_last;
return 0;
}
if (r < 0)
return r;
@ -2053,7 +2069,10 @@ int unit_get_cpu_usage(Unit *u, nsec_t *ret) {
else
ns = 0;
*ret = ns;
u->cpu_usage_last = ns;
if (ret)
*ret = ns;
return 0;
}
@ -2063,6 +2082,8 @@ int unit_reset_cpu_usage(Unit *u) {
assert(u);
u->cpu_usage_last = NSEC_INFINITY;
r = unit_get_cpu_usage_raw(u, &ns);
if (r < 0) {
u->cpu_usage_base = 0;

View file

@ -102,6 +102,7 @@ Unit *unit_new(Manager *m, size_t size) {
u->job_timeout = USEC_INFINITY;
u->ref_uid = UID_INVALID;
u->ref_gid = GID_INVALID;
u->cpu_usage_last = NSEC_INFINITY;
RATELIMIT_INIT(u->start_limit, m->default_start_limit_interval, m->default_start_limit_burst);
RATELIMIT_INIT(u->auto_stop_ratelimit, 10 * USEC_PER_SEC, 16);
@ -2620,7 +2621,10 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) {
unit_serialize_item(u, f, "assert-result", yes_no(u->assert_result));
unit_serialize_item(u, f, "transient", yes_no(u->transient));
unit_serialize_item_format(u, f, "cpu-usage-base", "%" PRIu64, u->cpu_usage_base);
if (u->cpu_usage_last != NSEC_INFINITY)
unit_serialize_item_format(u, f, "cpu-usage-last", "%" PRIu64, u->cpu_usage_last);
if (u->cgroup_path)
unit_serialize_item(u, f, "cgroup", u->cgroup_path);
@ -2843,11 +2847,19 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
continue;
} else if (streq(l, "cpu-usage-base") || streq(l, "cpuacct-usage-base")) {
} else if (STR_IN_SET(l, "cpu-usage-base", "cpuacct-usage-base")) {
r = safe_atou64(v, &u->cpu_usage_base);
if (r < 0)
log_unit_debug(u, "Failed to parse CPU usage %s, ignoring.", v);
log_unit_debug(u, "Failed to parse CPU usage base %s, ignoring.", v);
continue;
} else if (streq(l, "cpu-usage-last")) {
r = safe_atou64(v, &u->cpu_usage_last);
if (r < 0)
log_unit_debug(u, "Failed to read CPU usage last %s, ignoring.", v);
continue;

View file

@ -194,6 +194,7 @@ struct Unit {
/* Where the cpu.stat or cpuacct.usage was at the time the unit was started */
nsec_t cpu_usage_base;
nsec_t cpu_usage_last; /* the most recently read value */
/* Counterparts in the cgroup filesystem */
char *cgroup_path;