mirror of
https://github.com/systemd/systemd.git
synced 2025-03-21 02:50:18 +03:00
Merge pull request #12074 from poettering/io-acct
expose IO stats on the bus and in "systemctl status" and "systemd-run --wait"
This commit is contained in:
commit
c5b7ae0edb
@ -3233,21 +3233,140 @@ int unit_get_ip_accounting(
|
||||
return r;
|
||||
}
|
||||
|
||||
static int unit_get_io_accounting_raw(Unit *u, uint64_t ret[static _CGROUP_IO_ACCOUNTING_METRIC_MAX]) {
|
||||
static const char *const field_names[_CGROUP_IO_ACCOUNTING_METRIC_MAX] = {
|
||||
[CGROUP_IO_READ_BYTES] = "rbytes=",
|
||||
[CGROUP_IO_WRITE_BYTES] = "wbytes=",
|
||||
[CGROUP_IO_READ_OPERATIONS] = "rios=",
|
||||
[CGROUP_IO_WRITE_OPERATIONS] = "wios=",
|
||||
};
|
||||
uint64_t acc[_CGROUP_IO_ACCOUNTING_METRIC_MAX] = {};
|
||||
_cleanup_free_ char *path = NULL;
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
int r;
|
||||
|
||||
assert(u);
|
||||
|
||||
if (!u->cgroup_path)
|
||||
return -ENODATA;
|
||||
|
||||
if (unit_has_host_root_cgroup(u))
|
||||
return -ENODATA; /* TODO: return useful data for the top-level cgroup */
|
||||
|
||||
r = cg_all_unified();
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0) /* TODO: support cgroupv1 */
|
||||
return -ENODATA;
|
||||
|
||||
if (!FLAGS_SET(u->cgroup_realized_mask, CGROUP_MASK_IO))
|
||||
return -ENODATA;
|
||||
|
||||
r = cg_get_path("io", u->cgroup_path, "io.stat", &path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
f = fopen(path, "re");
|
||||
if (!f)
|
||||
return -errno;
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *line = NULL;
|
||||
const char *p;
|
||||
|
||||
r = read_line(f, LONG_LINE_MAX, &line);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
break;
|
||||
|
||||
p = line;
|
||||
p += strcspn(p, WHITESPACE); /* Skip over device major/minor */
|
||||
p += strspn(p, WHITESPACE); /* Skip over following whitespace */
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *word = NULL;
|
||||
|
||||
r = extract_first_word(&p, &word, NULL, EXTRACT_RETAIN_ESCAPE);
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
break;
|
||||
|
||||
for (CGroupIOAccountingMetric i = 0; i < _CGROUP_IO_ACCOUNTING_METRIC_MAX; i++) {
|
||||
const char *x;
|
||||
|
||||
x = startswith(word, field_names[i]);
|
||||
if (x) {
|
||||
uint64_t w;
|
||||
|
||||
r = safe_atou64(x, &w);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* Sum up the stats of all devices */
|
||||
acc[i] += w;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
memcpy(ret, acc, sizeof(acc));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unit_get_io_accounting(
|
||||
Unit *u,
|
||||
CGroupIOAccountingMetric metric,
|
||||
bool allow_cache,
|
||||
uint64_t *ret) {
|
||||
|
||||
uint64_t raw[_CGROUP_IO_ACCOUNTING_METRIC_MAX];
|
||||
int r;
|
||||
|
||||
/* Retrieve an IO account parameter. This will subtract the counter when the unit was started. */
|
||||
|
||||
if (!UNIT_CGROUP_BOOL(u, io_accounting))
|
||||
return -ENODATA;
|
||||
|
||||
if (allow_cache && u->io_accounting_last[metric] != UINT64_MAX)
|
||||
goto done;
|
||||
|
||||
r = unit_get_io_accounting_raw(u, raw);
|
||||
if (r == -ENODATA && u->io_accounting_last[metric] != UINT64_MAX)
|
||||
goto done;
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
for (CGroupIOAccountingMetric i = 0; i < _CGROUP_IO_ACCOUNTING_METRIC_MAX; i++) {
|
||||
/* Saturated subtraction */
|
||||
if (raw[i] > u->io_accounting_base[i])
|
||||
u->io_accounting_last[i] = raw[i] - u->io_accounting_base[i];
|
||||
else
|
||||
u->io_accounting_last[i] = 0;
|
||||
}
|
||||
|
||||
done:
|
||||
if (ret)
|
||||
*ret = u->io_accounting_last[metric];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unit_reset_cpu_accounting(Unit *u) {
|
||||
nsec_t ns;
|
||||
int r;
|
||||
|
||||
assert(u);
|
||||
|
||||
u->cpu_usage_last = NSEC_INFINITY;
|
||||
|
||||
r = unit_get_cpu_usage_raw(u, &ns);
|
||||
r = unit_get_cpu_usage_raw(u, &u->cpu_usage_base);
|
||||
if (r < 0) {
|
||||
u->cpu_usage_base = 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
u->cpu_usage_base = ns;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -3267,6 +3386,35 @@ int unit_reset_ip_accounting(Unit *u) {
|
||||
return r < 0 ? r : q;
|
||||
}
|
||||
|
||||
int unit_reset_io_accounting(Unit *u) {
|
||||
int r;
|
||||
|
||||
assert(u);
|
||||
|
||||
for (CGroupIOAccountingMetric i = 0; i < _CGROUP_IO_ACCOUNTING_METRIC_MAX; i++)
|
||||
u->io_accounting_last[i] = UINT64_MAX;
|
||||
|
||||
r = unit_get_io_accounting_raw(u, u->io_accounting_base);
|
||||
if (r < 0) {
|
||||
zero(u->io_accounting_base);
|
||||
return r;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int unit_reset_accounting(Unit *u) {
|
||||
int r, q, v;
|
||||
|
||||
assert(u);
|
||||
|
||||
r = unit_reset_cpu_accounting(u);
|
||||
q = unit_reset_io_accounting(u);
|
||||
v = unit_reset_ip_accounting(u);
|
||||
|
||||
return r < 0 ? r : q < 0 ? q : v;
|
||||
}
|
||||
|
||||
void unit_invalidate_cgroup(Unit *u, CGroupMask m) {
|
||||
assert(u);
|
||||
|
||||
|
@ -142,6 +142,16 @@ typedef enum CGroupIPAccountingMetric {
|
||||
_CGROUP_IP_ACCOUNTING_METRIC_INVALID = -1,
|
||||
} CGroupIPAccountingMetric;
|
||||
|
||||
/* Used when querying IO accounting data */
|
||||
typedef enum CGroupIOAccountingMetric {
|
||||
CGROUP_IO_READ_BYTES,
|
||||
CGROUP_IO_WRITE_BYTES,
|
||||
CGROUP_IO_READ_OPERATIONS,
|
||||
CGROUP_IO_WRITE_OPERATIONS,
|
||||
_CGROUP_IO_ACCOUNTING_METRIC_MAX,
|
||||
_CGROUP_IO_ACCOUNTING_METRIC_INVALID = -1,
|
||||
} CGroupIOAccountingMetric;
|
||||
|
||||
typedef struct Unit Unit;
|
||||
typedef struct Manager Manager;
|
||||
|
||||
@ -210,10 +220,13 @@ int unit_synthesize_cgroup_empty_event(Unit *u);
|
||||
int unit_get_memory_current(Unit *u, uint64_t *ret);
|
||||
int unit_get_tasks_current(Unit *u, uint64_t *ret);
|
||||
int unit_get_cpu_usage(Unit *u, nsec_t *ret);
|
||||
int unit_get_io_accounting(Unit *u, CGroupIOAccountingMetric metric, bool allow_cache, uint64_t *ret);
|
||||
int unit_get_ip_accounting(Unit *u, CGroupIPAccountingMetric metric, uint64_t *ret);
|
||||
|
||||
int unit_reset_cpu_accounting(Unit *u);
|
||||
int unit_reset_ip_accounting(Unit *u);
|
||||
int unit_reset_io_accounting(Unit *u);
|
||||
int unit_reset_accounting(Unit *u);
|
||||
|
||||
#define UNIT_CGROUP_BOOL(u, name) \
|
||||
({ \
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "selinux-access.h"
|
||||
#include "signal-util.h"
|
||||
#include "special.h"
|
||||
#include "string-table.h"
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
#include "user-util.h"
|
||||
@ -1029,30 +1030,57 @@ static int property_get_ip_counter(
|
||||
void *userdata,
|
||||
sd_bus_error *error) {
|
||||
|
||||
CGroupIPAccountingMetric metric;
|
||||
uint64_t value = (uint64_t) -1;
|
||||
static const char *const table[_CGROUP_IP_ACCOUNTING_METRIC_MAX] = {
|
||||
[CGROUP_IP_INGRESS_BYTES] = "IPIngressBytes",
|
||||
[CGROUP_IP_EGRESS_BYTES] = "IPEgressBytes",
|
||||
[CGROUP_IP_INGRESS_PACKETS] = "IPIngressPackets",
|
||||
[CGROUP_IP_EGRESS_PACKETS] = "IPEgressPackets",
|
||||
};
|
||||
|
||||
uint64_t value = UINT64_MAX;
|
||||
Unit *u = userdata;
|
||||
ssize_t metric;
|
||||
|
||||
assert(bus);
|
||||
assert(reply);
|
||||
assert(property);
|
||||
assert(u);
|
||||
|
||||
if (streq(property, "IPIngressBytes"))
|
||||
metric = CGROUP_IP_INGRESS_BYTES;
|
||||
else if (streq(property, "IPIngressPackets"))
|
||||
metric = CGROUP_IP_INGRESS_PACKETS;
|
||||
else if (streq(property, "IPEgressBytes"))
|
||||
metric = CGROUP_IP_EGRESS_BYTES;
|
||||
else {
|
||||
assert(streq(property, "IPEgressPackets"));
|
||||
metric = CGROUP_IP_EGRESS_PACKETS;
|
||||
}
|
||||
|
||||
assert_se((metric = string_table_lookup(table, ELEMENTSOF(table), property)) >= 0);
|
||||
(void) unit_get_ip_accounting(u, metric, &value);
|
||||
return sd_bus_message_append(reply, "t", value);
|
||||
}
|
||||
|
||||
static int property_get_io_counter(
|
||||
sd_bus *bus,
|
||||
const char *path,
|
||||
const char *interface,
|
||||
const char *property,
|
||||
sd_bus_message *reply,
|
||||
void *userdata,
|
||||
sd_bus_error *error) {
|
||||
|
||||
static const char *const table[_CGROUP_IO_ACCOUNTING_METRIC_MAX] = {
|
||||
[CGROUP_IO_READ_BYTES] = "IOReadBytes",
|
||||
[CGROUP_IO_WRITE_BYTES] = "IOWriteBytes",
|
||||
[CGROUP_IO_READ_OPERATIONS] = "IOReadOperations",
|
||||
[CGROUP_IO_WRITE_OPERATIONS] = "IOWriteOperations",
|
||||
};
|
||||
|
||||
uint64_t value = UINT64_MAX;
|
||||
Unit *u = userdata;
|
||||
ssize_t metric;
|
||||
|
||||
assert(bus);
|
||||
assert(reply);
|
||||
assert(property);
|
||||
assert(u);
|
||||
|
||||
assert_se((metric = string_table_lookup(table, ELEMENTSOF(table), property)) >= 0);
|
||||
(void) unit_get_io_accounting(u, metric, false, &value);
|
||||
return sd_bus_message_append(reply, "t", value);
|
||||
}
|
||||
|
||||
int bus_unit_method_attach_processes(sd_bus_message *message, void *userdata, sd_bus_error *error) {
|
||||
|
||||
_cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
|
||||
@ -1176,6 +1204,10 @@ const sd_bus_vtable bus_unit_cgroup_vtable[] = {
|
||||
SD_BUS_PROPERTY("IPIngressPackets", "t", property_get_ip_counter, 0, 0),
|
||||
SD_BUS_PROPERTY("IPEgressBytes", "t", property_get_ip_counter, 0, 0),
|
||||
SD_BUS_PROPERTY("IPEgressPackets", "t", property_get_ip_counter, 0, 0),
|
||||
SD_BUS_PROPERTY("IOReadBytes", "t", property_get_io_counter, 0, 0),
|
||||
SD_BUS_PROPERTY("IOReadOperations", "t", property_get_io_counter, 0, 0),
|
||||
SD_BUS_PROPERTY("IOWriteBytes", "t", property_get_io_counter, 0, 0),
|
||||
SD_BUS_PROPERTY("IOWriteOperations", "t", property_get_io_counter, 0, 0),
|
||||
SD_BUS_METHOD("GetProcesses", NULL, "a(sus)", bus_unit_method_get_processes, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_METHOD("AttachProcesses", "sau", NULL, bus_unit_method_attach_processes, SD_BUS_VTABLE_UNPRIVILEGED),
|
||||
SD_BUS_VTABLE_END
|
||||
|
@ -330,8 +330,7 @@ static int scope_start(Unit *u) {
|
||||
return r;
|
||||
|
||||
(void) unit_realize_cgroup(u);
|
||||
(void) unit_reset_cpu_accounting(u);
|
||||
(void) unit_reset_ip_accounting(u);
|
||||
(void) unit_reset_accounting(u);
|
||||
|
||||
unit_export_state_files(u);
|
||||
|
||||
|
@ -230,8 +230,7 @@ static int slice_start(Unit *u) {
|
||||
return r;
|
||||
|
||||
(void) unit_realize_cgroup(u);
|
||||
(void) unit_reset_cpu_accounting(u);
|
||||
(void) unit_reset_ip_accounting(u);
|
||||
(void) unit_reset_accounting(u);
|
||||
|
||||
slice_set_state(t, SLICE_ACTIVE);
|
||||
return 1;
|
||||
|
134
src/core/unit.c
134
src/core/unit.c
@ -113,6 +113,9 @@ Unit *unit_new(Manager *m, size_t size) {
|
||||
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);
|
||||
|
||||
for (CGroupIOAccountingMetric i = 0; i < _CGROUP_IO_ACCOUNTING_METRIC_MAX; i++)
|
||||
u->io_accounting_last[i] = UINT64_MAX;
|
||||
|
||||
return u;
|
||||
}
|
||||
|
||||
@ -159,7 +162,6 @@ static void unit_init(Unit *u) {
|
||||
|
||||
cc->cpu_accounting = u->manager->default_cpu_accounting;
|
||||
cc->io_accounting = u->manager->default_io_accounting;
|
||||
cc->ip_accounting = u->manager->default_ip_accounting;
|
||||
cc->blockio_accounting = u->manager->default_blockio_accounting;
|
||||
cc->memory_accounting = u->manager->default_memory_accounting;
|
||||
cc->tasks_accounting = u->manager->default_tasks_accounting;
|
||||
@ -2122,11 +2124,11 @@ void unit_trigger_notify(Unit *u) {
|
||||
}
|
||||
|
||||
static int unit_log_resources(Unit *u) {
|
||||
struct iovec iovec[1 + _CGROUP_IP_ACCOUNTING_METRIC_MAX + 4];
|
||||
bool any_traffic = false, have_ip_accounting = false;
|
||||
_cleanup_free_ char *igress = NULL, *egress = NULL;
|
||||
struct iovec iovec[1 + _CGROUP_IP_ACCOUNTING_METRIC_MAX + _CGROUP_IO_ACCOUNTING_METRIC_MAX + 4];
|
||||
bool any_traffic = false, have_ip_accounting = false, any_io = false, have_io_accounting = false;
|
||||
_cleanup_free_ char *igress = NULL, *egress = NULL, *rr = NULL, *wr = NULL;
|
||||
size_t n_message_parts = 0, n_iovec = 0;
|
||||
char* message_parts[3 + 1], *t;
|
||||
char* message_parts[1 + 2 + 2 + 1], *t;
|
||||
nsec_t nsec = NSEC_INFINITY;
|
||||
CGroupIPAccountingMetric m;
|
||||
size_t i;
|
||||
@ -2137,6 +2139,12 @@ static int unit_log_resources(Unit *u) {
|
||||
[CGROUP_IP_EGRESS_BYTES] = "IP_METRIC_EGRESS_BYTES",
|
||||
[CGROUP_IP_EGRESS_PACKETS] = "IP_METRIC_EGRESS_PACKETS",
|
||||
};
|
||||
const char* const io_fields[_CGROUP_IO_ACCOUNTING_METRIC_MAX] = {
|
||||
[CGROUP_IO_READ_BYTES] = "IO_METRIC_READ_BYTES",
|
||||
[CGROUP_IO_WRITE_BYTES] = "IO_METRIC_WRITE_BYTES",
|
||||
[CGROUP_IO_READ_OPERATIONS] = "IO_METRIC_READ_OPERATIONS",
|
||||
[CGROUP_IO_WRITE_OPERATIONS] = "IO_METRIC_WRITE_OPERATIONS",
|
||||
};
|
||||
|
||||
assert(u);
|
||||
|
||||
@ -2166,6 +2174,66 @@ static int unit_log_resources(Unit *u) {
|
||||
message_parts[n_message_parts++] = t;
|
||||
}
|
||||
|
||||
for (CGroupIOAccountingMetric k = 0; k < _CGROUP_IO_ACCOUNTING_METRIC_MAX; k++) {
|
||||
char buf[FORMAT_BYTES_MAX] = "";
|
||||
uint64_t value = UINT64_MAX;
|
||||
|
||||
assert(io_fields[k]);
|
||||
|
||||
(void) unit_get_io_accounting(u, k, k > 0, &value);
|
||||
if (value == UINT64_MAX)
|
||||
continue;
|
||||
|
||||
have_io_accounting = true;
|
||||
if (value > 0)
|
||||
any_io = true;
|
||||
|
||||
/* Format IO accounting data for inclusion in the structured log message */
|
||||
if (asprintf(&t, "%s=%" PRIu64, io_fields[k], value) < 0) {
|
||||
r = log_oom();
|
||||
goto finish;
|
||||
}
|
||||
iovec[n_iovec++] = IOVEC_MAKE_STRING(t);
|
||||
|
||||
/* Format the IO accounting data for inclusion in the human language message string, but only
|
||||
* for the bytes counters (and not for the operations counters) */
|
||||
if (k == CGROUP_IO_READ_BYTES) {
|
||||
assert(!rr);
|
||||
rr = strjoin("read ", format_bytes(buf, sizeof(buf), value), " from disk");
|
||||
if (!rr) {
|
||||
r = log_oom();
|
||||
goto finish;
|
||||
}
|
||||
} else if (k == CGROUP_IO_WRITE_BYTES) {
|
||||
assert(!wr);
|
||||
wr = strjoin("written ", format_bytes(buf, sizeof(buf), value), " to disk");
|
||||
if (!wr) {
|
||||
r = log_oom();
|
||||
goto finish;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (have_io_accounting) {
|
||||
if (any_io) {
|
||||
if (rr)
|
||||
message_parts[n_message_parts++] = TAKE_PTR(rr);
|
||||
if (wr)
|
||||
message_parts[n_message_parts++] = TAKE_PTR(wr);
|
||||
|
||||
} else {
|
||||
char *k;
|
||||
|
||||
k = strdup("no IO");
|
||||
if (!k) {
|
||||
r = log_oom();
|
||||
goto finish;
|
||||
}
|
||||
|
||||
message_parts[n_message_parts++] = k;
|
||||
}
|
||||
}
|
||||
|
||||
for (m = 0; m < _CGROUP_IP_ACCOUNTING_METRIC_MAX; m++) {
|
||||
char buf[FORMAT_BYTES_MAX] = "";
|
||||
uint64_t value = UINT64_MAX;
|
||||
@ -3203,6 +3271,20 @@ static const char *const ip_accounting_metric_field[_CGROUP_IP_ACCOUNTING_METRIC
|
||||
[CGROUP_IP_EGRESS_PACKETS] = "ip-accounting-egress-packets",
|
||||
};
|
||||
|
||||
static const char *const io_accounting_metric_field_base[_CGROUP_IO_ACCOUNTING_METRIC_MAX] = {
|
||||
[CGROUP_IO_READ_BYTES] = "io-accounting-read-bytes-base",
|
||||
[CGROUP_IO_WRITE_BYTES] = "io-accounting-write-bytes-base",
|
||||
[CGROUP_IO_READ_OPERATIONS] = "io-accounting-read-operations-base",
|
||||
[CGROUP_IO_WRITE_OPERATIONS] = "io-accounting-write-operations-base",
|
||||
};
|
||||
|
||||
static const char *const io_accounting_metric_field_last[_CGROUP_IO_ACCOUNTING_METRIC_MAX] = {
|
||||
[CGROUP_IO_READ_BYTES] = "io-accounting-read-bytes-last",
|
||||
[CGROUP_IO_WRITE_BYTES] = "io-accounting-write-bytes-last",
|
||||
[CGROUP_IO_READ_OPERATIONS] = "io-accounting-read-operations-last",
|
||||
[CGROUP_IO_WRITE_OPERATIONS] = "io-accounting-write-operations-last",
|
||||
};
|
||||
|
||||
int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) {
|
||||
CGroupIPAccountingMetric m;
|
||||
int r;
|
||||
@ -3249,6 +3331,13 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) {
|
||||
if (u->oom_kill_last > 0)
|
||||
(void) serialize_item_format(f, "oom-kill-last", "%" PRIu64, u->oom_kill_last);
|
||||
|
||||
for (CGroupIOAccountingMetric im = 0; im < _CGROUP_IO_ACCOUNTING_METRIC_MAX; im++) {
|
||||
(void) serialize_item_format(f, io_accounting_metric_field_base[im], "%" PRIu64, u->io_accounting_base[im]);
|
||||
|
||||
if (u->io_accounting_last[im] != UINT64_MAX)
|
||||
(void) serialize_item_format(f, io_accounting_metric_field_last[im], "%" PRIu64, u->io_accounting_last[im]);
|
||||
}
|
||||
|
||||
if (u->cgroup_path)
|
||||
(void) serialize_item(f, "cgroup", u->cgroup_path);
|
||||
|
||||
@ -3324,8 +3413,8 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
|
||||
|
||||
for (;;) {
|
||||
_cleanup_free_ char *line = NULL;
|
||||
CGroupIPAccountingMetric m;
|
||||
char *l, *v;
|
||||
ssize_t m;
|
||||
size_t k;
|
||||
|
||||
r = read_line(f, LONG_LINE_MAX, &line);
|
||||
@ -3577,10 +3666,8 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
|
||||
}
|
||||
|
||||
/* Check if this is an IP accounting metric serialization field */
|
||||
for (m = 0; m < _CGROUP_IP_ACCOUNTING_METRIC_MAX; m++)
|
||||
if (streq(l, ip_accounting_metric_field[m]))
|
||||
break;
|
||||
if (m < _CGROUP_IP_ACCOUNTING_METRIC_MAX) {
|
||||
m = string_table_lookup(ip_accounting_metric_field, ELEMENTSOF(ip_accounting_metric_field), l);
|
||||
if (m >= 0) {
|
||||
uint64_t c;
|
||||
|
||||
r = safe_atou64(v, &c);
|
||||
@ -3591,6 +3678,30 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
|
||||
continue;
|
||||
}
|
||||
|
||||
m = string_table_lookup(io_accounting_metric_field_base, ELEMENTSOF(io_accounting_metric_field_base), l);
|
||||
if (m >= 0) {
|
||||
uint64_t c;
|
||||
|
||||
r = safe_atou64(v, &c);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse IO accounting base value %s, ignoring.", v);
|
||||
else
|
||||
u->io_accounting_base[m] = c;
|
||||
continue;
|
||||
}
|
||||
|
||||
m = string_table_lookup(io_accounting_metric_field_last, ELEMENTSOF(io_accounting_metric_field_last), l);
|
||||
if (m >= 0) {
|
||||
uint64_t c;
|
||||
|
||||
r = safe_atou64(v, &c);
|
||||
if (r < 0)
|
||||
log_unit_debug(u, "Failed to parse IO accounting last value %s, ignoring.", v);
|
||||
else
|
||||
u->io_accounting_last[m] = c;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (unit_can_serialize(u)) {
|
||||
r = exec_runtime_deserialize_compat(u, l, v, fds);
|
||||
if (r < 0) {
|
||||
@ -5394,8 +5505,7 @@ int unit_prepare_exec(Unit *u) {
|
||||
(void) unit_realize_cgroup(u);
|
||||
|
||||
if (u->reset_accounting) {
|
||||
(void) unit_reset_cpu_accounting(u);
|
||||
(void) unit_reset_ip_accounting(u);
|
||||
(void) unit_reset_accounting(u);
|
||||
u->reset_accounting = false;
|
||||
}
|
||||
|
||||
|
@ -252,6 +252,10 @@ typedef struct Unit {
|
||||
/* The current counter of the oom_kill field in the memory.events cgroup attribute */
|
||||
uint64_t oom_kill_last;
|
||||
|
||||
/* Where the io.stat data was at the time the unit was started */
|
||||
uint64_t io_accounting_base[_CGROUP_IO_ACCOUNTING_METRIC_MAX];
|
||||
uint64_t io_accounting_last[_CGROUP_IO_ACCOUNTING_METRIC_MAX]; /* the most recently read value */
|
||||
|
||||
/* Counterparts in the cgroup filesystem */
|
||||
char *cgroup_path;
|
||||
CGroupMask cgroup_realized_mask; /* In which hierarchies does this unit's cgroup exist? (only relevant on cgroup v1) */
|
||||
|
@ -948,6 +948,8 @@ typedef struct RunContext {
|
||||
uint64_t cpu_usage_nsec;
|
||||
uint64_t ip_ingress_bytes;
|
||||
uint64_t ip_egress_bytes;
|
||||
uint64_t io_read_bytes;
|
||||
uint64_t io_write_bytes;
|
||||
uint32_t exit_code;
|
||||
uint32_t exit_status;
|
||||
} RunContext;
|
||||
@ -993,6 +995,8 @@ static int run_context_update(RunContext *c, const char *path) {
|
||||
{ "CPUUsageNSec", "t", NULL, offsetof(RunContext, cpu_usage_nsec) },
|
||||
{ "IPIngressBytes", "t", NULL, offsetof(RunContext, ip_ingress_bytes) },
|
||||
{ "IPEgressBytes", "t", NULL, offsetof(RunContext, ip_egress_bytes) },
|
||||
{ "IOReadBytes", "t", NULL, offsetof(RunContext, io_read_bytes) },
|
||||
{ "IOWriteBytes", "t", NULL, offsetof(RunContext, io_write_bytes) },
|
||||
{}
|
||||
};
|
||||
|
||||
@ -1181,6 +1185,8 @@ static int start_transient_service(
|
||||
.cpu_usage_nsec = NSEC_INFINITY,
|
||||
.ip_ingress_bytes = UINT64_MAX,
|
||||
.ip_egress_bytes = UINT64_MAX,
|
||||
.io_read_bytes = UINT64_MAX,
|
||||
.io_write_bytes = UINT64_MAX,
|
||||
.inactive_exit_usec = USEC_INFINITY,
|
||||
.inactive_enter_usec = USEC_INFINITY,
|
||||
};
|
||||
@ -1280,6 +1286,14 @@ static int start_transient_service(
|
||||
char bytes[FORMAT_BYTES_MAX];
|
||||
log_info("IP traffic sent: %s", format_bytes(bytes, sizeof(bytes), c.ip_egress_bytes));
|
||||
}
|
||||
if (c.io_read_bytes != UINT64_MAX) {
|
||||
char bytes[FORMAT_BYTES_MAX];
|
||||
log_info("IO bytes read: %s", format_bytes(bytes, sizeof(bytes), c.io_read_bytes));
|
||||
}
|
||||
if (c.io_write_bytes != UINT64_MAX) {
|
||||
char bytes[FORMAT_BYTES_MAX];
|
||||
log_info("IO bytes written: %s", format_bytes(bytes, sizeof(bytes), c.io_write_bytes));
|
||||
}
|
||||
}
|
||||
|
||||
/* Try to propagate the service's return value */
|
||||
|
@ -4125,9 +4125,10 @@ typedef struct UnitStatusInfo {
|
||||
uint64_t cpu_usage_nsec;
|
||||
uint64_t tasks_current;
|
||||
uint64_t tasks_max;
|
||||
|
||||
uint64_t ip_ingress_bytes;
|
||||
uint64_t ip_egress_bytes;
|
||||
uint64_t io_read_bytes;
|
||||
uint64_t io_write_bytes;
|
||||
|
||||
uint64_t default_memory_min;
|
||||
uint64_t default_memory_low;
|
||||
@ -4485,6 +4486,14 @@ static void print_status_info(
|
||||
format_bytes(buf_out, sizeof(buf_out), i->ip_egress_bytes));
|
||||
}
|
||||
|
||||
if (i->io_read_bytes != UINT64_MAX && i->io_write_bytes != UINT64_MAX) {
|
||||
char buf_in[FORMAT_BYTES_MAX], buf_out[FORMAT_BYTES_MAX];
|
||||
|
||||
printf(" IO: %s read, %s written\n",
|
||||
format_bytes(buf_in, sizeof(buf_in), i->io_read_bytes),
|
||||
format_bytes(buf_out, sizeof(buf_out), i->io_write_bytes));
|
||||
}
|
||||
|
||||
if (i->tasks_current != (uint64_t) -1) {
|
||||
printf(" Tasks: %" PRIu64, i->tasks_current);
|
||||
|
||||
@ -5495,6 +5504,8 @@ static int show_one(
|
||||
{ "TasksMax", "t", NULL, offsetof(UnitStatusInfo, tasks_max) },
|
||||
{ "IPIngressBytes", "t", NULL, offsetof(UnitStatusInfo, ip_ingress_bytes) },
|
||||
{ "IPEgressBytes", "t", NULL, offsetof(UnitStatusInfo, ip_egress_bytes) },
|
||||
{ "IOReadBytes", "t", NULL, offsetof(UnitStatusInfo, io_read_bytes) },
|
||||
{ "IOWriteBytes", "t", NULL, offsetof(UnitStatusInfo, io_write_bytes) },
|
||||
{ "ExecStartPre", "a(sasbttttuii)", map_exec, 0 },
|
||||
{ "ExecStart", "a(sasbttttuii)", map_exec, 0 },
|
||||
{ "ExecStartPost", "a(sasbttttuii)", map_exec, 0 },
|
||||
@ -5519,6 +5530,8 @@ static int show_one(
|
||||
.tasks_max = (uint64_t) -1,
|
||||
.ip_ingress_bytes = (uint64_t) -1,
|
||||
.ip_egress_bytes = (uint64_t) -1,
|
||||
.io_read_bytes = UINT64_MAX,
|
||||
.io_write_bytes = UINT64_MAX,
|
||||
};
|
||||
char **pp;
|
||||
int r;
|
||||
|
Loading…
x
Reference in New Issue
Block a user