Improvements to Lazy Loading

I would love to start talking about the lazy loading again that was added into RW7.2. Users are complaining about things being slower using their projects and some key features in Stacks have become less reliable because of it.

Most users do not have huge large projects that take many minutes to open. To these users, working with their project files feels slower because moving between pages takes longer, open a link dialog could potentially take a long time since all of the pages need to be loaded. I feel that this lazy load feature has hurt more users than it has improved.

The partials feature in Stacks was a huge game changing feature. It allows users to quickly change stacks across many pages. This has become unreliable now with the lazy loading since not all pages that contain a partial are loaded. Users will now change a partial expecting it to work as it did in RW7.1. However, when they publish, not all of their changes actually get published. This is even worse because it makes RapidWeaver and Stack unpredictable. When this happens users will get frustrated and lose trust in the product. None of us want that.

I could be wrong but I am pretty sure that there is nothing that @isaiah can do with this. Its a limitation in the RW API now. The ball is in Realmac’s court. Any serious RapidWeaver user will be using Stacks. When RapidWeaver breaks a major feature of Stacks, it hurts all of us.

I would love to see 2 things happen…

  1. Have an option to disable this and go back to the way things were. Sometimes the side effects are just too annoying.
  2. With lazy loading enabled, it would be great if it were true lazy loading, not just on-demand loading. After the first page of a project loads, RapidWeaver should be loading all of the other pages in the project run the background.
3 Likes

i swear i didn’t put Joe up to this. but since i’ve made both of these suggestions in private email to Tom, I’ll second them. i think both of these would be welcome improvements.

1 Like

This is ideally where we’d like to get to - unfortunately we can’t get there while plugins require most of their loading to be done on the main thread. It’s something that we’ve been working towards but have had to put on the back burner for now. I understand that this would require a decent amount of work from plugin developers to get things loading on background threads. If any plugin developers are happy to put this work in, it’s definitely something that we can look at continuing to work on.
For some plugins, the majority of the loading process is spent doing UI work so there’s no way we can run that in the background. The only speed “improvement” we could add was to defer loading until it was absolutely necessary.

I don’t have any specific feedback on the rest of your post - perhaps @tpbradley can jump in here.

(post withdrawn by author, will be automatically deleted in 24 hours unless flagged)

Hey guys, there’s quite a bit of info here so I’m going to summarise as much as possible.

Opening a link dialog doesn’t load all pages. It did in the initial releases and has been fixed. The cause was down to the page specifying it’s own extension, which we now cache. The user may experience an initial slow down in pre 7.1 projects while things are cached. Cached file extensions are persisted.

The average project has 35 pages with the maximums being between 1500 and 2500 pages. With lazy loading, the average load time for projects with less than 40 pages has decreased from 15 seconds to 2.3 seconds. So for most users, opening a project, making a change and publishing that change is now significantly faster.

So, I think this thread boils down to these two things.

  1. Users reporting that Stacks partials are unpredictable
  2. Page switching is slow

Stacks Partials
I’ve just tested Stacks partials and found that changing a partial does mark all pages using that partial as changed regardless of their loaded state. After hitting publish, all changed pages were published correctly. It’s worth noting that an API was introduced after the launch of lazy loading to allow stacks to do this and so we believe this issue is fixed. If that isn’t the case, then we’d appreciate a video showing what’s going on - preferably in RW 7.3 or 7.3.1.

Page switching
Background loading is a possibility here but for reasons that Simon stated it can’t yet be done. I’d like to reiterate that if plugin devs are willing to update their plugins, we’d be more than happy to add background loading.

Something I’ve heard from beta testers is that duplicating a page in a large project can also be very slow, bringing on the spinning beachball most times.

I would hazard a guess that they are only really seeing this delay on duplicating a Stacks page as it is done on main thread? (built-in pages shouldn’t “beachball” when being duplicated).

I would hazard a guess that they are only really seeing this delay on duplicating a Stacks page as it is done on main thread? (built-in pages shouldn’t “beachball” when being duplicated).

Considering they’re Foundry beta testers they would definitely be duplicating Stacks-based pages. Likely with Partials as well since it is Foundry-based.

I don’t want to talk for @isaiah here. He obviously is much more well versed in all of the nuances of what is happening under the hood here. My main intent was to bring the topic up in the open again so that things can be improved.

I pinged other plugin devs to reply here so that they can provide us with some feedback.

projects with less than 40 pages has decreased from 15 seconds to 2.3 seconds

this is a fact. and no one is debating that. the issue at hand is different:

Pre-7.1 when a document was opened you could do anything without incurring a delay. Post-7.1 some operations come with an unexpected delay: switching pages, export, etc.

i think Joe’s suggestions are all about reducing the unexpected delay – without impacting the new-speedier loading.

I’ve just tested Stacks partials and found that changing a partial does mark all pages using that partial as changed regardless of their loaded state.

Here are the steps:

  1. New project
  2. New stacks page
  3. Add a text stack
  4. Select the text stack and click the Partial button
  5. Exit the partial
  6. Duplicate the page.
  7. Option-key File Menu > Mark all pages as unchanged.
  8. Save and Quit
  9. Launch RW
  10. Double click on the partial to edit
  11. Change the border on the text stack.

Note that the the current page’s blue blue-changed-marker is now set. The other page is not. It should be since it also contains the same partial – that is now changed.

Performing the same operations in RW 7.0 will result in both pages being marked as changed as expected.

It’s worth noting that an API was introduced after the launch of lazy loading to allow stacks to do this and so we believe this issue is fixed

This is news to me. I feel pretty familiar with all the API that’s been changed, but I honestly don’t see any way to do this. Perhaps in my delirium around December I forgot a conversation we had about this? :stuck_out_tongue_closed_eyes:

Please feel free to refresh my memory. You have my consent to post my email about this here and humiliate me into action. :wink:

The current architecture relies on notifications. Each instance of a partial (partial-node) subscribes to change notifications of the partial itself. Unloaded pages are not subscribed to this notification and never see it.

I’ve attempted a number of simple fixes for this, but each involves significant tradeoffs that are worse than the problem I’m trying to fix.

I have some ideas planned for Stacks 4 that could make things easy – but they involve substantial changes to the way partials are managed and stored. Not something I really want to do on a minor point release.

I post this on the forum in response to this. To my knowledge, nothing has change since.

Change in partial does not mark all required pages as changed - #4 by isaiah

Background loading is a possibility here but for reasons that Simon stated it can’t yet be done

Simon said, “plugins require most of their loading to be done on the main thread”

Does that mean me? If so, then can you tell me specifically what you need for this. Maybe send me a private build that shows the problem in action. At least on the surface this seems like an achievable goal for most of my plugins.

You could at least make it an opt-in API – lazy loading for any plugin that opts-in to backgrounded loading. That way I could roll it out all the plugins gradually – with focus on the important ones first.

Isaiah

1 Like

I would hazard a guess that they are only really seeing this delay on duplicating a Stacks page as it is done on main thread? (built-in pages shouldn’t “beachball” when being duplicated).

i suspect the delay that Adam is talking about has nothing to do with duplicating the specific page. nor about “duplicating a Stacks page as it is done on main thread” (honestly, i don’t even know what you’re talking about here – but whatev – i think it’s irrelavent) – all that stuff hasn’t changed recently.

i’ve noticed that changes to the page hierarchy sometimes cause all pages to load. duplicating a page changes the hierarchy. if this happens on a large document, then duplicating a page will cause the “loading all the pages now” beachball.

queue @tpbradley to say this is a non-issue. that these two things aren’t connected. :stuck_out_tongue_closed_eyes:

maybe it’s plugin related. in my rewrite of PlusKit and SiteMap I’ve discovered a number of API calls that unexpectedly lead to page loads.

calling the file extension method, if i recall correctly, was one that bit pluskit. in the end i removed all file-extension stuff from pluskit. i couldn’t find a work-around so it just leaves extensions as-is. users have to do it manually now. i’ll be making the same change to stacks in the future.

I suspect plugins are bumping into these things all the time but just don’t know it. perhaps a solution would be to make it clear when this will happen.

  • in the headers mark the methods that lead to page loads
  • at runtime throw an exception or log it to the console or whatever

Fair enough, do you think there’s anything else you can do in Stacks to improve its loading or rendering speed? I’m not sure there’s anything more we can do here. We can only move around the loading times to make things seem more performant.

Yup, I’ve been able to replicate this behaviour. In my original test project I just added two stacks pages and applied the same partial to each. After reloading the project both pages were loaded (which shouldn’t happen) meaning they received the change notifications and updated their status. This specific case is down to a bug in RW which I’ll get fixed.

We had a conversation about the new API back in October '16… posting to humiliate you into action :stuck_out_tongue_winking_eye:

We need to be able to load and export a stacks page on a background thread. Nearly all plugins can do this so it makes sense to make it the default behaviour rather than adding an opt-in API. I appreciate Stacks is significantly more complex than the average plugin, but it would be great if you could do this.

Yup, just tested and duplicating a page does indeed force all other pages to load. Expect a fix in the next release.

Would be great if you could let us know which ones. Ideally, none of the API calls should force other pages to load. We’ve caught most of them, but some of the lesser-used ones may have slipped though. Also, calling private methods like the file extension override will cause a page load. Removing this is a good call :wink:

Logging when a page load occurs is a good idea, we’ll get this into the next release.

@isaiah New build with the following changes:

  • Duplicating a page should no longer load all pages
  • We now log to the console when a page is loaded
  • Fixed an issue where page migration could be called unnecessarily

Download RapidWeaver 7.3.1 (18606b) Public Beta 4: https://dl.devmate.com/com.realmacsoftware.rapidweaver/18606b/1489754922/RapidWeaver-18606b.zip

Let us know if you need anything else.

2 Likes

do you think there’s anything else you can do in Stacks

Certainly. It’s my top priority for S4.

But it seems like you’re trying to deflect this onto Stacks. What users are reporting is that RW 7.0 seemed faster. Stacks has not changed in that time.

Personally, I don’t really care if you implement those specific changes. When I made similar suggestions I did it just to keep the critique constructive.

I think the important point is to bring up the feedback we’ve had from some users – that RW 7.0 seemed faster.

We had a conversation about the new API back in October

I see. This was a miscommunication. I apologize for that. Marking all pages as changed is one of the “things I tried”.

  1. I assumed this was only a stopgap solution. It’s clearly not ideal to regularly mark every Stacks page as changed on a large file. It’s a step backward from the old behavior.

  2. There was one beta version that had this in place. Users really freak out when you mark every page as changed. The medicine was worse than the disease. I pulled it immediately.

Other things I’ve tried:

  • maintaining a list of partials and the pages they’re contained in.
    Partials can contain each other. Pages can have multiples of the same partial – or even the same partial within multiple different partials. Each change becomes an O(n^2) rebalance of the tree. Yuck.

  • forcing page-load then marking.
    The unexpected delay after making the first change in a partial is disconcerting. In large files it feels like a crash. This, at least, brings back earlier functionality.

We need to be able to load and export a stacks page on a background thread

OK. I just gave it a go. initWithSandwich doesn’t seem to crash when called from the background. At least on a small test file with 2 min. of testing. :wink: I suspect real use cases will uncover more.

What’s the next step?
Maybe send a build?

Nearly all plugins can do this

I think Blocks will be the real hurdle. It was written in 2006 on evenings and weekends. It shows. I don’t see being able to easily extricate the appkit from initWithCoder. If you mandate this is a requirement going forward, I think Blocks would probably get left behind.

Would be great if you could let us know which ones

I can, of course, when I bump into them. But that’s not super often.

Maybe just selected “Callers” in Xcode on and click on the method – see what pops up?

Or maybe create a test-mode for your own builds – insert a 2 second delay on every page load – so the load becomes super-obvious on internal builds.

I don’t want to let this discussion die off again. @dan What is the status?

It’s not dead, we’re discussing internally.

@tpbradley will post a public reply with the lowdown soon.

So right now, plugins do two things on load.

  1. Load data from disk into their model
  2. Build all of the UI

Unfortunately, Stacks is very slow at number 2. Quite possibly due to the number of stacks on a page and the type of stack used.

Some of the Stacks from Big White Duck were really impressive, but incredibly slow at the same time. They really pushed the boat in what the system can do. In some cases a page could take more than 15 seconds to load.

From my point of view, a performance problem needs to be resolved where the problem exists. Adding a background loading feature into RW doesn’t solve the performance problem, it’s treating the symptom.

Lazy loading was added to RW because it doesn’t make sense to waste CPU cycles and consume GBs of memory to have every page loaded just in case the user navigates to it. A user would typically be concentrating on a few pages at a time, not every page in the project. More importantly, lazy loading significantly reduces RW’s energy impact on the system, prolonging battery life.

Turning off lazy loading isn’t the answer here. It’s just treating the symptom. In the case of the example above, I found that simply moving between preview and edit caused a significant slow down. Something that pre-loading wouldn’t alleviate.

So as I see it there are currently two issues that need looking into.

  1. Navigating to an unloaded page is slow.
  2. Editing Stacks partials doesn’t mark related pages as changed.

For reasons stated above we can’t do anything in RW to help with number 1.

@isaiah, if there’s anything we can do to help with number 2 let us know.

If you remember that stack was completely re-written 9 months ago using child stacks and reduced the load time to < 5 seconds in my stress test with 50 of them on a page.

@tav I do remember! It’s a great example of RW running slowly, yet we were unable to do anything about it. You did a great job in optimising those stacks :wink:

This conversation seems to be going 'round and 'round.

I say: Customers tell us RW 7.0 was faster
Tom says: But Stacks is very slow.
I say: Customers tell us RW 7.0 was faster
Tom says: But Stacks is very slow.

So, one last time with feeling:

Customers tell us that RW 7.0 was faster.

I think if you cannot at least acknowledge this bug report then we’re probably at an impasse.

As for your critiques of Stacks’ speed. Yes. All valid concerns – but a bit off topic IMHO.

2 Likes