Alsa-Devel Archive on lore.kernel.org
 help / color / mirror / Atom feed
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;
}

----------------------------------------------------------------------

      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