Acelere as entradas do mapa organizacional ao fazer a correspondência por propriedade

8

Pergunta : Por que a org-map-entriescorrespondência de propriedades é tão lenta e o que posso fazer para acelerar isso?

Antecedentes : Eu tenho um uso relativamente simples para org-map-entries: agarre o esforço (em minutos inteiros) de todas as entradas da agenda organizacional com tag goale uma determinada prioridade (por exemplo B).

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

Isso é muito lento, levando mais de um minuto para o meu arquivo de agenda de ~ 12k linhas.

No entanto, se eu remover o PRIORITYfiltro para goalsselecionar qualquer item marcado, ele será concluído quase instantaneamente.

Também posso definir filtros como goal/DONEe eles são concluídos muito rapidamente, mas se eu fizer algo como goals+EFFORT>0voltaremos a demorar um minuto. Parece que as propriedades em geral são muito lentas para combinar.

Encontrei uma solução alternativa para truques : posso combinar propriedades dentro da função mapeada muito rapidamente usando org-entry-get. Quando faço isso, a execução é menor que um segundo. Isso parece bobagem, espero que exista uma maneira melhor, mas pelo menos funciona!

Já tentei : desde (benchmark 1000 (hw-org-effort-to-minutes "1:20"))retornos "Elapsed time: 0.000019s", acho que minha função não contribui muito.

De acordo com profiler, ~ 40% do tempo da CPU é usado cond, com ~ 29% vindo da análise de elementos ( org-element--current-element). As próximas duas maiores contribuições em geral são 14% e 13%, portanto, 40% condparece ser a maior parte do problema. Não sei por que a análise de elementos seria feita com mais frequência com correspondentes de propriedades, a menos que a diferença ocorra apenas na análise de cabeçalho (tags, TODO) vs. cabeçalho + corpo (propriedades).

holocronweaver
fonte

Respostas:

2

Uma maneira de melhorar a velocidade é analisar o conteúdo dos arquivos da agenda uma vez em um buffer temporário, coletando o esforço de todas as entradas correspondentes goal+PRIORITY="B"(consulte o Teste 1). Com ~ 10K linhas, recebo "Tempo decorrido: 0,052280s" em comparação com "Tempo decorrido: 1,340006s" usando org-map-entries(Teste 2), que eu acho que é o que você estava tentando fazer. Para obter melhores resultados, use org-map-entrieso Teste 3, que também é bastante rápido. Testado com o Emacs versão 26.2 e no modo Org versão 9.2.4.

Teste 1 (mais rápido)

(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)))

Teste 2 (mais lento)

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

Teste 3 (muito bom)

(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
fonte