Почему lsof в OS X так смехотворно медленный?

Я не могу понять, почему lsof на моем Mac (10.8.2, MacBook Pro) работает так медленно.

На моем Mac это lsofзанимает больше минуты:

$ touch /tmp/testfile
$ time lsof /tmp/testfile

real   1m16.483s
user   0m0.029s
sys    1m15.969s

На типичном компьютере Linux с Ubuntu 12.04 lsofтребуется 20 мс:

$ touch /tmp/testfile
$ time lsof /tmp/testfile

real   0m0.023s
user   0m0.008s
sys    0m0.012s

Проблема сохраняется, если я запускаю lsof -n(чтобы избежать поиска DNS). Кроме того, я попытался проверить, какие системные вызовы выполняются с lsofпомощью dtruss, и обнаружил, что он вызывает proc_infoдесятки тысяч раз:

$ sudo dtruss lsof /tmp/testfile 2> /tmp/dump
$ cat /tmp/dump | sort | uniq -c | sort -nr | head
10000 proc_info(0x2, 0x1199, 0x8) = 1272 0
 6876 proc_info(0x2, 0x45, 0x8) = 1272 0
 2360 proc_info(0x2, 0x190D, 0x8) = 1272 0
 1294 proc_info(0x2, 0xFF, 0x8) = 1272 0
 1152 proc_info(0x2, 0x474, 0x8) = 1272 0
 1079 proc_info(0x2, 0x2F, 0x8) = 1272 0
  709 proc_info(0x2, 0xFE, 0x8) = 1272 0
  693 proc_info(0x2, 0x1F, 0x8) = 1272 0
  623 proc_info(0x2, 0x11A, 0x8) = 1272 0
  528 proc_info(0x2, 0xF7, 0x8) = 1272 0

Любые идеи? Я провел эти тесты и получил одинаковые результаты, используя как версию, lsofвходящую в состав OS X (4.85), так и последнюю версию с ftp://sunsite.ualberta.ca/pub/Mirror/lsof/ (4.87).

(Любопытно, что причина, по которой я разочарован этой производительностью, заключается в том, что когда я перетаскиваю изображения в Evernote, он запускается lsofв процессе копирования файла, в результате чего моя система зависает на целую минуту каждый раз, когда я пытаюсь вставить изображение в Эверноут.)

Если у вас он выводится в консоль вместо файла, он зависает на каком-то конкретном месте? Я тоже на 10.8.2. У меня это заняло 6 секунд, и я заметил, что он каждый раз зависает на полпути к просмотру открытых файлов AirServer. Я убил AirServer, и время упало до 1,76 с. Возможно, в вашей системе есть что-то, что требует много времени для оценки?
Интересная точка данных, @WarrenPena. Если я запускаю lsofбез аргументов (чтобы перечислить все файлы), он зависает на минуту, а затем печатает все файлы. Но, как я уже упоминал, он все еще зависает, если я пытаюсь перечислить, у кого есть один открытый файл в каталоге / tmp, поэтому проблема не в конкретном открытом файле. Кроме того, у меня не запущен ни один процесс AirServer.
Это (только?) занимает у меня около секунды. Вы также можете попробовать sudo opensnoop -n lsof.
У меня это занимает 19 с. Без понятия, почему...
Хорошая идея, @LauriRanta. Я пробовал запускать sudo opensnoop -n lsofи lsof /tmp/testfileна двух вкладках, а opensnoop сообщил только, что было открыто три файла. Так что проблема должна быть не в чрезмерном количестве открываемых файлов, а в чем-то, связанном с чрезмерными proc_infoвызовами.
Вы заметили какую-либо другую медлительность на машине? Я вижу lsof, что Mountain Lion на секунду медленнее, чем Lion, поэтому явно происходят какие-то изменения (возможно, они оптимизируют другие вызовы или выполняют значительно больше работы с GateKeeper или подписыванием кода).
Я обнаружил, что выполнение lsof может занять несколько минут, если процесс имеет очень большое виртуальное адресное пространство. Обратите внимание, что виртуальное адресное пространство может быть намного больше, чем реально используемая память. Я видел такое, когда всайз был от 60G..11T.
~ 25 секунд здесь с MBP 2 ГГц на 10.9. Я думаю, что реализация проходит через каждый PID и запрашивает все их открытые FD.
реальный 4m27.515s пользователь 0m0.263s система 0m7.311s
20 секунд для меня, с MBP 2012 года на 10.13.4.

Ответы (3)

По моему опыту, от Mac OS X 10.7 (Lion) до 10.11.5 (EI Capitan) lsofвсегда зависали.

Чтобы решить проблему, добавьте -noption.

lsof -n

Согласно руководству lsof, -nвариант:

inhibits the conversion of network numbers to host names for network files.  
Inhibiting conversion may make  lsof  run faster.  It is also useful when host 
name lookup is not working properly

РЕДАКТИРОВАТЬ 2018-04-25: Если это все еще медленно, вы можете попробовать

-O to bypass  the  strategy it uses to avoid being blocked by some kernel operations
-P to inhibits the conversion of port numbers to port names for network files
-l to inhibits  the  conversion of user ID numbers to login names

Лучший способ выяснить, почему так медленно, — запустить инструмент «Инструменты» (в правом верхнем углу значка поиска Spotlight), чтобы выполнить «Системную трассировку» в /usr/sbin/lsof, а затем просмотреть график и системные вызовы.

введите описание изображения здесь введите описание изображения здесь введите описание изображения здесь введите описание изображения здесь введите описание изображения здесь

Ух ты! Добавление -nсокращения lsof +Dот 5.31 realдо 0.25 real. Этот вариант для... реальных
Все еще смехотворно медленно для меня...
Привет @Noldorin, ты на той же ОС, что и в этой старой теме? Если нет, новый конкретный вопрос, связанный здесь с вашей конкретной настройкой и конкретным временем, может стоить нового ответа.

Я думаю, что самая большая часть проблемы заключается в том, что macOS становится все более нелепой из-за раздувания и ненужных слоев за слоями расточительных фреймворков. Это означало, что сотни дополнительных процессов и тысячи дополнительных файлов остаются открытыми, что увеличивает объем работы lsof, которую необходимо выполнить, по крайней мере, на порядок, а возможно, и на два порядка.

lsofпереходил от разумной скорости к чудовищно медленной между 10,6 и 10,13.

Здесь, в текущей системе 10.13.4, я вижу следующее, когда открыто и запущено всего 7 приложений (Терминал, Chrome, Календарь, Finder, Adium, IPGadget и Stickies). (В Chrome 7 окон, по 10 вкладок в каждом.)

# ps ax | wc -l
     401
# time lsof -lnP | wc -l
   10976

real    0m49.684s
user    0m0.250s
sys 0m40.172s

Во время работы оба процессора занимают более 50% системного времени.

Добавление -Oиногда помогает, особенно если lsofон не запускался в последнее время, но лучшее, что я видел, это экономия около 10%. Обычно это ничтожно мало и, вероятно, не стоит рисков, описанных на странице руководства:

# time lsof -lnPO | wc -l
   10994

real    0m47.482s
user    0m0.249s
sys 0m40.472s

dtrussутверждает, что с моей текущей нагрузкой процесса более 89 000 вызовов proc_info(), и они находятся в ядре, и, как timeсообщается, подавляющее большинство времени проводится в ядре. Я не знаю, почему на один открытый файл приходится около 8 вызовов.

К сожалению, macOS/Darwin не включает еще более полезную и эффективную fstatкоманду BSD.

У меня нет отличного ответа, почему вашей системе требуется на минуту больше, чем моему самому медленному Mac, чтобы вызвать proc_info30 тысяч раз, но ваше время показывает, что и Linux, и OS X находятся в диапазоне 10 мс для пользовательского времени для запуска lsof. Можете ли вы воспроизвести медленную загрузку в безопасном режиме, чтобы исключить другие нагрузки на ваш процессор?

Я пробовал три Mac, и те, на которых работает 10.7.5, примерно на секунду быстрее, чем мой Mac 10.8.2. Более старые ОС — это более медленные процессоры Core 2 Duo, и я думаю, что i7 Mac под управлением более новой ОС будет таким же быстрым или даже быстрее, чем более старые ОС и ЦП, но я ошибаюсь.

Все машины делают примерно одинаковое количество вызовов proc_info, и все машины имеют ограниченное пользовательское время для команды, но у вас может быть более медленное общее время (и я понятия не имею, почему у вас так значительно медленнее, чем у моего Mountain Lion Мак).

11-дюймовый Air (i7) 2011 года с Mountain Lion — SSD:

$ system_profiler SPSoftwareDataType
      System Version: OS X 10.8.2 (or something)
      Kernel Version: Darwin 12.3.0
      Secure Virtual Memory: Enabled
$ time lsof /tmp/testfile 

real    0m1.179s
user    0m0.012s
sys     0m1.158s
$ sudo dtruss lsof /tmp/testfile 2> /tmp/dump
$ cat /tmp/dump | sort | uniq -c | sort -nr | head
9310 proc_info(0x2, 0x68, 0x8)           = 1272 0
1220 proc_info(0x2, 0xCEB6, 0x8)                 = 1272 0
$ cat /tmp/dump | cut -c -9 | sort | uniq -c | sort -nr | head
30884 proc_info
 116 write(0x4
  87 read(0x5,
  60 sigaction
  60 setitimer
  35 stat64("/
  30 sigprocma
  30 sigaltsta
  21 close(0x3
  18 close(0x6 

15-дюймовый MacBook Pro с Lion Server — жесткий диск:

$ system_profiler SPSoftwareDataType
      System Version: Mac OS X Server 10.7.5 (11G63)
      Kernel Version: Darwin 11.4.2
$ time lsof /tmp/testfile

real    0m0.329s
user    0m0.005s
sys     0m0.324s

27-дюймовый iMac под управлением Lion — жесткий диск:

$ system_profiler SPSoftwareDataType
      System Version: Mac OS X 10.7.5 (11G63b)
      Kernel Version: Darwin 11.4.2
$ time lsof /tmp/testfile

real    0m0.066s
user    0m0.002s
sys     0m0.065s
$ sudo dtruss lsof /tmp/testfile 2> /tmp/dump
$ cat /tmp/dump | cut -c -9 | sort | uniq -c | sort -nr | head
23034 proc_info
 188 write(0x4
 141 read(0x5,
  96 sigaction
  96 setitimer
  48 sigprocma
  48 sigaltsta
  31 stat64("/
  21 close(0x3
  18 close(0x6
+1. Я использую 10.8.2 на MBP конца 2010 года (i7 + 8 ГБ), и при запуске нескольких приложений я получаю ~ 1,8 с.