Message ID | 1483079175-28827-1-git-send-email-sutar.mounesh@gmail.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Fri, 30 Dec 2016 07:26:15 +0100, sutar.mounesh@gmail.com wrote: > > From: Joshua Frkuska joshua_frkuska@mentor.com > > This patch allows the effective period size to be a multiple of the slave-pcm period size. > Allowing only exact multiple of original period size is achieved by borrowing code from the > kernel hwrules implemention. > > This patch is intended to save cpu workload when for example, the slave operates with very > small periods but a user does not need that small periods. > > This feature is enabled by default and can be disabled by adding config option 'var_periodsize 0'. > > Signed-off-by: Alexander Jahn <ajahn@de.adit-jv.com> > Signed-off-by: Andreas Pape <apape@de.adit-jv.com> Looks like a good improvement. I applied this patch with a slight coding style fixes. thanks, Takashi > diff --git a/src/pcm/pcm_direct.c b/src/pcm/pcm_direct.c > index 6434983..8f42b19 100644 > --- a/src/pcm/pcm_direct.c > +++ b/src/pcm/pcm_direct.c > @@ -660,6 +660,28 @@ static int hw_param_interval_refine_minmax(snd_pcm_hw_params_t *params, > return hw_param_interval_refine_one(params, var, &t); > } > > +/* this code is used 'as-is' from the alsa kernel code */ > +static int snd_interval_step(struct snd_interval *i, unsigned int min, unsigned int step) > +{ > + unsigned int n; > + int changed = 0; > + n = (i->min - min) % step; > + if (n != 0 || i->openmin) { > + i->min += step - n; > + changed = 1; > + } > + n = (i->max - min) % step; > + if (n != 0 || i->openmax) { > + i->max -= n; > + changed = 1; > + } > + if (snd_interval_checkempty(i)) { > + i->empty = 1; > + return -EINVAL; > + } > + return changed; > +} > + > #undef REFINE_DEBUG > > int snd_pcm_direct_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) > @@ -710,15 +732,16 @@ int snd_pcm_direct_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) > &dshare->shmptr->hw.rate); > if (err < 0) > return err; > - err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_PERIOD_SIZE, > - &dshare->shmptr->hw.period_size); > - if (err < 0) > - return err; > - err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_PERIOD_TIME, > - &dshare->shmptr->hw.period_time); > - if (err < 0) > - return err; > + > if (dshare->max_periods < 0) { > + err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_PERIOD_SIZE, > + &dshare->shmptr->hw.period_size); > + if (err < 0) > + return err; > + err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_PERIOD_TIME, > + &dshare->shmptr->hw.period_time); > + if (err < 0) > + return err; > err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_BUFFER_SIZE, > &dshare->shmptr->hw.buffer_size); > if (err < 0) > @@ -730,11 +753,38 @@ int snd_pcm_direct_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) > } else if (params->rmask & ((1<<SND_PCM_HW_PARAM_PERIODS)| > (1<<SND_PCM_HW_PARAM_BUFFER_BYTES)| > (1<<SND_PCM_HW_PARAM_BUFFER_SIZE)| > - (1<<SND_PCM_HW_PARAM_BUFFER_TIME))) { > + (1<<SND_PCM_HW_PARAM_BUFFER_TIME)| > + (1<<SND_PCM_HW_PARAM_PERIOD_TIME)| > + (1<<SND_PCM_HW_PARAM_PERIOD_SIZE)| > + (1<<SND_PCM_HW_PARAM_PERIOD_BYTES))) { > + snd_interval_t period_size = dshare->shmptr->hw.period_size; > + snd_interval_t period_time = dshare->shmptr->hw.period_time; > int changed; > unsigned int max_periods = dshare->max_periods; > if (max_periods < 2) > max_periods = dshare->slave_buffer_size / dshare->slave_period_size; > + > + /*make sure buffer size does not exceed slave buffer size*/ > + err = hw_param_interval_refine_minmax(params, SND_PCM_HW_PARAM_BUFFER_SIZE, > + 2 * dshare->slave_period_size, dshare->slave_buffer_size); > + if (err < 0) > + return err; > + if (dshare->var_periodsize) { > + /*more tolerant settings...*/ > + if((dshare->shmptr->hw.buffer_size.max / 2) > period_size.max) > + period_size.max = dshare->shmptr->hw.buffer_size.max / 2; > + if((dshare->shmptr->hw.buffer_time.max / 2) > period_time.max) > + period_time.max = dshare->shmptr->hw.buffer_time.max / 2; > + } > + > + err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_PERIOD_SIZE, > + &period_size); > + if (err < 0) > + return err; > + err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_PERIOD_TIME, > + &period_time); > + if (err < 0) > + return err; > do { > changed = 0; > err = hw_param_interval_refine_minmax(params, SND_PCM_HW_PARAM_PERIODS, > @@ -746,8 +796,16 @@ int snd_pcm_direct_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) > if (err < 0) > return err; > changed |= err; > + err = snd_interval_step(hw_param_interval(params, SND_PCM_HW_PARAM_PERIOD_SIZE), > + 0, dshare->slave_period_size); > + if (err < 0) > + return err; > + changed |= err; > + if (err) > + params->rmask |= (1<<SND_PCM_HW_PARAM_PERIOD_SIZE); > } while (changed); > } > + dshare->timer_ticks = hw_param_interval(params, SND_PCM_HW_PARAM_PERIOD_SIZE)->max/dshare->slave_period_size; > params->info = dshare->shmptr->s.info; > #ifdef REFINE_DEBUG > snd_output_puts(log, "DMIX REFINE (end):\n"); > @@ -1183,6 +1241,7 @@ int snd_pcm_direct_initialize_poll_fd(snd_pcm_direct_t *dmix) > > dmix->tread = 1; > dmix->timer_need_poll = 0; > + dmix->timer_ticks = 1; > ret = snd_pcm_info(dmix->spcm, &info); > if (ret < 0) { > SNDERR("unable to info for slave pcm"); > @@ -1366,7 +1425,7 @@ int snd_pcm_direct_set_timer_params(snd_pcm_direct_t *dmix) > snd_timer_params_set_auto_start(¶ms, 1); > if (dmix->type != SND_PCM_TYPE_DSNOOP) > snd_timer_params_set_early_event(¶ms, 1); > - snd_timer_params_set_ticks(¶ms, 1); > + snd_timer_params_set_ticks(¶ms, dmix->timer_ticks); > if (dmix->tread) { > filter = (1<<SND_TIMER_EVENT_TICK) | > dmix->timer_events; > @@ -1656,6 +1715,7 @@ int snd_pcm_direct_parse_open_conf(snd_config_t *root, snd_config_t *conf, > rec->ipc_gid = -1; > rec->slowptr = 1; > rec->max_periods = 0; > + rec->var_periodsize = 1; > > /* read defaults */ > if (snd_config_search(root, "defaults.pcm.dmix_max_periods", &n) >= 0) { > @@ -1762,6 +1822,13 @@ int snd_pcm_direct_parse_open_conf(snd_config_t *root, snd_config_t *conf, > rec->max_periods = val; > continue; > } > + if (strcmp(id, "var_periodsize") == 0) { > + err = snd_config_get_bool(n); > + if (err < 0) > + return err; > + rec->var_periodsize = err; > + continue; > + } > SNDERR("Unknown field %s", id); > return -EINVAL; > } > diff --git a/src/pcm/pcm_direct.h b/src/pcm/pcm_direct.h > index 611ad29..91e816c 100644 > --- a/src/pcm/pcm_direct.h > +++ b/src/pcm/pcm_direct.h > @@ -147,12 +147,14 @@ struct snd_pcm_direct { > int tread: 1; > int timer_need_poll: 1; > unsigned int timer_events; > + unsigned int timer_ticks; > int server_fd; > pid_t server_pid; > snd_timer_t *timer; /* timer used as poll_fd */ > int interleaved; /* we have interleaved buffer */ > int slowptr; /* use slow but more precise ptr updates */ > int max_periods; /* max periods (-1 = fixed periods, 0 = max buffer size) */ > + int var_periodsize; /* allow variable period size if max_periods is != -1*/ > unsigned int channels; /* client's channels */ > unsigned int *bindings; > union { > @@ -326,6 +328,7 @@ struct snd_pcm_direct_open_conf { > int ipc_gid; > int slowptr; > int max_periods; > + int var_periodsize; > snd_config_t *slave; > snd_config_t *bindings; > }; > diff --git a/src/pcm/pcm_dmix.c b/src/pcm/pcm_dmix.c > index 825677f..0ab7323 100644 > --- a/src/pcm/pcm_dmix.c > +++ b/src/pcm/pcm_dmix.c > @@ -1040,6 +1040,7 @@ int snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name, > dmix->state = SND_PCM_STATE_OPEN; > dmix->slowptr = opts->slowptr; > dmix->max_periods = opts->max_periods; > + dmix->var_periodsize = opts->var_periodsize; > dmix->sync_ptr = snd_pcm_dmix_sync_ptr; > > retry: > diff --git a/src/pcm/pcm_dshare.c b/src/pcm/pcm_dshare.c > index 29cd6c6..a1fed5d 100644 > --- a/src/pcm/pcm_dshare.c > +++ b/src/pcm/pcm_dshare.c > @@ -725,6 +725,7 @@ int snd_pcm_dshare_open(snd_pcm_t **pcmp, const char *name, > dshare->state = SND_PCM_STATE_OPEN; > dshare->slowptr = opts->slowptr; > dshare->max_periods = opts->max_periods; > + dshare->var_periodsize = opts->var_periodsize; > dshare->sync_ptr = snd_pcm_dshare_sync_ptr; > > retry: > diff --git a/src/pcm/pcm_dsnoop.c b/src/pcm/pcm_dsnoop.c > index 1aedf3c..85f0ff4 100644 > --- a/src/pcm/pcm_dsnoop.c > +++ b/src/pcm/pcm_dsnoop.c > @@ -606,6 +606,7 @@ int snd_pcm_dsnoop_open(snd_pcm_t **pcmp, const char *name, > dsnoop->state = SND_PCM_STATE_OPEN; > dsnoop->slowptr = opts->slowptr; > dsnoop->max_periods = opts->max_periods; > + dsnoop->var_periodsize = opts->var_periodsize; > dsnoop->sync_ptr = snd_pcm_dsnoop_sync_ptr; > > retry: > -- > 1.7.9.5 >
diff --git a/src/pcm/pcm_direct.c b/src/pcm/pcm_direct.c index 6434983..8f42b19 100644 --- a/src/pcm/pcm_direct.c +++ b/src/pcm/pcm_direct.c @@ -660,6 +660,28 @@ static int hw_param_interval_refine_minmax(snd_pcm_hw_params_t *params, return hw_param_interval_refine_one(params, var, &t); } +/* this code is used 'as-is' from the alsa kernel code */ +static int snd_interval_step(struct snd_interval *i, unsigned int min, unsigned int step) +{ + unsigned int n; + int changed = 0; + n = (i->min - min) % step; + if (n != 0 || i->openmin) { + i->min += step - n; + changed = 1; + } + n = (i->max - min) % step; + if (n != 0 || i->openmax) { + i->max -= n; + changed = 1; + } + if (snd_interval_checkempty(i)) { + i->empty = 1; + return -EINVAL; + } + return changed; +} + #undef REFINE_DEBUG int snd_pcm_direct_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) @@ -710,15 +732,16 @@ int snd_pcm_direct_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) &dshare->shmptr->hw.rate); if (err < 0) return err; - err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_PERIOD_SIZE, - &dshare->shmptr->hw.period_size); - if (err < 0) - return err; - err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_PERIOD_TIME, - &dshare->shmptr->hw.period_time); - if (err < 0) - return err; + if (dshare->max_periods < 0) { + err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_PERIOD_SIZE, + &dshare->shmptr->hw.period_size); + if (err < 0) + return err; + err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_PERIOD_TIME, + &dshare->shmptr->hw.period_time); + if (err < 0) + return err; err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_BUFFER_SIZE, &dshare->shmptr->hw.buffer_size); if (err < 0) @@ -730,11 +753,38 @@ int snd_pcm_direct_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) } else if (params->rmask & ((1<<SND_PCM_HW_PARAM_PERIODS)| (1<<SND_PCM_HW_PARAM_BUFFER_BYTES)| (1<<SND_PCM_HW_PARAM_BUFFER_SIZE)| - (1<<SND_PCM_HW_PARAM_BUFFER_TIME))) { + (1<<SND_PCM_HW_PARAM_BUFFER_TIME)| + (1<<SND_PCM_HW_PARAM_PERIOD_TIME)| + (1<<SND_PCM_HW_PARAM_PERIOD_SIZE)| + (1<<SND_PCM_HW_PARAM_PERIOD_BYTES))) { + snd_interval_t period_size = dshare->shmptr->hw.period_size; + snd_interval_t period_time = dshare->shmptr->hw.period_time; int changed; unsigned int max_periods = dshare->max_periods; if (max_periods < 2) max_periods = dshare->slave_buffer_size / dshare->slave_period_size; + + /*make sure buffer size does not exceed slave buffer size*/ + err = hw_param_interval_refine_minmax(params, SND_PCM_HW_PARAM_BUFFER_SIZE, + 2 * dshare->slave_period_size, dshare->slave_buffer_size); + if (err < 0) + return err; + if (dshare->var_periodsize) { + /*more tolerant settings...*/ + if((dshare->shmptr->hw.buffer_size.max / 2) > period_size.max) + period_size.max = dshare->shmptr->hw.buffer_size.max / 2; + if((dshare->shmptr->hw.buffer_time.max / 2) > period_time.max) + period_time.max = dshare->shmptr->hw.buffer_time.max / 2; + } + + err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_PERIOD_SIZE, + &period_size); + if (err < 0) + return err; + err = hw_param_interval_refine_one(params, SND_PCM_HW_PARAM_PERIOD_TIME, + &period_time); + if (err < 0) + return err; do { changed = 0; err = hw_param_interval_refine_minmax(params, SND_PCM_HW_PARAM_PERIODS, @@ -746,8 +796,16 @@ int snd_pcm_direct_hw_refine(snd_pcm_t *pcm, snd_pcm_hw_params_t *params) if (err < 0) return err; changed |= err; + err = snd_interval_step(hw_param_interval(params, SND_PCM_HW_PARAM_PERIOD_SIZE), + 0, dshare->slave_period_size); + if (err < 0) + return err; + changed |= err; + if (err) + params->rmask |= (1<<SND_PCM_HW_PARAM_PERIOD_SIZE); } while (changed); } + dshare->timer_ticks = hw_param_interval(params, SND_PCM_HW_PARAM_PERIOD_SIZE)->max/dshare->slave_period_size; params->info = dshare->shmptr->s.info; #ifdef REFINE_DEBUG snd_output_puts(log, "DMIX REFINE (end):\n"); @@ -1183,6 +1241,7 @@ int snd_pcm_direct_initialize_poll_fd(snd_pcm_direct_t *dmix) dmix->tread = 1; dmix->timer_need_poll = 0; + dmix->timer_ticks = 1; ret = snd_pcm_info(dmix->spcm, &info); if (ret < 0) { SNDERR("unable to info for slave pcm"); @@ -1366,7 +1425,7 @@ int snd_pcm_direct_set_timer_params(snd_pcm_direct_t *dmix) snd_timer_params_set_auto_start(¶ms, 1); if (dmix->type != SND_PCM_TYPE_DSNOOP) snd_timer_params_set_early_event(¶ms, 1); - snd_timer_params_set_ticks(¶ms, 1); + snd_timer_params_set_ticks(¶ms, dmix->timer_ticks); if (dmix->tread) { filter = (1<<SND_TIMER_EVENT_TICK) | dmix->timer_events; @@ -1656,6 +1715,7 @@ int snd_pcm_direct_parse_open_conf(snd_config_t *root, snd_config_t *conf, rec->ipc_gid = -1; rec->slowptr = 1; rec->max_periods = 0; + rec->var_periodsize = 1; /* read defaults */ if (snd_config_search(root, "defaults.pcm.dmix_max_periods", &n) >= 0) { @@ -1762,6 +1822,13 @@ int snd_pcm_direct_parse_open_conf(snd_config_t *root, snd_config_t *conf, rec->max_periods = val; continue; } + if (strcmp(id, "var_periodsize") == 0) { + err = snd_config_get_bool(n); + if (err < 0) + return err; + rec->var_periodsize = err; + continue; + } SNDERR("Unknown field %s", id); return -EINVAL; } diff --git a/src/pcm/pcm_direct.h b/src/pcm/pcm_direct.h index 611ad29..91e816c 100644 --- a/src/pcm/pcm_direct.h +++ b/src/pcm/pcm_direct.h @@ -147,12 +147,14 @@ struct snd_pcm_direct { int tread: 1; int timer_need_poll: 1; unsigned int timer_events; + unsigned int timer_ticks; int server_fd; pid_t server_pid; snd_timer_t *timer; /* timer used as poll_fd */ int interleaved; /* we have interleaved buffer */ int slowptr; /* use slow but more precise ptr updates */ int max_periods; /* max periods (-1 = fixed periods, 0 = max buffer size) */ + int var_periodsize; /* allow variable period size if max_periods is != -1*/ unsigned int channels; /* client's channels */ unsigned int *bindings; union { @@ -326,6 +328,7 @@ struct snd_pcm_direct_open_conf { int ipc_gid; int slowptr; int max_periods; + int var_periodsize; snd_config_t *slave; snd_config_t *bindings; }; diff --git a/src/pcm/pcm_dmix.c b/src/pcm/pcm_dmix.c index 825677f..0ab7323 100644 --- a/src/pcm/pcm_dmix.c +++ b/src/pcm/pcm_dmix.c @@ -1040,6 +1040,7 @@ int snd_pcm_dmix_open(snd_pcm_t **pcmp, const char *name, dmix->state = SND_PCM_STATE_OPEN; dmix->slowptr = opts->slowptr; dmix->max_periods = opts->max_periods; + dmix->var_periodsize = opts->var_periodsize; dmix->sync_ptr = snd_pcm_dmix_sync_ptr; retry: diff --git a/src/pcm/pcm_dshare.c b/src/pcm/pcm_dshare.c index 29cd6c6..a1fed5d 100644 --- a/src/pcm/pcm_dshare.c +++ b/src/pcm/pcm_dshare.c @@ -725,6 +725,7 @@ int snd_pcm_dshare_open(snd_pcm_t **pcmp, const char *name, dshare->state = SND_PCM_STATE_OPEN; dshare->slowptr = opts->slowptr; dshare->max_periods = opts->max_periods; + dshare->var_periodsize = opts->var_periodsize; dshare->sync_ptr = snd_pcm_dshare_sync_ptr; retry: diff --git a/src/pcm/pcm_dsnoop.c b/src/pcm/pcm_dsnoop.c index 1aedf3c..85f0ff4 100644 --- a/src/pcm/pcm_dsnoop.c +++ b/src/pcm/pcm_dsnoop.c @@ -606,6 +606,7 @@ int snd_pcm_dsnoop_open(snd_pcm_t **pcmp, const char *name, dsnoop->state = SND_PCM_STATE_OPEN; dsnoop->slowptr = opts->slowptr; dsnoop->max_periods = opts->max_periods; + dsnoop->var_periodsize = opts->var_periodsize; dsnoop->sync_ptr = snd_pcm_dsnoop_sync_ptr; retry: