Linux ಕರ್ನಲ್ ಮತ್ತು ಅಪ್ಲಿಕೇಶನ್ಗಳನ್ನು ಡೀಬಗ್ ಮಾಡಲು ಹೆಚ್ಚಿನ ಸಂಖ್ಯೆಯ ಸಾಧನಗಳನ್ನು ಹೊಂದಿದೆ. ಅವುಗಳಲ್ಲಿ ಹೆಚ್ಚಿನವು ಅಪ್ಲಿಕೇಶನ್ ಕಾರ್ಯಕ್ಷಮತೆಯ ಮೇಲೆ ನಕಾರಾತ್ಮಕ ಪರಿಣಾಮ ಬೀರುತ್ತವೆ ಮತ್ತು ಉತ್ಪಾದನೆಯಲ್ಲಿ ಬಳಸಲಾಗುವುದಿಲ್ಲ.
ಒಂದೆರಡು ವರ್ಷಗಳ ಹಿಂದೆ ಇತ್ತು
eBPF ಅನ್ನು ಬಳಸುವ ಅನೇಕ ಅಪ್ಲಿಕೇಶನ್ ಉಪಯುಕ್ತತೆಗಳು ಈಗಾಗಲೇ ಇವೆ, ಮತ್ತು ಈ ಲೇಖನದಲ್ಲಿ ನಾವು ಲೈಬ್ರರಿಯ ಆಧಾರದ ಮೇಲೆ ನಿಮ್ಮ ಸ್ವಂತ ಪ್ರೊಫೈಲಿಂಗ್ ಉಪಯುಕ್ತತೆಯನ್ನು ಹೇಗೆ ಬರೆಯಬೇಕೆಂದು ನೋಡೋಣ.
ಸೆಫ್ ನಿಧಾನ
Ceph ಕ್ಲಸ್ಟರ್ಗೆ ಹೊಸ ಹೋಸ್ಟ್ ಅನ್ನು ಸೇರಿಸಲಾಗಿದೆ. ಕೆಲವು ಡೇಟಾವನ್ನು ಅದಕ್ಕೆ ಸ್ಥಳಾಂತರಿಸಿದ ನಂತರ, ಅದರ ಮೂಲಕ ಬರೆಯುವ ವಿನಂತಿಗಳನ್ನು ಪ್ರಕ್ರಿಯೆಗೊಳಿಸುವ ವೇಗವು ಇತರ ಸರ್ವರ್ಗಳಿಗಿಂತ ಕಡಿಮೆಯಾಗಿದೆ ಎಂದು ನಾವು ಗಮನಿಸಿದ್ದೇವೆ.
ಇತರ ಪ್ಲಾಟ್ಫಾರ್ಮ್ಗಳಿಗಿಂತ ಭಿನ್ನವಾಗಿ, ಈ ಹೋಸ್ಟ್ bcache ಮತ್ತು ಹೊಸ ಲಿನಕ್ಸ್ 4.15 ಕರ್ನಲ್ ಅನ್ನು ಬಳಸಿದೆ. ಈ ಕಾನ್ಫಿಗರೇಶನ್ನ ಹೋಸ್ಟ್ ಅನ್ನು ಇಲ್ಲಿ ಬಳಸಿರುವುದು ಇದೇ ಮೊದಲು. ಮತ್ತು ಆ ಕ್ಷಣದಲ್ಲಿ ಸಮಸ್ಯೆಯ ಮೂಲವು ಸೈದ್ಧಾಂತಿಕವಾಗಿ ಯಾವುದಾದರೂ ಆಗಿರಬಹುದು ಎಂದು ಸ್ಪಷ್ಟವಾಯಿತು.
ಹೋಸ್ಟ್ ಅನ್ನು ತನಿಖೆ ಮಾಡಲಾಗುತ್ತಿದೆ
ceph-osd ಪ್ರಕ್ರಿಯೆಯಲ್ಲಿ ಏನಾಗುತ್ತದೆ ಎಂಬುದನ್ನು ನೋಡುವ ಮೂಲಕ ಪ್ರಾರಂಭಿಸೋಣ. ಇದಕ್ಕಾಗಿ ನಾವು ಬಳಸುತ್ತೇವೆ
ಚಿತ್ರವು ಕಾರ್ಯವನ್ನು ನಮಗೆ ಹೇಳುತ್ತದೆ fdatasync() ಕಾರ್ಯಗಳಿಗೆ ವಿನಂತಿಯನ್ನು ಕಳುಹಿಸಲು ಸಾಕಷ್ಟು ಸಮಯವನ್ನು ಕಳೆದರು generic_make_request(). ಇದರರ್ಥ ಸಮಸ್ಯೆಗಳ ಕಾರಣವು osd ಡೀಮನ್ನ ಹೊರಗೆ ಎಲ್ಲೋ ಇರುತ್ತದೆ. ಇದು ಕರ್ನಲ್ ಅಥವಾ ಡಿಸ್ಕ್ ಆಗಿರಬಹುದು. iostat ಔಟ್ಪುಟ್ bcache ಡಿಸ್ಕ್ಗಳಿಂದ ವಿನಂತಿಗಳನ್ನು ಪ್ರಕ್ರಿಯೆಗೊಳಿಸುವಲ್ಲಿ ಹೆಚ್ಚಿನ ಸುಪ್ತತೆಯನ್ನು ತೋರಿಸಿದೆ.
ಹೋಸ್ಟ್ ಅನ್ನು ಪರಿಶೀಲಿಸುವಾಗ, systemd-udevd ಡೀಮನ್ ಹೆಚ್ಚಿನ ಪ್ರಮಾಣದ CPU ಸಮಯವನ್ನು ಬಳಸುತ್ತದೆ ಎಂದು ನಾವು ಕಂಡುಕೊಂಡಿದ್ದೇವೆ - ಹಲವಾರು ಕೋರ್ಗಳಲ್ಲಿ ಸುಮಾರು 20%. ಇದು ವಿಚಿತ್ರ ವರ್ತನೆ, ಆದ್ದರಿಂದ ನೀವು ಏಕೆ ಕಂಡುಹಿಡಿಯಬೇಕು. Systemd-udevd ಯುವೆಂಟ್ಗಳೊಂದಿಗೆ ಕಾರ್ಯನಿರ್ವಹಿಸುವುದರಿಂದ, ನಾವು ಅವುಗಳನ್ನು ನೋಡಲು ನಿರ್ಧರಿಸಿದ್ದೇವೆ udevadm ಮಾನಿಟರ್. ವ್ಯವಸ್ಥೆಯಲ್ಲಿನ ಪ್ರತಿ ಬ್ಲಾಕ್ ಸಾಧನಕ್ಕಾಗಿ ಹೆಚ್ಚಿನ ಸಂಖ್ಯೆಯ ಬದಲಾವಣೆಯ ಘಟನೆಗಳನ್ನು ರಚಿಸಲಾಗಿದೆ ಎಂದು ಅದು ತಿರುಗುತ್ತದೆ. ಇದು ತುಂಬಾ ಅಸಾಮಾನ್ಯವಾಗಿದೆ, ಆದ್ದರಿಂದ ಈ ಎಲ್ಲಾ ಘಟನೆಗಳನ್ನು ಏನು ಸೃಷ್ಟಿಸುತ್ತದೆ ಎಂಬುದನ್ನು ನಾವು ನೋಡಬೇಕಾಗಿದೆ.
BCC ಟೂಲ್ಕಿಟ್ ಅನ್ನು ಬಳಸುವುದು
ನಾವು ಈಗಾಗಲೇ ಕಂಡುಕೊಂಡಂತೆ, ಕರ್ನಲ್ (ಮತ್ತು ಸಿಸ್ಟಮ್ ಕರೆಯಲ್ಲಿನ ಸೆಫ್ ಡೀಮನ್) ಬಹಳಷ್ಟು ಸಮಯವನ್ನು ಕಳೆಯುತ್ತದೆ generic_make_request(). ಈ ಕಾರ್ಯದ ವೇಗವನ್ನು ಅಳೆಯಲು ಪ್ರಯತ್ನಿಸೋಣ. IN
ಈ ವೈಶಿಷ್ಟ್ಯವು ಸಾಮಾನ್ಯವಾಗಿ ತ್ವರಿತವಾಗಿ ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತದೆ. ಡಿವೈಸ್ ಡ್ರೈವರ್ ಕ್ಯೂಗೆ ವಿನಂತಿಯನ್ನು ರವಾನಿಸುವುದು ಮಾತ್ರ ಅದು ಮಾಡುತ್ತದೆ.
Bcache ವಾಸ್ತವವಾಗಿ ಮೂರು ಡಿಸ್ಕ್ಗಳನ್ನು ಒಳಗೊಂಡಿರುವ ಒಂದು ಸಂಕೀರ್ಣ ಸಾಧನವಾಗಿದೆ:
- ಬ್ಯಾಕಿಂಗ್ ಸಾಧನ (ಕ್ಯಾಶ್ಡ್ ಡಿಸ್ಕ್), ಈ ಸಂದರ್ಭದಲ್ಲಿ ಇದು ನಿಧಾನವಾದ 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 ನಲ್ಲಿ fio ರನ್ ಮಾಡುವ ಮೂಲಕ ಸಮಸ್ಯೆಯನ್ನು ಪುನರುತ್ಪಾದಿಸಲು ಪ್ರಯತ್ನಿಸಿದ್ದೇವೆ, ಯೂವೆಂಟ್ಗಳನ್ನು ಉತ್ಪಾದಿಸಲು udevadm ಟ್ರಿಗ್ಗರ್ ಅನ್ನು ನಿಯತಕಾಲಿಕವಾಗಿ ಚಾಲನೆ ಮಾಡುತ್ತಿದ್ದೇವೆ.
BCC-ಆಧಾರಿತ ಪರಿಕರಗಳನ್ನು ಬರೆಯುವುದು
ನಿಧಾನವಾದ ಕರೆಗಳನ್ನು ಪತ್ತೆಹಚ್ಚಲು ಮತ್ತು ಪ್ರದರ್ಶಿಸಲು ಸರಳವಾದ ಉಪಯುಕ್ತತೆಯನ್ನು ಬರೆಯಲು ಪ್ರಯತ್ನಿಸೋಣ generic_make_request(). ಈ ಕಾರ್ಯವನ್ನು ಕರೆಯಲಾದ ಡ್ರೈವ್ನ ಹೆಸರಿನಲ್ಲಿ ನಾವು ಆಸಕ್ತಿ ಹೊಂದಿದ್ದೇವೆ.
ಯೋಜನೆ ಸರಳವಾಗಿದೆ:
- ನೋಂದಣಿ kprobe ಮೇಲೆ generic_make_request():
- ನಾವು ಡಿಸ್ಕ್ ಹೆಸರನ್ನು ಮೆಮೊರಿಗೆ ಉಳಿಸುತ್ತೇವೆ, ಫಂಕ್ಷನ್ ಆರ್ಗ್ಯುಮೆಂಟ್ ಮೂಲಕ ಪ್ರವೇಶಿಸಬಹುದು;
- ನಾವು ಟೈಮ್ಸ್ಟ್ಯಾಂಪ್ ಅನ್ನು ಉಳಿಸುತ್ತೇವೆ.
- ನೋಂದಣಿ kretprobe ನಿಂದ ಹಿಂತಿರುಗಲು generic_make_request():
- ನಾವು ಪ್ರಸ್ತುತ ಟೈಮ್ಸ್ಟ್ಯಾಂಪ್ ಅನ್ನು ಪಡೆಯುತ್ತೇವೆ;
- ನಾವು ಉಳಿಸಿದ ಟೈಮ್ಸ್ಟ್ಯಾಂಪ್ಗಾಗಿ ನೋಡುತ್ತೇವೆ ಮತ್ತು ಅದನ್ನು ಪ್ರಸ್ತುತದ ಜೊತೆಗೆ ಹೋಲಿಕೆ ಮಾಡುತ್ತೇವೆ;
- ಫಲಿತಾಂಶವು ನಿರ್ದಿಷ್ಟಪಡಿಸಿದ ಒಂದಕ್ಕಿಂತ ಹೆಚ್ಚಿದ್ದರೆ, ನಾವು ಉಳಿಸಿದ ಡಿಸ್ಕ್ ಹೆಸರನ್ನು ಕಂಡುಹಿಡಿಯುತ್ತೇವೆ ಮತ್ತು ಅದನ್ನು ಟರ್ಮಿನಲ್ನಲ್ಲಿ ಪ್ರದರ್ಶಿಸುತ್ತೇವೆ.
Kprobes и kretprobes ಫ್ಲೈನಲ್ಲಿ ಫಂಕ್ಷನ್ ಕೋಡ್ ಅನ್ನು ಬದಲಾಯಿಸಲು ಬ್ರೇಕ್ಪಾಯಿಂಟ್ ಕಾರ್ಯವಿಧಾನವನ್ನು ಬಳಸಿ. ನೀವು ಓದಬಹುದು
ಪೈಥಾನ್ ಸ್ಕ್ರಿಪ್ಟ್ನಲ್ಲಿರುವ eBPF ಪಠ್ಯವು ಈ ರೀತಿ ಕಾಣುತ್ತದೆ:
bpf_text = “”” # Here will be the bpf program code “””
ಕಾರ್ಯಗಳ ನಡುವೆ ಡೇಟಾವನ್ನು ವಿನಿಮಯ ಮಾಡಲು, eBPF ಪ್ರೋಗ್ರಾಂಗಳನ್ನು ಬಳಸುತ್ತದೆ
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 ಕಾರ್ಯಕ್ರಮದ ಸಂದರ್ಭದಲ್ಲಿ ಟೇಬಲ್ ಲಭ್ಯವಿರುತ್ತದೆ. 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():
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 ಮತ್ತು ಟೈಮ್ಸ್ಟ್ಯಾಂಪ್ ಅನ್ನು ನಾವು ಕಂಡುಕೊಳ್ಳುತ್ತೇವೆ, ಆದರೆ ಹೊಸ ಡೇಟಾ ರಚನೆಗಾಗಿ ಮೆಮೊರಿಯನ್ನು ನಿಯೋಜಿಸುವುದಿಲ್ಲ. ಬದಲಿಗೆ, ನಾವು == ಪ್ರಸ್ತುತ PID ಅನ್ನು ಬಳಸಿಕೊಂಡು ಈಗಾಗಲೇ ಅಸ್ತಿತ್ವದಲ್ಲಿರುವ ರಚನೆಗಾಗಿ ಹ್ಯಾಶ್ ಟೇಬಲ್ ಅನ್ನು ಹುಡುಕುತ್ತೇವೆ. ರಚನೆಯು ಕಂಡುಬಂದರೆ, ನಾವು ಚಾಲನೆಯಲ್ಲಿರುವ ಪ್ರಕ್ರಿಯೆಯ ಹೆಸರನ್ನು ಕಂಡುಹಿಡಿಯುತ್ತೇವೆ ಮತ್ತು ಅದನ್ನು ಸೇರಿಸುತ್ತೇವೆ.
ಥ್ರೆಡ್ GID ಪಡೆಯಲು ನಾವು ಇಲ್ಲಿ ಬಳಸುವ ಬೈನರಿ ಶಿಫ್ಟ್ ಅಗತ್ಯವಿದೆ. ಆ. ನಾವು ಕೆಲಸ ಮಾಡುತ್ತಿರುವ ಸಂದರ್ಭದಲ್ಲಿ ಥ್ರೆಡ್ ಅನ್ನು ಪ್ರಾರಂಭಿಸಿದ ಮುಖ್ಯ ಪ್ರಕ್ರಿಯೆಯ PID. ನಾವು ಕರೆಯುವ ಕಾರ್ಯ
ಟರ್ಮಿನಲ್ಗೆ ಔಟ್ಪುಟ್ ಮಾಡುವಾಗ, ನಾವು ಪ್ರಸ್ತುತ ಥ್ರೆಡ್ನಲ್ಲಿ ಆಸಕ್ತಿ ಹೊಂದಿಲ್ಲ, ಆದರೆ ನಾವು ಮುಖ್ಯ ಪ್ರಕ್ರಿಯೆಯಲ್ಲಿ ಆಸಕ್ತಿ ಹೊಂದಿದ್ದೇವೆ. ನಿರ್ದಿಷ್ಟ ಮಿತಿಯೊಂದಿಗೆ ಪರಿಣಾಮವಾಗಿ ವಿಳಂಬವನ್ನು ಹೋಲಿಸಿದ ನಂತರ, ನಾವು ನಮ್ಮ ರಚನೆಯನ್ನು ಹಾದು ಹೋಗುತ್ತೇವೆ ಡೇಟಾ ಟೇಬಲ್ ಮೂಲಕ ಬಳಕೆದಾರರ ಜಾಗಕ್ಕೆ ಘಟನೆಗಳು, ಅದರ ನಂತರ ನಾವು ನಮೂದನ್ನು ಅಳಿಸುತ್ತೇವೆ p.
ಈ ಕೋಡ್ ಅನ್ನು ಲೋಡ್ ಮಾಡುವ ಪೈಥಾನ್ ಸ್ಕ್ರಿಪ್ಟ್ನಲ್ಲಿ, ನಾವು 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()
ಸ್ಕ್ರಿಪ್ಟ್ ಸ್ವತಃ ಇಲ್ಲಿ ಲಭ್ಯವಿದೆ
ಅಂತಿಮವಾಗಿ! ಈಗ ನಾವು ಸ್ಟಾಲಿಂಗ್ bcache ಸಾಧನದಂತೆ ತೋರುತ್ತಿರುವುದು ವಾಸ್ತವವಾಗಿ ಸ್ಥಗಿತಗೊಳಿಸುವ ಕರೆ ಎಂದು ನಾವು ನೋಡುತ್ತೇವೆ generic_make_request() ಕ್ಯಾಶ್ ಮಾಡಿದ ಡಿಸ್ಕ್ಗಾಗಿ.
ಕರ್ನಲ್ ಅನ್ನು ಅಗೆಯಿರಿ
ವಿನಂತಿ ಪ್ರಸರಣ ಸಮಯದಲ್ಲಿ ನಿಖರವಾಗಿ ಏನು ನಿಧಾನವಾಗುತ್ತಿದೆ? ವಿನಂತಿಯ ಲೆಕ್ಕಪತ್ರ ನಿರ್ವಹಣೆಯ ಪ್ರಾರಂಭಕ್ಕೂ ಮುಂಚೆಯೇ ವಿಳಂಬ ಸಂಭವಿಸುತ್ತದೆ ಎಂದು ನಾವು ನೋಡುತ್ತೇವೆ, ಅಂದರೆ. ಅದರ ಮೇಲಿನ ಅಂಕಿಅಂಶಗಳ ಹೆಚ್ಚಿನ ಔಟ್ಪುಟ್ಗಾಗಿ ನಿರ್ದಿಷ್ಟ ವಿನಂತಿಯ ಲೆಕ್ಕಪತ್ರ ನಿರ್ವಹಣೆ (/proc/diskstats ಅಥವಾ iostat) ಇನ್ನೂ ಪ್ರಾರಂಭವಾಗಿಲ್ಲ. ಸಮಸ್ಯೆಯನ್ನು ಪುನರುತ್ಪಾದಿಸುವಾಗ iostat ಅನ್ನು ಚಾಲನೆ ಮಾಡುವ ಮೂಲಕ ಇದನ್ನು ಸುಲಭವಾಗಿ ಪರಿಶೀಲಿಸಬಹುದು, ಅಥವಾ
ನಾವು ಕಾರ್ಯವನ್ನು ನೋಡಿದರೆ generic_make_request(), ನಂತರ ವಿನಂತಿಯು ಲೆಕ್ಕಪತ್ರವನ್ನು ಪ್ರಾರಂಭಿಸುವ ಮೊದಲು, ಇನ್ನೂ ಎರಡು ಕಾರ್ಯಗಳನ್ನು ಕರೆಯಲಾಗುತ್ತದೆ ಎಂದು ನಾವು ನೋಡುತ್ತೇವೆ. ಪ್ರಥಮ - generic_make_request_checks(), ಡಿಸ್ಕ್ ಸೆಟ್ಟಿಂಗ್ಗಳಿಗೆ ಸಂಬಂಧಿಸಿದಂತೆ ವಿನಂತಿಯ ನ್ಯಾಯಸಮ್ಮತತೆಯನ್ನು ಪರಿಶೀಲಿಸುತ್ತದೆ. ಎರಡನೇ -
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 | |
ನಾವು ಪರಿಹಾರದ ಸಮೀಪದಲ್ಲಿರುವಂತೆ ತೋರುತ್ತಿದೆ. ಸರದಿಯನ್ನು ಫ್ರೀಜ್ ಮಾಡಲು/ಫ್ರೀಜ್ ಮಾಡಲು ಬಳಸಲಾಗುವ ಕಾರ್ಯಗಳು
ಈ ಸರದಿಯನ್ನು ತೆರವುಗೊಳಿಸಲು ತೆಗೆದುಕೊಳ್ಳುವ ಸಮಯವು ಡಿಸ್ಕ್ ಲೇಟೆನ್ಸಿಗೆ ಸಮನಾಗಿರುತ್ತದೆ ಏಕೆಂದರೆ ಕರ್ನಲ್ ಎಲ್ಲಾ ಸರತಿಯಲ್ಲಿರುವ ಕಾರ್ಯಾಚರಣೆಗಳು ಪೂರ್ಣಗೊಳ್ಳಲು ಕಾಯುತ್ತದೆ. ಕ್ಯೂ ಖಾಲಿಯಾದ ನಂತರ, ಸೆಟ್ಟಿಂಗ್ಗಳ ಬದಲಾವಣೆಗಳನ್ನು ಅನ್ವಯಿಸಲಾಗುತ್ತದೆ. ಅದರ ನಂತರ ಅದನ್ನು ಕರೆಯಲಾಗುತ್ತದೆ
ಈಗ ಪರಿಸ್ಥಿತಿಯನ್ನು ಸರಿಪಡಿಸಲು ನಮಗೆ ಸಾಕಷ್ಟು ತಿಳಿದಿದೆ. udevadm ಟ್ರಿಗ್ಗರ್ ಆಜ್ಞೆಯು ಬ್ಲಾಕ್ ಸಾಧನದ ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ಅನ್ವಯಿಸಲು ಕಾರಣವಾಗುತ್ತದೆ. ಈ ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು udev ನಿಯಮಗಳಲ್ಲಿ ವಿವರಿಸಲಾಗಿದೆ. ಯಾವ ಸೆಟ್ಟಿಂಗ್ಗಳು ಕ್ಯೂ ಅನ್ನು ಫ್ರೀಜ್ ಮಾಡುತ್ತಿವೆ ಎಂಬುದನ್ನು sysfs ಮೂಲಕ ಬದಲಾಯಿಸಲು ಪ್ರಯತ್ನಿಸುವ ಮೂಲಕ ಅಥವಾ ಕರ್ನಲ್ ಮೂಲ ಕೋಡ್ ಅನ್ನು ನೋಡುವ ಮೂಲಕ ನಾವು ಕಂಡುಹಿಡಿಯಬಹುದು. ನಾವು BCC ಉಪಯುಕ್ತತೆಯನ್ನು ಸಹ ಪ್ರಯತ್ನಿಸಬಹುದು
~# /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 ಉಪಯುಕ್ತತೆಗಳನ್ನು ಅಭಿವೃದ್ಧಿಪಡಿಸಲು ಆಸಕ್ತಿ ಹೊಂದಿದ್ದರೆ, ಅದನ್ನು ನೋಡುವುದು ಯೋಗ್ಯವಾಗಿದೆ
eBPF ಆಧಾರಿತ ಇತರ ಆಸಕ್ತಿದಾಯಕ ಡೀಬಗ್ ಮತ್ತು ಪ್ರೊಫೈಲಿಂಗ್ ಪರಿಕರಗಳಿವೆ. ಅವುಗಳಲ್ಲಿ ಒಂದು -
ಮೂಲ: www.habr.com