Commit 1d0c29c0 authored by Jean-Claude BAU's avatar Jean-Claude BAU Committed by Adam Wujek

Optimization timeout generation

- Optimize the scheduler (main_loop) using system timer. It makes the
calculation of the timeout more precise  taking into account execution
time of some part of the code

- Optimize the L1SYNC sent messages too take into account the time spent
to send an frame
parent fbe6df4e
......@@ -13,6 +13,9 @@
#include <errno.h>
#include <sys/select.h>
#include <netinet/if_ether.h>
#include <signal.h>
#include <unistd.h>
#include <time.h>
#include <ppsi/ppsi.h>
#include <ppsi-wrs.h>
......@@ -86,10 +89,73 @@ static int run_all_state_machines(struct pp_globals *ppg)
return delay_ms;
}
static int alarmDetected=0;
static void sched_handler(int sig, siginfo_t *si, void *uc)
{
alarmDetected=1;
}
static void init_alarm(timer_t *timerid) {
struct sigevent sev;
struct sigaction sa;
/* Set the signal handler */
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = sched_handler;
sigemptyset(&sa.sa_mask);
if (sigaction(SIGALRM, &sa, NULL) == -1) {
fprintf(stderr, "ppsi: cannot set signal handler\n");
exit(1);
}
/* Create the timer */
sev.sigev_notify = SIGEV_SIGNAL;
sev.sigev_signo = SIGALRM;
sev.sigev_value.sival_ptr = timerid;
if (timer_create(CLOCK_MONOTONIC, &sev, timerid) == -1) {
fprintf(stderr, "ppsi: Cannot create timer\n");
exit(1);
}
}
static void start_alarm(timer_t *timerid, int delay_ms) {
struct itimerspec its;
its.it_value.tv_sec = delay_ms/1000;
its.it_value.tv_nsec = (delay_ms%1000) * 1000000;
its.it_interval.tv_sec =
its.it_interval.tv_nsec = 0;
if (timer_settime(*timerid, 0, &its, NULL) == -1){
fprintf(stderr, "ppsi: Cannot start timer\n");
}
}
static int stop_alarm(timer_t *timerid) {
struct itimerspec its;
struct itimerspec ito;
its.it_value.tv_sec =
its.it_value.tv_nsec =
its.it_interval.tv_sec =
its.it_interval.tv_nsec = 0;
if (timer_settime(*timerid, 0, &its, &ito) == -1){
fprintf(stderr, "ppsi: Cannot stop timer\n");
return 0;
}
return ito.it_value.tv_sec*1000+ito.it_value.tv_nsec/1000000;
}
void wrs_main_loop(struct pp_globals *ppg)
{
struct pp_instance *ppi;
int skipped_checks=0;
int delay_ms;
timer_t timerid;
int j;
/* Initialize each link's state machine */
......@@ -107,11 +173,25 @@ void wrs_main_loop(struct pp_globals *ppg)
delay_ms = run_all_state_machines(ppg);
while (1) {
int i;
/* Create the timer */
init_alarm(&timerid);
minipc_server_action(ppsi_ch, 10 /* ms */);
while (1) {
int packet_available;
/* Checking of received frames or minirpc are not done if the delay
* is 0 or the scheduling alarm is raised. These checks must be forced sometime
* (see skipped_checks)
*/
if ( !alarmDetected && (skipped_checks > 10 || delay_ms !=0) ) {
minipc_server_action(ppsi_ch, 1 /* ms */);
packet_available = wrs_net_ops.check_packet(ppg, delay_ms);
skipped_checks=0;
} else {
skipped_checks++;
packet_available=0;
}
#if 0
/*
* If Ebest was changed in previous loop, run best
* master clock before checking for new packets, which
......@@ -129,49 +209,61 @@ void wrs_main_loop(struct pp_globals *ppg)
}
ppg->ebest_updated = 0;
}
#endif
i = wrs_net_ops.check_packet(ppg, delay_ms);
if (i < 0)
continue;
if (i == 0) {
delay_ms = run_all_state_machines(ppg);
if ((packet_available<=0) && (alarmDetected || (delay_ms==0))) {
/* Time to run the state machine */
stop_alarm(&timerid); /* Clear previous alarm */
delay_ms = run_all_state_machines(ppg);
alarmDetected=0;
if ( delay_ms != 0 ) {
/* Start the alarm */
start_alarm(&timerid,delay_ms);
}
continue;
}
/* If delay_ms is -1, the above ops.check_packet will continue
* consuming the previous timeout (see its implementation).
* This ensures that every state machine is called at least once
* every delay_ms */
delay_ms = -1;
if (packet_available > 0 ) {
/* If delay_ms is -1, the above ops.check_packet will continue
* consuming the previous timeout (see its implementation).
* This ensures that every state machine is called at least once
* every delay_ms */
delay_ms = -1;
for (j = 0; j < ppg->nlinks; j++) {
int tmp_d,i;
ppi = INST(ppg, j);
for (j = 0; j < ppg->nlinks; j++) {
int tmp_d;
ppi = INST(ppg, j);
if ((ppi->ch[PP_NP_GEN].pkt_present) ||
(ppi->ch[PP_NP_EVT].pkt_present)) {
if ((ppi->ch[PP_NP_GEN].pkt_present) ||
(ppi->ch[PP_NP_EVT].pkt_present)) {
i = __recv_and_count(ppi, ppi->rx_frame,
PP_MAX_FRAME_LENGTH - 4,
&ppi->last_rcv_time);
i = __recv_and_count(ppi, ppi->rx_frame,
PP_MAX_FRAME_LENGTH - 4,
&ppi->last_rcv_time);
if (i == PP_RECV_DROP) {
continue; /* dropped or not for us */
}
if (i == -1) {
pp_diag(ppi, frames, 1, "Receive Error %i: %s\n",errno, strerror(errno));
continue;
}
if (i == PP_RECV_DROP) {
continue; /* dropped or not for us */
}
if (i == -1) {
pp_diag(ppi, frames, 1,
"Receive Error %i: %s\n",
errno, strerror(errno));
continue;
}
tmp_d = pp_state_machine(ppi, ppi->rx_ptp,
i - ppi->rx_offset);
tmp_d = pp_state_machine(ppi, ppi->rx_ptp,
i - ppi->rx_offset);
if ((delay_ms == -1) || (tmp_d < delay_ms))
delay_ms = tmp_d;
}
}
if ((delay_ms>0) && !alarmDetected ) {
int rem_delay_ms=stop_alarm(&timerid); /* Stop alarm and get remaining delay */
if ((delay_ms == -1) || (tmp_d < delay_ms))
delay_ms = tmp_d;
if ( rem_delay_ms < delay_ms) {
/* Re-adjust delay_ms */
delay_ms=rem_delay_ms;
}
alarmDetected=0;
start_alarm(&timerid,delay_ms); /* Start alarm */
}
}
}
......
......@@ -161,17 +161,50 @@ static inline Boolean le1_evt_LINK_OK(struct pp_instance *ppi) {
return L1E_DSPOR(ppi)->basic.L1SyncLinkAlive == TRUE;
}
#define pp_time_to_ms(ts) ts.secs * 1000 + ((ts.scaled_nsecs + 0x8000) >> TIME_INTERVAL_FRACBITS)/1000000
#define MEASURE_INIT_VALUE(x) {ppi->t_ops->get(ppi, &t);t.secs%=100;x=pp_time_to_ms(t);}
#define MEASURE_LAST_VALUE(x) {ppi->t_ops->get(ppi, &t);t.secs%=100;x=pp_time_to_ms(t);}
#define ADJUST_TIME_MS(a) {a+=100*1000;}
static __inline__ int measure_first_time(struct pp_instance *ppi) {
struct pp_time current_time;
int ms;
ppi->t_ops->get(ppi, &current_time);
ms=(current_time.secs&0xFFFF)*1000; /* do not take all second - Not necessary to calculate a difference*/
ms+=((current_time.scaled_nsecs + 0x8000) >> TIME_INTERVAL_FRACBITS)/1000000;
return ms;
}
static __inline__ int measure_last_time(struct pp_instance *ppi, int fmeas) {
int ms=measure_first_time(ppi);
if ( ms<fmeas ) {
/* Readjust the time */
ms+=0xFFFF*1000;
}
return ms;
}
static void l1e_send_sync_msg(struct pp_instance *ppi, Boolean immediatSend) {
if (pp_timeout(ppi, L1E_TIMEOUT_TX_SYNC) || immediatSend) {
int len;
int fmeas, lmeas;
int diff;
fmeas=measure_first_time(ppi);
pp_diag(ppi, ext, 1, "Sending L1SYNC_TLV signaling msg\n");
len = l1e_pack_signal(ppi);
__send_and_log(ppi, len, PP_NP_GEN,PPM_SIGNALING_NO_FWD_FMT);
lmeas=measure_last_time(ppi,fmeas);
diff=lmeas-fmeas;
/* Calculate when the next message should be sent */
/* A "diff" value is subtracted from the timer to take into account
* the execution time of this function. With small time-out like 64ms,
* the error become not negligible.
*/
__pp_timeout_set(ppi, L1E_TIMEOUT_TX_SYNC,
4 << (L1E_DSPOR_BS(ppi)->logL1SyncInterval + 8)); /* loop ever since */
(4 << (L1E_DSPOR_BS(ppi)->logL1SyncInterval + 8))-diff); /* loop ever since */
}
}
......
Markdown is supported
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