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 as mycat) 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 or xbt_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_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_dfs: DFS exploration algorithm of the model-checker

      • mc_odpor_execution: ODPOR exploration algorithm of the model-checker

    • 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_ooo: Out-of-Order exploration algorithm of the model-checker

    • mc_record: Logging specific to MC record/replay facility

    • mc_reduction: Logging specific to the reduction algorithms

      • mc_odpor: Logging specific to the odpor reduction

    • mc_state: Logging specific to MC states

      • mc_sleepset: DFS exploration algorithm of the model-checker

      • mc_wutstate: DFS exploration algorithm of the model-checker

    • 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);