Вопрос или проблема
Экспериментальная среда
┌──[[email protected]]-[/usr/share/bcc/tools]
└─$hostnamectl
Статическое имя хоста: vms99.liruilongs.github.io
Имя иконки: computer-vm
Шасси: vm
Идентификатор машины: ea70bf6266cb413c84266d4153276342
Идентификатор загрузки: 0d01838b0095494c82d1befb174a317d
Виртуализация: vmware
Операционная система: Rocky Linux 8.9 (Green Obsidian)
CPE OS Name: 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) # Симуляция долгого вычисления или ввода-вывода
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_sysclock_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_sysclock_nanosleep
do_syscall_64
entry_SYSCALL_64_after_hwframe
[неизвестно]
[неизвестно]
- python3 (51402)
2003178
..................
┌──[[email protected]]-[~/FlameGraph]
└─$
Буду очень благодарен за любую помощь, всего наилучшего
Ответ или решение
Когда при использовании BPF/eBPF для трассировки стека вызовов все функции в пользовательском режиме отображаются как [unknown]
, это может быть связано с несколькими факторами, которые необходимо рассмотреть подробно. Эта проблема часто возникает в средах, где информация о отладке недоступна или не загружается должным образом.
1. Отсутствие отладочных символов
Одной из наиболее распространенных причин для появления [unknown]
в трассировках является отсутствие отладочных символов (debugging symbols). Когда вы компилируете приложение, вы можете включать отладочную информацию, которая позволяет инструментам такие как BPF, распознавать имена функций и их местоположение в исходном коде. Например, при компиляции на C или C++ следует использовать флаг -g
.
В Python, как в случае с вашим кодом, отладочные символы могут быть менее очевидными, поскольку интерпретируемые языки не требуют компиляции в традиционном смысле. Однако, если вы запускаете интерпретатор Python без отладочной информации, это может привести к тому, что BPF не сможет точно указать функции, происходящие из пользовательского кода.
2. Механизмы оптимизации
Еще одной причиной может быть оптимизация кода, осуществляемая интерпретатором или компилятором. Например, методы и функции могут быть сокращены или инлайнены, что приводит к смешению информации об их существовании для инструментов трассировки.
3. Версии ядра и eBPF
Используемая версия ядра Linux также может оказывать влияние. Некоторые более старые версии могут не полностью поддерживать инструменты и возможности BPF, что может ограничить функциональность визуализации. Убедитесь, что вы используете корректную и актуальную версию ядра, чтобы воспользоваться всеми преимуществами механизма eBPF.
4. Подходящие флаги запуска
При использовании инструментов BPF, таких как бэктрейсы и трассировочные инструменты, могут понадобиться определенные флаги и параметры командной строки. Например, использование флагов для информирования о том, что вы хотите собирать данные с подмножества функций или проводить детальную трассировку.
5. Контекст выполнения
Учтите также, что "точка остановки" может не совпадать с пользовательским контекстом, в котором вы ожидаете увидеть эти функции. При выполнении системных вызовов, таких как в вашем примере с блокировкой в Python, калибровка стеков может смещаться, и вызовы могут отображаться как системные. Если ваши потоки блокируются на уровне ядра (например, при ожидании блокировки), вы можете видеть только функции в ядре.
Заключение
Чтобы устранить проблему с отображением [unknown]
, рекомендуется:
- Убедиться, что все программы, которые вы хотите анализировать, скомпилированы с отладочной информацией.
- Проверить совместимость используемой версии ядра с eBPF и убедиться, что все необходимые модули активированы.
- Применять инструменты трассировки с правильными флагами и параметрами.
- Рассмотреть возможность использования альтернативных подходов к отслеживанию, которые могут предоставить более полные данные о состоянии приложения.
Следуя этим рекомендациям, вы сможете повысить точность получаемой информации от eBPF инструментов и улучшить понимание происходящих в вашем коде процессов.