Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(416)

Side by Side Diff: third_party/WebKit/Source/core/html/parser/BackgroundHTMLParser.cpp

Issue 2065163005: ParseHTMLOnMainThread: notify main thread of chunks less frequently (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Add a setting to the experiment Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2013 Google, Inc. All Rights Reserved. 2 * Copyright (C) 2013 Google, Inc. All Rights Reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions 5 * modification, are permitted provided that the following conditions
6 * are met: 6 * are met:
7 * 1. Redistributions of source code must retain the above copyright 7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer. 8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright 9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the 10 * notice, this list of conditions and the following disclaimer in the
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after
86 86
87 void BackgroundHTMLParser::start(PassRefPtr<WeakReference<BackgroundHTMLParser>> reference, std::unique_ptr<Configuration> config, const KURL& documentURL, std: :unique_ptr<CachedDocumentParameters> cachedDocumentParameters, const MediaValue sCached::MediaValuesCachedData& mediaValuesCachedData, std::unique_ptr<WebTaskRu nner> loadingTaskRunner) 87 void BackgroundHTMLParser::start(PassRefPtr<WeakReference<BackgroundHTMLParser>> reference, std::unique_ptr<Configuration> config, const KURL& documentURL, std: :unique_ptr<CachedDocumentParameters> cachedDocumentParameters, const MediaValue sCached::MediaValuesCachedData& mediaValuesCachedData, std::unique_ptr<WebTaskRu nner> loadingTaskRunner)
88 { 88 {
89 new BackgroundHTMLParser(reference, std::move(config), documentURL, std::mov e(cachedDocumentParameters), mediaValuesCachedData, std::move(loadingTaskRunner) ); 89 new BackgroundHTMLParser(reference, std::move(config), documentURL, std::mov e(cachedDocumentParameters), mediaValuesCachedData, std::move(loadingTaskRunner) );
90 // Caller must free by calling stop(). 90 // Caller must free by calling stop().
91 } 91 }
92 92
93 BackgroundHTMLParser::Configuration::Configuration() 93 BackgroundHTMLParser::Configuration::Configuration()
94 : outstandingTokenLimit(defaultOutstandingTokenLimit) 94 : outstandingTokenLimit(defaultOutstandingTokenLimit)
95 , pendingTokenLimit(defaultPendingTokenLimit) 95 , pendingTokenLimit(defaultPendingTokenLimit)
96 , shouldCoalesceChunks(false)
96 { 97 {
97 } 98 }
98 99
99 BackgroundHTMLParser::BackgroundHTMLParser(PassRefPtr<WeakReference<BackgroundHT MLParser>> reference, std::unique_ptr<Configuration> config, const KURL& documen tURL, std::unique_ptr<CachedDocumentParameters> cachedDocumentParameters, const MediaValuesCached::MediaValuesCachedData& mediaValuesCachedData, std::unique_ptr <WebTaskRunner> loadingTaskRunner) 100 BackgroundHTMLParser::BackgroundHTMLParser(PassRefPtr<WeakReference<BackgroundHT MLParser>> reference, std::unique_ptr<Configuration> config, const KURL& documen tURL, std::unique_ptr<CachedDocumentParameters> cachedDocumentParameters, const MediaValuesCached::MediaValuesCachedData& mediaValuesCachedData, std::unique_ptr <WebTaskRunner> loadingTaskRunner)
100 : m_weakFactory(reference, this) 101 : m_weakFactory(reference, this)
101 , m_token(wrapUnique(new HTMLToken)) 102 , m_token(wrapUnique(new HTMLToken))
102 , m_tokenizer(HTMLTokenizer::create(config->options)) 103 , m_tokenizer(HTMLTokenizer::create(config->options))
103 , m_treeBuilderSimulator(config->options) 104 , m_treeBuilderSimulator(config->options)
104 , m_options(config->options) 105 , m_options(config->options)
105 , m_outstandingTokenLimit(config->outstandingTokenLimit) 106 , m_outstandingTokenLimit(config->outstandingTokenLimit)
106 , m_parser(config->parser) 107 , m_parser(config->parser)
107 , m_pendingTokens(wrapUnique(new CompactHTMLTokenStream)) 108 , m_pendingTokens(wrapUnique(new CompactHTMLTokenStream))
108 , m_pendingTokenLimit(config->pendingTokenLimit) 109 , m_pendingTokenLimit(config->pendingTokenLimit)
109 , m_xssAuditor(std::move(config->xssAuditor)) 110 , m_xssAuditor(std::move(config->xssAuditor))
110 , m_preloadScanner(wrapUnique(new TokenPreloadScanner(documentURL, std::move (cachedDocumentParameters), mediaValuesCachedData))) 111 , m_preloadScanner(wrapUnique(new TokenPreloadScanner(documentURL, std::move (cachedDocumentParameters), mediaValuesCachedData)))
111 , m_decoder(std::move(config->decoder)) 112 , m_decoder(std::move(config->decoder))
112 , m_loadingTaskRunner(std::move(loadingTaskRunner)) 113 , m_loadingTaskRunner(std::move(loadingTaskRunner))
113 , m_tokenizedChunkQueue(config->tokenizedChunkQueue.release()) 114 , m_tokenizedChunkQueue(config->tokenizedChunkQueue.release())
114 , m_startingScript(false) 115 , m_startingScript(false)
115 , m_lastBytesReceivedTime(0.0) 116 , m_lastBytesReceivedTime(0.0)
117 , m_shouldCoalesceChunks(config->shouldCoalesceChunks)
116 { 118 {
117 ASSERT(m_outstandingTokenLimit > 0); 119 ASSERT(m_outstandingTokenLimit > 0);
118 ASSERT(m_pendingTokenLimit > 0); 120 ASSERT(m_pendingTokenLimit > 0);
119 ASSERT(m_outstandingTokenLimit >= m_pendingTokenLimit); 121 ASSERT(m_outstandingTokenLimit >= m_pendingTokenLimit);
120 } 122 }
121 123
122 BackgroundHTMLParser::~BackgroundHTMLParser() 124 BackgroundHTMLParser::~BackgroundHTMLParser()
123 { 125 {
124 } 126 }
125 127
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
218 220
219 void BackgroundHTMLParser::pumpTokenizer() 221 void BackgroundHTMLParser::pumpTokenizer()
220 { 222 {
221 TRACE_EVENT0("loading", "BackgroundHTMLParser::pumpTokenizer"); 223 TRACE_EVENT0("loading", "BackgroundHTMLParser::pumpTokenizer");
222 HTMLTreeBuilderSimulator::SimulatedToken simulatedToken = HTMLTreeBuilderSim ulator::OtherToken; 224 HTMLTreeBuilderSimulator::SimulatedToken simulatedToken = HTMLTreeBuilderSim ulator::OtherToken;
223 225
224 // No need to start speculating until the main thread has almost caught up. 226 // No need to start speculating until the main thread has almost caught up.
225 if (m_input.totalCheckpointTokenCount() > m_outstandingTokenLimit) 227 if (m_input.totalCheckpointTokenCount() > m_outstandingTokenLimit)
226 return; 228 return;
227 229
230 bool shouldNotifyMainThread = false;
228 while (true) { 231 while (true) {
229 if (m_xssAuditor->isEnabled()) 232 if (m_xssAuditor->isEnabled())
230 m_sourceTracker.start(m_input.current(), m_tokenizer.get(), *m_token ); 233 m_sourceTracker.start(m_input.current(), m_tokenizer.get(), *m_token );
231 234
232 if (!m_tokenizer->nextToken(m_input.current(), *m_token)) { 235 if (!m_tokenizer->nextToken(m_input.current(), *m_token)) {
233 // We've reached the end of our current input. 236 // We've reached the end of our current input.
234 sendTokensToMainThread(); 237 shouldNotifyMainThread |= queueChunkForMainThread();
235 break; 238 break;
236 } 239 }
237 240
238 if (m_xssAuditor->isEnabled()) 241 if (m_xssAuditor->isEnabled())
239 m_sourceTracker.end(m_input.current(), m_tokenizer.get(), *m_token); 242 m_sourceTracker.end(m_input.current(), m_tokenizer.get(), *m_token);
240 243
241 { 244 {
242 TextPosition position = TextPosition(m_input.current().currentLine() , m_input.current().currentColumn()); 245 TextPosition position = TextPosition(m_input.current().currentLine() , m_input.current().currentColumn());
243 246
244 if (std::unique_ptr<XSSInfo> xssInfo = m_xssAuditor->filterToken(Fil terTokenRequest(*m_token, m_sourceTracker, m_tokenizer->shouldAllowCDATA()))) { 247 if (std::unique_ptr<XSSInfo> xssInfo = m_xssAuditor->filterToken(Fil terTokenRequest(*m_token, m_sourceTracker, m_tokenizer->shouldAllowCDATA()))) {
245 xssInfo->m_textPosition = position; 248 xssInfo->m_textPosition = position;
246 m_pendingXSSInfos.append(std::move(xssInfo)); 249 m_pendingXSSInfos.append(std::move(xssInfo));
247 } 250 }
248 251
249 CompactHTMLToken token(m_token.get(), position); 252 CompactHTMLToken token(m_token.get(), position);
250 253
251 bool shouldEvaluateForDocumentWrite = false; 254 bool shouldEvaluateForDocumentWrite = false;
252 m_preloadScanner->scan(token, m_input.current(), m_pendingPreloads, &m_viewportDescription, &shouldEvaluateForDocumentWrite); 255 m_preloadScanner->scan(token, m_input.current(), m_pendingPreloads, &m_viewportDescription, &shouldEvaluateForDocumentWrite);
253 256
254 simulatedToken = m_treeBuilderSimulator.simulate(token, m_tokenizer. get()); 257 simulatedToken = m_treeBuilderSimulator.simulate(token, m_tokenizer. get());
255 258
256 // Break chunks before a script tag is inserted and flag the chunk a s starting a script 259 // Break chunks before a script tag is inserted and flag the chunk a s starting a script
257 // so the main parser can decide if it should yield before processin g the chunk. 260 // so the main parser can decide if it should yield before processin g the chunk.
258 if (simulatedToken == HTMLTreeBuilderSimulator::ScriptStart) { 261 if (simulatedToken == HTMLTreeBuilderSimulator::ScriptStart) {
259 sendTokensToMainThread(); 262 shouldNotifyMainThread |= queueChunkForMainThread();
260 m_startingScript = true; 263 m_startingScript = true;
261 } 264 }
262 265
263 m_pendingTokens->append(token); 266 m_pendingTokens->append(token);
264 if (shouldEvaluateForDocumentWrite) { 267 if (shouldEvaluateForDocumentWrite) {
265 m_likelyDocumentWriteScriptIndices.append(m_pendingTokens->size( ) - 1); 268 m_likelyDocumentWriteScriptIndices.append(m_pendingTokens->size( ) - 1);
266 } 269 }
267 } 270 }
268 271
269 m_token->clear(); 272 m_token->clear();
270 273
271 if (simulatedToken == HTMLTreeBuilderSimulator::ScriptEnd || m_pendingTo kens->size() >= m_pendingTokenLimit) { 274 if (simulatedToken == HTMLTreeBuilderSimulator::ScriptEnd || m_pendingTo kens->size() >= m_pendingTokenLimit) {
272 sendTokensToMainThread(); 275 shouldNotifyMainThread |= queueChunkForMainThread();
273 // If we're far ahead of the main thread, yield for a bit to avoid c onsuming too much memory. 276 // If we're far ahead of the main thread, yield for a bit to avoid c onsuming too much memory.
274 if (m_input.totalCheckpointTokenCount() > m_outstandingTokenLimit) 277 if (m_input.totalCheckpointTokenCount() > m_outstandingTokenLimit)
275 break; 278 break;
276 } 279 }
280
281 if (!m_shouldCoalesceChunks && shouldNotifyMainThread) {
282 runOnMainThread(&HTMLDocumentParser::notifyPendingTokenizedChunks, m _parser);
283 shouldNotifyMainThread = false;
284 }
285 }
286 // Wait to notify the main thread about the chunks until we're at the
287 // limit. This lets the background parser generate lots of valuable
288 // preloads before anything expensive (extensions, scripts) take up time
289 // on the main thread. A busy main thread can cause preload delays.
290 if (shouldNotifyMainThread) {
291 runOnMainThread(&HTMLDocumentParser::notifyPendingTokenizedChunks, m_par ser);
277 } 292 }
278 } 293 }
279 294
280 void BackgroundHTMLParser::sendTokensToMainThread() 295 bool BackgroundHTMLParser::queueChunkForMainThread()
281 { 296 {
282 if (m_pendingTokens->isEmpty()) 297 if (m_pendingTokens->isEmpty())
283 return; 298 return false;
284 299
285 #if ENABLE(ASSERT) 300 #if ENABLE(ASSERT)
286 checkThatTokensAreSafeToSendToAnotherThread(m_pendingTokens.get()); 301 checkThatTokensAreSafeToSendToAnotherThread(m_pendingTokens.get());
287 checkThatPreloadsAreSafeToSendToAnotherThread(m_pendingPreloads); 302 checkThatPreloadsAreSafeToSendToAnotherThread(m_pendingPreloads);
288 checkThatXSSInfosAreSafeToSendToAnotherThread(m_pendingXSSInfos); 303 checkThatXSSInfosAreSafeToSendToAnotherThread(m_pendingXSSInfos);
289 #endif 304 #endif
290 305
291 double chunkStartTime = monotonicallyIncreasingTimeMS(); 306 double chunkStartTime = monotonicallyIncreasingTimeMS();
292 std::unique_ptr<HTMLDocumentParser::TokenizedChunk> chunk = wrapUnique(new H TMLDocumentParser::TokenizedChunk); 307 std::unique_ptr<HTMLDocumentParser::TokenizedChunk> chunk = wrapUnique(new H TMLDocumentParser::TokenizedChunk);
293 TRACE_EVENT_WITH_FLOW0("blink,loading", "BackgroundHTMLParser::sendTokensToM ainThread", chunk.get(), TRACE_EVENT_FLAG_FLOW_OUT); 308 TRACE_EVENT_WITH_FLOW0("blink,loading", "BackgroundHTMLParser::sendTokensToM ainThread", chunk.get(), TRACE_EVENT_FLAG_FLOW_OUT);
(...skipping 15 matching lines...) Expand all
309 chunk->tokens = std::move(m_pendingTokens); 324 chunk->tokens = std::move(m_pendingTokens);
310 chunk->startingScript = m_startingScript; 325 chunk->startingScript = m_startingScript;
311 chunk->likelyDocumentWriteScriptIndices.swap(m_likelyDocumentWriteScriptIndi ces); 326 chunk->likelyDocumentWriteScriptIndices.swap(m_likelyDocumentWriteScriptIndi ces);
312 m_startingScript = false; 327 m_startingScript = false;
313 328
314 bool isEmpty = m_tokenizedChunkQueue->enqueue(std::move(chunk)); 329 bool isEmpty = m_tokenizedChunkQueue->enqueue(std::move(chunk));
315 330
316 DEFINE_STATIC_LOCAL(CustomCountHistogram, chunkEnqueueTime, ("Parser.ChunkEn queueTime", 1, 10000, 50)); 331 DEFINE_STATIC_LOCAL(CustomCountHistogram, chunkEnqueueTime, ("Parser.ChunkEn queueTime", 1, 10000, 50));
317 chunkEnqueueTime.count(monotonicallyIncreasingTimeMS() - chunkStartTime); 332 chunkEnqueueTime.count(monotonicallyIncreasingTimeMS() - chunkStartTime);
318 333
319 if (isEmpty) {
320 runOnMainThread(&HTMLDocumentParser::notifyPendingTokenizedChunks, m_par ser);
321 }
322 334
323 m_pendingTokens = wrapUnique(new CompactHTMLTokenStream); 335 m_pendingTokens = wrapUnique(new CompactHTMLTokenStream);
336 return isEmpty;
324 } 337 }
325 338
326 // If the background parser is already running on the main thread, then it is 339 // If the background parser is already running on the main thread, then it is
327 // not necessary to post a task to the main thread to run asynchronously. The 340 // not necessary to post a task to the main thread to run asynchronously. The
328 // main parser deals with chunking up its own work. 341 // main parser deals with chunking up its own work.
329 // TODO(csharrison): This is a pretty big hack because we don't actually need a 342 // TODO(csharrison): This is a pretty big hack because we don't actually need a
330 // CrossThreadClosure in these cases. This is just experimental. 343 // CrossThreadClosure in these cases. This is just experimental.
331 template <typename FunctionType, typename... Ps> 344 template <typename FunctionType, typename... Ps>
332 void BackgroundHTMLParser::runOnMainThread(FunctionType function, Ps&&... parame ters) 345 void BackgroundHTMLParser::runOnMainThread(FunctionType function, Ps&&... parame ters)
333 { 346 {
334 if (isMainThread()) { 347 if (isMainThread()) {
335 (*WTF::bind(function, std::forward<Ps>(parameters)...))(); 348 (*WTF::bind(function, std::forward<Ps>(parameters)...))();
336 } else { 349 } else {
337 m_loadingTaskRunner->postTask(BLINK_FROM_HERE, crossThreadBind(function, std::forward<Ps>(parameters)...)); 350 m_loadingTaskRunner->postTask(BLINK_FROM_HERE, crossThreadBind(function, std::forward<Ps>(parameters)...));
338 } 351 }
339 } 352 }
340 353
341 } // namespace blink 354 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698