Передача более длинных строк в tr приводит к зависанию и скачку загрузки ЦП

Передача более длинных строк в tr приводит к зависанию и скачку загрузки ЦП

MacOS Yosemite (10.10.5). Я знаю, что это раздел Unix/Linux... но думаю, что этот вопрос, вероятно, больше подходит здесь, чем в стране MacOS.

Мой терминал начал зависать при запуске, прежде чем показать приглашение... и загрузка ЦП резко возросла в то же время. Я могу нажать CTRL-C и затем получить приглашение (вероятно, выход из какого-то зависшего/работающего .bashrc/.profile/etc).

Я быстро понял, что определенные строки в моем .bashrc вызывали зависание. Это что-то новое (т.е. я ничего не менял в моем .bashrc и все работало нормально), так что что-то изменилось в системе.

Похоже, что передача определенных более длинных строк приводит к зависанию/скачку загрузки ЦП.

Я могу воспроизвести это, протянув струну tr -d '\n'и посмотрев, зависнет ли она.

macattack:~ $ openssl rand -base64 93  | tr -d '\n'
eDsz4JqFX/HAVjplNI6WDWwPRp9l9snp6UKp/pLn+GbBvJx0+ZMvSJFS/SuCwjMRRXVXfUvBdkaH1R0UgCr2UOf283MvHVTRusLFEVPcGCIz1t3sFMU/3foRzNWVmattp@macattack:~ $ openssl rand -base64 94 | tr -d '\n'
^C
mattp@macattack:~ $ openssl rand -base64 94 | tr -du '\n'
^C

Похоже, что 93 символа — это магическое число, после которого tr начинает зависать. openssl не зависает (т.е. если я уберу канал ко trвсему, то все закроется). Однако моя исходная проблемная строка оказалась другой длины.

mattp@macattack:~ $ echo 'echo -e "$TS\t${TERM_SESSION_ID}\t$(pwd)\t$(history 1 | cut -c 8-)\n" >> $HOME/.history/history-$(date "+%Y-%m-%d")-${USER}.log;' | tr -d '\n'
^C-bash: echo: write error: Interrupted system call

mattp@macattack:~ $ echo 'echo -e "$TS\t${TERM_SESSION_ID}\t$(pwd)\t$(history 1 | cut -c 8-)\n" >> $HOME/.history/history-$(date "+%Y-%m-%d")-${USER}.log' | tr -d '\n'

mattp@macattack:~ $ echo 'echo -e "$TS\t${TERM_SESSION_ID}\t$(pwd)\t$(history 1 | cut -c 8-)\n" >> $HOME/.history/history-$(date "+%Y-%m-%d")-${USER}.log' | wc -c
     128
mattp@macattack:~ $

Это, вероятно, проблема с трубой, а не с trпроблемой. Я могу воспроизвести ту же проблему с помощью sed(команда не имеет смысла... просто иллюстрирует зависание).

mattp@macattack:~ $ echo 'echo -e "$TS\t${TERM_SESSION_ID}\t$(pwd)\t$(history 1 | cut -c 8-)\n" >> $HOME/.history/history-$(date "+%Y-%m-%d")-${USER}.log;'  | sed 's/\n/ /g'
^C-bash: echo: write error: Interrupted system call

mattp@macattack:~ $ echo 'echo -e "$TS\t${TERM_SESSION_ID}\t$(pwd)\t$(history 1 | cut -c 8-)\n" >> $HOME/.history/history-$(date "+%Y-%m-%d")-${USER}.log'  | sed 's/\n/ /g'
echo -e "$TS\t${TERM_SESSION_ID}\t$(pwd)\t$(history 1 | cut -c 8-)\n" >> $HOME/.history/history-$(date "+%Y-%m-%d")-${USER}.log
mattp@macattack:~

У меня закончились идеи по устранению этой неполадки.
Зависающие команды отлично работают на случайном сервере Centos Linux. До недавнего времени команды отлично работали на Mac. Я никогда раньше не сталкивался с зависанием конвейера. Я думал, что, возможно, проблема в странных символах во входных данных... но случайная строка OpenSSL показывает обратное. Значения ulimits такие же, как на другом Mac, на котором НЕТ этой проблемы.

mattp@macattack:~ $ ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
file size               (blocks, -f) unlimited
max locked memory       (kbytes, -l) unlimited
max memory size         (kbytes, -m) unlimited
open files                      (-n) 7168
pipe size            (512 bytes, -p) 1
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 709
virtual memory          (kbytes, -v) unlimited

При использовании dtrusson, trпохоже, происходит зависание при вызове read_nocancel.

Обновлять

Прогресс. Нашел комментарий о зависании и размерах буфера конвейера. Украл тестовый скрипт отсюда: Каков размер буфера трубы?

Запуск во время возникновения проблемы показывает буфер канала 128 байт. Перезагрузите (проблема временно исчезает), и буфер канала составляет 65536 байт. Смотрите вывод теста ниже.

Итак, теперь вопрос в том, почему/как «что-то» уменьшает размер буфера канала в системе.

С проблемой

$ /bin/bash -c 'for p in {0..18}; do pipe-buffer-test.sh $((2 ** $p)) 0.5; done'
write size:          1; bytes successfully before error: 128
write size:          2; bytes successfully before error: 128
write size:          4; bytes successfully before error: 128
write size:          8; bytes successfully before error: 128
write size:         16; bytes successfully before error: 128
write size:         32; bytes successfully before error: 128
write size:         64; bytes successfully before error: 128
write size:        128; bytes successfully before error: 128
write size:        256; bytes successfully before error: 0
write size:        512; bytes successfully before error: 0
write size:       1024; bytes successfully before error: 0
write size:       2048; bytes successfully before error: 0
write size:       4096; bytes successfully before error: 0
write size:       8192; bytes successfully before error: 0
write size:      16384; bytes successfully before error: 0
write size:      32768; bytes successfully before error: 0
write size:      65536; bytes successfully before error: 0
write size:     131072; bytes successfully before error: 0
write size:     262144; bytes successfully before error: 0

После перезагрузки (проблема временно исчезла)

$ /bin/bash -c 'for p in {0..18}; do pipe-buffer-test.sh $((2 ** $p)) 0.5; done'
write size:          1; bytes successfully before error: 65536
write size:          2; bytes successfully before error: 65536
write size:          4; bytes successfully before error: 65536
write size:          8; bytes successfully before error: 65536
write size:         16; bytes successfully before error: 65536
write size:         32; bytes successfully before error: 65536
write size:         64; bytes successfully before error: 65536
write size:        128; bytes successfully before error: 65536
write size:        256; bytes successfully before error: 65536
write size:        512; bytes successfully before error: 65536
write size:       1024; bytes successfully before error: 65536
write size:       2048; bytes successfully before error: 65536
write size:       4096; bytes successfully before error: 65536
write size:       8192; bytes successfully before error: 65536
write size:      16384; bytes successfully before error: 65536
write size:      32768; bytes successfully before error: 65536
write size:      65536; bytes successfully before error: 65536
write size:     131072; bytes successfully before error: 0
write size:     262144; bytes successfully before error: 0

решение1

На основе комментария @Barmar о протечке буферов ядра я взглянул на текущие не-ОС kexts. Я понял, что есть относительно новый из недавней установки BlockBlock (https://objective-see.com/products/blockblock.html).

Удалил BlockBlock, перезапустил и проблема не повторилась. Так что BlockBlock был виновником в этом случае, и я сообщил о проблеме автору.

Однако это не особенно удовлетворяет, поскольку я в основном применял подход «догадки и проверки», чтобы выяснить причину, и, честно говоря, я не совсем понимаю первопричину (с точки зрения ОС), а значит, я не буду знать, как устранять подобные неполадки в будущем.

Если кто-то с этим столкнется и сможет более подробно объяснить, что происходит, и предложить подход к устранению неполадок, это будет гораздо лучшим ответом, чем «удалить BlockBlock».

Связанный контент