diff --git a/pyls/plugins/jedi_completion.py b/pyls/plugins/jedi_completion.py index afa48322..9c16dd6a 100644 --- a/pyls/plugins/jedi_completion.py +++ b/pyls/plugins/jedi_completion.py @@ -1,6 +1,9 @@ # Copyright 2017 Palantir Technologies, Inc. +import os import logging import os.path as osp +from datetime import datetime, timedelta +from collections import defaultdict import parso @@ -49,10 +52,12 @@ # Types of parso node for errors _ERRORS = ('error_node', ) - +profile_dump = open('/tmp/pyls_completions.prof', 'w') @hookimpl def pyls_completions(config, document, position): """Get formatted completions for current code position""" + global profile_dump + t1 = datetime.now() settings = config.plugin_settings('jedi_completion', document_path=document.path) code_position = _utils.position_to_jedi_linecolumn(document, position) @@ -62,6 +67,7 @@ def pyls_completions(config, document, position): if not completions: return None + # t15 = datetime.now() completion_capabilities = config.capabilities.get('textDocument', {}).get('completion', {}) snippet_support = completion_capabilities.get('completionItem', {}).get('snippetSupport') @@ -71,8 +77,10 @@ def pyls_completions(config, document, position): include_params = snippet_support and should_include_params and use_snippets(document, position) include_class_objects = snippet_support and should_include_class_objects and use_snippets(document, position) + # t17 = datetime.now() + format_profile_ranges = defaultdict(timedelta) ready_completions = [ - _format_completion(c, include_params) + _format_completion(c, include_params, format_profile_ranges) for c in completions ] @@ -84,6 +92,17 @@ def pyls_completions(config, document, position): completion_dict['label'] += ' object' ready_completions.append(completion_dict) + t2 = datetime.now() + print( + # 'pid', os.getpid(), + 'pyls_completions', + 'total', t2 - t1, + 'format_profile_ranges', format_profile_ranges, + # 'jedi', t15 - t1, + # 'before_format', t17 - t15, + # 'format', t2 - t17, + file=profile_dump) + profile_dump.flush() return ready_completions or None @@ -137,15 +156,21 @@ def use_snippets(document, position): not (expr_type in _ERRORS and 'import' in code)) -def _format_completion(d, include_params=True): +def _format_completion(d, include_params=True, profile_ranges=None): + t1 = datetime.now() completion = { - 'label': _label(d), - 'kind': _TYPE_MAP.get(d.type), - 'detail': _detail(d), 'documentation': _utils.format_docstring(d.docstring()), - 'sortText': _sort_text(d), - 'insertText': d.name } + t2 = datetime.now() + sig = d.get_signatures() + completion.update({ + 'label': _label(d, sig), + 'kind': _TYPE_MAP.get(d.type), + 'sortText': _sort_text(d), + 'insertText': d.name, + 'detail': _detail(d), + }) + t3 = datetime.now() if d.type == 'path': path = osp.normpath(d.name) @@ -153,8 +178,14 @@ def _format_completion(d, include_params=True): path = path.replace('/', '\\/') completion['insertText'] = path - sig = d.get_signatures() - if (include_params and sig and not is_exception_class(d.name)): + profile_ranges['documentation'] += (t2 - t1) + profile_ranges['update'] += (t3 - t2) + profile_ranges['total'] += (t3 - t1) + if not include_params: + return completion + + if sig and not is_exception_class(d.name): + completion['label'] = _label(d, sig) positional_args = [param for param in sig[0].params if '=' not in param.description and param.name not in {'/', '*'}] @@ -174,12 +205,16 @@ def _format_completion(d, include_params=True): completion['insertText'] = d.name + '($0)' else: completion['insertText'] = d.name + '()' + # t4 = datetime.now() + + # profile_ranges['path'] += (t3 - t2) + # profile_ranges['forks'] += (t4 - t3) return completion -def _label(definition): - sig = definition.get_signatures() +def _label(definition, sig): + # sig = definition.get_signatures() if definition.type in ('function', 'method') and sig: params = ', '.join(param.name for param in sig[0].params) return '{}({})'.format(definition.name, params) diff --git a/pyls/python_ls.py b/pyls/python_ls.py index 754cee99..e49e6639 100644 --- a/pyls/python_ls.py +++ b/pyls/python_ls.py @@ -1,4 +1,5 @@ # Copyright 2017 Palantir Technologies, Inc. +from datetime import datetime from functools import partial import logging import os @@ -16,6 +17,7 @@ log = logging.getLogger(__name__) +profile_dump = open('/tmp/PythonLanguageServer.completions.prof', 'w') LINT_DEBOUNCE_S = 0.5 # 500 ms PARENT_PROCESS_WATCH_INTERVAL = 10 # 10 s MAX_WORKERS = 64 @@ -153,7 +155,9 @@ def _hook(self, hook_name, doc_uri=None, **kwargs): workspace = self._match_uri_to_workspace(doc_uri) doc = workspace.get_document(doc_uri) if doc_uri else None hook_handlers = self.config.plugin_manager.subset_hook_caller(hook_name, self.config.disabled_plugins) - return hook_handlers(config=self.config, workspace=workspace, document=doc, **kwargs) + ret = hook_handlers(config=self.config, workspace=workspace, document=doc, **kwargs) + + return ret def capabilities(self): server_capabilities = { @@ -237,7 +241,12 @@ def code_lens(self, doc_uri): return flatten(self._hook('pyls_code_lens', doc_uri)) def completions(self, doc_uri, position): + global profile_dump + t1 = datetime.now() completions = self._hook('pyls_completions', doc_uri, position=position) + t2 = datetime.now() + print('completions', t2 - t1, file=profile_dump) + profile_dump.flush() return { 'isIncomplete': False, 'items': flatten(completions)