From a0d32bb4b9da92d76c0e9492df3eec68a5bc455e Mon Sep 17 00:00:00 2001 From: ANtlord Date: Fri, 26 Jun 2020 13:55:09 +0300 Subject: [PATCH 1/2] Completion profile traps --- pyls/plugins/jedi_completion.py | 57 ++++++++++++++++++++++++++------- pyls/python_ls.py | 11 ++++++- 2 files changed, 56 insertions(+), 12 deletions(-) diff --git a/pyls/plugins/jedi_completion.py b/pyls/plugins/jedi_completion.py index afa48322..40973420 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,20 @@ 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), + #'documentation': _utils.format_docstring(d.docstring()), + } + t2 = datetime.now() + completion.update({ + 'label': d.name, 'kind': _TYPE_MAP.get(d.type), - 'detail': _detail(d), - 'documentation': _utils.format_docstring(d.docstring()), 'sortText': _sort_text(d), - 'insertText': d.name - } + 'insertText': d.name, + 'detail': _detail(d), + }) + t3 = datetime.now() if d.type == 'path': path = osp.normpath(d.name) @@ -153,8 +177,12 @@ def _format_completion(d, include_params=True): path = path.replace('/', '\\/') completion['insertText'] = path + if not include_params: + return completion + sig = d.get_signatures() - if (include_params and sig and not is_exception_class(d.name)): + 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 +202,19 @@ def _format_completion(d, include_params=True): completion['insertText'] = d.name + '($0)' else: completion['insertText'] = d.name + '()' + # t4 = datetime.now() + + profile_ranges['documentation'] += (t2 - t1) + profile_ranges['update'] += (t3 - t2) + profile_ranges['total'] += (t3 - t1) + # 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) From 21c484e64591e5352bc74b2166151ab6ac10e4ae Mon Sep 17 00:00:00 2001 From: ANtlord Date: Fri, 26 Jun 2020 14:19:15 +0300 Subject: [PATCH 2/2] Slow case demo --- pyls/plugins/jedi_completion.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pyls/plugins/jedi_completion.py b/pyls/plugins/jedi_completion.py index 40973420..9c16dd6a 100644 --- a/pyls/plugins/jedi_completion.py +++ b/pyls/plugins/jedi_completion.py @@ -159,11 +159,12 @@ def use_snippets(document, position): def _format_completion(d, include_params=True, profile_ranges=None): t1 = datetime.now() completion = { - #'documentation': _utils.format_docstring(d.docstring()), + 'documentation': _utils.format_docstring(d.docstring()), } t2 = datetime.now() + sig = d.get_signatures() completion.update({ - 'label': d.name, + 'label': _label(d, sig), 'kind': _TYPE_MAP.get(d.type), 'sortText': _sort_text(d), 'insertText': d.name, @@ -177,10 +178,12 @@ def _format_completion(d, include_params=True, profile_ranges=None): path = path.replace('/', '\\/') completion['insertText'] = path + profile_ranges['documentation'] += (t2 - t1) + profile_ranges['update'] += (t3 - t2) + profile_ranges['total'] += (t3 - t1) if not include_params: return completion - sig = d.get_signatures() if sig and not is_exception_class(d.name): completion['label'] = _label(d, sig) positional_args = [param for param in sig[0].params @@ -204,9 +207,6 @@ def _format_completion(d, include_params=True, profile_ranges=None): completion['insertText'] = d.name + '()' # t4 = datetime.now() - profile_ranges['documentation'] += (t2 - t1) - profile_ranges['update'] += (t3 - t2) - profile_ranges['total'] += (t3 - t1) # profile_ranges['path'] += (t3 - t2) # profile_ranges['forks'] += (t4 - t3)