tumashu / posframe

Pop a posframe (just a child-frame) at point, posframe is a **GNU ELPA** package!
443 stars 57 forks source link

Improve posframe performance again. #101

Open seagle0128 opened 3 years ago

seagle0128 commented 3 years ago

https://github.com/tumashu/posframe/blob/739d8fd1081bdd0d20dee9e437d64df58747b871/posframe.el#L301-L307

请教下,我看到这里判断arg是否被修改,如果修改过就会删除并重新创建子窗口。很多场景下会造成一定程度的闪烁,打开时(比如 ivy-posframe)会有一点延迟。有没有可能直接用modify-frame-parameters 来复用child frame呢?这样是否能提高性能?

最近我在看mini-frame,发现在很多场景下性能会比posframe高些。mini-frame就是尽量复用已经创建的frame。不过,由于在Linux上表现不佳,我还是倾向于使用posframe,但是希望能改进性能。希望您能看看?很多细节我还不是很明白。谢谢!

(if (frame-live-p posframe--frame)
  ;; 复用现有frame
  (modify-frame-paremeters ...)
;;创建新frame
(make-frame ...))
tumashu commented 3 years ago

posframe只有在极少数的情况下才会重建frame,大多数都是复用已经有的frame

seagle0128 commented 3 years ago

今天看到这个帖子,确实存在性能问题,尤其内存占用厉害。

https://emacs-china.org/t/emacs-savehist-printable-ivy-posframe-read/16797

tumashu commented 3 years ago

我感觉可能是不小心触发了某种潜在的 bug, 就 posframe 而言,也就是移动缩放 frame ,不太可能占用7G内存

seagle0128 commented 3 years ago

理论上如此,但值得好好分析。我也发现用了posframe之后,尤其是ivy-posframe,比之前占用内存多太多。以前是300M左右,现在长期700M+。

tumashu commented 3 years ago

有没有使用 emacs -Q 测试过 ivy-posframe ?

seagle0128 commented 3 years ago

刚简单做了一个测试,供参考:

GNU Emacs 28.0.50, macOS Big Sur, emacs -Q,打开ivy-mode, 打开相同的几个文件,做一些操作,大概占用~70M

经过一些操作,一段时间后:

tumashu commented 3 years ago

如果差异只有40M的话,还是可以忍受的。。。;)

seagle0128 commented 3 years ago

关键是时间长了,差距可能越来越大 😂

tumashu commented 3 years ago

http://git.savannah.gnu.org/cgit/emacs.git/commit/?id=246e107d73e633c06478eaf021776acedef9dafc

不知道这个对 posframe 的速度有没有提升?

tumashu commented 3 years ago
(benchmark 1000
           '(redraw-frame))

这个在果子机上速度如何?

seagle0128 commented 3 years ago
(benchmark 1000
           '(redraw-frame))

这个在果子机上速度如何?

测试三次,结果如下:

emacs -Q

Elapsed time: 0.475326s
Elapsed time: 0.468543s
Elapsed time: 0.460630s

In Centaur Emacs

Elapsed time: 5.598229s
Elapsed time: 6.027011s
Elapsed time: 6.101822s

差别很明显啊,不知道是哪里的原因

Update: 作了下profile,仍然看不出瓶颈。猜测是UI配置之类的导致? image

tumashu commented 3 years ago

在linux下, 1000次用时 0.0005

tumashu commented 3 years ago
(defun posframe--set-frame-position (posframe position
                                              parent-frame-width
                                              parent-frame-height)
  "Move POSFRAME to POSITION.
This need PARENT-FRAME-WIDTH and PARENT-FRAME-HEIGHT"
  (unless (and (equal position posframe--last-posframe-pixel-position)
               ;; When working frame's size change, re-posit
               ;; the posframe.
               (equal posframe--last-parent-frame-size
                      (cons parent-frame-width parent-frame-height))
               (equal posframe--last-posframe-displayed-size
                      (cons (frame-pixel-width posframe)
                            (frame-pixel-height posframe))))
    (set-frame-position posframe (car position) (cdr position))
    (setq-local posframe--last-posframe-pixel-position position)
    (setq-local posframe--last-parent-frame-size
                (cons parent-frame-width parent-frame-height))
    (setq-local posframe--last-posframe-displayed-size
                (cons (frame-pixel-width posframe)
                      (frame-pixel-height posframe))))
  ;; Make posframe's posframe--frame visible
  (unless (frame-visible-p posframe)
    (make-frame-visible posframe)
    ;; Fix issue: https://github.com/tumashu/ivy-posframe/pull/30
    ;; (redraw-frame posframe)
    ))

看看这个版本对速度有没有影响

seagle0128 commented 3 years ago

mac下emacs的UI效率确实不行,不过linux的UI不稳定,经常会有闪烁。 刚才那个问题找到原因了,居然是persp-mode引起的 😂

tumashu commented 3 years ago

是不是 persp-mode 将 child-frame 保存了,导致速度拖慢了。

seagle0128 commented 3 years ago

是不是 persp-mode 将 child-frame 保存了,导致速度拖慢了。

还不清楚,刚查了下,好像并没有保存child frame,相应的buffer我都ignore了。但可能保存这类frame的配置。再研究下。

研究了下 https://github.com/tumashu/ivy-posframe/pull/30 ,感觉用redraw不合理啊。frame-delete肯定不行,理想情况是清空buffer才是效率最高的。

tumashu commented 3 years ago

当时细节不知道了,我感觉是遇到刷新缓慢的问题,所以强制 redraw,好像也是果子机遇到的

seagle0128 commented 3 years ago

测试了一小会儿,速度有所提升,感受不是非常明显。但是会有闪烁,另外内存还是会增长,不过增长幅度目前还没法判断。

seagle0128 commented 3 years ago

在linux下, 1000次用时 0.0005

晚上又研究了一会,发现跟persp-mode没有必然联系,只跟frame大小有关。因为我用的是4K显示屏,全屏时就是6s左右,默认窗口大小(80x30)就是0.4s左右。Linux下跟窗口大小好像影响没这么明显。

zhenwenc commented 3 years ago

我没有用 persp-mode,不过测试结果也是5秒左右。另外我发现 posframe-run-hidehandler 被调用得很频繁(因为被加到了post-command-hook里),这对速度有影响吗?还有速度影响最明显的是用counsel搜索的时候,counsel--async-filter 被非常频繁地调用 (好像每次调用都会update buffer内容),不知道有没有联系。

tumashu commented 3 years ago

hidehandler 看起来好像没有运行速度慢的地方,所以我感觉可能不是瓶颈。

tumashu commented 3 years ago

去除 (redraw-frame posframe) 后,https://github.com/tumashu/ivy-posframe/pull/30 这个问题不知道存不存在? @seagle0128

tumashu commented 3 years ago

我写了一个简单的 benchmark 工具,暂时还比较粗糙,大家可以运行一下,看看效果如何

https://github.com/tumashu/posframe/blob/master/posframe-benchmark.el

seagle0128 commented 3 years ago

去除 (redraw-frame posframe) 后,tumashu/ivy-posframe#30 这个问题不知道存不存在?

@tumashu 去掉这个问题会存在,内容没有被清理,窗口会有一定的闪烁。

我没有用 persp-mode,不过测试结果也是5秒左右。另外我发现 posframe-run-hidehandler 被调用得很频繁(因为被加到了post-command-hook里),这对速度有影响吗?还有速度影响最明显的是用counsel搜索的时候,counsel--async-filter 被非常频繁地调用 (好像每次调用都会update buffer内容),不知道有没有联系。

@zhenwenc 对,跟persp-mode没有关系,跟窗口大小有关。我去掉persp-mode性能提高就是因为窗口是默认大小并没有最大化。posframe-run-hidehandler 我认为有不是瓶颈, 你可以profile再看看到底CPU占用如何。

seagle0128 commented 3 years ago

我写了一个简单的 benchmark 工具,暂时还比较粗糙,大家可以运行一下,看看效果如何

https://github.com/tumashu/posframe/blob/master/posframe-benchmark.el

默认最新版:

* Posframe Benchmark

** Benchmark ‘font-at’ 10000 times ...
Elapsed time: 0.237086s

** Benchmark ‘redraw-display’ 10000 times ...
Elapsed time: 59.314862s

** Benchmark ‘remove-text-properties’ 10000 times ...
Elapsed time: 0.003365s

** Benchmark ‘mouse-position’ 10000 times ...
Elapsed time: 1.041860s

** Benchmark ‘default-font-width’ 10000 times ...
Elapsed time: 0.216869s

** Benchmark ‘posframe--get-font-height’ 10000 times ...
Elapsed time: 0.005082s

** Benchmark ‘posframe--mouse-banish’ 10000 times ...
Elapsed time: 0.001690s

** Benchmark ‘frame-parameter’ 10000 times ...
Elapsed time: 0.045978s

** Benchmark ‘set-mouse-position’ 10000 times ...
Elapsed time: 0.240378s

** Benchmark ‘posn-at-point’ 10000 times ...
Elapsed time: 219.611200s (1.041883s in 6 GCs)

** Benchmark ‘set-frame-parameter’ 10000 times ...
Elapsed time: 0.006588s

** Benchmark ‘raise-frame’ 10000 times ...
Elapsed time: 1.084977s

* Finished.

去掉了redraw-frame 之后:

* Posframe Benchmark

** Benchmark ‘font-at’ 10000 times ...
Elapsed time: 0.203783s

** Benchmark ‘redraw-display’ 10000 times ...
Elapsed time: 60.493191s

** Benchmark ‘remove-text-properties’ 10000 times ...
Elapsed time: 0.002599s

** Benchmark ‘mouse-position’ 10000 times ...
Elapsed time: 1.046413s

** Benchmark ‘default-font-width’ 10000 times ...
Elapsed time: 0.223130s

** Benchmark ‘posframe--get-font-height’ 10000 times ...
Elapsed time: 0.005315s

** Benchmark ‘posframe--mouse-banish’ 10000 times ...
Elapsed time: 0.001859s

** Benchmark ‘frame-parameter’ 10000 times ...
Elapsed time: 0.176227s (0.134239s in 1 GCs)

** Benchmark ‘set-mouse-position’ 10000 times ...
Elapsed time: 0.224940s

** Benchmark ‘posn-at-point’ 10000 times ...
Elapsed time: 180.730515s (0.782196s in 5 GCs)

** Benchmark ‘set-frame-parameter’ 10000 times ...
Elapsed time: 0.004266s

** Benchmark ‘raise-frame’ 10000 times ...
Elapsed time: 0.670495s

* Finished.
tumashu commented 3 years ago

我这边类似这样, debian linux, 1000次的测试

* Posframe Benchmark

** Benchmark ‘font-at’ 1000 times ...
Elapsed time: 0.000333s

** Benchmark ‘redraw-display’ 1000 times ...
Elapsed time: 0.000595s

** Benchmark ‘redraw-frame’ 1000 times ...
Elapsed time: 0.000904s

** Benchmark ‘remove-text-properties’ 1000 times ...
Elapsed time: 0.000337s

** Benchmark ‘mouse-position’ 1000 times ...
Elapsed time: 0.086048s

** Benchmark ‘default-font-width’ 1000 times ...
Elapsed time: 0.006293s

** Benchmark ‘posframe--get-font-height’ 1000 times ...
Elapsed time: 0.000271s

** Benchmark ‘posframe--mouse-banish’ 1000 times ...
Elapsed time: -0.004739s

** Benchmark ‘frame-parameter’ 1000 times ...
Elapsed time: 0.009540s

** Benchmark ‘set-mouse-position’ 1000 times ...
Elapsed time: 0.000167s

** Benchmark ‘posn-at-point’ 1000 times ...
Elapsed time: 0.441456s

** Benchmark ‘set-frame-parameter’ 1000 times ...
Elapsed time: 0.000399s

** Benchmark ‘raise-frame’ 1000 times ...
Elapsed time: 3.044742s

* Finished.
tumashu commented 3 years ago
(defun ivy-posframe--display (str &optional poshandler)
  "Show STR in ivy's posframe with POSHANDLER."
  (if (not (posframe-workable-p))
      (ivy-display-function-fallback str)
    (with-ivy-window
      (apply #'posframe-show
             ivy-posframe-buffer
             :font ivy-posframe-font
             :string str
             ;; :position (point)
             :poshandler poshandler
             :background-color (face-attribute 'ivy-posframe :background nil t)
             :foreground-color (face-attribute 'ivy-posframe :foreground nil t)
             :internal-border-width ivy-posframe-border-width
             :internal-border-color (face-attribute 'ivy-posframe-border :background nil t)
             :override-parameters ivy-posframe-parameters
             :refposhandler ivy-posframe-refposhandler
             (funcall ivy-posframe-size-function))
      (ivy-posframe--add-prompt 'ignore)))
  (with-current-buffer ivy-posframe-buffer
    (setq-local truncate-lines ivy-truncate-lines)))

试试这个

seagle0128 commented 3 years ago

redraw-display 性能相差太大了。

@tumashu 你是指去掉 (redraw-frame posframe),用新的 ivy-posframe--display 对吗?结果是会残留之前的内容,闪一下显示新内容。

tumashu commented 3 years ago

不是,我是看见你的机器上 posn-at-point 速度也极其慢,所以我想测试一下是不是这个函数的调用导致的卡顿。

** Benchmark ‘posn-at-point’ 10000 times ...
Elapsed time: 219.611200s (1.041883s in 6 GCs)

最好的方法是 不使用 redraw-display 或者 redraw-frame, 但不知道怎么搞

tumashu commented 3 years ago

ivy-posframe--display 这个没用, 下载最新的 posframe 代码测试吧,看速度怎么样。

seagle0128 commented 3 years ago

现在用的就是最新代码,感觉不明显。

顺便提一句,隐藏minibuffer prompt那个实在tricky啊,mini-frame是怎么干的呢,好像所有都放到child frame了

tumashu commented 3 years ago
隐藏minibuffer prompt那个实在tricky啊,

学 helm 的 :-)

tumashu commented 3 years ago

@seagle0128 用最新的代码,并且把 redraw-frame 删除,看看速度有没有提升,如果没有提升,那估计还有其它瓶颈

seagle0128 commented 3 years ago

@tumashu 性能有一定提升,但是闪烁也挺难受啊 😂

tumashu commented 3 years ago

@seagle0128 要不编译一下emacs master试试? 因为: http://git.savannah.gnu.org/cgit/emacs.git/commit/?id=246e107d73e633c06478eaf021776acedef9dafc

seagle0128 commented 3 years ago

@tumashu 我用的就是最新版,6/2编译的。去掉 redraw-frame 性能会好些,有点闪烁,其实也还好,就怕强迫症 😂

tumashu commented 3 years ago

我倒是感觉, redraw 和 pos-at-point 这两个函数在果子机上极其缓慢,可能它们底层C代码存在性能问题,因为我看见这两天 emacs devel 上也在讨论 frame 性能相关的内容,建议在 emacs-devel 上问问大牛

seagle0128 commented 3 years ago

嗯,我这两天再抽空编译下新版本,看看有没有改善。

seagle0128 commented 3 years ago

刚才编译了新版本,同样的分辨率下测试 (benchmark-run 1000 (redraw-frame)),时间在 ~2s左右,提升不少啊!

tumashu commented 3 years ago

posframe 体验有提升没?

seagle0128 commented 3 years ago

有一定提升,还在观察中。。。

seagle0128 commented 3 years ago

更新下,最新版gccemacs使用ivy-posframe,性能提升明显,内存也有所改善。推荐大家试试。

tumashu commented 3 years ago

666,最近我看到一个大牛整改 refactor macox 的 window 相关的代码,不知道会不会对性能有所提升

tumashu commented 3 years ago

https://git.savannah.gnu.org/cgit/emacs.git/log/?h=scratch/ns/refactor

seagle0128 commented 3 years ago

看来换新开发者了啊,不容易 👍🏻👍🏻 😄😄

tumashu commented 3 years ago

应该叫有新的大牛加入。。。。 :-)

seagle0128 commented 3 years ago

刚编译了新版本,gccemacs越来越流畅了,继续观察中。。。 😄

tumashu commented 3 years ago

@seagle0128 能不能运行一下 posframe-benchmark, 看看哪些函数速度提升了。

zhenwenc commented 3 years ago

我也编译了gccemacs,使用两天感觉确实流畅不少。发现 flycheck-posframe dismiss 延迟了,大概是为了优化性能?

* Posframe Benchmark

** Benchmark ‘font-at’ 1000 times ...
Elapsed time: 0.013770s

** Benchmark ‘redraw-display’ 1000 times ...
Elapsed time: 1.318676s

** Benchmark ‘redraw-frame’ 1000 times ...
Elapsed time: 1.210649s

** Benchmark ‘remove-text-properties’ 1000 times ...
Elapsed time: 0.000453s

** Benchmark ‘mouse-position’ 1000 times ...
Elapsed time: 0.080340s

** Benchmark ‘default-font-width’ 1000 times ...
Elapsed time: 0.018745s

** Benchmark ‘posframe--get-font-height’ 1000 times ...
Elapsed time: 0.000092s

** Benchmark ‘posframe--mouse-banish’ 1000 times ...
Elapsed time: 0.000119s

** Benchmark ‘frame-parameter’ 1000 times ...
Elapsed time: 0.004652s

** Benchmark ‘set-mouse-position’ 1000 times ...
Elapsed time: 0.019597s

** Benchmark ‘posn-at-point’ 1000 times ...
Elapsed time: 0.906148s (0.162083s in 1 GCs)

** Benchmark ‘posn-x-y’ 1000 times ...
Elapsed time: 1.023758s (0.267148s in 2 GCs)

** Benchmark ‘posn-object-x-y’ 1000 times ...
Elapsed time: 0.883263s (0.134518s in 1 GCs)

** Benchmark ‘set-frame-parameter’ 1000 times ...
Elapsed time: 0.000449s

** Benchmark ‘raise-frame’ 1000 times ...
Elapsed time: 0.032924s

* Finished.
seagle0128 commented 3 years ago

@seagle0128 能不能运行一下 posframe-benchmark, 看看哪些函数速度提升了。

* Posframe Benchmark

** Benchmark ‘font-at’ 1000 times ...
Elapsed time: 0.017461s

** Benchmark ‘redraw-display’ 1000 times ...
Elapsed time: 1.266655s

** Benchmark ‘redraw-frame’ 1000 times ...
Elapsed time: 1.259094s

** Benchmark ‘remove-text-properties’ 1000 times ...
Elapsed time: 0.000298s

** Benchmark ‘mouse-position’ 1000 times ...
Elapsed time: 0.117805s

** Benchmark ‘default-font-width’ 1000 times ...
Elapsed time: 0.021617s

** Benchmark ‘posframe--get-font-height’ 1000 times ...
Elapsed time: 0.000495s

** Benchmark ‘posframe--mouse-banish’ 1000 times ...
Elapsed time: 0.000155s

** Benchmark ‘frame-parameter’ 1000 times ...
Elapsed time: 0.003491s

** Benchmark ‘set-mouse-position’ 1000 times ...
Elapsed time: 0.020867s

** Benchmark ‘posn-at-point’ 1000 times ...
Elapsed time: 1.083250s

** Benchmark ‘posn-x-y’ 1000 times ...
Elapsed time: 1.211351s (0.165975s in 1 GCs)

** Benchmark ‘posn-object-x-y’ 1000 times ...
Elapsed time: 1.062713s

** Benchmark ‘set-frame-parameter’ 1000 times ...
Elapsed time: 0.000392s

** Benchmark ‘raise-frame’ 1000 times ...
Elapsed time: 0.042280s

* Finished.