[PATCH V0 1/1] asoc: msm: use hashtable to check kcontrol
Raghu Ballappa Bankapur
quic_rbankapu at quicinc.com
Thu Jun 9 20:16:52 CEST 2022
Hi Takashi
Our implementation also falls inline with your approach [PATCH RFC]
ALSA: control: Use xarray for faster lookups (kernel.org)
<https://lore.kernel.org/all/20211028130027.18764-1-tiwai@suse.de/T/>,
but you approach looks to be clean with xarray.
is it possible to upstream those changes?
Regards
Raghu Bankapur
On 5/29/2022 3:05 PM, Takashi Iwai wrote:
> On Sun, 29 May 2022 10:50:09 +0200,
> Raghu Bankapur wrote:
>> use hashtabe instead of linear list to check kcontrol before
>> adding them for improving early audio KPI.
>>
>> Change-Id: I7134816736e08e338c0f22a8ae283a0520aa847a
>> Signed-off-by: Raghu Bankapur<quic_rbankapu at quicinc.com>
> Aha, interesting, a faster lookup is indeed measurable and needed.
>
> One point with your patch is whether it works when a control element
> gets removed dynamically. It's often the case with the user-space
> kctls. Also, multiple ctl elements may have the same name string but
> with different index or device number. Comparing only the string
> isn't enough. (And I wonder how about the hash key collision.)
>
> FWIW, I posted an RFC patch faster lookup with Xarray some time ago:
> https://lore.kernel.org/all/20211028130027.18764-1-tiwai@suse.de/T/
>
>
> thanks,
>
> Takashi
>
>
>> ---
>> include/sound/control.h | 4 ++
>> include/sound/core.h | 12 +++++-
>> sound/core/control.c | 92 +++++++++++++++++++++++++++++++++--------
>> sound/core/init.c | 3 ++
>> sound/soc/Kconfig | 9 ++++
>> 5 files changed, 101 insertions(+), 19 deletions(-)
>>
>> diff --git a/include/sound/control.h b/include/sound/control.h
>> index 985c51a8fb74..1b85d36c2066 100644
>> --- a/include/sound/control.h
>> +++ b/include/sound/control.h
>> @@ -70,6 +70,10 @@ struct snd_kcontrol_volatile {
>> struct snd_kcontrol {
>> struct list_head list; /* list of controls */
>> struct snd_ctl_elem_id id;
>> +#ifdef CONFIG_SND_CTL_HASHTABLE
>> + struct hlist_node hnode;
>> + unsigned int knametoint; /* kctl name to uint, hash key value */
>> +#endif
>> unsigned int count; /* count of same elements */
>> snd_kcontrol_info_t *info;
>> snd_kcontrol_get_t *get;
>> diff --git a/include/sound/core.h b/include/sound/core.h
>> index b7e9b58d3c78..dd6714fc43ff 100644
>> --- a/include/sound/core.h
>> +++ b/include/sound/core.h
>> @@ -14,7 +14,9 @@
>> #include <linux/pm.h> /* pm_message_t */
>> #include <linux/stringify.h>
>> #include <linux/printk.h>
>> -
>> +#ifdef CONFIG_SND_CTL_HASHTABLE
>> +#include <linux/hashtable.h>
>> +#endif
>> /* number of supported soundcards */
>> #ifdef CONFIG_SND_DYNAMIC_MINORS
>> #define SNDRV_CARDS CONFIG_SND_MAX_CARDS
>> @@ -24,6 +26,10 @@
>>
>> #define CONFIG_SND_MAJOR 116 /* standard configuration */
>>
>> +#ifdef CONFIG_SND_CTL_HASHTABLE
>> +#define SND_CTL_HASH_TABLE_BITS 14 /* buckets numbers: 1 << 14 */
>> +#endif
>> +
>> /* forward declarations */
>> struct pci_dev;
>> struct module;
>> @@ -103,7 +109,9 @@ struct snd_card {
>> size_t user_ctl_alloc_size; // current memory allocation by user controls.
>> struct list_head controls; /* all controls for this card */
>> struct list_head ctl_files; /* active control files */
>> -
>> +#ifdef CONFIG_SND_CTL_HASHTABLE
>> + DECLARE_HASHTABLE(ctl_htable, SND_CTL_HASH_TABLE_BITS);
>> +#endif
>> struct snd_info_entry *proc_root; /* root for soundcard specific files */
>> struct proc_dir_entry *proc_root_link; /* number link to real id */
>>
>> diff --git a/sound/core/control.c b/sound/core/control.c
>> index a25c0d64d104..914d05647497 100644
>> --- a/sound/core/control.c
>> +++ b/sound/core/control.c
>> @@ -368,6 +368,47 @@ enum snd_ctl_add_mode {
>> CTL_ADD_EXCLUSIVE, CTL_REPLACE, CTL_ADD_ON_REPLACE,
>> };
>>
>> +#ifdef CONFIG_SND_CTL_HASHTABLE
>> +char snd_ctl_string[50] = { '\0' };
>> +
>> +/* Used to convert the string into int value -- BKDRHash */
>> +unsigned int snd_ctl_strtoint(const char *s)
>> +{
>> + unsigned int res = 0;
>> +
>> + while (*s)
>> + res = (res << 5) - res + (*s++);
>> +
>> + return (res & 0x7FFFFFFF);
>> +}
>> +
>> +/**
>> + * snd_ctl_hash_check - Check the duplicate enrty on snd hashtable
>> + * @card: the card instance
>> + * @nametoint: kctl name to uint
>> + *
>> + * Finds the control instance with the given nametoint from the card.
>> + *
>> + * Return: The pointer of the instance if found, or %NULL if not.
>> + *
>> + */
>> +static struct snd_kcontrol *snd_ctl_hash_check(struct snd_card *card,
>> + unsigned int nametoint)
>> +{
>> + struct snd_kcontrol *kctl = NULL;
>> +
>> + if (snd_BUG_ON(!card))
>> + return NULL;
>> +
>> + hash_for_each_possible(card->ctl_htable, kctl, hnode, nametoint) {
>> + if (kctl->knametoint != nametoint)
>> + continue;
>> + return kctl;
>> + }
>> + return NULL;
>> +}
>> +#endif
>> +
>> /* add/replace a new kcontrol object; call with card->controls_rwsem locked */
>> static int __snd_ctl_add_replace(struct snd_card *card,
>> struct snd_kcontrol *kcontrol,
>> @@ -382,24 +423,38 @@ static int __snd_ctl_add_replace(struct snd_card *card,
>> if (id.index > UINT_MAX - kcontrol->count)
>> return -EINVAL;
>>
>> - old = snd_ctl_find_id(card, &id);
>> - if (!old) {
>> - if (mode == CTL_REPLACE)
>> - return -EINVAL;
>> - } else {
>> - if (mode == CTL_ADD_EXCLUSIVE) {
>> - dev_err(card->dev,
>> - "control %i:%i:%i:%s:%i is already present\n",
>> - id.iface, id.device, id.subdevice, id.name,
>> - id.index);
>> - return -EBUSY;
>> - }
>> +#ifdef CONFIG_SND_CTL_HASHTABLE
>> + snprintf(snd_ctl_string, strlen(kcontrol->id.name) + 6, "%s%d%d%d",
>> + kcontrol->id.name, kcontrol->id.iface, kcontrol->id.device,
>> + kcontrol->id.subdevice);
>>
>> - err = snd_ctl_remove(card, old);
>> - if (err < 0)
>> - return err;
>> - }
>> + kcontrol->knametoint = snd_ctl_strtoint(snd_ctl_string);
>> + if (kcontrol->knametoint < 0)
>> + return -EINVAL;
>> +
>> + old = snd_ctl_hash_check(card, kcontrol->knametoint);
>> + if (old) {
>> +#endif
>> + old = snd_ctl_find_id(card, &id);
>> + if (!old) {
>> + if (mode == CTL_REPLACE)
>> + return -EINVAL;
>> + } else {
>> + if (mode == CTL_ADD_EXCLUSIVE) {
>> + dev_err(card->dev,
>> + "control %i:%i:%i:%s:%i is already present\n",
>> + id.iface, id.device, id.subdevice, id.name,
>> + id.index);
>> + return -EBUSY;
>> + }
>>
>> + err = snd_ctl_remove(card, old);
>> + if (err < 0)
>> + return err;
>> + }
>> +#ifdef CONFIG_SND_CTL_HASHTABLE
>> + }
>> +#endif
>> if (snd_ctl_find_hole(card, kcontrol->count) < 0)
>> return -ENOMEM;
>>
>> @@ -410,7 +465,10 @@ static int __snd_ctl_add_replace(struct snd_card *card,
>>
>> for (idx = 0; idx < kcontrol->count; idx++)
>> snd_ctl_notify_one(card, SNDRV_CTL_EVENT_MASK_ADD, kcontrol, idx);
>> -
>> +
>> +#ifdef CONFIG_SND_CTL_HASHTABLE
>> + hash_add(card->ctl_htable, &kcontrol->hnode, kcontrol->knametoint);
>> +#endif
>> return 0;
>> }
>>
>> diff --git a/sound/core/init.c b/sound/core/init.c
>> index 31ba7024e3ad..fda38b2137ee 100644
>> --- a/sound/core/init.c
>> +++ b/sound/core/init.c
>> @@ -284,6 +284,9 @@ static int snd_card_init(struct snd_card *card, struct device *parent,
>> INIT_LIST_HEAD(&card->ctl_files);
>> spin_lock_init(&card->files_lock);
>> INIT_LIST_HEAD(&card->files_list);
>> +#ifdef CONFIG_SND_CTL_HASHTABLE
>> + hash_init(card->ctl_htable);
>> +#endif
>> mutex_init(&card->memory_mutex);
>> #ifdef CONFIG_PM
>> init_waitqueue_head(&card->power_sleep);
>> diff --git a/sound/soc/Kconfig b/sound/soc/Kconfig
>> index 5dcf77af07af..0eb18f8ee6fd 100644
>> --- a/sound/soc/Kconfig
>> +++ b/sound/soc/Kconfig
>> @@ -58,6 +58,15 @@ config SND_SOC_TOPOLOGY_KUNIT_TEST
>> config SND_SOC_ACPI
>> tristate
>>
>> +config SND_CTL_HASHTABLE
>> + bool "Add SND CTL hashtable"
>> + help
>> + This enables hash table in sound card for kcontrols. The traditional way is
>> + traversing the linked list of controls and compare each exsiting control with
>> + the new kcontrol to find out whether there are duplicate kcontrols, which will
>> + consumes much time during bootup. Enable this will use hash table instead of
>> + linked list to check new kcontrol and reduce much time for sound card registration.
>> +
>> # All the supported SoCs
>> source "sound/soc/adi/Kconfig"
>> source "sound/soc/amd/Kconfig"
>> --
>> 2.17.1
>>
More information about the Alsa-devel
mailing list