eBPF/BCC کا استعمال کرتے ہوئے ہائی سیف لیٹینسی سے کرنل پیچ تک

eBPF/BCC کا استعمال کرتے ہوئے ہائی سیف لیٹینسی سے کرنل پیچ تک

لینکس کے پاس کرنل اور ایپلیکیشنز کو ڈیبگ کرنے کے لیے ٹولز کی ایک بڑی تعداد ہے۔ ان میں سے بیشتر کا اطلاق کی کارکردگی پر منفی اثر پڑتا ہے اور اسے پیداوار میں استعمال نہیں کیا جا سکتا۔

سال کے ایک جوڑے پہلے تھا ایک اور آلہ تیار کیا گیا ہے - ای بی پی ایف۔ یہ دانا اور صارف کی ایپلی کیشنز کو کم اوور ہیڈ کے ساتھ ٹریس کرنا اور پروگراموں کو دوبارہ بنانے اور دانا میں تھرڈ پارٹی ماڈیول لوڈ کرنے کی ضرورت کے بغیر ممکن بناتا ہے۔

پہلے سے ہی بہت ساری ایپلیکیشن یوٹیلیٹیز ہیں جو eBPF استعمال کرتی ہیں، اور اس آرٹیکل میں ہم دیکھیں گے کہ لائبریری کی بنیاد پر آپ کی اپنی پروفائلنگ یوٹیلیٹی کیسے لکھی جائے۔ PythonBCC. مضمون حقیقی واقعات پر مبنی ہے۔ ہم یہ بتانے کے لیے مسئلے سے حل کریں گے کہ مخصوص حالات میں موجودہ یوٹیلیٹیز کو کس طرح استعمال کیا جا سکتا ہے۔

سیف سست ہے۔

سیف کلسٹر میں ایک نیا میزبان شامل کیا گیا ہے۔ کچھ ڈیٹا کو اس میں منتقل کرنے کے بعد، ہم نے دیکھا کہ اس کے ذریعے تحریری درخواستوں پر کارروائی کی رفتار دوسرے سرورز کے مقابلے میں بہت کم تھی۔

eBPF/BCC کا استعمال کرتے ہوئے ہائی سیف لیٹینسی سے کرنل پیچ تک
دوسرے پلیٹ فارمز کے برعکس، اس میزبان نے bcache اور نئے linux 4.15 کرنل کا استعمال کیا۔ یہ پہلا موقع تھا جب اس ترتیب کا میزبان یہاں استعمال کیا گیا تھا۔ اور اس وقت یہ واضح تھا کہ مسئلے کی جڑ نظریاتی طور پر کچھ بھی ہو سکتی ہے۔

میزبان سے تفتیش کر رہا ہے۔

آئیے یہ دیکھ کر شروع کریں کہ سیف او ایس ڈی کے عمل کے اندر کیا ہوتا ہے۔ اس کے لیے ہم استعمال کریں گے۔ مکمل и فلیمسکوپ (مزید جس کے بارے میں آپ پڑھ سکتے ہیں۔ یہاں):

eBPF/BCC کا استعمال کرتے ہوئے ہائی سیف لیٹینسی سے کرنل پیچ تک
تصویر ہمیں بتاتی ہے کہ فنکشن fdatasync() فنکشنز کو درخواست بھیجنے میں کافی وقت گزارا۔ generic_make_request(). اس کا مطلب یہ ہے کہ ممکنہ طور پر مسائل کی وجہ خود osd ڈیمون سے باہر ہے۔ یہ یا تو دانا یا ڈسک ہو سکتا ہے۔ iostat آؤٹ پٹ نے bcache ڈسک کے ذریعہ درخواستوں پر کارروائی کرنے میں ایک اعلی تاخیر کا مظاہرہ کیا۔

میزبان کو چیک کرتے وقت، ہم نے پایا کہ systemd-udevd ڈیمون CPU وقت کی ایک بڑی مقدار استعمال کرتا ہے - کئی کوروں پر تقریباً 20%۔ یہ عجیب رویہ ہے، لہذا آپ کو اس کی وجہ جاننے کی ضرورت ہے۔ چونکہ Systemd-udevd uevents کے ساتھ کام کرتا ہے، ہم نے ان کو دیکھنے کا فیصلہ کیا۔ udevadm مانیٹر. یہ پتہ چلتا ہے کہ سسٹم میں ہر بلاک ڈیوائس کے لیے بڑی تعداد میں تبدیلی کے واقعات پیدا کیے گئے تھے۔ یہ بہت غیر معمولی ہے، لہذا ہمیں یہ دیکھنا پڑے گا کہ ان تمام واقعات کو کیا پیدا ہوتا ہے.

BCC ٹول کٹ کا استعمال

جیسا کہ ہم پہلے ہی جان چکے ہیں، دانا (اور سسٹم کال میں سیف ڈیمون) بہت زیادہ وقت گزارتا ہے۔ generic_make_request(). آئیے اس فنکشن کی رفتار کو ماپنے کی کوشش کرتے ہیں۔ میں BCC پہلے سے ہی ایک شاندار افادیت ہے - funclatency. ہم ڈیمون کو اس کے PID کے ذریعے آؤٹ پٹ کے درمیان 1 سیکنڈ کے وقفے کے ساتھ ٹریس کریں گے اور نتیجہ ملی سیکنڈ میں آؤٹ پٹ کریں گے۔

eBPF/BCC کا استعمال کرتے ہوئے ہائی سیف لیٹینسی سے کرنل پیچ تک
یہ خصوصیت عام طور پر تیزی سے کام کرتی ہے۔ یہ صرف یہ کرتا ہے کہ درخواست کو ڈیوائس ڈرائیور کی قطار میں منتقل کیا جائے۔

Bcache ایک پیچیدہ ڈیوائس ہے جو اصل میں تین ڈسکوں پر مشتمل ہے:

  • بیکنگ ڈیوائس (کیشڈ ڈسک)، اس معاملے میں یہ ایک سست HDD ہے۔
  • کیشنگ ڈیوائس (کیشنگ ڈسک)، یہاں یہ NVMe ڈیوائس کا ایک پارٹیشن ہے۔
  • bcache ورچوئل ڈیوائس جس کے ساتھ ایپلیکیشن چلتی ہے۔

ہم جانتے ہیں کہ درخواست کی ترسیل سست ہے، لیکن ان آلات میں سے کس کے لیے؟ ہم تھوڑی دیر بعد اس سے نمٹیں گے۔

اب ہم جانتے ہیں کہ euvents سے مسائل پیدا ہونے کا امکان ہے۔ ان کی نسل کی اصل وجہ کیا ہے اس کا پتہ لگانا اتنا آسان نہیں ہے۔ فرض کریں کہ یہ کوئی ایسا سافٹ ویئر ہے جو وقتاً فوقتاً لانچ کیا جاتا ہے۔ آئیے دیکھتے ہیں کہ اسکرپٹ کا استعمال کرتے ہوئے سسٹم پر کس قسم کا سافٹ ویئر چلتا ہے۔ 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 پر fio چلا کر، وقتاً فوقتاً udevadm ٹرگر چلا کر uevents بنانے کے لیے مسئلہ کو دوبارہ پیدا کرنے کی کوشش کی۔

بی سی سی پر مبنی ٹولز لکھنا

آئیے سب سے سست کالوں کو ٹریس اور ڈسپلے کرنے کے لیے ایک سادہ یوٹیلیٹی لکھنے کی کوشش کرتے ہیں۔ generic_make_request(). ہم اس ڈرائیو کے نام میں بھی دلچسپی رکھتے ہیں جس کے لیے یہ فنکشن بلایا گیا تھا۔

منصوبہ آسان ہے:

  • رجسٹر کریں۔ kprobe پر generic_make_request():
    • ہم ڈسک کا نام میموری میں محفوظ کرتے ہیں، فنکشن آرگومنٹ کے ذریعے قابل رسائی۔
    • ہم ٹائم اسٹیمپ کو بچاتے ہیں۔

  • رجسٹر کریں۔ kretprobe سے واپسی کے لیے generic_make_request():
    • ہمیں موجودہ ٹائم اسٹیمپ ملتا ہے؛
    • ہم محفوظ کردہ ٹائم اسٹیمپ تلاش کرتے ہیں اور اس کا موجودہ سے موازنہ کرتے ہیں۔
    • اگر نتیجہ مخصوص کردہ سے زیادہ ہے، تو ہم محفوظ شدہ ڈسک کا نام تلاش کرتے ہیں اور اسے ٹرمینل پر ڈسپلے کرتے ہیں۔

Kprobes и کریٹ پروبس فلائی پر فنکشن کوڈ کو تبدیل کرنے کے لیے بریک پوائنٹ میکانزم کا استعمال کریں۔ آپ پڑھ سکتے ہیں۔ دستاویزات и اچھا اس موضوع پر مضمون. اگر آپ مختلف افادیت کے کوڈ کو دیکھیں BCC، پھر آپ دیکھ سکتے ہیں کہ ان کی ایک جیسی ساخت ہے۔ لہذا اس مضمون میں ہم سکرپٹ کے دلائل کو پارس کرنا چھوڑ دیں گے اور خود BPF پروگرام کی طرف بڑھیں گے۔

python اسکرپٹ کے اندر eBPF متن اس طرح لگتا ہے:

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

افعال کے درمیان ڈیٹا کا تبادلہ کرنے کے لیے، eBPF پروگرام استعمال کرتے ہیں۔ ہیش میزیں. ہم بھی ایسا ہی کریں گے۔ ہم عمل 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، کلیدی قسم کے ساتھ u64 اور قسم کی قدر struct data_t. یہ میز ہمارے بی پی ایف پروگرام کے تناظر میں دستیاب ہوگا۔ BPF_PERF_OUTPUT میکرو ایک اور ٹیبل کو رجسٹر کرتا ہے جسے کہا جاتا ہے۔ واقعات، جس کے لیے استعمال کیا جاتا ہے۔ ڈیٹا ٹرانسمیشن صارف کی جگہ میں۔

کسی فنکشن کو کال کرنے اور اس سے واپس آنے کے درمیان، یا مختلف فنکشنز میں کال کے درمیان تاخیر کی پیمائش کرتے وقت، آپ کو اس بات کو مدنظر رکھنا ہوگا کہ موصول ہونے والے ڈیٹا کا تعلق اسی تناظر سے ہونا چاہیے۔ دوسرے الفاظ میں، آپ کو افعال کے ممکنہ متوازی آغاز کے بارے میں یاد رکھنے کی ضرورت ہے۔ ہمارے پاس ایک عمل کے تناظر میں فنکشن کو کال کرنے اور دوسرے عمل کے تناظر میں اس فنکشن سے واپس آنے کے درمیان تاخیر کی پیمائش کرنے کی صلاحیت ہے، لیکن یہ ممکنہ طور پر بیکار ہے۔ یہاں ایک اچھی مثال ہوگی۔ حیاتیاتی افادیت، جہاں ہیش ٹیبل کی کلید کو پوائنٹر پر سیٹ کیا گیا ہے۔ ساخت کی درخواست، جو ایک ڈسک کی درخواست کی عکاسی کرتا ہے۔

اگلا، ہمیں کوڈ لکھنے کی ضرورت ہے جو اس وقت چلے گا جب زیر مطالعہ فنکشن کو بلایا جائے گا:

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 اور ٹائم اسٹیمپ کا پتہ لگاتے ہیں، لیکن نئے ڈیٹا ڈھانچے کے لیے میموری مختص نہیں کرتے ہیں۔ اس کے بجائے، ہم کلید == موجودہ پی آئی ڈی کا استعمال کرتے ہوئے پہلے سے موجود ڈھانچے کے لیے ہیش ٹیبل تلاش کرتے ہیں۔ اگر ڈھانچہ مل جاتا ہے، تو ہم چلنے والے عمل کا نام تلاش کرتے ہیں اور اسے اس میں شامل کرتے ہیں.

ہم یہاں جو بائنری شفٹ استعمال کرتے ہیں وہ تھریڈ GID حاصل کرنے کے لیے درکار ہے۔ وہ مرکزی عمل کی پی آئی ڈی جس نے تھریڈ شروع کیا جس کے تناظر میں ہم کام کر رہے ہیں۔ فنکشن جسے ہم کہتے ہیں۔ bpf_get_current_pid_tgid() تھریڈ کی GID اور PID دونوں کو ایک ہی 64 بٹ ویلیو میں لوٹاتا ہے۔

ٹرمینل پر آؤٹ پٹ کرتے وقت، ہم فی الحال دھاگے میں دلچسپی نہیں رکھتے، لیکن ہم مرکزی عمل میں دلچسپی رکھتے ہیں۔ ایک دی گئی حد کے ساتھ نتیجے میں تاخیر کا موازنہ کرنے کے بعد، ہم اپنی ساخت کو پاس کرتے ہیں۔ اعداد و شمار ٹیبل کے ذریعے صارف کی جگہ میں واقعات، جس کے بعد ہم اندراج کو حذف کر دیتے ہیں۔ p.

python اسکرپٹ میں جو اس کوڈ کو لوڈ کرے گا، ہمیں MIN_US اور FACTOR کو تاخیر کی حد اور وقت کی اکائیوں سے تبدیل کرنے کی ضرورت ہے، جسے ہم دلائل سے گزریں گے:

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 پروگرام کے ذریعے تیار کرنے کی ضرورت ہے۔ بی پی ایف میکرو اور نمونے رجسٹر کریں:

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 کا استعمال کرتے ہوئے ہائی سیف لیٹینسی سے کرنل پیچ تک
آخرکار! اب ہم دیکھتے ہیں کہ جو چیز اسٹالنگ bcache ڈیوائس کی طرح نظر آتی ہے وہ دراصل ایک اسٹالنگ کال ہے۔ 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()، کاؤنٹر کو کم کرنا منجمد_گہرائی.

اب ہم حالات کو درست کرنے کے لیے کافی جانتے ہیں۔ 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

نیا تبصرہ شامل کریں