Когда BPF(eBPF) отслеживает стек вызовов, все функции пользовательского режима отображаются как [неизвестно]. Почему это так?

Вопрос или проблема

Экспериментальная среда

┌──[[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], рекомендуется:

  1. Убедиться, что все программы, которые вы хотите анализировать, скомпилированы с отладочной информацией.
  2. Проверить совместимость используемой версии ядра с eBPF и убедиться, что все необходимые модули активированы.
  3. Применять инструменты трассировки с правильными флагами и параметрами.
  4. Рассмотреть возможность использования альтернативных подходов к отслеживанию, которые могут предоставить более полные данные о состоянии приложения.

Следуя этим рекомендациям, вы сможете повысить точность получаемой информации от eBPF инструментов и улучшить понимание происходящих в вашем коде процессов.

Оцените материал
Добавить комментарий

Капча загружается...