Skip to content

Commit

Permalink
history: optimize erasedups
Browse files Browse the repository at this point in the history
  • Loading branch information
akinomyoga committed Jun 19, 2022
1 parent 96e9bf8 commit 944d48e
Show file tree
Hide file tree
Showing 6 changed files with 317 additions and 143 deletions.
44 changes: 30 additions & 14 deletions ble.pp
Expand Up @@ -1021,6 +1021,36 @@ function ble/bin/.frozen:nawk { :; }
function ble/bin/.frozen:mawk { :; }
function ble/bin/.frozen:gawk { :; }

## @fn ble/bin/awk0
## awk implementation that supports NUL record separator
## @fn ble/bin/awk0.available
## initialize ble/bin/awk0 and returns whether ble/bin/awk0 is available
function ble/bin/awk0.available/test {
local count=0 cmd_awk=$1 awk_script='BEGIN { RS = "\0"; } { count++; } END { print count; }'
ble/util/assign count 'printf "a\0b\0" | "$cmd_awk" "$awk_script"'
((count==2))
}
function ble/bin/awk0.available {
local awk
for awk in mawk gawk; do
if ble/bin/.freeze-utility-path -n "$awk" &&
ble/bin/awk0.available/test ble/bin/"$awk" &&
builtin eval -- "function ble/bin/awk0 { ble/bin/$awk -v AWKTYPE=$awk \"\$@\"; }"; then
function ble/bin/awk0.available { ((1)); }
return 0
fi
done

if ble/bin/awk0.available/test ble/bin/awk &&
function ble/bin/awk0 { ble/bin/awk "$@"; }; then
function ble/bin/awk0.available { ((1)); }
return 0
fi

function ble/bin/awk0.available { ((0)); }
return 1
}

function ble/util/mkd {
local dir
for dir; do
Expand All @@ -1030,20 +1060,6 @@ function ble/util/mkd {
done
}

_ble_bin_awk_supports_null_RS=
function ble/bin/awk.supports-null-record-separator {
if [[ ! $_ble_bin_awk_supports_null_RS ]]; then
local count=0 awk_script='BEGIN { RS = "\0"; } { count++; } END { print count; }'
ble/util/assign count 'printf "a\0b\0" | ble/bin/awk "$awk_script" '
if ((count==2)); then
_ble_bin_awk_supports_null_RS=yes
else
_ble_bin_awk_supports_null_RS=no
fi
fi
[[ $_ble_bin_awk_supports_null_RS == yes ]]
}

#------------------------------------------------------------------------------
# readlink -f (Originally taken from akinomyoga/mshex.git)

Expand Down
1 change: 1 addition & 0 deletions docs/ChangeLog.md
Expand Up @@ -291,6 +291,7 @@
- prompt: reduce redundant evaluation of `PROMPT_COMMAND` on the startup `#D1778` 042376b
- main: run `ble/base/unload` directly at the end of `EXIT` handler `#D1797` 115baec
- util: optimize `ble/util/writearray` `#D1816` XXXXXXX
- history: optimize processing of `erasedups` (motivated by SuperSandro2000) `#D1817` XXXXXXX

## Compatibility

Expand Down
8 changes: 4 additions & 4 deletions lib/core-complete.sh
Expand Up @@ -6379,10 +6379,10 @@ function ble/complete/insert-all {
function ble/complete/insert-braces/.compose {
# Note: awk が RS = "\0" に対応していれば \0 で区切る。
# それ以外の場合には \x1E (ASCII RS) で区切る。
if ble/bin/awk.supports-null-record-separator; then
local printf_format='%s\0' RS='"\0"'
if ble/bin/awk0.available; then
local printf_format='%s\0' RS='"\0"' awk=ble/bin/awk0
else
local printf_format='%s\x1E' RS='"\x1E"'
local printf_format='%s\x1E' RS='"\x1E"' awk=ble/bin/awk
fi

local q=\'
Expand All @@ -6400,7 +6400,7 @@ function ble/complete/insert-braces/.compose {
esac
fi

printf "$printf_format" "$@" | ble/bin/awk '
printf "$printf_format" "$@" | "$awk" '
function starts_with(str, head) {
return substr(str, 1, length(head)) == head;
}
Expand Down
73 changes: 73 additions & 0 deletions note.txt
Expand Up @@ -6390,7 +6390,80 @@ bash_tips

2022-06-17

* util: erasedups 高速化 (motivated by SuperSandro2000) [#D1817]
https://github.com/akinomyoga/ble.sh/issues/198

一旦ファイルに書き出して awk で処理してから読み出す方式を試してみた。然し単
に配列を走査するよりも遅くなってしまった。

計測してみると awk による処理自体は高速だが書き出しと読み取りの両方で滅茶苦
茶時間がかかっている。printf '%s\n' "${arr[@]}" は遅いのだった。また、
mapfile -d '' も内部では1文字ずつ読むモードに切り替わってしまうのか遅い。こ
れは bash-5.2 以降でしか高速ではないのだった。

過去に同様の事をした気がする → #D1522 が対応する議論であった。

awk による処理は十分に高速の様だ (45ms)。読み取りは nlfix にすれば無視でき
るぐらいコストを小さくできる筈 (改行が大量に含まれていない限り)。

* done: 書き出しの高速化に関して。

printf '%s\0' が遅いので writearray を実装した筈なのに
writearray を確認してみたら遅い。これは別項目で考える事にする。

或いは history の出力を改めて解析した方が余程早いのではないか。と思ったが
history の出力が編集されていると微妙である。基本的には history の出力を使っ
て _ble_history を作っているのだから (そして勝手に Readline の編集が起こっ
ていなければ)、_ble_history の内容と history の出力結果は一致している筈で
ある。一方で、_ble_history_edit の内容に関しては結局配列として出力しなけ
ればならない。_ble_history の書き出しと _ble_history_edit の書き出しを並
列で実行するのだとしたら、_ble_history の側だけを history の出力を使って
高速化しても余り意味がない。

うーん。どうにも書き込みは並列で書き込むとしても精々 170 (printf) までしか
減らせない。更に bash-5.2 では printf は 455 もかかる。mawk でも 434 である。
なので、bash-5.2 だと絶望的である。元々直接ループを回していた時で 790 であ
る。高速化はしているが、結局大して高速化は期待できないのではないか。特に
5.2 以降で高速化しないのであれば古い ver で頑張る意味もない。

* done: 5.2 未満では nlfix で読み取らせる事にした。以下テスト用コード

{
ble/debug/stopwatch/start
ble/debug/stopwatch/stop 'save-data' >/dev/tty
ble/debug/stopwatch/start
ble/debug/stopwatch/stop 'proc-data' >/dev/tty
ble/debug/stopwatch/start
ble/debug/stopwatch/stop "load-data (${#_ble_history[*]}, ${#_ble_history_edit[*]})" >/dev/tty
# DEBUG
local dup=$( ( ( time ble/builtin/history/option:s/erasedups "$cmd"
declare -p _ble_history _ble_history_edit | sha256sum)
( time ble/builtin/history/option:s/erasedups.awk "$cmd"
declare -p _ble_history _ble_history_edit | sha256sum) ) | uniq -u)
ble/builtin/history/option:s/erasedups "$cmd"
if [[ ! $dup ]]; then
echo "${#delete_indices[@]}: ok"
else
echo "${#delete_indices[@]}: ng"
echo "$dup"
fi >/dev/tty
}

* done: awk0 が使えない場合には書き出しも nlfix にしてしまう?

→その様に実装してみた。nawk は遅くなる。mawk と gawk は十分な速度が出て
いる。それでも \0 の時よりは遅くなる様である。というか、mawk と gawk は結
局 \0 に対応しているので、この nlfix は実際の所使われる事はないという事に
なる。

* 別の可能性として erasedups で探索する範囲を制限するという事も考えられる。
Bash の erasedups は一時的に off にして、手動で見つかった項目を Bash のコ
マンド履歴からも削除するということ。探索範囲については、例えば起動時の
history の大きさを記録しておいて、それ以降に追加された項目のみを検査する
等。うーん。これは別項目として独立させる事にする。

* util: ble/util/writearray 最適化 [#D1816]
Ref. #D1817

やはり巨大な配列になると書き出しが最も遅い。

Expand Down

0 comments on commit 944d48e

Please sign in to comment.