Commit 1b1ab79b authored by Jorge Machado's avatar Jorge Machado

Add irq demo

parent b1052416
This source diff could not be displayed because it is too large. You can view the blob instead.
CFLAGS += -I./dep
demo-irq: demo-irq.c ./dep/*.c
gcc -o demo-irq demo-irq.c ./dep/*.c $(CFLAGS) -lm
clean:
-rm demo-irq
-rm .demo-irq.log
/*
* Copyright (C) 2020 CERN (www.cern.ch)
*
* Author: Miguel Jimenez Lopez <miguel.jimenez@sevensols.com>
*
* Released to the public domain as sample code to be customized.
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
#ifndef __DEMO_IRQ_PRIVATE_H__
#define __DEMO_IRQ_PRIVATE_H__
#define PROG_NAME "demo-irq"
#define TEST_FMC_DIO_CH 5
#define TEST_FMC_DIO_COUNT -1
#define TEST_FMC_DIO_PERIOD 100000000
#define STATS_LOG_PATH "./.demo-irq.log"
#define PROCESS_SLEEP_US 100000
struct _user_args {
char *fmc_dev_path;
unsigned int irq_period;
};
typedef struct _user_args * user_args;
static void demo_irq_process_loop(fmc_dio_device fmc_dev, stats_engine engine);
static void process_timestamps_to_engine(stats_engine engine, struct timespec *ts,
unsigned int nts);
static user_args create_user_arguments(void);
static int parse_user_arguments(int argc, char *argv[], user_args parsed_args);
static void destroy_user_arguments(user_args args);
static void show_help(void);
static unsigned int check_user_stop(void);
#endif
/*
* Copyright (C) 2020 CERN (www.cern.ch)
*
* Author: Miguel Jimenez Lopez <miguel.jimenez@sevensols.com>
*
* Released to the public domain as sample code to be customized.
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
#include "stats-engine.h"
#include "fmc-dio-device.h"
#include "printf-log.h"
#include "file-log.h"
#include "demo-irq-private.h"
int main(int argc, char *argv[])
{
fmc_dio_device dev;
log_device gen_log;
log_device stats_log;
user_args user_arguments;
log_device logs[2];
unsigned int n_logs = 2;
unsigned int user_stop = 0;
stats_engine sengine;
int ret = 0;
gen_log = create_printf_log_device();
stats_log = create_file_log_device(STATS_LOG_PATH);
logs[0] = gen_log;
logs[1] = stats_log;
user_arguments = create_user_arguments();
if(parse_user_arguments(argc, argv, user_arguments)) {
show_help();
ret = 1;
goto out_log;
}
sengine = create_stats_engine();
if(check_stats_engine(sengine)) {
ret = 1;
goto out_user_args;
}
attach_log_devices_to_stats_engine(sengine, logs, n_logs);
enable_log_for_stats_engine(sengine);
dev = create_fmc_dio_device(user_arguments->fmc_dev_path);
if(open_fmc_dio_device(dev)) {
ret = 1;
goto out_stats_engine;
}
attach_log_devices_to_fmc_dio_device(dev, logs, n_logs);
enable_log_for_fmc_dio_device(dev);
disable_fmc_dio_device_all_irq(dev);
enable_fmc_dio_device_irq(dev, TEST_FMC_DIO_CH);
setup_fmc_dio_device_irq(dev, user_arguments->irq_period, TEST_FMC_DIO_COUNT);
while(!user_stop) {
demo_irq_process_loop(dev, sengine);
user_stop = check_user_stop();
}
disable_fmc_dio_device_all_irq(dev);
out_fmc_dio_device:
close_fmc_dio_device(dev);
out_stats_engine:
destroy_stats_engine(sengine);
out_user_args:
destroy_user_arguments(user_arguments);
out_log:
destroy_log_device(stats_log);
destroy_log_device(gen_log);
return ret;
}
static void demo_irq_process_loop(fmc_dio_device fmc_dev, stats_engine engine)
{
struct timespec *ts;
unsigned int nts;
while(!get_utc_ts_from_fmc_dio_device(fmc_dev, TEST_FMC_DIO_CH, &ts, &nts)) {
process_timestamps_to_engine(engine, ts, nts);
usleep(PROCESS_SLEEP_US);
}
}
static void process_timestamps_to_engine(stats_engine engine, struct timespec *ts,
unsigned int nts)
{
for(int i = 0 ; i < nts ; i++) {
add_usr_timestamp_to_stats_engine(engine, &ts[i]);
run_stats_engine(engine);
}
free(ts);
}
static user_args create_user_arguments(void)
{
user_args arguments;
arguments = calloc(1, sizeof(*arguments));
return arguments;
}
static int parse_user_arguments(int argc, char *argv[], user_args parsed_args)
{
if(argc != 2 && argc != 3)
return 1;
parsed_args->fmc_dev_path = argv[1];
if(argc == 3)
sscanf(argv[2], "%d", &parsed_args->irq_period);
else
parsed_args->irq_period = TEST_FMC_DIO_PERIOD;
return 0;
}
static void destroy_user_arguments(user_args args)
{
if(args) {
free(args);
}
}
static void show_help(void)
{
printf("usage: %s <FMC device path> [<irq period (ns)>]\n", PROG_NAME);
}
static unsigned int check_user_stop(void)
{
int ret = 0;
char c;
fd_set fds;
struct timeval tv;
FD_ZERO(&fds);
FD_SET(STDIN_FILENO, &fds);
tv.tv_sec = 0;
tv.tv_usec = 1;
if(select(STDIN_FILENO+1, &fds, NULL, NULL, &tv) == 1) {
c = getchar();
if(c == 'q')
ret = 1;
}
return ret;
}
/*
* Copyright (C) 2020 CERN (www.cern.ch)
*
* Author: Miguel Jimenez Lopez <miguel.jimenez@sevensols.com>
*
* Released to the public domain as sample code to be customized.
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
#ifndef __FILE_LOG_PRIVATE_H__
#define __FILE_LOG_PRIVATE_H__
struct file_log_private {
FILE *fp;
char *path;
};
static int check_file_log_priv(log_device dev);
static struct file_log_private * get_private_info(log_device dev);
static void init_file_log_device(log_device dev);
static void send_to_file_log_device(log_device, const char *msg);
static void deinit_file_log_device(log_device dev);
#endif
/*
* Copyright (C) 2020 CERN (www.cern.ch)
*
* Author: Miguel Jimenez Lopez <miguel.jimenez@sevensols.com>
*
* Released to the public domain as sample code to be customized.
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
#include "log-device.h"
#include "file-log-private.h"
static struct log_device_iface _file_log_iface =
{
.init_log_device = init_file_log_device,
.send_to_log_device = send_to_file_log_device,
.clear_log_device = NULL,
.deinit_log_device = deinit_file_log_device,
};
static const log_device_interface file_log_iface = &_file_log_iface;
log_device create_file_log_device(const char *path)
{
return create_log_device((void *)path, file_log_iface);
}
static void init_file_log_device(log_device dev)
{
struct file_log_private *priv;
priv = calloc(1, sizeof(*priv));
priv->path = dev->private;
priv->fp = fopen(priv->path, "w+");
dev->private = priv;
}
static void send_to_file_log_device(log_device dev, const char *msg)
{
struct file_log_private *priv;
if(!check_file_log_priv(dev)) {
priv = get_private_info(dev);
fputs(msg, priv->fp);
fputs("\n", priv->fp);
}
}
static void deinit_file_log_device(log_device dev)
{
struct file_log_private *priv;
if(dev->private) {
priv = get_private_info(dev);
fclose(priv->fp);
free(dev->private);
}
}
static int check_file_log_priv(log_device dev)
{
return (dev->private != NULL) ? 0 : 1;
}
static struct file_log_private * get_private_info(log_device dev)
{
return (struct file_log_private *)dev->private;
}
/*
* Copyright (C) 2020 CERN (www.cern.ch)
*
* Author: Miguel Jimenez Lopez <miguel.jimenez@sevensols.com>
*
* Released to the public domain as sample code to be customized.
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
#ifndef __FILE_LOG_H__
#define __FILE_LOG_H__
log_device create_file_log_device(const char *file);
#endif
/*
* Copyright (C) 2020 CERN (www.cern.ch)
*
* Author: Miguel Jimenez Lopez <miguel.jimenez@sevensols.com>
*
* Released to the public domain as sample code to be customized.
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
#ifndef __FMC_DIO_DEVICE_PRIVATE_H__
#define __FMC_DIO_DEVICE_PRIVATE_H__
#include "../../fmc-dio/sw/kernel/fmc-dio.h"
#define MAX_TMP_BUF 1024
#define FMC_DIO_N_CH 5
#define NS_IN_A_SEC 1000000000
struct fmc_dio_dev {
char *dev_name;
int fd;
log_device *logs;
unsigned int n_logs;
int enabled_log;
unsigned int total_n_ts;
unsigned int partial_n_ts;
struct wr_dio_cmd cmd;
};
static const fmc_dio_device BAD_FMC_DEVICE = NULL;
static int check_fmc_dio_device(fmc_dio_device dev);
static int enable_fmc_dio_device_hw_irq(fmc_dio_device dev,
int ch, int en);
static int setup_fmc_dio_device_hw_irq(fmc_dio_device dev,
unsigned long period,
long count);
static int get_hw_ts_from_fmc_dio_device(fmc_dio_device dev, int ch,
struct timespec **ts, unsigned int *nts);
static int get_kernel_leaps_info(fmc_dio_device dev);
static void log_msg(fmc_dio_device dev, const char *msg);
static void LOG(fmc_dio_device dev, const char *fmt, ...);
#endif
/*
* Copyright (C) 2020 CERN (www.cern.ch)
*
* Author: Miguel Jimenez Lopez <miguel.jimenez@sevensols.com>
*
* Released to the public domain as sample code to be customized.
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <errno.h>
#include <string.h>
#include <stdint.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/timex.h>
#include <sys/ioctl.h>
#include "fmc-dio-device.h"
#include "fmc-dio-device-private.h"
fmc_dio_device create_fmc_dio_device(char *name)
{
fmc_dio_device dev = calloc(1, sizeof(*dev));
if(!dev)
return BAD_FMC_DEVICE;
dev->dev_name = name;
return dev;
}
static int check_fmc_dio_device(fmc_dio_device dev)
{
if(dev != BAD_FMC_DEVICE) {
return 0;
}
else {
return 1;
}
}
int open_fmc_dio_device(fmc_dio_device dev)
{
if(check_fmc_dio_device(dev))
return -EINVAL;
dev->fd = open(dev->dev_name, O_RDWR);
if(dev->fd < 0) {
free(dev);
return -ENODEV;
}
if(ioctl(dev->fd, PRIV_MEZZANINE_ID, (unsigned long) dev->dev_name) < 0 &&
errno != EAGAIN) {
free(dev);
return -EFAULT;
}
return 0;
}
void attach_log_devices_to_fmc_dio_device(fmc_dio_device dev,
log_device *log_devs,
unsigned int n_log_devs)
{
if(check_fmc_dio_device(dev) || !log_devs || n_log_devs == 0)
return;
dev->logs = log_devs;
dev->n_logs = n_log_devs;
}
int enable_log_for_fmc_dio_device(fmc_dio_device dev)
{
if(check_fmc_dio_device(dev))
return -EINVAL;
dev->enabled_log = 1;
return 0;
}
int disable_log_for_fmc_dio_device(fmc_dio_device dev)
{
if(check_fmc_dio_device(dev))
return -EINVAL;
dev->enabled_log = 0;
return 0;
}
void close_fmc_dio_device(fmc_dio_device dev)
{
if(check_fmc_dio_device(dev))
return;
close(dev->fd);
free(dev);
}
int enable_fmc_dio_device_irq(fmc_dio_device dev, int ch)
{
int ret;
if(check_fmc_dio_device(dev)) {
return -EINVAL;
}
ret = enable_fmc_dio_device_hw_irq(dev, ch, 1);
return ret;
}
int enable_fmc_dio_device_all_irq(fmc_dio_device dev)
{
int ret = 0;
for(int i = 0 ; i <= FMC_DIO_N_CH ; i++) {
ret = enable_fmc_dio_device_irq(dev, i);
if(ret)
break;
}
return ret;
}
int disable_fmc_dio_device_irq(fmc_dio_device dev, int ch)
{
int ret;
if(check_fmc_dio_device(dev)) {
return -EINVAL;
}
ret = enable_fmc_dio_device_hw_irq(dev, ch, 0);
return ret;
}
int disable_fmc_dio_device_all_irq(fmc_dio_device dev)
{
int ret = 0;
for(int i = 0 ; i <= FMC_DIO_N_CH ; i++) {
ret = disable_fmc_dio_device_irq(dev, i);
if(ret)
break;
}
return ret;
}
static int enable_fmc_dio_device_hw_irq(fmc_dio_device dev,
int ch, int en)
{
if(ch < 0 || ch > FMC_DIO_N_CH) {
return -EINVAL;
}
struct wr_dio_cmd *c = &dev->cmd;
en = (en) ? 1 : 0;
c->command = WR_DIO_CMD_MASK_IRQ;
c->flags = WR_DIO_F_MASK;
c->channel = 1 << ch;
c->value = (en) ? WR_DIO_F_MASK_ENABLE_IRQ :
WR_DIO_F_MASK_DISABLE_IRQ;
if(ioctl(dev->fd, PRIV_MEZZANINE_CMD, c) < 0)
return -EFAULT;
return 0;
}
int setup_fmc_dio_device_irq(fmc_dio_device dev,
unsigned long period,
long count)
{
int ret;
if(check_fmc_dio_device(dev))
return -EINVAL;
ret = setup_fmc_dio_device_hw_irq(dev, period, count);
return ret;
}
static int setup_fmc_dio_device_hw_irq(fmc_dio_device dev,
unsigned long period,
long count)
{
struct wr_dio_cmd *c = &dev->cmd;
int ret;
c->command = WR_DIO_CMD_IRQ;
c->flags = 0x0;
c->flags |= WR_DIO_F_LOOP;
c->flags |= WR_DIO_F_NOW;
c->t[1].tv_nsec = period % NS_IN_A_SEC;
c->t[1].tv_sec = period / NS_IN_A_SEC;
c->value= count;
ret = ioctl(dev->fd, PRIV_MEZZANINE_CMD, c);
if(ret < 0) {
return -EFAULT;
}
return 0;
}
int get_tai_ts_from_fmc_dio_device(fmc_dio_device dev, int ch,
struct timespec **ts, unsigned int *nts)
{
if(check_fmc_dio_device(dev))
return -EINVAL;
return get_hw_ts_from_fmc_dio_device(dev, ch, ts, nts);
}
int get_utc_ts_from_fmc_dio_device(fmc_dio_device dev, int ch,
struct timespec **ts, unsigned int *nts)
{
int ret;
int tai;
ret = get_tai_ts_from_fmc_dio_device(dev, ch, ts, nts);
if(ret)
return ret;
tai = get_kernel_leaps_info(dev);
for(int i = 0 ; i < *nts ; i++)
(*ts)[i].tv_sec -= tai;
return ret;
}
static int get_hw_ts_from_fmc_dio_device(fmc_dio_device dev, int ch,
struct timespec **ts, unsigned int *nts)
{
struct wr_dio_cmd *c = &dev->cmd;
int ret;
c->command = WR_DIO_CMD_STAMP;
c->flags = 0;
c->channel = ch;
ret = ioctl(dev->fd, PRIV_MEZZANINE_CMD, (unsigned long) c);
if(ret < 0) {
return -EFAULT;
}
if(c->nstamp <= 0) {
return -EAGAIN;
}
*nts = c->nstamp;
*ts = calloc(c->nstamp, sizeof(struct timespec));
if(!*ts)
return -ENOMEM;
for(int i = 0 ; i < c->nstamp ; i++) {
(*ts)[i] = c->t[i];
}
dev->total_n_ts += c->nstamp;
dev->partial_n_ts += c->nstamp;
return 0;
}
static int get_kernel_leaps_info(fmc_dio_device dev)
{
struct timex tx = {0};
if (adjtimex(&tx) < 0) {
return -EFAULT;
}
return tx.tai;
}
unsigned int get_total_n_timestamps(fmc_dio_device dev)
{
if(check_fmc_dio_device(dev))
return 0;
return dev->total_n_ts;
}
unsigned int get_partial_n_timestamps(fmc_dio_device dev)
{
if(check_fmc_dio_device(dev))
return 0;
return dev->partial_n_ts;
}
void reset_partial_n_timestamps(fmc_dio_device dev)
{
if(check_fmc_dio_device(dev))
return;
dev->partial_n_ts = 0;
}
static void log_msg(fmc_dio_device dev, const char *msg)
{
if(!dev->logs || dev->n_logs == 0)
return;
if(!dev->enabled_log)
return;
for(int i = 0 ; i < dev->n_logs ; i++)
send_to_log_device(dev->logs[i], msg);
}
static void LOG(fmc_dio_device dev, const char *fmt, ...)
{
va_list ap;
char buffer[MAX_TMP_BUF] = {0};
va_start(ap, fmt);
vsnprintf(buffer, MAX_TMP_BUF-1, fmt, ap);
va_end(ap);
log_msg(dev, buffer);
}
/*
* Copyright (C) 2020 CERN (www.cern.ch)
*
* Author: Miguel Jimenez Lopez <miguel.jimenez@sevensols.com>
*
* Released to the public domain as sample code to be customized.
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
#ifndef __FMC_DIO_DEVICE_H__
#define __FMC_DIO_DEVICE_H__
#include <time.h>
#include "log-device.h"
typedef struct fmc_dio_dev * fmc_dio_device;
fmc_dio_device create_fmc_dio_device(char *name);
int open_fmc_dio_device(fmc_dio_device dev);
void close_fmc_dio_device(fmc_dio_device dev);
void attach_log_devices_to_fmc_dio_device(fmc_dio_device dev,
log_device *log_devs,
unsigned int n_log_devs);
int enable_log_for_fmc_dio_device(fmc_dio_device dev);
int disable_log_for_fmc_dio_device(fmc_dio_device dev);
int enable_fmc_dio_device_irq(fmc_dio_device dev, int ch);
int enable_fmc_dio_device_all_irq(fmc_dio_device dev);
int disable_fmc_dio_device_irq(fmc_dio_device dev, int ch);
int disable_fmc_dio_device_all_irq(fmc_dio_device dev);
int setup_fmc_dio_device_irq(fmc_dio_device dev,
unsigned long period,
long count);
int get_tai_ts_from_fmc_dio_device(fmc_dio_device dev, int ch,
struct timespec **ts, unsigned int *nts);
int get_utc_ts_from_fmc_dio_device(fmc_dio_device dev, int ch,
struct timespec **ts, unsigned int *nts);
unsigned int get_total_n_timestamps(fmc_dio_device dev);
unsigned int get_partial_n_timestamps(fmc_dio_device dev);
void reset_partial_n_timestamps(fmc_dio_device dev);
#endif
/*
* Copyright (C) 2020 CERN (www.cern.ch)
*
* Author: Miguel Jimenez Lopez <miguel.jimenez@sevensols.com>
*
* Released to the public domain as sample code to be customized.
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
#ifndef __LOG_DEVICE_PRIVATE_H__
#define __LOG_DEVICE_PRIVATE_H__
static const log_device BAD_LOG_DEVICE = NULL;
static int check_log_device(log_device dev);
static int check_log_device_interface(log_device dev);
#endif
/*
* Copyright (C) 2020 CERN (www.cern.ch)
*
* Author: Miguel Jimenez Lopez <miguel.jimenez@sevensols.com>
*
* Released to the public domain as sample code to be customized.
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
#include <stdlib.h>
#include "log-device.h"
#include "log-device-private.h"
log_device create_log_device(void *args, log_device_interface interface)
{
log_device dev = calloc(1, sizeof(struct log_dev));
if(dev != BAD_LOG_DEVICE && interface != NULL) {
dev->private = args;
dev->ops = interface;
if(dev->ops->init_log_device)
dev->ops->init_log_device(dev);
}
return dev;
}
void send_to_log_device(log_device dev, const char *msg)
{
if(check_log_device_interface(dev))
return;
dev->ops->send_to_log_device(dev, msg);
}
void clear_log_device(log_device dev)
{
if(check_log_device_interface(dev))
return;
if(dev->ops->clear_log_device)
dev->ops->clear_log_device(dev);
}
void destroy_log_device(log_device dev)
{
if(check_log_device_interface(dev))
return;
if(dev->ops->deinit_log_device)
dev->ops->deinit_log_device(dev);
free(dev);
}
static int check_log_device(log_device dev)
{
return (dev == BAD_LOG_DEVICE) ? 1 : 0;
}
static int check_log_device_interface(log_device dev)
{
if(check_log_device(dev))
return 1;
if(!dev->ops)
return 1;
else
return 0;
}
/*
* Copyright (C) 2020 CERN (www.cern.ch)
*
* Author: Miguel Jimenez Lopez <miguel.jimenez@sevensols.com>
*
* Released to the public domain as sample code to be customized.
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
#ifndef __LOG_DEVICE_H__
#define __LOG_DEVICE_H__
typedef struct log_device_iface * log_device_interface;
struct log_dev {
log_device_interface ops;
void *private;
};
typedef struct log_dev * log_device;
struct log_device_iface {
void (*init_log_device)(log_device dev);
void (*send_to_log_device)(log_device dev, const char *msg);
void (*deinit_log_device)(log_device dev);
void (*clear_log_device)(log_device dev);
};
log_device create_log_device(void *args, log_device_interface interface);
void send_to_log_device(log_device dev, const char *msg);
void clear_log_device(log_device dev);
void destroy_log_device(log_device dev);
#endif
/*
* Copyright (C) 2020 CERN (www.cern.ch)
*
* Author: Miguel Jimenez Lopez <miguel.jimenez@sevensols.com>
*
* Released to the public domain as sample code to be customized.
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
#ifndef __PRINTF_LOG_PRIVATE_H__
#define __PRINTF_LOG_PRIVATE_H__
static void send_to_printf_log_device(log_device dev, const char *msg);
static void clear_printf_log_device(log_device dev);
#endif
/*
* Copyright (C) 2020 CERN (www.cern.ch)
*
* Author: Miguel Jimenez Lopez <miguel.jimenez@sevensols.com>
*
* Released to the public domain as sample code to be customized.
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
#include <stddef.h>
#include <stdio.h>
#include "log-device.h"
#include "printf-log-private.h"
static struct log_device_iface _printf_log_iface =
{
.init_log_device = NULL,
.send_to_log_device = send_to_printf_log_device,
.deinit_log_device = NULL,
.clear_log_device = clear_printf_log_device,
};
static const log_device_interface printf_log_iface = &_printf_log_iface;
static void send_to_printf_log_device(log_device dev, const char *msg)
{
printf("%s\n", msg);
}
static void clear_printf_log_device(log_device dev)
{
printf("\e[1;1H\e[2J");
}
log_device create_printf_log_device(void)
{
return create_log_device(NULL, printf_log_iface);
}
/*
* Copyright (C) 2020 CERN (www.cern.ch)
*
* Author: Miguel Jimenez Lopez <miguel.jimenez@sevensols.com>
*
* Released to the public domain as sample code to be customized.
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
#ifndef __PRINTF_LOG_H__
#define __PRINTF_LOG_H__
#include "log-device.h"
log_device create_printf_log_device(void);
void clear_screen(log_device device);
#endif
/*
* Copyright (C) 2020 CERN (www.cern.ch)
*
* Author: Miguel Jimenez Lopez <miguel.jimenez@sevensols.com>
*
* Released to the public domain as sample code to be customized.
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
#ifndef __STATS_ENGINE_PRIVATE_H__
#define __STATS_ENGINE_PRIVATE_H__
#define MAX_TS 1000
#define NS_IN_A_SEC 1000000000
#define MAX_TMP_BUF 1024
struct ts_stats {
double mean;
double std;
unsigned int ts_per_second;
unsigned int ts_total;
};
struct _stats_engine {
struct timespec usr_ts[MAX_TS];
struct timespec sys_ts[MAX_TS];
double diff_ts[MAX_TS];
struct ts_stats stats;
unsigned int n_ts;
unsigned int current_ts;
unsigned int next_ts;
log_device *logs;
unsigned int n_logs;
int enabled_log;
};
const stats_engine BAD_STATS_ENGINE = NULL;
static void update_n_ts_stats_engine(stats_engine engine);
static void update_index_stats_engine(unsigned int *index);
static void log_stats_engine(stats_engine engine, int verbose);
static int check_log_configuration(stats_engine engine);
static void log_msg(stats_engine engine,
const char *msg);
static void log_clear(stats_engine engine);
static void LOG(stats_engine engine, const char *fmt, ...);
static int timespec_subtract(struct timespec *result,
struct timespec *x,
struct timespec *y);
static double compute_mean(const double *values,
const unsigned int n_values);
static double compute_stdev(const double *values,
const unsigned int n_values,
const double mean);
static int compute_ts_per_second(const int sec,
const struct timespec *ts,
const unsigned int n_ts);
#endif
/*
* Copyright (C) 2020 CERN (www.cern.ch)
*
* Author: Miguel Jimenez Lopez <miguel.jimenez@sevensols.com>
*
* Released to the public domain as sample code to be customized.
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include <stdarg.h>
#include <errno.h>
#include "stats-engine.h"
#include "stats-engine-private.h"
stats_engine create_stats_engine(void)
{
stats_engine engine = calloc(1, sizeof(*engine));
return engine;
}
int check_stats_engine(stats_engine engine)
{
if(engine != BAD_STATS_ENGINE)
return 0;
else
return 1;
}
void attach_log_devices_to_stats_engine(stats_engine engine,
log_device *log_devs,
unsigned int n_log_devs)
{
if(check_stats_engine(engine) || !log_devs || n_log_devs == 0)
return;
engine->logs = log_devs;
engine->n_logs = n_log_devs;
}
int enable_log_for_stats_engine(stats_engine engine)
{
if(check_stats_engine(engine))
return -EINVAL;
engine->enabled_log = 1;
return 0;
}
int disable_log_for_stats_engine(stats_engine engine)
{
if(check_stats_engine(engine))
return -EINVAL;
return 0;
}
int add_usr_timestamp_to_stats_engine(stats_engine engine, struct timespec *ts)
{
struct timespec system_ts;
if(check_stats_engine(engine))
return -EINVAL;
clock_gettime(CLOCK_REALTIME, &system_ts);
engine->sys_ts[engine->next_ts] = system_ts;
engine->usr_ts[engine->next_ts] = *ts;
update_index_stats_engine(&engine->next_ts);
update_n_ts_stats_engine(engine);
return 0;
}
int run_stats_engine(stats_engine engine)
{
struct timespec ts;
int neg;
int count_ts;
if(check_stats_engine(engine))
return -EINVAL;
neg = timespec_subtract(&ts, &engine->sys_ts[engine->current_ts],
&engine->usr_ts[engine->current_ts]);
engine->diff_ts[engine->current_ts] = ((neg) ? -1.0 : 1.0)*(ts.tv_sec + ((double) ts.tv_nsec / NS_IN_A_SEC));
engine->stats.mean = compute_mean(engine->diff_ts, engine->n_ts);
engine->stats.std = compute_stdev(engine->diff_ts, engine->n_ts, engine->stats.mean);
count_ts = compute_ts_per_second(engine->usr_ts[engine->current_ts].tv_sec,
engine->usr_ts, engine->n_ts);
if(count_ts != -1)
engine->stats.ts_per_second = count_ts;
engine->stats.ts_total++;
log_stats_engine(engine, 0);
update_index_stats_engine(&engine->current_ts);
return 0;
}
void destroy_stats_engine(stats_engine engine)
{
if(check_stats_engine(engine))
return;
free(engine);
}
static void update_n_ts_stats_engine(stats_engine engine)
{
if(engine->n_ts < MAX_TS)
engine->n_ts++;
}
static void update_index_stats_engine(unsigned int *index)
{
if(*index == MAX_TS-1)
*index = 0;
else
(*index)++;
}
static void log_stats_engine(stats_engine engine, int verbose)
{
LOG(engine, "\n===================== STATS ENGINE LOG =====================\n");
if(verbose) {
LOG(engine, "n_ts: %d", engine->n_ts);
LOG(engine, "next_ts: %d\n", engine->next_ts);
for(int i = 0 ; i < engine->n_ts ; i++) {
LOG(engine, "\tsys_ts[%d]: sec %ld, nsec %ld",
i, engine->sys_ts[i].tv_sec,
engine->sys_ts[i].tv_nsec);
LOG(engine, "\twr_ts[%d]: sec %ld, nsec %ld",
i, engine->usr_ts[i].tv_sec,
engine->usr_ts[i].tv_nsec);
LOG(engine, "\tdiff[%d]: diff %f",
i, engine->diff_ts[i]);
}
}
LOG(engine, "\nMetrics => nts: %d, nts_per_sec: %d\nmean: %f, stdev: %f",
engine->stats.ts_total, engine->stats.ts_per_second, engine->stats.mean, engine->stats.std);
LOG(engine, "\n============================================================\n");
log_clear(engine);
}
static int check_log_configuration(stats_engine engine)
{
if(!engine->logs || engine->n_logs == 0)
return 1;
if(!engine->enabled_log)
return 1;
return 0;
}
static void log_msg(stats_engine engine, const char *msg)
{
if(check_log_configuration(engine))
return;
for(int i = 0 ; i < engine->n_logs ; i++)
send_to_log_device(engine->logs[i], msg);
}
static void log_clear(stats_engine engine)
{
if(check_log_configuration(engine))
return;
for(int i = 0 ; i < engine->n_logs ; i++)
clear_log_device(engine->logs[i]);
}
static void LOG(stats_engine engine, const char *fmt, ...)
{
va_list ap;
char buffer[MAX_TMP_BUF] = {0};
va_start(ap, fmt);
vsnprintf(buffer, MAX_TMP_BUF-1, fmt, ap);
va_end(ap);
log_msg(engine, buffer);
}
static int timespec_subtract(struct timespec *result,
struct timespec *x,
struct timespec *y)
{
struct timespec xx = *x;
struct timespec yy = *y;
x = &xx; y = &yy;
if (x->tv_nsec > NS_IN_A_SEC-1)
{
x->tv_sec += x->tv_nsec / NS_IN_A_SEC;
x->tv_nsec %= NS_IN_A_SEC;
}
if (y->tv_nsec > NS_IN_A_SEC-1)
{
y->tv_sec += y->tv_nsec / NS_IN_A_SEC;
y->tv_nsec %= NS_IN_A_SEC;
}
result->tv_sec = x->tv_sec - y->tv_sec;
result->tv_nsec = x->tv_nsec - y->tv_nsec;
if(result->tv_sec>0 && result->tv_nsec < 0)
{
result->tv_nsec += NS_IN_A_SEC;
result->tv_sec--;
}
else if(result->tv_sec<0 && result->tv_nsec > 0)
{
result->tv_nsec -= NS_IN_A_SEC;
result->tv_sec++;
}
return (result->tv_sec < 0) || (result->tv_nsec<0);
}
static double compute_mean(const double *values,
const unsigned int n_values)
{
double mean = 0.0;
for(int i = 0 ; i < n_values ; i++) {
mean += values[i];
}
mean /= n_values;
return mean;
}
static double compute_stdev(const double *values,
const unsigned int n_values,
const double mean)
{
double stdev = 0.0;
double aux = 0.0;
for(int i = 0 ; i < n_values ; i++) {
aux += pow((values[i]-mean),2);
}
stdev = sqrt((aux/n_values));
return stdev;
}
static int compute_ts_per_second(const int sec,
const struct timespec *ts,
const unsigned int n_ts)
{
static int prev_sec = -1;
int count = -1;
if(prev_sec == -1) {
prev_sec = sec;
}
else {
if(prev_sec != sec) {
count = 0;
for(int i = 0 ; i < n_ts ; i++) {
if(ts[i].tv_sec == prev_sec)
count++;
}
prev_sec = sec;
}
}
return count;
}
/*
* Copyright (C) 2020 CERN (www.cern.ch)
*
* Author: Miguel Jimenez Lopez <miguel.jimenez@sevensols.com>
*
* Released to the public domain as sample code to be customized.
*
* This work is part of the White Rabbit project, a research effort led
* by CERN, the European Institute for Nuclear Research.
*/
#ifndef __STATS_ENGINE_H__
#define __STATS_ENGINE_H__
#include <time.h>
#include "log-device.h"
typedef struct _stats_engine *stats_engine;
stats_engine create_stats_engine(void);
int check_stats_engine(stats_engine engine);
void attach_log_devices_to_stats_engine(stats_engine engine,
log_device *log_devs,
unsigned int n_log_devs);
int enable_log_for_stats_engine(stats_engine engine);
int disable_log_for_stats_engine(stats_engine engine);
int add_usr_timestamp_to_stats_engine(stats_engine engine,
struct timespec *ts);
int run_stats_engine(stats_engine engine);
void destroy_stats_engine(stats_engine engine);
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment