Files
mlpack/fastlib2/fastlib/fx/fx.c
T
2008-05-18 23:15:02 +00:00

2040 lines
48 KiB
C

// Copyright 2007 Georgia Institute of Technology. All rights reserved.
/**
* @file fx.c
*
* Definitions for integration with the experiment-running system.
*/
#include "fx.h"
#include "datanode.h"
#include "stopwatch.h"
#include "fastlib/base/debug.h"
#include <stdarg.h>
#include <unistd.h>
#include <sys/resource.h>
#include <sys/time.h>
#include <sys/utsname.h>
#include <pthread.h>
/* TODO: Use this mutex where appropriate */
static pthread_mutex_t fx__mutex;
fx_module *fx_root = NULL;
char fx_mod_marker[] = "UMPQVPDRT";
const char *fx_mod_name[] = {
"unknown",
"submodule",
"parameter",
"required parameter",
"reserved parameter",
"provided parameter",
"default parameter",
"result",
"timer"
};
const char *fx_val_name[] = {
"string",
"double",
"int",
"bool",
"string list",
"double list",
"int list",
"bool list"
};
/* Long enough to store a double, long long, or bool as a string
* - doubles have 16 sig figs, as in: -X.XXXXXXXXXXXXXXXe-XXX
* - ints have at most 3 sig figs per byte; they need 2 more chars for
* sign and null, but have enough spare even if just 4 bytes
* - bools are strings "true" or "false"
*/
#define FX__BUF_SIZE (3 * (sizeof(long long) > 8 ? sizeof(long long) : 8))
const fx_entry_doc fx__fx_entries[] = {
{"load", FX_PARAM, FX_STR_LIST, NULL,
" Load files containing additional input parameters.\n"},
{"output", FX_PARAM, FX_STR, NULL,
" Output results to this file.\n"},
{"timing", FX_PARAM, FX_BOOL, NULL,
" Whether to attempt speed up for a timing run.\n"},
{"rusage", FX_PARAM, FX_BOOL, NULL,
" Whether to emit rusage data in \"info\".\n"},
{"silent", FX_PARAM, FX_BOOL, NULL,
" Whether to skip the printing of results to screen.\n"},
FX_ENTRY_DOC_DONE
};
const fx_module_doc fx__fx_doc = {
fx__fx_entries, NULL,
"Options for the FASTexec experiment-running system.\n"
};
const fx_entry_doc fx__debug_entries[] = {
{"verbosity_level", FX_PARAM, FX_DOUBLE, NULL,
" Controls the amount of debug info to print.\n"},
{"print_got_heres", FX_PARAM, FX_BOOL, NULL,
" Whether to print \"got here\" notices.\n"},
{"print_warnings", FX_PARAM, FX_BOOL, NULL,
" Whether to print warning messages.\n"},
{"abort_on_nonfatal", FX_PARAM, FX_BOOL, NULL,
" Whether to treat nonfatal errors as fatal.\n"},
{"pause_on_nonfatal", FX_PARAM, FX_BOOL, NULL,
" Whether to wait for user feedback on nonfatal errors.\n"},
{"print_notify_locs", FX_PARAM, FX_BOOL, NULL,
" Whether to print \"file:function:line:\" before notifications.\n"},
FX_ENTRY_DOC_DONE
};
const fx_module_doc fx__debug_doc = {
fx__debug_entries, NULL,
"Options for FASTlib's debugging features.\n"
};
const fx_entry_doc fx__rusage_entries[] = {
{"utime/sec", FX_RESULT, FX_INT, NULL,
" Seconds of computation in user-time.\n"},
{"utime/usec", FX_RESULT, FX_INT, NULL,
" Additional microseconds spent in user-time.\n"},
{"stime/sec", FX_RESULT, FX_INT, NULL,
" Seconds of computation in system-time.\n"},
{"stime/usec", FX_RESULT, FX_INT, NULL,
" Additional microseconds spent in system-time.\n"},
{"minflt", FX_RESULT, FX_INT, NULL,
" (See getrusage documentation.)\n"},
{"majflt", FX_RESULT, FX_INT, NULL,
" (See getrusage documentation.)\n"},
{"maxrss", FX_RESULT, FX_INT, NULL,
" (See getrusage documentation.)\n"},
{"ixrss", FX_RESULT, FX_INT, NULL,
" (See getrusage documentation.)\n"},
{"idrss", FX_RESULT, FX_INT, NULL,
" (See getrusage documentation.)\n"},
{"isrss", FX_RESULT, FX_INT, NULL,
" (See getrusage documentation.)\n"},
{"nswap", FX_RESULT, FX_INT, NULL,
" (See getrusage documentation.)\n"},
{"inblock", FX_RESULT, FX_INT, NULL,
" (See getrusage documentation.)\n"},
{"oublock", FX_RESULT, FX_INT, NULL,
" (See getrusage documentation.)\n"},
{"msgsnd", FX_RESULT, FX_INT, NULL,
" (See getrusage documentation.)\n"},
{"msgrcv", FX_RESULT, FX_INT, NULL,
" (See getrusage documentation.)\n"},
{"nsignals", FX_RESULT, FX_INT, NULL,
" (See getrusage documentation.)\n"},
{"nvcsw", FX_RESULT, FX_INT, NULL,
" (See getrusage documentation.)\n"},
{"nivcsw", FX_RESULT, FX_INT, NULL,
" (See getrusage documentation.)\n"},
FX_ENTRY_DOC_DONE
};
const fx_module_doc fx__rusage_doc = {
fx__rusage_entries, NULL,
"Resource usage information generated by getrusage.\n"
};
const fx_submodule_doc fx__info_submods[] = {
{"rusage/self", &fx__rusage_doc,
" Resources consumed by the experiment's main thread.\n"},
{"rusage/children", &fx__rusage_doc,
" Resources consumed by all child threads.\n"},
FX_SUBMODULE_DOC_DONE
};
const fx_entry_doc fx__info_entries[] = {
{"sys/node/name", FX_RESULT, FX_STR, NULL,
" The host computer of the experiment.\n"},
{"sys/arch/name", FX_RESULT, FX_STR, NULL,
" The host computer's architecture, i.e. 64-bit x86.\n"},
{"sys/kernel/name", FX_RESULT, FX_STR, NULL,
" The name of operating system.\n"},
{"sys/kernel/release", FX_RESULT, FX_STR, NULL,
" The version of the operating system.\n"},
{"sys/kernel/build", FX_RESULT, FX_STR, NULL,
" Further OS version details.\n"},
FX_ENTRY_DOC_DONE
};
const fx_module_doc fx__info_doc = {
fx__info_entries, fx__info_submods,
"Extraneous system details pertaining to an experiment.\n"
};
const fx_submodule_doc fx__std_submods[] = {
{"fx", &fx__fx_doc,
" Options for the FASTexec experiment-running system.\n"},
{"debug", &fx__debug_doc,
" Options for FASTlib's debugging feautres.\n"},
{"info", &fx__info_doc,
" Extraneous system details pertaining to an experiment.\n"},
FX_SUBMODULE_DOC_DONE
};
const fx_entry_doc fx__std_entries[] = {
{"help", FX_PARAM, FX_STR, NULL,
" Prints this information. Permits --help=path/to/submod.\n"},
{"total_time", FX_TIMER, FX_CUSTOM, NULL,
" The measured running time of the program.\n"},
FX_ENTRY_DOC_DONE
};
const fx_module_doc fx__std_doc = {
fx__std_entries, fx__std_submods,
"Standard FASTlib options:\n"
};
const fx_entry_doc fx__timer_entries[] = {
{"cycles", FX_TIMER, FX_INT, NULL, "text"},
{"real", FX_TIMER, FX_DOUBLE, NULL, "text"},
{"user", FX_TIMER, FX_DOUBLE, NULL, "text"},
{"sys", FX_TIMER, FX_DOUBLE, NULL, "text"},
FX_ENTRY_DOC_DONE
};
const fx_module_doc fx__timer_doc = {
fx__timer_entries, NULL, "text"
};
static void fx__write_path(fx_module *entry, FILE *stream)
{
if (entry->parent) {
fx__write_path(entry->parent, stream);
putc('/', stream);
}
fprintf(stream, entry->key);
}
COMPILER_NO_RETURN
static void fx__print_fatal_msg(const char *file, const char *func, int line,
const char *prefix, fx_module *entry,
const char *suffix, ...)
{
va_list vl;
fl_print_msg_header(fl_msg_marker[FL_MSG_FATAL],
fl_msg_color[FL_MSG_FATAL]);
fl_print_msg_loc(file, func, line);
va_start(vl, suffix);
vfprintf(stderr, prefix, vl);
fx__write_path(entry, stderr);
vfprintf(stderr, suffix, vl);
va_end(vl);
fprintf(stderr, "\n");
fl_abort();
}
static void fx__print_msg(const char *file, const char *func, int line,
fl_msg_t msg_type, const char *prefix,
fx_module *entry, const char *suffix, ...)
{
va_list vl;
fl_print_msg_header(fl_msg_marker[msg_type], fl_msg_color[msg_type]);
if (msg_type < FL_MSG_NOTIFY_STAR || print_notify_locs) {
fl_print_msg_loc(file, func, line);
}
va_start(vl, suffix);
vfprintf(stderr, prefix, vl);
fx__write_path(entry, stderr);
vfprintf(stderr, suffix, vl);
va_end(vl);
fprintf(stderr, "\n");
if (msg_type < FL_MSG_NOTIFY_STAR) {
if (msg_type == FL_MSG_FATAL || abort_on_nonfatal) {
fl_abort();
} else if (pause_on_nonfatal) {
fl_pause();
}
}
}
#define FX__FATAL(prefix, entry, msg_params...) \
fx__print_fatal_msg(__FILE__, __FUNCTION__, __LINE__, \
prefix, entry, msg_params)
#define FX__NONFATAL(prefix, entry, msg_params...) \
fx__print_msg(__FILE__, __FUNCTION__, __LINE__, \
FL_MSG_NONFATAL, prefix, entry, msg_params)
#define FX__SEMIFATAL(success, prefix, entry, msg_params...) \
if (!success) { \
FX__FATAL(prefix, entry, msg_params); \
} else if (!FAILED(*success)) { \
*success = SUCCESS_FAIL; \
FX__NONFATAL(prefix, entry, msg_params); \
} else NOP
int fx_module_is_type(fx_module *entry, fx_mod_t mod_type)
{
if (mod_type >= FX_RESERVED) { /* Types without subtypes */
return entry->mod_type == mod_type;
} else if (mod_type >= FX_PARAM) { /* (Required) parameters */
return entry->mod_type >= mod_type && entry->mod_type < FX_TIMER;
} else { /* Modules and unknowns */
return entry->mod_type >= mod_type;
}
}
static success_t fx__check_mod_type(const char *header, fx_mod_t mod_type,
fx_module *entry)
{
if (unlikely(!fx_module_is_type(entry, mod_type))) {
if (entry->mod_type < FX_PARAM) {
FX__NONFATAL("%s %s \"", entry, "\" is not documented.",
header, fx_mod_name[mod_type]);
return SUCCESS_WARN;
} else {
FX__NONFATAL("%s %s \"", entry, "\" is documented as a %s.",
header, fx_mod_name[mod_type], fx_mod_name[entry->mod_type]);
return SUCCESS_FAIL;
}
}
return SUCCESS_PASS;
}
static success_t fx__check_val_type(const char *header, fx_val_t val_type,
fx_module *entry)
{
if (unlikely(entry->val_type != val_type)) {
if (entry->val_type < 0) {
FX__NONFATAL("%s %s \"", entry, "\" is of custom type.",
header, fx_val_name[val_type]);
return SUCCESS_FAIL;
} else {
FX__NONFATAL("%s %s \"", entry, "\" is of type %s.",
header, fx_val_name[val_type], fx_val_name[entry->val_type]);
return SUCCESS_WARN;
}
}
return SUCCESS_PASS;
}
static double fx__scan_double_impl(fx_module *entry, const char *val,
success_t *success_ptr, int list)
{
double retval = 0.0;
if (unlikely(sscanf(val, "%lf", &retval) != 1)) {
FX__SEMIFATAL(success_ptr,
"%c%s \"", entry, "\" is not a double%s: \"%s\".",
toupper(*fx_mod_name[entry->mod_type]),
fx_mod_name[entry->mod_type] + 1,
list ? " list" : "", entry->val);
}
return retval;
}
static long long fx__scan_int_impl(fx_module *entry, const char *val,
success_t *success_ptr, int list)
{
long long retval = 0;
if (sscanf(val, "%lld", &retval) != 1) {
FX__SEMIFATAL(success_ptr,
"%c%s \"", entry, "\" is not an int%s: \"%s\".",
toupper(*fx_mod_name[entry->mod_type]),
fx_mod_name[entry->mod_type] + 1,
list ? " list" : "", entry->val);
}
return retval;
}
static int fx__scan_bool_impl(fx_module *entry, const char *val,
success_t *success_ptr, int list)
{
int retval = 0;
if (strchr("1tTyY", val[0])) {
retval = 1;
} else if (!strchr("0fFnN", val[0])) {
FX__SEMIFATAL(success_ptr,
"%c%s \"", entry, "\" is not a bool%s: \"%s\".",
toupper(*fx_mod_name[entry->mod_type]),
fx_mod_name[entry->mod_type] + 1,
list ? " list" : "", entry->val);
}
return retval;
}
static double fx__scan_double(fx_module *entry)
{
return fx__scan_double_impl(entry, entry->val, NULL, 0);
}
static long long fx__scan_int(fx_module *entry)
{
return fx__scan_int_impl(entry, entry->val, NULL, 0);
}
static int fx__scan_bool(fx_module *entry)
{
return fx__scan_bool_impl(entry, entry->val, NULL, 0);
}
static const size_t fx__list_size(fx_module *entry, size_t req_size,
success_t *success_ptr)
{
char *val = entry->val;
size_t count = 1;
while ((val = strchr(val, ','))) {
++count;
++val;
}
if (req_size && count != req_size) {
FX__SEMIFATAL(success_ptr,
"%c%s \"", entry, "\" is not of length %d: \"%s\".",
toupper(*fx_mod_name[entry->mod_type]),
fx_mod_name[entry->mod_type] + 1,
req_size, entry->val);
}
return count;
}
static const char **fx__scan_str_list(fx_module *mod, size_t *size_ptr,
success_t *success_ptr)
{
char **retval;
char **elem;
char *str;
size_t len = strlen(mod->val);
size_t count = fx__list_size(mod, *size_ptr, success_ptr);
/* Allocate space for string, elements, and array */
mod->val = realloc(mod->val,
stride_align(2 * len + 2, char *) + count * sizeof(char *));
retval = (char **)(mod->val + stride_align(2 * len + 2, char *));
*size_ptr = count;
/* Copy string to form elements; simulate "leading comma" */
str = mod->val + len;
strcpy(str + 1, mod->val);
/* Demark elements and add to array */
elem = retval;
do {
*str++ = '\0';
*elem++ = str;
} while ((str = strchr(str, ',')));
/* Parse escaped characters */
while (elem-- > retval) {
unhex_in_place(*elem);
}
return (const char **)retval;
}
static double *fx__scan_double_list(fx_module *mod, size_t *size_ptr,
success_t *success_ptr)
{
double *retval;
double *elem;
const char *str;
size_t len = strlen(mod->val);
size_t count = fx__list_size(mod, *size_ptr, success_ptr);
/* Allocate space for string and array */
mod->val = realloc(mod->val,
stride_align(len + 1, double) + count * sizeof(double));
retval = (double *)(mod->val + stride_align(len + 1, double));
*size_ptr = count;
/* Backstep once to simulate "leading comma" */
str = mod->val - 1;
/* Fill the array */
elem = retval;
do {
*elem++ = fx__scan_double_impl(mod, ++str, success_ptr, 1);
} while ((str = strchr(str, ',')));
return retval;
}
static long long *fx__scan_int_list(fx_module *mod, size_t *size_ptr,
success_t *success_ptr)
{
long long *retval;
long long *elem;
const char *str;
size_t len = strlen(mod->val);
size_t count = fx__list_size(mod, *size_ptr, success_ptr);
/* Allocate space for string and array */
mod->val = realloc(mod->val,
stride_align(len + 1, long long) + count * sizeof(long long));
retval = (long long *)(mod->val + stride_align(len + 1, long long));
*size_ptr = count;
/* Backstep once to simulate "leading comma" */
str = mod->val - 1;
/* Fill the array */
elem = retval;
do {
*elem++ = fx__scan_int_impl(mod, ++str, success_ptr, 1);
} while ((str = strchr(str, ',')));
return retval;
}
static int *fx__scan_bool_list(fx_module *mod, size_t *size_ptr,
success_t *success_ptr)
{
int *retval;
int *elem;
const char *str;
size_t len = strlen(mod->val);
size_t count = fx__list_size(mod, *size_ptr, success_ptr);
/* Allocate space for string and array */
mod->val = realloc(mod->val,
stride_align(len + 1, int) + count * sizeof(int));
retval = (int *)(mod->val + stride_align(len + 1, int));
*size_ptr = count;
/* Backstep once to simulate "leading comma" */
str = mod->val - 1;
/* Fill the array */
elem = retval;
do {
*elem++ = fx__scan_bool_impl(mod, ++str, success_ptr, 1);
} while ((str = strchr(str, ',')));
return retval;
}
static char *fx__alloc_double(double val)
{
char *retval = malloc(FX__BUF_SIZE * sizeof(char));
sprintf(retval, "%.16g", val);
return retval;
}
static char *fx__alloc_int(long long val)
{
char *retval = malloc(FX__BUF_SIZE * sizeof(char));
sprintf(retval, "%lld", val);
return retval;
}
static char *fx__alloc_bool(int val)
{
return strdup(val ? "t" : "f");
}
static char *fx__alloc_str_list(size_t size, va_list vl)
{
if (size == 0) {
return strdup("");
} else {
va_list vl_temp;
char *retval;
char *str;
size_t len;
size_t i;
va_copy(vl_temp, vl);
len = 0;
for (i = 0; i < size; ++i) {
len += strlen(va_arg(vl_temp, const char *));
}
va_end(vl_temp);
retval = malloc((3 * len + size) * sizeof(char));
str = hex_to_string(retval, va_arg(vl, const char *), "_.-+");
while (--size) {
*str++ = ',';
str = hex_to_string(str, va_arg(vl, const char *), "_.-+");
}
return retval;
}
}
static char *fx__alloc_double_list(size_t size, va_list vl)
{
if (size == 0) {
return strdup("");
} else {
char *retval = malloc(size * FX__BUF_SIZE * sizeof(char));
char *str = retval;
str += sprintf(str, "%.16g", va_arg(vl, double));
while (--size) {
str += sprintf(str, ",%.16g", va_arg(vl, double));
}
return retval;
}
}
static char *fx__alloc_int_list(size_t size, va_list vl)
{
if (size == 0) {
return strdup("");
} else {
char *retval = malloc(size * FX__BUF_SIZE * sizeof(char));
char *str = retval;
str += sprintf(str, "%lld", va_arg(vl, long long));
while (--size) {
str += sprintf(str, ",%lld", va_arg(vl, long long));
}
return retval;
}
}
static char *fx__alloc_bool_list(size_t size, va_list vl)
{
if (size == 0) {
return strdup("");
} else {
char *retval = malloc(size * 2 * sizeof(char));
char *str = retval;
*str++ = va_arg(vl, int) ? 't' : 'f';
while (--size) {
*str++ = ',';
*str++ = va_arg(vl, int) ? 't' : 'f';
}
*str = '\0';
return retval;
}
}
static char *fx__alloc_str_array(size_t size, const char *const *list)
{
if (size == 0) {
return strdup("");
} else {
char *retval;
char *str;
size_t len;
size_t i;
len = 0;
for (i = 0; i < size; ++i) {
len += strlen(list[i]);
}
retval = malloc((3 * len + size) * sizeof(char));
str = hex_to_string(retval, *list++, "_.-+");
while (--size) {
*str++ = ',';
str = hex_to_string(str, *list++, "_.-+");
}
return retval;
}
}
static char *fx__alloc_double_array(size_t size, const double *list)
{
if (size == 0) {
return strdup("");
} else {
char *retval = malloc(size * FX__BUF_SIZE * sizeof(char));
char *str = retval;
str += sprintf(str, "%.16g", *list++);
while (--size) {
str += sprintf(str, ",%.16g", *list++);
}
return retval;
}
}
static char *fx__alloc_int_array(size_t size, const long long *list)
{
if (size == 0) {
return strdup("");
} else {
char *retval = malloc(size * FX__BUF_SIZE * sizeof(char));
char *str = retval;
str += sprintf(str, "%lld", *list++);
while (--size) {
str += sprintf(str, ",%lld", *list++);
}
return retval;
}
}
static char *fx__alloc_bool_array(size_t size, const int *list)
{
if (size == 0) {
return strdup("");
} else {
char *retval = malloc(size * 2 * sizeof(char));
char *str = retval;
*str++ = *list++ ? 't' : 'f';
while (--size) {
*str++ = ',';
*str++ = *list++ ? 't' : 'f';
}
*str = '\0';
return retval;
}
}
static char *fx__alloc_format(const char *format, va_list vl)
{
va_list vl_temp;
char *retval;
size_t len;
va_copy(vl_temp, vl);
len = vsnprintf(NULL, 0, format, vl_temp);
va_end(vl_temp);
retval = malloc((len + 1) * sizeof(char));
vsprintf(retval, format, vl);
return retval;
}
static char *fx__alloc_format_list(size_t size, va_list vl)
{
if (size == 0) {
return strdup("");
} else {
va_list vl_temp;
char *retval;
char *str;
char *temp;
size_t len;
size_t i;
va_copy(vl_temp, vl);
len = 0;
for (i = 0; i < size; ++i) {
len += vsnprintf(NULL, 0, va_arg(vl_temp, const char *), vl_temp);
}
va_end(vl_temp);
retval = malloc((4 * len + size + 1) * sizeof(char));
temp = retval + 3 * len + size;
vsprintf(temp, va_arg(vl, const char *), vl);
str = hex_to_string(retval, temp, "_.-+");
while (--size) {
*str++ = ',';
vsprintf(temp, va_arg(vl, const char *), vl);
str = hex_to_string(retval, temp, "_.-+");
}
return retval;
}
}
static fx_module *fx__lookup(fx_module *mod, const char *key)
{
return datanode_lookup(mod ? mod : fx_root, key, 1);
}
static void fx__check_lookup(fx_mod_t mod_type, fx_val_t val_type,
fx_module *entry)
{
if (PASSED(fx__check_mod_type("Requested", mod_type, entry))) {
fx__check_val_type("Requested", val_type, entry);
}
}
static fx_module *fx__get_entry(fx_module *mod, const char *key,
fx_mod_t mod_type, fx_val_t val_type)
{
fx_module *retval = fx__lookup(mod, key);
DEBUG_ONLY(fx__check_lookup(mod_type, val_type, retval));
return retval;
}
static fx_module *fx__param(fx_module *mod, const char *key,
fx_val_t val_type)
{
fx_module *retval = fx__get_entry(mod, key, FX_PARAM, val_type);
if (retval->mod_type == FX_PARAM) {
if (retval->val) {
retval->mod_type = FX_PROVIDED;
} else {
retval->mod_type = FX_DEFAULT;
}
}
return retval;
}
static fx_module *fx__param_req(fx_module *mod, const char *key,
fx_val_t val_type)
{
fx_module *retval = fx__get_entry(mod, key, FX_REQUIRED, val_type);
if (!retval->val) {
FX__FATAL("Required parameter \"", retval, "\" is unspecified.");
}
return retval;
}
const char *fx_param_str_req(fx_module *mod, const char *key)
{
return fx__param_req(mod, key, FX_STR)->val;
}
double fx_param_double_req(fx_module *mod, const char *key)
{
return fx__scan_double(fx__param_req(mod, key, FX_DOUBLE));
}
long long fx_param_int_req(fx_module *mod, const char *key)
{
return fx__scan_int(fx__param_req(mod, key, FX_INT));
}
int fx_param_bool_req(fx_module *mod, const char *key)
{
return fx__scan_bool(fx__param_req(mod, key, FX_BOOL));
}
const char **fx_param_str_list_req(fx_module *mod, const char *key,
size_t *size_ptr)
{
fx_module *param = fx__param_req(mod, key, FX_STR_LIST);
return fx__scan_str_list(param, size_ptr, NULL);
}
double *fx_param_double_list_req(fx_module *mod, const char *key,
size_t *size_ptr)
{
fx_module *param = fx__param_req(mod, key, FX_DOUBLE_LIST);
return fx__scan_double_list(param, size_ptr, NULL);
}
long long *fx_param_int_list_req(fx_module *mod, const char *key,
size_t *size_ptr)
{
fx_module *param = fx__param_req(mod, key, FX_INT_LIST);
return fx__scan_int_list(param, size_ptr, NULL);
}
int *fx_param_bool_list_req(fx_module *mod, const char *key,
size_t *size_ptr)
{
fx_module *param = fx__param_req(mod, key, FX_BOOL_LIST);
return fx__scan_bool_list(param, size_ptr, NULL);
}
const char *fx_param_str(fx_module *mod, const char *key, const char *def)
{
fx_module *param = fx__param(mod, key, FX_STR);
if (!param->val) {
param->val = strdup(def);
}
return param->val;
}
double fx_param_double(fx_module *mod, const char *key, double def)
{
fx_module *param = fx__param(mod, key, FX_DOUBLE);
if (!param->val) {
param->val = fx__alloc_double(def);
} else {
def = fx__scan_double(param);
}
return def;
}
long long fx_param_int(fx_module *mod, const char *key, long long def)
{
fx_module *param = fx__param(mod, key, FX_INT);
if (!param->val) {
param->val = fx__alloc_int(def);
} else {
def = fx__scan_int(param);
}
return def;
}
int fx_param_bool(fx_module *mod, const char *key, int def)
{
fx_module *param = fx__param(mod, key, FX_BOOL);
if (!param->val) {
param->val = fx__alloc_bool(def);
} else {
def = fx__scan_bool(param);
}
return def;
}
const char **fx_param_str_list(fx_module *mod, const char *key,
size_t *size_ptr, size_t def_size, ...)
{
fx_module *param = fx__param(mod, key, FX_STR_LIST);
if (!param->val) {
va_list vl;
va_start(vl, def_size);
param->val = fx__alloc_str_list(def_size, vl);
va_end(vl);
}
return fx__scan_str_list(param, size_ptr, NULL);
}
double *fx_param_double_list(fx_module *mod, const char *key,
size_t *size_ptr, size_t def_size, ...)
{
fx_module *param = fx__param(mod, key, FX_DOUBLE_LIST);
if (!param->val) {
va_list vl;
va_start(vl, def_size);
param->val = fx__alloc_double_list(def_size, vl);
va_end(vl);
}
return fx__scan_double_list(param, size_ptr, NULL);
}
long long *fx_param_int_list(fx_module *mod, const char *key,
size_t *size_ptr, size_t def_size, ...)
{
fx_module *param = fx__param(mod, key, FX_INT_LIST);
if (!param->val) {
va_list vl;
va_start(vl, def_size);
param->val = fx__alloc_int_list(def_size, vl);
va_end(vl);
}
return fx__scan_int_list(param, size_ptr, NULL);
}
int *fx_param_bool_list(fx_module *mod, const char *key,
size_t *size_ptr, size_t def_size, ...)
{
fx_module *param = fx__param(mod, key, FX_BOOL_LIST);
if (!param->val) {
va_list vl;
va_start(vl, def_size);
param->val = fx__alloc_bool_list(def_size, vl);
va_end(vl);
}
return fx__scan_bool_list(param, size_ptr, NULL);
}
const char **fx_param_str_array(fx_module *mod, const char *key,
size_t *size_ptr, size_t def_size,
const char *const *def_array)
{
fx_module *param = fx__param(mod, key, FX_STR_LIST);
if (!param->val) {
param->val = fx__alloc_str_array(def_size, def_array);
}
return fx__scan_str_list(param, size_ptr, NULL);
}
double *fx_param_double_array(fx_module *mod, const char *key,
size_t *size_ptr, size_t def_size,
const double *def_array)
{
fx_module *param = fx__param(mod, key, FX_DOUBLE_LIST);
if (!param->val) {
param->val = fx__alloc_double_array(def_size, def_array);
}
return fx__scan_double_list(param, size_ptr, NULL);
}
long long *fx_param_int_array(fx_module *mod, const char *key,
size_t *size_ptr, size_t def_size,
const long long *def_array)
{
fx_module *param = fx__param(mod, key, FX_INT_LIST);
if (!param->val) {
param->val = fx__alloc_int_array(def_size, def_array);
}
return fx__scan_int_list(param, size_ptr, NULL);
}
int *fx_param_bool_array(fx_module *mod, const char *key,
size_t *size_ptr, size_t def_size,
const int *def_array)
{
fx_module *param = fx__param(mod, key, FX_BOOL_LIST);
if (!param->val) {
param->val = fx__alloc_bool_array(def_size, def_array);
}
return fx__scan_bool_list(param, size_ptr, NULL);
}
void fx_set_param_str(fx_module *mod, const char *key, const char *val)
{
fx_module *param = fx__get_entry(mod, key, FX_RESERVED, FX_STR);
free(param->val);
param->val = strdup(val);
}
void fx_set_param_double(fx_module *mod, const char *key, double val)
{
fx_module *param = fx__get_entry(mod, key, FX_RESERVED, FX_DOUBLE);
free(param->val);
param->val = fx__alloc_double(val);
}
void fx_set_param_int(fx_module *mod, const char *key, long long val)
{
fx_module *param = fx__get_entry(mod, key, FX_RESERVED, FX_INT);
free(param->val);
param->val = fx__alloc_int(val);
}
void fx_set_param_bool(fx_module *mod, const char *key, int val)
{
fx_module *param = fx__get_entry(mod, key, FX_RESERVED, FX_BOOL);
free(param->val);
param->val = fx__alloc_bool(val);
}
void fx_set_param_str_list(fx_module *mod, const char *key,
size_t size, ...)
{
va_list vl;
fx_module *param = fx__get_entry(mod, key, FX_RESERVED, FX_STR_LIST);
va_start(vl, size);
free(param->val);
param->val = fx__alloc_str_list(size, vl);
va_end(vl);
}
void fx_set_param_double_list(fx_module *mod, const char *key,
size_t size, ...)
{
va_list vl;
fx_module *param = fx__get_entry(mod, key, FX_RESERVED, FX_DOUBLE_LIST);
va_start(vl, size);
free(param->val);
param->val = fx__alloc_double_list(size, vl);
va_end(vl);
}
void fx_set_param_int_list(fx_module *mod, const char *key,
size_t size, ...)
{
va_list vl;
fx_module *param = fx__get_entry(mod, key, FX_RESERVED, FX_INT_LIST);
va_start(vl, size);
free(param->val);
param->val = fx__alloc_int_list(size, vl);
va_end(vl);
}
void fx_set_param_bool_list(fx_module *mod, const char *key,
size_t size, ...)
{
va_list vl;
fx_module *param = fx__get_entry(mod, key, FX_RESERVED, FX_BOOL_LIST);
va_start(vl, size);
free(param->val);
param->val = fx__alloc_bool_list(size, vl);
va_end(vl);
}
void fx_set_param_str_array(fx_module *mod, const char *key,
size_t size, const char *const *array)
{
fx_module *param = fx__get_entry(mod, key, FX_RESERVED, FX_STR_LIST);
free(param->val);
param->val = fx__alloc_str_array(size, array);
}
void fx_set_param_double_array(fx_module *mod, const char *key,
size_t size, const double *array)
{
fx_module *param = fx__get_entry(mod, key, FX_RESERVED, FX_DOUBLE_LIST);
free(param->val);
param->val = fx__alloc_double_array(size, array);
}
void fx_set_param_int_array(fx_module *mod, const char *key,
size_t size, const long long *array)
{
fx_module *param = fx__get_entry(mod, key, FX_RESERVED, FX_INT_LIST);
free(param->val);
param->val = fx__alloc_int_array(size, array);
}
void fx_set_param_bool_array(fx_module *mod, const char *key,
size_t size, const int *array)
{
fx_module *param = fx__get_entry(mod, key, FX_RESERVED, FX_BOOL_LIST);
free(param->val);
param->val = fx__alloc_bool_array(size, array);
}
void fx_default_param(fx_module *mod, const char *key,
const char *def_format, ...)
{
fx_module *param = fx__param(mod, key, FX_STR);
if (!param->val) {
va_list vl;
va_start(vl, def_format);
param->val = fx__alloc_format(def_format, vl);
va_end(vl);
}
}
void fx_default_param_list(fx_module *mod, const char *key,
size_t *size_ptr, size_t def_size, ...)
{
fx_module *param = fx__param(mod, key, FX_STR_LIST);
if (!param->val) {
va_list vl;
va_start(vl, def_size);
param->val = fx__alloc_format_list(def_size, vl);
va_end(vl);
}
}
void fx_format_param(fx_module *mod, const char *key,
const char *format, ...)
{
va_list vl;
fx_module *param = fx__get_entry(mod, key, FX_RESERVED, FX_STR);
va_start(vl, format);
free(param->val);
param->val = fx__alloc_format(format, vl);
va_end(vl);
}
void fx_format_param_list(fx_module *mod, const char *key,
size_t size, ...)
{
va_list vl;
fx_module *param = fx__get_entry(mod, key, FX_RESERVED, FX_STR_LIST);
va_start(vl, size);
free(param->val);
param->val = fx__alloc_format_list(size, vl);
va_end(vl);
}
void fx_clear_param(fx_module *mod, const char *key)
{
fx_module *param = fx__lookup(mod, key);
DEBUG_ONLY(fx__check_mod_type("Requested", FX_RESERVED, param));
free(param->val);
param->val = NULL;
}
int fx_param_exists(fx_module *mod, const char *key)
{
fx_module *param = fx__lookup(mod, key);
DEBUG_ONLY(fx__check_mod_type("Requested", FX_PARAM, param));
if (param->mod_type == FX_PARAM) {
if (param->val) {
param->mod_type = FX_PROVIDED;
}
}
return param->val != 0;
}
static fx_module *fx__get_result(fx_module *mod, const char *key,
fx_val_t val_type)
{
fx_module *retval = fx__get_entry(mod, key, FX_RESULT, val_type);
if (!retval->val) {
FX__FATAL("Accessed result \"", retval, "\" is unspecified.");
}
return retval;
}
const char *fx_get_result_str(fx_module *mod, const char *key)
{
return fx__get_result(mod, key, FX_STR)->val;
}
double fx_get_result_double(fx_module *mod, const char *key)
{
return fx__scan_double(fx__get_result(mod, key, FX_DOUBLE));
}
long long fx_get_result_int(fx_module *mod, const char *key)
{
return fx__scan_int(fx__get_result(mod, key, FX_INT));
}
int fx_get_result_bool(fx_module *mod, const char *key)
{
return fx__scan_bool(fx__get_result(mod, key, FX_BOOL));
}
const char **fx_get_result_str_list(fx_module *mod, const char *key,
size_t *size_ptr)
{
fx_module *result = fx__get_result(mod, key, FX_STR_LIST);
return fx__scan_str_list(result, size_ptr, NULL);
}
double *fx_get_result_double_list(fx_module *mod, const char *key,
size_t *size_ptr)
{
fx_module *result = fx__get_result(mod, key, FX_DOUBLE_LIST);
return fx__scan_double_list(result, size_ptr, NULL);
}
long long *fx_get_result_int_list(fx_module *mod, const char *key,
size_t *size_ptr)
{
fx_module *result = fx__get_result(mod, key, FX_INT_LIST);
return fx__scan_int_list(result, size_ptr, NULL);
}
int *fx_get_result_bool_list(fx_module *mod, const char *key,
size_t *size_ptr)
{
fx_module *result = fx__get_result(mod, key, FX_BOOL_LIST);
return fx__scan_bool_list(result, size_ptr, NULL);
}
void fx_result_str(fx_module *mod, const char *key, const char *val)
{
fx_module *result = fx__get_entry(mod, key, FX_RESULT, FX_STR);
free(result->val);
result->val = strdup(val);
}
void fx_result_double(fx_module *mod, const char *key, double val)
{
fx_module *result = fx__get_entry(mod, key, FX_RESULT, FX_DOUBLE);
free(result->val);
result->val = fx__alloc_double(val);
}
void fx_result_int(fx_module *mod, const char *key, long long val)
{
fx_module *result = fx__get_entry(mod, key, FX_RESULT, FX_INT);
free(result->val);
result->val = fx__alloc_int(val);
}
void fx_result_bool(fx_module *mod, const char *key, int val)
{
fx_module *result = fx__get_entry(mod, key, FX_RESULT, FX_BOOL);
free(result->val);
result->val = fx__alloc_bool(val);
}
void fx_result_str_list(fx_module *mod, const char *key,
size_t size, ...)
{
va_list vl;
fx_module *result = fx__get_entry(mod, key, FX_RESULT, FX_STR_LIST);
va_start(vl, size);
free(result->val);
result->val = fx__alloc_str_list(size, vl);
va_end(vl);
}
void fx_result_double_list(fx_module *mod, const char *key,
size_t size, ...)
{
va_list vl;
fx_module *result = fx__get_entry(mod, key, FX_RESULT, FX_DOUBLE_LIST);
va_start(vl, size);
free(result->val);
result->val = fx__alloc_double_list(size, vl);
va_end(vl);
}
void fx_result_int_list(fx_module *mod, const char *key,
size_t size, ...)
{
va_list vl;
fx_module *result = fx__get_entry(mod, key, FX_RESULT, FX_INT_LIST);
va_start(vl, size);
free(result->val);
result->val = fx__alloc_int_list(size, vl);
va_end(vl);
}
void fx_result_bool_list(fx_module *mod, const char *key,
size_t size, ...)
{
va_list vl;
fx_module *result = fx__get_entry(mod, key, FX_RESULT, FX_BOOL_LIST);
va_start(vl, size);
free(result->val);
result->val = fx__alloc_bool_list(size, vl);
va_end(vl);
}
void fx_result_str_array(fx_module *mod, const char *key,
size_t size, const char *const *array)
{
fx_module *result = fx__get_entry(mod, key, FX_RESULT, FX_STR_LIST);
free(result->val);
result->val = fx__alloc_str_array(size, array);
}
void fx_result_double_array(fx_module *mod, const char *key,
size_t size, const double *array)
{
fx_module *result = fx__get_entry(mod, key, FX_RESULT, FX_DOUBLE_LIST);
free(result->val);
result->val = fx__alloc_double_array(size, array);
}
void fx_result_int_array(fx_module *mod, const char *key,
size_t size, const long long *array)
{
fx_module *result = fx__get_entry(mod, key, FX_RESULT, FX_INT_LIST);
free(result->val);
result->val = fx__alloc_int_array(size, array);
}
void fx_result_bool_array(fx_module *mod, const char *key,
size_t size, const int *array)
{
fx_module *result = fx__get_entry(mod, key, FX_RESULT, FX_BOOL_LIST);
free(result->val);
result->val = fx__alloc_bool_array(size, array);
}
void fx_format_result(fx_module *mod, const char *key,
const char *format, ...)
{
va_list vl;
fx_module *result = fx__get_entry(mod, key, FX_RESULT, FX_STR);
va_start(vl, format);
free(result->val);
result->val = fx__alloc_format(format, vl);
va_end(vl);
}
void fx_format_result_list(fx_module *mod, const char *key,
size_t size, ...)
{
va_list vl;
fx_module *result = fx__get_entry(mod, key, FX_RESULT, FX_STR_LIST);
va_start(vl, size);
free(result->val);
result->val = fx__alloc_format_list(size, vl);
va_end(vl);
}
void fx_clear_result(fx_module *mod, const char *key)
{
fx_module *result = fx__lookup(mod, key);
DEBUG_ONLY(fx__check_mod_type("Requested", FX_RESULT, result));
free(result->val);
result->val = NULL;
}
int fx_result_exists(fx_module *mod, const char *key)
{
fx_module *result = fx__lookup(mod, key);
DEBUG_ONLY(fx__check_mod_type("Requested", FX_RESULT, result));
return result->val != NULL;
}
fx_timer *fx_get_timer(fx_module *mod, const char *key) {
fx_module *timer = fx__lookup(mod, key);
DEBUG_ONLY(fx__check_mod_type("Requested", FX_TIMER, timer));
if (!timer->val) {
timer->mod_type = FX_TIMER;
timer->val_type = FX_CUSTOM;
timer->val = malloc(sizeof(fx_timer));
stopwatch_init((fx_timer *)timer->val);
}
return (fx_timer *)timer->val;
}
void fx_timer_start(fx_module *mod, const char *key)
{
stopwatch_start(fx_get_timer(mod, key));
}
void fx_timer_stop(fx_module *mod, const char *key)
{
struct timestamp now;
timestamp_now(&now);
stopwatch_stop(fx_get_timer(mod, key), &now);
}
void fx_reset_timer(fx_module *mod, const char *key)
{
stopwatch_init(fx_get_timer(mod, key));
}
fx_module *fx_submodule(fx_module *mod, const char *key)
{
fx_module *submod = fx__lookup(mod, key);
DEBUG_ONLY(fx__check_mod_type("Requested", FX_MODULE, submod));
return submod;
}
fx_module *fx_copy_module(fx_module *mod, const char *src_key,
const char *dest_format, ...)
{
va_list vl;
char *dest_key;
fx_module *dest_mod;
va_start(vl, dest_format);
dest_key = fx__alloc_format(dest_format, vl);
va_end(vl);
dest_mod = fx__lookup(mod, dest_key);
if (src_key) {
datanode_copy(dest_mod, fx__lookup(mod, src_key), 1);
if (fx_module_is_type(dest_mod, FX_MODULE)) {
fx_module *parent = dest_mod;
while ((parent = parent->parent) && parent->mod_type == FX_UNKNOWN) {
parent->mod_type = FX_MODULE;
}
}
}
DEBUG_ONLY(fx__check_mod_type("Requested", FX_MODULE, dest_mod));
free(dest_key);
return dest_mod;
}
static const char *fx__match_prefix(const char *key, const char *prefix)
{
for (; *key == '/'; ++key);
for (; *prefix == '/'; ++prefix);
while (*prefix) {
const char *slash = strchr(prefix, '/');
size_t len = slash ? slash - prefix : strlen(prefix);
if (strncmp(key, prefix, len) == 0
&& (key[len] == '\0' || key[len] == '/')) {
for (key += len; *key == '/'; ++key);
for (prefix += len; *prefix == '/'; ++prefix);
} else {
return NULL;
}
}
return key;
}
success_t fx_help(const fx_module_doc *doc, const char *key)
{
success_t retval = SUCCESS_WARN;
for (; *key == '/'; ++key);
if (*key == '\0') {
retval = SUCCESS_PASS;
printf("%s\n", doc->text);
}
if (doc->entries) {
const fx_entry_doc *entry_doc;
if (*key == '\0') {
printf("Entries:\n");
}
for (entry_doc = doc->entries; entry_doc->key; ++entry_doc) {
if (entry_doc->text) {
if (fx__match_prefix(entry_doc->key, key)) {
retval = SUCCESS_PASS;
if (entry_doc->val_type < 0) {
printf("\"%s\", %s:\n", entry_doc->key,
fx_mod_name[entry_doc->mod_type]);
} else {
printf("\"%s\", %s (%s):\n", entry_doc->key,
fx_mod_name[entry_doc->mod_type],
fx_val_name[entry_doc->val_type]);
}
printf("%s\n", entry_doc->text);
}
}
}
}
if (doc->submodules) {
const fx_submodule_doc *submod_doc;
if (*key == '\0') {
printf("Submodules:\n");
}
for (submod_doc = doc->submodules; submod_doc->key; ++submod_doc) {
const char *match = fx__match_prefix(key, submod_doc->key);
if (match) {
retval |= fx_help(submod_doc->doc, match);
} else if (submod_doc->text) {
if (fx__match_prefix(submod_doc->key, key)) {
retval = SUCCESS_PASS;
printf("\"%s\":\n%s\n", submod_doc->key, submod_doc->text);
}
}
}
}
return retval;
}
COMPILER_NO_RETURN
static void fx__std_help(const char *prog, const char *help,
const fx_module_doc *doc)
{
success_t success;
printf("%s --help%c%s\n\n", prog, *help ? '=' : ' ', help);
if (doc) {
success = fx_help(doc, help);
} else {
NONFATAL("Program \"%s\" is not documented.\n", prog);
success = SUCCESS_WARN;
}
success |= fx_help(&fx__std_doc, help);
if (!PASSED(success)) {
NONFATAL("No documentation available for \"%s\".\n", help);
}
exit(1);
}
static void fx__fill_docs(fx_module *mod, const fx_module_doc *doc)
{
if (mod->mod_type == FX_UNKNOWN) {
mod->mod_type = FX_MODULE;
}
if (doc->submodules) {
const fx_submodule_doc *submod_doc;
for (submod_doc = doc->submodules; submod_doc->key; ++submod_doc) {
fx_module *submod = datanode_lookup(mod, submod_doc->key, 1);
fx__fill_docs(submod, submod_doc->doc);
while ((submod = submod->parent) && submod->mod_type == FX_UNKNOWN) {
submod->mod_type = FX_MODULE;
}
}
}
if (doc->entries) {
const fx_entry_doc *entry_doc;
for (entry_doc = doc->entries; entry_doc->key; ++entry_doc) {
fx_module *entry = datanode_lookup(mod, entry_doc->key, 1);
DEBUG_ASSERT(entry_doc->mod_type != FX_UNKNOWN);
DEBUG_ASSERT(entry_doc->mod_type != FX_PROVIDED);
DEBUG_ASSERT(entry_doc->mod_type != FX_DEFAULT);
DEBUG_ASSERT(entry_doc->mod_type != FX_PARAM
|| entry_doc->val_type != FX_CUSTOM);
entry->mod_type = entry_doc->mod_type;
entry->val_type = entry_doc->val_type;
entry->meta = entry_doc->meta;
while ((entry = entry->parent) && entry->mod_type == FX_UNKNOWN) {
entry->mod_type = FX_MODULE;
}
}
}
}
static void fx__parse_cmd_line(fx_module *root, int argc, char *argv[])
{
int i;
for (i = 0; i < argc; ++i) {
if (argv[i][0] != '-' || argv[i][1] != '-') {
NONFATAL("Ignoring argument missing \"--\": \"%s\".", argv[i]);
} else {
char *arg = strdup(argv[i] + 2);
char *val = strchr(arg, '=');
fx_module *entry;
if (val) {
*val++ = '\0';
unhex_in_place(val);
} else {
val = "";
}
unhex_in_place(arg);
entry = datanode_lookup_expert(root, arg, 1);
if (entry->val) {
FX__NONFATAL("Repeated \"--", entry, "=%s\" overwriting \"%s\".",
val, entry->val);
free(entry->val);
}
entry->val = strdup(val);
free(arg);
}
}
}
static void fx__load_param_files(fx_module *root)
{
size_t size = 0;
const char **load = fx_param_str_list_req(root, "fx/load", &size);
while (size--) {
FILE *stream = fopen(*load++, "r");
datanode_read(root, stream, NULL, 0);
fclose(stream);
}
}
static success_t fx__check_param(fx_module *param)
{
success_t success = SUCCESS_PASS;
size_t size = 0;
/* Note: params can't be FX_CUSTOM */
switch (param->val_type) {
case FX_STR:
break;
case FX_DOUBLE:
fx__scan_double_impl(param, param->val, &success, 0);
break;
case FX_INT:
fx__scan_int_impl(param, param->val, &success, 0);
break;
case FX_BOOL:
fx__scan_bool_impl(param, param->val, &success, 0);
break;
case FX_STR_LIST:
break;
case FX_DOUBLE_LIST:
fx__scan_double_list(param, &size, &success);
break;
case FX_INT_LIST:
fx__scan_int_list(param, &size, &success);
break;
case FX_BOOL_LIST:
fx__scan_bool_list(param, &size, &success);
break;
}
return success;
}
static success_t fx__check_inputs(fx_module *mod)
{
fx_module *child;
success_t success = SUCCESS_PASS;
if (mod->mod_type == FX_REQUIRED && !mod->val) {
FX__NONFATAL("Required parameter \"", mod, "\" is unspecified.");
success = SUCCESS_FAIL;
} else if (mod->mod_type == FX_RESERVED && mod->val) {
FX__NONFATAL("Reserved parameter \"", mod, "\" must not be specified.");
success = SUCCESS_FAIL;
} else if (mod->val) {
success = fx__check_mod_type("Input", FX_PARAM, mod);
if (PASSED(success)) {
success &= fx__check_param(mod);
}
}
for (child = mod->first_child; child; child = child->next) {
success &= fx__check_inputs(child);
}
return success;
}
static void fx__report_sys(fx_module *sys)
{
struct utsname info;
uname(&info);
fx_result_str(sys, "node/name", info.nodename);
fx_result_str(sys, "arch/name", info.machine);
fx_result_str(sys, "kernel/name", info.sysname);
fx_result_str(sys, "kernel/release", info.release);
fx_result_str(sys, "kernel/build", info.version);
}
static void fx__read_debug_params(fx_module *debug)
{
verbosity_level = fx_param_double(debug, "verbosity_level", 1.0);
print_got_heres = fx_param_bool(debug, "print_got_heres", 1);
print_warnings = fx_param_bool(debug, "print_warnings", 1);
abort_on_nonfatal = fx_param_bool(debug, "abort_on_nonfatal", 0);
pause_on_nonfatal = fx_param_bool(debug, "pause_on_nonfatal", 0);
print_notify_locs = fx_param_bool(debug, "print_notify_locs", 0);
}
static void fx__attempt_speedup(fx_module *root)
{
/* Try to minimize disk access */
sync();
sleep(3);
/* Start and stop default timer to bring code into cache */
fx_timer_start(root, "total_time");
fx_timer_stop(root, "total_time");
fx_reset_timer(root, "total_time");
}
fx_module *fx_init(int argc, char *argv[], const fx_module_doc *doc)
{
fx_module *root = malloc(sizeof(fx_module));
if (!fx_root) {
fx_root = root;
}
datanode_init(root, "");
fx__fill_docs(root, &fx__std_doc);
if (doc) {
fx__fill_docs(root, doc);
}
if (argc > 0) {
fx__parse_cmd_line(root, argc - 1, argv + 1);
if (fx_param_exists(root, "fx/load")) {
fx__load_param_files(root);
}
if (fx_param_exists(root, "help")) {
fx__std_help(argv[0], fx_param_str_req(root, "help"), doc);
}
MUST_NOT_FAIL_MSG(fx__check_inputs(root),
"There were problems with input parameters; try --help.");
fx__report_sys(fx_submodule(root, "info/sys"));
fx__read_debug_params(fx_submodule(root, "debug"));
if (fx_param_bool(root, "fx/timing", 0)) {
fx__attempt_speedup(root);
}
}
fx_timer_start(root, "total_time");
return root;
}
static void fx__timer_double(fx_module *mod, const char *key, double val)
{
fx_module *timer = fx__lookup(mod, key);
DEBUG_ONLY(fx__check_lookup(FX_TIMER, FX_DOUBLE, timer));
free(timer->val);
timer->val = fx__alloc_int(val);
}
#ifdef HAVE_RDTSC
static void fx__timer_int(fx_module *mod, const char *key, long long val)
{
fx_module *timer = fx__lookup(mod, key);
DEBUG_ONLY(fx__check_lookup(FX_TIMER, FX_INT, timer));
free(timer->val);
timer->val = fx__alloc_int(val);
}
#endif
static void fx__stop_timers(fx_module *mod, struct timestamp *now)
{
fx_module *child;
for (child = mod->first_child; child; child = child->next) {
fx__stop_timers(child, now);
}
if (mod->mod_type == FX_TIMER && mod->val_type == FX_CUSTOM && mod->val) {
fx_timer *timer = (fx_timer *)mod->val;
if (STOPWATCH_ACTIVE(timer)) {
stopwatch_stop(timer, now);
}
fx__fill_docs(mod, &fx__timer_doc);
#ifdef HAVE_RDTSC
fx__timer_int(mod, "cylces", timer->total.cycles);
#endif
fx__timer_double(mod, "real", timer->total.micros / 1e6);
fx__timer_double(mod, "user",
timer->total.cpu.tms_utime / sysconf(_SC_CLK_TCK));
fx__timer_double(mod, "sys",
timer->total.cpu.tms_stime / sysconf(_SC_CLK_TCK));
}
}
static void fx__report_rusage(fx_module *mod, int usage_type)
{
struct rusage usage;
getrusage(usage_type, &usage);
/* Note: many of these are unsupported by various OSes */
fx_result_int(mod, "utime/sec", usage.ru_utime.tv_sec);
fx_result_int(mod, "utime/usec", usage.ru_utime.tv_usec);
fx_result_int(mod, "stime/sec", usage.ru_stime.tv_sec);
fx_result_int(mod, "stime/usec", usage.ru_stime.tv_usec);
fx_result_int(mod, "minflt", usage.ru_minflt);
fx_result_int(mod, "majflt", usage.ru_majflt);
fx_result_int(mod, "maxrss", usage.ru_maxrss);
fx_result_int(mod, "ixrss", usage.ru_ixrss);
fx_result_int(mod, "idrss", usage.ru_idrss);
fx_result_int(mod, "isrss", usage.ru_isrss);
fx_result_int(mod, "nswap", usage.ru_nswap);
fx_result_int(mod, "inblock", usage.ru_inblock);
fx_result_int(mod, "oublock", usage.ru_oublock);
fx_result_int(mod, "msgsnd", usage.ru_msgsnd);
fx_result_int(mod, "msgrcv", usage.ru_msgrcv);
fx_result_int(mod, "nsignals", usage.ru_nsignals);
fx_result_int(mod, "nvcsw", usage.ru_nvcsw);
fx_result_int(mod, "nivcsw", usage.ru_nivcsw);
}
static void fx__output_results(fx_module *root)
{
if (fx_param_exists(root, "fx/output")) {
FILE *stream = fopen(fx_param_str_req(root, "fx/output"), "w");
datanode_write(root, stream, fx_mod_marker);
fclose(stream);
}
if (!fx_param_bool(root, "fx/silent", 0)) {
datanode_write(root, stdout, fx_mod_marker);
}
}
void fx_done(fx_module *root)
{
struct timestamp now;
timestamp_now(&now);
if (!root) {
root = fx_root;
fx_root = NULL;
}
DEBUG_ASSERT_MSG(root != NULL,
"Cannot call fx_done without first calling fx_init.");
fx__stop_timers(root, &now);
if (fx_param_bool(root, "fx/rusage", 0)) {
fx__report_rusage(
fx_submodule(root, "info/rusage/self"), RUSAGE_SELF);
fx__report_rusage(
fx_submodule(root, "info/rusage/children"), RUSAGE_CHILDREN);
}
fx__output_results(root);
datanode_destroy(root);
free(root);
}