diff options
author | Jacob Segal <jacob.e.segal@gmail.com> | 2018-12-16 20:47:35 -0800 |
---|---|---|
committer | Jacob Segal <jacob.e.segal@gmail.com> | 2019-01-06 00:41:57 -0800 |
commit | cb0a5c7a36122a053c6c86cab145aa4c0336f5ba (patch) | |
tree | fc61bb533d5f629e611fad30bb26d8806f2333cc /autoload | |
parent | 5bbe77101db18968fde65210956e54750d7ff4f5 (diff) | |
download | ale-cb0a5c7a36122a053c6c86cab145aa4c0336f5ba.zip |
Improve perf for compile dbs in large projects
When using a compilation database (compile_commands.json) in very large
projects, significant delays would occur when changing files --
particularly those that happened to be far down the db. Rather than
iterating over the whole list every time, we now build up a lookup table
based on the tail of the filename (and tail of the directory for
widening searches) and iterate over the much smaller list of compile
commands for files with the given name.
Test metrics (from compile_database_perf/test.sh) show a 90% performance
improvement -- from 25 seconds to 2.5 seconds per run.
Diffstat (limited to 'autoload')
-rw-r--r-- | autoload/ale/c.vim | 50 |
1 files changed, 36 insertions, 14 deletions
diff --git a/autoload/ale/c.vim b/autoload/ale/c.vim index 617e81f6..746d19b0 100644 --- a/autoload/ale/c.vim +++ b/autoload/ale/c.vim @@ -157,15 +157,17 @@ if !exists('s:compile_commands_cache') let s:compile_commands_cache = {} endif -function! s:GetListFromCompileCommandsFile(compile_commands_file) abort +function! s:GetLookupFromCompileCommandsFile(compile_commands_file) abort + let l:empty = [{}, {}] + if empty(a:compile_commands_file) - return [] + return l:empty endif let l:time = getftime(a:compile_commands_file) if l:time < 0 - return [] + return l:empty endif let l:key = a:compile_commands_file . ':' . l:time @@ -174,21 +176,36 @@ function! s:GetListFromCompileCommandsFile(compile_commands_file) abort return s:compile_commands_cache[l:key] endif - let l:data = [] - silent! let l:data = json_decode(join(readfile(a:compile_commands_file), '')) + let l:raw_data = [] + silent! let l:raw_data = json_decode(join(readfile(a:compile_commands_file), '')) + + let l:file_lookup = {} + let l:dir_lookup = {} + + for l:entry in l:raw_data + let l:basename = tolower(fnamemodify(l:entry.file, ':t')) + let l:file_lookup[l:basename] = get(l:file_lookup, l:basename, []) + [l:entry] - if !empty(l:data) - let s:compile_commands_cache[l:key] = l:data + let l:dirbasename = tolower(fnamemodify(l:entry.directory, ':p:h:t')) + let l:dir_lookup[l:dirbasename] = get(l:dir_lookup, l:basename, []) + [l:entry] + endfor + + if !empty(l:file_lookup) && !empty(l:dir_lookup) + let l:result = [l:file_lookup, l:dir_lookup] + let s:compile_commands_cache[l:key] = l:result - return l:data + return l:result endif - return [] + return l:empty endfunction -function! ale#c#ParseCompileCommandsFlags(buffer, dir, json_list) abort +function! ale#c#ParseCompileCommandsFlags(buffer, dir, file_lookup, dir_lookup) abort " Search for an exact file match first. - for l:item in a:json_list + let l:basename = tolower(expand('#' . a:buffer . ':t')) + let l:file_list = get(a:file_lookup, l:basename, []) + + for l:item in l:file_list if bufnr(l:item.file) is a:buffer return ale#c#ParseCFlags(a:dir, l:item.command) endif @@ -197,7 +214,10 @@ function! ale#c#ParseCompileCommandsFlags(buffer, dir, json_list) abort " Look for any file in the same directory if we can't find an exact match. let l:dir = ale#path#Simplify(expand('#' . a:buffer . ':p:h')) - for l:item in a:json_list + let l:dirbasename = tolower(expand('#' . a:buffer . ':p:h:t')) + let l:dir_list = get(a:dir_lookup, l:dirbasename, []) + + for l:item in l:dir_list if ale#path#Simplify(fnamemodify(l:item.file, ':h')) is? l:dir return ale#c#ParseCFlags(a:dir, l:item.command) endif @@ -208,9 +228,11 @@ endfunction function! ale#c#FlagsFromCompileCommands(buffer, compile_commands_file) abort let l:dir = ale#path#Dirname(a:compile_commands_file) - let l:json_list = s:GetListFromCompileCommandsFile(a:compile_commands_file) + let l:lookups = s:GetLookupFromCompileCommandsFile(a:compile_commands_file) + let l:file_lookup = l:lookups[0] + let l:dir_lookup = l:lookups[1] - return ale#c#ParseCompileCommandsFlags(a:buffer, l:dir, l:json_list) + return ale#c#ParseCompileCommandsFlags(a:buffer, l:dir, l:file_lookup, l:dir_lookup) endfunction function! ale#c#GetCFlags(buffer, output) abort |