Commit 7e616c84 authored by Arnaud Blanchard's avatar Arnaud Blanchard
Browse files

Add functionalities to save to save profiling data, change the way the name is generated

parent 92f64eac
......@@ -28,22 +28,22 @@ Few functions helping for pseudo realtime applications.
#include "blc_tools.h"
#define BLC_COMMAND_LOOP_THREAD() for(blc_command_loop_init(-2); blc_command_loop_start();blc_command_loop_end())
0 for system as fast as possible, -1 for blocking on keyborad.
period in microseconds
0 for system as fast as possible, -1 for blocking on keyborad, -2 blocking after first iteration.
Warning the period can be till 10ms longer than, asked. Problem of usleep/nano sleep */
#define BLC_COMMAND_LOOP(period) for(blc_command_loop_init(period); blc_command_loop_start();blc_command_loop_end())
typedef enum {BLC_QUIT=0, BLC_RUN, BLC_PAUSE} type_blc_status;
typedef enum {BLC_QUIT=0, BLC_RUN, BLC_PAUSE, BLC_STEPS} type_blc_status;
typedef void (*type_blc_command_cb)(char const *argument, void *user_data);
extern int blc_input_terminal, blc_output_terminal;
extern type_blc_status blc_status;
extern int blc_loop_iteration;
extern uint64_t blc_loop_iteration;
extern uint64_t blc_loop_iteration_limit;
extern long blc_command_loop_period;
extern FILE *blc_profile_file;
......@@ -58,6 +58,9 @@ void pause_cb();
///Add a command in the list of possible command lines from the user.
void blc_command_add(const char *command_name, type_blc_command_cb callback, const char *prompt, const char *help, void *user_data);
///Remove a previously added command
void blc_command_remove(const char *command_name);
///Interpret the command passed in string.
void blc_command_interpret_string(char const *input_string, size_t size);
......@@ -98,7 +101,10 @@ void blc_loop_add_posting_semaphore(void *semaphore);
/**The loop willt start only once the waiting_callback callback will be executed.
The waiting time does not count is the loop timing*/
void blc_loop_add_waiting_callback( void(*waiting_callback)(void*), void *user_data);
/// Loop period in ms. If loop period = BLC_LOOP_NON_STOP the system is as fast as possible, if it is BLC_LOOP_BLOCK , it is command with return on stdin. If itis BLC_LLOP_THREAD it starts a parrallel thread to interpret command. In this latter case do not use stdin yourself.
/** Loop period in ms.
- 0 the system is as fast as possible
- -1 it blocks on keyboard
- -2 it blocks on keyboard after a first iteration*/
void blc_command_loop_init(long loop_period);
int blc_command_loop_start();
void blc_command_loop_end();
......@@ -29,20 +29,8 @@
#include "blc_core.h"
#include "blc_command.h"
///Add an argument to the list argv of arguments. Add eventually a value as well.
void blc_add_arg( int *argc, char ***argv, char const *arg, char const *value);
///Allocate and fill a command line with the array of argument. The array must be terminated by a NULL argument and must the returned command line me be freed after use.
///It does not handle spaces in argument !!!
char *blc_create_command_line_from_argv(char const *const *argv);
///Allocate and fill an array of argument by spiting the command_line. The array is terminated by a NULL argument and it must be freed after used.
///It does not handle spaces in argument !!!
char * const*blc_create_argv_from_command_line(char const *command_line);
///Set the desciption of the program used for help. A copy of desciption is done (strdup).
void blc_program_set_description(char const *description);
......@@ -102,6 +102,18 @@ void blc_command_add(const char *command_name, type_blc_command_cb callback, con
APPEND_ITEM(&blc_commands, &blc_commands_nb, &tmp_command);
void blc_command_remove(const char *command_name){
int i;
FOR_INV(i, blc_commands_nb){
if (strcmp(blc_commands[i].name, command_name) == 0) break;
if (i==-1) EXIT_ON_ERROR("You try to remove a command '%s' that does not exist", command_name);
REMOVE_ITEM(&blc_commands, &blc_commands_nb, i);
void blc_command_interpret_string(char const *input_string, size_t size){
char const*parameter;
char *parameter2;
......@@ -110,7 +122,7 @@ void blc_command_interpret_string(char const *input_string, size_t size){
const blc_command *command;
size_t name_size, line_capability=0;
FOR_EACH_INV(command, blc_commands, blc_commands_nb){
FOR_EACH(command, blc_commands, blc_commands_nb){
name_size = strlen(command->name);
if (strncmp(command->name, input_string, name_size) == 0){
parameter = input_string + name_size;
......@@ -122,19 +134,26 @@ void blc_command_interpret_string(char const *input_string, size_t size){
parameter2_size = getline(&parameter2, &line_capability, stdin)-1;
if (command->callback) command->callback(parameter2, command->user_data); //In which callback is NULL ??
if (command->callback == NULL) EXIT_ON_ERROR("Command callback is NULL for command '%s'", command->name);
command->callback(parameter2, command->user_data);
break; //Command has been found
if ((command->prompt != NULL) && (command->prompt[0]!='|')) continue; // If we do not wait for parameter, the command must be exact.
else command->callback(parameter, command->user_data);
//A parameter was expected
if (command->prompt) {
command->callback(parameter, command->user_data);
else continue; //Maybe it is a command with a longer name, we continue to check
/* if ((command->prompt != NULL) && (command->prompt[0]!='|')) continue; // If we do not wait for parameter, the command must be exact.
if (command < blc_commands) fprintf(stderr, "%s: unknown command in: '%s'\n", blc_program_name, input_string);
if (command == blc_commands+blc_commands_nb) fprintf(stderr, "%s: unknown command in: '%s'\n", blc_program_name, input_string);
void blc_command_interpret_block(){
......@@ -158,7 +177,6 @@ void blc_command_interpret_block(){
line[line_size]=0; // Removing the last return char (\n)
blc_command_interpret_string(line, line_size);
......@@ -3,6 +3,8 @@
#include "blc_realtime.h"
#include <unistd.h> //sleep
#include <errno.h> //errno
#include <math.h> //pthread_mutex
#include <time.h> //nanosleep
#include <sys/time.h> //gettimeofday
#include <pthread.h> //pthread_mutex
......@@ -16,7 +18,8 @@ static long blc_current_duration;
static int intermediate_iteration;
long blc_command_loop_period=-2; //unitialised
int blc_loop_iteration;
uint64_t blc_loop_iteration_limit=UINT64_MAX;
uint64_t blc_loop_iteration=0;
static void(**waiting_callbacks)(void*)=NULL;
static void **waiting_callabacks_user_data=NULL;
......@@ -31,6 +34,11 @@ static int posting_semaphores_nb;
static pthread_t loop_thread, loop_check_stuck_thread;
static pthread_mutex_t mutex_lock_keyboard=PTHREAD_MUTEX_INITIALIZER;
static int step_iteration;
static struct timeval step_timer, profile_timer;
static sem_t *blocking_semaphore=NULL;
#include "blc_program.h"
type_blc_status blc_status=BLC_RUN;
......@@ -38,7 +46,7 @@ type_blc_status blc_status=BLC_RUN;
void blc_fprint_stats(FILE *file)
if (intermediate_iteration){
fprintf(file, "%s: %d iterations, average duration: %.3fms [%.3f, %.3f], average frequency: %.3fHz period: %.3fms\n", blc_program_name, intermediate_iteration, blc_duration/(1000.f*intermediate_iteration), blc_duration_min/1000., blc_duration_max/1000., 1e6*intermediate_iteration/(double)blc_period, blc_period/(1000.*intermediate_iteration));
fprintf(file, "%-16.16s %4d iterations duration:%8.3fms[%8.3f, %8.3f] frequency:%8.3fHz period:%8.3fms\n", blc_program_name, intermediate_iteration, blc_duration/(1000.f*intermediate_iteration), blc_duration_min/1000., blc_duration_max/1000., 1e6*intermediate_iteration/(double)blc_period, blc_period/(1000.*intermediate_iteration));
......@@ -84,37 +92,77 @@ void blc_loop_add_posting_semaphore(void *semaphore){
if (blc_loop_try_add_posting_semaphore(semaphore)==0) EXIT_ON_ERROR("The semaphore you want to add is NULL");
void blc_command_send_to_stdout(char const *argument){
//We send the argument to stdout if it is not a terminal
static void blc_command_send_to_stdout(char const *argument){
if (blc_output_terminal==0){
if (argument) SYSTEM_ERROR_CHECK(printf("%s", argument), -1, NULL);
SYSTEM_ERROR_CHECK(printf("\n"), -1, NULL);
SYSTEM_ERROR_CHECK(fflush(stdout), -1, NULL);
//We execute the argument and send it with prefix '&' to stdout if it is not a terminal
static void blc_command_send_to_all(char const *argument){
blc_command_interpret_string(argument, strlen(argument));
if (blc_output_terminal==0){
if (argument) SYSTEM_ERROR_CHECK(printf("&%s", argument), -1, NULL);
SYSTEM_ERROR_CHECK(printf("\n"), -1, NULL);
SYSTEM_ERROR_CHECK(fflush(stdout), -1, NULL);
void blc_command_ask_quit(){
sem_t **sem;
if (blc_status==BLC_PAUSE) BLC_PTHREAD_CHECK(pthread_mutex_unlock(&mutex_lock_keyboard), NULL);
if (blc_status==BLC_PAUSE) BLC_PTHREAD_CHECK(pthread_mutex_unlock(&mutex_lock_keyboard), NULL);
if (blc_status!=BLC_STEPS) blc_status=BLC_QUIT;
FOR_EACH(sem, waiting_semaphores, waiting_semaphores_nb ){
while (sem_trywait(*sem)!=0){
if (errno==EAGAIN) sem_post(*sem);
else EXIT_ON_SYSTEM_ERROR("unlocking semaphore");
if (blocking_semaphore){
if (sem_trywait(blocking_semaphore)==0){
sem_post(blocking_semaphore); // we succeed, it was not a problem, I free it.
else if (errno==EAGAIN) sem_post(blocking_semaphore);
else EXIT_ON_SYSTEM_ERROR("unlocking semaphore for quitting");
static void step_forward_cb(const char* steps_nb_str, void*){
int steps_nb, pos;
if (steps_nb_str){
if (sscanf(steps_nb_str, "%d%n", &steps_nb, &pos)!=1 || pos !=strlen(steps_nb_str) || steps_nb<1){
color_eprintf(BLC_YELLOW, "'%s' is not a valid step number\n", steps_nb_str);
else {
BLC_PTHREAD_CHECK(pthread_mutex_unlock(&mutex_lock_keyboard), NULL);
else {
BLC_PTHREAD_CHECK(pthread_mutex_unlock(&mutex_lock_keyboard), NULL);
void pause_cb()
if (blc_status==BLC_RUN){
if (blc_status==BLC_RUN || blc_status==BLC_STEPS){
fprintf(stderr, "=== %s: pause ===\n", blc_program_name);
}else {
blc_command_add(">", step_forward_cb, "|iterations", "continue for steps nb iterations", NULL);
fprintf(stderr, "=== %s: pause iteration %lld === '' to continue, '>[<nb>]' to step one or run nb iterations ===\n", blc_program_name, blc_loop_iteration);
}else if (blc_status==BLC_PAUSE){
fprintf(stderr, "=== %s: continue === \n", blc_program_name);
BLC_PTHREAD_CHECK(pthread_mutex_unlock(&mutex_lock_keyboard), NULL);
fprintf(stderr, "=== %s: running ===\n", blc_program_name);
else EXIT_ON_ERROR("Unknown status '%d'", blc_status);
static void *loop_check_stuck(void*){
......@@ -129,6 +177,7 @@ static void *loop_check_stuck(void*){
if(blc_status==BLC_RUN){ //in BLC_PAUSE it is normal to block
if (iteration==blc_loop_iteration) {
color_eprintf(BLC_YELLOW, "'%s' seems blocked on iteration '%d'. The loop has been stopped for more than %ds\n", blc_program_name, iteration, checking_time);
if (blc_profile_file) fflush(blc_profile_file); //It may help for debuggage
else if (was_stucked) {
......@@ -151,15 +200,16 @@ static void *command_thread_interpret_loop(void *){
return NULL;
void blc_command_loop_init(long loop_period)
if (blc_command_loop_period!=-2) EXIT_ON_ERROR("You already launch a loop");
void blc_command_loop_init(long loop_period){
if (blc_command_loop_period==-3) EXIT_ON_ERROR("You already are in a blc_command_loop");
BLC_PTHREAD_CHECK(pthread_mutex_lock(&mutex_lock_keyboard), NULL);
if (blc_command_loop_period==-2){
else BLC_PTHREAD_CHECK(pthread_mutex_lock(&mutex_lock_keyboard), NULL);
if (blc_input_terminal){
blc_command_display_help(); //We display help only for keyboard
......@@ -169,32 +219,44 @@ void blc_command_loop_init(long loop_period)
blc_command_add("h", (type_blc_command_cb)blc_command_display_help, NULL, "display this help", NULL);
blc_command_add("q", (type_blc_command_cb)blc_command_ask_quit, NULL, "quit the application", NULL);
if (loop_period!=-1) { //we lock on keyboard. But if the program lock we still read keyboard
if (blc_command_loop_period!=-1) { //we lock on keyboard. But if the program lock we still read keyboard
SYSTEM_ERROR_CHECK(pthread_create(&loop_check_stuck_thread, NULL, loop_check_stuck, NULL), -1, NULL);
blc_command_add("s", (type_blc_command_cb)display_stats, NULL, "display time stats", NULL); //We did not do stat on keyboard
fprintf(stderr, "=== %s: running ===\n", blc_program_name);
blc_command_add("|", (type_blc_command_cb)blc_command_send_to_stdout, "|text", "send the text to stdout", NULL);
blc_command_add("|", (type_blc_command_cb)blc_command_send_to_stdout, "command", "send the command to stdout", NULL);
blc_command_add("&", (type_blc_command_cb)blc_command_send_to_all, "command", "intepret caommdn and send it to stdout", NULL);
SYSTEM_ERROR_CHECK(pthread_create(&loop_thread, NULL, command_thread_interpret_loop, NULL), -1, NULL);
int blc_command_loop_start(){
int i;
if (blc_profile_file) gettimeofday(&profile_timer, NULL);
//We wait before counting the duration time as the time for waiting does not matter
if (blc_loop_iteration==blc_loop_iteration_limit){
fprintf(stderr, "%s: %d iterations executed in %.3fms\n", blc_program_name, (int)blc_loop_iteration-step_iteration, blc_us_time_diff(&step_timer)/1000.f);
//We eventiualy wait for keyboard return key
if ((blc_status==BLC_PAUSE) || (blc_command_loop_period==-1)) BLC_PTHREAD_CHECK(pthread_mutex_lock(&mutex_lock_keyboard), NULL);
else if (blc_status==BLC_RUN){
else if (blc_status==BLC_RUN){
//We wait for semaphore
FOR(i, waiting_semaphores_nb) SYSTEM_ERROR_CHECK(sem_wait(waiting_semaphores[i]), -1, NULL);
FOR(i, waiting_semaphores_nb) {
SYSTEM_ERROR_CHECK(sem_wait(blocking_semaphore), -1, NULL);
//Waiting general user defined callbacks
FOR(i, waiting_callbacks_nb) waiting_callbacks[i](waiting_callabacks_user_data[i]);
else blc_command_loop_period=-2; //In case we start another loop after
else blc_command_loop_period=-3; //In case we start another loop after
//We start counting the duration time
if (intermediate_iteration==0) blc_us_time_diff(&timer);
......@@ -207,11 +269,16 @@ void blc_command_loop_end(){
div_t ratio;
struct timespec time_left, tmp_rem;
int diff, i;
uint64_t start_time;
if (blc_profile_file) start_time=timer.tv_sec*1000000+timer.tv_usec;
if (blc_profile_file) fprintf(blc_profile_file, "%ld\t%lld\t%lu\t\n",profile_timer.tv_sec*1000000+profile_timer.tv_usec, start_time, blc_current_duration);
// fflush(stderr);
//We post the semaphore usualy to say the data is ready to read
FOR(i, posting_semaphores_nb) SYSTEM_ERROR_CHECK(sem_post(posting_semaphores[i]), -1, NULL);
if (blc_current_duration<blc_duration_min) blc_duration_min=blc_current_duration;
......@@ -89,44 +89,6 @@ static struct program_parameter *blc_program_parameters=NULL;
static int blc_program_parameters_nb;
void blc_add_arg( int *argc, char ***argv, char const *arg, char const *value){
APPEND_ITEM(argv, argc, &arg);
if (value!=NULL) APPEND_ITEM(argv, argc, &value);
char *blc_create_command_line_from_argv(char const *const *argv){
int command_line_size, i;
char *command_line, *pos;
for(i=0; argv[i] != NULL; i++) command_line_size+=strlen(argv[i])+1; // + 1 for the space
command_line=MANY_ALLOCATIONS(command_line_size+1, char);
for(i=0; argv[i] != NULL; i++)
pos+=sprintf(pos, "%s ", argv[i]);
return command_line;
char * const*blc_create_argv_from_command_line(char const *command_line)
char * const*argv=NULL;
char *arg_pt;
char const *pos;
char tmp_arg[NAME_MAX+1];
int length, argc=0;
while(sscanf(pos, SCAN_CONV(NAME_MAX, "s")"%n", tmp_arg, &length)==1)
arg_pt = strdup(tmp_arg);
APPEND_ITEM(&argv, &argc, &arg_pt);
APPEND_ITEM(&argv, &argc, &arg_pt);
return argv;
void blc_program_set_description(char const *description)
......@@ -162,6 +124,8 @@ void blc_program_add_multiple_parameters(char ***result_list, char const *name,
void blc_program_add_option(char const **result, char letter, char const *long_option, char const *parameter, char const *help, char const* default_value){
type_program_option tmp_program_option;
// if ((parameter) && (default_value)) EXIT_ON_ERROR("option '%s': you cannot required an parameter '%s' and having a default value '%s'", long_option, parameter, default_value);
tmp_program_option.type = STRING;
tmp_program_option.string_pt = result;
......@@ -212,6 +176,7 @@ static void blc_program_option_interpret(int *argc, char **argv[])
type_program_option *program_option;
char pipe_name[PATH_MAX+1];
//We store enough room for all the optional letters + ':' + terminating null char
optstring = MANY_ALLOCATIONS(blc_program_options_nb*2+1, char);
......@@ -362,18 +327,13 @@ static void blc_program_interpret_parameters(int *argc, char **argv[]){
void blc_program_parse_args(int *argc, char ***argv){
if (blc_program_name==NULL) blc_program_name = basename((*argv)[0]);
blc_program_option_interpret(argc, argv);
blc_program_interpret_parameters(argc, argv);
void blc_program_parse_args_and_print_title(int *argc, char ***argv){
if (blc_program_name==NULL) blc_program_name = basename((*argv)[0]);
underline_fprintf('=', stderr, blc_program_name);
blc_program_parse_args(argc, argv);
/*Display format as python argparse*/
Display help:
usage: t_parse_args [-f] [-s string] string [string]
......@@ -7,9 +7,7 @@ usage: t_parse_args [-f] [-s string] string [string]
Program to show how to parse arguments.
positional arguments:
string Required parameter
string Show how to accept simple text as option
string Required parameter string Show how to accept simple text as option
optional arguments:
-f, --flag Show how to read a flag
-s, --simple string Simple text as option (default: Default text)
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment