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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.