Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve performance of Promise especially in Windows #716

Merged
merged 13 commits into from
Feb 5, 2020
Merged

Conversation

lambdalisue
Copy link
Member

@lambdalisue lambdalisue commented Feb 3, 2020

I've relied on Async.Promise to make fern.vim but the performance issue occurred in Windows.

lambdalisue/vim-fern#57

This PR introduces an event loop and workers to execute tasks. Approx. 20x performance improvement has observed in above plugin.

Regression tests

let s:Promise = vital#vital#import('Async.Promise')

function! s:tick() abort
  let promise = s:Promise.resolve(reltime())
  for i in range(1000)
    let promise = promise.then({ s -> s })
  endfor
  return promise.then({ s -> reltimestr(reltime(s)) })
endfunction

function! s:test() abort
  new
  let bufnr = bufnr('%')
  let promise = s:Promise.all([
        \ s:tick(),
        \ s:tick(),
        \ s:tick(),
        \ s:tick(),
        \ s:tick(),
        \ s:tick(),
        \ s:tick(),
        \ s:tick(),
        \ s:tick(),
        \ s:tick(),
        \])
  call promise.then({ vs -> setbufline(bufnr, 1, map(vs, { _, v -> v })) })
endfunction

call s:test()

Summary

  • Slight performance regressions has observed in Neovim on macOS (approx 1.1 -> 1.9)
  • Slight performance improveoment has observed in Vim on macOS (approx 2.3 -> 1.7)
  • Significant performance improveoment has observed in Vim on Windows (approx. 18.1 -> 3.9)

Before

Neovim v0.4 macOS
1.357061
1.316463
1.264815
1.229064
1.192373
1.154427
1.119024
1.082092
1.041670
0.994399

Vim 8.1 macOS
2.510612
2.465745
2.425529
2.385125
2.342392
2.288333
2.246469
2.204589
2.163871
2.123382

Vim 8.2 Windows
18.334129
18.291351
18.250988
18.196796
18.157503
18.116416
18.075665
18.031709
17.991818
17.951131

After

Neovim v0.4 macOS
2.130478
2.092259
2.058482
2.023667
1.990111
1.939237
1.903443
1.868484
1.835093
1.795646

Vim 8.1 macOS
1.939646
1.891795
1.850817
1.809631
1.768790
1.729066
1.687586
1.643133
1.596527
1.554153

Vim 8.2 Windows
4.146574
4.101837
4.060613
4.021967
3.984135
3.946313
3.909356
3.862812
3.818288
3.776003

The timer_start() is FILO in Vim and FIFO in Neovim.
Using Async.Later correct this order to FIFO.
@lambdalisue lambdalisue requested a review from rhysd February 3, 2020 15:09
@lambdalisue lambdalisue requested review from mattn and thinca February 3, 2020 15:16
@lambdalisue lambdalisue changed the title Improve performance of Promise especially in Windows Improve performance of Promise especially in Windows - WIP Feb 3, 2020
@lambdalisue
Copy link
Member Author

It seems test become fragile. I'll try to fix

@rhysd
Copy link
Contributor

rhysd commented Feb 3, 2020

Thank you for adding this.

approx. 20x in Windows for the plugin above.

Would you also confirm that performance regressions don't happen on other platform?

@lambdalisue lambdalisue changed the title Improve performance of Promise especially in Windows - WIP Improve performance of Promise especially in Windows Feb 3, 2020
@lambdalisue
Copy link
Member Author

Done. Please review it @rhysd @thinca @mattn 🙇

@rhysd
Copy link
Contributor

rhysd commented Feb 3, 2020

Let me check this tomorrow or day after tomorrow. I actually need to make another pull request and need to reply to an issue today...

try
call call('call', remove(s:tasks, 0))
catch
call s:error_handler()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If nulll is set via set_error_handler, v:exception should be raised here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While the error handling is a safety-net, I've changed behavior to use s:_default_error_handler() instead when s:error_handler is v:null.

@lambdalisue lambdalisue requested review from mattn and rhysd February 5, 2020 03:54
@lambdalisue
Copy link
Member Author

# Run reviewdog.

reviewdog -reporter=github-pr-check

2020/02/05 04:26:23 [vint] reported: https://github.com/vim-jp/vital.vim/runs/426832132

2020/02/05 04:26:23 [vital-throw-message] reported: https://github.com/vim-jp/vital.vim/runs/426832133

reviewdog: Check request failed: Post https://reviewdog.app/check: x509: certificate is valid for invalid.invalid, not reviewdog.app

The command "if [[ "${RUN_LINT}" == "true" ]] ; then bash scripts/run-lint-on-ci.sh ; fi" exited with 1.

It seems reviewdog is not available for now? Anyway ignore the CI failure.

Copy link
Contributor

@rhysd rhysd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good for me. Waiting for other reviewers' checks

@lambdalisue
Copy link
Member Author

lambdalisue commented Feb 5, 2020

I'll merge it (at least) once @mattn accepts it. (And review-dog get back.)

@lambdalisue lambdalisue merged commit 4d1d157 into master Feb 5, 2020
@lambdalisue lambdalisue deleted the promise branch February 5, 2020 13:12
lambdalisue added a commit to lambdalisue/vital-Whisky that referenced this pull request Feb 5, 2020
lambdalisue added a commit to lambdalisue/vim-fern that referenced this pull request Feb 5, 2020
lambdalisue added a commit to lambdalisue/vim-fern that referenced this pull request Feb 5, 2020
lambdalisue added a commit to lambdalisue/vim-fern that referenced this pull request Feb 5, 2020
@rhysd
Copy link
Contributor

rhysd commented Feb 5, 2020

🎉


function! s:set_max_workers(n) abort
if a:n <= 0
throw 'vital: Async.Later: the n must be a positive integer'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
throw 'vital: Async.Later: the n must be a positive integer'
throw 'vital: Async.Later: the max_workers must be a positive integer'

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A term n is used in help as well so I think it's ok to use tern n here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The message will be shown for a user, so it is better if the message is articulate.
But I do not request to fix this strongly.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The message will be shown for a user,

I think users don't understand anyway even n was max_workers... So I'll keep it at least for now.

Assert Equals(exception, v:null)
Assert Match(
\ messages,
\ '^\nHello World\nfunction .*<SNR>\d\+_throw, line 1',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test depends on locale. line will be a in Japanese locale.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How should I fix this? IMO, we should enforce English during tests like https://github.com/lambdalisue/fern.vim/blob/master/test/.themisrc#L12-L17

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with fixing message locale 😃

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment on lines +64 to +69
Internally, it enqueues a {task} into an internal task queue. Tasks
in the queue will be dequeued and processed by internal workers. The
number of internal workers are gradually increase until all tasks in
the queue are completed or reached to the value of "max_workers".
Once the queue become empty, the number of internal workers are
gradually decrease so that no workers exists at the end.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is a reason the workers gradually increase/decrease instead of immediate?
Did you encounter performance issues?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. The first version starts 50 timers at the beginning but sometimes it took more than 10ms in Windows (tests has randomly failed.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants