Вопрос или проблема
Экспериментальная среда
┌──[[email protected]]-[/usr/share/bcc/tools]
└─$hostnamectl
Статическое имя хоста: vms99.liruilongs.github.io
Имя иконки: computer-vm
Шасси: vm
Идентификатор машины: ea70bf6266cb413c84266d4153276342
Идентификатор загрузки: 0d01838b0095494c82d1befb174a317d
Виртуализация: vmware
Операционная система: Rocky Linux 8.9 (Green Obsidian)
Имя ОС CPE: cpe:/o:rocky:rocky:8:GA
Ядро: Linux 4.18.0-513.9.1.el8_9.x86_64
Архитектура: x86-64
┌──[[email protected]]-[/usr/share/bcc/tools]
└─$
При использовании BPF/eBPF
для отслеживания стека вызовов я обнаружил, что все функции в пользовательском режиме отображаются как [неизвестно]
┌──[[email protected]]-[/usr/share/bcc/tools]
└─$profile
Выборка с частотой 49 Гц для всех потоков по стеку пользователя + ядра... Нажмите Ctrl-C для завершения.
^C
_raw_spin_unlock_irqrestore
_raw_spin_unlock_irqrestore
prepare_to_swait_event
rcu_gp_kthread
kthread
ret_from_fork
- rcu_sched (14)
1
kmem_cache_alloc_node
kmem_cache_alloc_node
__alloc_skb
__ip_append_data.isra.50
ip_append_data.part.51
ip_send_unicast_reply
tcp_v4_send_reset
tcp_v4_rcv
ip_protocol_deliver_rcu
ip_local_deliver_finish
ip_local_deliver
ip_rcv
__netif_receive_skb_core
process_backlog
__napi_poll
net_rx_action
__softirqentry_text_start
do_softirq_own_stack
do_softirq.part.16
__local_bh_enable_ip
ip_finish_output2
ip_output
__ip_queue_xmit
__tcp_transmit_skb
tcp_connect
tcp_v4_connect
__inet_stream_connect
inet_stream_connect
__sys_connect
__x64_sys_connect
do_syscall_64
entry_SYSCALL_64_after_hwframe
[неизвестно]
- haproxy (1203)
1
show_vma_header_prefix
show_vma_header_prefix
show_map_vma
show_map
seq_read
vfs_read
ksys_read
do_syscall_64
entry_SYSCALL_64_after_hwframe
[неизвестно]
[неизвестно]
- awk (39726)
1
.............
┌──[[email protected]]-[/usr/share/bcc/tools]
└─$
В чем причина этого? Это связано с отсутствием информации для отладки в программе? Или по какой-то другой причине?
Я использовал Python
для написания демонстрации lock
, и это также произошло
┌──[[email protected]]-[~]
└─$cat lock_demo.py
import threading
import time
lock = threading.Lock()
def worker(id):
print(f"Рабочий {id} запущен")
with lock:
print(f"Рабочий {id} захватил блокировку")
time.sleep(2) # Симуляция длительных вычислений или I/O
print(f"Рабочий {id} освободил блокировку")
threads = []
for i in range(5):
t = threading.Thread(target=worker, args=(i,))
threads.append(t)
t.start()
for t in threads:
t.join()
print("Все рабочие завершили работу")
threadsnoop
┌──[[email protected]]-[~]
└─$threadsnoop
TIME(ms) PID COMM FUNC
0 51671 b'python3' b'[неизвестно]'
0 51671 b'python3' b'[неизвестно]'
0 51671 b'python3' b'[неизвестно]'
0 51671 b'python3' b'[неизвестно]'
0 51671 b'python3' b'[неизвестно]'
offcputime
┌──[[email protected]]-[~/FlameGraph]
└─$offcputime -p `pgrep -f lock_demo.py`
Отслеживание времени вне ЦП (мкС) PID 51397 по стеку пользователя + ядра... Нажмите Ctrl-C для завершения.
^C
.......................
finish_task_switch
__sched_text_start
schedule
futex_wait_queue_me
futex_wait
do_futex
__x64_sys_futex
do_syscall_64
entry_SYSCALL_64_after_hwframe
[неизвестно]
- python3 (51402)
157
finish_task_switch
__sched_text_start
schedule
futex_wait_queue_me
futex_wait
do_futex
__x64_sys_futex
do_syscall_64
entry_SYSCALL_64_after_hwframe
[неизвестно]
- python3 (51400)
213
finish_task_switch
__sched_text_start
schedule
futex_wait_queue_me
futex_wait
do_futex
__x64_sys_futex
do_syscall_64
entry_SYSCALL_64_after_hwframe
[неизвестно]
- python3 (51397)
267
finish_task_switch
__sched_text_start
schedule
do_nanosleep
hrtimer_nanosleep
common_nsleep_timens
__x64_sys_clock_nanosleep
do_syscall_64
entry_SYSCALL_64_after_hwframe
[неизвестно]
[неизвестно]
- python3 (51400)
2002609
finish_task_switch
__sched_text_start
schedule
do_nanosleep
hrtimer_nanosleep
common_nsleep_timens
__x64_sys_clock_nanosleep
do_syscall_64
entry_SYSCALL_64_after_hwframe
[неизвестно]
[неизвестно]
- python3 (51402)
2003178
..................
┌──[[email protected]]-[~/FlameGraph]
└─$
Любая помощь будет очень ценна, наилучшие пожелания
Ответ или решение
Причина появления [unknown]
в трассировке стека вызовов с использованием eBPF
Когда вы используете BPF
или eBPF
для отслеживания стека вызовов в пользовательских программах и видите, что функции в пользовательском режиме отображаются как [unknown]
, это может быть вызвано несколькими факторами. В этой статье мы подробно рассмотрим основные причины, по которым eBPF
не может разрешить имена функций, и предложим возможные пути решения проблемы.
Причины появления [unknown]
-
Отсутствие отладочной информации
- Самая распространенная причина, по которой
eBPF
не может отобразить имена пользовательских функций, — это отсутствие отладочной информации в скомпилированных бинарных файлах. Отладочная информация генерируется компиляторами с использованием таких опций, как-g
для GCC. Если ваши программы были скомпилированы без этой информации,eBPF
не сможет сопоставить адреса функций с их именами.
- Самая распространенная причина, по которой
-
Использование
stripped
бинарников- Многие дистрибутивы Linux и дистрибутивы программного обеспечения по умолчанию поставляются с бинарниками, от которых удалена отладочная информация для уменьшения размера файла и повышения безопасности. Если вы работаете с такими бинарниками (например, в случае приложений, установленных через дистрибутивные пакеты), это также приводит к тому, что на выходе вы видите
[unknown]
.
- Многие дистрибутивы Linux и дистрибутивы программного обеспечения по умолчанию поставляются с бинарниками, от которых удалена отладочная информация для уменьшения размера файла и повышения безопасности. Если вы работаете с такими бинарниками (например, в случае приложений, установленных через дистрибутивные пакеты), это также приводит к тому, что на выходе вы видите
-
Устаревшие версии инструментов BPF
- Использование устаревших или несовместимых версий инструментов
BPF
может также оказать влияние на их возможность правильно интерпретировать стеки вызовов. Убедитесь, что у вас установлены последние версии инструментовBPF
, таких какbpftrace
,bcc
и другие.
- Использование устаревших или несовместимых версий инструментов
-
Запуск в средах с высоким уровнем абстракции
- В случаях запуска ваших приложений в окружениях с высоким уровнем абстракции, таких как контейнеры, виртуальные машины или в средах, использующих особые библиотеки (например,
glibc
), могут возникать проблемы с разрешением адресов функций.
- В случаях запуска ваших приложений в окружениях с высоким уровнем абстракции, таких как контейнеры, виртуальные машины или в средах, использующих особые библиотеки (например,
-
Политики безопасности и конфигурации ядра
- Некоторые настройки безопасности, например
SELinux
, могут ограничить доступ к отладочной информации. Убедитесь, что ваша система правильно настроена, чтобы разрешить доступ к необходимым данным.
- Некоторые настройки безопасности, например
-
Процессы, использующие динамическую загрузку
- Если ваше приложение использует динамическую загрузку библиотек, то может быть сложнее отслеживать их. В этом случае вы можете также видеть
[unknown]
, так как адреса загружаемых функций могут быть не доступны во время вашего наблюдения.
- Если ваше приложение использует динамическую загрузку библиотек, то может быть сложнее отслеживать их. В этом случае вы можете также видеть
Возможные решения
- Компиляция с отладочной информацией: При компиляции ваших программ добавьте флаг
-g
, чтобы включить отладочную информацию. - Убедитесь в наличии отладочной информации: Вы можете использовать такие утилиты, как
file
илиreadelf
, чтобы проверить, есть ли отладочная информация в вашем бинарном файле:file your_program readelf --debug-dump your_program
- Убедитесь в актуальности инструментов: Обновите ваши инструменты и библиотеки, связанные с
BPF
, до последних стабильных версий. Используйте команду пакетного менеджера вашей системы для этого. - Проверьте настройки безопасности: Убедитесь, что настройки безопасности вашего ядра не мешают работе инструментов
BPF
.
Заключение
Изучение узких мест в производительности вашего приложения с помощью BPF
и eBPF
позволяет значительно оптимизировать его работу. Однако важно обеспечить наличие необходимой информации для корректной работы этих инструментов. Уделяя внимание деталям компиляции, версиям инструментов и конфигурации системы, вы сможете не только предотвратить возникновение проблемы с [unknown]
, но и улучшить общее качество трассировки стека вызовов.