Changeset 129239 in webkit
- Timestamp:
- Sep 21, 2012 10:28:24 AM (12 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r129236 r129239 1 2012-09-21 Evan Wallace <evan.exe@gmail.com> 2 3 [WebSocket] Receiving a large message is really slow 4 https://bugs.webkit.org/show_bug.cgi?id=97237 5 6 Reviewed by Alexey Proskuryakov. 7 8 WebSocketChannel always reallocates its internal buffer when it receives 9 and appends new data which causes dramatic slowdowns for messages over 10 2 MB in size. This patch changes the internal buffer of WebSocketChannel 11 from a raw char array to a Vector<char> and uses its amortized append() 12 method. This brings the time to receive a 5 MB message from 5.2 seconds 13 to 0.25 seconds. 14 15 This patch is only for optimization. No new tests are needed. 16 17 * Modules/websockets/WebSocketChannel.cpp: 18 (WebCore::WebSocketChannel::WebSocketChannel): 19 (WebCore::WebSocketChannel::~WebSocketChannel): 20 (WebCore::WebSocketChannel::fail): 21 (WebCore::WebSocketChannel::resume): 22 (WebCore::WebSocketChannel::didReceiveSocketStreamData): 23 (WebCore::WebSocketChannel::appendToBuffer): 24 (WebCore::WebSocketChannel::skipBuffer): 25 (WebCore::WebSocketChannel::processBuffer): 26 (WebCore::WebSocketChannel::resumeTimerFired): 27 (WebCore::WebSocketChannel::processFrame): 28 * Modules/websockets/WebSocketChannel.h: 29 1 30 2012-09-21 Andrey Adaikin <aandrey@chromium.org> 2 31 -
trunk/Source/WebCore/Modules/websockets/WebSocketChannel.cpp
r124846 r129239 74 74 : m_document(document) 75 75 , m_client(client) 76 , m_buffer(0)77 , m_bufferSize(0)78 76 , m_resumeTimer(this, &WebSocketChannel::resumeTimerFired) 79 77 , m_suspended(false) … … 98 96 WebSocketChannel::~WebSocketChannel() 99 97 { 100 fastFree(m_buffer);101 98 } 102 99 … … 207 204 RefPtr<WebSocketChannel> protect(this); // The client can close the channel, potentially removing the last reference. 208 205 m_shouldDiscardReceivedData = true; 209 if ( m_buffer)210 skipBuffer(m_buffer Size); // Save memory.206 if (!m_buffer.isEmpty()) 207 skipBuffer(m_buffer.size()); // Save memory. 211 208 m_deflateFramer.didFail(); 212 209 m_hasContinuousFrame = false; … … 239 236 { 240 237 m_suspended = false; 241 if (( m_buffer|| m_closed) && m_client && !m_resumeTimer.isActive())238 if ((!m_buffer.isEmpty() || m_closed) && m_client && !m_resumeTimer.isActive()) 242 239 m_resumeTimer.startOneShot(0); 243 240 } … … 313 310 return; 314 311 } 315 while (!m_suspended && m_client && m_buffer)312 while (!m_suspended && m_client && !m_buffer.isEmpty()) 316 313 if (!processBuffer()) 317 314 break; … … 393 390 bool WebSocketChannel::appendToBuffer(const char* data, size_t len) 394 391 { 395 size_t newBufferSize = m_bufferSize + len; 396 if (newBufferSize < m_bufferSize) { 397 LOG(Network, "WebSocket buffer overflow (%lu+%lu)", static_cast<unsigned long>(m_bufferSize), static_cast<unsigned long>(len)); 398 return false; 399 } 400 char* newBuffer = 0; 401 if (!tryFastMalloc(newBufferSize).getValue(newBuffer)) 402 return false; 403 404 if (m_buffer) 405 memcpy(newBuffer, m_buffer, m_bufferSize); 406 memcpy(newBuffer + m_bufferSize, data, len); 407 fastFree(m_buffer); 408 m_buffer = newBuffer; 409 m_bufferSize = newBufferSize; 392 size_t newBufferSize = m_buffer.size() + len; 393 if (newBufferSize < m_buffer.size()) { 394 LOG(Network, "WebSocket buffer overflow (%lu+%lu)", static_cast<unsigned long>(m_buffer.size()), static_cast<unsigned long>(len)); 395 return false; 396 } 397 m_buffer.append(data, len); 410 398 return true; 411 399 } … … 413 401 void WebSocketChannel::skipBuffer(size_t len) 414 402 { 415 ASSERT(len <= m_bufferSize); 416 m_bufferSize -= len; 417 if (!m_bufferSize) { 418 fastFree(m_buffer); 419 m_buffer = 0; 420 return; 421 } 422 memmove(m_buffer, m_buffer + len, m_bufferSize); 403 ASSERT(len <= m_buffer.size()); 404 memmove(m_buffer.data(), m_buffer.data() + len, m_buffer.size() - len); 405 m_buffer.resize(m_buffer.size() - len); 423 406 } 424 407 … … 427 410 ASSERT(!m_suspended); 428 411 ASSERT(m_client); 429 ASSERT( m_buffer);430 LOG(Network, "WebSocketChannel %p processBuffer %lu", this, static_cast<unsigned long>(m_buffer Size));412 ASSERT(!m_buffer.isEmpty()); 413 LOG(Network, "WebSocketChannel %p processBuffer %lu", this, static_cast<unsigned long>(m_buffer.size())); 431 414 432 415 if (m_shouldDiscardReceivedData) … … 434 417 435 418 if (m_receivedClosingHandshake) { 436 skipBuffer(m_buffer Size);419 skipBuffer(m_buffer.size()); 437 420 return false; 438 421 } … … 441 424 442 425 if (m_handshake->mode() == WebSocketHandshake::Incomplete) { 443 int headerLength = m_handshake->readServerHandshake(m_buffer , m_bufferSize);426 int headerLength = m_handshake->readServerHandshake(m_buffer.data(), m_buffer.size()); 444 427 if (headerLength <= 0) 445 428 return false; … … 457 440 skipBuffer(headerLength); 458 441 m_client->didConnect(); 459 LOG(Network, "remaining in read buf %lu", static_cast<unsigned long>(m_buffer Size));460 return m_buffer;442 LOG(Network, "remaining in read buf %lu", static_cast<unsigned long>(m_buffer.size())); 443 return !m_buffer.isEmpty(); 461 444 } 462 445 ASSERT(m_handshake->mode() == WebSocketHandshake::Failed); … … 478 461 479 462 RefPtr<WebSocketChannel> protect(this); // The client can close the channel, potentially removing the last reference. 480 while (!m_suspended && m_client && m_buffer)463 while (!m_suspended && m_client && !m_buffer.isEmpty()) 481 464 if (!processBuffer()) 482 465 break; … … 518 501 bool WebSocketChannel::processFrame() 519 502 { 520 ASSERT( m_buffer);503 ASSERT(!m_buffer.isEmpty()); 521 504 522 505 WebSocketFrame frame; 523 506 const char* frameEnd; 524 507 String errorString; 525 WebSocketFrame::ParseFrameResult result = WebSocketFrame::parseFrame(m_buffer , m_bufferSize, frame, frameEnd, errorString);508 WebSocketFrame::ParseFrameResult result = WebSocketFrame::parseFrame(m_buffer.data(), m_buffer.size(), frame, frameEnd, errorString); 526 509 if (result == WebSocketFrame::FrameIncomplete) 527 510 return false; … … 531 514 } 532 515 533 ASSERT(m_buffer < frameEnd);534 ASSERT(frameEnd <= m_buffer + m_bufferSize);516 ASSERT(m_buffer.data() < frameEnd); 517 ASSERT(frameEnd <= m_buffer.data() + m_buffer.size()); 535 518 536 519 OwnPtr<InflateResultHolder> inflateResult = m_deflateFramer.inflate(frame); … … 586 569 } 587 570 m_continuousFrameData.append(frame.payload, frame.payloadLength); 588 skipBuffer(frameEnd - m_buffer );571 skipBuffer(frameEnd - m_buffer.data()); 589 572 if (frame.final) { 590 573 // onmessage handler may eventually call the other methods of this channel, … … 618 601 else 619 602 message = ""; 620 skipBuffer(frameEnd - m_buffer );603 skipBuffer(frameEnd - m_buffer.data()); 621 604 if (message.isNull()) 622 605 fail("Could not decode a text frame as UTF-8."); … … 628 611 ASSERT(m_continuousFrameData.isEmpty()); 629 612 m_continuousFrameData.append(frame.payload, frame.payloadLength); 630 skipBuffer(frameEnd - m_buffer );613 skipBuffer(frameEnd - m_buffer.data()); 631 614 } 632 615 break; … … 636 619 OwnPtr<Vector<char> > binaryData = adoptPtr(new Vector<char>(frame.payloadLength)); 637 620 memcpy(binaryData->data(), frame.payload, frame.payloadLength); 638 skipBuffer(frameEnd - m_buffer );621 skipBuffer(frameEnd - m_buffer.data()); 639 622 m_client->didReceiveBinaryData(binaryData.release()); 640 623 } else { … … 643 626 ASSERT(m_continuousFrameData.isEmpty()); 644 627 m_continuousFrameData.append(frame.payload, frame.payloadLength); 645 skipBuffer(frameEnd - m_buffer );628 skipBuffer(frameEnd - m_buffer.data()); 646 629 } 647 630 break; … … 668 651 else 669 652 m_closeEventReason = ""; 670 skipBuffer(frameEnd - m_buffer );653 skipBuffer(frameEnd - m_buffer.data()); 671 654 m_receivedClosingHandshake = true; 672 655 startClosingHandshake(m_closeEventCode, m_closeEventReason); … … 679 662 case WebSocketFrame::OpCodePing: 680 663 enqueueRawFrame(WebSocketFrame::OpCodePong, frame.payload, frame.payloadLength); 681 skipBuffer(frameEnd - m_buffer );664 skipBuffer(frameEnd - m_buffer.data()); 682 665 break; 683 666 … … 685 668 // A server may send a pong in response to our ping, or an unsolicited pong which is not associated with 686 669 // any specific ping. Either way, there's nothing to do on receipt of pong. 687 skipBuffer(frameEnd - m_buffer );670 skipBuffer(frameEnd - m_buffer.data()); 688 671 break; 689 672 690 673 default: 691 674 ASSERT_NOT_REACHED(); 692 skipBuffer(frameEnd - m_buffer );675 skipBuffer(frameEnd - m_buffer.data()); 693 676 break; 694 677 } 695 678 696 return m_buffer;679 return !m_buffer.isEmpty(); 697 680 } 698 681 -
trunk/Source/WebCore/Modules/websockets/WebSocketChannel.h
r124846 r129239 196 196 OwnPtr<WebSocketHandshake> m_handshake; 197 197 RefPtr<SocketStreamHandle> m_handle; 198 char* m_buffer; 199 size_t m_bufferSize; 198 Vector<char> m_buffer; 200 199 201 200 Timer<WebSocketChannel> m_resumeTimer;
Note: See TracChangeset
for help on using the changeset viewer.