Skip to content
This repository has been archived by the owner on Oct 16, 2021. It is now read-only.

LspInstall is very expensive to load #143

Open
akinsho opened this issue Aug 16, 2021 · 6 comments
Open

LspInstall is very expensive to load #143

akinsho opened this issue Aug 16, 2021 · 6 comments

Comments

@akinsho
Copy link
Contributor

akinsho commented Aug 16, 2021

Hi @kabouzeid,

Been using lspinstall for a while and have noticed quite an increase in the time to load lspconfig which I initially attributed to that plugin but having disabled lspinstall I've realised that it is quite expensive to load. I dug through the code base and realised something. One of the first things the plugin does is iterate a list of servers

for lang, server_config in pairs(servers) do

Derived from

I'm pretty confident that this is the reason for the quite high startup cost of this plugin, roughly around 15ms+ on a quite beefy machine, which is the slowest of any plugin I use. The reason being that requiring a module is kind of expensive and doing it 35+ times right on startup is very expensive. It means that when setting up this plugin a user has to essentially load most of this plugin's codebase just set up the few servers they use, in my case I only install 2 currently, but this logic requires the code for 35+.

I think another way to potentially handle this is that this plugin already checks if a server is installed by checking for its directory. Potentially, you could use libuv to read the contents of a directory and check what servers are installed and only require those rather than all of them, e.g.

function get_servers()
	local directory_fd = vim.loop.fs_opendir(install_path)
	local dirs = vim.loop.fs_readdir(directory_fd
	local servers = {}
	for _, lang in ipairs(dirs) do
        if langs[lang] then
			local server = require(('lspinstall/servers/%s'):format(lang))
			table.insert(servers, server)
		end
	end
	return servers
end

Another potential solution would be using lazy.nvim's patterns this plugin by TJ is kind of just an example of how a plugin author can lazy require modules so that they aren't actually required unless a property on the table gets accessed.

this would look more like

local servers = {
 bash = lazy.require('lspinstall/servers/bash') -- this will not be required immediately
 ...
}

-- This is only actually required when a property is indexed
-- e.g.
-- bash.server_config -- accessing the prop actually triggers the require
@siduck
Copy link

siduck commented Aug 24, 2021

I agree with @akinsho , it takes 16ms on my old machine
image
many lsp servers which I dont use are also sourced :

image

@williamboman
Copy link

Just out of curiosity - what tools are you using to profile this?

@siduck
Copy link

siduck commented Sep 4, 2021

Just out of curiosity - what tools are you using to profile this?

https://github.com/norcalli/profiler.nvim

@lewis6991
Copy link

#173 should alleviate the problem

@kabouzeid
Copy link
Owner

Ahh this looks very good! Thank you @lewis6991. I'll make some tests and if it works as it expected merge soon.

@lewis6991
Copy link

lewis6991 commented Sep 28, 2021

Here's my startup time currently using impatients profiler.

───────────────────────────┬────────────────┬────────────┬────────────┬────────────┬────────────┐
                           │ Loader         │ Resolve    │ Load       │ Exec       │ Total      │
───────────────────────────┼────────────────┼────────────┼────────────┼────────────┼────────────┤
Total                      │                │   2.2017ms │   4.4617ms │  93.9100ms │ 100.5734ms │
───────────────────────────┴────────────────┴────────────┴────────────┴────────────┴────────────┘
────────────────────────────────────────────────────────────────────────────────────────────────┐
By Plugin                                                                                       │
───────────────────────────┬────────────────┬────────────┬────────────┬────────────┬────────────┤
lspinstall                 │          cache │   0.6123ms │   0.2323ms │  37.1933ms │  38.0378ms │
lewis6991                  │          cache │   0.1113ms │   0.1262ms │  34.0965ms │  34.3340ms │
impatient                  │       standard │   0.0000ms │   0.0000ms │   4.7589ms │   4.7589ms │
packer_compiled            │          cache │   0.0234ms │   0.0844ms │   4.3859ms │   4.4938ms │
diffview                   │          cache │   0.3135ms │   0.7074ms │   3.1027ms │   4.1236ms │
octo                       │          cache │   0.2004ms │   1.0370ms │   1.6385ms │   2.8760ms │
telescope                  │          cache │   0.0714ms │   0.1609ms │   2.2520ms │   2.4843ms │
vim                        │          mixed │   0.0953ms │   0.6230ms │   1.2499ms │   1.9681ms │
treesitter-context         │          cache │   0.0175ms │   0.0326ms │   1.2366ms │   1.2867ms │
gitsigns                   │          cache │   0.2141ms │   0.2849ms │   0.7009ms │   1.1999ms │
null-ls                    │          cache │   0.0868ms │   0.2017ms │   0.6182ms │   0.9067ms │
nvim-treesitter            │          cache │   0.0568ms │   0.1866ms │   0.5071ms │   0.7505ms │
plenary                    │          cache │   0.0890ms │   0.1956ms │   0.4602ms │   0.7448ms │
trouble                    │          cache │   0.0624ms │   0.1407ms │   0.4320ms │   0.6352ms │
symbols-outline            │          cache │   0.0679ms │   0.1424ms │   0.3272ms │   0.5374ms │
colorizer                  │          cache │   0.0192ms │   0.0553ms │   0.3495ms │   0.4239ms │
dirvish                    │          cache │   0.0329ms │   0.0668ms │   0.1577ms │   0.2574ms │
lspconfig                  │          cache │   0.0153ms │   0.0600ms │   0.1032ms │   0.1784ms │
fzf_lib                    │          cache │   0.0061ms │   0.0075ms │   0.0952ms │   0.1087ms │
packer                     │          cache │   0.0317ms │   0.0389ms │   0.0370ms │   0.1075ms │
foldsigns                  │          cache │   0.0111ms │   0.0160ms │   0.0597ms │   0.0868ms │
nvim-treesitter-playground │          cache │   0.0229ms │   0.0194ms │   0.0326ms │   0.0748ms │
persistence                │          cache │   0.0106ms │   0.0084ms │   0.0431ms │   0.0622ms │
spellsitter                │          cache │   0.0109ms │   0.0173ms │   0.0164ms │   0.0446ms │
ffi                        │      preloader │   0.0000ms │   0.0000ms │   0.0354ms │   0.0354ms │
spaceless                  │          cache │   0.0106ms │   0.0093ms │   0.0112ms │   0.0312ms │
cleanfold                  │          cache │   0.0084ms │   0.0071ms │   0.0089ms │   0.0244ms │
bit                        │             NA │   0.0000ms │   0.0000ms │   0.0003ms │   0.0003ms │
───────────────────────────┴────────────────┴────────────┴────────────┴────────────┴────────────┘

lspinstall is taking about 40ms which equals my init.lua.

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

No branches or pull requests

5 participants