Mercurial > hg
view contrib/bash_completion @ 39568:842cd0bdda75
util: teach lrucachedict to enforce a max total cost
Now that lrucachedict entries can have a numeric cost associated
with them and we can easily pop the oldest item in the cache, it
now becomes relatively trivial to implement support for enforcing
a high water mark on the total cost of items in the cache.
This commit teaches lrucachedict instances to have a max cost
associated with them. When items are inserted, we pop old items
until enough "cost" frees up to make room for the new item.
This feature is close to zero cost when not used (modulo the insertion
regressed introduced by the previous commit):
$ ./hg perflrucachedict --size 4 --gets 1000000 --sets 1000000 --mixed 1000000
! gets
! wall 0.607444 comb 0.610000 user 0.610000 sys 0.000000 (best of 17)
! wall 0.601653 comb 0.600000 user 0.600000 sys 0.000000 (best of 17)
! inserts
! wall 0.678261 comb 0.680000 user 0.680000 sys 0.000000 (best of 14)
! wall 0.685042 comb 0.680000 user 0.680000 sys 0.000000 (best of 15)
! sets
! wall 0.808770 comb 0.800000 user 0.800000 sys 0.000000 (best of 13)
! wall 0.834241 comb 0.830000 user 0.830000 sys 0.000000 (best of 12)
! mixed
! wall 0.782441 comb 0.780000 user 0.780000 sys 0.000000 (best of 13)
! wall 0.803804 comb 0.800000 user 0.800000 sys 0.000000 (best of 13)
$ hg perflrucachedict --size 1000 --gets 1000000 --sets 1000000 --mixed 1000000
! init
! wall 0.006952 comb 0.010000 user 0.010000 sys 0.000000 (best of 418)
! gets
! wall 0.613350 comb 0.610000 user 0.610000 sys 0.000000 (best of 17)
! wall 0.617415 comb 0.620000 user 0.620000 sys 0.000000 (best of 17)
! inserts
! wall 0.701270 comb 0.700000 user 0.700000 sys 0.000000 (best of 15)
! wall 0.700516 comb 0.700000 user 0.700000 sys 0.000000 (best of 15)
! sets
! wall 0.825720 comb 0.830000 user 0.830000 sys 0.000000 (best of 13)
! wall 0.837946 comb 0.840000 user 0.830000 sys 0.010000 (best of 12)
! mixed
! wall 0.821644 comb 0.820000 user 0.820000 sys 0.000000 (best of 13)
! wall 0.850559 comb 0.850000 user 0.850000 sys 0.000000 (best of 12)
I reckon the slight slowdown on insert is due to added if checks.
For caches with total cost limiting enabled:
$ hg perflrucachedict --size 4 --gets 1000000 --sets 1000000 --mixed 1000000 --costlimit 100
! gets w/ cost limit
! wall 0.598737 comb 0.590000 user 0.590000 sys 0.000000 (best of 17)
! inserts w/ cost limit
! wall 1.694282 comb 1.700000 user 1.700000 sys 0.000000 (best of 6)
! mixed w/ cost limit
! wall 1.157655 comb 1.150000 user 1.150000 sys 0.000000 (best of 9)
$ hg perflrucachedict --size 1000 --gets 1000000 --sets 1000000 --mixed 1000000 --costlimit 10000
! gets w/ cost limit
! wall 0.598526 comb 0.600000 user 0.600000 sys 0.000000 (best of 17)
! inserts w/ cost limit
! wall 37.838315 comb 37.840000 user 37.840000 sys 0.000000 (best of 3)
! mixed w/ cost limit
! wall 18.060198 comb 18.060000 user 18.060000 sys 0.000000 (best of 3)
$ hg perflrucachedict --size 1000 --gets 1000000 --sets 1000000 --mixed 1000000 --costlimit 10000 --mixedgetfreq 90
! gets w/ cost limit
! wall 0.600024 comb 0.600000 user 0.600000 sys 0.000000 (best of 17)
! inserts w/ cost limit
! wall 37.154547 comb 37.120000 user 37.120000 sys 0.000000 (best of 3)
! mixed w/ cost limit
! wall 4.381602 comb 4.380000 user 4.370000 sys 0.010000 (best of 3)
The functions we're benchmarking are slightly different, which could
move numbers by a few milliseconds. But the slowdown on insert is too
great to be explained by that. The slowness is due to insert heavy
operations needing to call popoldest() repeatedly when the cache is
at capacity. The next commit will address this.
Differential Revision: https://phab.mercurial-scm.org/D4503
author | Gregory Szorc <gregory.szorc@gmail.com> |
---|---|
date | Thu, 06 Sep 2018 14:04:46 -0700 |
parents | c54d4607e8aa |
children | f71c8eea7161 |
line wrap: on
line source
# bash completion for the Mercurial distributed SCM -*- sh -*- # Docs: # # If you source this file from your .bashrc, bash should be able to # complete a command line that uses hg with all the available commands # and options and sometimes even arguments. # # Mercurial allows you to define additional commands through extensions. # Bash should be able to automatically figure out the name of these new # commands and their options. See below for how to define _hg_opt_foo # and _hg_cmd_foo functions to fine-tune the completion for option and # non-option arguments, respectively. # # # Notes about completion for specific commands: # # - the completion function for the email command from the patchbomb # extension will try to call _hg_emails to get a list of e-mail # addresses. It's up to the user to define this function. For # example, put the addresses of the lists that you usually patchbomb # in ~/.patchbomb-to and the addresses that you usually use to send # the patchbombs in ~/.patchbomb-from and use something like this: # # _hg_emails() # { # if [ -r ~/.patchbomb-$1 ]; then # cat ~/.patchbomb-$1 # fi # } # # # Writing completion functions for additional commands: # # If it exists, the function _hg_cmd_foo will be called without # arguments to generate the completion candidates for the hg command # "foo". If the command receives some arguments that aren't options # even though they start with a "-", you can define a function called # _hg_opt_foo to generate the completion candidates. If _hg_opt_foo # doesn't return 0, regular completion for options is attempted. # # In addition to the regular completion variables provided by bash, # the following variables are also set: # - $hg - the hg program being used (e.g. /usr/bin/hg) # - $cmd - the name of the hg command being completed # - $cmd_index - the index of $cmd in $COMP_WORDS # - $cur - the current argument being completed # - $prev - the argument before $cur # - $global_args - "|"-separated list of global options that accept # an argument (e.g. '--cwd|-R|--repository') # - $canonical - 1 if we canonicalized $cmd before calling the function # 0 otherwise # shopt -s extglob _hg_cmd() { HGPLAIN=1 "$hg" "$@" 2>/dev/null } _hg_commands() { local commands commands="$(HGPLAINEXCEPT=alias _hg_cmd debugcomplete "$cur")" || commands="" COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$commands' -- "$cur")) } _hg_paths() { local paths="$(_hg_cmd paths -q)" COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$paths' -- "$cur")) } _hg_repos() { local i for i in $(compgen -d -- "$cur"); do test ! -d "$i"/.hg || COMPREPLY=(${COMPREPLY[@]:-} "$i") done } _hg_debugpathcomplete() { local files="$(_hg_cmd debugpathcomplete $1 "$cur")" local IFS=$'\n' COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$files' -- "$cur")) } _hg_status() { if [ -z "$HGCOMPLETE_NOSTATUS" ]; then local files="$(_hg_cmd status -n$1 "glob:$cur**")" local IFS=$'\n' COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$files' -- "$cur")) fi } _hg_branches() { local branches="$(_hg_cmd branches -q)" local IFS=$'\n' COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$branches' -- "$cur")) } _hg_bookmarks() { local bookmarks="$(_hg_cmd bookmarks -q)" local IFS=$'\n' COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$bookmarks' -- "$cur")) } _hg_labels() { local labels="$(_hg_cmd debugnamecomplete "$cur")" local IFS=$'\n' COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$labels' -- "$cur")) } # this is "kind of" ugly... _hg_count_non_option() { local i count=0 local filters="$1" for ((i=1; $i<=$COMP_CWORD; i++)); do if [[ "${COMP_WORDS[i]}" != -* ]]; then if [[ ${COMP_WORDS[i-1]} == @($filters|$global_args) ]]; then continue fi count=$(($count + 1)) fi done echo $(($count - 1)) } _hg_fix_wordlist() { local LASTCHAR=' ' if [ ${#COMPREPLY[@]} = 1 ]; then [ -d "$COMPREPLY" ] && LASTCHAR=/ COMPREPLY=$(printf %q%s "$COMPREPLY" "$LASTCHAR") else for ((i=0; i < ${#COMPREPLY[@]}; i++)); do [ -d "${COMPREPLY[$i]}" ] && COMPREPLY[$i]=${COMPREPLY[$i]}/ done fi } _hg() { local cur prev cmd cmd_index opts i aliashg # global options that receive an argument local global_args='--cwd|-R|--repository|--color|--config|--encoding|--encodingmode|--pager' local hg="$1" local canonical=0 aliashg=$(alias $hg 2>/dev/null) if [[ -n "$aliashg" ]]; then aliashg=${aliashg#"alias $hg='"} aliashg=${aliashg%"'"} hg=$aliashg fi COMPREPLY=() cur="$2" prev="$3" # searching for the command # (first non-option argument that doesn't follow a global option that # receives an argument) for ((i=1; $i<=$COMP_CWORD; i++)); do if [[ ${COMP_WORDS[i]} != -* ]]; then if [[ ${COMP_WORDS[i-1]} != @($global_args) ]]; then cmd="${COMP_WORDS[i]}" cmd_index=$i break fi fi done if [[ "$cur" == -* ]]; then if [ "$(type -t "_hg_opt_$cmd")" = function ] && "_hg_opt_$cmd"; then _hg_fix_wordlist return fi opts=$(HGPLAINEXCEPT=alias _hg_cmd debugcomplete --options "$cmd") COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$opts' -- "$cur")) _hg_fix_wordlist return fi # global options case "$prev" in -R|--repository) _hg_paths _hg_repos _hg_fix_wordlist return ;; --cwd) # Stick with default bash completion _hg_fix_wordlist return ;; --color) local choices='true false yes no always auto never debug' COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$choices' -- "$cur")) _hg_fix_wordlist return ;; --pager) local choices='true false yes no always auto never' COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$choices' -- "$cur")) _hg_fix_wordlist return ;; esac if [ -z "$cmd" ] || [ $COMP_CWORD -eq $i ]; then _hg_commands _hg_fix_wordlist return fi # try to generate completion candidates for whatever command the user typed local help if _hg_command_specific; then _hg_fix_wordlist return fi # canonicalize the command name and try again help=$(_hg_cmd help "$cmd") if [ $? -ne 0 ]; then # Probably either the command doesn't exist or it's ambiguous return fi cmd=${help#hg } cmd=${cmd%%[$' \n']*} canonical=1 _hg_command_specific _hg_fix_wordlist } _hg_command_specific() { if [ "$(type -t "_hg_cmd_$cmd")" = function ]; then "_hg_cmd_$cmd" return 0 fi if [ "$cmd" != status ]; then case "$prev" in -r|--rev) if [[ $canonical = 1 || status != "$cmd"* ]]; then _hg_labels return 0 fi return 1 ;; -B|--bookmark) if [[ $canonical = 1 || status != "$cmd"* ]]; then _hg_bookmarks return 0 fi return 1 ;; -b|--branch) if [[ $canonical = 1 || status != "$cmd"* ]]; then _hg_branches return 0 fi return 1 ;; esac fi local aliascmd=$(_hg_cmd showconfig alias.$cmd | awk '{print $1}') [ -n "$aliascmd" ] && cmd=$aliascmd case "$cmd" in help) _hg_commands ;; export) if _hg_ext_mq_patchlist qapplied && [ "${COMPREPLY[*]}" ]; then return 0 fi _hg_labels ;; manifest|update|up|checkout|co) _hg_labels ;; pull|push|outgoing|incoming) _hg_paths _hg_repos ;; paths) _hg_paths ;; add) _hg_status "u" ;; merge) _hg_labels ;; commit|ci|record|amend) _hg_status "mar" ;; remove|rm) _hg_debugpathcomplete -n ;; forget) _hg_debugpathcomplete -fa ;; diff) _hg_status "mar" ;; revert) _hg_status "mard" ;; clone) local count=$(_hg_count_non_option) if [ $count = 1 ]; then _hg_paths fi _hg_repos ;; debugindex|debugindexdot) COMPREPLY=(${COMPREPLY[@]:-} $(compgen -f -X "!*.i" -- "$cur")) ;; debugdata) COMPREPLY=(${COMPREPLY[@]:-} $(compgen -f -X "!*.d" -- "$cur")) ;; *) return 1 ;; esac return 0 } complete -o bashdefault -o default -o nospace -F _hg hg \ || complete -o default -o nospace -F _hg hg # Completion for commands provided by extensions # bookmarks _hg_cmd_bookmarks() { _hg_bookmarks return } # mq _hg_ext_mq_patchlist() { local patches patches=$(_hg_cmd $1) if [ $? -eq 0 ] && [ "$patches" ]; then COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$patches' -- "$cur")) return 0 fi return 1 } _hg_ext_mq_queues() { local root=$(_hg_cmd root) local n for n in $(cd "$root"/.hg && compgen -d -- "$cur"); do # I think we're usually not interested in the regular "patches" queue # so just filter it. if [ "$n" != patches ] && [ -e "$root/.hg/$n/series" ]; then COMPREPLY=(${COMPREPLY[@]:-} "$n") fi done } _hg_cmd_qpop() { if [[ "$prev" = @(-n|--name) ]]; then _hg_ext_mq_queues return fi _hg_ext_mq_patchlist qapplied } _hg_cmd_qpush() { if [[ "$prev" = @(-n|--name) ]]; then _hg_ext_mq_queues return fi _hg_ext_mq_patchlist qunapplied } _hg_cmd_qgoto() { if [[ "$prev" = @(-n|--name) ]]; then _hg_ext_mq_queues return fi _hg_ext_mq_patchlist qseries } _hg_cmd_qdelete() { local qcmd=qunapplied if [[ "$prev" = @(-r|--rev) ]]; then qcmd=qapplied fi _hg_ext_mq_patchlist $qcmd } _hg_cmd_qfinish() { if [[ "$prev" = @(-a|--applied) ]]; then return fi _hg_ext_mq_patchlist qapplied } _hg_cmd_qsave() { if [[ "$prev" = @(-n|--name) ]]; then _hg_ext_mq_queues return fi } _hg_cmd_rebase() { if [[ "$prev" = @(-s|--source|-d|--dest|-b|--base|-r|--rev) ]]; then _hg_labels return fi } _hg_cmd_strip() { if [[ "$prev" = @(-B|--bookmark) ]]; then _hg_bookmarks return fi _hg_labels } _hg_cmd_qcommit() { local root=$(_hg_cmd root) # this is run in a sub-shell, so we can't use _hg_status local files=$(cd "$root/.hg/patches" && _hg_cmd status -nmar) COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$files' -- "$cur")) } _hg_cmd_qfold() { _hg_ext_mq_patchlist qunapplied } _hg_cmd_qrename() { _hg_ext_mq_patchlist qseries } _hg_cmd_qheader() { _hg_ext_mq_patchlist qseries } _hg_cmd_qclone() { local count=$(_hg_count_non_option) if [ $count = 1 ]; then _hg_paths fi _hg_repos } _hg_ext_mq_guards() { _hg_cmd qselect --series | sed -e 's/^.//' } _hg_cmd_qselect() { local guards=$(_hg_ext_mq_guards) COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$guards' -- "$cur")) } _hg_cmd_qguard() { local prefix='' if [[ "$cur" == +* ]]; then prefix=+ elif [[ "$cur" == -* ]]; then prefix=- fi local ncur=${cur#[-+]} if ! [ "$prefix" ]; then _hg_ext_mq_patchlist qseries return fi local guards=$(_hg_ext_mq_guards) COMPREPLY=(${COMPREPLY[@]:-} $(compgen -P $prefix -W '$guards' -- "$ncur")) } _hg_opt_qguard() { local i for ((i=cmd_index+1; i<=COMP_CWORD; i++)); do if [[ ${COMP_WORDS[i]} != -* ]]; then if [[ ${COMP_WORDS[i-1]} != @($global_args) ]]; then _hg_cmd_qguard return 0 fi elif [ "${COMP_WORDS[i]}" = -- ]; then _hg_cmd_qguard return 0 fi done return 1 } _hg_cmd_qqueue() { local q local queues local opts="--list --create --rename --delete --purge" queues=$( _hg_cmd qqueue --quiet ) COMPREPLY=( $( compgen -W "${opts} ${queues}" "${cur}" ) ) } # hbisect _hg_cmd_bisect() { local i subcmd # find the sub-command for ((i=cmd_index+1; i<=COMP_CWORD; i++)); do if [[ ${COMP_WORDS[i]} != -* ]]; then if [[ ${COMP_WORDS[i-1]} != @($global_args) ]]; then subcmd="${COMP_WORDS[i]}" break fi fi done if [ -z "$subcmd" ] || [ $COMP_CWORD -eq $i ] || [ "$subcmd" = help ]; then COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W 'bad good help init next reset' -- "$cur")) return fi case "$subcmd" in good|bad) _hg_labels ;; esac return } # patchbomb _hg_cmd_email() { case "$prev" in -c|--cc|-t|--to|-f|--from|--bcc) # we need an e-mail address. let the user provide a function # to get them if [ "$(type -t _hg_emails)" = function ]; then local arg=to if [[ "$prev" == @(-f|--from) ]]; then arg=from fi local addresses=$(_hg_emails $arg) COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$addresses' -- "$cur")) fi return ;; -m|--mbox) # fallback to standard filename completion return ;; -s|--subject) # free form string return ;; esac _hg_labels return } # gpg _hg_cmd_sign() { _hg_labels } # transplant _hg_cmd_transplant() { case "$prev" in -s|--source) _hg_paths _hg_repos return ;; --filter) # standard filename completion return ;; esac # all other transplant options values and command parameters are revisions _hg_labels return } # shelve _hg_shelves() { local shelves="$(_hg_cmd shelve -ql)" local IFS=$'\n' COMPREPLY=(${COMPREPLY[@]:-} $(compgen -W '$shelves' -- "$cur")) } _hg_cmd_shelve() { if [[ "$prev" = @(-d|--delete|-l|--list|-p|--patch|--stat) ]]; then _hg_shelves else _hg_status "mard" fi } _hg_cmd_unshelve() { _hg_shelves }