Acelere las entradas de org-map cuando coincida por propiedad

8

Pregunta : ¿Por qué la org-map-entriescoincidencia de propiedades es tan lenta y qué puedo hacer para acelerarla?

Antecedentes : tengo un uso relativamente simple para org-map-entries: tomar el esfuerzo (en minutos enteros) de todas las entradas de la agenda de la organización con etiqueta goaly una prioridad dada (por ejemplo B).

(org-map-entries #'hw-org-get-effort-in-minutes "goal+PRIORITY=\"B\"" 'agenda)

Esto es terriblemente lento, toma más de un minuto para mi archivo de agenda de ~ 12k líneas.

Sin embargo, si elimino el PRIORITYfiltro para goalsque se seleccione cualquier elemento etiquetado, se completa casi al instante.

También puedo configurar filtros como goal/DONEy se completan muy rápidamente, pero si hago algo así goals+EFFORT>0, volveremos a tomar más de un minuto. Parece que las propiedades en general son muy lentas para igualar.

Encontré una solución alternativa : puedo hacer coincidir propiedades dentro de la función asignada muy rápidamente usando org-entry-get. Cuando hago esto, la ejecución es menos de un segundo. Esto parece una tontería, espero que haya una mejor manera, ¡pero al menos funciona!

Ya lo intenté : desde que (benchmark 1000 (hw-org-effort-to-minutes "1:20"))regresa "Elapsed time: 0.000019s", no creo que mi función contribuya mucho.

De acuerdo con profiler, ~ 40% del tiempo de CPU es utilizado por cond, con ~ 29% proveniente del análisis de elementos ( org-element--current-element). Las siguientes dos contribuciones más grandes en general son 14% y 13%, por lo que el 40% condparece ser la mayor parte del problema. No estoy seguro de por qué el análisis de elementos se haría con más frecuencia con los emparejadores de propiedades, a menos que la diferencia provenga de analizar solo el encabezado (etiquetas, TODO) frente al encabezado + cuerpo (propiedades).

Tejedor de holocrón
fuente

Respuestas:

2

Una forma de mejorar la velocidad es analizar el contenido de los archivos de la agenda una vez en un búfer temporal, recogiendo el esfuerzo de todas las entradas que coinciden goal+PRIORITY="B"(ver Prueba 1). Con ~ 10K líneas, obtengo "Tiempo transcurrido: 0.052280s" en comparación con "Tiempo transcurrido: 1.340006s" usando org-map-entries(Prueba 2), que creo que es lo que estaba tratando de hacer. Para obtener mejores resultados org-map-entries, puede probar la Prueba 3, que también es bastante rápida. Probado con Emacs versión 26.2 y el modo Org versión 9.2.4.

Prueba 1 (más rápida)

(org-duration-from-minutes
 (apply '+ (let (efforts
                 (regexp (concat org-effort-property ":\s*\\(.+\\)")))
             (with-temp-buffer
               (mapcar #'insert-file-contents org-agenda-files)
               (goto-char (point-min))
               (while (re-search-forward regexp nil t)
                 (let ((effort (match-string 1)))
                   (save-excursion
                     (outline-previous-heading)
                     (when (and (member "goal" (org-get-tags))
                                (= (and (looking-at org-heading-regexp)
                                        (org-get-priority (match-string 0)))
                                1000))
                    (push (org-duration-to-minutes effort) efforts))))))
          efforts)))

Prueba 2 (más lenta)

(org-duration-from-minutes
 (apply '+ (org-map-entries
            (lambda ()
              (org-duration-to-minutes
               (org-entry-get nil org-effort-property)))
            "goal+PRIORITY=\"B\""
            'agenda)))

Prueba 3 (bastante bien)

(org-duration-from-minutes
 (apply '+ (org-map-entries
            (lambda ()
              (if (re-search-forward (concat org-effort-property ":\s*\\(.+\\)")
                                     (save-excursion
                                       (org-end-of-meta-data)
                                       (point))
                                     t)
                  (let ((effort (match-string 1)))
                    (outline-previous-heading)
                    (when (looking-at org-complex-heading-regexp)
                      (let ((priority (match-string 3))
                            (tags (match-string 5)))
                        (if (and (string= priority "[#B]")
                                 (string-match ":goal:" tags))
                            (org-duration-to-minutes effort)
                          0))))
                0))
            nil 'agenda)))
jagrg
fuente