|
Packit Service |
db8eaa |
/*
|
|
Packit Service |
db8eaa |
* simple multi-thread stress test for PCM
|
|
Packit Service |
db8eaa |
*
|
|
Packit Service |
db8eaa |
* The main thread simply feeds or reads the sample data with the
|
|
Packit Service |
db8eaa |
* random size continuously. Meanwhile, the worker threads call some
|
|
Packit Service |
db8eaa |
* update function depending on the given mode, and show the thread
|
|
Packit Service |
db8eaa |
* number of the read value.
|
|
Packit Service |
db8eaa |
*
|
|
Packit Service |
db8eaa |
* The function for the worker thread is specified via -m option.
|
|
Packit Service |
db8eaa |
* When the random mode ('r') is set, the update function is chosen
|
|
Packit Service |
db8eaa |
* randomly in the loop.
|
|
Packit Service |
db8eaa |
*
|
|
Packit Service |
db8eaa |
* When the -v option is passed, this tries to show some obtained value
|
|
Packit Service |
db8eaa |
* from the function. Without -v, as default, it shows the thread number
|
|
Packit Service |
db8eaa |
* (0-9). In addition, it puts the mode suffix ('a' for avail, 'd' for
|
|
Packit Service |
db8eaa |
* delay, etc) for the random mode, as well as the suffix '!' indicating
|
|
Packit Service |
db8eaa |
* the error from the called function.
|
|
Packit Service |
db8eaa |
*/
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
#include <stdio.h>
|
|
Packit Service |
db8eaa |
#include <pthread.h>
|
|
Packit Service |
db8eaa |
#include <getopt.h>
|
|
Packit Service |
db8eaa |
#include "../include/asoundlib.h"
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
#define MAX_THREADS 10
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
enum {
|
|
Packit Service |
db8eaa |
MODE_AVAIL_UPDATE,
|
|
Packit Service |
db8eaa |
MODE_STATUS,
|
|
Packit Service |
db8eaa |
MODE_HWSYNC,
|
|
Packit Service |
db8eaa |
MODE_TIMESTAMP,
|
|
Packit Service |
db8eaa |
MODE_DELAY,
|
|
Packit Service |
db8eaa |
MODE_RANDOM
|
|
Packit Service |
db8eaa |
};
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static char mode_suffix[] = {
|
|
Packit Service |
db8eaa |
'a', 's', 'h', 't', 'd', 'r'
|
|
Packit Service |
db8eaa |
};
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static const char *devname = "default";
|
|
Packit Service |
db8eaa |
static int stream = SND_PCM_STREAM_PLAYBACK;
|
|
Packit Service |
db8eaa |
static int num_threads = 1;
|
|
Packit Service |
db8eaa |
static int periodsize = 16 * 1024;
|
|
Packit Service |
db8eaa |
static int bufsize = 16 * 1024 * 4;
|
|
Packit Service |
db8eaa |
static int channels = 2;
|
|
Packit Service |
db8eaa |
static int rate = 48000;
|
|
Packit Service |
db8eaa |
static snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int running_mode = MODE_AVAIL_UPDATE;
|
|
Packit Service |
db8eaa |
static int show_value = 0;
|
|
Packit Service |
db8eaa |
static int quiet = 0;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static pthread_t peeper_threads[MAX_THREADS];
|
|
Packit Service |
db8eaa |
static int running = 1;
|
|
Packit Service |
db8eaa |
static snd_pcm_t *pcm;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static void *peeper(void *data)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
int thread_no = (long)data;
|
|
Packit Service |
db8eaa |
snd_pcm_sframes_t val;
|
|
Packit Service |
db8eaa |
snd_pcm_status_t *stat;
|
|
Packit Service |
db8eaa |
snd_htimestamp_t tstamp;
|
|
Packit Service |
db8eaa |
int mode = running_mode, err;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
snd_pcm_status_alloca(&stat;;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
while (running) {
|
|
Packit Service |
db8eaa |
if (running_mode == MODE_RANDOM)
|
|
Packit Service |
db8eaa |
mode = rand() % MODE_RANDOM;
|
|
Packit Service |
db8eaa |
switch (mode) {
|
|
Packit Service |
db8eaa |
case MODE_AVAIL_UPDATE:
|
|
Packit Service |
db8eaa |
val = snd_pcm_avail_update(pcm);
|
|
Packit Service |
db8eaa |
err = 0;
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
case MODE_STATUS:
|
|
Packit Service |
db8eaa |
err = snd_pcm_status(pcm, stat);
|
|
Packit Service |
db8eaa |
val = snd_pcm_status_get_avail(stat);
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
case MODE_HWSYNC:
|
|
Packit Service |
db8eaa |
err = snd_pcm_hwsync(pcm);
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
case MODE_TIMESTAMP:
|
|
Packit Service |
db8eaa |
err = snd_pcm_htimestamp(pcm, (snd_pcm_uframes_t *)&val,
|
|
Packit Service |
db8eaa |
&tstamp);
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
default:
|
|
Packit Service |
db8eaa |
err = snd_pcm_delay(pcm, &val;;
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
if (quiet)
|
|
Packit Service |
db8eaa |
continue;
|
|
Packit Service |
db8eaa |
if (running_mode == MODE_RANDOM) {
|
|
Packit Service |
db8eaa |
fprintf(stderr, "%d%c%s", thread_no, mode_suffix[mode],
|
|
Packit Service |
db8eaa |
err ? "!" : "");
|
|
Packit Service |
db8eaa |
} else {
|
|
Packit Service |
db8eaa |
if (show_value && mode != MODE_HWSYNC)
|
|
Packit Service |
db8eaa |
fprintf(stderr, "\r%d ", (int)val);
|
|
Packit Service |
db8eaa |
else
|
|
Packit Service |
db8eaa |
fprintf(stderr, "%d%s", thread_no,
|
|
Packit Service |
db8eaa |
err ? "!" : "");
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
return NULL;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static void usage(void)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
fprintf(stderr, "usage: multi-thread [-options]\n");
|
|
Packit Service |
db8eaa |
fprintf(stderr, " -D str Set device name\n");
|
|
Packit Service |
db8eaa |
fprintf(stderr, " -r val Set sample rate\n");
|
|
Packit Service |
db8eaa |
fprintf(stderr, " -p val Set period size (in frame)\n");
|
|
Packit Service |
db8eaa |
fprintf(stderr, " -b val Set buffer size (in frame)\n");
|
|
Packit Service |
db8eaa |
fprintf(stderr, " -c val Set number of channels\n");
|
|
Packit Service |
db8eaa |
fprintf(stderr, " -f str Set PCM format\n");
|
|
Packit Service |
db8eaa |
fprintf(stderr, " -s str Set stream direction (playback or capture)\n");
|
|
Packit Service |
db8eaa |
fprintf(stderr, " -t val Set number of threads\n");
|
|
Packit Service |
db8eaa |
fprintf(stderr, " -m str Running mode (avail, status, hwsync, timestamp, delay, random)\n");
|
|
Packit Service |
db8eaa |
fprintf(stderr, " -v Show value\n");
|
|
Packit Service |
db8eaa |
fprintf(stderr, " -q Quiet mode\n");
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int parse_options(int argc, char **argv)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
int c, i;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
while ((c = getopt(argc, argv, "D:r:f:p:b:s:t:m:vq")) >= 0) {
|
|
Packit Service |
db8eaa |
switch (c) {
|
|
Packit Service |
db8eaa |
case 'D':
|
|
Packit Service |
db8eaa |
devname = optarg;
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
case 'r':
|
|
Packit Service |
db8eaa |
rate = atoi(optarg);
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
case 'p':
|
|
Packit Service |
db8eaa |
periodsize = atoi(optarg);
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
case 'b':
|
|
Packit Service |
db8eaa |
bufsize = atoi(optarg);
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
case 'c':
|
|
Packit Service |
db8eaa |
channels = atoi(optarg);
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
case 'f':
|
|
Packit Service |
db8eaa |
format = snd_pcm_format_value(optarg);
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
case 's':
|
|
Packit Service |
db8eaa |
if (*optarg == 'p' || *optarg == 'P')
|
|
Packit Service |
db8eaa |
stream = SND_PCM_STREAM_PLAYBACK;
|
|
Packit Service |
db8eaa |
else if (*optarg == 'c' || *optarg == 'C')
|
|
Packit Service |
db8eaa |
stream = SND_PCM_STREAM_CAPTURE;
|
|
Packit Service |
db8eaa |
else {
|
|
Packit Service |
db8eaa |
fprintf(stderr, "invalid stream direction\n");
|
|
Packit Service |
db8eaa |
return 1;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
case 't':
|
|
Packit Service |
db8eaa |
num_threads = atoi(optarg);
|
|
Packit Service |
db8eaa |
if (num_threads < 1 || num_threads > MAX_THREADS) {
|
|
Packit Service |
db8eaa |
fprintf(stderr, "invalid number of threads\n");
|
|
Packit Service |
db8eaa |
return 1;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
case 'm':
|
|
Packit Service |
db8eaa |
for (i = 0; i <= MODE_RANDOM; i++)
|
|
Packit Service |
db8eaa |
if (mode_suffix[i] == *optarg)
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
if (i > MODE_RANDOM) {
|
|
Packit Service |
db8eaa |
fprintf(stderr, "invalid mode type\n");
|
|
Packit Service |
db8eaa |
return 1;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
running_mode = i;
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
case 'v':
|
|
Packit Service |
db8eaa |
show_value = 1;
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
case 'q':
|
|
Packit Service |
db8eaa |
quiet = 1;
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
default:
|
|
Packit Service |
db8eaa |
usage();
|
|
Packit Service |
db8eaa |
return 1;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int setup_params(void)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_pcm_hw_params_t *hw;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
/* FIXME: more finer error checks */
|
|
Packit Service |
db8eaa |
snd_pcm_hw_params_alloca(&hw;;
|
|
Packit Service |
db8eaa |
snd_pcm_hw_params_any(pcm, hw);
|
|
Packit Service |
db8eaa |
snd_pcm_hw_params_set_access(pcm, hw, SND_PCM_ACCESS_RW_INTERLEAVED);
|
|
Packit Service |
db8eaa |
snd_pcm_hw_params_set_format(pcm, hw, format);
|
|
Packit Service |
db8eaa |
snd_pcm_hw_params_set_channels(pcm, hw, channels);
|
|
Packit Service |
db8eaa |
snd_pcm_hw_params_set_rate(pcm, hw, rate, 0);
|
|
Packit Service |
db8eaa |
snd_pcm_hw_params_set_period_size(pcm, hw, periodsize, 0);
|
|
Packit Service |
db8eaa |
snd_pcm_hw_params_set_buffer_size(pcm, hw, bufsize);
|
|
Packit Service |
db8eaa |
if (snd_pcm_hw_params(pcm, hw) < 0) {
|
|
Packit Service |
db8eaa |
fprintf(stderr, "snd_pcm_hw_params error\n");
|
|
Packit Service |
db8eaa |
return 1;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
int main(int argc, char **argv)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
char *buf;
|
|
Packit Service |
db8eaa |
int i, err;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
if (parse_options(argc, argv))
|
|
Packit Service |
db8eaa |
return 1;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
err = snd_pcm_open(&pcm, devname, stream, 0);
|
|
Packit Service |
db8eaa |
if (err < 0) {
|
|
Packit Service |
db8eaa |
fprintf(stderr, "cannot open pcm %s\n", devname);
|
|
Packit Service |
db8eaa |
return 1;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
if (setup_params())
|
|
Packit Service |
db8eaa |
return 1;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
buf = calloc(1, snd_pcm_format_size(format, bufsize) * channels);
|
|
Packit Service |
db8eaa |
if (!buf) {
|
|
Packit Service |
db8eaa |
fprintf(stderr, "cannot alloc buffer\n");
|
|
Packit Service |
db8eaa |
return 1;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
for (i = 0; i < num_threads; i++) {
|
|
Packit Service |
db8eaa |
if (pthread_create(&peeper_threads[i], NULL, peeper, (void *)(long)i)) {
|
|
Packit Service |
db8eaa |
fprintf(stderr, "pthread_create error\n");
|
|
Packit Service |
db8eaa |
return 1;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
if (stream == SND_PCM_STREAM_CAPTURE)
|
|
Packit Service |
db8eaa |
snd_pcm_start(pcm);
|
|
Packit Service |
db8eaa |
for (;;) {
|
|
Packit Service |
db8eaa |
int size = rand() % (bufsize / 2);
|
|
Packit Service |
db8eaa |
if (stream == SND_PCM_STREAM_PLAYBACK)
|
|
Packit Service |
db8eaa |
err = snd_pcm_writei(pcm, buf, size);
|
|
Packit Service |
db8eaa |
else
|
|
Packit Service |
db8eaa |
err = snd_pcm_readi(pcm, buf, size);
|
|
Packit Service |
db8eaa |
if (err < 0) {
|
|
Packit Service |
db8eaa |
fprintf(stderr, "read/write error %d\n", err);
|
|
Packit Service |
db8eaa |
err = snd_pcm_recover(pcm, err, 0);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
if (stream == SND_PCM_STREAM_CAPTURE)
|
|
Packit Service |
db8eaa |
snd_pcm_start(pcm);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
running = 0;
|
|
Packit Service |
db8eaa |
for (i = 0; i < num_threads; i++)
|
|
Packit Service |
db8eaa |
pthread_cancel(peeper_threads[i]);
|
|
Packit Service |
db8eaa |
for (i = 0; i < num_threads; i++)
|
|
Packit Service |
db8eaa |
pthread_join(peeper_threads[i], NULL);
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
return 1;
|
|
Packit Service |
db8eaa |
}
|