EBPF/BCC استعمال ڪندي هاءِ ڪيف ليٽيسي کان ڪرنل پيچ تائين

EBPF/BCC استعمال ڪندي هاءِ ڪيف ليٽيسي کان ڪرنل پيچ تائين

لينڪس وٽ وڏي تعداد ۾ اوزار آھن ڪنيل ۽ ايپليڪيشنن کي ڊيبگ ڪرڻ لاءِ. انھن مان گھڻا اپليڪيشن جي ڪارڪردگي تي منفي اثر آھن ۽ پيداوار ۾ استعمال نه ٿو ڪري سگهجي.

ٻه سال اڳ هو هڪ ٻيو اوزار تيار ڪيو ويو آهي - eBPF. اهو ممڪن بڻائي ٿو ته ڪنيل ۽ صارف ايپليڪيشنن کي گهٽ اوور هيڊ سان ٽريڪ ڪرڻ ۽ پروگرامن کي ٻيهر ٺاهڻ جي ضرورت کان سواءِ ۽ ٽئين پارٽي ماڊلز کي ڪرنل ۾ لوڊ ڪرڻ.

اڳ ۾ ئي ڪيتريون ئي ايپليڪيشن يوٽيلٽيون آهن جيڪي استعمال ڪن ٿيون eBPF، ۽ هن آرٽيڪل ۾ اسين ڏسنداسين ته ڪيئن لکجي توهان جي پنهنجي پروفائلنگ يوٽيلٽي کي لائبريري جي بنياد تي پٿون بي سي سي. مضمون حقيقي واقعن تي ٻڌل آهي. اسان مسئلي کان حل ڪنداسين ته ڏيکاريون ته موجوده افاديت ڪيئن مخصوص حالتن ۾ استعمال ڪري سگھجن ٿيون.

ڪيف سست آهي

هڪ نئون ميزبان شامل ڪيو ويو آهي سيف ڪلستر ۾. ان ۾ ڪجھ ڊيٽا لڏڻ کان پوء، اسان ڏٺو ته پروسيسنگ لکڻ جي درخواستن جي رفتار ٻين سرورن جي ڀيٽ ۾ تمام گھٽ ھئي.

EBPF/BCC استعمال ڪندي هاءِ ڪيف ليٽيسي کان ڪرنل پيچ تائين
ٻين پليٽ فارمن جي برعڪس، هي ميزبان استعمال ڪيو bcache ۽ نئين لينڪس 4.15 ڪنيل. هي پهريون ڀيرو هو جو هن ترتيب جو ميزبان هتي استعمال ڪيو ويو. ۽ ان وقت اها ڳالهه واضح هئي ته مسئلي جو جڙ نظرياتي طور ڪجهه به ٿي سگهي ٿو.

ميزبان جي تحقيق

اچو ته ڏسو ته سيف-او ايس ڊي جي عمل جي اندر ڇا ٿئي ٿو. ان لاءِ اسان استعمال ڪنداسين عجيب и فليم اسڪوپ (جنهن بابت وڌيڪ توهان پڙهي سگهو ٿا هتي):

EBPF/BCC استعمال ڪندي هاءِ ڪيف ليٽيسي کان ڪرنل پيچ تائين
تصوير اسان کي ٻڌائي ٿو ته فنڪشن fdatasync() ڪمن کي درخواست موڪلڻ ۾ گھڻو وقت گذريو generic_make_request(). هن جو مطلب اهو آهي ته گهڻو ڪري مسئلن جو سبب او ايس ڊي ڊيمن کان ٻاهر آهي. اهو ٿي سگهي ٿو ڪنيال يا ڊسڪ. آئيوسٽٽ آئوٽ بڪچ ڊسڪ پاران پروسيسنگ درخواستن ۾ هڪ اعلي ويڪرائي ڏيکاري ٿي.

جڏهن ميزبان کي چيڪ ڪيو، اسان اهو محسوس ڪيو ته سسٽم ڊي-يو ڊي ڊي ڊيمون سي پي يو جي وقت جي وڏي مقدار کي استعمال ڪري ٿو - ڪيترن ئي ڪور تي تقريبا 20٪. هي عجيب رويي آهي، تنهنڪري توهان کي ڳولڻ جي ضرورت آهي ڇو. جيئن ته Systemd-udevd uevents سان ڪم ڪري ٿو، اسان انهن کي ڏسڻ جو فيصلو ڪيو udevadm مانيٽر. اهو ظاهر ٿئي ٿو ته تبديلي جي واقعن جو هڪ وڏو تعداد سسٽم ۾ هر بلاڪ ڊوائيس لاء ٺاهي وئي. اهو بلڪل غير معمولي آهي، تنهنڪري اسان کي اهو ڏسڻو پوندو ته انهن سڀني واقعن کي ڇا پيدا ڪري ٿو.

BCC Toolkit استعمال ڪندي

جيئن ته اسان اڳ ۾ ئي ڳولي چڪا آهيون، ڪني (۽ سسٽم ڪال ۾ سيف ڊيمون) گهڻو وقت خرچ ڪري ٿو. generic_make_request(). اچو ته هن فنڪشن جي رفتار کي ماپڻ جي ڪوشش ڪريون. IN بي سي سي اتي اڳ ۾ ئي هڪ شاندار افاديت آهي - فنڪشنلٽي. اسان ڊيمون کي ان جي PID ذريعي 1 سيڪنڊ جي وقفي سان آئوٽ پُٽ جي وچ ۾ ڳولينداسين ۽ نتيجو مليس سيڪنڊن ۾ ڪڍنداسين.

EBPF/BCC استعمال ڪندي هاءِ ڪيف ليٽيسي کان ڪرنل پيچ تائين
هي مضمون عام طور تي جلدي ڪم ڪري ٿو. اهو سڀ ڪجهه ڪري ٿو درخواست کي ڊوائيس ڊرائيور قطار ڏانهن منتقل ڪري ٿو.

بيچ هڪ پيچيده ڊوائيس آهي جيڪو اصل ۾ ٽن ڊسڪ تي مشتمل آهي:

  • بيڪنگ ڊيوائس (ڪيش ٿيل ڊسڪ)، انهي صورت ۾ اهو هڪ سست HDD آهي؛
  • ڪيشنگ ڊيوائس (ڪيشنگ ڊسڪ)، ھتي ھي آھي NVMe ڊيوائس جو ھڪڙو ڀاڱو؛
  • bcache ورچوئل ڊيوائس جنهن سان ايپليڪيشن هلندي آهي.

اسان ڄاڻون ٿا ته درخواست ٽرانسميشن سست آهي، پر انهن مان ڪهڙي ڊوائيس لاء؟ اسان ان سان ٿوري دير بعد ڊيل ڪنداسين.

اسان هاڻي ڄاڻون ٿا ته ايونٽس مسئلا پيدا ڪرڻ جو امڪان آهي. اهو ڳولڻ بلڪل آسان ناهي ته انهن جي نسل جو ڪهڙو سبب آهي. اچو ته فرض ڪريو ته هي ڪجهه قسم جو سافٽ ويئر آهي جيڪو وقتي طور تي لانچ ڪيو ويندو آهي. اچو ته ڏسو ته اسڪرپٽ استعمال ڪندي سسٽم تي ڪهڙي قسم جو سافٽ ويئر هلندو آهي execsnoop ساڳئي کان بي سي سي يوٽيلٽي ڪٽ. اچو ته ان کي هلائي ۽ ٻاھر موڪليو فائل ڏانھن.

مثال طور هن طرح:

/usr/share/bcc/tools/execsnoop  | tee ./execdump

اسان هتي execsnoop جي مڪمل پيداوار نه ڏيکارينداسين، پر اسان جي دلچسپي جي هڪ قطار هن طرح نظر آئي:

sh 1764905 5802 0 sudo arcconf getconfig 1 AD | grep Temperature | awk -F '[:/]' '{print $2}' | sed 's/^ ([0-9]*) C.*/1/'

ٽيون ڪالم پروسيس جو PPID (والدين PID) آهي. PID 5802 سان عمل اسان جي مانيٽرنگ سسٽم جي سلسلي مان هڪ آهي. جڏهن مانيٽرنگ سسٽم جي ترتيب جي جانچ ڪندي، غلط پيرا ميٽر مليا ويا. HBA اڊاپٽر جو گرمي پد هر 30 سيڪنڊن ۾ ورتو ويو، جيڪو گهڻو ڪري ضرورت کان وڌيڪ آهي. چيڪ جي وقفي کي گهڻي وقت تائين تبديل ڪرڻ کان پوءِ، اسان ڏٺو ته هن ميزبان تي درخواست جي پروسيسنگ ويڪرائي ٻين ميزبانن جي مقابلي ۾ وڌيڪ نه رهي.

پر اهو اڃا تائين واضح ناهي ته bcache ڊوائيس ايترو سست ڇو هو. اسان هڪجهڙائي واري ترتيب سان هڪ ٽيسٽ پليٽ فارم تيار ڪيو ۽ ڪوشش ڪئي ته مسئلي کي ٻيهر پيدا ڪرڻ جي ذريعي فيو کي هلائيندي bcache تي، وقتي طور تي هلائيندڙ udevadm ٽرگر کي يووينٽس پيدا ڪرڻ لاءِ.

BCC تي ٻڌل اوزار لکڻ

اچو ته هڪ سادي افاديت لکڻ جي ڪوشش ڪريون ۽ سست ترين ڪالن کي ظاهر ڪرڻ لاءِ generic_make_request(). اسان کي ڊرائيو جي نالي ۾ پڻ دلچسپي آهي جنهن لاء هن فنڪشن کي سڏيو ويو هو.

منصوبو سادو آهي:

  • رجسٽر kprobe تي generic_make_request():
    • اسان ڊسڪ جو نالو ميموري ۾ محفوظ ڪريون ٿا، فنڪشنل آرگيومينٽ ذريعي رسائي لائق؛
    • اسان ٽائم اسٽيمپ بچايو.

  • رجسٽر kretprobe کان واپسي لاء generic_make_request():
    • اسان کي موجوده timestamp حاصل;
    • اسان محفوظ ٿيل ٽائم اسٽيمپ ڳوليندا آهيون ۽ ان جو موجوده وقت سان مقابلو ڪندا آهيون.
    • جيڪڏهن نتيجو بيان ڪيل هڪ کان وڌيڪ آهي، ته پوء اسان محفوظ ڪيل ڊسڪ جو نالو ڳوليندا آهيون ۽ ان کي ٽرمينل تي ڏيکاري ٿو.

Kprobes и kretprobes فلائي تي فنڪشن ڪوڊ تبديل ڪرڻ لاءِ بريڪ پوائنٽ ميڪانيزم استعمال ڪريو. توهان پڙهي سگهو ٿا دستاويز и سٺو هن موضوع تي مضمون. جيڪڏھن توھان ڏسو مختلف يوٽيلٽيز جي ڪوڊ ۾ بي سي سي، پوءِ توهان ڏسي سگهو ٿا ته انهن جي هڪجهڙائي آهي. تنهن ڪري هن آرٽيڪل ۾ اسين اسڪرپٽ دليلن کي پارس ڪرڻ کي ڇڏي ڏينداسين ۽ پاڻ کي BPF پروگرام ڏانهن منتقل ڪنداسين.

پٿون اسڪرپٽ اندر eBPF متن هن طرح ڏسڻ ۾ اچي ٿو:

bpf_text = “”” # Here will be the bpf program code “””

ڪمن جي وچ ۾ ڊيٽا مٽائڻ لاء، اي بي پي ايف پروگرام استعمال ڪن ٿا hash ٽيبل. اسان به ائين ئي ڪنداسين. اسان پروسيس PID کي ڪيئي طور استعمال ڪنداسين، ۽ ساخت کي قدر جي طور تي بيان ڪنداسين:

struct data_t {
	u64 pid;
	u64 ts;
	char comm[TASK_COMM_LEN];
	u64 lat;
	char disk[DISK_NAME_LEN];
};

BPF_HASH(p, u64, struct data_t);
BPF_PERF_OUTPUT(events);

هتي اسان رجسٽر ڪريون ٿا هيش ٽيبل نالي p، اهم قسم سان اوڪس اينيمڪس ۽ قسم جو قدر struct data_t. ٽيبل اسان جي BPF پروگرام جي حوالي سان دستياب ٿي ويندي. BPF_PERF_OUTPUT ميڪرو هڪ ٻي ٽيبل رجسٽر ڪري ٿو جنهن کي سڏيو ويندو آهي ڏينهن، جنهن لاءِ استعمال ڪيو ويندو آهي ڊيٽا جي منتقلي استعمال ڪندڙ خلا ۾.

جڏهن ڪنهن فنڪشن کي ڪال ڪرڻ ۽ ان مان موٽڻ جي وچ ۾ دير کي ماپڻ، يا مختلف ڪمن جي ڪالن جي وچ ۾، توهان کي اهو خيال رکڻو پوندو ته موصول ٿيل ڊيٽا جو تعلق ساڳيو ئي حوالي سان هجڻ گهرجي. ٻين لفظن ۾، توهان کي ياد رکڻ جي ضرورت آهي ڪم جي ممڪن متوازي لانچ بابت. اسان وٽ هڪ عمل جي سلسلي ۾ هڪ فنڪشن کي سڏڻ ۽ ٻئي عمل جي حوالي سان انهي فنڪشن مان واپسي جي وچ ۾ دير جي ماپ ڪرڻ جي صلاحيت آهي، پر اهو ممڪن آهي بيڪار. هتي هڪ سٺو مثال هوندو حياتياتي افاديت، جتي hash table key مقرر ڪئي وئي آهي هڪ پوائنٽر ڏانهن struct درخواست، جيڪو هڪ ڊسڪ جي درخواست کي ظاهر ڪري ٿو.

اڳيون، اسان کي اهو ڪوڊ لکڻو پوندو جيڪو هلندو جڏهن مطالعي هيٺ فنڪشن سڏيو ويندو آهي:

void start(struct pt_regs *ctx, struct bio *bio) {
	u64 pid = bpf_get_current_pid_tgid();
	struct data_t data = {};
	u64 ts = bpf_ktime_get_ns();
	data.pid = pid;
	data.ts = ts;
	bpf_probe_read_str(&data.disk, sizeof(data.disk), (void*)bio->bi_disk->disk_name);
	p.update(&pid, &data);
}

هتي سڏايل فنڪشن جو پهريون دليل ٻئي دليل طور متبادل ڪيو ويندو generic_make_request(). ان کان پوء، اسان پروسيس جي PID حاصل ڪندا آهيون جنهن جي حوالي سان اسان ڪم ڪري رهيا آهيون، ۽ موجوده ٽائيم اسٽيمپ نانو سيڪنڊن ۾. اسان اهو سڀ ڪجهه تازو چونڊيل ۾ لکندا آهيون struct data_t ڊيٽا. اسان ڊسڪ جو نالو ڍانچي مان حاصل ڪندا آهيون بايو، جيڪو سڏڻ وقت گذري ويو generic_make_request()، ۽ ان کي محفوظ ڪريو ساڳئي ڍانچي ۾ ڊيٽا. آخري قدم هيش ٽيبل تي هڪ داخلا شامل ڪرڻ آهي جيڪو اڳ ذڪر ڪيو ويو آهي.

واپسي تي هيٺين فنڪشن کي سڏيو ويندو generic_make_request():

void stop(struct pt_regs *ctx) {
    u64 pid = bpf_get_current_pid_tgid();
    u64 ts = bpf_ktime_get_ns();
    struct data_t* data = p.lookup(&pid);
    if (data != 0 && data->ts > 0) {
        bpf_get_current_comm(&data->comm, sizeof(data->comm));
        data->lat = (ts - data->ts)/1000;
        if (data->lat > MIN_US) {
            FACTOR
            data->pid >>= 32;
            events.perf_submit(ctx, data, sizeof(struct data_t));
        }
        p.delete(&pid);
    }
}

هي فنڪشن پوئين هڪ سان ملندڙ جلندڙ آهي: اسان پروسيس جي PID ۽ ٽائم اسٽيمپ کي ڳوليندا آهيون، پر نئين ڊيٽا جي جوڙجڪ لاء ميموري مختص نه ڪندا آهيون. ان جي بدران، اسان اڳ ۾ ئي موجود ڍانچي لاءِ هيش ٽيبل ڳوليندا آهيون key == موجوده PID استعمال ڪندي. جيڪڏهن ساخت ملي ٿي، ته پوءِ اسان رننگ پروسيس جو نالو ڳوليون ۽ ان ۾ شامل ڪريون.

بائنري شفٽ اسان هتي استعمال ڪريون ٿا ٿريڊ GID حاصل ڪرڻ لاءِ. اهي. مکيه عمل جي PID جنهن سلسلي ۾ شروع ڪيو جنهن جي حوالي سان اسان ڪم ڪري رهيا آهن. فنڪشن جنهن کي اسان سڏين ٿا bpf_get_current_pid_tgid() ٿريڊ جي GID ۽ ان جي PID کي ھڪڙي ھڪڙي 64-bit قدر ۾ واپس ڏئي ٿو.

جڏهن ٽرمينل ڏانهن نڪرڻ، اسان في الحال موضوع ۾ دلچسپي نه ٿا رکون، پر اسان بنيادي عمل ۾ دلچسپي رکون ٿا. ھڪڙي ڏنل حد سان نتيجن جي دير جي مقابلي کان پوء، اسان پنھنجي جوڙجڪ کي پاس ڪريون ٿا ڊيٽا ٽيبل ذريعي استعمال ڪندڙ خلا ۾ ڏينهن، جنهن کان پوءِ اسان داخلا کي حذف ڪريون ٿا p.

پٿون اسڪرپٽ ۾ جيڪو هن ڪوڊ کي لوڊ ڪندو، اسان کي MIN_US ۽ فيڪٽر کي دير جي حدن ۽ وقت جي يونٽن سان تبديل ڪرڻ جي ضرورت آهي، جنهن کي اسين دليلن مان گذرنداسين:

bpf_text = bpf_text.replace('MIN_US',str(min_usec))
if args.milliseconds:
	bpf_text = bpf_text.replace('FACTOR','data->lat /= 1000;')
	label = "msec"
else:
	bpf_text = bpf_text.replace('FACTOR','')
	label = "usec"

هاڻي اسان کي تيار ڪرڻ جي ضرورت آهي BPF پروگرام ذريعي BPF ميڪرو ۽ نموني رجسٽر ڪريو:

b = BPF(text=bpf_text)
b.attach_kprobe(event="generic_make_request",fn_name="start")
b.attach_kretprobe(event="generic_make_request",fn_name="stop")

اسان کي به طئي ڪرڻو پوندو struct data_t اسان جي اسڪرپٽ ۾، ٻي صورت ۾ اسان ڪجھ به نه پڙهي سگهنداسين:

TASK_COMM_LEN = 16	# linux/sched.h
DISK_NAME_LEN = 32	# linux/genhd.h
class Data(ct.Structure):
	_fields_ = [("pid", ct.c_ulonglong),
            	("ts", ct.c_ulonglong),
            	("comm", ct.c_char * TASK_COMM_LEN),
            	("lat", ct.c_ulonglong),
            	("disk",ct.c_char * DISK_NAME_LEN)]

آخري قدم آھي ٻاھر ڪڍڻ واري ڊيٽا کي ٽرمينل ڏانھن:

def print_event(cpu, data, size):
    global start
    event = ct.cast(data, ct.POINTER(Data)).contents
    if start == 0:
        start = event.ts
    time_s = (float(event.ts - start)) / 1000000000
    print("%-18.9f %-16s %-6d   %-1s %s   %s" % (time_s, event.comm, event.pid, event.lat, label, event.disk))

b["events"].open_perf_buffer(print_event)
# format output
start = 0
while 1:
    try:
        b.perf_buffer_poll()
    except KeyboardInterrupt:
        exit()

رسم الخط پاڻ وٽ موجود آهي GITHub. اچو ته ان کي آزمائشي پليٽ فارم تي هلائڻ جي ڪوشش ڪريو جتي fio هلندڙ آهي، bcache ڏانهن لکڻ، ۽ udevadm مانيٽر کي ڪال ڪريو:

EBPF/BCC استعمال ڪندي هاءِ ڪيف ليٽيسي کان ڪرنل پيچ تائين
آخرڪار! هاڻي اسان ڏسون ٿا ته جيڪو ڏسڻ ۾ اچي ٿو هڪ اسٽالنگ بيڪيچ ڊوائيس اصل ۾ هڪ اسٽالنگ ڪال آهي generic_make_request() ڪيش ٿيل ڊسڪ لاءِ.

ڪرنل ۾ کڙو ڪريو

درخواست جي منتقلي دوران ڇا واقعي سست ٿي رهيو آهي؟ اسان ڏسون ٿا ته دير ٿئي ٿي ان کان اڳ جو حساب ڪتاب جي درخواست جي شروعات کان اڳ، يعني. ان تي شماريات جي وڌيڪ پيداوار لاءِ مخصوص درخواست جو حساب ڪتاب (/proc/diskstats يا iostat) اڃا شروع نه ٿيو آهي. اهو آساني سان تصديق ڪري سگهجي ٿو iostat هلائڻ دوران مسئلو ٻيهر پيدا ڪرڻ، يا بي سي سي اسڪرپٽ بايوليٽيسي, جيڪو درخواست جي حساب جي شروعات ۽ پڇاڙي تي ٻڌل آهي. انهن مان ڪو به افاديت نه ڏيکاريندو ته ڪيش ٿيل ڊسڪ جي درخواستن لاءِ مسئلا.

جيڪڏهن اسان فنڪشن کي ڏسو generic_make_request()، پوءِ اسان ڏسنداسين ته درخواست جي اڪائونٽنگ شروع ٿيڻ کان اڳ، ٻه وڌيڪ افعال سڏبا آهن. پهريون - generic_make_request_checks()، ڊسڪ سيٽنگن جي حوالي سان درخواست جي مشروعيت تي چيڪ ڪري ٿو. ٻيون - blk_queue_enter()، جنهن ۾ هڪ دلچسپ چئلينج آهي انتظار_واقعي_انٽرپٽيبل():

ret = wait_event_interruptible(q->mq_freeze_wq,
	(atomic_read(&q->mq_freeze_depth) == 0 &&
	(preempt || !blk_queue_preempt_only(q))) ||
	blk_queue_dying(q));

ان ۾، ڪنييل قطار کي اڻڄاتل ڪرڻ لاء انتظار ڪري ٿو. اچو ته دير جو اندازو لڳايو blk_queue_enter():

~# /usr/share/bcc/tools/funclatency  blk_queue_enter -i 1 -m               	 
Tracing 1 functions for "blk_queue_enter"... Hit Ctrl-C to end.

 	msecs           	: count 	distribution
     	0 -> 1      	: 341  	|****************************************|

 	msecs           	: count 	distribution
     	0 -> 1      	: 316  	|****************************************|

 	msecs           	: count 	distribution
     	0 -> 1      	: 255  	|****************************************|
     	2 -> 3      	: 0    	|                                    	|
     	4 -> 7      	: 0    	|                                    	|
     	8 -> 15     	: 1    	|                                    	|

اهو لڳي ٿو ته اسان هڪ حل جي ويجهو آهيون. هڪ قطار کي منجمد / غير منجمد ڪرڻ لاء استعمال ٿيل فنڪشن آهن blk_mq_freeze_queue и blk_mq_unfreeze_queue. اهي استعمال ڪيا ويندا آهن جڏهن ضروري هجي ته درخواست جي قطار سيٽنگن کي تبديل ڪرڻ لاء، جيڪي ممڪن طور تي هن قطار ۾ درخواستن لاء خطرناڪ آهن. جڏهن سڏڻ blk_mq_freeze_queue() فنڪشن blk_freeze_queue_start() انسداد وڌايو ويو آهي q->mq_freeze_depth. ان کان پوء، ڪرنل قطار ۾ خالي ٿيڻ لاء انتظار ڪري ٿو blk_mq_freeze_queue_wait().

هن قطار کي صاف ڪرڻ ۾ جيڪو وقت لڳندو آهي اهو ڊسڪ ليٽيسي جي برابر هوندو آهي جيئن ڪنيل سڀني قطار جي عملن جي مڪمل ٿيڻ جو انتظار ڪري. هڪ دفعو قطار خالي آهي، سيٽنگون تبديليون لاڳو ٿينديون آهن. جنهن کان پوء ان کي سڏيو ويندو آهي blk_mq_unfreeze_queue()، ڪائونٽر کي گهٽائڻ freeze_depth.

هاڻي اسان صورتحال کي درست ڪرڻ لاء ڪافي ڄاڻون ٿا. udevadm ٽرگر ڪمانڊ بلاڪ ڊيوائس لاءِ سيٽنگون لاڳو ڪري ٿي. اهي سيٽنگون udev قاعدن ۾ بيان ڪيون ويون آهن. اسان ڳولي سگھون ٿا ته ڪھڙي سيٽنگون قطار کي منجمد ڪري رھيا آھن انھن کي sysfs ذريعي تبديل ڪرڻ جي ڪوشش ڪندي يا ڪنيل سورس ڪوڊ کي ڏسڻ سان. اسان پڻ ڪوشش ڪري سگھون ٿا BCC افاديت ٽڪر، جيڪو ٽرمينل تي هر ڪال لاءِ ڪرنل ۽ يوزر اسپيس اسٽيڪ جا نشان ڪڍي ڇڏيندو blk_freeze_queueمثال طور

~# /usr/share/bcc/tools/trace blk_freeze_queue -K -U
PID 	TID 	COMM        	FUNC        	 
3809642 3809642 systemd-udevd   blk_freeze_queue
    	blk_freeze_queue+0x1 [kernel]
    	elevator_switch+0x29 [kernel]
    	elv_iosched_store+0x197 [kernel]
    	queue_attr_store+0x5c [kernel]
    	sysfs_kf_write+0x3c [kernel]
    	kernfs_fop_write+0x125 [kernel]
    	__vfs_write+0x1b [kernel]
    	vfs_write+0xb8 [kernel]
    	sys_write+0x55 [kernel]
    	do_syscall_64+0x73 [kernel]
    	entry_SYSCALL_64_after_hwframe+0x3d [kernel]
    	__write_nocancel+0x7 [libc-2.23.so]
    	[unknown]

3809631 3809631 systemd-udevd   blk_freeze_queue
    	blk_freeze_queue+0x1 [kernel]
    	queue_requests_store+0xb6 [kernel]
    	queue_attr_store+0x5c [kernel]
    	sysfs_kf_write+0x3c [kernel]
    	kernfs_fop_write+0x125 [kernel]
    	__vfs_write+0x1b [kernel]
    	vfs_write+0xb8 [kernel]
    	sys_write+0x55 [kernel]
    	do_syscall_64+0x73 [kernel]
    	entry_SYSCALL_64_after_hwframe+0x3d [kernel]
    	__write_nocancel+0x7 [libc-2.23.so]
    	[unknown]

Udev ضابطا تمام گهٽ تبديل ٿيندا آهن ۽ عام طور تي اهو ڪنٽرول انداز ۾ ٿئي ٿو. تنهن ڪري اسان ڏسون ٿا ته اڳ ۾ ئي مقرر ڪيل قدرن کي لاڳو ڪرڻ سبب ايپليڪيشن کان ڊسڪ ڏانهن درخواست جي منتقلي ۾ دير ۾ اضافو ٿئي ٿو. يقينا، udev واقعا پيدا ڪرڻ جڏهن ڊسڪ جي ترتيب ۾ ڪا به تبديلي نه آهي (مثال طور، ڊوائيس نصب نه آهي/منقطع ٿيل آهي) سٺو عمل ناهي. بهرحال، اسان مدد ڪري سگھون ٿا ڪنيل کي غير ضروري ڪم نه ڪرڻ ۽ درخواست جي قطار کي منجمد ڪرڻ جي صورت ۾ ضروري نه آهي. ٽي ننڍو انجام ڏيڻ صورتحال کي درست ڪريو.

ٿڪل

eBPF هڪ تمام لچڪدار ۽ طاقتور اوزار آهي. مضمون ۾ اسان هڪ عملي صورت ۾ ڏٺو ۽ ڏيکاري ٿو ته ڇا ڪري سگهجي ٿو جو هڪ ننڍڙو حصو. جيڪڏهن توهان BCC افاديت کي ترقي ڪرڻ ۾ دلچسپي رکو ٿا، اهو هڪ نظر وٺڻ جي قابل آهي سرڪاري سبق، جيڪو بنيادي ڳالهين کي چڱي طرح بيان ڪري ٿو.

اي بي پي ايف جي بنياد تي ٻيا دلچسپ ڊيبگنگ ۽ پروفائلنگ جا اوزار آھن. انهن مان هڪ - bpftrace، جيڪو توهان کي awk-جهڙي ٻولي ۾ طاقتور ون-لائنرز ۽ ننڍا پروگرام لکڻ جي اجازت ڏئي ٿو. ٻيو - ebpf_exporter، توهان کي اجازت ڏئي ٿو گهٽ-سطح، اعليٰ ريزوليوشن ميٽرڪس سڌو سنئون توهان جي پروميٿيوس سرور ۾، جنهن سان بعد ۾ خوبصورت تصويرون ۽ ايستائين جو الرٽ حاصل ڪرڻ جي صلاحيت سان.

جو ذريعو: www.habr.com

تبصرو شامل ڪريو