Span
The span component in Melon is used to measure C language function consumption. This module needs to be used together with the function
module, so it is also necessary to enable the function template through defining macro MLN_FUNC_FLAG
, thereby enabling function consumption tracing.
Currently supported consumption are as follows:
- time consumption
Header file
#include "mln_span.h"
Module
span
Functions/Macros
mln_span_start
mln_span_start();
Description: Start the measurement. This macro function sets the global variables used by the module and only tracks the functions called by the thread that calls this function during the measurement.
Note: This macro function needs to be called in the same scope as the mln_span_stop
macro function, or the call stack depth of the mln_span_stop
should be deeper than the call stack depth of the mln_span_start
. For example:
If there are three functions:
main
,foo
, andbar
, and their calling relationships are as follows:
void bar(void) { } void foo(void) { bar(); } int main(void) { foo(); return 0; }
If
mln_span_start
is called before thebar
call infoo
, thenmln_span_stop
should be called aftermln_span_start
infoo
or within thebar
function, but not inmain
.
Not following the above rules may lead to a situation where memory leaks could occur.
Return value: none
mln_span_stop
mln_span_stop();
Description: Stop the measurement. This macro function destroys some global variables within the module but retains the structure containing the measured values for this measurement. The timing of calling this macro function follows the description in mln_span_start
.
Return value: None
mln_span_release
mln_span_release();
Description: Release the structure containing the measured values for this measurement. Note: This macro function should be called after mln_span_stop
, otherwise, it may lead to memory access exceptions.
Return value: None
mln_span_move
mln_span_move();
Description: Retrieve the structure containing the measured values for this measurement and set the global pointer pointing to this structure to NULL
. Note: This macro function should be called after mln_span_stop
, otherwise, unpredictable errors may occur.
Return value: Pointer to mln_span_t
mln_span_dump
void mln_span_dump(mln_span_dump_cb_t cb, void *data);
typedef void (*mln_span_dump_cb_t)(mln_span_t *s, int level, void *data);
Description: Use a user-defined output function and auxiliary data to output the current measurement data. The meanings of the parameters of mln_span_dump_cb_t
are as follows:
s
: Pointer to the current traversed span node.level
: The current level of the span in the call stack (relative to the function call wheremln_span_start
is called).data
: User-defined data.
Return value: None.
mln_span_free
void mln_span_free(mln_span_t *s);
Description: Free the memory allocated for the mln_span_t
structure.
Return value: None
mln_span_file
mln_span_file(s);
Description: Get the filename of the specified span's location.
Return value: char *
pointer to the filename.
mln_span_func
mln_span_func(s);
Description: Get the function name referred to by the specified span.
Return value: char *
pointer to the function name.
mln_span_line
mln_span_line(s);
Description: Get the line number of the file referred to by the specified span.
Return value: int
representing the line number.
mln_span_time_cost
mln_span_time_cost(s);
Description: Get the duration of the measurement taken by the specified span, in microseconds.
Return value: mln_u64_t
representing the duration in microseconds.
Example
This is a multi-threading example demonstrating the usage of the mln_span
interfaces and its runtime behavior in a multi-threaded environment.
//a.c
#include <pthread.h>
#include "mln_span.h"
#include "mln_func.h"
#include "mln_log.h"
static void mln_span_dump_callback(mln_span_t *s, int level, void *data)
{
int i;
for (i = 0; i < level * 2; ++i) {
mln_log(none, " ");
}
mln_log(none, "| %s at %s:%d takes %U (us)\n", \
mln_span_func(s), mln_span_file(s), mln_span_line(s), mln_span_time_cost(s));
}
MLN_FUNC(, int, abc, (int a, int b), (a, b), {
return a + b;
})
MLN_FUNC(static, int, bcd, (int a, int b), (a, b), {
return abc(a, b) + abc(a, b);
})
MLN_FUNC(static, int, cde, (int a, int b), (a, b), {
return bcd(a, b) + bcd(a, b);
})
void *pentry(void *args)
{
int i;
mln_span_start();
for (i = 0; i < 10; ++i) {
cde(i, i + 1);
}
mln_span_stop();
mln_span_dump(mln_span_dump_callback, NULL);
mln_span_release();
return NULL;
}
int main(void)
{
int i;
pthread_t pth;
pthread_create(&pth, NULL, pentry, NULL);
for (i = 0; i < 10; ++i) {
bcd(i, i + 1);
}
pthread_join(pth, NULL);
return 0;
}
Compile the program:
cc -o a a.c -I /usr/local/melon/include/ -L /usr/local/melon/lib/ -lmelon -DMLN_FUNC_FLAG -lpthread
After execution, you should see the following output:
| pentry at a.c:32 takes 16 (us)
| cde at a.c:25 takes 2 (us)
| bcd at a.c:21 takes 1 (us)
| abc at a.c:17 takes 1 (us)
| abc at a.c:17 takes 0 (us)
| bcd at a.c:21 takes 0 (us)
| abc at a.c:17 takes 0 (us)
| abc at a.c:17 takes 0 (us)
| cde at a.c:25 takes 3 (us)
| bcd at a.c:21 takes 1 (us)
| abc at a.c:17 takes 0 (us)
| abc at a.c:17 takes 1 (us)
| bcd at a.c:21 takes 0 (us)
| abc at a.c:17 takes 0 (us)
| abc at a.c:17 takes 0 (us)
| cde at a.c:25 takes 1 (us)
| bcd at a.c:21 takes 1 (us)
| abc at a.c:17 takes 0 (us)
| abc at a.c:17 takes 0 (us)
| bcd at a.c:21 takes 0 (us)
| abc at a.c:17 takes 0 (us)
| abc at a.c:17 takes 0 (us)
| cde at a.c:25 takes 1 (us)
| bcd at a.c:21 takes 1 (us)
| abc at a.c:17 takes 1 (us)
| abc at a.c:17 takes 0 (us)
| bcd at a.c:21 takes 0 (us)
| abc at a.c:17 takes 0 (us)
| abc at a.c:17 takes 0 (us)
| cde at a.c:25 takes 1 (us)
| bcd at a.c:21 takes 1 (us)
| abc at a.c:17 takes 0 (us)
| abc at a.c:17 takes 0 (us)
| bcd at a.c:21 takes 0 (us)
| abc at a.c:17 takes 0 (us)
| abc at a.c:17 takes 0 (us)
| cde at a.c:25 takes 1 (us)
| bcd at a.c:21 takes 1 (us)
| abc at a.c:17 takes 0 (us)
| abc at a.c:17 takes 0 (us)
| bcd at a.c:21 takes 0 (us)
| abc at a.c:17 takes 0 (us)
| abc at a.c:17 takes 0 (us)
| cde at a.c:25 takes 3 (us)
| bcd at a.c:21 takes 2 (us)
| abc at a.c:17 takes 0 (us)
| abc at a.c:17 takes 0 (us)
| bcd at a.c:21 takes 1 (us)
| abc at a.c:17 takes 0 (us)
| abc at a.c:17 takes 0 (us)
| cde at a.c:25 takes 1 (us)
| bcd at a.c:21 takes 0 (us)
| abc at a.c:17 takes 0 (us)
| abc at a.c:17 takes 0 (us)
| bcd at a.c:21 takes 1 (us)
| abc at a.c:17 takes 0 (us)
| abc at a.c:17 takes 0 (us)
| cde at a.c:25 takes 1 (us)
| bcd at a.c:21 takes 0 (us)
| abc at a.c:17 takes 0 (us)
| abc at a.c:17 takes 0 (us)
| bcd at a.c:21 takes 1 (us)
| abc at a.c:17 takes 1 (us)
| abc at a.c:17 takes 0 (us)
| cde at a.c:25 takes 1 (us)
| bcd at a.c:21 takes 0 (us)
| abc at a.c:17 takes 0 (us)
| abc at a.c:17 takes 0 (us)
| bcd at a.c:21 takes 1 (us)
| abc at a.c:17 takes 0 (us)
| abc at a.c:17 takes 0 (us)