From 130897ac5ac03adb4604d27497c378c64c7b22dd Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Mon, 20 Oct 2014 19:36:39 +0200 Subject: ASoC: dapm: Remove path 'walked' flag The 'walked' flag was used to avoid walking paths that have already been walked. But since we started caching the number of inputs and outputs of a path we never actually get into a situation where we try to walk a path that has the 'walked' flag set. There are two cases in which we can end up walking a path multiple times within a single run of is_connected_output_ep() or is_connected_input_ep(). 1) If a path splits up and rejoins later: .--> C ---v A -> B E --> F '--> D ---^ When walking from A to F we'll end up at E twice, once via C and once via D. But since we do a depth first search we'll fully discover the path and initialize the number of outputs/inputs of the widget the first time we get there. The second time we get there we'll use the cached value and not bother to check any of the paths again. So we'll never see a path where 'walked' is set in this case. 2) If there is a circle: A --> B <-- C <-.--> F '--> D ---' When walking from A to F we'll end up twice at B. But since there is a circle the 'walking' flag will still be set on B once we get there the second time. This means we won't look at any of it's outgoing paths. So in this case we won't ever see a path where 'walked' is set either. So it is safe to remove the flag. This on one hand means we remove some always true checks from one of the hottest paths of the DAPM algorithm and on the other hand means we do not have to do the tedious clearing of the flag after checking the number inputs or outputs of a widget. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- include/sound/soc-dapm.h | 1 - 1 file changed, 1 deletion(-) (limited to 'include/sound') diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 3a4d7da67b8d..ebb93f29e4f3 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -508,7 +508,6 @@ struct snd_soc_dapm_path { /* status */ u32 connect:1; /* source and sink widgets are connected */ - u32 walked:1; /* path has been walked */ u32 walking:1; /* path is in the process of being walked */ u32 weak:1; /* path ignored for power management */ -- cgit v1.2.3 From 6dd98b0a3e58b7b48a422802b5610b95ef5128eb Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 25 Oct 2014 17:41:59 +0200 Subject: ASoC: dapm: Introduce toplevel widget categories DAPM widgets can be classified into four categories: * supply: Supply widgets do not affect the power state of their non-supply widget neighbors and unlike other widgets a supply widget is not powered up when it is on an active path, but when at least on of its neighbors is powered up. * source: A source is a widget that receives data from outside the DAPM graph or generates data. This can for example be a microphone, the playback DMA or a signal generator. A source widget will be considered powered up if there is an active path to a sink widget. * sink: A sink is a widget that transmits data to somewhere outside of the DAPM graph. This can e.g. be a speaker or the capture DMA. A sink widget will be considered powered up if there is an active path from a source widget. * normal: Normal widgets are widgets not covered by the categories above. A normal widget will be considered powered up if it is on an active path between a source widget and a sink widget. The way the number of input and output paths for a widget is calculated depends on its category. There are a bunch of factors which decide which category a widget is. Currently there is no formal classification of these categories and we calculate the category of the widget based on these factors whenever we want to know it. This is at least once for every widget during each power update sequence. The factors which determine the category of the widgets are mostly static though and if at all change rather seldom. This patch introduces three new per widget flags, one for each of non-normal widgets categories. Instead of re-computing the category each time we want to know them the flags will be checked. For the majority of widgets the category is solely determined by the widget id, which means it never changes and only has to be set once when the widget is created. The only widgets with dynamic categories are: snd_soc_dapm_dai_out: Is considered a sink iff the capture stream is active, otherwise normal. snd_soc_dapm_dai_in: Is considered a source iff the playback stream is active, otherwise normal. snd_soc_dapm_input: Is considered a sink iff it has no outgoing paths, otherwise normal. snd_soc_dapm_output: Is considered a source iff it has no incoming paths, otherwise normal. snd_soc_dapm_line: Is considered a sink iff it has no outgoing paths and is considered a source iff it has no incoming paths, otherwise normal. For snd_soc_dapm_dai_out/snd_soc_dapm_dai_in widgets the category will be updated when a stream is started or stopped. For the other dynamic widgets the category will be updated when a path connecting to it is added or removed. Introducing those new widget categories allows to make is_connected_{output,input}_ep, which are among the hottest paths of the DAPM algorithm, more generic and significantly shorter. The before and after sizes for is_connected_{output,input}_ep are: On ARM (defconfig + CONFIG_SND_SOC): function old new delta is_connected_output_ep 480 340 -140 is_connected_input_ep 456 352 -104 On amd64 (defconfig + CONFIG_SND_SOC): function old new delta is_connected_output_ep 579 427 -152 is_connected_input_ep 563 427 -136 Which is about a 25%-30% decrease, other architectures are expected to have similar numbers. At the same time the size of the snd_soc_dapm_widget struct does not change since the new flags are stored in the same word as the existing flags. Note: that since the per widget 'ext' flag was only used to decide whether a snd_soc_dapm_input or snd_soc_dapm_output widget was a source or a sink it is now unused and can be removed. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- include/sound/soc-dapm.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'include/sound') diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index ebb93f29e4f3..8cf3aad30864 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -543,11 +543,13 @@ struct snd_soc_dapm_widget { unsigned char active:1; /* active stream on DAC, ADC's */ unsigned char connected:1; /* connected codec pin */ unsigned char new:1; /* cnew complete */ - unsigned char ext:1; /* has external widgets */ unsigned char force:1; /* force state */ unsigned char ignore_suspend:1; /* kept enabled over suspend */ unsigned char new_power:1; /* power from this run */ unsigned char power_checked:1; /* power checked this run */ + unsigned char is_supply:1; /* Widget is a supply type widget */ + unsigned char is_sink:1; /* Widget is a sink type widget */ + unsigned char is_source:1; /* Widget is a source type widget */ int subseq; /* sort within widget type */ int (*power_check)(struct snd_soc_dapm_widget *w); -- cgit v1.2.3 From c1862c8bae520a8986dd7c47ce33f16eb7c791c2 Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 25 Oct 2014 17:42:00 +0200 Subject: ASoC: dapm: Add a flag to mark paths connected to supply widgets Supply widgets do not count towards the input and output widgets of their neighbors and for supply widgets themselves we do not care for the number of input or output paths. This means that a path that connects to a supply widget effectively behaves the same as a path that as the weak property set. This patch adds a new path flag that gets set to true when the path is connected to at least one supply widget. If a path with the flag set is encountered in is_connected_{input,output}_ep() is is skipped in the same way that weak paths are skipped. This slightly brings down the number of path checks. Since both the weak and the supply flag are implemented as bitfields which are stored in the same word there is no runtime overhead due to checking both rather than just one and also the size of the path struct is not increased by this patch. Another advantage is that we do not have to handle supply widgets in is_connected_{input,output}_ep() anymore since it will never be called for supply widgets. The only exception is from dapm_widget_power_read_file() where a check is added to special case supply widgets. Testing with the ADAU1761, which has a handful of supply widgets, shows the following changes in the DAPM stats for a playback stream start. Power Path Neighbour Before: 34 78 117 After: 34 48 117 Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- include/sound/soc-dapm.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/sound') diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 8cf3aad30864..e7ebeb717482 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -510,6 +510,7 @@ struct snd_soc_dapm_path { u32 connect:1; /* source and sink widgets are connected */ u32 walking:1; /* path is in the process of being walked */ u32 weak:1; /* path ignored for power management */ + u32 is_supply:1; /* At least one of the connected widgets is a supply */ int (*connected)(struct snd_soc_dapm_widget *source, struct snd_soc_dapm_widget *sink); -- cgit v1.2.3 From 8be4da29cf5b8ec65e974c36e7ae4d90b381ac5e Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 25 Oct 2014 17:42:01 +0200 Subject: ASoC: dapm: Mark endpoints instead of IO widgets dirty during suspend/resume The state of endpoint widgets is affected by that card's power state. Endpoint widgets that do no have the ignore_suspend flag set will be considered inactive during suspend. So they have to be re-checked and marked dirty after the card's power state changes. Currently the input and output widgets are marked dirty instead, this works most of the time since typically a path from one endpoint to another will go via a input or output widget. But marking the endpoints dirty is technically more correct and will also work for odd corner cases. Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- include/sound/soc-dapm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/sound') diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index e7ebeb717482..43ca1656dab4 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -435,7 +435,7 @@ void snd_soc_dapm_auto_nc_pins(struct snd_soc_card *card); unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol); /* Mostly internal - should not normally be used */ -void dapm_mark_io_dirty(struct snd_soc_dapm_context *dapm); +void dapm_mark_endpoints_dirty(struct snd_soc_card *card); /* dapm path query */ int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream, -- cgit v1.2.3 From 92a99ea439c4e27fc6e32eb6d51c5d091c6084bd Mon Sep 17 00:00:00 2001 From: Lars-Peter Clausen Date: Sat, 25 Oct 2014 17:42:03 +0200 Subject: ASoC: dapm: Use more aggressive caching Currently we cache the number of input and output paths going to/from a widget only within a power update sequence. But not in between power update sequences. But we know how changes to the DAPM graph affect the number of input (form a source) and output (to a sink) paths of a widget and only need to recalculate them if a operation has been performed that might have changed them. * Adding/removing or connecting/disconnecting a path means that the for the source of the path the number of output paths can change and for the sink the number of input paths can change. * Connecting/disconnecting a widget has the same effect has connecting/ disconnecting all paths of the widget. So for the widget itself the number of inputs and outputs can change, for all sinks of the widget the number of inputs can change and for all sources of the widget the number of outputs can change. * Activating/Deactivating a stream can either change the number of outputs on the sources of the widget associated with the stream or the number of inputs on the sinks. Instead of always invalidating all cached numbers of input and output paths for each power up or down sequence this patch restructures the code to only invalidate the cached numbers when a operation that might change them has been performed. This can greatly reduce the number of DAPM power checks for some very common operations. Since per DAPM operation typically only either change the number of inputs or outputs the number of path checks is reduced by at least 50%. The number of neighbor checks is also reduced about the same percentage, but since the number of neighbors encountered when walking from sink to source is not the same as when walking from source to sink the actual numbers will slightly vary from card to card (e.g. for a mixer we see 1 neighbor when walking from source to sink, but the number of inputs neighbors when walking from source to sink). Bigger improvements can be observed for widgets with multiple connected inputs and output (e.g. mixers probably being the most widespread form of this). Previously we had to re-calculate the number of inputs and outputs on all input and output paths. With this change we only have to re-calculate the number of outputs on the input path that got changed and the number of inputs on the output paths. E.g. imagine the following example: A --> B ----. v M --> N --> Z <-- S <-- R | v X Widget Z has multiple input paths, if any change was made that cause Z to be marked as dirty the power state of Z has to be re-computed. This requires to know the number of inputs and outputs of Z, which requires to know the number of inputs and outputs of all widgets on all paths from or to Z. Previously this meant re-computing all inputs and outputs of all the path going into or out of Z. With this patch in place only paths that actually have changed need to be re-computed. If the system is idle (or the part of the system affected by the changed path) the number of path checks drops to either 0 or 1, regardless of how large or complex the DAPM context is. 0 if there is no connected sink and no connected source. 1 if there is either a connected source or sink, but not both. The number of neighbor checks again will scale accordingly and will be a constant number that is the number of inputs or outputs of the widget for which we did the path check. When loading a state file or switching between different profiles typically multiple mixer and mux settings are changed, so we see the benefit of this patch multiplied for these kinds of operations. Testing with the ADAU1761 shows the following changes in DAPM stats for changing a single Mixer switch for a Mixer with 5 inputs while the DAPM context is idle. Power Path Neighbour Before: 2 12 30 After: 2 1 2 For the same switch, but with a active playback stream the stat changed are as follows. Power Path Neighbour Before: 10 20 54 After: 10 7 21 Cumulative numbers for switching the audio profile which changes 7 controls while the system is idle: Power Path Neighbour Before: 16 80 170 After: 16 7 23 Cumulative numbers for switching the audio profile which changes 7 controls while playback is active: Power Path Neighbour Before: 51 123 273 After: 51 29 109 Starting (or stopping) the playback stream: Power Path Neighbour Before: 34 34 117 After: 34 17 69 Signed-off-by: Lars-Peter Clausen Signed-off-by: Mark Brown --- include/sound/soc-dapm.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/sound') diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h index 43ca1656dab4..89823cfe6f04 100644 --- a/include/sound/soc-dapm.h +++ b/include/sound/soc-dapm.h @@ -569,6 +569,7 @@ struct snd_soc_dapm_widget { struct list_head sinks; /* used during DAPM updates */ + struct list_head work_list; struct list_head power_list; struct list_head dirty; int inputs; -- cgit v1.2.3