Deweloper odkrył, że podpięcie debuggera Chrome DevTools poprzez Playwright lub Puppeteer spowalnia przesyłanie danych oparte na fetch ponad 20-krotnie, co sprawia, że codzienne testy wydajności stają się mylącymi danymi.

Zagadka, która zapoczątkowała dochodzenie

Coffer, przeglądarkowa pamięć masowa, która szyfruje dane przed wysłaniem ich na serwer, regularnie przesyła pliki o przepustowości klasy gigabitowej przez sieć lokalną. Gdy zespół mierzył prędkość wysyłania, zauważył rozbieżność: pobieranie nasycało łącze, ale wysyłanie odbywało się z prędkością zaledwie jednej ósmej dostępnej przepustowości. Ta rozbieżność skłoniła do trzech rund zmian w kodzie, które nie przyniosły efektu, aż do momentu, gdy czwarta „poprawka” wydawała się dawać ogromny skok – który jednak znikał natychmiast po odłączeniu debuggera.

Co zespół próbował najpierw

Inżynierowie sprawdzali typowe podejrzane elementy:

  • Rozmiar fragmentu (Chunk size) – Podwojenie bloku z 16 MiB do 32 MiB nie zmieniło przepustowości.
  • Pipelining – Nałożenie szyfrowania kolejnego bloku na bieżące przesyłanie dało skromny zysk rzędu 13%, nieodróżnialny od szumu pomiarowego.
  • Współbieżność (Concurrency) – Uruchomienie kilku przesyłań równolegle zakończyło się osiągnięciem tej samej całkowitej prędkości, co sugerowało istnienie globalnego limitu.

Żadna z tych zmian nie wyjaśniała 8-krotnego spowolnienia.

Zaskakujące porównanie bezpośrednie

Aby wyizolować problem, zespół zmienił implementację klienta. Korzystając z .NET HttpClient, zarejestrowali 700 Mbps w tej samej sieci; to samo żądanie wysłane przez API fetch() w Chromium utknęło na poziomie 140 Mbps. Ten drastyczny kontrast wskazywał na stos sieciowy przeglądarki jako winowajcę – dopóki kolejny eksperyment nie wykazał czegoś innego.

Ukryty koszt debuggera

Playwright i Puppeteer sterują Chrome za pomocą Chrome DevTools Protocol (CDP). Protokół ten podłącza debugger do procesu przeglądarki, udostępniając zdarzenia sieciowe, migawki DOM i logi konsoli. Zespół przeprowadził ukierunkowany test: wywołanie fetch() wysyłające ładunek typu Uint8Array, raz z podłączonym debuggerem CDP, a raz bez niego.

  • Podłączony debugger: 113 Mbps

Obecność debuggera zmniejszyła prędkość wysyłania ponad 20-krotnie. Ręczny test w zwykłym oknie Edge – bez podłączonego debuggera – osiągnął ponad 600 Mbps, co potwierdziło, że sama przeglądarka potrafi obsłużyć taki ruch, gdy nie jest obciążona dodatkowymi procesami.

Skromna, realna poprawa

Choć debugger odpowiadał za większość spowolnienia, zespół odkrył również autentyczną optymalizację: zmiana ciała żądania z Uint8Array na Blob zwiększyła prędkość w Chromium o około 30%. Jest to przydatna poprawka, ale daleka od „cudownego” przyspieszenia, na które pierwotnie liczono.

Dlaczego jest to ważne dla inżynierów

  • Narzędzia mogą kłamać. Narzędzia do pomiaru wydajności, które automatyzują przeglądarki, same stanowią część łańcucha pomiarowego.
  • Benchmarki, które wydają się niemożliwe, wymagają weryfikacji. Jeśli liczby drastycznie odbiegają od przepustowości sieci, środowisko pomiarowe powinno być pierwszym podejrzanym.
  • Wynik zerowy jest wartościowy. Potwierdzenie, że zmiana nic nie daje, zapobiega marnowaniu wysiłku na ściganie fantomowych błędów.
  • Ręczne kontrole to tani sposób na ubezpieczenie. Uruchomienie tej samej operacji w zwykłym oknie przeglądarki może ujawnić ukryty narzut związany z instrumentacją.

Kontrargument: kiedy debuggery są niezbędne

Debuggery zapewniają wgląd w zachowanie strony, ślady błędów i osie czasu sieci, które w przeciwnym razie są niedostępne. W przypadku testów regresyjnych, audytów bezpieczeństwa czy złożonych interakcji UI, podłączenie debuggera CDP jest często nieuniknione. Kluczem jest oddzielenie testów funkcjonalnych od surowych pomiarów wydajności oraz wyłączenie debuggera, gdy to właśnie te drugie są celem.

Wniosek: Narzędzia, które umożliwiają automatyzację testów, mogą stać się również największym źródłem zniekształceń wydajności. Zanim zaczniesz obwiniać przeglądarkę, sieć lub kod, sprawdź, czy żaden debugger po cichu nie ogranicza strumienia danych.