Skip to content

Commit

Permalink
Add GetSystemResources D-Bus API
Browse files Browse the repository at this point in the history
The GetSystemResources is a D-Bus API to get the system resources of the
specific node. The system resources are the number of cpu, cpu time,
total memory size and used memory size. This API will help know how much
node consumes the system resources.

Signed-off-by: Joonyoung Shim <[email protected]>
  • Loading branch information
dofmind committed Oct 30, 2023
1 parent 93774b8 commit a07d1ca
Show file tree
Hide file tree
Showing 12 changed files with 282 additions and 0 deletions.
6 changes: 6 additions & 0 deletions data/org.eclipse.bluechi.Node.xml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,12 @@
<method name="SetLogLevel">
<arg name="level" type="s" direction="in" />
</method>
<method name="GetResources">
<arg name="cpu_number" type="u" direction="out" />
<arg name="cpu_time" type="t" direction="out" />
<arg name="memory_total" type="t" direction="out" />
<arg name="memory_used" type="t" direction="out" />
</method>

<property name="Name" type="s" access="read" />
<property name="Status" type="s" access="read" />
Expand Down
6 changes: 6 additions & 0 deletions data/org.eclipse.bluechi.internal.Agent.xml
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,12 @@
<method name="SetLogLevel">
<arg name="level" type="s" direction="in" />
</method>
<method name="GetSystemResources">
<arg name="cpu_number" type="u" direction="out" />
<arg name="cpu_time" type="t" direction="out" />
<arg name="memory_total" type="t" direction="out" />
<arg name="memory_used" type="t" direction="out" />
</method>

<signal name="JobDone">
<arg name="id" type="u" />
Expand Down
4 changes: 4 additions & 0 deletions doc/docs/api/description.md
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,10 @@ Object path: `/org/eclipse/bluechi/node/$name`

Set the new log level for bluechi-agent by invoking the internal bluechi-agent API.

* `GetSystemResources(out u cpu_number, out t cpu_time, out t memory_total, out t memory_used)`

Returns information about system resources (cpu and memory) on this node.

#### Properties

* `Name` - `s`
Expand Down
4 changes: 4 additions & 0 deletions doc/man/bluechictl.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,10 @@ Creates a monitor on the given agent to observe changes in the specified units.

Creates a monitor to observe connection state changes for all nodes.

### **bluechictl** *system-resources* *agent*

Fetches information about system resources on the specific bluechi-agents.


**Example:**

Expand Down
45 changes: 45 additions & 0 deletions src/agent/agent.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "libbluechi/common/network.h"
#include "libbluechi/common/opt.h"
#include "libbluechi/common/parse-util.h"
#include "libbluechi/common/procfs-util.h"
#include "libbluechi/common/time-util.h"
#include "libbluechi/log/log.h"
#include "libbluechi/service/shutdown.h"
Expand Down Expand Up @@ -1460,6 +1461,49 @@ static int agent_method_set_log_level(
return sd_bus_reply_method_return(m, "");
}

/*************************************************************************
************** org.eclipse.bluechi.Agent.GetSystemResources *
*************************************************************************/

static int agent_method_get_system_resources(
UNUSED sd_bus_message *m, UNUSED void *userdata, UNUSED sd_bus_error *ret_error) {
_cleanup_sd_bus_message_ sd_bus_message *reply = NULL;
uint32_t cpu_number = 0;
uint64_t cpu_time = 0;
uint64_t memory_total = 0;
uint64_t memory_used = 0;
long ret = 0;

int r = sd_bus_message_new_method_return(m, &reply);
if (r < 0) {
return sd_bus_reply_method_errorf(reply, SD_BUS_ERROR_FAILED, "Internal error");
}

ret = sysconf(_SC_NPROCESSORS_ONLN);
if (ret < 0) {
return sd_bus_reply_method_errorf(reply, SD_BUS_ERROR_FAILED, "Internal error");
}
assert(ret > 0);
cpu_number = ret;

r = procfs_cpu_get_usage(&cpu_time);
if (r < 0) {
return sd_bus_reply_method_errorf(reply, SD_BUS_ERROR_FAILED, "Internal error");
}

r = procfs_memory_get(&memory_total, &memory_used);
if (r < 0) {
return sd_bus_reply_method_errorf(reply, SD_BUS_ERROR_FAILED, "Internal error");
}

r = sd_bus_message_append(reply, "uttt", cpu_number, cpu_time, memory_total, memory_used);
if (r < 0) {
return sd_bus_reply_method_errorf(reply, SD_BUS_ERROR_FAILED, "Internal error");
}

return sd_bus_message_send(reply);
}


static const sd_bus_vtable internal_agent_vtable[] = {
SD_BUS_VTABLE_START(0),
Expand All @@ -1478,6 +1522,7 @@ static const sd_bus_vtable internal_agent_vtable[] = {
SD_BUS_METHOD("EnableMetrics", "", "", agent_method_enable_metrics, 0),
SD_BUS_METHOD("DisableMetrics", "", "", agent_method_disable_metrics, 0),
SD_BUS_METHOD("SetLogLevel", "s", "", agent_method_set_log_level, 0),
SD_BUS_METHOD("GetSystemResources", "", "uttt", agent_method_get_system_resources, 0),
SD_BUS_SIGNAL_WITH_NAMES("JobDone", "us", SD_BUS_PARAM(id) SD_BUS_PARAM(result), 0),
SD_BUS_SIGNAL_WITH_NAMES("JobStateChanged", "us", SD_BUS_PARAM(id) SD_BUS_PARAM(state), 0),
SD_BUS_SIGNAL_WITH_NAMES(
Expand Down
12 changes: 12 additions & 0 deletions src/bindings/python/bluechi/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,18 @@ def set_log_level(self, level: str) -> None:
level,
)

def get_system_resources(self) -> Tuple[UInt32, UInt64, UInt64, UInt64]:
"""
GetSystemResources:
@cpu_number: The cpu number of the node.
@cpu_time: The cpu time (nsec) of the node.
@memory_total: The total memory size (kB) of the node.
@memory_used: The used memory size (kB) of the node.
Get the system resources of the node.
"""
return self.get_proxy().GetSystemResources()

@property
def name(self) -> str:
return self.get_proxy().Name
Expand Down
50 changes: 50 additions & 0 deletions src/client/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -614,6 +614,49 @@ static int method_thaw_unit_on(Client *client, char *node_name, char *unit) {
return 0;
}

static int method_get_system_resources_on(Client *client, char *node_name) {
int r = 0;
_cleanup_sd_bus_error_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_sd_bus_message_ sd_bus_message *result = NULL;
uint32_t cpu_number = 0;
uint64_t cpu_time = 0;
uint64_t memory_total = 0;
uint64_t memory_used = 0;

r = assemble_object_path_string(NODE_OBJECT_PATH_PREFIX, node_name, &client->object_path);
if (r < 0) {
return r;
}

r = sd_bus_call_method(
client->api_bus,
BC_INTERFACE_BASE_NAME,
client->object_path,
NODE_INTERFACE,
"GetSystemResources",
&error,
&result,
"");
if (r < 0) {
fprintf(stderr, "Failed to issue method call: %s\n", error.message);
return r;
}

r = sd_bus_message_read(result, "uttt", &cpu_number, &cpu_time, &memory_total, &memory_used);
if (r < 0) {
fprintf(stderr, "Failed to read the system resources of the node: %s\n", strerror(-r));
return r;
}

printf("CPU(s): %u, CPU time: %lu nsec, Memory: %lu kB / %lu kB\n",
cpu_number,
cpu_time,
memory_used,
memory_total);

return 0;
}


int client_call_manager(Client *client) {
int r = 0;
Expand Down Expand Up @@ -750,6 +793,11 @@ int client_call_manager(Client *client) {
} else {
return -EINVAL;
}
} else if (streq(client->op, "system-resources")) {
if (client->opargc != 1) {
return -EINVAL;
}
return method_get_system_resources_on(client, client->opargv[0]);
} else if (streq(client->op, "version")) {
printf("%s\n", CONFIG_H_BC_VERSION);
} else {
Expand Down Expand Up @@ -793,5 +841,7 @@ int print_client_usage(char *argv) {
printf(" usage: monitor node-connection\n");
printf(" - daemon-reload: reload systemd daemon on a specific node\n");
printf(" usage: disable nodename\n");
printf(" - system-resources: returns the system resources on a specific nodes\n");
printf(" usage: system-resources nodename\n");
return 0;
}
7 changes: 7 additions & 0 deletions src/libbluechi/common/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ static inline int steal_fd(int *fdp) {
return fd;
}

static inline void fclosep(FILE **f) {
if (*f) {
fclose(*f);
}
}

static inline void closep(const int *fd) {
if (*fd >= 0) {
close(*fd);
Expand Down Expand Up @@ -60,6 +66,7 @@ static inline void *malloc0_array(size_t base_size, size_t element_size, size_t
#define _cleanup_(x) __attribute__((__cleanup__(x)))
#define _cleanup_free_ _cleanup_(freep)
#define _cleanup_fd_ _cleanup_(closep)
#define _cleanup_fclose_ _cleanup_(fclosep)

// NOLINTBEGIN(bugprone-macro-parentheses)
#define DEFINE_CLEANUP_FUNC(_type, _freefunc) \
Expand Down
138 changes: 138 additions & 0 deletions src/libbluechi/common/procfs-util.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <errno.h>

#include "libbluechi/common/common.h"
#include "procfs-util.h"

#define MEMINFO_BUF_SIZE 60
#define STAT_BUF_SIZE 512

#define BASE_DECIMAL 10

#define IDLE_INDEX 3
#define IOWAIT_INDEX 4
#define STEAL_INDEX 7

#define NSEC_PER_SEC 1000000000ULL

#define DIV_ROUND_UP(n, d) (((n) + (d) -1) / (d))

static uint64_t calc_gcd64(uint64_t a, uint64_t b) {
while (b > 0) {
uint64_t t = a % b;

a = b;
b = t;
}

return a;
}

int procfs_cpu_get_usage(uint64_t *ret) {
long ticks_per_second = 0;
uint64_t sum = 0, gcd = 0, a = 0, b = 0;
_cleanup_fclose_ FILE *f = NULL;
char buf[STAT_BUF_SIZE];
const char *p = buf;
int i = 0;

assert(ret);

f = fopen("/proc/stat", "re");
if (!f) {
return -errno;
}

if (!fgets(buf, sizeof(buf), f) || buf[0] != 'c' /* not "cpu" */) {
return -EINVAL;
}

p += strcspn(p, " \t");

while (p && *p != '\0') {
char *endptr = NULL;
uint64_t val = UINT64_MAX;

val = strtoul(p, &endptr, BASE_DECIMAL);
if ((errno == ERANGE && val == UINT64_MAX) || (errno != EAGAIN && errno != 0 && val == 0)) {
return -errno;
}

if (i != IDLE_INDEX && i != IOWAIT_INDEX && i != STEAL_INDEX) {
sum += val;
}

p = ++endptr;
i++;
}

ticks_per_second = sysconf(_SC_CLK_TCK);
if (ticks_per_second < 0) {
return -errno;
}
assert(ticks_per_second > 0);

/* 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 = (uint64_t) NSEC_PER_SEC / gcd;
b = (uint64_t) ticks_per_second / gcd;

*ret = DIV_ROUND_UP(sum * a, b);
return 0;
}

int procfs_memory_get(uint64_t *ret_total, uint64_t *ret_used) {
uint64_t mem_total = UINT64_MAX, mem_available = UINT64_MAX;
_cleanup_fclose_ FILE *f = NULL;
char buf[MEMINFO_BUF_SIZE];

f = fopen("/proc/meminfo", "re");
if (!f) {
return -errno;
}

while (fgets(buf, sizeof(buf), f) != NULL) {
char *c = strchr(buf, ':');
if (!c) {
continue;
}
*c = '\0';

if (streq(buf, "MemTotal")) {
mem_total = strtoul(c + 1, NULL, BASE_DECIMAL);
if ((errno == ERANGE && mem_total == UINT64_MAX) ||
(errno != EAGAIN && errno != 0 && mem_total == 0)) {
return -errno;
}
continue;
}

if (streq(buf, "MemAvailable")) {
mem_available = strtoul(c + 1, NULL, BASE_DECIMAL);
if ((errno == ERANGE && mem_available == UINT64_MAX) ||
(errno != EAGAIN && errno != 0 && mem_available == 0)) {
return -errno;
}
continue;
}

if (mem_total != UINT64_MAX && mem_available != UINT64_MAX) {
break;
}
}

if (mem_available > mem_total) {
return -EINVAL;
}

if (ret_total) {
*ret_total = mem_total;
}

if (ret_used) {
*ret_used = mem_total - mem_available;
}

return 0;
}
7 changes: 7 additions & 0 deletions src/libbluechi/common/procfs-util.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once

#include <inttypes.h>

int procfs_cpu_get_usage(uint64_t *ret);
int procfs_memory_get(uint64_t *ret_total, uint64_t *ret_used);
2 changes: 2 additions & 0 deletions src/libbluechi/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ libbluechi_src = [
'common/opt.h',
'common/parse-util.c',
'common/parse-util.h',
'common/procfs-util.c',
'common/procfs-util.h',
'common/network.h',
'common/network.c',
'common/time-util.c',
Expand Down
1 change: 1 addition & 0 deletions src/manager/node.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ static const sd_bus_vtable node_vtable[] = {
SD_BUS_METHOD("DisableUnitFiles", "asb", "a(sss)", node_method_passthrough_to_agent, 0),
SD_BUS_METHOD("Reload", "", "", node_method_passthrough_to_agent, 0),
SD_BUS_METHOD("SetLogLevel", "s", "", node_method_set_log_level, 0),
SD_BUS_METHOD("GetSystemResources", "", "uttt", node_method_passthrough_to_agent, 0),
SD_BUS_PROPERTY("Name", "s", node_property_get_nodename, 0, SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Status", "s", node_property_get_status, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("LastSeenTimestamp", "t", node_property_get_last_seen, 0, SD_BUS_VTABLE_PROPERTY_EXPLICIT),
Expand Down

0 comments on commit a07d1ca

Please sign in to comment.