mirror of
https://codeberg.org/dnkl/yambar.git
synced 2025-04-24 21:05:40 +02:00
modules: add mem module
This commit is contained in:
parent
d8d44b0f33
commit
337ce7681f
6 changed files with 248 additions and 0 deletions
|
@ -16,6 +16,7 @@
|
||||||
* border: new decoration.
|
* border: new decoration.
|
||||||
* i3/sway: new boolean tag: `empty`
|
* i3/sway: new boolean tag: `empty`
|
||||||
(https://codeberg.org/dnkl/yambar/issues/139).
|
(https://codeberg.org/dnkl/yambar/issues/139).
|
||||||
|
* mem: a module handling system memory monitoring
|
||||||
|
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
|
@ -13,6 +13,7 @@ foreach man_src : ['yambar.1.scd', 'yambar.5.scd', 'yambar-decorations.5.scd',
|
||||||
'yambar-modules-script.5.scd', 'yambar-modules-sway-xkb.5.scd',
|
'yambar-modules-script.5.scd', 'yambar-modules-sway-xkb.5.scd',
|
||||||
'yambar-modules-sway.5.scd', 'yambar-modules-xkb.5.scd',
|
'yambar-modules-sway.5.scd', 'yambar-modules-xkb.5.scd',
|
||||||
'yambar-modules-xwindow.5.scd', 'yambar-modules.5.scd',
|
'yambar-modules-xwindow.5.scd', 'yambar-modules.5.scd',
|
||||||
|
'yambar-modules-mem.5.scd',
|
||||||
'yambar-particles.5.scd', 'yambar-tags.5.scd']
|
'yambar-particles.5.scd', 'yambar-tags.5.scd']
|
||||||
parts = man_src.split('.')
|
parts = man_src.split('.')
|
||||||
name = parts[-3]
|
name = parts[-3]
|
||||||
|
|
51
doc/yambar-modules-mem.5.scd
Normal file
51
doc/yambar-modules-mem.5.scd
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
yambar-modules-mem(5)
|
||||||
|
|
||||||
|
# NAME
|
||||||
|
mem - This module provides the memory usage
|
||||||
|
|
||||||
|
# TAGS
|
||||||
|
|
||||||
|
[[ *Name*
|
||||||
|
:[ *Type*
|
||||||
|
:[ *Description*
|
||||||
|
| free
|
||||||
|
: int
|
||||||
|
: Free memory in bytes
|
||||||
|
| used
|
||||||
|
: int
|
||||||
|
: Used memory in bytes
|
||||||
|
| total
|
||||||
|
: int
|
||||||
|
: Total memory in bytes
|
||||||
|
| percent_free
|
||||||
|
: range
|
||||||
|
: Free memory in percent
|
||||||
|
| percent_used
|
||||||
|
: range
|
||||||
|
: Used memory in percent
|
||||||
|
|
||||||
|
# CONFIGURATION
|
||||||
|
|
||||||
|
[[ *Name*
|
||||||
|
:[ *Type*
|
||||||
|
:[ *Req*
|
||||||
|
:[ *Description*
|
||||||
|
| interval
|
||||||
|
: string
|
||||||
|
: no
|
||||||
|
: Refresh interval of the memory usage stats in ms (default=500). Cannot be less then 500 ms
|
||||||
|
|
||||||
|
# EXAMPLES
|
||||||
|
|
||||||
|
```
|
||||||
|
bar:
|
||||||
|
left:
|
||||||
|
- mem:
|
||||||
|
interval: 2500
|
||||||
|
content:
|
||||||
|
string: {text: "{used:mb}MB"}
|
||||||
|
```
|
||||||
|
|
||||||
|
# SEE ALSO
|
||||||
|
|
||||||
|
*yambar-modules*(5), *yambar-particles*(5), *yambar-tags*(5), *yambar-decorations*(5)
|
192
modules/mem.c
Normal file
192
modules/mem.c
Normal file
|
@ -0,0 +1,192 @@
|
||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <poll.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#define LOG_MODULE "mem"
|
||||||
|
#define LOG_ENABLE_DBG 0
|
||||||
|
#define SMALLEST_INTERVAL 500
|
||||||
|
#include "../bar/bar.h"
|
||||||
|
#include "../config-verify.h"
|
||||||
|
#include "../config.h"
|
||||||
|
#include "../log.h"
|
||||||
|
#include "../plugin.h"
|
||||||
|
|
||||||
|
struct private
|
||||||
|
{
|
||||||
|
struct particle *label;
|
||||||
|
uint16_t interval;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
destroy(struct module *mod)
|
||||||
|
{
|
||||||
|
struct private *m = mod->private;
|
||||||
|
m->label->destroy(m->label);
|
||||||
|
free(m);
|
||||||
|
module_default_destroy(mod);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *
|
||||||
|
description(struct module *mod)
|
||||||
|
{
|
||||||
|
return "mem";
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
get_mem_stats(uint64_t *mem_free, uint64_t *mem_total)
|
||||||
|
{
|
||||||
|
bool mem_total_found = false;
|
||||||
|
bool mem_free_found = false;
|
||||||
|
|
||||||
|
FILE *fp = NULL;
|
||||||
|
char *line = NULL;
|
||||||
|
size_t len = 0;
|
||||||
|
ssize_t read = 0;
|
||||||
|
|
||||||
|
fp = fopen("/proc/meminfo", "r");
|
||||||
|
if (NULL == fp) {
|
||||||
|
LOG_ERRNO("unable to open /proc/meminfo");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((read = getline(&line, &len, fp)) != -1) {
|
||||||
|
if (strncmp(line, "MemTotal:", sizeof("MemTotal:") - 1) == 0) {
|
||||||
|
read = sscanf(line + sizeof("MemTotal:") - 1, "%" SCNu64, mem_total);
|
||||||
|
mem_total_found = (read == 1);
|
||||||
|
}
|
||||||
|
if (strncmp(line, "MemAvailable:", sizeof("MemAvailable:") - 1) == 0) {
|
||||||
|
read = sscanf(line + sizeof("MemAvailable:"), "%" SCNu64, mem_free);
|
||||||
|
mem_free_found = (read == 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(line);
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
return mem_free_found && mem_total_found;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct exposable *
|
||||||
|
content(struct module *mod)
|
||||||
|
{
|
||||||
|
const struct private *p = mod->private;
|
||||||
|
uint64_t mem_free = 0;
|
||||||
|
uint64_t mem_used = 0;
|
||||||
|
uint64_t mem_total = 0;
|
||||||
|
|
||||||
|
if (!get_mem_stats(&mem_free, &mem_total)) {
|
||||||
|
LOG_ERR("unable to retrieve the memory stats");
|
||||||
|
}
|
||||||
|
|
||||||
|
mem_used = mem_total - mem_free;
|
||||||
|
|
||||||
|
double percent_used = ((double)mem_used * 100) / (mem_total + 1);
|
||||||
|
double percent_free = ((double)mem_free * 100) / (mem_total + 1);
|
||||||
|
|
||||||
|
struct tag_set tags = {
|
||||||
|
.tags = (struct tag *[]){tag_new_int(mod, "free", mem_free * 1024), tag_new_int(mod, "used", mem_used * 1024),
|
||||||
|
tag_new_int(mod, "total", mem_total * 1024),
|
||||||
|
tag_new_int_range(mod, "percent_free", round(percent_free), 0, 100),
|
||||||
|
tag_new_int_range(mod, "percent_used", round(percent_used), 0, 100)},
|
||||||
|
.count = 5,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct exposable *exposable = p->label->instantiate(p->label, &tags);
|
||||||
|
tag_set_destroy(&tags);
|
||||||
|
return exposable;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
run(struct module *mod)
|
||||||
|
{
|
||||||
|
const struct bar *bar = mod->bar;
|
||||||
|
bar->refresh(bar);
|
||||||
|
struct private *p = mod->private;
|
||||||
|
while (true) {
|
||||||
|
struct pollfd fds[] = {{.fd = mod->abort_fd, .events = POLLIN}};
|
||||||
|
|
||||||
|
int res = poll(fds, 1, p->interval);
|
||||||
|
if (res < 0) {
|
||||||
|
if (EINTR == errno) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG_ERRNO("unable to poll abort fd");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fds[0].revents & POLLIN)
|
||||||
|
break;
|
||||||
|
|
||||||
|
bar->refresh(bar);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct module *
|
||||||
|
mem_new(uint16_t interval, struct particle *label)
|
||||||
|
{
|
||||||
|
struct private *p = calloc(1, sizeof(*p));
|
||||||
|
p->label = label;
|
||||||
|
p->interval = interval;
|
||||||
|
|
||||||
|
struct module *mod = module_common_new();
|
||||||
|
mod->private = p;
|
||||||
|
mod->run = &run;
|
||||||
|
mod->destroy = &destroy;
|
||||||
|
mod->content = &content;
|
||||||
|
mod->description = &description;
|
||||||
|
return mod;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct module *
|
||||||
|
from_conf(const struct yml_node *node, struct conf_inherit inherited)
|
||||||
|
{
|
||||||
|
const struct yml_node *interval = yml_get_value(node, "interval");
|
||||||
|
const struct yml_node *c = yml_get_value(node, "content");
|
||||||
|
|
||||||
|
return mem_new(interval == NULL ? SMALLEST_INTERVAL : yml_value_as_int(interval), conf_to_particle(c, inherited));
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
conf_verify_interval(keychain_t *chain, const struct yml_node *node)
|
||||||
|
{
|
||||||
|
if (!conf_verify_unsigned(chain, node))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (yml_value_as_int(node) < SMALLEST_INTERVAL) {
|
||||||
|
LOG_ERR("%s: interval value cannot be less than %d ms", conf_err_prefix(chain, node), SMALLEST_INTERVAL);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
verify_conf(keychain_t *chain, const struct yml_node *node)
|
||||||
|
{
|
||||||
|
static const struct attr_info attrs[] = {
|
||||||
|
{"interval", false, &conf_verify_interval},
|
||||||
|
MODULE_COMMON_ATTRS,
|
||||||
|
};
|
||||||
|
|
||||||
|
return conf_verify_dict(chain, node, attrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
const struct module_iface module_mem_iface = {
|
||||||
|
.verify_conf = &verify_conf,
|
||||||
|
.from_conf = &from_conf,
|
||||||
|
};
|
||||||
|
|
||||||
|
#if defined(CORE_PLUGINS_AS_SHARED_LIBRARIES)
|
||||||
|
extern const struct module_iface iface __attribute__((weak, alias("module_mem_iface")));
|
||||||
|
#endif
|
|
@ -17,6 +17,7 @@ mod_data = {
|
||||||
'backlight': [[], [m, udev]],
|
'backlight': [[], [m, udev]],
|
||||||
'battery': [[], [udev]],
|
'battery': [[], [udev]],
|
||||||
'clock': [[], []],
|
'clock': [[], []],
|
||||||
|
'mem': [[], []],
|
||||||
'i3': [['i3-common.c', 'i3-common.h'], [dynlist, json]],
|
'i3': [['i3-common.c', 'i3-common.h'], [dynlist, json]],
|
||||||
'label': [[], []],
|
'label': [[], []],
|
||||||
'network': [[], []],
|
'network': [[], []],
|
||||||
|
|
2
plugin.c
2
plugin.c
|
@ -49,6 +49,7 @@ EXTERN_MODULE(sway_xkb);
|
||||||
EXTERN_MODULE(script);
|
EXTERN_MODULE(script);
|
||||||
EXTERN_MODULE(xkb);
|
EXTERN_MODULE(xkb);
|
||||||
EXTERN_MODULE(xwindow);
|
EXTERN_MODULE(xwindow);
|
||||||
|
EXTERN_MODULE(mem);
|
||||||
|
|
||||||
EXTERN_PARTICLE(empty);
|
EXTERN_PARTICLE(empty);
|
||||||
EXTERN_PARTICLE(list);
|
EXTERN_PARTICLE(list);
|
||||||
|
@ -136,6 +137,7 @@ init(void)
|
||||||
#if defined(HAVE_PLUGIN_xwindow)
|
#if defined(HAVE_PLUGIN_xwindow)
|
||||||
REGISTER_CORE_MODULE(xwindow, xwindow);
|
REGISTER_CORE_MODULE(xwindow, xwindow);
|
||||||
#endif
|
#endif
|
||||||
|
REGISTER_CORE_MODULE(mem, mem);
|
||||||
|
|
||||||
REGISTER_CORE_PARTICLE(empty, empty);
|
REGISTER_CORE_PARTICLE(empty, empty);
|
||||||
REGISTER_CORE_PARTICLE(list, list);
|
REGISTER_CORE_PARTICLE(list, list);
|
||||||
|
|
Loading…
Add table
Reference in a new issue