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

AltTab is slow to appear when many windows are open #171

Closed
mfn opened this issue Mar 10, 2020 · 53 comments
Closed

AltTab is slow to appear when many windows are open #171

mfn opened this issue Mar 10, 2020 · 53 comments
Labels
need breakthrough Need a breakthrough idea to move forwards performance

Comments

@mfn
Copy link

mfn commented Mar 10, 2020

Using Version 3.1.0 on 10.15.3 (19D76) using a MacBook Pro (15-inch, 2018) 2,9 GHz 6-Core Intel Core i9.

On my endeavor to mimic the HyperSwitch behavior, I set the "Apparition delay" to 0.

Yet it has a noticeable delay before showing me the grid of application. Not just the first time, all the time.

I've HyperSwitch running next to it and, comparatively, it comes up instantly.

In my super-scientific-not-really benchmarking, I would say the delay is about 250-300ms.

How did I came to this number? Apparently, HyperSwitch also has a way to change the delay, it's called "Delay activation for" I've set it to 0. I increased it gradually until I felt the delay matched that of AltTab 🤷‍♀️

I've searched existing issues:

Thanks

Debug profile:

  • App version: 3.1.2
  • App preferences:
    • NSWindow Frame SUUpdateAlert: Optional(530 476 620 392 0 0 1680 1027 )
    • SUHasLaunchedBefore: Optional(1)
    • SULastCheckTime: Optional(2020-03-12 06:05:47 +0000)
    • SUUpdateRelaunchingMarker: Optional(0)
    • hideSpaceNumberLabels: Optional(true)
    • maxScreenUsage: Optional(80)
    • metaKey: Optional(⌥ option)
    • minCellsPerRow: Optional(7)
    • showOnScreen: Optional(Screen including mouse)
    • theme: Optional(❖ Windows 10)
    • windowDisplayDelay: Optional(0)
  • Applications count: 60
  • Windows:
    • {isMinimized: true, isHidden: false, isOnAllSpaces: false, spaceId: 1, spaceIndex: 2}
    • {isMinimized: true, isHidden: false, isOnAllSpaces: false, spaceId: 1, spaceIndex: 2}
    • {isMinimized: true, isHidden: false, isOnAllSpaces: false, spaceId: 1, spaceIndex: 2}
    • {isMinimized: true, isHidden: false, isOnAllSpaces: false, spaceId: 1, spaceIndex: 2}
    • {isMinimized: false, isHidden: false, isOnAllSpaces: false, spaceId: 1, spaceIndex: 2}
    • {isMinimized: false, isHidden: false, isOnAllSpaces: false, spaceId: 1, spaceIndex: 2}
    • {isMinimized: false, isHidden: false, isOnAllSpaces: false, spaceId: 1, spaceIndex: 2}
    • {isMinimized: false, isHidden: false, isOnAllSpaces: false, spaceId: 1, spaceIndex: 2}
    • {isMinimized: false, isHidden: false, isOnAllSpaces: false, spaceId: 1, spaceIndex: 2}
    • {isMinimized: false, isHidden: false, isOnAllSpaces: false, spaceId: 1, spaceIndex: 2}
    • {isMinimized: false, isHidden: false, isOnAllSpaces: false, spaceId: 1, spaceIndex: 2}
    • {isMinimized: false, isHidden: false, isOnAllSpaces: false, spaceId: 1, spaceIndex: 2}
    • {isMinimized: false, isHidden: false, isOnAllSpaces: false, spaceId: 1, spaceIndex: 2}
    • {isMinimized: false, isHidden: false, isOnAllSpaces: false, spaceId: 1, spaceIndex: 2}
    • {isMinimized: false, isHidden: false, isOnAllSpaces: false, spaceId: 1, spaceIndex: 2}
    • {isMinimized: false, isHidden: false, isOnAllSpaces: false, spaceId: 1, spaceIndex: 2}
    • {isMinimized: false, isHidden: false, isOnAllSpaces: false, spaceId: 1, spaceIndex: 2}
    • {isMinimized: false, isHidden: false, isOnAllSpaces: false, spaceId: 1, spaceIndex: 2}
    • {isMinimized: false, isHidden: false, isOnAllSpaces: false, spaceId: 1, spaceIndex: 2}
  • OS version: Version 10.15.3 (Build 19D76)
  • OS architecture: x86_64
  • Locale: en_AT (current)
  • Spaces count: 1
  • Hardware model: MacBookPro15,1
  • Displays count: 1
  • CPU model: Intel(R) Core(TM) i9-8950HK CPU @ 2.90GHz
  • Memory size: 34,36 GB
  • Active CPU count: 12
  • Current CPU frequency: 2.9 Ghz
@lwouis
Copy link
Owner

lwouis commented Mar 10, 2020

Thank you for sharing this feedback! By the way, there is a "send feedback" menu if you click on the menubar item.

image

It creates a form that will basically open a github issue for you. It is very handy for performance issue as it will attach a debug profile of your machine, similar to what you intuitively listed at the top of your message, but more detailed.

image

I think you may want to just put random text and submit it, just to grab the profile from the newly made ticket and paste it here. I would then clean the new ticket so only this one here exists.

Another thing to help investigate this issue would be to use Instruments on the app. It's more involved of course, but that would be way more helpful as we would have hard data to understand where time is spent on your system. On my system everything is instant for instance. You could just run the app with instruments and save the Time Profiler report file as an attachment in this ticket.

Lastly, a simple context questions:

  • Do you have external monitors? What's their resolution? Are they high dpi?
  • Do you have lots of windows open?

I'm trying to imagine the amount of work needed to display the thumbnails in your case.

@lwouis lwouis added performance unreproducible Need help from the author to reproduce the issue labels Mar 11, 2020
@mfn
Copy link
Author

mfn commented Mar 11, 2020

Thank you for sharing this feedback! By the way, there is a "send feedback" menu if you click on the menubar item.

Meh, thanks 😄 Wouldn't occur to me that this is an github template, thx 👍

Btw, I believe it doesn't work. I was prompted with a textarea like entry and when I hit "Send", nothing happened but AltTab also disappeared from the menubar 🤷‍♀️

Do you have external monitors? What's their resolution? Are they high dpi?

No, didn't use any external monitors at all for these tests.

Do you have lots of windows open?

With HyperSwitch I count 13, with AltTab 16. Seems that AltTab does not hide hidden/minimized application.

Another thing to help investigate this issue would be to use Instruments on the app.

Not sure .. is this ? First hit of https://www.google.com/search?hl=en&q=osx%20instruments => https://en.wikipedia.org/wiki/Instruments_(software)

Means I need xcode from app store for this, right?

Thanks!

@lwouis
Copy link
Owner

lwouis commented Mar 12, 2020

@mfn thanks for finding out that the feedback form was crashing the app on submit! I released a fix for that. Could you try to submit using the new version? You can update AltTab by clicking there:

image

You should see the new version 3.1.2 I just released. That one should let you send feedback, with the useful debug profile.

Not sure .. is this ? First hit of https://www.google.com/search?hl=en&q=osx%20instruments => https://en.wikipedia.org/wiki/Instruments_(software)

Means I need xcode from app store for this, right?

It seems you're unfamiliar with the XCode ecosystem. I think it's going to be a bit too tricky for you to investigate the issue then. If you want to invest the time and learn, I'll give you some pointers:

Download and install XCode, Apple official IDE. It is (almost) the only way to work on macOS software. In a terminal, run pod install first, to bring dependencies this project uses. Then you can open this project in XCode by double-clicking the alt-tab-macos.xcworkspace file. Then you can click here to start profiling using Instruments:

image

You may need a lot of learning and OS knowledge. If you don't feel like investing time, then just update to 3.1.2 and submit the feedback form to help us see what's unique about your system that's triggering poor performance in alt-tab ;)

@lwouis
Copy link
Owner

lwouis commented Mar 12, 2020

I opened 25 windows on my retina screen, and indeed alt-tab pops up after a few milliseconds. I think i would be hard to shave even more time than what we are currently doing.

The way HyperSwitch is faster is because they show you old thumbnails they cached. They show you incorrect information basically, then they refresh the thumbnails on a schedule every few seconds.

@mfn
Copy link
Author

mfn commented Mar 12, 2020

The way HyperSwitch is faster is because they show you old thumbnails they cached. They show you incorrect information basically, then they refresh the thumbnails on a schedule every few seconds.

Well, basically this is the answer, isn't it? 😄

I commented on this in #45 (comment) but I'm not sure what was the actual decision not to consider the caching.

You immediate answer in #45 (comment)

I think there is no need to compromise by caching.

🤷‍♀️

From my user perspective:

  • the goal is to switch to another application
  • the goal is not to have to wait until the thumbnails are calculated
    So naturally I'm fine with seeing cached images the first few ms

I can only tell that this works really well for me with HyperSwitch but makes it not possible for me to use AltTab sadly

It seems you're unfamiliar with the XCode ecosystem. I think it's going to be a bit too tricky for you to investigate the issue then. If you want to invest the time and learn, I'll give you some pointers:

Yeah totally, never did anything with it.

run pod install first, to bring dependencies this project uses

~ $ pod
bash: pod: command not found

😢

But I figured it's this cocoapod, so sudo gem install cocoapods did it 👍

Btw, is it updated the lockfile:

diff --git a/Podfile.lock b/Podfile.lock
index 1e903bb..4604eb4 100644
--- a/Podfile.lock
+++ b/Podfile.lock
@@ -17,4 +17,4 @@ SPEC CHECKSUMS:

 PODFILE CHECKSUM: 465451026269525f0f1d2dc7053cf0b789a35421

-COCOAPODS: 1.8.4
+COCOAPODS: 1.9.1

Tried to run this profiler, but:
image

Also the regular Build didn't work:
image

But given what you said, I guess for this purpose it doesn't make sense to continue down this pat anyway as you already pinpointed the difference in behaviour.

Not sure were this leaves this issue. Are you open to consider the caching approach?

@lwouis
Copy link
Owner

lwouis commented Mar 12, 2020

Also the regular Build didn't work

You're close to being able to running it locally. You are missing one step that is running scripts/generate_selfsigned_codesign_certificate.sh. I should I referred you to the contribution docs where it is explained.

Not sure were this leaves this issue. Are you open to consider the caching approach?

Overall, I think if we introduce caching, then we need a proper ticket to explain details about the UX, and things like refresh frequency and other specs. Please have a look at prior discussion where I highlight issues I perceive with caching:

If we don't introduce caching, but still want better performance, then I don't know if a ticket is a good supporting material as performance is a never-ending endeavor. We can always be faster, and what is currently fast enough for someone is not for another person. I want to avoid a never-closing ticket where we track performance. I do want to improve performance as much as possible though. Not sure how to achieve that best though. We are reaching a point where we need low-level experts now that can understand interaction with the GPU and the OS. I tried my best, but I don't have 10 years of experience doing C or C++ so my best is limited.

What do you think?

@mfn
Copy link
Author

mfn commented Mar 14, 2020

What do you think?

Honestly?

Despite all the feedback you gave regarding caching / showing wrong information: I still think it's the way to solve the problem that some (obviously not you) experience a delay they cannot "configure away" 🤷‍♀️

@lwouis
Copy link
Owner

lwouis commented Mar 15, 2020

How about the UI? Would you communicate the fact that the thumbnails are stale to the user with some UI language? (e.g. adding a spinner somewhere on the window until all thumbnails are fresh, dimming a bit the stale thumbnails, marking them with some icon or text if they are stale, etc). Or do you think it's okay to not communicate that info?

I actually think it would be pretty easy to implement caching. Today there is a function to refresh all thumbnails on shortcut press. It may be as easy as calling that function on a timer, then on shortcut press show the UI then call it once more, or even do like HyperSwitch and not even trigger a refresh on shortcut, but just wait for the timer to trigger the next refresh.

To enable caching, there would be a checkbox in the preferences panel "Cache thumbnails for more responsiveness" with a slider to decide the frequency. Something between 1 and 5s maybe?

I'm worried about these background refreshes using the computer resources a lot, especially the battery on unplugged laptops. I wonder if HyperSwitch has a considerable impact on battery life with its continuous background work

@mfn
Copy link
Author

mfn commented Mar 15, 2020

How about the UI? Would you communicate the fact that the thumbnails are stale to the user with some UI language?

It's a valid question.

HyperSwitch just went ahead, implemented caching and, to me knowledge, there's no UI info about it.

HyperSwitch also (again, to my knowledge) doesn't have a dedicated public forum or something, so there's hardy any info / user feedback how users of it perceive it.

I guess they just a) don't care b) cope with it c) chose another tool.

To enable caching, there would be a checkbox in the preferences panel "Cache thumbnails for more responsiveness" with a slider to decide the frequency. Something between 1 and 5s maybe?

Why would there need to be a frequency? Sounds more complex than just chaching.

When I enable caching I will have these two expectations (based on our dialog here):

  1. thumbnails show up as instantly as they can be when I invoke AltTab
  2. in the background a refresh of the thumbs is triggered
    • once it's done doing that, it updates the thumbs in the cache
      • whether this updates the screen UI too depends on whether AltTab is still invoked (as in: the thumbnail is still shown) or not

I'm worried about these background refreshes

If they would be continuously (i.e. frequency) I would be too but I don't follow where this comes from.

thanks!

@lwouis
Copy link
Owner

lwouis commented Mar 15, 2020

If they would be continuously (i.e. frequency) I would be too but I don't follow where this comes from.

I thought HS used a scheduled refresh! I just tested, and it refreshes the thumbnails after a few seconds after you interact with the app. This includes invoking the UI, but also just moving the selected thumbnail left/right triggers it, which is why I assumed in the past that there was a scheduled refresh.

Ok so if there is no periodic re-cache, it means that the thumbnails can get really stale.

I'm fine with adding cache as a preference. Like I said I think the implementation may be trivial. Feel free to open a PR if you want this fast. The current next milestone is focusing on keyboard shortcuts issues.

@lwouis lwouis added preference Introduction of a new preference and removed unreproducible Need help from the author to reproduce the issue labels Mar 15, 2020
@lwouis
Copy link
Owner

lwouis commented Mar 16, 2020

I experimented with some kind of basic caching. Here is the branch where the logic is: show the UI, then update the thumbnails and refresh the UI.

I noticed some interesting things.

The UI still has some ms of latency before it shows in high load situation. I simulate high load by having 63 windows open on my retina display. That's a lot of pixels to push on screen (each thumbnail is a full high dpi image, downscaled, which takes memory and cpu/gpu).

Because it's slow to simply display the cached content, I wondered "is this poor implementation of our NSCollectionView, or is there another limiting factor like the image being downscaled from CPU instead of GPU, or memory recopies from GPU mem to CPU mem. To help shed some light, I launched HyperSwitch to see if they perform fast. If they do, then there is something that we are doing wrong, or not doing.

HS only shows 27 thumbnails in this scenario for some reason. 5 x 5 + 2 offscreen at the bottom. It means it's hard to compare because if I only keep 27 windows, suddently AltTab performs quickly too. Not as quickly, but almost instant too.

Conclusions: caching may be the wrong target here. I think there may be a perf bottleneck with either layout. Only measuring/profiling will reveal where time is actually spent. I did a whole bunch of that already however, and it's extremely hard to find the bottleneck lots of computation is not done in our threads, but on the OS threads. Also the profiling is not showing memory recopy, gpu vs cpu rendering of NSView, layer caches, buffering, etc, which is where I think the bottleneck is.

@lwouis lwouis changed the title Apparition delay of 0 takes longer then 0 until AltTab comes up AltTab appears after a few hundreds milliseconds on some workloads Mar 16, 2020
@lwouis lwouis added help wanted and removed preference Introduction of a new preference labels Mar 16, 2020
@lwouis
Copy link
Owner

lwouis commented Mar 17, 2020

I used Instruments to profile while having hundreds of windows open. I see the following:

image

All the _dispatch_worker_thread2 threads are because when querying all window screenshots, we do it in a multithreaded pool. So all these 1-4ms calls for screenshots are parallel. Very nice.

We see all the latency is coming from Main Thread taking ~200ms. On the right you see where most of the time is spent:

image

The first is 112ms spent on layout:

image

The second is internal CALayer rendering:

image

This confirms my suspicion that it's not so much about caching the pictures as it's actually quite fast to retrieve them all (I know this because I tried to retrieve them 60 times a second in the past to have them be live/video). The issue is with layouting the view.

I think the layout code is pretty poor and can greatly be enhanced. The main issue I believe is in this function. Especially the invalidateLayout and layoutSubtreeIfNeeded calls.

@lwouis
Copy link
Owner

lwouis commented Mar 17, 2020

I pushed code in the cache branch that shows the previous view instantly, then re-layouts. It looks pretty janky but has no latency.

@mfn could you please test it and tell me if you would prefer that experience to the current one? I'll attach a build here for your convenience: AltTab.app.zip

This illustrates that is it possible to have no latency with fresh images being fetched, but that the issue is layout performance. There are many ways to go about optimizing layout:

  • I read about layer issues: some people dismiss NSImageView in the NSCollectionView and use CALayer directly. There may be tricks like that where we more efficiently reuse computed pixels instead of recomputing everything
    * We could start feeding the NSCollectionView with some deltas instead of updating the datasource array and calling reloadData to reload everything. This would let the NSCollectionView optimize its rendering by only re-rendering items that changed. I think this is the most promising avenue right now. This would also allow us to have animations when AltTab is open, and a new window opens in the background. Update: scratch that, if we want fresh thumbnails then we need to reload all items anyway.
  • General optimizations to avoid accumulating garbage: reuse objects instead of creating new ones, etc. This is more in combination with the above 2 points, as it would not generate large gains.

Update: another option I forgot would be to use a third-party OSS library to replace NSCollectionView.

@mfn
Copy link
Author

mfn commented Mar 17, 2020

Oh wow, the performance is like day and night!

WOW, really!

could you please test it and tell me if you would prefer that experience to the current one?

That's a big 👍

@mfn
Copy link
Author

mfn commented Mar 17, 2020

One drawback I noticed is: every time switching to a new window, it now appears instantly but after a few ms it shuffles the recently switches windows in to their (I suppose chronological?) place, which is visible and distracting.

Hard to explain 😄

@mfn
Copy link
Author

mfn commented Mar 19, 2020

I'm finally able to use it daily. I just never could because of this latency.

I'm so grateful you did bear with my on this matter!

(Now I can also give more feedback finally 😏 )

@lwouis
Copy link
Owner

lwouis commented Mar 19, 2020

I worked deeper on this. It's such a complex problem. I've noticed that HyperSwitch has many limitations:

  • Their first invocation shows bogus thumbnails the first time then they are refreshed
  • They don't show more than 27 thumbnails, which means they are dodging the perf problems for high thumbnails number. We could also go that route if we implement paging to replace the scale-down approach that's used today.
  • I haven't tested changing screens between invocations with HS. I expect, it may make it slow to show since they can't cache and need to redraw the whole UI on different screens when you move the mouse back and forth between screens with this preference enabled:
    image
  • HS has many bugs I encountered: app starting/quitting in the background, windows opened/closed in the background, or focus changing, or windows getting resized, etc. Many use-cases that are just broken with HS.

A general thing about caching:

  • We could cache the windows screenshots. However it's only taking a a few ms, so i think it's not useful.
  • We can't cache anything else, because the user can change screen and then the whole layout, size of things, and view layers and not reusable and we need to compute layout + app logic + AppKit gpu/layers/pixels which is where most of the time is spent. There is no way around that.

@mfn note that the version you're using has many issues with corner cases I think. In other words, it's easy to make the app seem fast if you break functionality with some use-cases. Like I don't use the setting to pop the UI on the screen including the mouse, but we have it in AltTab, and if you use that, or have apps open while AltTab is open, or other complex use-cases, I'm sure you will start seeing problems.

I think the way forward is about small optimizations to scrap off a few dozen ms, or complete rewrite to leave NSCollectionView and go with a custom NSView with our custom logic.

@lwouis
Copy link
Owner

lwouis commented Mar 19, 2020

Very interesting discussion here for a similar issues where people discuss AppKit as layer on top of OpenGL/Metal and that either you tune AppKit but it's very hard cause poor documentation, or you just draw it yourself in OpenGL/Metal then you have understanding.

I found especially interesting to learn that WindowServer is doing the rendering work which explains why i don't see rendering in the profiler in Instruments. Something like 20-50ms is spent on AltTab threads, yet i feel it's taking more frames that than to display e2e.

I'll also look into finding ways to measure how many frames it takes to render the window in a more scientific way. I found this tool but there may be better ways like recording the display and keyboard with my iphone slow-mo camera and just counting the frames. But even then, the OS is probably generating lag on it's own so i need to compare to a baseline fast app like maybe typing a character in the terminal? Anyway lots to study here

lwouis added a commit that referenced this issue Mar 24, 2020
Replaced the NSCollectionView with a custom NSView. Benefit includes simpler code, and control over recycling logic.

In cases where the user has many open windows, replaced the downscaling strategy with a scrollable view
@lwouis
Copy link
Owner

lwouis commented Aug 26, 2020

Anyway, in that case I can feel a bit of latency before seeing something.

How does it compare with the public release in that scenario? Better, worse?

I'm actually surprise to hear that because on my laptop if I bring up 200 windows AltTab is still blazing fast to show up. When checking in Instruments, I see around 1-2 frames (16-30ms) of delay to render

@nfekete
Copy link

nfekete commented Aug 26, 2020

I still feel some kind of lag with this build, but that might be due to system being overloaded with so many open windows anyway and not switching to the AltTab app quick enough. In other cases it feels more snappy than the current stable release.
But there is some issue with the display of the window previews. I see that when I do an Alt-Tab and the thumbnails appear, they are more or less correct, then a delayed/deferred update comes where some of the thumbnails gets updated with the wrong thumbnail of another app/window, then another delayed update comes now with the correct thumbnail. Overall there is too much movement in the thumbnail grid and temporarily thumbnails of other windows appear instead of the correct thumbnail for that app. For example, I've temporarily seen one of my open Chrome windows' thumbnail in place of the Slack app's thumbnail.

Update: also, Chrome window thumbnail in place of iTerm2 window thumbnail.

@lwouis
Copy link
Owner

lwouis commented Aug 26, 2020

@nfekete thank you so much for sharing this feedback! You uncovered a logical bug. I think I found the reason why you see the wrong thumbnails in the wrong places. Could you please try this new build? AltTab.app.zip

I see that when I do an Alt-Tab and the thumbnails appear, they are more or less correct, then a delayed/deferred update comes where some of the thumbnails gets updated with the wrong thumbnail of another app/window, then another delayed update comes now with the correct thumbnail. Overall there is too much movement in the thumbnail grid

You say there are 3 "waves" of update? It should be only 1. Could you possible share a video of that in action, using the build I just shared? (Loom is a really fast way to share such video)

@ghost
Copy link

ghost commented Aug 26, 2020

Could you please try this new build? AltTab.app.zip

Hah, didn't notice there was a lag until it was pointed out! Wow this test build (quoted one from 30 mins ago) is way snappier. Amazing! A big 'works' from me! I don't notice any lag with any thumbnails. Entire grid of my 28 windows showed immediately.

@nfekete
Copy link

nfekete commented Aug 26, 2020

You say there are 3 "waves" of update? It should be only 1. Could you possible share a video of that in action, using the build I just shared? (Loom is a really fast way to share such video)

I would say there was the initial display of the thumbnail, then followed by two waves of updates.

I have tried the new build too, and I can confirm the incorrect thumbnail problem that was present in the previous build is now gone and that it's only doing one wave of (visible) update. I put visible there because there might be a second wave as before, but now that the thumbnails are correct it would not be noticeable or visible at all. I tried doing a recording with the previous build but I couldn't reproduce the double update problem again. I'm not sure why.

Most of the time, AltTab appears real quick, most of the time it's perceived as close to instant. Rarely, especially if switching from one complex GUI app to another, then quickly switching back to the previous complex GUI app, there is a slight lag in appearance of the thumbnails, then a delayed update mostly for just the first two thumbnails in the grid (the two thumbnails corresponding to the two complex GUI apps I'm switching back and forth between). This is a huge improvement compared to the current release where - with this amount of open windows - most of the time I had close to one second lag initially, but I could easily trigger 3-4 second lags too, with system under load. The system I am using is a 6 core 2019 MacBook Pro w/ 3k retina + 4k UHD external display, both with fractional scaling - that means most of the time an app window is about 16 million pixels on the external display (fractional scaling @ 2560x1440 is actually 5120x2880 pixels) - I am using full-screen windows most of the time).

@lwouis
Copy link
Owner

lwouis commented Aug 26, 2020

then a delayed update mostly for just the first two thumbnails in the grid

The current code is supposed to work like this:

  • AltTab is summoned
  • Thumbnails for the first 3 windows is fetched
  • UI is shown with first 3 windows being up-to-date, and all others being the cached version
  • Thumbnails get updated 1 by 1, starting from the 4th window; as the first 3 are already up-to-date

Could you share a video of the action? I would really like to see it for myself to try to understand what you're witnessing

@nfekete
Copy link

nfekete commented Aug 26, 2020

Here's a demo video. I recorded the video with KeyCastr running so that you can see when the keys were pressed compared to when AltTab appears on screen and the timing of the updates. Edit: if you take a look at about 30 seconds in the video, after I switch to the SCAD window and do another ⌘⇥, you can see the layout gets updated with the order of the windows changed with the MRU update from the last switch. It takes about 11-12 frames for the AltTab window to appear, and another 15 frames for the first two rows to be updated with the current MRU app order. Don't ask me what is the frame rate of the recording, I wasn't able to figure out. It might be 35 fps or 55 fps, or something else entirely. Edit2: the video is variable frame rate, so I don't know the duration equivalents of those frame counts.

Sometimes I still experience some kind of lag, up to about one second. Many times it's real quick though so I'm not sure where the variation in lag comes from. Note that at this time my system is really heavily overloaded and it might be simply from just MacOS task scheduling, swapping, or some other blocking kernel level task that is preventing AltTab from running.

Side note: I observed that the system in general runs much nicer with application windows minimized. I also set AltTab to only show apps that are not minimized so I can keep the number of non-minimized windows low. This way, usually everything is nice and snappy.

@nathang21
Copy link

@nfekete thank you so much for sharing this feedback! You uncovered a logical bug. I think I found the reason why you see the wrong thumbnails in the wrong places. Could you please try this new build? AltTab.app.zip

This is fantastic, night and day difference for me, much more responsive.

@lwouis
Copy link
Owner

lwouis commented Aug 26, 2020

@nfekete I think at 30s, what we are seeing, is macOS paint cycle being a bit late. It seems to display without the changes for a few frames, then update the view later.

I made a build where I force an update of the view before showing the window. Could you please tell me if the issue still happen? AltTab.app.zip

Regarding the lag, yes it's most likely the computer being slow, not AltTab doing something wrong. AltTab is very dependent on its environment. The thumbnails are coming from the WindowServer. If it's too busy, it will block AltTab while it's getting the info ready.

@nfekete
Copy link

nfekete commented Aug 26, 2020

I can still see a delayed update that is related to a change in the MRU list in the first few thumbnails. See a recording about it. At about 3 seconds, I switch from the Chrome window to an empty Safari Window, skipping over the iTerm2 window. Then, immediately triggering AltTab again (at 9 seconds), I am presented with a thumbnail order of Chrome, iTerm2, Safari, while in fact, the current app is Safari, the and the MRU apps would be Chrome, iTerm2 in that order. So the displayed thumbnails should be of Safari, Chrome, iTerm2 instead. At 10 seconds, the thumbnails are refreshed, now with the correct order.

Regarding the lag, yes it's most likely the computer being slow, not AltTab doing something wrong. AltTab is very dependent on its environment. The thumbnails are coming from the WindowServer. If it's too busy, it will block AltTab while it's getting the info ready.

True, with this many windows open, WindowServer is using ever more CPU cycles. The more open windows you have, the more CPU it's using, and this happens independent of AltTab, even if I don't use AltTab at all. I found that minimizing windows have a huge impact on this aspect.

Otherwise I have to say I am really satisfied with this performance improvement on AltTab's behalf. I think the WindowServer performance problem can not be avoided with so many open, but not minimized windows, so I'm not sure how much more could be improved on AltTab side. Minimizing them works wonderfully though.

@lwouis
Copy link
Owner

lwouis commented Aug 26, 2020

Could you please try this another build? I tried a more aggressive forcing of the update before the window is displayed AltTab.app.zip

Minimizing them works wonderfully though

Yes, during my tests, I had like 40 Chrome windows open with a big animated gif on each. That way I could see the thumbnails being updated in details as each would update and show a different visual on each alt-tab summon. However, I thought I was going crazy because I was seeing lots of them not updating in AltTab, when I was sure the code was correct.

I think some apps like Chrome notice if their windows are not visible (obstructed by other windows, or minimized), and stop rendering, which reduces the burden on the WindowServer, and the system in general.

lwouis added a commit that referenced this issue Aug 26, 2020
BREAKING CHANGE: the window thumbnails are now updated *after* the UI is shown. AltTab will first display its window, with the first 3 thumbnails up-to-date, then asynchronously update the rest of the thumbnails one-by-one. This improves the experience of users with lots of windows open.
@nfekete
Copy link

nfekete commented Aug 26, 2020

It still happens sometimes, but I would say it's really difficult to trigger it in the sense that I have to really push the system hard to happen. See a short video here.

Analyzing the video, considering what I did, this is what happens here:

  1. I have a Finder Window with Airdrop virtual folder opened as the currently focused application window.
  2. I'm AltTab switching and I select an iTerm2 window, then I release the AltTab modifier key, triggering a focus event for the iTerm2 window. AltTab grid is hidden. Video starts here (I had to crop it here because of some private data was visible in the AltTab grid).
  3. The focus transfer is still in the process (WindowServer busy with so many windows open). First, the Finder window is defocuses (this is already visible in the video).
  4. This is the moment when I trigger AltTab again by pressing the ⌘⇥ shortcut. This is visible in the lower left corner of the video.
  5. The focused iTerm2 window is brought to the front. At this moment in time, AltTab was already triggered in the previous step. Another ⌘⇥ keypress is registered that should move the selection in the AltTab grid from the 2nd to the 3rd position later when the grid appears.
  6. AltTab grid appears with the current app shown as being the Finder/AirDrop window, MRU app being a Chrome window with this page. Another ⌘⇥ keypress is registered that should move the selection in the AltTab grid from the 3rd to the 4th position later when AltTab will process these keypresses.
  7. AltTab grid is refreshed with the correct MRU window list: iTerm2 as the currently focused window, Finder/AirDrop as the last focused window, Chrome with the current page as the previous to last. AltTab grid selection moves to 4th position, catching up with previous keypresses.

Based on the above sequence seems that the behavior of AltTab is correct and the grid refresh is only because of the real underlying sequence of these events.

@lwouis
Copy link
Owner

lwouis commented Aug 27, 2020

Oh I see. Basically AltTab starts rendering, and right after the window focus changes, so AltTab refreshes. This looks normal indeed. In your previous videos, it was different though. You were doing slow actions like slowly pressing alt-tab, then AltTab would update even though nothing changed focus in the background.

Would you say that that second kind of issue is gone with the latest build I shared?

@nfekete
Copy link

nfekete commented Aug 27, 2020

I am unsure even about the previous behavior, wether we've seen something else or the same thing as this last time. But based on the testing I did last time, this is as much as I could trigger.

Overall it feels really nice and snappy, I am very satisfied with it.

@lwouis lwouis closed this as completed in da16a0b Aug 27, 2020
lwouis pushed a commit that referenced this issue Aug 27, 2020
# [6.0.0](v5.3.0...v6.0.0) (2020-08-27)

### Bug Fixes

* alt-tab own windows were not shown in alt-tab (closes [#555](#555)) ([8bcbc04](8bcbc04))
* clicking the main window would steal focus ([de02e5b](de02e5b))
* display firefox develop edition fullscreen windows (closes [#558](#558)) ([3250d37](3250d37))
* guarantee alt-tab window is always up-to-date on display ([be4c5f1](be4c5f1))
* ignore zombie processes ([50c8c82](50c8c82))
* moving some of the preferences sliders was very laggy ([a552c4c](a552c4c))
* shortcuts stop working if active app is quit (closes [#557](#557)) ([023561d](023561d))

### Features

* display quickly even with many open windows (closes [#171](#171)) ([da16a0b](da16a0b))
* improve the 3 colored buttons when hovering (closes [#516](#516)) ([3ddedff](3ddedff))
* update chinese localization ([e150a9a](e150a9a))

### Performance Improvements

* alt-tab appears quicker when summoned ([c2bb896](c2bb896))
* main window appears (a few frames) faster on trigger ([2bc09e6](2bc09e6))

### BREAKING CHANGES

* the window thumbnails are now updated *after* the UI is shown. AltTab will first display its window, with the first 3 thumbnails up-to-date, then asynchronously update the rest of the thumbnails one-by-one. This improves the experience of users with lots of windows open.
@ALB13
Copy link

ALB13 commented Aug 28, 2020

Holy COW, this is SOOO much faster! Amazing work, thank-you for taking care of this so fast!

Bummed I missed out on the fun prior to release (it's been one of those weeks), but was pleasantly surprised today when I updated.

@jaekyeom
Copy link

  • Potentially, let the user force sync or async. The preference could be: always sync, always async, automatic. I think this is to be avoided though. Ideally the heuristic is good enough that noone wants to change it.

@lwouis
Thanks for this amazing work!
Are there any plans to add this preference to the app? Thumbnails definitely help in most cases, but sometimes I just want to do a quick alt-tab without even looking at the thumbnails, and I cannot turn on and off "Hide window thumbnails" to make it faster every time ;)

@lwouis
Copy link
Owner

lwouis commented Sep 22, 2020

@jaekyeom in the current release, and for a few releases now, the logic is to drop UI operations such as refreshing thumbnails, when the user releases the shortcut quickly.

If you alt-tab really fast, the app will not refresh thumbnails. The experience should be smooth. Is it not for you?

@jaekyeom
Copy link

jaekyeom commented Sep 23, 2020

@lwouis Actually there were some cases that the AltTab window stays open when I alt-tab quickly, but now I get what the "Apparition delay" is for. After adding a small "Apparition delay", it feels very smooth on quick alt-tabs. Thank you!

ADD:
I've just noticed that even after increasing the "Apparition delay", the active-app-only switch shortcut always wait for the UI to show up instead of switching to the last window instantly. Is this intentional?

@lwouis
Copy link
Owner

lwouis commented Sep 23, 2020

@jaekyeom yes, AltTab has gotten so fast at this point that on most machines I expect the UI to show within only a few frames (less than 50ms) of you pressing the shortcut. Thus if you release it "fast", you are physically still slower than those 50ms, so the app has no chance to recognize it and cancel showing the UI. This result in a visual flicker of the UI. This is a limitation of the user's finger speed.

The workaround is to allow user to have a window of time, a delay before showing the UI. This is what you have set in the preferences. This way AltTab refrains from showing until that time window is over, then it shows. This lets you release quickly and not see the UI at all

@jaekyeom
Copy link

@lwouis Thanks for the answer. To clarify, what I ADDed in my last comment was that the behavior is different for my Shortcut 1 (for "All apps") and Shortcut 2 (for "Active app"). My current setting of the "Apparition delay" is 199ms. If I press Shortcut 1 quickly, then switching happens without the UI showing up. However, when I press Shortcut 2 quickly, windows don't switch instantly and the UI always shows up after the delay.

@lwouis
Copy link
Owner

lwouis commented Sep 23, 2020

Oh thank you for sharing this other bug!

Indeed I was able to reproduce it on v6.6.0. Good news is that the issue is gone in my local build. I'm waiting for people in #556 to give me more feedback to release that version. When that happens, that bug will be fixed for you.

Could you please test the build I shared there to help testing it before release? My current worry is that some people say that shortcut with the shift key are not working properly.

@jaekyeom
Copy link

jaekyeom commented Oct 3, 2020

@lwouis Sorry for the huge delay on my side. In fact, I had downloaded the test build and have been using/testing it. I was going to write a reply at some point, but instead I got totally engaged with some work and thus too busy ;)

This test build indeed solves the original problem I was having!
But I think that the key-hold-down-repeat feature is causing some issue, which turns out to be already reported ( #633 ).

@AChangXD
Copy link

AChangXD commented Sep 9, 2023

This issue is still happening when computing previews

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
need breakthrough Need a breakthrough idea to move forwards performance
Projects
None yet
Development

No branches or pull requests

8 participants