From: Stefan Schoenleitner <dev.c0debabe@gmail.com>
To: alsa-devel <alsa-devel@alsa-project.org>
Subject: Re: need help with io plugin programming: how to add delay ?
Date: Wed, 23 Dec 2009 09:55:29 +0100 [thread overview]
Message-ID: <4B31DB01.4050308@gmail.com> (raw)
In-Reply-To: <53baa24a0912221814t3e8628c4odc908c0813c0a56b@mail.gmail.com>
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;
}
----------------------------------------------------------------------
prev parent reply other threads:[~2009-12-23 8:55 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2009-12-22 19:55 need help with io plugin programming: how to add delay ? Stefan Schoenleitner
2009-12-22 23:08 ` Stefan Schoenleitner
2009-12-23 2:14 ` Alex Austin
2009-12-23 8:15 ` Stefan Schoenleitner
2009-12-23 9:28 ` Alex Austin
2009-12-23 11:17 ` Stefan Schoenleitner
2009-12-23 16:39 ` Mads Kiilerich
2009-12-23 17:08 ` Stefan Schoenleitner
2009-12-23 17:40 ` Mark Brown
2009-12-23 18:24 ` Stefan Schoenleitner
2009-12-23 17:09 ` Mark Brown
2009-12-23 8:55 ` Stefan Schoenleitner [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4B31DB01.4050308@gmail.com \
--to=dev.c0debabe@gmail.com \
--cc=alsa-devel@alsa-project.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox