Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 28 additions & 5 deletions docs/sphinx/ApplicationAPI.rst
Original file line number Diff line number Diff line change
Expand Up @@ -165,26 +165,49 @@ when given specific STL containers as value, e.g. ``std::tuple`` for tuples or
For detailed information on how to create each compound type, refer to the
:cpp:enum:`adiak_type_t` documentation.

Scalar size specifiers
................................

Adiak internally stores scalar values as 32-bit integer, 64-bit integer, or
64-bit floating point values. Adiak automatically converts smaller integers
(such as ``short``) to ``int``, and ``float`` to ``double``. However, when types
other than (unsigned) ``int`` or ``double`` are used in compound types, you must
use a length specifier in the :cpp:func:`adiak_namevalue` type string argument
to indicate the exact input type, e.g. `"%f32"` for ``float`` or `"%i16"`
for ``signed short``. The available type specifiers are "%i8", "%i16", "%i32",
"%u8", "%u16", "%u32", "%f32", and "%f64". For 64-bit integers, use "%lld" or
"%llu". Examples:

.. code-block:: c

const unsigned char bytes[4] = { 32, 33, 34, 35 };
const signed short smallints[4] = { -1024, 0, 1, 512 };
const float floats[3] = { 0.42, 42.0, 42.42 };

adiak_namevalue("bytes", adiak_general, NULL, "{%u8}", bytes, 4);
adiak_namevalue("smallints", adiak_general, NULL, "[%i16]", smallints, 4);
adiak_namevalue("floats", adiak_general, NULL, "{%f32}", floats, 3);

.. _reference_values:

Reference values
................................

Optionally, values can be stored as references, where Adiak does not copy the data
but only keeps a pointer to it.
Reference entries are available for string types and compound types (lists, sets,
etc.). Scalar types (int, double, etc.) cannot be stored as references.
but only keeps a pointer to it.
Reference entries are available for string types and compound types (lists, sets,
etc.). Scalar types (int, double, etc.) cannot be stored as references.

Any objects stored as references must be retained in memory by the application
throughout the lifetime of the program or until :cpp:func:`adiak_clean` is called.

Currently, reference values must be created through the C API. To do so,
place a ``&`` in front of the type specifier in :cpp:func:`adiak_namevalue`,
place a ``&`` in front of the type specifier in :cpp:func:`adiak_namevalue`,
e.g. ``&{%d}`` for a list of integers or ``&%s`` for a string. For compound
types, the ``&`` can be applied to an inner type to create a shallow copy, e.g.
``{&%s}`` for a shallow-copy list of zero-copy strings. Examples:

.. code-block:: c
.. code-block:: c

static const int array[9] = { -1, 2, -3, 4, 5, 4, 3, 2, 1 };
static const char* string_a = "A long string";
Expand Down
20 changes: 17 additions & 3 deletions include/adiak.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,17 @@ typedef enum {
* that must be passed as the \a typestr argument in \ref adiak_namevalue for
* values of the corresponding type.
*
* For integer and floating point scalar values, an optional size specifier
* can be added in the typestring to specify the exact input type (8, 16,
* 32, or 64 bit). The available specifiers are i8, i16, i32, i64, u8, u16,
* u32, u64, f32, and f64. For example, use "%f32" for 32-bit float values,
* "%i16" for signed short (16-bit) integers, etc.
*
* Type | Typestring | Value category
* -----------------|--------------|---------------
* adiak_long | "%ld" | rational
* adiak_ulong | "%lu" | rational
* adiak_int | "%d" | rational
* adiak_int | "%d", "%i" | rational
* adiak_uint | "%u" | rational
* adiak_double | "%f" | rational
* adiak_date | "%D" | interval
Expand Down Expand Up @@ -196,6 +202,8 @@ typedef struct adiak_datatype_t {
int is_reference;
/** \brief Number of sub-elements for reference container values */
int num_ref_elements;
/** \brief Size in bytes of the original input data (currently only for base types) */
size_t num_bytes;
} adiak_datatype_t;

/** \brief Adiak value union
Expand Down Expand Up @@ -240,7 +248,7 @@ typedef union adiak_value_t {
long long v_longlong;
} adiak_value_t;

static const adiak_datatype_t adiak_unset_datatype = { adiak_type_unset, adiak_numerical_unset, 0, 0, NULL, 0, 0 };
static const adiak_datatype_t adiak_unset_datatype = { adiak_type_unset, adiak_numerical_unset, 0, 0, NULL, 0, 0, 0 };

/**
* \}
Expand Down Expand Up @@ -285,16 +293,22 @@ void adiak_fini();
* from the string specifiers shown in \ref adiak_type_t. The varargs contain the value
* and, if needed, any additional parameters for the type (e.g., list length).
*
* When scalar values other than (unsigned) \c int, \c long, or \c double are used in
* compound types, use a length specifier to indicate the exact type in \a typestr,
* e.g. "%f32" for 32-bit \c float or "%i16" for \c short.
*
* Examples:
*
* \code
* adiak_namevalue("numrecords", adiak_general, NULL, "%d", 10);
*
* adiak_namevalue("buildcompiler", adiak_general, "build data", "%v", "[email protected]");
*
* double gridvalues[] = { 5.4, 18.1, 24.0, 92.8 };
* adiak_namevalue("gridvals", adiak_general, NULL, "[%f]", gridvalues, 4);
*
* unsigned char bytes[] = { 32, 33, 34, 35 };
* adiak_namevalue("bytes", adiak_general, NULL, "{%u8}", bytes, 4);
*
* struct { int pos; const char *val; } letters[3] = { {1, "a"}, {2, "b"}, {3, "c"} };
* adiak_namevalue("alphabet", adiak_general, NULL, "[(%d, %s)]", letters, 3, 2);
* \endcode
Expand Down
159 changes: 128 additions & 31 deletions src/adiak.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <string.h>
#include <assert.h>
#include <stdio.h>
#include <stdint.h>

#include "adiak.h"
#include "adiak_tool.h"
Expand Down Expand Up @@ -64,25 +65,30 @@ static int measure_adiak_walltime;
static int measure_adiak_systime;
static int measure_adiak_cputime;

static adiak_datatype_t base_long = { adiak_long, adiak_rational, 0, 0, NULL, 0, 0 };
static adiak_datatype_t base_ulong = { adiak_ulong, adiak_rational, 0, 0, NULL, 0, 0 };
static adiak_datatype_t base_longlong = { adiak_longlong, adiak_rational, 0, 0, NULL, 0, 0 };
static adiak_datatype_t base_ulonglong = { adiak_ulonglong, adiak_rational, 0, 0, NULL, 0, 0 };
static adiak_datatype_t base_int = { adiak_int, adiak_rational, 0, 0, NULL, 0, 0 };
static adiak_datatype_t base_uint = { adiak_uint, adiak_rational, 0, 0, NULL, 0, 0 };
static adiak_datatype_t base_double = { adiak_double, adiak_rational, 0, 0, NULL, 0, 0 };
static adiak_datatype_t base_date = { adiak_date, adiak_interval, 0, 0, NULL, 0, 0 };
static adiak_datatype_t base_timeval = { adiak_timeval, adiak_interval, 0, 0, NULL, 0, 0 };
static adiak_datatype_t base_version = { adiak_version, adiak_ordinal, 0, 0, NULL, 0, 0 };
static adiak_datatype_t base_string = { adiak_string, adiak_ordinal, 0, 0, NULL, 0, 0 };
static adiak_datatype_t base_catstring = { adiak_catstring, adiak_categorical, 0, 0, NULL, 0, 0 };
static adiak_datatype_t base_jsonstring = { adiak_jsonstring, adiak_categorical, 0, 0, NULL, 0, 0 };
static adiak_datatype_t base_path = { adiak_path, adiak_categorical, 0, 0, NULL, 0, 0 };
static adiak_datatype_t base_version_ref = { adiak_version, adiak_ordinal, 0, 0, NULL, 1, 0 };
static adiak_datatype_t base_string_ref = { adiak_string, adiak_ordinal, 0, 0, NULL, 1, 0 };
static adiak_datatype_t base_catstring_ref = { adiak_catstring, adiak_categorical, 0, 0, NULL, 1, 0 };
static adiak_datatype_t base_jsonstring_ref = { adiak_jsonstring, adiak_categorical, 0, 0, NULL, 1, 0 };
static adiak_datatype_t base_path_ref = { adiak_path, adiak_categorical, 0, 0, NULL, 1, 0 };
static adiak_datatype_t base_long = { adiak_long, adiak_rational, 0, 0, NULL, 0, 0, sizeof(long) };
static adiak_datatype_t base_ulong = { adiak_ulong, adiak_rational, 0, 0, NULL, 0, 0, sizeof(unsigned long) };
static adiak_datatype_t base_longlong = { adiak_longlong, adiak_rational, 0, 0, NULL, 0, 0, sizeof(long long) };
static adiak_datatype_t base_ulonglong = { adiak_ulonglong, adiak_rational, 0, 0, NULL, 0, 0, sizeof(unsigned long long) };
static adiak_datatype_t base_int = { adiak_int, adiak_rational, 0, 0, NULL, 0, 0, sizeof(int) };
static adiak_datatype_t base_i8 = { adiak_int, adiak_rational, 0, 0, NULL, 0, 0, 1 };
static adiak_datatype_t base_i16 = { adiak_int, adiak_rational, 0, 0, NULL, 0, 0, 2 };
static adiak_datatype_t base_u8 = { adiak_uint, adiak_rational, 0, 0, NULL, 0, 0, 1 };
static adiak_datatype_t base_u16 = { adiak_uint, adiak_rational, 0, 0, NULL, 0, 0, 2 };
static adiak_datatype_t base_uint = { adiak_uint, adiak_rational, 0, 0, NULL, 0, 0, sizeof(unsigned int) };
static adiak_datatype_t base_double = { adiak_double, adiak_rational, 0, 0, NULL, 0, 0, sizeof(double) };
static adiak_datatype_t base_float = { adiak_double, adiak_rational, 0, 0, NULL, 0, 0, sizeof(float) };
static adiak_datatype_t base_date = { adiak_date, adiak_interval, 0, 0, NULL, 0, 0, sizeof(long) };
static adiak_datatype_t base_timeval = { adiak_timeval, adiak_interval, 0, 0, NULL, 0, 0, sizeof(struct timeval*) };
static adiak_datatype_t base_version = { adiak_version, adiak_ordinal, 0, 0, NULL, 0, 0, sizeof(char*) };
static adiak_datatype_t base_string = { adiak_string, adiak_ordinal, 0, 0, NULL, 0, 0, sizeof(char*) };
static adiak_datatype_t base_catstring = { adiak_catstring, adiak_categorical, 0, 0, NULL, 0, 0, sizeof(char*) };
static adiak_datatype_t base_jsonstring = { adiak_jsonstring, adiak_categorical, 0, 0, NULL, 0, 0, sizeof(char*) };
static adiak_datatype_t base_path = { adiak_path, adiak_categorical, 0, 0, NULL, 0, 0, sizeof(char*) };
static adiak_datatype_t base_version_ref = { adiak_version, adiak_ordinal, 0, 0, NULL, 1, 0, sizeof(char*) };
static adiak_datatype_t base_string_ref = { adiak_string, adiak_ordinal, 0, 0, NULL, 1, 0, sizeof(char*) };
static adiak_datatype_t base_catstring_ref = { adiak_catstring, adiak_categorical, 0, 0, NULL, 1, 0, sizeof(char*) };
static adiak_datatype_t base_jsonstring_ref = { adiak_jsonstring, adiak_categorical, 0, 0, NULL, 1, 0, sizeof(char*) };
static adiak_datatype_t base_path_ref = { adiak_path, adiak_categorical, 0, 0, NULL, 1, 0, sizeof(char*) };

static adiak_t* adiak_get_config();
static void adiak_register(int adiak_version, int category,
Expand All @@ -91,6 +97,7 @@ static void adiak_register(int adiak_version, int category,
int report_on_all_ranks, void *opaque_val);

static int find_end_brace(const char *typestr, char endchar, int typestr_start, int typestr_end);
static int parse_scalar_len_spec(const char* typestr, int *pos);
static adiak_datatype_t *parse_typestr(const char *typestr, va_list *ap);
static adiak_datatype_t *parse_typestr_helper(const char *typestr, int typestr_start, int typestr_end,
int is_reference, va_list *ap, int *new_typestr_start);
Expand Down Expand Up @@ -397,10 +404,22 @@ int adiak_get_subval(adiak_datatype_t* t, adiak_value_t* val, int elem, adiak_da
break;
case adiak_int:
case adiak_uint:
(*subval).v_int = *((int *) ptr);
switch ((*subtype)->num_bytes) {
case 1:
(*subval).v_int = *((int8_t *) ptr);
break;
case 2:
(*subval).v_int = *((int16_t *) ptr);
break;
default:
(*subval).v_int = *((int *) ptr);
}
break;
case adiak_double:
(*subval).v_double = *((double *) ptr);
if ((*subtype)->num_bytes == 4)
(*subval).v_double = *((float *) ptr);
else
(*subval).v_double = *((double *) ptr);
break;
case adiak_timeval:
case adiak_version:
Expand Down Expand Up @@ -543,6 +562,7 @@ static adiak_datatype_t *parse_typestr(const char *typestr, va_list *ap)

static adiak_type_t toplevel_type(const char *typestr) {
const char *cur = typestr;
int pos = 0;
if (!cur)
return adiak_type_unset;
while (isspace(*cur) || *cur == ',' || *cur == '&')
Expand All @@ -561,7 +581,8 @@ static adiak_type_t toplevel_type(const char *typestr) {
}
return adiak_type_unset;
case 'd': return adiak_int;
case 'u': return adiak_uint;
case 'i': return parse_scalar_len_spec(cur, &pos) == 8 ? adiak_longlong : adiak_int;
case 'u': return parse_scalar_len_spec(cur, &pos) == 8 ? adiak_ulonglong : adiak_uint;
case 'f': return adiak_double;
case 'D': return adiak_date;
case 't': return adiak_timeval;
Expand Down Expand Up @@ -709,12 +730,10 @@ static int calc_size(adiak_datatype_t* datatype)
return sizeof(long);
case adiak_longlong:
case adiak_ulonglong:
return sizeof(long long);
case adiak_int:
case adiak_uint:
return sizeof(int);
case adiak_double:
return sizeof(double);
return (int) datatype->num_bytes;
case adiak_timeval:
return sizeof(struct timeval *);
case adiak_version:
Expand Down Expand Up @@ -756,11 +775,23 @@ static int copy_value(adiak_value_t *target, adiak_datatype_t *datatype, void *p
return sizeof(long long);
case adiak_int:
case adiak_uint:
target->v_int = *((int *) ptr);
return sizeof(int);
switch (datatype->num_bytes) {
case 1:
target->v_int = *((int8_t *) ptr);
break;
case 2:
target->v_int = *((int16_t *) ptr);
break;
default:
target->v_int = *((int *) ptr);
}
return datatype->num_bytes;
case adiak_double:
target->v_double= *((double *) ptr);
return sizeof(double);
if (datatype->num_bytes == 4)
target->v_double = *((float *) ptr);
else
target->v_double = *((double *) ptr);
return datatype->num_bytes;
case adiak_timeval: {
struct timeval* v = (struct timeval*) ptr;
if (!datatype->is_reference) {
Expand Down Expand Up @@ -804,6 +835,25 @@ static int copy_value(adiak_value_t *target, adiak_datatype_t *datatype, void *p
return -1;
}

static int parse_scalar_len_spec(const char* typestr, int *pos)
{
if (typestr[(*pos)+1] == '8') {
*pos += 1;
return 1;
} else if (typestr[(*pos)+1] == '1' && typestr[(*pos)+2] == '6') {
*pos += 2;
return 2;
} else if (typestr[(*pos)+1] == '3' && typestr[(*pos)+2] == '2') {
*pos += 2;
return 4;
} else if (typestr[(*pos)+1] == '6' && typestr[(*pos)+2] == '4') {
*pos += 2;
return 8;
} else if (typestr[(*pos)+1] >= '0' && typestr[(*pos)+1] <= '9')
return -1;
return 0;
}

static adiak_datatype_t *parse_typestr_helper(const char *typestr, int typestr_start, int typestr_end, int is_reference,
va_list *ap, int *new_typestr_start)

Expand Down Expand Up @@ -900,10 +950,57 @@ static adiak_datatype_t *parse_typestr_helper(const char *typestr, int typestr_s
t = is_long ? (is_longlong ? &base_longlong : &base_long) : &base_int;
break;
case 'u':
t = is_long ? (is_longlong ? &base_ulonglong : &base_ulong) : &base_uint;
switch (parse_scalar_len_spec(typestr, &cur)) {
case 0:
t = is_long ? (is_longlong ? &base_ulonglong : &base_ulong) : &base_uint;
break;
case 1:
t = &base_u8;
break;
case 2:
t = &base_u16;
break;
case 4:
t = &base_uint;
break;
case 8:
t = &base_ulonglong;
break;
default:
goto error;
}
break;
case 'i':
switch (parse_scalar_len_spec(typestr, &cur)) {
case 0:
case 4:
t = &base_int;
break;
case 1:
t = &base_i8;
break;
case 2:
t = &base_i16;
break;
case 8:
t = &base_longlong;
break;
default:
goto error;
}
break;
case 'f':
t = &base_double;
switch (parse_scalar_len_spec(typestr, &cur)) {
case 0:
case 8:
t = &base_double;
break;
case 4:
t = &base_float;
break;
default:
goto error;
}
break;
case 'D':
t = &base_date;
Expand Down
Loading