Apologies for the delayed response :-) On Monday, November 23, 2015 at 10:35:37 AM UTC-8, Daniel Vogelheim wrote:
(1) reducing the small script threshold from 30 KB, which was preventing >> the background thread from even attempting to parse many scripts. >> > > We should try this. Which threshold did you choose? > I lowered it to 1 byte in an effort to get the script streaming thread to parse as many scripts as possible regardless of size. I realize that this might not be a good strategy since the thread synchronously parses whichever script it gets first, so it actually might decrease overall throughput/utilization. I can try some other settings, (e.g. 1 KB) which might give better signal that the script has a higher probability of being fully downloaded. > > >> (2) forcing the script streaming thread to perform eager rather than lazy >> parsing in hopes of reducing the total amount of parsing happening on the >> main thread. >> > > I expect this to be _very_ bad for memory consumption. The V8 AST - the > result of a parse - is unfortunately rather large, so that not parsing > everything upfront conserves a lot of memory. I'm skeptical this change > would be beneficial in general and think this would require some rather > careful benchmarking across different websites and device types. > > That said, I've recently run across several situations - usually large, > framework-y web apps - where excessive lazy- and then re-parsing was a > problem. I'm quite certain our lazy parse heuristic could be improved; I > don't really have a plan how. If you have any suggestions, I'd be eager to > listen. > > Generally speaking, the heuristic tries to "guess" whether a given > function will be called during the initial script evaluation. This gets > called a lot and hence needs to be fast, and since it needs to decide > before the function is even parsed, it only has the function header to go > on. > Makes sense. I'm mostly seeing how far I can push scripts to parse in the background, so memory wasn't my main concern. But yes, benchmarking to find sensible heuristics seems like a good plan to me :-) Re-parsing is an interesting aspect to this. I'll look into this some more to see if we're getting hit by lots of re-parsing. > > >> (3) allowing the main thread to retry posting parsing tasks to the >> background thread at a later time if the background thread is currently >> busy. >> > > This might make sense, but I guess it's difficult to do, since there isn't > really a good point when that should get done. See below on task > scheduling, though. > > These tweaks may have moved the needly slightly (I'm not 100% convinced >> since I haven't done any rigorous measurements), but I'm still seeing a >> suspiciously high amount of CPU time spent on the main thread parsing JS >> along with a suspiciously low amount of parsing activity on the background >> thread when looking at both Instruments profiles and Chrome traces recorded >> with chrome://tracing. In a simplified test page that tries loading >> multiple async scripts concurrently, I noticed that even when the script >> streaming thread parses a script, it then sends a task back to the main >> thread which then proceeds to do a bunch more lazy parsing! I realize that >> the background thread isn't allowed to generate code so it must give it >> back to the main thread, but this additional parsing time surprised me. >> > > Not sure what you're describing here. There's two things: > > - There's a 'finishing' step to background parsing that needs to happen on > the main thread. Basically, background parsing can't modify any global > state while the main thread might mutate it, so the background parser > builds up a separate data structure, which the main thread will then need > to patch into the heap. This happens for every background parse, and I > don't see a chance to avoid this without a major rewrite. > I think this is what I was referring to. I saw some references to this step in some of the comments. > > - The background parse thread uses the same lazy/eager parse heuristic as > the main thread. If it guesses wrongly, then the main thread will have to > do a lot of synchronous parsing while it executes. > > You should be able to distinguish these in chrome://tracing, as the first > happens before any execute (for that script), while the second happens > during an execute. > Cool, I'll check that out. > > I tried adding some more tracing events to get a better picture of what's >> going on at various times. For example, it seems like we receive JS scripts >> on the main thread in clusters rather than in an evenly spaced manner >> which, due to the fact that the background thread synchronously parses a >> single JS file at a time, causes the other scripts to have to wait to be >> parsed. A pool of worker threads might help some, but probably won't be >> sufficient on devices with low core counts. It might be better if we could >> incrementally parse JS and multiplex multiple JS files on one or two >> parsing threads. Incremental parsing sounds like a big, potentially >> invasive effort though. >> > > Hmm. There are some changes to Chromium's task scheduling in progress, > that might help us here. And with (3) above. That work is still ongoing, > though, and I'm not terribly familiar with it, so I'd need to find the > right people to talk to. > Understanding how Chrome scheduling works would be useful even outside of all this parsing stuff :-) > > I realize that forcing more parsing onto the background thread could cause >> adverse side effects related to page interactivity, but I'd like to be able >> to experiment with different amounts of parsing on either the main thread >> or the background thread. I was wondering, given the steps I've taken, if >> I've missed or misunderstood anything. I think off-main-thread parsing is a >> great idea, so any help debugging/understanding/improving the script >> streaming thread would be very much appreciated :-) And while the script >> streaming stuff was just the first weird thing I stumbled across, given the >> importance of parsing in general on complex, JS-heavy sites like Facebook, >> any additional info related to how V8 does parsing and how sites might be >> able to take advantage of that would be very helpful. >> > > Generally, we might look at (code) caching. The code cache - if successful > - skips the parse entirely. How effective that is of course depends on how > often you update how much of your code; and possibly on how exactly you do > that. > I've also looked into the V8 code cache a little bit. We seem to have a decent hit rate with a warm cache, but we still spend a non-trivial chunk of time in parsing/code-gen looking stuff according to Instruments (the exact numbers escape me right now). I've been wanting to dig into this a bit more to get a sense of the heuristics the cache uses w.r.t. things like size, eviction policy, etc. > > Another, more complex thing (where I'm not sure about the details) might > be Service Workers, since they allow a site to be explicit about what it > wants cached, etc. This is not merely an implementation detail, though, and > may require some greater rework on your side. Honestly, I'm not sure what > the current status of ServiceWorkers is, though. > Facebook is actively investigating using ServiceWorkers more widely for a variety of things, so this might be a possibility. > > > A silly question: How do we reproduce this? https://facebook.com, and I > suspect I need to be logged in? Anything else? > Yep, just refreshing news feed while logged in and waiting until the page has stopped changing/loading. Thanks a bunch! -Mark -- -- v8-dev mailing list [email protected] http://groups.google.com/group/v8-dev --- You received this message because you are subscribed to the Google Groups "v8-dev" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. For more options, visit https://groups.google.com/d/optout.
