HPN #04: ottimizzazione speculativa con Chrome Predictor

Di - 29 May 2013 - in
High Performance Networking

Chrome diventa più veloce finché viene usato. Questa frase si sente dire spesso, ma dì per sé non significa nulla. Vediamo allora di capire cosa vuol dire e perché non è una vuota trovata di marketing. Chrome usa un oggetto chiamato Predictor, che è un’istanza del kernel process del browser e ha il solo scopo di osservare gli schemi di navigazione per imparare e anticipare le azioni future più probabili dell’utente. Per comprendere i contenuti di questa puntata è necessario aver letto la precedente, in quanto vengono usati termini e concetti ivi spiegati.

Andiamo più a fondo nella scoperta di questo oggetto vedendo alcuni esempi di segnali processati:

  • Il rollover (passaggio col puntatore del mouse) su un link indica un prossimo probabile evento di navigazione, che Chrome può accelerare effettuando un DNS lookup speculativo dell’hostname di destinazione, così come potenzialmente iniziare il TCP handshake. Quando l’utente clicca sul link in questione (che avviene circa 200ms dopo il rollover), c’è una buona probabilità che il browser abbia già completato i passi relativi a DNS e TCP, risparmiando centinaia di millisecondi di latenza per l’evento di navigazione.
  • Quando si scrive nella Omnibox (la barra degli indirizzi) vengono visualizzati suggerimenti molto probabili. Il vantaggio in questo caso può essere davvero grande, perché i suggerimenti sono dei risultati di precedenti navigazioni e vengono tenuti molto in considerazione dal browser, che può effettuare DNS lookup, TCP handshake e addirittura renderizzare la pagina in una scheda nascosta.
  • Ogni utente ha una lista di siti preferiti, che Chrome impara a conoscere. In particolare, il browser ricorda le risorse di questi siti e può risolverle ed effettuarne il fetch anticipato per accelerare la navigazione.

La lista può continuare per molto, ma ormai ci siamo fatti un’idea di quanto possa essere accelerata la navigazione in Chrome, quasi ad avvicinarsi a quel Sacro Graal che è il caricamento istantaneo delle pagine. Tutto questo è frutto dell’esperienza, di ciò che il browser impara finché viene utilizzato, il risultato di stime probabilistiche sulle ricerche fatte nel tempo. All’atto pratico, come abbiamo visto negli esempi soprastanti, Chrome utilizza quattro tecniche per l’ottimizzazione:

  • DNS pre-resolve: risoluzione degli hostname in anticipo, per evitare la latenza DNS
  • TCP pre-connect: connessione al server destinazione in anticipo, per evitare la latenza del TCP handshake
  • Resource prefetching: fetch di risorse critiche in anticipo, per accelerare il rendering della pagina
  • Page prerendering: fetch anticipato dell’intera pagina con tutte le sue risorse per abilitare il caricamento istantaneo

La decisione di utilizzare una o più di queste tecniche è ottimizzata da un gran numero di vincoli, ma si tratta sempre di ottimizzazione speculativa, il che significa che se fatta in modo sbagliato può effettuare del lavoro inutile, comportare traffico eccessivo e, addirittura, avere un effetto negativo nel tempo di caricamento delle pagine che sono realmente destinazione dell’utente.

Questo è un problema che Chrome affronta, come già detto, con il tempo. Il Predictor analizza più segnali possibili, tra cui le azioni generate dall’utente, i dati presenti nella cronologia di navigazione, così come segnali dal renderer e dal network stack. In modo simile al ResourceDispatcherHost, che è responsabile del coordinamento di tutta l’attività di navigazione di Chrome, l’oggetto Predictor crea dei filtri sull’attività generata dall’utente e dal network:

  • Filtro IPC per monitorare i segnali provenienti dai render process;
  • L’oggetto ConnectInterceptor, aggiunto ad ogni richiesta, per osservare il traffico e registrare le metriche di successo per ogni risorsa.

Facciamo un piccolo esempio. Il render process può inviare un messaggio al processo del browser con uno dei seguenti suggerimenti, che sono definiti adeguatamente in ResolutionMotivation (url_info.h):

enum ResolutionMotivation {
 MOUSE_OVER_MOTIVATED,    // Mouse-over avviato dall'utente
 OMNIBOX_MOTIVATED,    // La Omnibox ha suggerito la risoluzione
 STARTUP_LIST_MOTIVATED,    // La risorsa è tra le prime 10    nella lista di avvio
 EARLY_LOAD_MOTIVATED,    // In alcuni casi viene usato il prefetcher
 // per avviare la connessione in anticipo
 // I seguenti utilizzano il prefetch predittivo, avviato da una navigazione.
 // Viene impostato anche il referring_url_ quando questi messaggi vengono usati.
 STATIC_REFERAL_MOTIVATED,    // Un database esterno suggerisce questa risoluzione
 LEARNED_REFERAL_MOTIVATED,    // Una navigazione precedente indica questa direzione
 SELF_REFERAL_MOTIVATED,        // Indovina la necessità di una nuova connessione
 }

Dato questo segnale, il compito del Predictor è di valutare la probabilità di successo e gestire l’attività delle risorse, se disponibili. Ogni suggerimento può avere una probabilità di successo propria, una priorità, un tempo di scadenza. La combinazione di tutti questi attributi può essere utilizzata per definire e mantenere una coda di priorità interna di ottimizzazione speculativa.
Infine, per ogni richiesta soddisfatta proveniente da questa lista, il Predictor è in grado di tracciare il suo tasso di successo, fattore che aiuta a migliorare successive decisioni.

Con questa puntata abbiamo concluso l’approfondimento sull’architettura di Google Chrome. Dal prossimo appuntamento cominceremo ad innoltrarci nel vivo dell’ottimizzazione, quindi continuate a seguirci!

Leave a Reply

Mattia Migliorini Articolo scritto da

Studente di informatica presso l’Università di Padova, web designer, amante di Linux e dell’open source in generale.
Membro di Ubuntu e di 2viLUG, da gennaio 2012 è collaboratore di Engeene.

Contatta l'autore

Previous post:

Next post: