The XBT toolbox
XBT is not an interface to describe your application, but rather a toolbox of features that are used everywhere in SimGrid. The code described in this page is not specific to any of the existing interfaces, and it’s used in all of them.
Logging API
As introduced in Textual logging, the SimGrid logging mechanism allows to configure at runtime the messages that should be displayed and those that should be omitted. Each message produced in the code is given a category (denoting its topic) and a priority. Then at runtime, each category is given a threshold (only messages of priority higher than that threshold are displayed), a layout (deciding how the messages in this category are formatted), and an appender (deciding what to do with the message: either print on stderr or to a file).
This section documents the provided API. To see how to configure these features at runtime, please refer to Logging configuration.
Declaring categories
Typically, there will be a category for each module of the implementation, so that users can independently control the logging for each module. Refer to the Existing categories section for a list of all existing categories in SimGrid.
-
XBT_LOG_NEW_CATEGORY(category, description)
Creates a new category that is not within any existing categories. It will be located right below the
root
category.category
must be a valid identifier (such asmycat
) with no quote or anything. It should also be unique over the whole binary.description
must be a string, between quotes.
-
XBT_LOG_NEW_SUBCATEGORY(category, parent_category, description)
Creates a new category under the provided
parent_category
.
-
XBT_LOG_NEW_DEFAULT_CATEGORY(category, description)
Similar to
XBT_LOG_NEW_CATEGORY
, and the created category is the default one in the current source file.
-
XBT_LOG_NEW_DEFAULT_SUBCATEGORY(category, parent_category, description)
Similar to
XBT_LOG_NEW_SUBCATEGORY
, and the created category is the default one in the current source file.
-
XBT_LOG_EXTERNAL_CATEGORY(category)
Make an external category (i.e., a category declared in another source file) visible from this source file. In each source file, at most one one category can be the default one.
-
XBT_LOG_EXTERNAL_DEFAULT_CATEGORY(category)
Use an external category as default category in this source file.
Logging messages
Default category
-
XBT_CRITICAL(format_string, parameters...)
Report a fatal error to the default category.
-
XBT_ERROR(format_string, parameters...)
Report an error to the default category.
-
XBT_WARN(format_string, parameters...)
Report a warning or an important information to the default category.
-
XBT_INFO(format_string, parameters...)
Report an information of regular importance to the default category.
-
XBT_VERB(format_string, parameters...)
Report a verbose information to the default category.
-
XBT_DEBUG(format_string, parameters...)
Report a debug-only information to the default category.
For each of the logging macros, the first parameter must be a printf-like format string, and the subsequent parameters must match this format. If you compile with the -Wall option, the compiler will warn you for unmatched arguments, such as passing a pointer while the format string expects an integer. Using this option is usually a good idea.
Here is an example: XBT_WARN("Values are: %d and '%s'", 5, "oops");
-
XBT_IN(format_string, parameters...)
Report that the execution flow enters a given function (which name is displayed automatically).
-
XBT_OUT(format_string, parameters...)
Report that the execution flow exits a given function (which name is displayed automatically).
-
XBT_HERE(format_string, parameters...)
Report that the execution flow reaches a given location.
Specific category
-
XBT_CCRITICAL(category, format_string, parameters...)
Report a fatal error to the specified
category
.
-
XBT_CERROR(category, format_string, parameters...)
Report an error to the specified
category
.
-
XBT_CWARN(category, format_string, parameters...)
Report a warning or an important information to the specified
category
.
-
XBT_CINFO(category, format_string, parameters...)
Report an information of regular importance to the specified
category
.
-
XBT_CVERB(category, format_string, parameters...)
Report a verbose information to the specified
category
.
-
XBT_CDEBUG(category, format_string, parameters...)
Report a debug-only information to the specified
category
.
Of course, the specified category must be visible from this source file, either because it was created there (e.g. with XBT_LOG_NEW_CATEGORY
) or because it was made
visible with XBT_LOG_EXTERNAL_CATEGORY
.
Other functions
-
XBT_LOG_ISENABLED(category, priority)
Returns true if that category displays the messages of that priority. It’s useful to compute a value that is used only in the logging, such as the textual representation of a non-trivial object.
The specified priority must be one of
xbt_log_priority_trace
,xbt_log_priority_debug
,xbt_log_priority_verbose
,xbt_log_priority_info
,xbt_log_priority_warning
,xbt_log_priority_error
orxbt_log_priority_critical
.
-
void xbt_log_control_set(const char *setting)
Sets the provided
setting
as if it was passed in a--log
command-line parameter.
You should not use any of the macros which name starts with ‘_’.
Existing categories
This is the list of all categories existing in the SimGrid implementation. Some of them only exist with specific compile-time options, while your implementation may add new ones. Please add --help-log-categories
to the command-line of a SimGrid simulator to see the exact list of categories usable with it.
dag_parsing: Generation DAGs from files
instr: Logging the behavior of the tracing system (used for Visualization/Analysis of simulations)
instr_paje_events: Paje tracing event system (events)
instr_paje_trace: tracing event system
instr_routing: Tracing platform hierarchy
instr_smpi: Tracing SMPI
ker_engine: Logging specific to Engine (kernel)
kernel: SimGrid internals
Battery: Logging specific to the battery plugin
Chiller: Logging specific to the solar panel plugin
SolarPanel: Logging specific to the solar panel plugin
Task: Logging specific to the task plugin
cmonkey: Chaos Monkey plugin
config: About the configuration of SimGrid
host_dvfs: Logging specific to the HostDvfs plugin
host_energy: Logging specific to the host energy plugin
ker_activity: Kernel activity-related synchronization
ker_actor: Logging specific to Actor’s kernel side
ker_bmf: Kernel BMF solver
ker_context: Context switching mechanism
ker_cpu: Kernel cpu-related synchronization
ker_io: Kernel io-related synchronization
ker_lmm: Kernel Linear Max-Min solver
ker_mailbox: Mailbox implementation
ker_mess: Kernel message synchronization
ker_mq: Message queue implementation
ker_network: Kernel network-related synchronization
ker_platform: Kernel platform-related information
ker_netpoint: Kernel implementation of netpoints
ker_routing_cluster: Kernel Cluster Routing
ker_routing_dijkstra: Kernel Dijkstra Routing
ker_routing_dragonfly: Kernel Dragonfly Routing
ker_routing_fat_tree: Kernel Fat-Tree Routing
ker_routing_floyd: Kernel Floyd Routing
ker_routing_full: Kernel Full Routing
ker_routing_generic: Kernel Generic Routing
ker_routing_none: Kernel No Routing
ker_routing_star: Kernel Star Routing
ker_routing_torus: Kernel Torus Routing
ker_routing_vivaldi: Kernel Vivaldi Routing
ker_routing_wifi: Kernel Wifi Routing
platf_parse: Logging specific to the parsing of platform files
ker_resource: Resources, modeling the platform performance
res_cpu: CPU resource, fueling execution activites
cpu_cas: CPU resource, CAS01 model (used by default)
cpu_ti: CPU resource, Trace Integration model
res_disk: Disk resources, that fuel I/O activities
res_host: Host resources agregate CPU, networking and I/O features
res_network: Network resources, that fuel communications
res_ns3: Network model based on ns-3
res_vm: Virtual Machines, containing actors and mobile across hosts
ker_simcall: transmuting from user request into kernel handlers
ker_synchro: Kernel synchronization activities (lock/acquire on a mutex, semaphore or condition)
ker_barrier: Barrier kernel-space implementation
ker_condition: Condition variables kernel-space implementation
ker_mutex: Mutex kernel-space implementation
ker_semaphore: Semaphore kernel-space implementation
link_energy: Logging specific to the LinkEnergy plugin
link_energy_wifi: Logging specific to the link energy wifi plugin
link_load: Logging specific to the LinkLoad plugin
mc: All MC categories
mc_Session: Model-checker session
mc_bfs: BFS exploration algorithm of the model-checker
mc_channel: MC interprocess communication
mc_checkerside: MC communication with the application
mc_client: MC client logic
mc_comm_determinism: Logging specific to MC communication determinism detection
mc_ct: Critical transition exploration algorithm. For now, the answer is approximate when used with reduction
mc_dfs: DFS exploration algorithm of the model-checker
mc_dpor: Dynamic partial order reduction algorithm
mc_explo: Generic exploration algorithm of the model-checker
mc_global: Logging specific to MC (global)
mc_observer: Logging specific to MC simcall observation
obs_comm: Logging specific to the Communication simcalls observation
obs_mutex: Logging specific to mutex simcalls observation
obs_waittest: Logging specific to the wait and test simcalls observation
mc_record: Logging specific to MC record/replay facility
mc_reduction: Logging specific to the reduction algorithms
mc_bfsodpor: Logging specific to the odpor reduction
mc_odpor: Logging specific to the odpor reduction
mc_odpor_execution: ODPOR exploration algorithm of the model-checker
mc_state: Logging specific to MC states
mc_bfswutstate: Model-checker state dedicated to the BFS version of ODPOR algorithm
mc_sleepset: DFS exploration algorithm of the model-checker
mc_wutstate: States using wakeup tree for ODPOR algorithm
mc_transition: Logging specific to MC transitions
mc_trans_actorlifecycle: Logging specific to MC transitions about actors’ lifecycle: joining, ending
mc_trans_any: Logging specific to MC WaitAny / TestAny transitions
mc_trans_comm: Logging specific to MC transitions about communications
mc_trans_rand: Logging specific to MC Random transitions
mc_trans_synchro: Logging specific to MC synchronization transitions
mc_udpor: Logging specific to verification using UDPOR
mc_event: Logging specific to the unfolding events used in UDPOR
mc_extension: Logging specific to the extension computation in UDPOR
mc_wut: Logging specific to ODPOR WakeupTrees
plugin: Common category for the logging of all plugins
host_load: Logging specific to the HostLoad plugin
producer_consumer: Producer-Consumer plugin logging category
python: python
s4u: Log channels of the S4U (SimGrid for you) interface
s4u_activity: S4U activities
s4u_activityset: S4U set of activities
s4u_comm: S4U asynchronous communications
s4u_exec: S4U asynchronous executions
s4u_io: S4U asynchronous I/Os
s4u_mess: S4U asynchronous messaging
s4u_actor: S4U actors
s4u_channel: S4U Communication Mailboxes
s4u_engine: Logging specific to S4U (engine)
s4u_file: S4U files
s4u_host: Logging specific to the S4U hosts
s4u_jbod: Logging specific to the JBOD implmentation
s4u_mqueue: S4U Message Queues
s4u_synchro: S4U synchronization objects
s4u_barrier: S4U barrier
s4u_sema: S4U semaphores
s4u_vm: S4U virtual machines
vm_live_migration: S4U virtual machines live migration
smpi: All SMPI categories
smpi_bench: Logging specific to SMPI (benchmarking)
smpi_coll: Logging specific to SMPI collectives.
smpi_colls: Logging specific to SMPI collectives
smpi_comm: Logging specific to SMPI (comm)
smpi_config: Logging specific to SMPI (config)
smpi_datatype: Logging specific to SMPI (datatype)
smpi_host: Logging specific to SMPI (host)
smpi_io: Logging specific to SMPI (RMA operations)
smpi_kernel: Logging specific to SMPI (kernel)
smpi_memory: Memory layout support for SMPI
smpi_mpi: Logging specific to SMPI ,(mpi)
smpi_op: Logging specific to SMPI (op)
smpi_pmpi: Logging specific to SMPI (pmpi)
smpi_process: Logging specific to SMPI (kernel)
smpi_replay: Trace Replay with SMPI
smpi_request: Logging specific to SMPI (request)
smpi_rma: Logging specific to SMPI (RMA operations)
smpi_shared: Logging specific to SMPI (shared memory macros)
smpi_utils: Logging specific to SMPI (utils)
sthread: pthread intercepter
unit: Unit tests of the Trace Manager
xbt: All XBT categories (SimGrid toolbox)
log: Loggings from the logging mechanism itself
parse: Parsing functions
replay: Replay trace reader
xbt_cfg: configuration support
xbt_dict: Dictionaries provide the same functionalities as hash tables
xbt_dict_cursor: To traverse dictionaries
xbt_dyn: Dynamic arrays
xbt_exception: Exceptions
xbt_graph: Graph
xbt_help: Help messages
xbt_mallocator: Mallocators
xbt_parmap: parmap: parallel map
xbt_random: Random
Full example
#include "xbt/log.h"
/* create a category and a default subcategory */
XBT_LOG_NEW_CATEGORY(VSS);
XBT_LOG_NEW_DEFAULT_SUBCATEGORY(SA, VSS);
int main() {
/* Now set the parent's priority. (the string would typically be a runtime option) */
xbt_log_control_set("SA.thresh:info");
/* This request is enabled, because WARNING >= INFO. */
XBT_CWARN(VSS, "Low fuel level.");
/* This request is disabled, because DEBUG < INFO. */
XBT_CDEBUG(VSS, "Starting search for nearest gas station.");
/* The default category SA inherits its priority from VSS. Thus,
the following request is enabled because INFO >= INFO. */
XBT_INFO("Located nearest gas station.");
/* This request is disabled, because DEBUG < INFO. */
XBT_DEBUG("Exiting gas station search");
}
Performance concern
This module is highly optimized. Messages that will not be displayed are not even built. For example, using XBT_DEBUG
in a category that turns debug messages off only costs a
single integer comparison at runtime, and the parameters are not even evaluated.
You can even specify a compile-time threshold that will completely remove every logging below the specified priority. Passing -DNDEBUG
to cmake disables every logging of
priority below INFO while -DNLOG
removes any logging at compile time. Note that using this feature may hinder the stability of SimGrid, as we consider the logs to be fast
enough to not thoughtfully test the case where they are removed at compile time.
Dynamic arrays
As SimGrid used to be written in pure C, it used to rely on custom data containers such as dynamic arrays and dictionnaries. Nowadays, the standard library of C++ is used internally, but some part of the interface still rely on the old containers, that are thus still available.
Warning
You should probably not start a new project using these data structures, as we will deprecate them from SimGrid as soon as possible. Better implementations exist out there anyway, in particular if you’re not writting pure C code.
-
typedef struct xbt_dynar_s *xbt_dynar_t
Dynar data type (opaque type)
These are the SimGrid version of the DYNamically sized ARays, which all C programmer recode one day or another. For performance concerns, the content of dynars must be homogeneous (in contrary to
xbt_dict_t
). You thus have to provide the function which will be used to free the content at structure creation (of type void_f_pvoid_t).
-
typedef const struct xbt_dynar_s *const_xbt_dynar_t
constant dynar
Creation and destruction
-
xbt_dynar_t xbt_dynar_new(const unsigned long elm_size, void_f_pvoid_t free_f)
Creates a new dynar. If a
free_f
is provided, the elements have to be pointer of pointer. That is to say that dynars can contain either base types (int, char, double, etc) or pointer of pointers (struct **).- Parameters:
elmsize – size of each element in the dynar
free_f – function to call each time we want to get rid of an element (or nullptr if nothing to do).
-
void xbt_dynar_free(xbt_dynar_t *dynar)
Destructor: kilkil a dynar and its content.
-
void xbt_dynar_free_container(xbt_dynar_t *dynar)
Destructor of the structure leaving the content unmodified. Ie, the array is freed, but the content is not touched (the free_f function is not used).
- Parameters:
dynar – poor victim
Dynars as regular arrays
-
void xbt_dynar_get_cpy(const_xbt_dynar_t dynar, unsigned long idx, void *dst)
Retrieve a copy of the Nth element of a dynar.
- Parameters:
dynar – information dealer
idx – index of the slot we want to retrieve
dst – [out] where to put the result to.
-
void xbt_dynar_insert_at(xbt_dynar_t dynar, int idx, const void *src)
Set the Nth dynar’s element, expanding the dynar and sliding the previous values to the right.
Set the Nth element of a dynar, expanding the dynar if needed, and moving the previously existing value and all subsequent ones to one position right in the dynar.
-
void xbt_dynar_remove_at(xbt_dynar_t dynar, int idx, void *dst)
Remove the Nth element, sliding other values to the left.
Get the Nth element of a dynar, removing it from the dynar and moving all subsequent values to one position left in the dynar.
If the object argument of this function is a non-null pointer, the removed element is copied to this address. If not, the element is freed using the free_f function passed at dynar creation.
-
int xbt_dynar_member(const_xbt_dynar_t dynar, const void *elem)
Returns a boolean indicating whether the element is part of the dynar.
Beware that if your dynar contains pointed values (such as strings) instead of scalar, this function is probably not what you want. It would compare the pointer values, not the pointed elements.
-
void xbt_dynar_sort(const_xbt_dynar_t dynar, int_f_cpvoid_cpvoid_t compar_fn)
Sorts a dynar according to the function
compar_fn
This function simply apply the classical qsort(3) function to the data stored in the dynar. You should thus refer to the libc documentation, or to some online tutorial on how to write a comparison function. Here is a quick example if you have integers in your dynar:
int cmpfunc (const void * a, const void * b) { int intA = *(int*)a; int intB = *(int*)b; return intA - intB; }
- Parameters:
dynar – the dynar to sort
compar_fn – comparison function of type (int (compar_fn*) (const void*) (const void*)).
Dynar size
-
int xbt_dynar_is_empty(const_xbt_dynar_t dynar)
check if a dynar is empty
-
unsigned long xbt_dynar_length(const_xbt_dynar_t dynar)
Count of dynar’s elements.
-
void xbt_dynar_reset(xbt_dynar_t dynar)
Frees the content and set the size to 0.
Perl-like interface
-
void xbt_dynar_push(xbt_dynar_t dynar, const void *src)
Add an element at the end of the dynar.
-
void xbt_dynar_pop(xbt_dynar_t dynar, void *dst)
Get and remove the last element of the dynar.
-
void xbt_dynar_unshift(xbt_dynar_t dynar, const void *src)
Add an element at the beginning of the dynar.
This is less efficient than xbt_dynar_push()
-
void xbt_dynar_shift(xbt_dynar_t dynar, void *dst)
Get and remove the first element of the dynar.
This is less efficient than xbt_dynar_pop()
-
void xbt_dynar_map(const_xbt_dynar_t dynar, void_f_pvoid_t op)
Apply a function to each member of a dynar.
The mapped function may change the value of the element itself, but should not mess with the structure of the dynar.
Direct content manipulation
Those functions do not retrieve the content, but only their address.
-
void *xbt_dynar_set_at_ptr(const xbt_dynar_t dynar, unsigned long idx)
-
void *xbt_dynar_get_ptr(const_xbt_dynar_t dynar, unsigned long idx)
Retrieve a pointer to the Nth element of a dynar.
Note that the returned value is the actual content of the dynar. Make a copy before fooling with it.
-
void *xbt_dynar_insert_at_ptr(xbt_dynar_t dynar, int idx)
Make room for a new element, and return a pointer to it.
You can then use regular affectation to set its value instead of relying on the slow memcpy. This is what xbt_dynar_insert_at_as() does.
-
void *xbt_dynar_push_ptr(xbt_dynar_t dynar)
Make room at the end of the dynar for a new element, and return a pointer to it.
You can then use regular affectation to set its value instead of relying on the slow memcpy. This is what xbt_dynar_push_as() does.
-
void *xbt_dynar_pop_ptr(xbt_dynar_t dynar)
Mark the last dynar’s element as unused and return a pointer to it.
You can then use regular affectation to set its value instead of relying on the slow memcpy. This is what xbt_dynar_pop_as() does.
Dynars of scalars
While the other functions use a memcpy to retrieve the content into the user provided area, those ones use a regular affectation. It only works for scalar values, but should be a little faster.
-
xbt_dynar_get_as(dynar, idx, type)
Quick retrieval of scalar content.
-
xbt_dynar_set_as(dynar, idx, type, val)
Quick setting of scalar content.
-
xbt_dynar_getlast_as(dynar, type)
Quick retrieval of scalar content.
-
xbt_dynar_getfirst_as(dynar, type)
Quick retrieval of scalar content.
-
xbt_dynar_push_as(dynar, type, value)
Quick insertion of scalar content.
-
xbt_dynar_pop_as(dynar, type)
Quick removal of scalar content.
Iterating over Dynars
-
xbt_dynar_foreach(_dynar, _cursor, _data)
Iterates over the whole dynar.
Here is an example of usage:
xbt_dynar_t dyn; unsigned int cpt; char* str; xbt_dynar_foreach (dyn,cpt,str) { printf("Seen %s\n",str); }
Note that underneath, that’s a simple for loop with no real black magic involved. It’s perfectly safe to interrupt a foreach with a break or a return statement, but inserting or removing elements during the traversal is probably a bad idea (even if you can fix side effects by manually changing the counter).
- Parameters:
_dynar – what to iterate over
_cursor – an unsigned integer used as cursor
Example with scalar values
xbt_dynar_t d = xbt_dynar_new(sizeof(int), nullptr);
/* 1. Populate the dynar */
xbt_dynar_t d = xbt_dynar_new(sizeof(int), nullptr);
for (int cpt = 0; cpt < NB_ELEM; cpt++) {
xbt_dynar_push_as(d, int, cpt); /* This is faster (and possible only with scalars) */
/* xbt_dynar_push(d,&cpt); This would also work */
xbt_test_log("Push %d, length=%lu", cpt, xbt_dynar_length(d));
}
/* 2. Traverse manually the dynar */
for (cursor = 0; cursor < NB_ELEM; cursor++) {
int* iptr = (int*)xbt_dynar_get_ptr(d, cursor);
/* 1. Populate further the dynar */
for (int cpt = 0; cpt < NB_ELEM; cpt++) {
xbt_dynar_insert_at(d, cpt, &cpt);
xbt_test_log("Push %d, length=%lu", cpt, xbt_dynar_length(d));
}
/* 3. Traverse the dynar */
int cpt;
xbt_dynar_foreach(d, cursor, cpt) {
xbt_test_assert(cursor == (unsigned int) cpt, "The retrieved value is not the same than the injected one (%u!=%d)", cursor, cpt);
}
/* 4. Reset the values */
for (int i = 0; i < NB_ELEM; i++)
*(int*)xbt_dynar_get_ptr(d, i) = i;
/* 5. Shift all the values */
for (int i = 0; i < NB_ELEM; i++) {
int val;
xbt_dynar_shift(d, &val);
}
// the dynar is empty after shifting all values
/* 5. Free the resources */
xbt_dynar_free(&d);
Example with pointed values
xbt_dynar_t d = xbt_dynar_new(sizeof(char*), &xbt_free_ref);
/// Push/shift example
for (int i = 0; i < NB_ELEM; i++) {
char * val = xbt_strdup("hello");
xbt_dynar_push(d, &val);
}
for (int i = 0; i < NB_ELEM; i++) {
char *val;
xbt_dynar_shift(d, &val);
REQUIRE("hello" == val);
xbt_free(val);
}
xbt_dynar_free(&d);
/// Unshift, traverse and pop example
d = xbt_dynar_new(sizeof(char**), &xbt_free_ref);
for (int i = 0; i < NB_ELEM; i++) {
std::string val = std::to_string(i);
s1 = xbt_strdup(val.c_str());
xbt_dynar_unshift(d, &s1);
}
/* 2. Traverse the dynar with the macro */
xbt_dynar_foreach (d, iter, s1) {
std::string val = std::to_string(NB_ELEM - iter - 1);
REQUIRE(s1 == val); // The retrieved value is not the same than the injected one
}
/* 3. Traverse the dynar with the macro */
for (int i = 0; i < NB_ELEM; i++) {
std::string val = std::to_string(i);
xbt_dynar_pop(d, &s2);
REQUIRE(s2 == val); // The retrieved value is not the same than the injected one
xbt_free(s2);
}
/* 4. Free the resources */
xbt_dynar_free(&d);