ftrace คือเครื่องมือดีบักที่ช่วยให้เข้าใจสิ่งที่เกิดขึ้นภายใน เคอร์เนลของ Linux ส่วนต่อไปนี้จะแสดงรายละเอียดฟังก์ชัน ftrace พื้นฐาน, ftrace การใช้ Atrace (ซึ่งรวบรวมเหตุการณ์ของเคอร์เนล) และ ftrace แบบไดนามิก
สำหรับรายละเอียดเกี่ยวกับฟังก์ชัน ftrace ขั้นสูงซึ่งไม่มีให้บริการใน
systrace โปรดดูเอกสาร ftrace ที่
<kernel
tree>/Documentation/trace/ftrace.txt
บันทึกเหตุการณ์ของเคอร์เนลด้วย Atrace
atrace (frameworks/native/cmds/atrace
) ใช้ ftrace เพื่อบันทึก
เหตุการณ์ของเคอร์เนล ในทางกลับกัน systrace.py (หรือ run_systrace.py ในเวอร์ชันที่ใหม่กว่าของ
Catapult) ใช้ adb
เพื่อเรียกใช้แอตทริบิวต์บนอุปกรณ์ แอตทริบิวต์ของแอตทริบิวต์จะดำเนินการดังต่อไปนี้
- ตั้งค่าการติดตามโหมดผู้ใช้โดยการตั้งค่าพร็อพเพอร์ตี้
(
debug.atrace.tags.enableflags
) - เปิดใช้ฟังก์ชัน ftrace ที่ต้องการโดยการเขียนไปยัง ftrace sysfs โหนด แต่เนื่องจาก ftrace สนับสนุนฟีเจอร์เพิ่มเติม คุณจึงอาจต้องกำหนด บางโหนดของ Sysfs ด้วยตนเองแล้วใช้ Atrace
อาศัยการใช้แอตทริบิวต์เพื่อตั้งค่า ยกเว้นการติดตามเวลาเปิดเครื่อง เป็นค่าที่เหมาะสม ที่พักนี้เป็นบิตมาสก์และไม่มีส่วนดี วิธีกำหนดค่าที่ถูกต้องนอกเหนือจากการดูส่วนหัวที่เหมาะสม (ซึ่งอาจเปลี่ยนแปลงได้ใน Android รุ่นต่างๆ)
เปิดใช้เหตุการณ์ ftrace
โหนด ftrace sysfs อยู่ใน /sys/kernel/tracing
และมีการติดตาม
กิจกรรมจะถูกแบ่งออกเป็นหมวดหมู่ใน /sys/kernel/tracing/events
หากต้องการเปิดใช้เหตุการณ์ตามหมวดหมู่ ให้ใช้
echo 1 > /sys/kernel/tracing/events/irq/enable
หากต้องการเปิดใช้เหตุการณ์แบบทีละเหตุการณ์ ให้ใช้
echo 1 > /sys/kernel/tracing/events/sched/sched_wakeup/enable
หากเปิดใช้เหตุการณ์เพิ่มเติมด้วยการเขียนไปยังโหนด Sysfs ระบบจะดำเนินการ
ไม่ จะถูกรีเซ็ตโดย Atrace รูปแบบทั่วไป
สำหรับการเรียกอุปกรณ์ Qualcomm คือการเปิดใช้ kgsl
(GPU) และ
mdss
(แสดงไปป์ไลน์) ของการติดตามแล้วจากนั้นใช้ Atrace หรือ
systrace:
adb shell "echo 1 > /sys/kernel/tracing/events/mdss/enable"
adb shell "echo 1 > /sys/kernel/tracing/events/kgsl/enable"
./systrace.py sched freq idle am wm gfx view binder_driver irq workq ss sync -t 10 -b 96000 -o full_trace.html
นอกจากนี้ คุณยังสามารถใช้ ftrace โดยไม่มี atrace หรือ systrace ซึ่ง มีประโยชน์เมื่อคุณต้องการติดตามเฉพาะเคอร์เนล (หรือหากใช้เวลานานในการเขียน พร็อพเพอร์ตี้การติดตามโหมดผู้ใช้ด้วยตนเอง) ในการเรียกใช้เพียง ftrace ให้ทำดังนี้
- กำหนดขนาดบัฟเฟอร์ให้มีค่าใหญ่พอสำหรับการติดตาม ดังนี้
echo 96000 > /sys/kernel/tracing/buffer_size_kb
- เปิดใช้งานการติดตาม:
echo 1 > /sys/kernel/tracing/tracing_on
- ทำการทดสอบ แล้วปิดใช้การติดตาม
echo 0 > /sys/kernel/tracing/tracing_on
- ทิ้งการติดตาม:
cat /sys/kernel/tracing/trace > /data/local/tmp/trace_output
Track_output จะให้การติดตามในรูปแบบข้อความ หากต้องการแสดงภาพโดยใช้ ทำจากหนังสติ๊ก ซื้อ ตัวเร่งปฏิกิริยา ที่เก็บจาก GitHub และเรียกใช้ query2html
catapult/tracing/bin/trace2html ~/path/to/trace_file
โดยค่าเริ่มต้น ระบบจะเขียน trace_file.html
เป็น
ไดเรกทอรี
เชื่อมโยงเหตุการณ์
การดูการแสดงภาพจาก Catapult และ ftrace มักจะมีประโยชน์ บันทึกพร้อมกัน เช่น เหตุการณ์ ftrace บางเหตุการณ์ (โดยเฉพาะผู้ให้บริการ ไม่แสดงภาพด้วย Catapult แต่การประทับเวลาของ Catapult สัมพันธ์กับเหตุการณ์แรกในการติดตามหรือกับการประทับเวลาที่เฉพาะเจาะจง ถูกส่งออกโดย Atrace ในขณะที่การประทับเวลาแบบ ftrace แบบข้อมูลดิบจะขึ้นอยู่กับ แหล่งที่มาของนาฬิกาแบบสัมบูรณ์ในเคอร์เนลของ Linux
วิธีค้นหาเหตุการณ์ ftrace จากเหตุการณ์ Catapult
- เปิดบันทึก ftrace ที่เป็นข้อมูลดิบ การติดตามใน Sytrace เวอร์ชันล่าสุดคือ
ที่บีบอัดโดยค่าเริ่มต้น:
- หากคุณจับภาพ Systrace ด้วย
--no-compress
แล้ว ไฟล์ HTML ในส่วนที่ขึ้นต้นด้วย BEGIN TRACE - หากไม่ ให้เรียกใช้ html2trace จาก
ตัวเร่งปฏิกิริยา
แผนผัง (
tracing/bin/html2trace
) เพื่อยกเลิกการบีบอัดการติดตาม
- หากคุณจับภาพ Systrace ด้วย
- ค้นหาการประทับเวลาแบบสัมพัทธ์ในการแสดงภาพจาก Catapult
- ค้นหาบรรทัดที่จุดเริ่มต้นของการติดตามที่มี
tracing_mark_sync
ซึ่งควรมีหน้าตาเช่นนี้<5134>-5134 (-----) [003] ...1 68.104349: tracing_mark_write: trace_event_clock_sync: parent_ts=68.104286
หากไม่มีบรรทัดนี้ (หรือหากใช้ ftrace โดยไม่มีแอตทริบิวต์) ให้ทำดังนี้ เวลาจะสัมพันธ์กันจากเหตุการณ์แรกในบันทึก ftrace- เพิ่มการประทับเวลาสัมพัทธ์ (เป็นมิลลิวินาที) ไปยังค่าใน
parent_ts
(เป็นวินาที) - ค้นหาการประทับเวลาใหม่
- เพิ่มการประทับเวลาสัมพัทธ์ (เป็นมิลลิวินาที) ไปยังค่าใน
ขั้นตอนเหล่านี้ควรนำคุณไปยัง (หรืออย่างน้อยก็ใกล้กับ) เหตุการณ์
ใช้ ftrace แบบไดนามิก
เมื่อ Systrace และ ftrace มาตรฐานไม่เพียงพอ จะมีตัวระบุ มีทรัพยากรเพิ่มเติม: ftrace แบบไดนามิก การติดตามแบบไดนามิกต้องมีการเขียนใหม่ ของรหัสเคอร์เนลหลังจากเปิดเครื่อง ส่งผลให้ไม่สามารถใช้งานได้ในเวอร์ชันที่ใช้งานจริง เคอร์เนลด้วยเหตุผลด้านความปลอดภัย อย่างไรก็ตาม ทุกข้อบกพร่อง ด้านประสิทธิภาพที่ยาก ท้ายที่สุดแล้วปี 2015 และ 2016 ก็เกิดจากสาเหตุหลักจากการใช้ ftrace แบบไดนามิก โดยเฉพาะอย่างยิ่ง มีประสิทธิภาพในการแก้ไขข้อบกพร่องของสลีปที่หยุดชะงักเพราะคุณอาจได้รับสแต็กเทรซ ในเคอร์เนลทุกครั้งที่คุณกดฟังก์ชันที่ทริกเกอร์การนอนหลับอย่างไม่ขาดตอน อีกทั้งยังแก้ไขข้อบกพร่องของส่วนที่มีการปิดใช้การรบกวนและการขัดจังหวะชั่วคราวได้ด้วย ซึ่งการทำเช่นนี้ มีประโยชน์อย่างมากในการพิสูจน์ปัญหา
หากต้องการเปิด ftrace แบบไดนามิก ให้แก้ไข defconfig ของเคอร์เนลดังนี้
- ลบ CONFIG_STRICT_MEMORY_RWX (หากมี) หากคุณใช้เวอร์ชัน 3.18 หรือ ใหม่กว่ากับ arm64 ไม่ได้อยู่ตรงนั้นนะ
- เพิ่มรายการต่อไปนี้: CONFIG_DYNAMIC_FTRACE=y, CONFIG_FUNCTION_TRACER=y, CONFIG_IRQSOFF_TRACER=y, CONFIG_FUNCTION_PROFILER=y และ CONFIG_PREEMPT_TRACER=y
- สร้างและเปิดเครื่องเคอร์เนลใหม่
- เรียกใช้รายการต่อไปนี้เพื่อตรวจหาตัวติดตามที่ใช้ได้
cat /sys/kernel/tracing/available_tracers
- ยืนยันว่าคำสั่งแสดง
function
,irqsoff
,preemptoff
และpreemptirqsoff
- เรียกใช้สิ่งต่อไปนี้เพื่อให้แน่ใจว่าฟุตเทรซแบบไดนามิกทํางานอยู่
cat /sys/kernel/tracing/available_filter_functions | grep <a function you care about>
หลังจากเสร็จสิ้นขั้นตอนเหล่านี้ คุณจะมี ftrace แบบไดนามิก ซึ่งเป็นเครื่องมือสร้างโปรไฟล์ฟังก์ชัน เครื่องมือสร้างโปรไฟล์ irqsoff และเครื่องมือสร้างโปรไฟล์ชั่วคราวที่ใช้ได้ เราขอย้ำว่า ขอแนะนําให้อ่านเอกสารประกอบเกี่ยวกับ ftrace ในหัวข้อเหล่านี้ก่อนใช้ เพราะมีพลังแต่มีความซับซ้อน irqsoff และ Preemptoff มีประโยชน์ในการยืนยันว่าผู้ขับขี่อาจมองข้ามหรือขัดจังหวะการทำงาน ปิดไปนานเกินไป
เครื่องมือสร้างโปรไฟล์ฟังก์ชันเป็นตัวเลือกที่ดีที่สุดสําหรับปัญหาด้านประสิทธิภาพและมักจะ ใช้เพื่อหาตำแหน่งที่เรียกใช้ฟังก์ชัน
หากข้อมูลจากเครื่องมือสร้างโปรไฟล์ฟังก์ชันไม่เจาะจงมากพอ คุณสามารถรวม
ftrace Trackpoints ด้วยเครื่องมือสร้างโปรไฟล์ฟังก์ชัน เหตุการณ์ ftrace สามารถเปิดใช้ได้ใน
ด้วยวิธีเดียวกันกับปกติ และจะแทรกสลับกับการติดตามของคุณ
ดีมากหากมีการนอนต่อเนื่องนานๆ ครั้งและไม่รบกวนในบางช่วงเวลา
ที่ต้องการแก้ไขข้อบกพร่อง: ตั้งค่าตัวกรอง ftrace เป็นฟังก์ชันที่ต้องการ
เปิดใช้จุดติดตาม
ให้ทำการติดตาม คุณแยกวิเคราะห์การติดตามที่ได้ได้ด้วย
trace2html
ค้นหาเหตุการณ์ที่ต้องการ แล้วรับสแต็กเทรซใกล้เคียง
ในการติดตามดิบ
ใช้ Lockstat
บางครั้ง ftrace อาจไม่เพียงพอ และคุณต้องแก้ไขข้อบกพร่องของสิ่งที่ดูเหมือนจะ
การช่วงชิงล็อกเคอร์เนล ยังมีตัวเลือกเคอร์เนลอีก 1 อย่างที่ควรลองใช้ ได้แก่
CONFIG_LOCK_STAT
ซึ่งเป็นทางเลือกสุดท้ายเพราะ
ทำงานบนอุปกรณ์ Android ได้ยากเพราะวิดีโอจะขยายขนาด
เคอร์เนลเกินกว่าที่อุปกรณ์ส่วนใหญ่สามารถจัดการได้
อย่างไรก็ตาม Lockstat จะใช้การแก้ไขข้อบกพร่อง
โครงสร้างพื้นฐานในการล็อก ซึ่งจะเป็นประโยชน์สำหรับแอปอื่นๆ อีกมากมาย ทุกคน
การเปิดอุปกรณ์ควรจะหาวิธีที่จะทำให้ตัวเลือกนั้นทำงานได้
บนอุปกรณ์ทุกชนิด เพราะจะมีเวลาที่คุณคิด
"หากฉันเปิด LOCK_STAT
ได้เพียงคนเดียว ฉันก็จะยืนยันหรือปฏิเสธการดำเนินการนี้ได้
เป็นปัญหาที่เกิดขึ้นใน 5 นาทีแทนที่จะเป็น 5 วัน"
หากคุณเปิดเครื่องเคอร์เนลด้วยตัวเลือกการกำหนดค่าได้ การติดตามล็อกจะคล้ายกับ ฟุตเรซ:
- เปิดใช้งานการติดตาม:
echo 1 > /proc/sys/kernel/lock_stat
- ทำการทดสอบ
- ปิดใช้การติดตาม:
echo 0 > /proc/sys/kernel/lock_stat
- ถ่ายโอนการติดตามของคุณ:
cat /proc/lock_stat > /data/local/tmp/lock_stat
หากต้องการความช่วยเหลือในการตีความผลลัพธ์ที่ได้รับ โปรดดูเอกสารประกอบของ Lockstat
ที่ <kernel>/Documentation/locking/lockstat.txt
ใช้จุดติดตามของผู้ให้บริการ
ใช้จุดติดตามอัปสตรีมก่อน แต่บางครั้งคุณอาจต้องใช้จุดติดตามของผู้ให้บริการ ดังนี้
{ "gfx", "Graphics", ATRACE_TAG_GRAPHICS, { { OPT, "events/mdss/enable" }, { OPT, "events/sde/enable" }, { OPT, "events/mali_systrace/enable" }, } },
จุดติดตามขยายได้ด้วยบริการ HAL ซึ่งจะช่วยให้คุณเพิ่มการติดตามเฉพาะอุปกรณ์ได้ คะแนน/หมวดหมู่ Tracepoints จะผสานรวมกับ Perfetto, atrace/systrace และระบบในอุปกรณ์ แอปการติดตาม
API สำหรับการใช้จุด/หมวดหมู่การติดตามมีดังนี้
- listCategory()สร้าง (หมวดหมู่ vec<TracingCategory>);
- เปิดหมวดหมู่(vec<string> หมวดหมู่) ที่สร้าง (สถานะสถานะ);
- disabledAllCategory() สร้าง (สถานะสถานะ);