1/* 2 * simple multi-thread stress test for PCM 3 * 4 * The main thread simply feeds or reads the sample data with the 5 * random size continuously. Meanwhile, the worker threads call some 6 * update function depending on the given mode, and show the thread 7 * number of the read value. 8 * 9 * The function for the worker thread is specified via -m option. 10 * When the random mode ('r') is set, the update function is chosen 11 * randomly in the loop. 12 * 13 * When the -v option is passed, this tries to show some obtained value 14 * from the function. Without -v, as default, it shows the thread number 15 * (0-9). In addition, it puts the mode suffix ('a' for avail, 'd' for 16 * delay, etc) for the random mode, as well as the suffix '!' indicating 17 * the error from the called function. 18 */ 19 20#include <stdio.h> 21#include <pthread.h> 22#include <getopt.h> 23#include "../include/asoundlib.h" 24 25#define MAX_THREADS 10 26 27enum { 28 MODE_AVAIL_UPDATE, 29 MODE_STATUS, 30 MODE_HWSYNC, 31 MODE_TIMESTAMP, 32 MODE_DELAY, 33 MODE_RANDOM 34}; 35 36static char mode_suffix[] = { 37 'a', 's', 'h', 't', 'd', 'r' 38}; 39 40static const char *pcmdev = "default"; 41static int stream = SND_PCM_STREAM_PLAYBACK; 42static int num_threads = 1; 43static int periodsize = 16 * 1024; 44static int bufsize = 16 * 1024 * 4; 45static int channels = 2; 46static int rate = 48000; 47static snd_pcm_format_t format = SND_PCM_FORMAT_S16_LE; 48 49static int running_mode = MODE_AVAIL_UPDATE; 50static int show_value = 0; 51static int quiet = 0; 52 53static pthread_t peeper_threads[MAX_THREADS]; 54static int running = 1; 55static snd_pcm_t *pcm; 56 57static void *peeper(void *data) 58{ 59 int thread_no = (long)data; 60 snd_pcm_sframes_t val; 61 snd_pcm_status_t *stat; 62 snd_htimestamp_t tstamp; 63 int mode = running_mode, err; 64 65 snd_pcm_status_alloca(&stat); 66 67 while (running) { 68 if (running_mode == MODE_RANDOM) 69 mode = rand() % MODE_RANDOM; 70 switch (mode) { 71 case MODE_AVAIL_UPDATE: 72 val = snd_pcm_avail_update(pcm); 73 err = 0; 74 break; 75 case MODE_STATUS: 76 err = snd_pcm_status(pcm, stat); 77 val = snd_pcm_status_get_avail(stat); 78 break; 79 case MODE_HWSYNC: 80 err = snd_pcm_hwsync(pcm); 81 break; 82 case MODE_TIMESTAMP: 83 err = snd_pcm_htimestamp(pcm, (snd_pcm_uframes_t *)&val, 84 &tstamp); 85 break; 86 default: 87 err = snd_pcm_delay(pcm, &val); 88 break; 89 } 90 91 if (quiet) 92 continue; 93 if (running_mode == MODE_RANDOM) { 94 fprintf(stderr, "%d%c%s", thread_no, mode_suffix[mode], 95 err ? "!" : ""); 96 } else { 97 if (show_value && mode != MODE_HWSYNC) 98 fprintf(stderr, "\r%d ", (int)val); 99 else 100 fprintf(stderr, "%d%s", thread_no, 101 err ? "!" : ""); 102 } 103 } 104 return NULL; 105} 106 107static void usage(void) 108{ 109 fprintf(stderr, "usage: multi-thread [-options]\n"); 110 fprintf(stderr, " -D str Set device name\n"); 111 fprintf(stderr, " -r val Set sample rate\n"); 112 fprintf(stderr, " -p val Set period size (in frame)\n"); 113 fprintf(stderr, " -b val Set buffer size (in frame)\n"); 114 fprintf(stderr, " -c val Set number of channels\n"); 115 fprintf(stderr, " -f str Set PCM format\n"); 116 fprintf(stderr, " -s str Set stream direction (playback or capture)\n"); 117 fprintf(stderr, " -t val Set number of threads\n"); 118 fprintf(stderr, " -m str Running mode (avail, status, hwsync, timestamp, delay, random)\n"); 119 fprintf(stderr, " -v Show value\n"); 120 fprintf(stderr, " -q Quiet mode\n"); 121} 122 123static int parse_options(int argc, char **argv) 124{ 125 int c, i; 126 127 while ((c = getopt(argc, argv, "D:r:f:p:b:s:t:m:vq")) >= 0) { 128 switch (c) { 129 case 'D': 130 pcmdev = optarg; 131 break; 132 case 'r': 133 rate = atoi(optarg); 134 break; 135 case 'p': 136 periodsize = atoi(optarg); 137 break; 138 case 'b': 139 bufsize = atoi(optarg); 140 break; 141 case 'c': 142 channels = atoi(optarg); 143 break; 144 case 'f': 145 format = snd_pcm_format_value(optarg); 146 break; 147 case 's': 148 if (*optarg == 'p' || *optarg == 'P') 149 stream = SND_PCM_STREAM_PLAYBACK; 150 else if (*optarg == 'c' || *optarg == 'C') 151 stream = SND_PCM_STREAM_CAPTURE; 152 else { 153 fprintf(stderr, "invalid stream direction\n"); 154 return 1; 155 } 156 break; 157 case 't': 158 num_threads = atoi(optarg); 159 if (num_threads < 1 || num_threads > MAX_THREADS) { 160 fprintf(stderr, "invalid number of threads\n"); 161 return 1; 162 } 163 break; 164 case 'm': 165 for (i = 0; i <= MODE_RANDOM; i++) 166 if (mode_suffix[i] == *optarg) 167 break; 168 if (i > MODE_RANDOM) { 169 fprintf(stderr, "invalid mode type\n"); 170 return 1; 171 } 172 running_mode = i; 173 break; 174 case 'v': 175 show_value = 1; 176 break; 177 case 'q': 178 quiet = 1; 179 break; 180 default: 181 usage(); 182 return 1; 183 } 184 } 185 return 0; 186} 187 188static int setup_params(void) 189{ 190 snd_pcm_hw_params_t *hw; 191 192 /* FIXME: more finer error checks */ 193 snd_pcm_hw_params_alloca(&hw); 194 snd_pcm_hw_params_any(pcm, hw); 195 snd_pcm_hw_params_set_access(pcm, hw, SND_PCM_ACCESS_RW_INTERLEAVED); 196 snd_pcm_hw_params_set_format(pcm, hw, format); 197 snd_pcm_hw_params_set_channels(pcm, hw, channels); 198 snd_pcm_hw_params_set_rate(pcm, hw, rate, 0); 199 snd_pcm_hw_params_set_period_size(pcm, hw, periodsize, 0); 200 snd_pcm_hw_params_set_buffer_size(pcm, hw, bufsize); 201 if (snd_pcm_hw_params(pcm, hw) < 0) { 202 fprintf(stderr, "snd_pcm_hw_params error\n"); 203 return 1; 204 } 205 return 0; 206} 207 208int main(int argc, char **argv) 209{ 210 char *buf; 211 int i, err; 212 213 if (parse_options(argc, argv)) 214 return 1; 215 216 err = snd_pcm_open(&pcm, pcmdev, stream, 0); 217 if (err < 0) { 218 fprintf(stderr, "cannot open pcm %s\n", pcmdev); 219 return 1; 220 } 221 222 if (setup_params()) 223 return 1; 224 225 buf = calloc(1, snd_pcm_format_size(format, bufsize) * channels); 226 if (!buf) { 227 fprintf(stderr, "cannot alloc buffer\n"); 228 return 1; 229 } 230 231 for (i = 0; i < num_threads; i++) { 232 if (pthread_create(&peeper_threads[i], NULL, peeper, (void *)(long)i)) { 233 fprintf(stderr, "pthread_create error\n"); 234 return 1; 235 } 236 } 237 238 if (stream == SND_PCM_STREAM_CAPTURE) 239 snd_pcm_start(pcm); 240 for (;;) { 241 int size = rand() % (bufsize / 2); 242 if (stream == SND_PCM_STREAM_PLAYBACK) 243 err = snd_pcm_writei(pcm, buf, size); 244 else 245 err = snd_pcm_readi(pcm, buf, size); 246 if (err < 0) { 247 fprintf(stderr, "read/write error %d\n", err); 248 err = snd_pcm_recover(pcm, err, 0); 249 if (err < 0) 250 break; 251 if (stream == SND_PCM_STREAM_CAPTURE) 252 snd_pcm_start(pcm); 253 } 254 } 255 256 running = 0; 257 for (i = 0; i < num_threads; i++) 258 pthread_cancel(peeper_threads[i]); 259 for (i = 0; i < num_threads; i++) 260 pthread_join(peeper_threads[i], NULL); 261 262 return 1; 263} 264