Skip to content
Snippets Groups Projects
Commit b4a463d6 authored by floreal.risso's avatar floreal.risso
Browse files

Merge branch 'dev' into pr_memory

parents 6799510a b11a3602
No related branches found
No related tags found
3 merge requests!9fix sensor example (doc),!6Simple memory sensor,!5Add dev name to labels
Pipeline #5435 failed
This commit is part of merge request !5. Comments created here will be created in the context of that merge request.
......@@ -59,11 +59,15 @@ make
```
You may want to run `./configure.sh --help` to see configuration options.
To use `amd_rapl` you have to load the module `msr`
```bash
sudo modprobe msr
```
To execute mojitos without being root to monitor performance counters
```bash
sudo sh -c 'echo 0 >/proc/sys/kernel/perf_event_paranoid'
```
To execute mohitos without being root for accessing RAPL
To execute mojitos without being root for accessing RAPL
```bash
sudo chmod a+w /sys/class/powercap/intel-rapl/*/*
sudo chmod a+w /sys/class/powercap/intel-rapl/*/*/*
......
......@@ -4,12 +4,15 @@
# Copyright (C) 2023-2023 Georges Da Costa <georges.da-costa@irit.fr>
try() { "$@" || die "cannot $*"; }
die() { yell "$*"; exit 111; }
die() {
yell "$*"
exit 111
}
yell() { echo "$0: $*" >&2; }
echo() { printf '%s\n' "$*"; }
isnum() {
case "${1#[+-]}" in
*[!0-9]*|'') return 1 ;;
*[!0-9]* | '') return 1 ;;
*) return 0 ;;
esac
}
......@@ -43,16 +46,16 @@ usage() {
}
ls_sensors() {
try cd src
[ -d src ] || die 'fatal: the "src" directory does not exit.'
[ -z "$hdr_whitelist" ] && hdr_whitelist='.*'
dprint hdr_blacklist >&2
dprint hdr_whitelist >&2
ls -1 *.h |
grep -xEv "($hdr_blacklist)\.h" |
grep -xE "($hdr_whitelist)\.h" |
sed 's/\.h$//'
try find src -type f -name '*.h' |
sed 's,src/\(.*\)\.h,\1,' |
grep -xEv "($hdr_blacklist)" |
grep -xE "($hdr_whitelist)"
}
# gen_sensors_h(sensor, nb_sensors)
......@@ -86,10 +89,10 @@ gen_sensors_h() {
printf ' int opt_idx = offset;\n'
for sensor in $sensors; do
cat <<-!
for (int i = 0; i < ${sensor}.nb_opt; i++) {
opts[opt_idx++] = ${sensor}_opt[i];
}
sensors[(*nb_defined)++] = ${sensor};
for (int i = 0; i < ${sensor}.nb_opt; i++) {
opts[opt_idx++] = ${sensor}_opt[i];
}
sensors[(*nb_defined)++] = ${sensor};
!
done
printf ' assert((offset + *nb_defined) <= len);\n'
......@@ -103,6 +106,11 @@ gen_sensors_mk() {
printf '$(OBJ_DIR)/%s.o ' "$sensor"
done
printf '\n'
for sensor in $sensors; do
printf '$(OBJ_DIR)/%s.o: $(SRC_DIR)/%s.c $(SRC_DIR)/%s.h $(SRC_DIR)/util.h\n' \
"$sensor" "$sensor" "$sensor"
printf '\t$(CC) $(CFLAGS) -c $< -o $@\n'
done
}
detect_caps() {
......@@ -110,11 +118,21 @@ detect_caps() {
[ -d /sys/class/infiniband ] && hdr_whitelist="${hdr_whitelist}|infiniband"
[ -r /proc/stat ] && hdr_whitelist="${hdr_whitelist}|load"
if [ "$(uname -r | cut -d "." -f 1)" -gt "2" ]; then
hdr_whitelist="${hdr_whitelist}|memory"
fi
if [ -r /proc/net/route ]; then
dev=$(awk 'NR == 2 { print $1 }' /proc/net/route)
[ -e "/sys/class/net/$dev" ] && hdr_whitelist="${hdr_whitelist}|network"
fi
if [ -e /usr/local/cuda/lib64 ] && [ -e /usr/local/cuda/include ]; then
hdr_whitelist="${hdr_whitelist}|nvidia_gpu"
NVML_LDFLAGS="-L/usr/local/cuda/lib64 -lnvidia-ml"
NVML_IFLAGS="-I/usr/local/cuda/include"
fi
vendor=$(awk '/vendor_id/ {print $3; exit}' /proc/cpuinfo)
vendor_lc=$(echo "$vendor" | tr 'A-Z' 'a-z')
case $vendor_lc in
......@@ -136,7 +154,7 @@ detect_caps() {
}
case $1 in
--all|-a)
--all | -a)
all=1
;;
esac
......@@ -144,30 +162,33 @@ esac
[ "$all" ] || detect_caps
[ "$all" ] ||
while [ "$1" ]; do
case $1 in
--include|-i)
shift; [ "$1" ] || usage
hdr_whitelist="${hdr_whitelist}|${1}"
;;
--exclude|-e)
shift; [ "$1" ] || usage
hdr_blacklist="${hdr_blacklist}|${1}"
;;
--list-sensors|-l)
ls_sensors
exit 0
;;
--unique|-u)
shift; [ "$1" ] || usage
hdr_whitelist=$1
;;
--help|-h)
usage
;;
esac
shift
done
while [ "$1" ]; do
case $1 in
--include | -i)
shift
[ "$1" ] || usage
hdr_whitelist="${hdr_whitelist}|${1}"
;;
--exclude | -e)
shift
[ "$1" ] || usage
hdr_blacklist="${hdr_blacklist}|${1}"
;;
--list-sensors | -l)
ls_sensors
exit 0
;;
--unique | -u)
shift
[ "$1" ] || usage
hdr_whitelist=$1
;;
--help | -h)
usage
;;
esac
shift
done
sensors=$(ls_sensors)
nb_sensors=$(echo "$sensors" | sed '/^$/d' | wc -l)
......@@ -177,12 +198,14 @@ if [ "$nb_sensors" -eq 0 ]; then
exit 1
fi
try gen_sensors_h "$sensors" "$nb_sensors" > "$target_hdr"
try gen_sensors_mk "$sensors" > "$target_mk"
try gen_sensors_h "$sensors" "$nb_sensors" >"$target_hdr"
try gen_sensors_mk "$sensors" >"$target_mk"
try printf "NVML_LDFLAGS = %s\n" "$NVML_LDFLAGS" >>"$target_mk"
try printf "NVML_IFLAGS = %s\n" "$NVML_IFLAGS" >>"$target_mk"
printf -- 'Run `make` to build `bin/mojitos`.\n' >&2
printf -- 'The resulting binary will have the %d following sensors:\n' "$nb_sensors" >&2
echo "$sensors" >&2
make clean >/dev/null
/*
* Example of a basic counter: an accumulator
**/
unsigned int init_acc(char *, void **);
unsigned int get_acc(uint64_t *results, void *);
void clean_acc(void *);
void label_acc(char **labels, void *);
Sensor rapl = {
.init = init_acc,
.get = get_acc,
.clean = clean_acc,
.label = label_acc,
.nb_opt = 1,
};
Optparse rapl_opt[1] = {
{
.longname = "accumulator",
.shortname = 'a',
.argtype = OPTPARSE_NONE, /* OPTPARSE_NONE / OPTPARSE_OPTIONAL / OPTPARSE_REQUIRED */
.usage_arg = NULL,
.usage_msg = "dumb accumulator",
},
};
doc/network.md 0 → 100644
This sensor can autodetect interfaces in use by giving the special
interface name "X". But the total number of interfaces it can autodetect
is currently under a hard-limit. This hard-limit can be changed by
modifying this line in `src/network.c`:
```c
#define NB_MAX_DEV 8
```
# Nvidia Gpu
The `nvidia_gpu` sensor provides basic information about the gpu. Depending on
the driver version it is possible that not all sensors are supported, so an
error message will be written to `stderr` but the execution will continue.
For more information you can consult the [nvidia nvml api](https://docs.nvidia.com/deploy/index.html).
## [Clock](https://docs.nvidia.com/deploy/nvml-api/group__nvmlDeviceEnumvs.html#group__nvmlDeviceEnumvs_1g805c0647be9996589fc5e3f6ff680c64)
All speeds are in Mhz.
|Output |Description |
|--------|-------------------------------|
|graphics|Graphics clock |
|sm |Streaming Multiprocessor clock |
|memory |Memory clock |
|video |Video encoder/decoder clock |
## [Memory](https://docs.nvidia.com/deploy/nvml-api/structnvmlMemory__t.html#structnvmlMemory__t)
All values are in bytes.
|Output |Description |
|--------|-------------------------------------|
|free |Unallocated device memory |
|used |Sum of Reserved and Allocated memory |
|total |Total physical device memory |
## [Utilization](https://docs.nvidia.com/deploy/nvml-api/structnvmlUtilization__t.html#structnvmlUtilization__t)
Utilization information for a device. Each sample period may be between 1
second and 1/6 second, depending on the product being queried.
All values are a percent of time over the past sample period.
|Output |Description |
|--------|---------------------|
|gpu | Usage of the GPU |
|memory | Usage of the Memory |
## [Power](https://docs.nvidia.com/deploy/nvml-api/group__nvmlDeviceQueries.html#group__nvmlDeviceQueries_1g7ef7dff0ff14238d08a19ad7fb23fc87)
Retrieves power usage for this GPU in milliwatts and its associated circuitry (e.g. memory)
|Output |Description |
|--------|-------------------------|
|power | Power consumption in mW |
## [Temperature](https://docs.nvidia.com/deploy/nvml-api/group__nvmlDeviceEnumvs.html#group__nvmlDeviceEnumvs_1g2650b526841fa38b8f293c2d509a1de0)
Temperature of the GPU.
|Output |Description |
|------------|----------------------------|
|temperature | Temperature of the GPU die |
......@@ -7,8 +7,20 @@ BIN_DIR = bin
TESTS_DIR = tests
BIN = mojitos
PREFIX = /usr/local
CC = gcc
CPPFLAGS = -std=gnu99 -Wall -Wextra -Wpedantic -Wno-unused-function -I./lib $(NVML_IFLAGS)
CFLAGS = $(CPPFLAGS) -O3 -Werror
LDFLAGS = $(NVML_LDFLAGS)
ASTYLE = astyle --style=kr -xf -s4 -k3 -n -Z -Q
all: $(BIN) man
CAPTOR_OBJ =
NVML_LDFLAGS =
NVML_IFLAGS =
include ./sensors.mk
......@@ -16,18 +28,15 @@ OBJ = \
$(CAPTOR_OBJ) \
$(OBJ_DIR)/util.o
CC = gcc
CPPFLAGS = -std=gnu99 -Wall -Wextra -Wpedantic -Wno-unused-function -I./lib
CFLAGS = $(CPPFLAGS) -O3 -Werror
LDFLAGS =
ASTYLE = astyle --style=kr -xf -s4 -k3 -n -Z -Q
all: $(BIN) man
options:
@echo BIN: $(BIN)
@echo CC: $(CC)
@echo CFLAGS: $(CFLAGS)
@echo LDFLAGS: $(LDFLAGS)
@echo OBJ: $(OBJ)
$(BIN): $(BIN_DIR) $(OBJ) $(OBJ_DIR)/$(BIN).o
$(CC) $(LDFLAGS) -o $(BIN_DIR)/$(BIN) $(OBJ) $(OBJ_DIR)/$(BIN).o
$(CC) -o $(BIN_DIR)/$(BIN) $(OBJ) $(OBJ_DIR)/$(BIN).o $(LDFLAGS)
$(OBJ): $(OBJ_DIR)
$(OBJ_DIR)/counters.o: $(SRC_DIR)/counters_option.h
......@@ -35,7 +44,7 @@ $(OBJ_DIR)/counters.o: $(SRC_DIR)/counters_option.h
$(OBJ_DIR)/$(BIN).o: $(SRC_DIR)/$(BIN).c $(SRC_DIR)/counters_option.h
$(CC) $(CFLAGS) -c $< -o $@
$(OBJ_DIR)/%.o: $(SRC_DIR)/%.c $(SRC_DIR)/%.h
$(OBJ_DIR)/util.o: $(SRC_DIR)/util.c $(SRC_DIR)/util.h
$(CC) $(CFLAGS) -c $< -o $@
$(SRC_DIR)/counters_option.h: $(SRC_DIR)/counters_option.sh
......@@ -74,4 +83,16 @@ man: $(BIN)
'/^USAGE/ { $$0=usage } 1' \
doc/$(BIN).pre.1 > doc/$(BIN).1 2>/dev/null
.PHONY: all clean mojitos debug format tests readme man
install: $(BIN) man
mkdir -p $(PREFIX)/bin
cp $(BIN_DIR)/$(BIN) $(PREFIX)/bin/.
chmod 755 $(PREFIX)/bin/$(BIN)
mkdir -p $(PREFIX)/share/man/man1
cp $(DOC_DIR)/$(BIN).1 $(PREFIX)/share/man/man1/.
chmod 644 $(PREFIX)/share/man/man1/$(BIN).1
uninstall:
rm -f $(PREFIX)/bin/$(BIN)
rm -f $(PREFIX)/share/man/man1/$(BIN).1
.PHONY: all clean mojitos debug format tests readme man install uninstall
......@@ -25,6 +25,7 @@
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <inttypes.h>
#include "info_reader.h"
#include "util.h"
......@@ -120,7 +121,7 @@ uint64_t read_msr(int fd, uint64_t msr)
{
uint64_t data;
if (pread(fd, &data, sizeof data, msr) != sizeof data) {
fprintf(stderr, "read_msr(%ld):", msr);
fprintf(stderr, "read_msr(%"PRIu64"):", msr);
perror("pread");
exit(127);
}
......@@ -175,7 +176,7 @@ uint64_t raw_to_joule(uint64_t raw, uint64_t unit)
void debug_print_sensor(CpuSensor *sensor)
{
//CASSERT(sizeof(CpuSensor) == 56, amd_rapl_c);
printf("cpu_id : %d, package_id : %d, core_id : %d, name : %s, fd: %d, energy_units : %d, core_energy: %ld\n",
printf("cpu_id : %d, package_id : %d, core_id : %d, name : %s, fd: %d, energy_units : %d, core_energy: %"PRIu64"\n",
sensor->cpu_id,
sensor->package_id,
sensor->core_id,
......@@ -200,17 +201,36 @@ void debug_print_amd_rapl(AmdRapl *rapl)
unsigned int get_nb_cpu()
{
char filename[BUFFER_SIZE];
int cpy_errno;
unsigned int n_cpu = 0;
for (;; n_cpu++) {
snprintf(filename, BUFFER_SIZE, base_str, n_cpu);
int fd = open(filename, O_RDONLY);
cpy_errno = errno;
if (fd < 0) {
break;
}
close(fd);
}
if (n_cpu == 0) {
perror("open()");
fprintf(stderr, "on the file: '%s'\n", filename);
switch (cpy_errno) {
case ENOENT:
fprintf(stderr, "Amd rapl works with msr module, try to run 'sudo modprobe msr', then retry.\n");
exit(99);
case EACCES:
fprintf(stderr, "Amd rapl must be executed with the administrator privilege, try with 'sudo'.\n");
exit(98);
default:
fprintf(stderr, "Unexpected error\n");
exit(97);
}
}
// n_cpu > 0
return n_cpu;
}
......@@ -294,11 +314,6 @@ unsigned int init_amd_rapl(char *none, void **ptr)
UNUSED(none);
unsigned int max_cpus = get_nb_cpu();
if (max_cpus == 0) {
fprintf(stderr, base_str, 0);
perror(":open()");
exit(127);
}
CpuSensor *cpu_information = (CpuSensor *) calloc(max_cpus, sizeof(CpuSensor));
if (parse_cpuinfo(cpu_information, max_cpus)) {
......
src/memory.c 0 → 100644
/*******************************************************
Copyright (C) 2023-2023 Georges Da Costa <georges.da-costa@irit.fr>
This file is part of Mojitos.
Mojitos is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Mojitos is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with MojitO/S. If not, see <https://www.gnu.org/licenses/>.
*******************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <sys/sysinfo.h>
#include <string.h>
#include "util.h"
typedef enum {
TOTALRAM = 0,
FREERAM,
SHAREDRAM,
BUFFERRAM,
TOTALSWAP,
FREESWAP,
PROCS,
TOTALHIGH,
FREEHIGH,
MEM_UNIT,
MEMORY_COUNT,
} MemoryKind;
static const char *memory_labels[MEMORY_COUNT] = {
"totalram", "freeram", "sharedram", "bufferram",
"totalswap", "freeswap",
"procs",
"totalhigh", "freehigh", "mem_unit",
};
unsigned int init_memory(char *none1, void **none2)
{
UNUSED(none1);
UNUSED(none2);
struct sysinfo info;
if (sysinfo(&info) < 0) {
fprintf(stderr, "Failed to get the memory information");
return 0;
}
return MEMORY_COUNT;
}
unsigned int get_memory(uint64_t *results, void *none)
{
UNUSED(none);
struct sysinfo info;
if (sysinfo(&info) < 0) {
fprintf(stderr, "Failed to get the memory information");
exit(99);
}
// Can't use memcpy, the size isn't always the same
results[TOTALRAM] = info.totalram;
results[FREERAM] = info.freeram;
results[SHAREDRAM] = info.sharedram;
results[BUFFERRAM] = info.bufferram;
results[TOTALSWAP] = info.totalswap;
results[FREESWAP] = info.freeswap;
results[PROCS] = info.procs;
results[TOTALHIGH] = info.totalhigh;
results[FREEHIGH] = info.freehigh;
results[MEM_UNIT] = info.mem_unit;
return MEMORY_COUNT;
}
void label_memory(char **labels, void *none)
{
UNUSED(none);
memcpy(labels, memory_labels, sizeof(char *) * MEMORY_COUNT);
}
void clean_memory(void *none)
{
UNUSED(none);
return;
}
src/memory.h 0 → 100644
/*******************************************************
Copyright (C) 2023-2023 Georges Da Costa <georges.da-costa@irit.fr>
This file is part of Mojitos.
Mojitos is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Mojitos is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with MojitO/S. If not, see <https://www.gnu.org/licenses/>.
*******************************************************/
unsigned int init_memory(char *, void **);
unsigned int get_memory(uint64_t *results, void *);
void clean_memory(void *);
void label_memory(char **labels, void *);
Sensor memory = {
.init = init_memory,
.get = get_memory,
.clean = clean_memory,
.label = label_memory,
.nb_opt = 1,
};
Optparse memory_opt[1] = {
{
.longname = "memory",
.shortname = 'm',
.argtype = OPTPARSE_NONE,
.usage_arg = NULL,
.usage_msg = "Retrieves information about the memory via the syscall 'sysinfo(2)'.",
},
};
......@@ -17,28 +17,40 @@
along with MojitO/S. If not, see <https://www.gnu.org/licenses/>.
*******************************************************/
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>
#include "util.h"
#define NB_MAX_DEV 8
#define NB_SENSOR 4
static char *route = "/proc/net/route";
char *_labels_network[NB_SENSOR] = {
"%s:rxp",
"%s:rxb",
"%s:txp",
"%s:txb",
};
struct Network {
uint64_t values[NB_SENSOR];
uint64_t tmp_values[NB_SENSOR];
int sources[NB_SENSOR];
uint64_t values[NB_MAX_DEV][NB_SENSOR];
uint64_t tmp_values[NB_MAX_DEV][NB_SENSOR];
int sources[NB_MAX_DEV][NB_SENSOR];
char labels[NB_MAX_DEV][NB_SENSOR][128];
char devs[NB_MAX_DEV][128];
int ndev;
};
typedef struct Network Network;
unsigned int _get_network(uint64_t *results, int *sources)
static void _get_network(uint64_t *results, int *sources)
{
if (sources == NULL) {
return 0;
return;
}
char buffer[128];
......@@ -51,18 +63,51 @@ unsigned int _get_network(uint64_t *results, int *sources)
results[i] = strtoull(buffer, NULL, 10);
}
return NB_SENSOR;
}
/*
* read from fd len chars and store them into buf
* make *s points to the first occurence of c into buf
*/
static int strchr_refill(int fd, char *buf, int len, char **s, char c)
{
*s = strchr(*s, c);
if (*s == NULL) {
int nbytes = read(fd, buf, len - 1);
if (nbytes < 0) {
perror("read");
return -1;
}
buf[len - 1] = '\0';
/* whole file read */
if (nbytes == 0) {
return 0;
}
*s = strchr(buf, c);
}
return 1;
}
unsigned int init_network(char *dev, void **ptr)
{
if (dev == NULL) {
return 0;
exit(1);
}
char *filenames[] = {
"/sys/class/net/%s/statistics/rx_packets",
"/sys/class/net/%s/statistics/rx_bytes",
"/sys/class/net/%s/statistics/tx_packets",
"/sys/class/net/%s/statistics/tx_bytes",
};
struct Network *state = malloc(sizeof(struct Network));
memset(state, '\0', sizeof(*state));
if (strcmp(dev, "X") == 0) {
int fd = open(route, O_RDONLY);
......@@ -74,50 +119,110 @@ unsigned int init_network(char *dev, void **ptr)
char buffer[1000];
if (read(fd, buffer, 999) < 0 ) {
perror("read");
/* skip first line */
char *s = buffer;
int ret = strchr_refill(fd, buffer, sizeof(buffer), &s, '\n');
if (ret != 1) {
close(fd);
free(state);
exit(1);
}
s++;
char *start_of_dev = index(buffer, '\n') + 1;
char *end_of_dev = index(start_of_dev, '\t');
*end_of_dev = '\0';
dev = start_of_dev;
close(fd);
}
char *start_of_dev = s;
/* jump to the end of the device name */
ret = strchr_refill(fd, buffer, sizeof(buffer), &s, '\t');
if (ret != 1) {
close(fd);
free(state);
exit(1);
}
char *filenames[] = {"/sys/class/net/%s/statistics/rx_packets",
"/sys/class/net/%s/statistics/rx_bytes",
"/sys/class/net/%s/statistics/tx_packets",
"/sys/class/net/%s/statistics/tx_bytes"
};
state->ndev++; // ndev should be equal to 1 at this point
memcpy(&(state->devs[state->ndev - 1]), start_of_dev,
MIN((size_t)(sizeof(state->devs[0]) - 1), (size_t)(s - start_of_dev)));
for (;;) {
/* jump to the next line */
ret = strchr_refill(fd, buffer, sizeof(buffer), &s, '\n');
if (ret != 1) {
break;
}
s++;
start_of_dev = s;
ret = strchr_refill(fd, buffer, sizeof(buffer), &s, '\t');
if (ret != 1) {
break;
}
/* compare dev name to the previously saved one */
int newdev = 1;
for (int i = 0; i < state->ndev && newdev; i++) {
if (strncmp(start_of_dev, state->devs[i], s - start_of_dev) == 0) {
newdev = 0;
}
}
if (newdev) {
if (state->ndev >= NB_MAX_DEV) {
fprintf(stderr, "Maximum amount of network devices exceeded (%d).\n", NB_MAX_DEV);
break;
}
state->ndev++;
memcpy(&(state->devs[state->ndev - 1]), start_of_dev,
MIN((size_t)(sizeof(state->devs[0]) - 1), (size_t)(s - start_of_dev)));
}
}
Network *state = malloc(sizeof(Network));
close(fd);
} else {
state->ndev = 1;
memcpy(&(state->devs[0]), dev, strlen(dev) + 1);
}
char buffer2[256];
for (int i = 0; i < NB_SENSOR; i++) {
snprintf(buffer2, 256, filenames[i], dev);
state->sources[i] = open(buffer2, O_RDONLY);
for (int i = 0; i < state->ndev; i++) {
for (int j = 0; j < NB_SENSOR; j++) {
snprintf(buffer2, sizeof(buffer2), filenames[j], state->devs[i]);
errno = 0;
int fd = open(buffer2, O_RDONLY);
if (fd < 0) {
fprintf(stderr, "init_network: open: %s: %.*s\n", strerror(errno),
(int)sizeof(buffer2), buffer2);
free(state);
exit(1);
}
state->sources[i][j] = fd;
snprintf(state->labels[i][j], sizeof(state->labels[i][j]), _labels_network[j],
state->devs[i]);
}
}
*ptr = (void *) state;
_get_network(state->values, state->sources);
return NB_SENSOR;
for (int i = 0; i < state->ndev; i++) {
_get_network(state->values[i], state->sources[i]);
}
return state->ndev * NB_SENSOR;
}
unsigned int get_network(uint64_t *results, void *ptr)
{
Network *state = (Network *) ptr;
_get_network(state->tmp_values, state->sources);
struct Network *state = (struct Network *) ptr;
for (int i = 0; i < NB_SENSOR; i++) {
results[i] = modulo_substraction(state->tmp_values[i], state->values[i]);
for (int i = 0; i < state->ndev; i++) {
_get_network(state->tmp_values[i], state->sources[i]);
for (int j = 0; j < NB_SENSOR; j++) {
results[i*NB_SENSOR + j] = modulo_substraction(state->tmp_values[i][j], state->values[i][j]);
}
memcpy(&(state->values[i]), &(state->tmp_values[i]),
NB_SENSOR * sizeof(state->values[i][0]));
}
memcpy(state->values, state->tmp_values, NB_SENSOR * sizeof(uint64_t));
return NB_SENSOR;
return state->ndev * NB_SENSOR;
}
void clean_network(void *ptr)
......@@ -128,19 +233,22 @@ void clean_network(void *ptr)
return;
}
for (int i = 0; i < NB_SENSOR; i++) {
close(state->sources[i]);
for (int i = 0; i < state->ndev; i++) {
for (int j = 0; j < NB_SENSOR; j++) {
close(state->sources[i][j]);
}
}
free(state);
}
char *_labels_network[NB_SENSOR] = {"rxp", "rxb", "txp", "txb"};
void label_network(char **labels, void *none)
void label_network(char **labels, void *ptr)
{
UNUSED(none);
struct Network *state = (struct Network *) ptr;
for (int i = 0; i < NB_SENSOR; i++) {
labels[i] = _labels_network[i];
for (int i = 0; i < state->ndev; i++) {
for (int j = 0; j < NB_SENSOR; j++) {
labels[i*NB_SENSOR + j] = state->labels[i][j];
}
}
}
src/nvidia_gpu.c 0 → 100644
+ 593
0
View file @ b4a463d6
/*******************************************************
Copyright (C) 2023-2023 Georges Da Costa <georges.da-costa@irit.fr>
This file is part of Mojitos.
Mojitos is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Mojitos is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with MojitO/S. If not, see <https://www.gnu.org/licenses/>.
*******************************************************/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
// Pedantic throws a warning in the nvml library
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"
#include <nvml.h>
#pragma GCC diagnostic pop
#include "util.h"
// -----------------------------SENSOR_KIND
typedef enum {
CLOCK_SENSOR = 0,
MEMORY_SENSOR = 1,
UTILIZATION_SENSOR = 2,
POWER_SENSOR = 3,
TEMPERATURE_SENSOR = 4,
COUNT_SENSOR = 5,
} SENSOR_KIND;
typedef struct Device Device;
typedef struct NvidiaGpu NvidiaGpu;
typedef struct ISensor ISensor;
typedef struct Sensor Sensor;
// -- Sensor interface
typedef unsigned int (Initializer) (const Device *, void **);
typedef unsigned int (Getter) (uint64_t *, const Device *, void *);
typedef unsigned int (Labeller) (char **, void *);
typedef void (Cleaner) (void *);
struct ISensor {
Initializer *init;
Getter *get;
Labeller *label;
Cleaner *clean;
};
// -- Sensor
struct Sensor {
void *data;
const ISensor *fun;
};
// -- Device: represents a gpu
struct Device {
char name[NVML_DEVICE_NAME_BUFFER_SIZE];
nvmlDevice_t device;
unsigned int idx;
Sensor sensors[COUNT_SENSOR];
unsigned int count;
};
// -- NvidiaGpu: represents the devices
struct NvidiaGpu {
Device *devices;
unsigned int count;
};
// -- Label template
static const char *label_template = "gpu%u_%s_%s";
static const char *short_label_template = "gpu%u_%s";
// ----------------------------CLOCK_SENSOR
#define CLOCK_LABEL_SIZE 25
// -- All existing clocks
// -- SM : Streaming Multiprocessor
static const nvmlClockType_t clocks[NVML_CLOCK_COUNT] = {NVML_CLOCK_GRAPHICS, NVML_CLOCK_SM, NVML_CLOCK_MEM, NVML_CLOCK_VIDEO};
static const char *clock_names[NVML_CLOCK_COUNT] = {"graphics", "sm", "memory", "video"};
static const char *clock_base_name = "clk";
// -- Must contain the clocks compatible with the device
typedef struct {
nvmlClockType_t clocks[NVML_CLOCK_COUNT];
char labels[NVML_CLOCK_COUNT][CLOCK_LABEL_SIZE];
unsigned int count;
} ClockData;
unsigned int init_clock_sensor(const Device *device, void **data)
{
const nvmlDevice_t nvml_device = device->device;
const unsigned int device_idx = device->idx;
ClockData tmp = {0};
nvmlReturn_t err;
unsigned int clock;
// -- Test all clocks
for (unsigned int i = 0; i < NVML_CLOCK_COUNT; i++) {
if ((err = nvmlDeviceGetClockInfo(nvml_device, clocks[i], &clock)) == NVML_SUCCESS) {
snprintf(tmp.labels[tmp.count], CLOCK_LABEL_SIZE, label_template, device_idx, clock_base_name, clock_names[i]);
tmp.clocks[tmp.count] = clocks[i];
tmp.count += 1;
} else {
fprintf(stderr, "Failed to get %s clock : %s\n", clock_names[i], nvmlErrorString(err));
}
}
// -- No clock avaible
if (tmp.count == 0) {
return 0;
}
*data = calloc(1, sizeof(ClockData));
memcpy(*data, &tmp, sizeof (ClockData));
return tmp.count;
}
unsigned int get_clock_sensor(uint64_t *results, const Device *device, void *data)
{
const nvmlDevice_t nvml_device = device->device;
ClockData *clock_data = (ClockData *) data;
nvmlReturn_t err;
unsigned int clock;
for (unsigned int i = 0; i < clock_data->count; i++) {
nvmlClockType_t clock_type = clock_data->clocks[i];
if((err = nvmlDeviceGetClockInfo(nvml_device, clock_type, &clock)) != NVML_SUCCESS) {
fprintf(stderr, "Failed to get %s clock : %s\n", clock_names[clock_type], nvmlErrorString(err));
exit(99);
}
results[i] = clock;
}
return clock_data->count;
}
unsigned int label_clock_sensor(char **labels, void *data)
{
ClockData *clock_data = (ClockData *) data;
for (unsigned int i = 0; i < clock_data->count; i++) {
labels[i] = clock_data->labels[i];
}
return clock_data->count;
}
void clean_clock_sensor(void *data)
{
free(data);
}
// ---------------------------MEMORY_SENSOR
#define MEMORY_LABEL_SIZE 25
typedef enum {
FREE_MEMORY = 0U,
USED_MEMORY = 1U,
TOTAL_MEMORY = 2U,
COUNT_MEMORY = 3U,
} MemoryKind;
static const char *memory_names[COUNT_MEMORY] = {"free", "used", "total"};
static const char *memory_base_name = "mem";
typedef struct {
char labels[COUNT_MEMORY][MEMORY_LABEL_SIZE];
} MemoryData;
unsigned int init_memory_sensor(const Device *device, void **data)
{
const nvmlDevice_t nvml_device = device->device;
const unsigned int device_idx = device->idx;
nvmlMemory_t memory;
nvmlReturn_t err;
if ((err = nvmlDeviceGetMemoryInfo(nvml_device, &memory)) != NVML_SUCCESS) {
fprintf(stderr, "Failed to get device memory : %s\n", nvmlErrorString(err));
return 0;
}
MemoryData *memory_data = (MemoryData *) calloc(1, sizeof(MemoryData));
for (unsigned int i = 0; i < COUNT_MEMORY; i++) {
snprintf(memory_data->labels[i], MEMORY_LABEL_SIZE, label_template, device_idx, memory_base_name, memory_names[i]);
}
*data = (void *) memory_data;
return COUNT_MEMORY;
}
unsigned int get_memory_sensor(uint64_t *results, const Device *device, void *none)
{
UNUSED(none);
const nvmlDevice_t nvml_device = device->device;
nvmlMemory_t memory;
nvmlReturn_t err;
if ((err = nvmlDeviceGetMemoryInfo(nvml_device, &memory)) != NVML_SUCCESS) {
fprintf(stderr, "Failed to get device memory : %s\n", nvmlErrorString(err));
exit(99);
}
results[FREE_MEMORY] = memory.free;
results[USED_MEMORY] = memory.used;
results[TOTAL_MEMORY] = memory.total;
return COUNT_MEMORY;
}
unsigned int label_memory_sensor(char **labels, void *data)
{
MemoryData *memory_data = (MemoryData *) data;
for (unsigned int i = 0; i < COUNT_MEMORY; i++) {
labels[i] = memory_data->labels[i];
}
return COUNT_MEMORY;
}
void clean_memory_sensor(void *data)
{
free(data);
}
// ----------------------UTILIZATION_SENSOR
#define UTILIZATION_LABEL_SIZE 35
typedef enum {
GPU_UTILIZATION = 0U,
MEMORY_UTILIZATION = 1U,
COUNT_UTILIZATION = 2U,
} UtilizationKind;
typedef struct {
char labels[COUNT_UTILIZATION][UTILIZATION_LABEL_SIZE];
} UtilizationData;
static const char *utilization_names[COUNT_UTILIZATION] = {"gpu", "memory"};
static const char *utilization_base_name = "utilization";
unsigned int init_utilization_sensor(const Device *device, void **data)
{
const nvmlDevice_t nvml_device = device->device;
const unsigned int device_idx = device->idx;
nvmlReturn_t err;
nvmlUtilization_t utilization;
if ((err = nvmlDeviceGetUtilizationRates(nvml_device, &utilization)) != NVML_SUCCESS) {
fprintf(stderr, "Failed to get device utilization: %s\n", nvmlErrorString(err));
return 0;
}
UtilizationData *utilization_data = (UtilizationData *) calloc(1, sizeof(UtilizationData));
for (unsigned int i = 0; i < COUNT_UTILIZATION; i++) {
snprintf(utilization_data->labels[i], UTILIZATION_LABEL_SIZE, label_template, device_idx, utilization_base_name, utilization_names[i]);
}
*data = (void *) utilization_data;
return COUNT_UTILIZATION;
}
unsigned int get_utilization_sensor(uint64_t *results, const Device *device, void *none)
{
UNUSED(none);
const nvmlDevice_t nvml_device = device->device;
nvmlReturn_t err;
nvmlUtilization_t utilization;
if ((err = nvmlDeviceGetUtilizationRates(nvml_device, &utilization)) != NVML_SUCCESS) {
fprintf(stderr, "Failed to get device utilization: %s\n", nvmlErrorString(err));
exit(99);
}
results[GPU_UTILIZATION] = utilization.gpu;
results[MEMORY_UTILIZATION] = utilization.memory;
return COUNT_UTILIZATION;
}
unsigned int label_utilization_sensor(char **labels, void *data)
{
UtilizationData *utilization_data = (UtilizationData *) data;
for (unsigned int i = 0; i < COUNT_UTILIZATION; i++) {
labels[i] = utilization_data->labels[i];
}
return COUNT_UTILIZATION;
}
void clean_utilization_sensor(void *data)
{
free(data);
}
// ----------------------------POWER_SENSOR
#define POWER_LABEL_SIZE 25
#define COUNT_POWER 1
static const char *power_base_name = "power";
typedef struct {
char label[POWER_LABEL_SIZE];
} PowerData;
unsigned int init_power_sensor(const Device *device, void **data)
{
const nvmlDevice_t nvml_device = device->device;
const unsigned int device_idx = device->idx;
unsigned int power;
nvmlReturn_t err;
if ((err = nvmlDeviceGetPowerUsage(nvml_device, &power)) != NVML_SUCCESS) {
printf("Failed to get the device power consumption: %s\n", nvmlErrorString(err));
return 0;
}
PowerData *power_data = (PowerData *) calloc(1, sizeof(PowerData));
snprintf(power_data->label, POWER_LABEL_SIZE, short_label_template, device_idx, power_base_name);
*data = (void *) power_data;
return COUNT_POWER;
}
unsigned int get_power_sensor(uint64_t *results, const Device *device, void *none)
{
UNUSED(none);
const nvmlDevice_t nvml_device = device->device;
unsigned int power;
nvmlReturn_t err;
if ((err = nvmlDeviceGetPowerUsage(nvml_device, &power)) != NVML_SUCCESS) {
printf("Failed to get the device power consumption: %s\n", nvmlErrorString(err));
exit(99);
}
*results = power;
return COUNT_POWER;
}
unsigned int label_power_sensor(char **labels, void *data)
{
PowerData *power_data = (PowerData *) data;
*labels = power_data->label;
return COUNT_POWER;
}
void clean_power_sensor(void *data)
{
free(data);
}
// ----------------------TEMPERATURE_SENSOR
#define TEMPERATURE_LABEL_SIZE 35
#define COUNT_TEMPERATURE 1
static const char *temperature_base_name = "temperature";
typedef struct {
char label[TEMPERATURE_LABEL_SIZE];
} TemperatureData;
unsigned int init_temperature_sensor(const Device *device, void **data)
{
const nvmlDevice_t nvml_device = device->device;
const unsigned int device_idx = device->idx;
unsigned int temperature;
nvmlReturn_t err;
if ((err = nvmlDeviceGetTemperature(nvml_device, NVML_TEMPERATURE_GPU, &temperature)) != NVML_SUCCESS) {
printf("Failed to get the device temperature: %s\n", nvmlErrorString(err));
return 0;
}
TemperatureData *temperature_data = (TemperatureData *) calloc(1, sizeof(TemperatureData));
snprintf(temperature_data->label, TEMPERATURE_LABEL_SIZE, short_label_template, device_idx, temperature_base_name);
*data = (void *) temperature_data;
return COUNT_TEMPERATURE;
}
unsigned int get_temperature_sensor(uint64_t *results, const Device *device, void *none)
{
UNUSED(none);
const nvmlDevice_t nvml_device = device->device;
unsigned int temperature;
nvmlReturn_t err;
if ((err = nvmlDeviceGetTemperature(nvml_device, NVML_TEMPERATURE_GPU, &temperature)) != NVML_SUCCESS) {
printf("Failed to get the device temperature: %s\n", nvmlErrorString(err));
exit(99);
}
*results = temperature;
return COUNT_TEMPERATURE;
}
unsigned int label_temperature_sensor(char **labels, void *data)
{
TemperatureData *temperature_data = (TemperatureData *) data;
*labels = temperature_data->label;
return COUNT_TEMPERATURE;
}
void clean_temperature_sensor(void *data)
{
free(data);
}
// -------------------------AVAIBLE_SENSORS
static const ISensor avaible_sensors[COUNT_SENSOR] = {
{.init = init_clock_sensor, .get = get_clock_sensor, .label = label_clock_sensor, .clean = clean_clock_sensor},
{.init = init_memory_sensor, .get = get_memory_sensor, .label = label_memory_sensor, .clean = clean_memory_sensor},
{.init = init_utilization_sensor, .get = get_utilization_sensor, .label = label_utilization_sensor, .clean = clean_utilization_sensor},
{.init = init_power_sensor, .get = get_power_sensor, .label = label_power_sensor, .clean = clean_power_sensor},
{.init = init_temperature_sensor, .get = get_temperature_sensor, .label = label_temperature_sensor, .clean = clean_temperature_sensor},
};
// ------------------------DEVICE_FUNCTIONS
unsigned int init_device(unsigned int device_idx, Device *device)
{
nvmlReturn_t result;
nvmlDevice_t nvml_device;
if ((result = nvmlDeviceGetHandleByIndex(device_idx, &nvml_device)) != NVML_SUCCESS) {
fprintf(stderr, "Failed to get device handle for device %d: %s\n", device_idx, nvmlErrorString(result));
return 0;
}
if ((result = nvmlDeviceGetName(nvml_device, device->name, NVML_DEVICE_NAME_BUFFER_SIZE))) {
fprintf(stderr, "Failed to get device name for device %d: %s\n", device_idx, nvmlErrorString(result));
return 0;
}
device->device = nvml_device;
device->idx = device_idx;
unsigned int sensor_count = 0;
unsigned int total_count = 0;
for (unsigned int i = 0; i < COUNT_SENSOR; i++) {
Sensor *sensor = &device->sensors[sensor_count];
sensor->fun = &avaible_sensors[i];
unsigned int count;
if ((count = sensor->fun->init(device, &sensor->data)) != 0) {
sensor_count += 1;
total_count += count;
}
}
device->count = sensor_count;
return total_count;
}
unsigned int get_device(uint64_t *results, Device *device)
{
unsigned int count = 0;
for (unsigned int i = 0; i < device->count; i++) {
Sensor *sensor = &device->sensors[i];
unsigned int result = sensor->fun->get(results, device, sensor->data);
count += result;
results += result;
}
return count;
}
unsigned int label_device(char **labels, Device *device)
{
unsigned int count = 0;
for (unsigned int i = 0; i < device->count; i++) {
Sensor *sensor = &device->sensors[i];
unsigned int result = sensor->fun->label(labels, sensor->data);
labels += result;
count += result;
}
return count;
}
void clean_device(Device *device)
{
for (unsigned int i = 0; i < device->count; i++) {
Sensor *sensor = &device->sensors[i];
sensor->fun->clean(sensor->data);
}
}
// ------------------------NVIDIA_INTERFACE
unsigned int init_nvidia_gpu(char *none, void **ptr)
{
UNUSED(none);
UNUSED(ptr);
nvmlReturn_t result;
if ((result = nvmlInit()) != NVML_SUCCESS) {
fprintf(stderr, "Failed to initialize NVML: %s\n", nvmlErrorString(result));
exit(1);
}
unsigned int avaible_device_count;
if ((result = nvmlDeviceGetCount(&avaible_device_count)) != NVML_SUCCESS) {
fprintf(stderr, "Failed to get device count : %s\n", nvmlErrorString(result));
nvmlShutdown();
exit(1);
}
Device *devices = calloc(avaible_device_count, sizeof(Device));
unsigned int sensor_count = 0;
unsigned int device_count = 0;
for (unsigned int i = 0; i < avaible_device_count; i++) {
unsigned int initialized_count;
if ((initialized_count = init_device(i, &devices[device_count])) != 0) {
sensor_count += initialized_count;
device_count += 1;
}
}
NvidiaGpu *nvidia = (NvidiaGpu *) calloc(1, sizeof(NvidiaGpu));
nvidia->devices = devices;
nvidia->count = device_count;
*ptr = (void *) nvidia;
return sensor_count;
}
unsigned int get_nvidia_gpu(uint64_t *results, void *ptr)
{
NvidiaGpu *nvidia = (NvidiaGpu *) ptr;
unsigned count = 0;
for (unsigned int i = 0; i < nvidia->count; i++) {
unsigned int result = get_device(results, &nvidia->devices[i]);
results += result;
count += result;
}
return count;
}
unsigned int label_nvidia_gpu(char **labels, void *ptr)
{
NvidiaGpu *nvidia = (NvidiaGpu *) ptr;
unsigned count = 0;
for (unsigned int i = 0; i < nvidia->count; i++) {
unsigned int result = label_device(labels, &nvidia->devices[i]);
labels += result;
count += result;
}
return count;
}
void clean_nvidia_gpu(void *ptr)
{
NvidiaGpu *nvidia = (NvidiaGpu *) ptr;
for (unsigned int i = 0; i < nvidia->count; i++) {
clean_device(&nvidia->devices[i]);
}
free(nvidia->devices);
free(nvidia);
nvmlShutdown();
}
/*******************************************************
Copyright (C) 2023-2023 Georges Da Costa <georges.da-costa@irit.fr>
This file is part of Mojitos.
Mojitos is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Mojitos is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with MojitO/S. If not, see <https://www.gnu.org/licenses/>.
*******************************************************/
unsigned int init_nvidia_gpu(char *, void **);
unsigned int get_nvidia_gpu(uint64_t *results, void *);
void clean_nvidia_gpu(void *);
void label_nvidia_gpu(char **labels, void *);
Sensor nvidia_gpu = {
.init = init_nvidia_gpu,
.get = get_nvidia_gpu,
.clean = clean_nvidia_gpu,
.label = label_nvidia_gpu,
.nb_opt = 1,
};
Optparse nvidia_gpu_opt[1] = {
{
.longname = "nvidia-gpu",
.shortname = 'n',
.argtype = OPTPARSE_NONE,
.usage_arg = NULL,
.usage_msg = "provides basic gpu information [clocks, memory, utilization, power, temperature].",
},
};
......@@ -38,6 +38,8 @@
exit(code); \
} while (0)
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
/**
* @brief Substracts lhs by rhs, assuming that lhs is a cyclic increment from rhs,
......
......@@ -21,9 +21,11 @@
#include "util.c"
#include "amd_rapl.c"
#include "info_reader.c"
#include "memory.c"
TMAIN({
CALL_TFUNCTION(test_util);
CALL_TFUNCTION(test_amd_rapl);
CALL_TFUNCTION(test_info_reader);
CALL_TFUNCTION(test_memory);
})
tests/memory.c 0 → 100644
/*******************************************************
Copyright (C) 2023-2023 Georges Da Costa <georges.da-costa@irit.fr>
This file is part of Mojitos.
Mojitos is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Mojitos is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with MojitO/S. If not, see <https://www.gnu.org/licenses/>.
*******************************************************/
#include "small_test.h"
#include "../src/memory.c"
// In order to verify the integrity.
TFUNCTION(test_labels, {
// If it fails update the tests
int tested_count = 10;
int expected_count = MEMORY_COUNT;
TEST_INT(&tested_count, &expected_count);
const char *result = NULL;
char *expected = NULL;
expected = "totalram";
result = memory_labels[TOTALRAM];
TEST_STR(result, expected);
expected = "freeram";
result = memory_labels[FREERAM];
TEST_STR(result, expected);
expected = "sharedram";
result = memory_labels[SHAREDRAM];
TEST_STR(result, expected);
expected = "bufferram";
result = memory_labels[BUFFERRAM];
TEST_STR(result, expected);
expected = "totalswap";
result = memory_labels[TOTALSWAP];
TEST_STR(result, expected);
expected = "freeswap";
result = memory_labels[FREESWAP];
TEST_STR(result, expected);
expected = "procs";
result = memory_labels[PROCS];
TEST_STR(result, expected);
expected = "totalhigh";
result = memory_labels[TOTALHIGH];
TEST_STR(result, expected);
expected = "freehigh";
result = memory_labels[FREEHIGH];
TEST_STR(result, expected);
expected = "mem_unit";
result = memory_labels[MEM_UNIT];
TEST_STR(result, expected);
})
TFILE_ENTRY_POINT(test_memory, {
CALL_TFUNCTION(test_labels);
})
......@@ -253,8 +253,8 @@
#define DEFERRED_ERROR(nb_error) \
INDENTED_PRINT("|_Deferred Error : %d\n",nb_error);
typedef int (Comparator) (void *, void *);
typedef char *(Formatter) (char[FMT_BUFFER_SIZE], void *);
typedef int (Comparator) (const void *, const void *);
typedef char *(Formatter) (char[FMT_BUFFER_SIZE], const void *);
typedef struct {
Comparator *compare;
......@@ -263,7 +263,7 @@ typedef struct {
// ---------------------------TEST FUNCTION
int test(char *file, int line, unsigned int __indentation_level, void *result, void *expected, const TestInterface *interface)
int test(char *file, int line, unsigned int __indentation_level, const void *result, const void *expected, const TestInterface *interface)
{
__indentation_level += 1;
static char buffer_result[FMT_BUFFER_SIZE];
......@@ -281,7 +281,7 @@ int test(char *file, int line, unsigned int __indentation_level, void *result, v
// ------------------------------INTERFACES
// -- str_interface
int str_compare(void *ptr1, void *ptr2)
int str_compare(const void *ptr1, const void *ptr2)
{
char *str1 = (char *) ptr1;
char *str2 = (char *) ptr2;
......@@ -295,7 +295,7 @@ int str_compare(void *ptr1, void *ptr2)
}
}
char *str_format(char buffer[FMT_BUFFER_SIZE], void *ptr)
char *str_format(char buffer[FMT_BUFFER_SIZE], const void *ptr)
{
UNUSED(buffer);
static char *str_null = "NULL";
......@@ -310,14 +310,14 @@ static const TestInterface str_interface = {
// -- bool_interface
int bool_compare(void *ptr1, void *ptr2)
int bool_compare(const void *ptr1, const void *ptr2)
{
bool *bool1 = (bool *) ptr1;
bool *bool2 = (bool *) ptr2;
return *bool1 == *bool2;
}
char *bool_format(char buffer[FMT_BUFFER_SIZE], void *ptr)
char *bool_format(char buffer[FMT_BUFFER_SIZE], const void *ptr)
{
UNUSED(buffer);
bool *_bool = (bool *) ptr;
......@@ -331,14 +331,14 @@ static const TestInterface bool_interface = {
// -- int_interface
int int_compare(void *ptr1, void *ptr2)
int int_compare(const void *ptr1, const void *ptr2)
{
int *int1 = (int *) ptr1;
int *int2 = (int *) ptr2;
return *int1 == *int2;
}
char *int_format(char buffer[FMT_BUFFER_SIZE], void *ptr)
char *int_format(char buffer[FMT_BUFFER_SIZE], const void *ptr)
{
int *_int = (int *) ptr;
snprintf(buffer, FMT_BUFFER_SIZE, "%d", *_int);
......@@ -352,12 +352,12 @@ static const TestInterface int_interface = {
// -- ptr_interface
int ptr_compare(void *ptr1, void *ptr2)
int ptr_compare(const void *ptr1, const void *ptr2)
{
return ptr1 == ptr2;
}
char *ptr_format(char buffer[FMT_BUFFER_SIZE], void *ptr)
char *ptr_format(char buffer[FMT_BUFFER_SIZE], const void *ptr)
{
snprintf(buffer, FMT_BUFFER_SIZE, "%p", ptr);
return buffer;
......@@ -370,14 +370,14 @@ static const TestInterface ptr_interface = {
// -- u64_interface
int u64_compare(void *ptr1, void *ptr2)
int u64_compare(const void *ptr1, const void *ptr2)
{
uint64_t *v1 = (uint64_t *) ptr1;
uint64_t *v2 = (uint64_t *) ptr2;
return *v1 == *v2;
}
char *u64_format(char buffer[FMT_BUFFER_SIZE], void *ptr)
char *u64_format(char buffer[FMT_BUFFER_SIZE], const void *ptr)
{
uint64_t *v = (uint64_t *) ptr;
snprintf(buffer, FMT_BUFFER_SIZE, "%"PRIu64"", *v);
......
......@@ -77,6 +77,50 @@ TFUNCTION(test_modulo_substraction, {
TEST_UINT64_T(&result, &expected);
})
TFUNCTION(test_max, {
int expected = 0;
int result = 0;
expected = 10;
result = MAX(expected, 9);
TEST_INT(&result, &expected);
expected = -15;
result = MAX(expected, -16);
TEST_INT(&result, &expected);
expected = 0;
result = MAX(expected, -1);
TEST_INT(&result, &expected);
expected = 1;
result = MAX(expected, 0);
TEST_INT(&result, &expected);
})
TFUNCTION(test_min, {
int expected = 0;
int result = 0;
expected = 9;
result = MIN(expected, 10);
TEST_INT(&result, &expected);
expected = -16;
result = MIN(expected, -15);
TEST_INT(&result, &expected);
expected = -1;
result = MIN(expected, 0);
TEST_INT(&result, &expected);
expected = 0;
result = MIN(expected, 1);
TEST_INT(&result, &expected);
})
TFILE_ENTRY_POINT(test_util, {
CALL_TFUNCTION(test_modulo_substraction);
CALL_TFUNCTION(test_max);
CALL_TFUNCTION(test_min);
})
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment