Skip to content

Make sphinx-lint faster #76

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

Closed
AlexWaygood opened this issue Oct 10, 2023 · 11 comments · Fixed by #90
Closed

Make sphinx-lint faster #76

AlexWaygood opened this issue Oct 10, 2023 · 11 comments · Fixed by #90

Comments

@AlexWaygood
Copy link
Collaborator

We're running sphinx-lint as part of pre-commit at CPython, and it's a really useful check. However, it's by far the slowest check if you run pre-commit run --all-files locally. It would be great if we could speed it up somehow! (Note: I haven't looked into this at all yet; I don't know if there are any speedups that would be easily doable.)

@AA-Turner
Copy link
Member

See also python/cpython#110617; this seems partially a problem in pre-commit.

A

@AlexWaygood
Copy link
Collaborator Author

See also python/cpython#110617; this seems partially a problem in pre-commit.

A

Very nice! python/cpython#110617 sped things up on my laptop from around 22 seconds to around 17 seconds. That still feels painfully slow for local usage, though; let's see if we can improve on it even further ;)

@AlexWaygood
Copy link
Collaborator Author

Also: we should document somewhere that people are recommended to add require_serial: true if they're running sphinx-lint via pre-commit.

@AlexWaygood
Copy link
Collaborator Author

I did some profiling of sphinx-lint; here are the results (sorted by which functions have the most cumulative time spent in them):

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
      7/1    0.000    0.000    3.535    3.535 {built-in method builtins.exec}
        1    0.000    0.000    3.535    3.535 <string>:1(<module>)
        1    0.000    0.000    3.535    3.535 __main__.py:182(main)
        1    0.000    0.000    3.523    3.523 __main__.py:171(print_errors)
        1    0.000    0.000    3.523    3.523 __main__.py:152(sort_errors)
        7    0.000    0.000    3.523    0.503 sphinxlint.py:52(check_file)
        7    0.001    0.000    3.519    0.503 sphinxlint.py:33(check_text)
   158463    0.152    0.000    1.608    0.000 regex.py:249(match)
       14    0.050    0.004    1.556    0.111 utils.py:141(hide_non_rst_blocks)
   173060    0.496    0.000    1.514    0.000 regex.py:453(_compile)
    40278    0.076    0.000    1.288    0.000 utils.py:124(is_multiline_non_rst_block)
    40837    0.086    0.000    1.148    0.000 utils.py:30(clean_paragraph)
   163348    0.178    0.000    0.903    0.000 utils.py:12(_clean_heuristic)
        7    0.000    0.000    0.805    0.115 checkers.py:440(check_bad_dedent)
   349529    0.344    0.000    0.676    0.000 enum.py:1509(__and__)
   176114    0.555    0.000    0.574    0.000 {built-in method builtins.min}
        7    0.016    0.002    0.455    0.065 checkers.py:160(check_missing_space_after_role)
        7    0.017    0.002    0.262    0.037 checkers.py:464(check_dangling_hyphen)
   352879    0.147    0.000    0.259    0.000 enum.py:686(__call__)
        7    0.011    0.002    0.237    0.034 checkers.py:304(check_missing_space_before_default_role)
        7    0.008    0.001    0.203    0.029 checkers.py:87(check_unbalanced_inline_literals_delimiters)
        7    0.009    0.001    0.203    0.029 checkers.py:327(check_hyperlink_reference_missing_backtick)
        7    0.008    0.001    0.197    0.028 checkers.py:66(check_missing_space_after_literal)
   199512    0.187    0.000    0.187    0.000 {method 'finditer' of '_regex.Pattern' objects}
        7    0.004    0.001    0.155    0.022 checkers.py:284(check_missing_space_before_role)
   173060    0.112    0.000    0.148    0.000 <frozen importlib._bootstrap>:1207(_handle_fromlist)
   173060    0.117    0.000    0.146    0.000 regex.py:475(complain_unused_args)
   234853    0.140    0.000    0.140    0.000 {method 'match' of '_regex.Pattern' objects}
     9891    0.012    0.000    0.118    0.000 regex.py:340(finditer)
   352879    0.111    0.000    0.111    0.000 enum.py:1091(__new__)
    47431    0.097    0.000    0.097    0.000 {method 'sub' of '_regex.Pattern' objects}
   864591    0.093    0.000    0.093    0.000 {built-in method builtins.isinstance}
   134889    0.085    0.000    0.085    0.000 {method 'search' of '_regex.Pattern' objects}
     1080    0.003    0.000    0.067    0.000 utils.py:177(type_of_explicit_markup)
     3297    0.008    0.000    0.062    0.000 rst.py:154(inline_markup_gen)
    42295    0.041    0.000    0.061    0.000 utils.py:45(escape2null)
        7    0.008    0.001    0.055    0.008 checkers.py:245(check_role_with_double_backticks)
     3304    0.003    0.000    0.050    0.000 regex.py:349(compile)
    23149    0.039    0.000    0.049    0.000 utils.py:78(paragraphs)
      690    0.003    0.000    0.048    0.000 checkers.py:455(check_block)
        7    0.029    0.004    0.032    0.005 checkers.py:215(check_missing_space_in_hyperlink)
        7    0.028    0.004    0.032    0.005 checkers.py:230(check_missing_underscore_after_hyperlink)
   173263    0.030    0.000    0.030    0.000 {method 'get' of 'dict' objects}
   173060    0.029    0.000    0.029    0.000 regex.py:480(<setcomp>)
        7    0.007    0.001    0.024    0.003 checkers.py:188(check_role_without_backticks)
        7    0.007    0.001    0.024    0.003 checkers.py:348(check_missing_colon_in_role)
   173130    0.022    0.000    0.022    0.000 {built-in method builtins.hasattr}
        7    0.002    0.000    0.020    0.003 checkers.py:50(check_missing_backtick_after_role)
        7    0.007    0.001    0.019    0.003 checkers.py:148(check_directive_missing_colons)
   160569    0.019    0.000    0.019    0.000 {method 'append' of 'list' objects}
     1402    0.002    0.000    0.019    0.000 regex.py:263(search)
    23472    0.012    0.000    0.019    0.000 utils.py:8(match_size)
        7    0.007    0.001    0.016    0.002 checkers.py:136(check_directive_with_three_dots)
    46/18    0.000    0.000    0.014    0.001 _regex_core.py:417(_parse_pattern)
   280/18    0.003    0.000    0.014    0.001 _regex_core.py:427(parse_sequence)
        7    0.009    0.001    0.013    0.002 checkers.py:377(check_trailing_whitespace)
    28/13    0.000    0.000    0.012    0.001 _regex_core.py:803(parse_paren)
        1    0.000    0.000    0.011    0.011 __main__.py:25(parse_args)
    42936    0.010    0.000    0.010    0.000 {method 'find' of 'str' objects}
        9    0.000    0.000    0.010    0.001 argparse.py:1419(add_argument)
        9    0.000    0.000    0.010    0.001 argparse.py:2587(_get_formatter)
    66258    0.010    0.000    0.010    0.000 {method 'join' of 'str' objects}
        9    0.000    0.000    0.010    0.001 argparse.py:164(__init__)
        1    0.000    0.000    0.008    0.008 argparse.py:1737(__init__)
    73424    0.008    0.000    0.008    0.000 {method 'rstrip' of 'str' objects}
    35961    0.008    0.000    0.008    0.000 {method 'endswith' of 'str' objects}
     10/1    0.000    0.000    0.007    0.007 <frozen importlib._bootstrap>:1165(_find_and_load)
     10/1    0.000    0.000    0.007    0.007 <frozen importlib._bootstrap>:1120(_find_and_load_unlocked)
     3350    0.003    0.000    0.007    0.000 enum.py:1499(__or__)
      9/1    0.000    0.000    0.007    0.007 <frozen importlib._bootstrap>:666(_load_unlocked)
      5/1    0.000    0.000    0.007    0.007 <frozen importlib._bootstrap_external>:934(exec_module)
        7    0.004    0.001    0.007    0.001 checkers.py:201(check_backtick_before_role)
    40855    0.007    0.000    0.007    0.000 {method 'replace' of 'str' objects}
     21/2    0.000    0.000    0.006    0.003 <frozen importlib._bootstrap>:233(_call_with_frames_removed)
        1    0.000    0.000    0.006    0.006 shutil.py:1(<module>)
    21261    0.006    0.000    0.006    0.000 {method 'count' of 'str' objects}
     1474    0.002    0.000    0.006    0.000 _regex_core.py:2488(__init__)
       15    0.000    0.000    0.005    0.000 _regex_core.py:946(parse_lookaround)
    34724    0.005    0.000    0.005    0.000 {method 'end' of '_regex.Match' objects}
    36126    0.004    0.000    0.004    0.000 {method 'start' of '_regex.Match' objects}
   256/17    0.001    0.000    0.004    0.000 _regex_core.py:3422(pack_characters)
        1    0.000    0.000    0.003    0.003 _regex_core.py:893(parse_extension)
      4/3    0.000    0.000    0.003    0.001 _regex_core.py:2978(pack_characters)
      7/6    0.000    0.000    0.003    0.001 _regex_core.py:2096(pack_characters)
      7/6    0.000    0.000    0.003    0.001 _regex_core.py:2097(<listcomp>)
   280/18    0.001    0.000    0.003    0.000 _regex_core.py:3410(optimise)
        7    0.003    0.000    0.003    0.000 checkers.py:361(check_carriage_return)
        7    0.003    0.000    0.003    0.000 checkers.py:369(check_horizontal_tab)
        7    0.002    0.000    0.003    0.000 {method 'read' of '_io.TextIOWrapper' objects}
      327    0.001    0.000    0.003    0.000 _regex_core.py:3504(_flush_characters)
      7/6    0.000    0.000    0.003    0.000 _regex_core.py:2046(optimise)
        5    0.000    0.000    0.003    0.001 <frozen importlib._bootstrap_external>:1007(get_code)
      697    0.002    0.000    0.002    0.000 {method 'splitlines' of 'str' objects}
       10    0.000    0.000    0.002    0.000 <frozen importlib._bootstrap>:1054(_find_spec)
      4/3    0.000    0.000    0.002    0.001 _regex_core.py:2973(optimise)
        8    0.000    0.000    0.002    0.000 <frozen importlib._bootstrap_external>:1496(find_spec)
        8    0.000    0.000    0.002    0.000 <frozen importlib._bootstrap_external>:1464(_get_spec)
       25    0.000    0.000    0.002    0.000 <frozen importlib._bootstrap_external>:1604(find_spec)
    11218    0.002    0.000    0.002    0.000 {method 'group' of '_regex.Match' objects}
      7/6    0.000    0.000    0.002    0.000 _regex_core.py:2137(_flatten_branches)
        9    0.000    0.000    0.002    0.000 shutil.py:1398(get_terminal_size)
        5    0.000    0.000    0.002    0.000 <frozen importlib._bootstrap_external>:1127(get_data)
        1    0.000    0.000    0.002    0.002 bz2.py:1(<module>)
       18    0.000    0.000    0.002    0.000 _regex_core.py:1424(parse_set)
       15    0.000    0.000    0.002    0.000 _regex_core.py:3069(pack_characters)
        9    0.002    0.000    0.002    0.000 {built-in method nt.get_terminal_size}
13372/13358    0.002    0.000    0.002    0.000 {built-in method builtins.len}
        5    0.002    0.000    0.002    0.000 {built-in method io.open_code}
      340    0.000    0.000    0.001    0.000 _regex_core.py:384(make_case_flags)
        9    0.000    0.000    0.001    0.000 <frozen importlib._bootstrap>:566(module_from_spec)
       18    0.000    0.000    0.001    0.000 _regex_core.py:1490(parse_set_imp_union)
       15    0.000    0.000    0.001    0.000 _regex_core.py:3062(optimise)
       51    0.001    0.000    0.001    0.000 {built-in method nt.stat}
       79    0.000    0.000    0.001    0.000 _regex_core.py:1513(parse_set_member)
        2    0.000    0.000    0.001    0.001 <frozen importlib._bootstrap_external>:1231(create_module)
        2    0.001    0.001    0.001    0.001 {built-in method _imp.create_dynamic}
   468/24    0.000    0.000    0.001    0.000 _regex_core.py:1904(compile)
        1    0.000    0.000    0.001    0.001 lzma.py:1(<module>)
     2040    0.001    0.000    0.001    0.000 _regex_core.py:4008(get)
       81    0.000    0.000    0.001    0.000 _regex_core.py:1554(parse_set_item)
    31/17    0.000    0.000    0.001    0.000 _regex_core.py:3489(_compile)
       77    0.000    0.000    0.001    0.000 _regex_core.py:1202(parse_escape)
      119    0.001    0.000    0.001    0.000 <frozen importlib._bootstrap_external>:96(_path_join)
      249    0.000    0.000    0.001    0.000 _regex_core.py:3898(__init__)
       37    0.000    0.000    0.001    0.000 <frozen importlib._bootstrap_external>:140(_path_stat)
      9/6    0.000    0.000    0.001    0.000 _regex_core.py:1116(parse_flags_subpattern)
       22    0.000    0.000    0.001    0.000 __init__.py:272(_compile)
      9/6    0.000    0.000    0.001    0.000 _regex_core.py:1102(parse_subpattern)
        7    0.001    0.000    0.001    0.000 {built-in method io.open}
        4    0.000    0.000    0.001    0.000 _compiler.py:738(compile)
       21    0.000    0.000    0.001    0.000 __init__.py:225(compile)
      678    0.000    0.000    0.001    0.000 _regex_core.py:4151(match)
        1    0.000    0.000    0.001    0.001 fnmatch.py:1(<module>)
        7    0.000    0.000    0.001    0.000 <frozen codecs>:319(decode)
        7    0.001    0.000    0.001    0.000 {built-in method _codecs.utf_8_decode}
      7/6    0.000    0.000    0.001    0.000 _regex_core.py:2120(_compile)
      4/3    0.000    0.000    0.001    0.000 _regex_core.py:3000(_compile)
   280/18    0.000    0.000    0.001    0.000 _regex_core.py:3406(fix_groups)
        1    0.000    0.000    0.001    0.001 <frozen importlib._bootstrap>:975(exec_module)
      543    0.000    0.000    0.001    0.000 _regex_core.py:1847(make_sequence)
        1    0.000    0.000    0.001    0.001 <frozen posixpath>:1(<module>)
        3    0.000    0.000    0.000    0.000 argparse.py:1337(__init__)
      7/6    0.000    0.000    0.000    0.000 _regex_core.py:2042(fix_groups)
      4/3    0.000    0.000    0.000    0.000 _regex_core.py:2969(fix_groups)
        5    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap_external>:727(_compile_bytecode)
       47    0.000    0.000    0.000    0.000 _regex_core.py:394(make_character)
        7    0.000    0.000    0.000    0.000 _regex_core.py:2317(_reduce_to_set)
        5    0.000    0.000    0.000    0.000 {built-in method marshal.loads}
     2202    0.000    0.000    0.000    0.000 _regex_core.py:1854(__init__)
        4    0.000    0.000    0.000    0.000 _parser.py:972(parse)
       15    0.000    0.000    0.000    0.000 _regex_core.py:3091(_compile)
      567    0.000    0.000    0.000    0.000 _regex_core.py:3399(__init__)
    29/21    0.000    0.000    0.000    0.000 _regex_core.py:2851(optimise)
      5/4    0.000    0.000    0.000    0.000 _parser.py:449(_parse_sub)
        1    0.000    0.000    0.000    0.000 argparse.py:1868(parse_args)
       15    0.000    0.000    0.000    0.000 _regex_core.py:1381(parse_property)
        1    0.000    0.000    0.000    0.000 argparse.py:1875(parse_known_args)
        4    0.000    0.000    0.000    0.000 _compiler.py:571(_code)
        1    0.000    0.000    0.000    0.000 {built-in method builtins.print}
        7    0.000    0.000    0.000    0.000 _regex_core.py:335(_compile_firstset)
      6/5    0.000    0.000    0.000    0.000 _parser.py:509(_parse)
        1    0.000    0.000    0.000    0.000 argparse.py:1913(_parse_known_args)
    29/21    0.000    0.000    0.000    0.000 _regex_core.py:2880(_compile)
       14    0.000    0.000    0.000    0.000 {built-in method builtins.__build_class__}
    21/17    0.000    0.000    0.000    0.000 _regex_core.py:3813(optimise)
        9    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:493(_init_module_attrs)
        1    0.000    0.000    0.000    0.000 argparse.py:2062(consume_positionals)
       18    0.000    0.000    0.000    0.000 _regex_core.py:4320(_get_required_string)
     1088    0.000    0.000    0.000    0.000 {method 'lstrip' of 'str' objects}
        7    0.000    0.000    0.000    0.000 <frozen genericpath>:16(exists)
       55    0.000    0.000    0.000    0.000 _regex_core.py:1857(with_flags)
       10    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap_external>:437(cache_from_source)
        7    0.000    0.000    0.000    0.000 _regex_core.py:345(_check_firstset)
        1    0.000    0.000    0.000    0.000 __main__.py:204(<listcomp>)
       29    0.000    0.000    0.000    0.000 _regex_core.py:511(apply_quantifier)
       25    0.000    0.000    0.000    0.000 _regex_core.py:376(_flatten_code)
       18    0.000    0.000    0.000    0.000 {built-in method regex._regex.compile}
       15    0.000    0.000    0.000    0.000 _regex_core.py:1644(lookup_property)
        1    0.000    0.000    0.000    0.000 argparse.py:2213(_match_arguments_partial)
        5    0.000    0.000    0.000    0.000 {method 'read' of '_io.BufferedReader' objects}
      249    0.000    0.000    0.000    0.000 _regex_core.py:3926(_compile)
       12    0.000    0.000    0.000    0.000 {method '__exit__' of '_io._IOBase' objects}
       14    0.000    0.000    0.000    0.000 __main__.py:123(walk)
       10    0.000    0.000    0.000    0.000 __init__.py:89(find_spec)
       15    0.000    0.000    0.000    0.000 _regex_core.py:3059(fix_groups)
        7    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap_external>:159(_path_isfile)
        1    0.000    0.000    0.000    0.000 __init__.py:163(match)
        7    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap_external>:150(_path_is_mode_type)
     14/4    0.000    0.000    0.000    0.000 _compiler.py:37(_compile)
      280    0.000    0.000    0.000    0.000 _regex_core.py:508(<listcomp>)
        7    0.000    0.000    0.000    0.000 <frozen genericpath>:27(isfile)
    29/21    0.000    0.000    0.000    0.000 _regex_core.py:2856(pack_characters)
      799    0.000    0.000    0.000    0.000 {method 'startswith' of 'str' objects}
     1474    0.000    0.000    0.000    0.000 {built-in method builtins.chr}
        4    0.000    0.000    0.000    0.000 _regex_core.py:2150(_split_common_prefix)
       12    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:392(cached)
     1457    0.000    0.000    0.000    0.000 {built-in method builtins.ord}
       10    0.000    0.000    0.000    0.000 _regex_core.py:3833(_compile)
        3    0.000    0.000    0.000    0.000 _regex_core.py:2192(_split_common_suffix)
        7    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap_external>:567(_get_cached)
       14    0.000    0.000    0.000    0.000 <frozen ntpath>:231(splitext)
        1    0.000    0.000    0.000    0.000 __init__.py:350(namedtuple)
       36    0.000    0.000    0.000    0.000 _regex_core.py:2517(_compile)
       10    0.000    0.000    0.000    0.000 {built-in method builtins.locals}
      237    0.000    0.000    0.000    0.000 _regex_core.py:2371(_flush_set_members)
     1495    0.000    0.000    0.000    0.000 _regex_core.py:2508(optimise)
       10    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:169(__enter__)
       15    0.000    0.000    0.000    0.000 _regex_core.py:1633(standardise_name)
        5    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap_external>:1146(path_stats)
     1092    0.000    0.000    0.000    0.000 {method 'extend' of 'list' objects}
      119    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap_external>:119(<listcomp>)
        3    0.000    0.000    0.000    0.000 gettext.py:608(gettext)
        4    0.000    0.000    0.000    0.000 <frozen abc>:105(__new__)
        3    0.000    0.000    0.000    0.000 gettext.py:570(dgettext)
      9/8    0.000    0.000    0.000    0.000 _regex_core.py:3473(get_firstset)
     1433    0.000    0.000    0.000    0.000 _regex_core.py:1877(fix_groups)
     1362    0.000    0.000    0.000    0.000 {method 'isspace' of 'str' objects}
       18    0.000    0.000    0.000    0.000 _regex_core.py:4219(__init__)
        3    0.000    0.000    0.000    0.000 gettext.py:511(translation)
       30    0.000    0.000    0.000    0.000 <frozen os>:674(__getitem__)
    18/17    0.000    0.000    0.000    0.000 _regex_core.py:3596(get_required_string)
        9    0.000    0.000    0.000    0.000 argparse.py:1848(_add_action)
        3    0.000    0.000    0.000    0.000 gettext.py:471(find)
        7    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap_external>:1599(_get_spec)
        4    0.000    0.000    0.000    0.000 _compiler.py:509(_compile_info)
        9    0.000    0.000    0.000    0.000 argparse.py:1669(_add_action)
        6    0.000    0.000    0.000    0.000 {built-in method __new__ of type object at 0x00007FFC470F8F90}
       83    0.000    0.000    0.000    0.000 _parser.py:164(__getitem__)
       10    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:179(_get_module_lock)
       18    0.000    0.000    0.000    0.000 locale.py:666(getpreferredencoding)
       14    0.000    0.000    0.000    0.000 <frozen genericpath>:121(_splitext)
        2    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap_external>:1239(exec_module)
        1    0.000    0.000    0.000    0.000 _compression.py:1(<module>)
       29    0.000    0.000    0.000    0.000 _regex_core.py:4190(expect)
        1    0.000    0.000    0.000    0.000 {built-in method builtins.eval}
        7    0.000    0.000    0.000    0.000 sphinxlint.py:38(<setcomp>)
        9    0.000    0.000    0.000    0.000 argparse.py:1480(_add_action)
        7    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap_external>:778(spec_from_file_location)
        2    0.000    0.000    0.000    0.000 {built-in method _imp.exec_dynamic}
       37    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:1030(__exit__)
        9    0.000    0.000    0.000    0.000 _regex_core.py:1085(parse_flags)
       35    0.000    0.000    0.000    0.000 {built-in method builtins.max}
       71    0.000    0.000    0.000    0.000 {built-in method builtins.getattr}
        3    0.000    0.000    0.000    0.000 _regex_core.py:1321(parse_hex_escape)
       10    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap_external>:132(_path_split)
        9    0.000    0.000    0.000    0.000 argparse.py:601(_format_args)
       58    0.000    0.000    0.000    0.000 _regex_core.py:2842(__init__)
        2    0.000    0.000    0.000    0.000 enum.py:1369(_missing_)
        8    0.000    0.000    0.000    0.000 argparse.py:1560(_get_optional_kwargs)
       19    0.000    0.000    0.000    0.000 _regex_core.py:3658(_handle_case_folding)
        2    0.000    0.000    0.000    0.000 argparse.py:1470(add_argument_group)
    29/21    0.000    0.000    0.000    0.000 _regex_core.py:2848(fix_groups)
    20/19    0.000    0.000    0.000    0.000 {built-in method builtins.all}
       32    0.000    0.000    0.000    0.000 {method 'add' of 'set' objects}
       30    0.000    0.000    0.000    0.000 <frozen os>:748(encodekey)
       15    0.000    0.000    0.000    0.000 _regex_core.py:1612(numeric_to_rational)
    66/33    0.000    0.000    0.000    0.000 _regex_core.py:1910(__hash__)
       15    0.000    0.000    0.000    0.000 _regex_core.py:1402(parse_property_name)
     15/5    0.000    0.000    0.000    0.000 _parser.py:174(getwidth)
        1    0.000    0.000    0.000    0.000 argparse.py:1960(take_action)
        2    0.000    0.000    0.000    0.000 argparse.py:1647(__init__)
       12    0.000    0.000    0.000    0.000 <frozen _collections_abc>:771(get)
        5    0.000    0.000    0.000    0.000 _regex_core.py:3915(get_firstset)
       10    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:173(__exit__)
       17    0.000    0.000    0.000    0.000 _regex_core.py:3612(__init__)
      125    0.000    0.000    0.000    0.000 _regex_core.py:2204(<genexpr>)
      132    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:244(_verbose_message)
       18    0.000    0.000    0.000    0.000 {built-in method _locale.getencoding}
      123    0.000    0.000    0.000    0.000 _regex_core.py:2162(<genexpr>)
       10    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:71(__init__)
       30    0.000    0.000    0.000    0.000 _regex_core.py:3053(__init__)
        9    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:920(find_spec)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:778(exec_module)
       10    0.000    0.000    0.000    0.000 _regex_core.py:2505(rebuild)
       10    0.000    0.000    0.000    0.000 _regex_core.py:3587(is_empty)
        1    0.000    0.000    0.000    0.000 argparse.py:2465(_get_values)
        1    0.000    0.000    0.000    0.000 {built-in method _imp.exec_builtin}
       10    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:748(find_spec)
       16    0.000    0.000    0.000    0.000 _regex_core.py:4074(get_while)
       14    0.000    0.000    0.000    0.000 {built-in method builtins.any}
    66/33    0.000    0.000    0.000    0.000 {built-in method builtins.hash}
       18    0.000    0.000    0.000    0.000 _regex_core.py:3996(__init__)
        3    0.000    0.000    0.000    0.000 gettext.py:216(_expand_lang)
        7    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap_external>:172(_path_isabs)
       10    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:100(acquire)
       10    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:125(release)
        7    0.000    0.000    0.000    0.000 enum.py:1359(_iter_member_by_def_)
        1    0.000    0.000    0.000    0.000 _regex_core.py:3626(rebuild)
        5    0.000    0.000    0.000    0.000 _compiler.py:241(_optimize_charset)
       26    0.000    0.000    0.000    0.000 _parser.py:254(get)
        5    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap_external>:642(_classify_pyc)
       37    0.000    0.000    0.000    0.000 argparse.py:1390(register)
       15    0.000    0.000    0.000    0.000 {method 'match' of 're.Pattern' objects}
        7    0.000    0.000    0.000    0.000 _regex_core.py:2873(get_firstset)
        7    0.000    0.000    0.000    0.000 <frozen codecs>:309(__init__)
       30    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap_external>:134(<genexpr>)
       29    0.000    0.000    0.000    0.000 _regex_core.py:559(parse_quantifier)
       20    0.000    0.000    0.000    0.000 {built-in method _thread.allocate_lock}
       17    0.000    0.000    0.000    0.000 _regex_core.py:3486(has_simple_start)
        2    0.000    0.000    0.000    0.000 {built-in method builtins.sorted}
       15    0.000    0.000    0.000    0.000 _regex_core.py:3217(__init__)
       32    0.000    0.000    0.000    0.000 _regex_core.py:3240(_compile)
       33    0.000    0.000    0.000    0.000 _parser.py:233(__next)
        1    0.000    0.000    0.000    0.000 <frozen ntpath>:242(basename)
        7    0.000    0.000    0.000    0.000 _regex_core.py:2917(get_required_string)
       62    0.000    0.000    0.000    0.000 {method 'rfind' of 'str' objects}
        5    0.000    0.000    0.000    0.000 _regex_core.py:2547(get_required_string)
       10    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:198(cb)
        1    0.000    0.000    0.000    0.000 argparse.py:2514(<listcomp>)
       15    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap_external>:84(_unpack_uint32)
        1    0.000    0.000    0.000    0.000 _regex_core.py:1171(parse_name)
        1    0.000    0.000    0.000    0.000 __main__.py:20(as_supported_options)
        1    0.000    0.000    0.000    0.000 <frozen ntpath>:208(split)
        1    0.000    0.000    0.000    0.000 functools.py:518(decorating_function)
        4    0.000    0.000    0.000    0.000 {built-in method _abc._abc_init}
        9    0.000    0.000    0.000    0.000 argparse.py:1594(_pop_action_class)
        5    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap_external>:675(_validate_timestamp_pyc)
       30    0.000    0.000    0.000    0.000 <frozen os>:742(check_str)
       33    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap_external>:1421(_path_importer_cache)
        7    0.000    0.000    0.000    0.000 checkers.py:386(check_missing_final_newline)
       10    0.000    0.000    0.000    0.000 {built-in method _imp.is_builtin}
       37    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:1026(__enter__)
       12    0.000    0.000    0.000    0.000 enum.py:193(__get__)
        9    0.000    0.000    0.000    0.000 argparse.py:841(__init__)
        7    0.000    0.000    0.000    0.000 _compiler.py:396(_simple)
       25    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap_external>:67(_relax_case)
        9    0.000    0.000    0.000    0.000 _regex_core.py:1069(parse_flag_set)
       25    0.000    0.000    0.000    0.000 argparse.py:1394(_registry_get)
       18    0.000    0.000    0.000    0.000 _regex_core.py:4194(at_end)
       34    0.000    0.000    0.000    0.000 _parser.py:160(__len__)
       36    0.000    0.000    0.000    0.000 _regex_core.py:3207(_compile)
       14    0.000    0.000    0.000    0.000 sphinxlint.py:54(<genexpr>)
        9    0.000    0.000    0.000    0.000 _regex_core.py:1924(__init__)
        7    0.000    0.000    0.000    0.000 enum.py:1349(_iter_member_by_value_)
        4    0.000    0.000    0.000    0.000 _parser.py:224(__init__)
       13    0.000    0.000    0.000    0.000 _regex_core.py:2168(<genexpr>)
        7    0.000    0.000    0.000    0.000 argparse.py:2521(_get_value)
       20    0.000    0.000    0.000    0.000 _regex_core.py:3588(<genexpr>)
       11    0.000    0.000    0.000    0.000 {method 'format' of 'str' objects}
        1    0.000    0.000    0.000    0.000 functools.py:35(update_wrapper)
       14    0.000    0.000    0.000    0.000 _regex_core.py:2038(__init__)
       18    0.000    0.000    0.000    0.000 _regex_core.py:4281(_check_group_features)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:770(create_module)
        4    0.000    0.000    0.000    0.000 _regex_core.py:4238(open_group)
       20    0.000    0.000    0.000    0.000 _parser.py:172(append)
       54    0.000    0.000    0.000    0.000 {method 'rpartition' of 'str' objects}
        8    0.000    0.000    0.000    0.000 _parser.py:369(_escape)
        3    0.000    0.000    0.000    0.000 _regex_core.py:2417(is_empty)
        9    0.000    0.000    0.000    0.000 argparse.py:1607(_check_conflict)
        4    0.000    0.000    0.000    0.000 __main__.py:22(<genexpr>)
       45    0.000    0.000    0.000    0.000 _regex_core.py:1638(<genexpr>)
       30    0.000    0.000    0.000    0.000 {method 'index' of 'str' objects}
        2    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:422(spec_from_loader)
        9    0.000    0.000    0.000    0.000 _regex_core.py:1919(get_required_string)
        9    0.000    0.000    0.000    0.000 {method 'fileno' of '_io.TextIOWrapper' objects}
        5    0.000    0.000    0.000    0.000 _compiler.py:214(_compile_charset)
       50    0.000    0.000    0.000    0.000 {method 'items' of 'dict' objects}
       33    0.000    0.000    0.000    0.000 {built-in method nt.fspath}
        1    0.000    0.000    0.000    0.000 _parser.py:94(closegroup)
        2    0.000    0.000    0.000    0.000 argparse.py:984(__init__)
       14    0.000    0.000    0.000    0.000 _parser.py:286(tell)
        9    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:405(parent)
       14    0.000    0.000    0.000    0.000 sphinxlint.py:40(<genexpr>)
        9    0.000    0.000    0.000    0.000 argparse.py:594(format)
       36    0.000    0.000    0.000    0.000 _regex_core.py:3204(__init__)
        9    0.000    0.000    0.000    0.000 argparse.py:206(__init__)
       57    0.000    0.000    0.000    0.000 {built-in method _imp.acquire_lock}
        5    0.000    0.000    0.000    0.000 _regex_core.py:2511(get_firstset)
       57    0.000    0.000    0.000    0.000 {built-in method _imp.release_lock}
        1    0.000    0.000    0.000    0.000 {built-in method _imp.create_builtin}
       24    0.000    0.000    0.000    0.000 _parser.py:249(match)
        8    0.000    0.000    0.000    0.000 _regex_core.py:2961(__init__)
       61    0.000    0.000    0.000    0.000 _regex_core.py:1883(pack_characters)
        9    0.000    0.000    0.000    0.000 argparse.py:585(_metavar_formatter)
        5    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap_external>:599(_check_name_wrapper)
       10    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:357(__init__)
       33    0.000    0.000    0.000    0.000 {method 'pop' of 'list' objects}
       45    0.000    0.000    0.000    0.000 {method 'upper' of 'str' objects}
        9    0.000    0.000    0.000    0.000 _regex_core.py:2210(<genexpr>)
        1    0.000    0.000    0.000    0.000 bz2.py:26(BZ2File)
       15    0.000    0.000    0.000    0.000 _regex_core.py:1913(__eq__)
       26    0.000    0.000    0.000    0.000 {method 'pop' of 'dict' objects}
        3    0.000    0.000    0.000    0.000 _compiler.py:434(_get_literal_prefix)
       50    0.000    0.000    0.000    0.000 _regex_core.py:3231(optimise)
        7    0.000    0.000    0.000    0.000 {built-in method nt._path_splitroot}
        7    0.000    0.000    0.000    0.000 _regex_core.py:2081(_add_precheck)
       15    0.000    0.000    0.000    0.000 enum.py:1529(__invert__)
        1    0.000    0.000    0.000    0.000 __main__.py:31(<setcomp>)
       14    0.000    0.000    0.000    0.000 _parser.py:109(__init__)
       10    0.000    0.000    0.000    0.000 _regex_core.py:2551(<genexpr>)
       14    0.000    0.000    0.000    0.000 {built-in method builtins.setattr}
        2    0.000    0.000    0.000    0.000 argparse.py:926(__init__)
        3    0.000    0.000    0.000    0.000 locale.py:396(normalize)
        2    0.000    0.000    0.000    0.000 _regex_core.py:3290(optimise)
       45    0.000    0.000    0.000    0.000 {method 'setdefault' of 'dict' objects}
        2    0.000    0.000    0.000    0.000 _regex_core.py:3234(get_firstset)
        2    0.000    0.000    0.000    0.000 argparse.py:961(__init__)
        1    0.000    0.000    0.000    0.000 lzma.py:38(LZMAFile)
        6    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:48(_new_module)
        8    0.000    0.000    0.000    0.000 _compiler.py:568(isstring)
        3    0.000    0.000    0.000    0.000 argparse.py:1598(_get_handler)
        9    0.000    0.000    0.000    0.000 _regex_core.py:1933(_compile)
        6    0.000    0.000    0.000    0.000 _regex_core.py:2418(<genexpr>)
        1    0.000    0.000    0.000    0.000 _regex_core.py:3036(get_required_string)
        7    0.000    0.000    0.000    0.000 enum.py:117(_iter_bits_lsb)
       19    0.000    0.000    0.000    0.000 regex.py:646(<genexpr>)
        1    0.000    0.000    0.000    0.000 _regex_core.py:2994(get_firstset)
        9    0.000    0.000    0.000    0.000 {built-in method _imp.find_frozen}
        4    0.000    0.000    0.000    0.000 {built-in method _sre.compile}
        8    0.000    0.000    0.000    0.000 __main__.py:206(<genexpr>)
        4    0.000    0.000    0.000    0.000 _parser.py:956(fix_flags)
        1    0.000    0.000    0.000    0.000 __main__.py:116(<setcomp>)
        1    0.000    0.000    0.000    0.000 <frozen ntpath>:154(splitdrive)
        4    0.000    0.000    0.000    0.000 _regex_core.py:4264(close_group)
        2    0.000    0.000    0.000    0.000 _regex_core.py:3275(__init__)
        1    0.000    0.000    0.000    0.000 argparse.py:1106(__init__)
        7    0.000    0.000    0.000    0.000 <frozen codecs>:260(__init__)
       10    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:165(__init__)
       15    0.000    0.000    0.000    0.000 {built-in method from_bytes}
       10    0.000    0.000    0.000    0.000 _parser.py:79(groups)
        8    0.000    0.000    0.000    0.000 _regex_core.py:1957(_compile)
       20    0.000    0.000    0.000    0.000 {method '__exit__' of '_thread.lock' objects}
       26    0.000    0.000    0.000    0.000 _regex_core.py:1907(is_empty)
       17    0.000    0.000    0.000    0.000 _regex_core.py:3713(__del__)
        1    0.000    0.000    0.000    0.000 argparse.py:2219(<listcomp>)
        9    0.000    0.000    0.000    0.000 {method 'find' of 'bytearray' objects}
       20    0.000    0.000    0.000    0.000 {built-in method _thread.get_ident}
       16    0.000    0.000    0.000    0.000 {method 'split' of 'str' objects}
        1    0.000    0.000    0.000    0.000 _parser.py:446(_uniq)
        9    0.000    0.000    0.000    0.000 enum.py:1249(value)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:254(_requires_builtin_wrapper)
        4    0.000    0.000    0.000    0.000 _parser.py:73(__init__)
       15    0.000    0.000    0.000    0.000 _regex_core.py:410(make_property)
        1    0.000    0.000    0.000    0.000 argparse.py:1018(__init__)
        1    0.000    0.000    0.000    0.000 _parser.py:82(opengroup)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:895(_resolve_filename)
       11    0.000    0.000    0.000    0.000 {method 'discard' of 'set' objects}
       25    0.000    0.000    0.000    0.000 {built-in method builtins.callable}
        2    0.000    0.000    0.000    0.000 _compiler.py:465(_get_charset_prefix)
       12    0.000    0.000    0.000    0.000 _regex_core.py:3943(get_required_string)
        2    0.000    0.000    0.000    0.000 _regex_core.py:3321(_compile)
        6    0.000    0.000    0.000    0.000 _regex_core.py:3039(__del__)
        1    0.000    0.000    0.000    0.000 argparse.py:1544(_get_positional_kwargs)
        3    0.000    0.000    0.000    0.000 _regex_core.py:3085(get_firstset)
        1    0.000    0.000    0.000    0.000 argparse.py:1860(_get_positional_actions)
        1    0.000    0.000    0.000    0.000 _compression.py:33(DecompressReader)
        5    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap_external>:1097(__init__)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:962(create_module)
        1    0.000    0.000    0.000    0.000 _compiler.py:405(_generate_overlap_table)
       17    0.000    0.000    0.000    0.000 _regex_core.py:1880(optimise)
        4    0.000    0.000    0.000    0.000 _regex_core.py:2544(max_width)
        7    0.000    0.000    0.000    0.000 argparse.py:2229(_parse_optional)
        7    0.000    0.000    0.000    0.000 _parser.py:168(__setitem__)
        4    0.000    0.000    0.000    0.000 enum.py:796(<genexpr>)
        5    0.000    0.000    0.000    0.000 {built-in method _imp._fix_co_filename}
        3    0.000    0.000    0.000    0.000 _regex_core.py:1930(get_firstset)
       10    0.000    0.000    0.000    0.000 __init__.py:96(<lambda>)
        1    0.000    0.000    0.000    0.000 enum.py:792(__iter__)
        2    0.000    0.000    0.000    0.000 _regex_core.py:1898(get_firstset)
        9    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:413(has_location)
        5    0.000    0.000    0.000    0.000 _compiler.py:426(_get_iscased)
        7    0.000    0.000    0.000    0.000 {built-in method _stat.S_ISREG}
        9    0.000    0.000    0.000    0.000 _regex_core.py:1901(has_simple_start)
        4    0.000    0.000    0.000    0.000 __init__.py:424(<genexpr>)
        1    0.000    0.000    0.000    0.000 functools.py:479(lru_cache)
        4    0.000    0.000    0.000    0.000 _parser.py:162(__delitem__)
        5    0.000    0.000    0.000    0.000 {method 'clear' of 'set' objects}
        5    0.000    0.000    0.000    0.000 {method 'isidentifier' of 'str' objects}
        2    0.000    0.000    0.000    0.000 enum.py:1445(<listcomp>)
        6    0.000    0.000    0.000    0.000 _regex_core.py:3108(is_empty)
        7    0.000    0.000    0.000    0.000 argparse.py:2547(_check_value)
        1    0.000    0.000    0.000    0.000 _compression.py:9(BaseStream)
        4    0.000    0.000    0.000    0.000 {built-in method sys.intern}
        1    0.000    0.000    0.000    0.000 sphinxlint.py:26(from_argparse)
        7    0.000    0.000    0.000    0.000 _regex_core.py:1892(can_be_affix)
        1    0.000    0.000    0.000    0.000 {built-in method fromkeys}
        6    0.000    0.000    0.000    0.000 {method 'lower' of 'str' objects}
        5    0.000    0.000    0.000    0.000 enum.py:1366(<lambda>)
        1    0.000    0.000    0.000    0.000 argparse.py:1861(<listcomp>)
        5    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap_external>:1122(get_filename)
        5    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap_external>:931(create_module)
        4    0.000    0.000    0.000    0.000 {method '__contains__' of 'frozenset' objects}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
        1    0.000    0.000    0.000    0.000 argparse.py:2332(_get_nargs_pattern)
        3    0.000    0.000    0.000    0.000 argparse.py:623(<listcomp>)
        6    0.000    0.000    0.000    0.000 _regex_core.py:3923(has_simple_start)
        1    0.000    0.000    0.000    0.000 argparse.py:2223(<listcomp>)
        1    0.000    0.000    0.000    0.000 {method 'groups' of 're.Match' objects}
        1    0.000    0.000    0.000    0.000 __main__.py:35(EnableAction)
        3    0.000    0.000    0.000    0.000 enum.py:1244(name)
        1    0.000    0.000    0.000    0.000 <frozen ntpath>:35(_get_bothseps)
        2    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap_external>:1220(__init__)
        1    0.000    0.000    0.000    0.000 {method 'isdigit' of 'str' objects}
        2    0.000    0.000    0.000    0.000 _regex_core.py:3259(max_width)
        7    0.000    0.000    0.000    0.000 argparse.py:1777(identity)
        1    0.000    0.000    0.000    0.000 argparse.py:955(__call__)
        3    0.000    0.000    0.000    0.000 _regex_core.py:3115(max_width)
        1    0.000    0.000    0.000    0.000 __main__.py:49(StoreSortFieldAction)
        1    0.000    0.000    0.000    0.000 argparse.py:1322(__init__)
        1    0.000    0.000    0.000    0.000 {built-in method _imp.get_frozen_object}
        1    0.000    0.000    0.000    0.000 _compiler.py:31(_combine_flags)
        3    0.000    0.000    0.000    0.000 _regex_core.py:1947(max_width)
        1    0.000    0.000    0.000    0.000 __main__.py:42(DisableAction)
        1    0.000    0.000    0.000    0.000 {built-in method from_iterable}
        1    0.000    0.000    0.000    0.000 {method 'remove' of 'list' objects}
        3    0.000    0.000    0.000    0.000 _regex_core.py:1966(max_width)
        1    0.000    0.000    0.000    0.000 shutil.py:61(Error)
        3    0.000    0.000    0.000    0.000 {method 'reverse' of 'list' objects}
        1    0.000    0.000    0.000    0.000 {built-in method sys._getframe}
        3    0.000    0.000    0.000    0.000 _regex_core.py:2514(has_simple_start)
        1    0.000    0.000    0.000    0.000 _regex_core.py:3342(max_width)
        1    0.000    0.000    0.000    0.000 shutil.py:77(RegistryError)
        1    0.000    0.000    0.000    0.000 shutil.py:81(_GiveupOnFastCopy)
        1    0.000    0.000    0.000    0.000 shutil.py:64(SameFileError)
        1    0.000    0.000    0.000    0.000 shutil.py:67(SpecialFileError)
        1    0.000    0.000    0.000    0.000 shutil.py:71(ExecError)
        1    0.000    0.000    0.000    0.000 {method 'values' of 'dict' objects}
        1    0.000    0.000    0.000    0.000 {method 'update' of 'dict' objects}
        1    0.000    0.000    0.000    0.000 {built-in method builtins.iter}
        1    0.000    0.000    0.000    0.000 shutil.py:74(ReadError)
        1    0.000    0.000    0.000    0.000 <frozen importlib._bootstrap>:795(is_package)
Script I used for profiling it (has to be run from a directory that includes a CPython clone)
import cProfile
import sys
from sphinxlint.__main__ import main

files = [f"cpython/Doc/library/{module}.rst" for module in ("os", "typing", "sqlite3", "stdtypes", "argparse", "enum")]
files.append("cpython/Doc/reference/datamodel.rst")
cmd = f'main({["foo"] + files})'
cProfile.run(cmd, sort="cumulative")

@AA-Turner
Copy link
Member

AA-Turner commented Oct 10, 2023

Similarly, you could profile with py-spy:

py-spy record -o sphinx-lint-profile.json -f speedscope -r 750 -- python -m sphinxlint Doc/library/os.rst Doc/library/typing.rst Doc/library/sqlite3.rst Doc/library/stdtypes.rst Doc/library/argparse .rst Doc/library/enum.rst Doc/reference/datamodel.rst

This creates a JSON profile file used in the online viewer (https://www.speedscope.app/).

A

@AlexWaygood
Copy link
Collaborator Author

I have a patch locally that seems to provide a 24% speedup just by pre-compiling some regexes in utils.py. Will create the PR after dinner!

@rtobar
Copy link
Contributor

rtobar commented Oct 10, 2023

I have a patch locally that seems to provide a 24% speedup just by pre-compiling some regexes in utils.py. Will create the PR after dinner!

Enjoy dinner! And sorry for stepping into your toes, but I also went in the same direction after a quick profiling (using pyinstrument) and already created #77. I don't mind if yours gets picked up though, whatever makes the world faster.

@AlexWaygood
Copy link
Collaborator Author

I can't see anything else that provides an easy speedup here (and the impact of these PRs combined is great!), so I'll close this once #76 (comment) is done. Doing #76 (comment) first requires us to figure out which is faster, though: adding require_serial: true to the pre-commit config, or adding @rtobar's new -j flag from #78 to the pre-commit config.

@ezio-melotti
Copy link
Collaborator

As we discussed briefly at the sprint, I think that sphinx-lint goes through each file and applies all checkers, so if the file is big enough that it doesn't fit in the cache, the caching won't be as effective. From a quick test, increasing the cache seemed to make things about ~15% faster.

To determine the optimal cache size, you could inspect the cache info of each cache to determine the number of hits and misses, or profile the code, see the number of calls for each cached function, and divide by the number of documents to get an idea of how many items are in each document.

As we were leaving, I was about to suggest you to test it on these repos, to get an idea of both real-world performance improvements, and real-world file sizes that you can use to decide the cache size.

cc @AlexWaygood, @hugovk

@ezio-melotti
Copy link
Collaborator

After all the optimizations, sphinx-lint is about 3x faster on my machine. On the CPython docs it went from ~1m30s to just 30s. Good job everyone!

@AlexWaygood
Copy link
Collaborator Author

AlexWaygood commented Oct 13, 2023

pre-commit run --all-files sphinx-lint on CPython takes 4 seconds on my laptop following python/cpython@0ed2329 -- the same command took 22 seconds prior to python/cpython@e24f9ae! :D

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 a pull request may close this issue.

4 participants