Ottimizzazione delle prestazioni di blocco dei caratteri


13

Voglio eseguire una variante della corrispondenza del blocco caratteri ancorato. Ho delle definizioni di funzione che iniziano con un elenco di nomi e voglio che quei nomi vengano evidenziati all'interno del corpo della funzione.

Ho creato una funzione che lo fa e l'ho registrata come funzione jit-lock con jit-lock-register, tuttavia le prestazioni sono piuttosto scarse e lo scorrimento è in ritardo nei file più grandi.

  • Come posso misurare le prestazioni? Se ho appena tempo di chiamare la mia funzione su un file di grandi dimensioni (con float-time prima e dopo o con elp) ottengo prestazioni molto diverse, ci vuole da 0,65 a 12 secondi. Esiste un modo consigliato per confrontare le prestazioni di blocco dei caratteri?
  • C'è qualche differenza nelle prestazioni tra un matcher ancorato definito in parole chiave lock-font e l'aggiunta di una funzione tramite jit-lock-register?

Modifica: sembra che la variabilità delle prestazioni sia correlata alla garbage collection, le invocazioni della mia funzione jit-lock diventano progressivamente più lente con ogni invocazione fino a quando viene eseguita la garbage collection, a quel punto diventano nuovamente veloci.


Per il primo articolo, prova il profiler.
Malabarba,

Posso (e ho) usato anche il profiler per vedere quali parti del mio codice richiedono tempo, ma poiché le prestazioni sono così incoerenti, è difficile dire se eventuali modifiche apportate sono un miglioramento o meno.
Joakim Hårsman,

Hai del codice che possiamo testare? Questo potrebbe aiutarci molto.
PythonNut,

1
Sebbene non riguardi la profilazione o le micro-ottimizzazioni, di per sé: ho trovato il pacchetto font-lock-studio come un altro strumento utile per comprendere le prestazioni di font-lock. Può aiutare allo stesso modo di qualsiasi altro debugger stepping interattivo: potresti scoprire che i percorsi di esecuzione non sono quelli che ti aspetti, e questo è il problema principale delle prestazioni.
Greg Hendershott,

Grazie per il suggerimento su font-lock-studio, è fantastico! Tuttavia non aiuta con le funzioni jit-lock, ma sicuramente lo fa con tutto il resto.
Joakim Hårsman,

Risposte:


8

Si scopre che le prestazioni selvaggiamente variabili erano legate alla garbage collection. Ogni chiamata alla funzione diventerebbe più lenta fino a quando non verrà eseguita una garbage collection. Con stock emacs, gc veniva eseguito ogni paio di secondi, ma avevo una riga nel mio init.el per migliorare il tempo di avvio che impostava gc-contro-soglia a 20 MB e ciò significava che gc veniva eseguito molto più raramente, facendo sì che i benchmark riferire tempi più lenti e più lenti fino a quando un paio di minuti è stato eseguito un gc, quindi i tempi sarebbero precipitati ed essere di nuovo veloci.

Dopo aver ripristinato il valore predefinito di gc-cons-threshhold, il benchmarking è diventato più semplice.

Ho quindi profilato per la memoria con il profiler incorporato ( M-x profiler-start) e ho scoperto che le chiamate a sintassi-pps causavano la maggior parte delle allocazioni, quindi dopo qualche ottimizzazione per chiamare sintassi-pps meno spesso ho raggiunto prestazioni accettabili.

L'uso della modalità jit-lock (aggiunta di una funzione tramite jit-lock-register) sembra essere il modo più semplice per far funzionare in modo affidabile il blocco dei font su più righe, quindi quello è stato il metodo che ho scelto.

Modifica: dopo aver scoperto che le prestazioni non erano ancora abbastanza buone in buffer molto grandi, ho trascorso molto tempo a ottimizzare l'uso e l'allocazione della CPU, misurando i miglioramenti delle prestazioni con il profiler Emacs incorporato ( M-x profiler-start). Tuttavia, Emacs continua a balbettare e si blocca quando si scorre rapidamente attraverso buffer molto grandi. La rimozione della funzione jit-lock con cui mi sono registrato jit-lock-registerrimuoveva la balbuzie e si blocca, ma la creazione di profili ha mostrato che la funzione jit-lock si completerebbe in circa 8 ms, che dovrebbe essere abbastanza veloce per uno scorrimento regolare. La rimozione della chiamata jit-lock-registere invece l'utilizzo di un normale matcher di blocco dei caratteri e delle parole chiave ha risolto il problema.

TLDR: farlo è stato lento e balbettare:

(defun my-font-lock-function (start end)
"Set faces for font-lock between START and END.")

(jit-lock-register 'my-font-lock-function)

In questo modo è stato veloce e non balbettare:

(defun my-font-lock-function (start end)
"Set faces for font-lock between START and END.")

(defun my-font-lock-matcher (limit)
    (my-font-lock-function (point) limit)
   nil)

(setq font-lock-defaults
  (list 
     ...
    ;; Note that the face specified here doesn't matter since
    ;; my-font-lock-matcher always returns nil and sets the face on
    ;; its own.
    `(my-font-lock-matcher (1 font-lock-keyword-face nil))))

Potresti condividere il codice che hai usato? La tua soluzione potrebbe aiutare gli altri a cercare di ottenere la stessa cosa.
Manuel Uberti,

Non ho davvero usato alcun codice specifico, ho solo chiamato meno sintassi-pps. Puoi controllare il codice in questione qui: bitbucket.org/harsman/dyalog-mode/src/… Cerca dyalog-fontify-locals.
Joakim Hårsman,

Immagino che dyalog-fontify-locals-matcherdovrebbe essere my-font-lock-matchere uno dei enddovrebbe essere limit. Comunque, scoperta davvero interessante!
Lindydancer il

@Lindydancer: Sì, grazie. Fisso.
Joakim Hårsman,

1
Ri gc-cons-threshold:, se stai incasinando i valori interni solo per migliorare i tempi di avvio, ti suggerisco di usarli emacs-startup-hookper ripristinarli in seguito.
phils,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.