[alsa-devel] need help with io plugin programming: how to add delay ?
Stefan Schoenleitner
dev.c0debabe at gmail.com
Wed Dec 23 09:55:29 CET 2009
Hi,
I tracked down the timing problem even more and write another piece of testing code (see below).
The code should just do something each 20ms.
I discovered that using printf() in critical section is not a good idea as it introduces
unwanted delay that is not calculated in the timeout.
You can test it by setting DO_PRINTF to 1.
However, if no printf()'s are performed I still do not get a precise delay of 20ms +/- 1ms (even with realtime priority).
See example output here:
----------------------------------------------------------------------
$ sudo nice -n-19 ./test-timer
delay[ 0]: 0.007194ms
delay[ 1]: 21.125031ms --> thats too long :(
delay[ 2]: 20.112892ms
delay[ 3]: 20.113100ms
delay[ 4]: 20.121551ms
delay[ 5]: 22.959203ms --> thats too long :(
delay[ 6]: 20.131611ms
delay[ 7]: 20.145507ms
delay[ 8]: 20.131889ms
delay[ 9]: 20.145649ms
delay[10]: 20.142365ms
----------------------------------------------------------------------
* How can I deal with the problem ?
* Where does the unwanted delay come from ?
cheers,
stefan
---------------------------- timer-test.c ----------------------------
#define _POSIX_C_SOURCE 199309L
#define _BSD_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include <poll.h>
#include <assert.h>
#define DELAYSTAMPS 30
#define DO_PRINTF 0
/* adapted from glibc sys/time.h timersub() macro */
#define priv_timespecsub(a, b, result) \
do { \
(result)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
(result)->tv_nsec = (a)->tv_nsec - (b)->tv_nsec; \
if ((result)->tv_nsec < 0) { \
--(result)->tv_sec; \
(result)->tv_nsec += 1000000000; \
} \
} while (0)
#define priv_timespecadd(a, b, result) \
do { \
(result)->tv_sec = (a)->tv_sec + (b)->tv_sec; \
(result)->tv_nsec = (a)->tv_nsec + (b)->tv_nsec; \
if ((result)->tv_nsec >=1000000000L) { \
++(result)->tv_sec; \
(result)->tv_nsec -= 1000000000L; \
} \
} while (0)
pthread_mutex_t timer_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t timer_condition = PTHREAD_COND_INITIALIZER;
int main(void)
{
int t, len, ret;
struct timespec start, now, period_time, delta, timeout;
struct timespec prev, delta_prev;
double delaystamps[DELAYSTAMPS];
int i;
// one period is 20ms
period_time.tv_sec=0;
period_time.tv_nsec = 20 * 1000000L;
start.tv_sec=0;
start.tv_nsec=0;
clock_gettime(CLOCK_REALTIME, &start);
for (i=0; i<DELAYSTAMPS; i++)
{
memcpy(&prev, &start, sizeof(struct timespec));
clock_gettime(CLOCK_REALTIME, &start);
priv_timespecadd(&start, &period_time, &timeout);
//printf("timeout at %li:%li\n", timeout.tv_sec, timeout.tv_nsec/1000000L);
priv_timespecsub(&start, &prev, &delta_prev);
#if (DO_PRINTF==1)
printf("last action %fms ago\n", delta_prev.tv_sec*1000.0 + delta_prev.tv_nsec/1000000.0);
#endif
delaystamps[i]=delta_prev.tv_sec*1000.0 + delta_prev.tv_nsec/1000000.0;
// -------------------------- BEGIN PROCESSING BLOCK --------------------------
// process data (requires some amount of time)
usleep(10000);
// -------------------------- END PROCESSING BLOCK --------------------------
// sleep for the rest of the time until the period is over
clock_gettime(CLOCK_REALTIME, &now);
priv_timespecsub(&timeout, &now, &delta);
if ((now.tv_sec >= timeout.tv_sec) && (now.tv_nsec >= timeout.tv_nsec))
{
//printf("we're late, don't sleep\n");
}
else
{
#if (DO_PRINTF==1)
printf("sleeping for %lims\n", delta.tv_sec*1000 + delta.tv_nsec/1000000L);
#endif
//nanosleep(&delta, NULL);
// wait for timeout using a fake pthread condition which is never signaled
pthread_mutex_lock(&timer_mutex);
pthread_cond_timedwait(&timer_condition, &timer_mutex, &timeout);
pthread_mutex_unlock(&timer_mutex);
}
}
// print delay timestamps
for (i=0; i<DELAYSTAMPS; i++)
{
printf("delay[%2i]: %fms", i, delaystamps[i]);
if (delaystamps[i] > 21)
printf("\t--> thats too long :(");
printf("\n");
}
return 0;
}
----------------------------------------------------------------------
More information about the Alsa-devel
mailing list