history_graph.cpp 6.6 KB
Newer Older
Arnaud Blanchard's avatar
Arnaud Blanchard committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#include "blc_program.h"
#include "graph.h"
#include <pthread.h>
#include <sys/time.h>
#include <unistd.h>

typedef struct history:blc_array{
    blc_array *array;
    
    void init_timer();
    void start_refresh_history_chars();
    void start_refresh_history_floats();
    int  compute_next_k();
    
    int sampling_period, iteration, length;
    size_t element_size;
    unsigned long initial_us;
}type_history;

pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;
int k;

void type_history::init_timer(){
    struct timeval initial_timer;
    
    gettimeofday(&initial_timer, NULL);
    length=dims[dims_nb-1].length;
    initial_us = initial_timer.tv_sec*1000000+initial_timer.tv_usec;
    k=length-1;
}

/**This is in order to take into acount the absolute time. If an iteration is longer than it should, the next one will be shorter.*/

int type_history::compute_next_k(){
    div_t samples_div;
    struct timeval timer;
    
    gettimeofday(&timer, NULL);
    
    //sample_div.quot is the theoritical iteration.
    samples_div=div(timer.tv_sec*1000000+timer.tv_usec-initial_us, sampling_period);
    
    //We try to stay in the midle of the iteration
    if ((int)(iteration-samples_div.quot) >= 0)  usleep((iteration+1-samples_div.quot)*sampling_period+sampling_period/2-samples_div.rem);
    
    iteration++;
    
    return div(samples_div.quot, length).rem;
}

void type_history::start_refresh_history_chars(){
    int i, next_k;
    
    while(1){
        next_k=compute_next_k();
        pthread_mutex_lock(&mutex);
        if(next_k==k+1){ //normal case
            FOR(i, array->total_length) chars[i*length+next_k]=array->chars[i];
        }
        else if ((next_k-k)>1){
            color_eprintf(BLC_BRIGHT_YELLOW, "Missing '%d' samples\n", next_k-k);
            FOR(i, array->total_length) memset(chars+i*length+k, array->chars[i], next_k-k+1);
        }
        else if (next_k==k){
            color_eprintf(BLC_BRIGHT_YELLOW, "Twice the same sample iteration %d\n", iteration);
        }
        else FOR(i, array->total_length){ //It accross the end of the buffer
            memset(chars+i*length+k, array->chars[i], length-k);
            memset(chars+i*length, array->chars[i], next_k+1);
        }
        k=next_k;
        pthread_mutex_unlock(&mutex);
    }
}

void type_history::start_refresh_history_floats(){
    int i, j, next_k;
    
    while(1){
        next_k=compute_next_k();
        pthread_mutex_lock(&mutex);
        if(next_k==k+1){ //normal case
            FOR(i, array->total_length) floats[i*length+next_k]=array->floats[i];
        }
        else if ((next_k-k)>1){
            color_eprintf(BLC_BRIGHT_YELLOW, "Missing '%d' samples\n", next_k-k);
            FOR(i, array->total_length) for(j=k; j!=next_k+1; j++) floats[i*length+j]=array->floats[i];
        }
        else if (next_k==k){
            color_eprintf(BLC_BRIGHT_YELLOW, "Twice the same sample iteration %d\n", iteration);
        }
        else FOR(i, array->total_length){ //It accross the end of the buffer
            for(j=k; j!=length; j++) floats[i*length+j]=array->floats[i];
            for(j=0; j!=next_k+1; j++) floats[i*length+j]=array->floats[i];
        }
        k=next_k;
        pthread_mutex_unlock(&mutex);
    }
}

static void *refresh_history_cb(void *history_pt){
    type_history *history=(type_history*)history_pt;
    
    history->init_timer();
    
    switch (history->type) {
        case 'UIN8': case 'INT8':
            history->start_refresh_history_chars();
            break;
        case 'FL32':
            history->start_refresh_history_floats();
            break;
        default:
            break;
    }
    return NULL;
}

119
void create_history_graph(blc_channel *input, char const *title, int history_length, int refresh_period, int sampling_period, float min, float max, char const *verbatim){
Arnaud Blanchard's avatar
Arnaud Blanchard committed
120
121
122
123
124
125
126
127
128
129
    char const *gnuplot_format=NULL;
    char command[LINE_MAX];
    
    char code;
    int i, offset, columns_nb=0;
    FILE *pipef;
    pthread_t thread;
    
    type_history history;
    
130
    switch (input->dims_nb){
Arnaud Blanchard's avatar
Arnaud Blanchard committed
131
132
133
134
        case 0:
            columns_nb=1;
            break;
        case 1:
135
            columns_nb=input->dims[0].length;
Arnaud Blanchard's avatar
Arnaud Blanchard committed
136
137
            break;
        default:
138
            EXIT_ON_ARRAY_ERROR(input, "Too many dims");
Arnaud Blanchard's avatar
Arnaud Blanchard committed
139
140
141
142
143
            break;
    }
    
    SYSTEM_ERROR_CHECK(pipef=popen("gnuplot", "w"), NULL, "Calling gnuplot");
    
144
    switch (input->type){
Arnaud Blanchard's avatar
Arnaud Blanchard committed
145
146
147
148
149
150
151
152
153
154
155
156
        case 'UIN8':
            gnuplot_format="%uchar";
            history.element_size=sizeof(uchar);
            break;
        case 'INT8':
            gnuplot_format="%char";
            history.element_size=sizeof(char);
            break;
        case 'FL32':
            gnuplot_format="%float";
            history.element_size=sizeof(float);
            break;
157
        default: EXIT_ON_ARRAY_ERROR(input, "The type is not managed");
Arnaud Blanchard's avatar
Arnaud Blanchard committed
158
159
160
161
    }
    
    init_term(pipef, title, verbatim);
    fprintf(pipef, "set xlabel 'time(s)'\n");
162
    
Arnaud Blanchard's avatar
Arnaud Blanchard committed
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
    
    if (min!=max) fprintf(pipef, "set yrange [%f:%f]\n", min, max);
    
    offset=snprintf(command, LINE_MAX, "plot  '-'  binary format='%s' record=%d using ($0*%f):1  title '%d' with %s",   gnuplot_format, history_length, sampling_period/1000000.f, 0, with_option);
    
    for(i=1; i!=columns_nb; i++){
        if (i<10) code=48+i; //01234567890
        else if (i<36) code=97+i-10; //abc...xyz
        else if (i<62) code=65+i-36; //ABC...XYZ
        else if (i==62) code='[';
        else if (i==63) code=']';
        else EXIT_ON_ERROR("Too many columns. You have '%d' max is 64", columns_nb);
        offset+=snprintf(command+offset, LINE_MAX-offset, ", '-'  binary format='%s' record=%d  u ($0*%f):1 t '%c' w %s", gnuplot_format, history_length, sampling_period/1000000.f, code, with_option);
    }
    
178
    history.init(input->type, input->format, 2, columns_nb, history_length);
Arnaud Blanchard's avatar
Arnaud Blanchard committed
179
    history.sampling_period=sampling_period;
180
    history.array=input;
Arnaud Blanchard's avatar
Arnaud Blanchard committed
181
182
183
    
    pthread_create(&thread, NULL, refresh_history_cb, &history);
    
184
185
186
    blc_loop_try_add_waiting_semaphore(input->sem_new_data);
    blc_loop_try_add_posting_semaphore(input->sem_ack_data);

Arnaud Blanchard's avatar
Arnaud Blanchard committed
187
188
189
190
191
192
193
194
195
196
197
198
    BLC_COMMAND_LOOP(refresh_period){
        fprintf(pipef, "\n%s\n", command);
        FOR(i, columns_nb){
            pthread_mutex_lock(&mutex);
            SYSTEM_ERROR_CHECK(fwrite(&history.chars[(i*history_length+k+1)*history.element_size], history.element_size, history_length-k-1, pipef), -1, NULL);
            SYSTEM_ERROR_CHECK(fwrite(&history.chars[(i*history_length)*history.element_size], history.element_size, k+1, pipef), -1, NULL);
            pthread_mutex_unlock(&mutex);
        }
        SYSTEM_ERROR_CHECK(fflush(pipef), -1, NULL);
    }
    SYSTEM_ERROR_CHECK(fclose(pipef), -1, NULL);
}