Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

layers: Use a two-stage cache #174

Merged
merged 5 commits into from Aug 13, 2017
Merged

layers: Use a two-stage cache #174

merged 5 commits into from Aug 13, 2017

Conversation

algernon
Copy link
Contributor

With the new implementation, there are two lookup functions, because we have two caches, and different parts of the firmware will want to use either this or that (or perhaps both, in rare cases).

First of all, we use caches because looking up a key through all the layers is costy, and the cost increases dramatically the more layers we have.

Then, we have the effectiveKeymapCache, because to have layer behaviours we want, that is, if you hold a key on a layer, release the layer key but continue holding the other, we want for the layered keycode to continue repeating. At the same time, we want other keys to not be affected by the now-turned-off layer. So we update the keycode in the cache on-demand, when the key is pressed or released. (see the top of handleKeyswitchEvent).

On the other hand, we also have plugins that scan the whole keymap, and do things based on that information, such as highlighting keys that changed between layers. These need to be able to look at a state of where the keymap should be, not necessarily where it is. The effectiveKeymapCache is not useful here. So we use a keymapCache which we update whenever layers change (see Layer.on and Layer.off), and it updates the cache to show how the keymap should look, without the effectiveKeymapCache-induced behaviour.

Thus, if we are curious about what a given key will do, use lookup. If we are curious what the active layer state describes the key as, use lookupUncached.

This is one way to fix #173, at the cost of ~128 bytes of code, 64 bytes of SRAM, and ~+0.07-0.1ms of cycle time. Kaleidoscope-Numlock and any other plugin that wants the real keymap, will need to be updated to use Layer.lookupUncached (which we may want to rename, as it is looking up a cached value, just a different one).

I will be opening another PR soon, to see how the other proposed behaviour turns out.

Only update the keymap cache if the layer state changed for real. If we turn a
layer that was already on, on again, we do not need to update. Same for turning
them off.

This results in a tiny speedup if we have code that calls `Layer.on()` or
`Layer.off()` often.

Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
With the new implementation, there are two lookup functions, because we have two
caches, and different parts of the firmware will want to use either this or
that (or perhaps both, in rare cases).

First of all, we use caches because looking up a key through all the layers
is costy, and the cost increases dramatically the more layers we have.

Then, we have the `effectiveKeymapCache`, because to have layer behaviours
we want, that is, if you hold a key on a layer, release the layer key but
continue holding the other, we want for the layered keycode to continue
repeating. At the same time, we want other keys to not be affected by the
now-turned-off layer. So we update the keycode in the cache on-demand, when
the key is pressed or released. (see the top of `handleKeyswitchEvent`).

On the other hand, we also have plugins that scan the whole keymap, and do
things based on that information, such as highlighting keys that changed
between layers. These need to be able to look at a state of where the
keymap *should* be, not necessarily where it is. The `effectiveKeymapCache`
is not useful here. So we use a `keymapCache` which we update whenever
layers change (see `Layer.on` and `Layer.off`), and it updates the cache to
show how the keymap should look, without the `effectiveKeymapCache`-induced
behaviour.

Thus, if we are curious about what a given key will do, use `lookup`. If we
are curious what the active layer state describes the key as, use
`lookupUncached`.

Signed-off-by: Gergely Nagy <algernon@madhouse-project.org>
@algernon algernon added bug Something isn't working enhancement New feature or request labels Aug 12, 2017
@algernon algernon self-assigned this Aug 12, 2017
@algernon algernon requested a review from obra August 12, 2017 06:37
@obra
Copy link
Member

obra commented Aug 12, 2017

Hi! Thanks for pushing on this.

'effective' feels like a weird name to me. Are you using it to mean 'the current state of the keymap, including possible additional layers for keys that were being held down before we changed layers'?

I think we want to name the lookup functions in a way that suggests when you might want one or the other.

So, If I've got this right, 'lookup', would become something like 'lookup live keymap state' and 'lookupUncached' would become something like 'lookup key on active layer'

@algernon
Copy link
Contributor Author

'effective' feels like a weird name to me. Are you using it to mean 'the current state of the keymap, including possible additional layers for keys that were being held down before we changed layers'?

Yep.

I think we want to name the lookup functions in a way that suggests when you might want one or the other.

Agreed, though, part of me feels that one of them should remain called lookup, the one we use more often. No strong feelings about any name though.

So, If I've got this right, 'lookup', would become something like 'lookup live keymap state' and 'lookupUncached' would become something like 'lookup key on active layer'

Correct, indeed.

Rename effectiveKeymapCache to liveCompositeKeymap to try to
describe what it does just a tiny bit better
@obra
Copy link
Member

obra commented Aug 13, 2017

@algernon - I did some renamings. I'd love to know if they accurately describe the intent of the features.

@obra
Copy link
Member

obra commented Aug 13, 2017

I'm merging this for now so that we get at least a day of soak time before I need to send it to the factory.
I'm happy to take naming patches or to back it out if it turns out to have issues, but we're really tight on time.

@obra obra merged commit 9e222ea into master Aug 13, 2017
@algernon algernon deleted the h/layers/double-caching branch August 13, 2017 08:19
@algernon
Copy link
Contributor Author

At a first glance, I'm happy with the new names. Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working enhancement New feature or request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Unbreak the layering (again)
2 participants