TRACE-CMD-SQLHIST(1) libtracefs Manual TRACE-CMD-SQLHIST(1)

trace-cmd-sqlhist - استفاده از زبان SQL برای ایجاد یا نمایش ساخت هیستوگرام‌ها و رویدادهای ساختگی در tracefs

trace-cmd sqlhist [OPTIONS] [SQL-select-command]

دستور trace-cmd sqlhist(1) یک عبارت شبیه به SQL را برای ایجاد هیستوگرام‌های tracefs و رویدادهای ساختگی (synthetic events) دریافت می‌کند که می‌توانند اقدامات گوناگونی را برای پردازش‌های مختلف داده‌ها انجام دهند.

سامانه فایل tracefs با زیرساخت ردیابی (tracing) لینوکس که شامل رویدادهای ایستا و پویای مختلف در سراسر هسته است ارتباط برقرار می‌کند. هر یک از این رویدادها می‌تواند یک «هیستوگرام» متصل به خود داشته باشد، به‌طوری که فیلدهای رویداد، دسته‌های (buckets) هیستوگرام را تعیین می‌کنند.

یک رویداد ساختگی (synthetic event) روشی برای پیوند دادن دو رویداد مجزا و استفاده از فیلدها و برچسب‌های زمانی آن رویدادها جهت ایجاد یک رویداد پویای جدید است. این رویداد پویای جدید، یک رویداد ساختگی نامیده می‌شود. می‌توان محاسبات ساده‌ای روی فیلدهای هر رویداد انجام داد؛ برای مثال، محاسبه تفاضل (delta) میان یک فیلد از یک رویداد و فیلدی از رویداد دیگر. این قابلیت برای برچسب‌های زمانی رویدادها نیز کار می‌کند، به‌طوری که اختلاف زمانی بین دو رویداد نیز قابل استخراج و درج در رویداد ساختگی است.

اقدامات دیگری نیز می‌توان بر پایه فیلدهای رویدادها انجام داد. هنگامی که یک متغیر استفاده‌شده در ساخت رویداد ساختگی به یک مقدار بیشینه برسد، یا صرفاً مقدارش تغییر کند، می‌توان یک تصویر لحظه‌ای (snapshot) از بافر حلقه‌ای هسته تهیه کرد.

دستورات لازم برای ایجاد هیستوگرام‌ها و رویدادهای ساختگی پیچیده هستند و به‌خاطرسپاری آن‌ها آسان نیست. ابزار trace-cmd sqlhist برای تبدیل نحو SQL به دستورات لازم جهت ایجاد هیستوگرام یا رویداد ساختگی به کار می‌رود.

بخش SQL-select-command یک رشته SQL است که توسط tracefs_sqlhist(3) تعریف می‌شود.

توجه داشته باشید که این دستور باید با دسترسی ریشه (یا sudo) اجرا شود، زیرا تعامل با دایرکتوری tracefs نیازمند دسترسی کاربر ریشه است؛ مگر اینکه گزینه -t به همراه رونوشتی از دایرکتوری tracefs و رویدادهای آن مشخص شده باشد.

-n name

نام رویداد ساختگی جهت ایجاد. این رویداد سپس می‌تواند مانند هر رویداد دیگری استفاده شده و از طریق trace-cmd record(1) فعال شود.

-t tracefs-dir

به‌منظور آزمایش این دستور توسط کاربر غیر ریشه، می‌توان از یک رونوشت از دایرکتوری tracefs استفاده کرد و ارسال آن دایرکتوری با این گزینه، امکان کارکرد برنامه را فراهم می‌سازد. مسلماً، -e بدون دسترسی ریشه کار نخواهد کرد زیرا قادر به اجرا نخواهد بود.
# mkdir /tmp/tracing
# cp -r /sys/kernel/tracing/events /tmp/tracing
# exit
$ trace-cmd sqlhist -t /tmp/tracing ...

-e

نه تنها دستورات ایجاد هیستوگرام را نمایش می‌دهد، بلکه آن‌ها را اجرا نیز می‌کند. این کار نیازمند دسترسی ریشه است.

-f file

به جای خواندن دستورات SQL از خط فرمان، آن‌ها را از file می‌خواند. اگر file برابر با - باشد، ورودی از ورودی استاندارد خوانده می‌شود.

-m var

انجام اقدام تعیین‌شده هنگامی که متغیر var به یک مقدار بیشینه جدید برسد. این گزینه به همراه -c قابل استفاده نیست. متغیر var باید در SQL-select-command تعریف شده باشد.

-c var

انجام اقدام تعیین‌شده هنگامی که متغیر var تغییر مقدار دهد. این گزینه به همراه -m قابل استفاده نیست. متغیر var باید در SQL-select-command تعریف شده باشد.

-s

تهیه یک تصویر لحظه‌ای (snapshot) به جای فراخوانی رویداد ساختگی.

-T

انجام هم‌زمان تهیه تصویر لحظه‌ای و ردیابی رویداد ساختگی.

-S fields[,fields]

ذخیره فیلدهای مشخص‌شده. این فیلدها باید از فیلدهای رویداد پایانی («end») مشخص‌شده در SQL-select-command باشند.

-B instance

برای عبارت‌های ساده‌ای که فقط یک هیستوگرام تولید می‌کنند، نمایه (instance) ارائه‌شده در اینجا مکانی خواهد بود که هیستوگرام در آن ساخته می‌شود. این گزینه برای ایجاد کامل رویداد ساختگی نادیده گرفته می‌شود، زیرا رویدادهای ساختگی تأثیری سراسری روی تمام نمونه‌های ردیابی دارند، در حالی که هیستوگرام‌ها فقط بر یک نمایه منفرد اثر می‌گذارند.

همان‌طور که در بالا شرح داده شد، برای اهداف آزمایشی، یک رونوشت از دایرکتوری رویداد تهیه کنید:

$ mkdir /tmp/tracing
$ sudo cp -r /sys/kernel/tracing/events /tmp/tracing/
$ sudo chmod -R 0644 /tmp/tracing/

برای نمونه‌ای از یک خروجی هیستوگرام ساده با استفاده از رونوشت دایرکتوری tracefs.

$ trace-cmd sqlhist -t /tmp/tracing/ 'SELECT CAST(call_site as SYM-OFFSET), bytes_req, CAST(bytes_alloc AS _COUNTER_) FROM kmalloc'

خروجی زیر را تولید می‌کند:

echo 'hist:keys=call_site.sym-offset,bytes_req:vals=bytes_alloc' > /sys/kernel/tracing/events/kmem/kmalloc/trigger

که می‌تواند توسط کاربر ریشه (root) استفاده شود:

   # echo 'hist:keys=call_site.sym-offset,bytes_req:vals=bytes_alloc' > /sys/kernel/tracing/events/kmem/kmalloc/trigger
   # cat /sys/kernel/tracing/events/kmem/kmalloc/hist
# event histogram
#
# trigger info: hist:keys=call_site.sym-offset,bytes_req:vals=hitcount,bytes_alloc:sort=hitcount:size=2048 [active]
#
{ call_site: [ffffffff813f8d8a] load_elf_phdrs+0x4a/0xb0                               , bytes_req:        728 } hitcount:          1  bytes_alloc:       1024
{ call_site: [ffffffffc0c69e74] nf_ct_ext_add+0xd4/0x1d0 [nf_conntrack]                , bytes_req:        128 } hitcount:          1  bytes_alloc:        128
{ call_site: [ffffffff818355e6] dma_resv_get_fences+0xf6/0x440                         , bytes_req:          8 } hitcount:          1  bytes_alloc:          8
{ call_site: [ffffffffc06dc73f] intel_gt_get_buffer_pool+0x15f/0x290 [i915]            , bytes_req:        424 } hitcount:          1  bytes_alloc:        512
{ call_site: [ffffffff813f8d8a] load_elf_phdrs+0x4a/0xb0                               , bytes_req:        616 } hitcount:          1  bytes_alloc:       1024
{ call_site: [ffffffff8161a44c] __sg_alloc_table+0x11c/0x180                           , bytes_req:         32 } hitcount:          1  bytes_alloc:         32
{ call_site: [ffffffffc070749d] shmem_get_pages+0xad/0x5d0 [i915]                      , bytes_req:         16 } hitcount:          1  bytes_alloc:         16
{ call_site: [ffffffffc07507f5] intel_framebuffer_create+0x25/0x60 [i915]              , bytes_req:        408 } hitcount:          1  bytes_alloc:        512
{ call_site: [ffffffffc06fc20f] eb_parse+0x34f/0x910 [i915]                            , bytes_req:        408 } hitcount:          1  bytes_alloc:        512
{ call_site: [ffffffffc0700ebd] i915_gem_object_get_pages_internal+0x5d/0x270 [i915]   , bytes_req:         16 } hitcount:          1  bytes_alloc:         16
{ call_site: [ffffffffc0771188] intel_frontbuffer_get+0x38/0x220 [i915]                , bytes_req:        400 } hitcount:          1  bytes_alloc:        512
{ call_site: [ffffffff8161a44c] __sg_alloc_table+0x11c/0x180                           , bytes_req:        128 } hitcount:          1  bytes_alloc:        128
{ call_site: [ffffffff813f8f45] load_elf_binary+0x155/0x1680                           , bytes_req:         28 } hitcount:          1  bytes_alloc:         32
{ call_site: [ffffffffc07038c8] __assign_mmap_offset+0x208/0x3d0 [i915]                , bytes_req:        288 } hitcount:          1  bytes_alloc:        512
{ call_site: [ffffffff813737b2] alloc_bprm+0x32/0x2f0                                  , bytes_req:        416 } hitcount:          1  bytes_alloc:        512
{ call_site: [ffffffff813f9027] load_elf_binary+0x237/0x1680                           , bytes_req:         64 } hitcount:          1  bytes_alloc:         64
{ call_site: [ffffffff8161a44c] __sg_alloc_table+0x11c/0x180                           , bytes_req:         64 } hitcount:          1  bytes_alloc:         64
{ call_site: [ffffffffc040ffe7] drm_vma_node_allow+0x27/0xe0 [drm]                     , bytes_req:         40 } hitcount:          2  bytes_alloc:        128
{ call_site: [ffffffff813cda98] __do_sys_timerfd_create+0x58/0x1c0                     , bytes_req:        336 } hitcount:          2  bytes_alloc:       1024
{ call_site: [ffffffff818355e6] dma_resv_get_fences+0xf6/0x440                         , bytes_req:         40 } hitcount:          2  bytes_alloc:        128
{ call_site: [ffffffff8139b75a] single_open+0x2a/0xa0                                  , bytes_req:         32 } hitcount:          2  bytes_alloc:         64
{ call_site: [ffffffff815df715] bio_kmalloc+0x25/0x80                                  , bytes_req:        136 } hitcount:          2  bytes_alloc:        384
{ call_site: [ffffffffc071e5cd] i915_vma_work+0x1d/0x50 [i915]                         , bytes_req:        416 } hitcount:          3  bytes_alloc:       1536
{ call_site: [ffffffff81390d0d] alloc_fdtable+0x4d/0x100                               , bytes_req:         56 } hitcount:          3  bytes_alloc:        192
{ call_site: [ffffffffc06ff65f] i915_gem_do_execbuffer+0x158f/0x2440 [i915]            , bytes_req:         16 } hitcount:          4  bytes_alloc:         64
{ call_site: [ffffffff8137713c] alloc_pipe_info+0x5c/0x230                             , bytes_req:        384 } hitcount:          5  bytes_alloc:       2560
{ call_site: [ffffffff813771b4] alloc_pipe_info+0xd4/0x230                             , bytes_req:        640 } hitcount:          5  bytes_alloc:       5120
{ call_site: [ffffffff81834cdb] dma_resv_list_alloc+0x1b/0x40                          , bytes_req:         40 } hitcount:          6  bytes_alloc:        384
{ call_site: [ffffffff81834cdb] dma_resv_list_alloc+0x1b/0x40                          , bytes_req:         56 } hitcount:          9  bytes_alloc:        576
{ call_site: [ffffffff8120086e] tracing_map_sort_entries+0x9e/0x3e0                    , bytes_req:         24 } hitcount:         60  bytes_alloc:       1920
Totals:
    Hits: 122
    Entries: 30
    Dropped: 0

توجه داشته باشید گرچه در مثال‌ها برای کلیدواژه‌های SQL از حروف بزرگ استفاده شده است، اما این کار اجباری نیست. SELECT می‌تواند به صورت select یا حتی sElEcT نیز باشد.

با استفاده از زبان کامل SQL، می‌توان رویدادهای ساختگی (synthetic events) را ایجاد و پردازش کرد. به عنوان مثال، با استفاده از trace-cmd sqlhist به همراه trace-cmd record(1)، می‌توان تأخیر بیداری (wake up latency) را با ایجاد یک رویداد ساختگی از طریق پیوند دادن رویدادهای sched_waking و sched_switch ثبت کرد.

 # trace-cmd sqlhist -n wakeup_lat -e -T -m lat 'SELECT end.next_comm AS comm, (end.TIMESTAMP_USECS - start.TIMESTAMP_USECS) AS lat FROM ' \
   'sched_waking AS start JOIN sched_switch AS end ON start.pid = end.next_pid WHERE end.next_prio < 100 && end.next_comm == "cyclictest"'
 # trace-cmd start -e all -e wakeup_lat -R stacktrace
 # cyclictest -l 1000 -p80 -i250  -a -t -q -m -d 0 -b 1000 --tracemark
 # trace-cmd show -s | tail -30
         <idle>-0       [002] dNh4 23454.902246: sched_wakeup: comm=cyclictest pid=12272 prio=120 target_cpu=002
         <idle>-0       [005] ...1 23454.902246: cpu_idle: state=4294967295 cpu_id=5
         <idle>-0       [007] d..1 23454.902246: cpu_idle: state=0 cpu_id=7
         <idle>-0       [002] dNh1 23454.902247: hrtimer_expire_exit: hrtimer=0000000037956dc2
         <idle>-0       [005] d..1 23454.902248: cpu_idle: state=0 cpu_id=5
         <idle>-0       [002] dNh1 23454.902248: write_msr: 6e0, value 4866ce957272
         <idle>-0       [006] ...1 23454.902248: cpu_idle: state=4294967295 cpu_id=6
         <idle>-0       [002] dNh1 23454.902249: local_timer_exit: vector=236
         <idle>-0       [006] d..1 23454.902250: cpu_idle: state=0 cpu_id=6
         <idle>-0       [002] .N.1 23454.902250: cpu_idle: state=4294967295 cpu_id=2
         <idle>-0       [002] dN.1 23454.902251: rcu_utilization: Start context switch
         <idle>-0       [002] dN.1 23454.902252: rcu_utilization: End context switch
         <idle>-0       [001] ...1 23454.902252: cpu_idle: state=4294967295 cpu_id=1
         <idle>-0       [002] dN.3 23454.902253: prandom_u32: ret=3692516021
         <idle>-0       [001] d..1 23454.902254: cpu_idle: state=0 cpu_id=1
         <idle>-0       [002] d..2 23454.902254: sched_switch: prev_comm=swapper/2 prev_pid=0 prev_prio=120 prev_state=R ==> next_comm=cyclictest next_pid=12275 next_prio=19
         <idle>-0       [002] d..4 23454.902256: wakeup_lat: next_comm=cyclictest lat=17
         <idle>-0       [002] d..5 23454.902258: <stack trace>
=> trace_event_raw_event_synth
=> action_trace
=> event_hist_trigger
=> event_triggers_call
=> trace_event_buffer_commit
=> trace_event_raw_event_sched_switch
=> __traceiter_sched_switch
=> __schedule
=> schedule_idle
=> do_idle
=> cpu_startup_entry
=> secondary_startup_64_no_verify

در اینجا گزینه‌های مثال بالا توضیح داده شده‌اند:

-n wakeup_lat

نام رویداد ساختگیِ مورد استفاده را wakeup_lat تعیین می‌کند.

-e

دستورهایی را که چاپ می‌شوند اجرا می‌کند.

-T

هم یک کنش ردگیری (trace) و سپس یک کنش تصویر لحظه‌ای (snapshot) انجام می‌دهد (جابه‌جایی بافر به بافر ایستان snapshot).

-m lat

هر زمان که lat به یک مقدار بیشینه جدید برسد، کنش‌ها را فعال می‌کند.

اکنون تجزیه و تحلیل عبارت SQL:

'SELECT end.next_comm AS comm, (end.TIMESTAMP_USECS - start.TIMESTAMP_USECS) AS lat FROM ' \
   'sched_waking AS start JOIN sched_switch AS end ON start.pid = end.next_pid WHERE end.next_prio < 100 && end.next_comm == "cyclictest"'
end.next_comm AS comm
فیلد next_comm از رویداد sched_switch را ذخیره کرده و آن را در فیلد comm از رویداد ساختگی wakeup_lat قرار می‌دهد.

(end.TIMESTAMP_USECS - start.TIMESTAMP_USECS) AS lat

اختلاف (دلتا) برچسب‌های زمانی بین رویداد sched_switch و رویداد sched_waking را محاسبه می‌کند. از آنجا که برچسب‌های زمانی معمولاً بر حسب نانوثانیه ثبت می‌شوند، TIMESTAMP برچسب زمانی کامل به نانوثانیه را ارائه می‌دهد، اما در اینجا، TIMESTAMP_USECS آن را به میکروثانیه کوتاه می‌کند. این مقدار در متغیر lat ذخیره می‌شود که در رویداد ساختگی نیز ثبت خواهد شد.

FROM sched_waking AS start JOIN sched_switch AS end ON start.pid = end.next_pid

رویداد ساختگی را با پیوند دادن (join) sched_waking به sched_switch و تطبیق فیلد pid در sched_waking با فیلد next_pid در sched_switch ایجاد می‌کند. همچنین start را یک نام مستعار برای sched_waking و end را یک نام مستعار برای sched_switch قرار می‌دهد تا در ادامه عبارت SQL بتوان به ترتیب از start و end به عنوان جایگزین sched_waking و sched_switch استفاده کرد.

WHERE end.next_prio < 100 && end.next_comm == "cyclictest"

منطق را فیلتر می‌کند تا تنها در صورتی اجرا شود که فیلد next_prio در sched_waking کمتر از ۱۰۰ باشد. (توجه داشته باشید که در کرنل، اولویت‌ها معکوس هستند و اولویت‌های بلادرنگ بین ۰ تا ۱۰۰ نمایش داده می‌شوند که در آن ۰ بالاترین اولویت است). همچنین ردگیری فقط زمانی انجام می‌شود که next_comm (وظیفه‌ای که وارد زمان‌بندی می‌شود) از رویداد sched_switch نام "cyclictest" را داشته باشد.

برای دستور trace-cmd(3):

trace-cmd start -e all -e wakeup_lat -R stacktrace

trace-cmd start

ردگیری را فعال می‌کند (روی فایل ذخیره نمی‌کند).

-e all

فعال‌سازی همه رویدادها

-e wakeup_lat -R stacktrace

باعث می‌شود رویداد "wakeup_lat" (رویداد ساختگی ما) تریگر stacktrace را فعال کند، به طوری که برای هر نمونه از رویداد "wakeup_lat"، یک ردپای پشته کرنل (kernel stack trace) در بافر حلقه‌ای ثبت خواهد شد.

پس از فراخوانی cyclictest (یک ابزار بلادرنگ برای سنجش تاخیر بیدار شدن)، بافر snapshot را بخوانید.

trace-cmd show -s

دستور trace-cmd show بافر حلقه‌ای کرنل را می‌خواند و گزینه -s به جای بافر عادی، بافر snapshot را خواهد خواند.
<idle>-0       [002] d..4 23454.902256: wakeup_lat: next_comm=cyclictest lat=17
مشاهده می‌کنیم که رویداد "wakeup_lat" روی CPU 2 با تاخیر بیدار شدن ۱۷ میکروثانیه رخ داده است.

این مورد می‌تواند درون یک فایل trace.dat استخراج شود تا trace-cmd(3) و همچنین kernelshark بتوانند آن را خوانده و تحلیل‌های بیشتری انجام دهند.

    # trace-cmd extract -s
    # trace-cmd report --cpu 2 | tail -30
          <idle>-0     [002] 23454.902238: prandom_u32:          ret=1633425088
          <idle>-0     [002] 23454.902239: sched_wakeup:         cyclictest:12275 [19] CPU:002
          <idle>-0     [002] 23454.902241: hrtimer_expire_exit:  hrtimer=0xffffbbd68286fe60
          <idle>-0     [002] 23454.902241: hrtimer_cancel:       hrtimer=0xffffbbd6826efe70
          <idle>-0     [002] 23454.902242: hrtimer_expire_entry: hrtimer=0xffffbbd6826efe70 now=23455294430750 function=hrtimer_wakeup/0x0
          <idle>-0     [002] 23454.902243: sched_waking:         comm=cyclictest pid=12272 prio=120 target_cpu=002
          <idle>-0     [002] 23454.902244: prandom_u32:          ret=1102749734
          <idle>-0     [002] 23454.902246: sched_wakeup:         cyclictest:12272 [120] CPU:002
          <idle>-0     [002] 23454.902247: hrtimer_expire_exit:  hrtimer=0xffffbbd6826efe70
          <idle>-0     [002] 23454.902248: write_msr:            6e0, value 4866ce957272
          <idle>-0     [002] 23454.902249: local_timer_exit:     vector=236
          <idle>-0     [002] 23454.902250: cpu_idle:             state=4294967295 cpu_id=2
          <idle>-0     [002] 23454.902251: rcu_utilization:      Start context switch
          <idle>-0     [002] 23454.902252: rcu_utilization:      End context switch
          <idle>-0     [002] 23454.902253: prandom_u32:          ret=3692516021
          <idle>-0     [002] 23454.902254: sched_switch:         swapper/2:0 [120] R ==> cyclictest:12275 [19]
          <idle>-0     [002] 23454.902256: wakeup_lat:           next_comm=cyclictest lat=17
          <idle>-0     [002] 23454.902258: kernel_stack:         <stack trace >
=> trace_event_raw_event_synth (ffffffff8121a0db)
=> action_trace (ffffffff8121e9fb)
=> event_hist_trigger (ffffffff8121ca8d)
=> event_triggers_call (ffffffff81216c72)
=> trace_event_buffer_commit (ffffffff811f7618)
=> trace_event_raw_event_sched_switch (ffffffff8110fda4)
=> __traceiter_sched_switch (ffffffff8110d449)
=> __schedule (ffffffff81c02002)
=> schedule_idle (ffffffff81c02c86)
=> do_idle (ffffffff8111e898)
=> cpu_startup_entry (ffffffff8111eba9)
=> secondary_startup_64_no_verify (ffffffff81000107)

trace-cmd(1), tracefs_sqlhist(3)

نوشته شده توسط Steven Rostedt، <rostedt@goodmis.org[1]>

https://git.kernel.org/pub/scm/utils/trace-cmd/trace-cmd.git

کپی‌رایت (C) 2021 ، Inc. استفاده آزاد از این نرم‌افزار تحت شرایط مجوز عمومی همگانی گنو (GPL) مجاز است.

1.
rostedt@goodmis.org
mailto:rostedt@goodmis.org
03/09/2026 libtracefs