- จุดเริ่มต้นมาจากรายงานว่า การอ่านไฟล์ใน Python binding ของ Apache OpenDAL ช้ากว่า
open().read()ในตัวของ Python แต่คอขวดไม่ได้อยู่ที่ OpenDAL หรือ PyO3 เอง - ใน benchmark การอ่านไฟล์ 64MiB พบว่า
python-fs-readใช้เวลาประมาณ 15~19ms ขณะที่ Ruststd::fsและ implementation ภาษา C ใช้เวลาประมาณ 23ms ทำให้ดูเหมือนว่า Rust/C ช้ากว่า Python - เมื่อตามรอยด้วย
strace,eBPF,perfความแตกต่างเชื่อมโยงกับ offset ภายใน page ของ buffer ปลายทางของ system callreadและเกิดอาการช้าซ้ำได้บริเวณใกล้0x10 - พบปรากฏการณ์คล้ายกันในตระกูล AMD Ryzen 9 5900X, Ryzen 7 5700X, Ryzen 9 5900HX โดยเบาะแสสำคัญคือประสิทธิภาพการทำงานของ
rep movsbภายใน_copy_to_iterของ kernel - ไม่ใช่ว่า Python เร็วกว่าโดยธรรมชาติ แต่เป็นผลจากบั๊กของ CPU AMD Zen 3 ที่เกี่ยวข้องกับ FSRM/
rep movsbและความบังเอิญของ memory offset ส่วนการที่jemallocช่วยให้ดีขึ้นก็ไม่ได้มาจาก allocator เอง แต่เพราะได้ offset ที่ต่างออกไป
Benchmark แปลก ๆ ที่เริ่มจาก OpenDAL Python binding
- Apache OpenDAL เป็น data access layer สำหรับอ่านและเขียนข้อมูลจากหลาย storage service ด้วยวิธีแบบรวมศูนย์ ส่วน Python binding ให้บริการผ่าน PyO3
- ผู้ใช้รายงานว่าโค้ดที่อ่านไฟล์ 150MB ด้วย OpenDAL Python binding ช้ากว่าการอ่านไฟล์ในตัวของ Python
open(...).read()ในตัวของ Python 100 ครั้ง:4.470868484000675- OpenDAL Python binding 100 ครั้ง:
8.993250704006641
- แม้ในการอ่านไฟล์ 64MiB ที่ทำให้เรียบง่ายขึ้น OpenDAL binding ก็ยังช้ากว่า
python-fs-read: เฉลี่ย 15.9mspython-opendal-read: เฉลี่ย 32.9ms- การอ่านในตัวของ Python ถูกวัดว่าเร็วกว่า OpenDAL binding 2.07 เท่า
การไล่ตามลงไปถึง Rust OpenDAL และ std::fs
- แม้ implement logic เดียวกันด้วยบริการ OpenDAL
fsของ Rust ก็ยังช้ากว่าการอ่านในตัวของ Pythonrust-opendal-fs-read: เฉลี่ย 23.8mspython-fs-read: เฉลี่ย 15.6ms- การอ่านในตัวของ Python ถูกวัดว่าเร็วกว่า implementation Rust OpenDAL 1.52 เท่า
- เนื่องจากบริการ
fsของ OpenDAL ใช้ std::fs ของ Rust จึงเขียน implementation ที่ใช้std::fsแยกต่างหากเพื่อตรวจสอบ overhead ของ OpenDAL เอง - ใน implementation ที่ใช้ Rust
std::fsโดยตรงก็ยังได้แนวโน้มเดิมrust-std-fs-read: เฉลี่ย 23.1mspython-fs-read: เฉลี่ย 15.2ms- การอ่านในตัวของ Python ถูกวัดว่าเร็วกว่า Rust
std::fs1.52 เท่า
system call และ mmap ที่เห็นจาก strace
- จากการวิเคราะห์ด้วย
straceพบว่าทั้ง Rust และ Python ใช้mmapสำหรับการ allocate buffer ขนาดใหญ่ - การรัน Rust
std::fsมีลำดับคือเปิด/tmp/file, อ่าน 64MiB หนึ่งครั้ง, เรียกreadเพื่อตรวจ EOF แล้วปิดไฟล์ - การอ่านในตัวของ Python เรียก system call มากกว่า เช่น
newfstatat,ioctl,lseekแต่เวลารวมกลับสั้นกว่า - การเรียก
mmap(NULL, 67112960, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0)ไม่ได้ใช้ map ไฟล์ แต่ใช้สำหรับ allocate anonymous memory67112960คือขนาด 64MiB บวกอีก 4KiBMAP_ANONYMOUSหมายถึงการ allocate memory ที่ไม่เกี่ยวกับไฟล์
- build ค่าเริ่มต้นของ Rust บน
x86_64-unknown-linux-gnuใช้mallocของglibcและglibcสามารถใช้mmapสำหรับ allocation ขนาดใหญ่ได้
Rust ที่เร็วขึ้นด้วย jemalloc และข้อสรุประหว่างทางที่พลิกกลับ
- เมื่อเปลี่ยน global allocator ของ Rust เป็น
jemallocator::Jemallocก็เร็วกว่า Pythonrust-std-fs-read-with-jemalloc: เฉลี่ย 9.7mspython-fs-read: เฉลี่ย 15.8ms- implementation Rust ที่ใช้ jemalloc ถูกวัดว่าเร็วกว่า Python 1.64 เท่า
- ณ จุดนี้ดูเหมือนว่า
mmapหรือ default memory allocator จะเป็นสาเหตุ แต่การตีความถูกแก้ไขในอัปเดตภายหลัง - ตามอัปเดตวันที่ 2023-12-01 ความต่างไม่ได้เกิดจาก
jemalloc,pymalloc,mimallocเร็วกว่าglibc mallocโดยพื้นฐาน - ความต่างจริง ๆ มาจาก offset ภายใน page ของ buffer ที่ allocator สร้างขึ้น
rust-std-fs-read: อ่านที่ offset0x10จาก address เริ่มต้นของmmaprust-std-fs-read-with-jemalloc: อ่านที่ offset0x740จาก address เริ่มต้นของmmap
- ช่วงที่มีปัญหาถูกสรุปว่าอยู่ในช่วง
0x00..0x10ภายใน page และสามารถ reproduce ปัญหาเดียวกันได้แม้ใช้jemalloc
ปัญหาที่ reproduce ตามเครื่องได้มากกว่าการตั้งค่าซอฟต์แวร์
- เมื่อการอภิปรายดำเนินต่อไป มีการยืนยันว่าอาการ Rust ช้ากว่า Python เด่นชัดเป็นพิเศษบนเครื่องของผู้เขียน
- CPU ของผู้เขียนคือ AMD Ryzen 9 5950X 16-Core Processor และหน่วยความจำเป็น DDR4 3200 MT/s 16GB DIMM
- แม้เปลี่ยนการตั้งค่าหลายอย่าง ความต่างด้านประสิทธิภาพแบบสัมพัทธ์ก็ไม่หายไป
- เปิด
mitigations=offของ Linux kernel กลับคืน ก็ไม่ทำให้ผลลัพธ์เปลี่ยน - เมื่อเปลี่ยน Transparent Hugepage เป็น
always,madvise,neverค่าสัมบูรณ์เปลี่ยน แต่สัดส่วนสัมพัทธ์ยังคงอยู่ - แม้ผูกกับ CPU core เฉพาะด้วย
core_affinityผลลัพธ์ก็เหมือนเดิม
- เปิด
- การวัด latency ของ system call
readด้วย eBPF ก็พบว่าฝั่ง Rust ช้ากว่า- Python
read file: 8,134,049ns - Rust
std::fsread file: 24,636,975ns
- Python
- จากการสังเกต เป็นเรื่องยากที่จะอธิบายความต่างด้วย OpenDAL, PyO3 หรือ Rust standard library เพียงอย่างเดียว และเวลาต่างกันตั้งแต่ระดับ system call แล้ว
เบาะแส memory offset ที่ปรากฏใน implementation ภาษา C
- แม้ implement การอ่านไฟล์ 64MiB แบบเดียวกันด้วย C
fopen/malloc/freadก็ยังช้ากว่า Pythonc-fs-read: เฉลี่ย 23.8mspython-fs-read: เฉลี่ย 19.1ms- การอ่านในตัวของ Python ถูกวัดว่าเร็วกว่า implementation ภาษา C 1.25 เท่า
- เมื่อตรวจ address ของ pointer ด้วย
strace -e raw=read,mmapพบว่า offset เริ่มต้นของ buffer ใน C และ Python ต่างกัน- C:
readที่ offset0x10จาก address ที่mmapreturn - Python:
readที่ offset0x30จาก address ที่mmapreturn
- C:
- เมื่อปรับ offset ใน implementation ภาษา C ด้วยวิธีเดียวกัน ประสิทธิภาพดีขึ้นอย่างมาก
c-fs-read-with-offset: เฉลี่ย 8.9ms- เร็วกว่า Python 2.15 เท่า และเร็วกว่า implementation C เดิม 2.68 เท่า
- ปัญหานี้ reproduce ได้บน AMD Ryzen 9 5900X และ AMD Ryzen 7 5700X ด้วย
- ใน Std::fs::read slow? ของชุมชน Rust ก็มีรายงานปรากฏการณ์คล้ายกัน และมีการชี้ถึงความเกี่ยวข้องระหว่าง offset ของ memory region กับประสิทธิภาพของ system call
rep movsb ที่ perf analysis ชี้ไป
- kernel developer รายหนึ่ง reproduce
c-fs-readและเวอร์ชันที่ใส่ offset บนAMD Ryzen 9 5900HXแล้ววิเคราะห์ด้วยperf - ค่า
L1-dcache-prefetchesและL1-dcache-loadsต่างกันมากตามการมีหรือไม่มี offset- ไม่มี offset:
L1-dcache-loadsประมาณ 127,845,213,L1-dcache-prefetchesประมาณ 1,843,493 - มี offset:
L1-dcache-loadsประมาณ 13,965,813,L1-dcache-prefetchesประมาณ 395,578
- ไม่มี offset:
- hotspot อยู่ใน path ของ
readใน kernel ต่อเนื่องจากshmem_file_read_iter→copy_page_to_iter→_copy_to_iter - assembly หลักภายใน
_copy_to_iterคือrep movsbและ sample ส่วนใหญ่กระจุกอยู่ที่ instruction นี้ - การวิเคราะห์ภายหลังสรุปว่า เบาะแสที่สำคัญกว่าไม่ใช่ L1 prefetch เอง แต่เป็นปรากฏการณ์ที่
rep movsbทำงานได้แย่กับข้อมูลที่ page-aligned และดีขึ้นเมื่อ page alignment ถูกทำให้คลาดออกไป
FSRM และปัญหาของ AMD Zen 3
- รายงานบั๊ก Ubuntu glibc ที่ถูกแชร์คือ Terrible memcpy performance on Zen 3 when using rep movsb ก็กล่าวถึงปัญหาประสิทธิภาพของ
rep movsbเช่นกัน - ตัวอย่างในรายงานดังกล่าวอธิบายว่า ในการ copy 2113 bytes เส้นทาง
rep movsbทำได้ประมาณ 3.2GB/s แต่เมื่อเปลี่ยนขนาดเป็น 2111 bytes จะเพิ่มขึ้นเป็นมากกว่า 100GB/s - FSRM ย่อมาจาก Fast Short REP MOV เป็นฟีเจอร์ที่ออกแบบมาเพื่อทำให้
rep movsbและrep movsdเร็วขึ้น - FSRM เป็นฟีเจอร์ที่เริ่มจาก Intel และถูกนำมาใช้ใน AMD ด้วย โดยบน CPU ที่ประกาศรองรับ
glibcจะใช้ FSRM เป็นค่าเริ่มต้น - ดังนั้น ไม่ใช่ว่า Python เร็วกว่า C/Rust โดยพื้นฐาน แต่เป็นเพราะบั๊กของ AMD CPU ที่ทำให้ read path ของ C/Rust ช้าลงที่ memory offset บางตำแหน่ง
อัปเดต: AMD รับรู้หรือไม่ และการรับมือของ glibc
- ตามอัปเดตวันที่ 2023-12-01 เข้าใจว่า AMD ทราบบั๊กนี้มาตั้งแต่ปี 2021
- หลังบทความเผยแพร่ ผู้อ่านหลายคนส่งลิงก์ให้ AMD ดังนั้นจึงถือว่า AMD รับรู้ปัญหานี้แล้ว
- ผู้เขียนเห็นว่า AMD ควรรับผิดชอบแก้บั๊กนี้ใน
amd-ucodeแต่จากข้อมูลที่ยังไม่ยืนยัน อาจแก้ผ่านamd-ucodeบน Zen 3 ได้ยาก - ความหวังที่เป็นไปได้ในทางปฏิบัติคือให้ glibc ปิดใช้ FSRM เมื่อจำเป็น
- ฝั่ง glibc กำลังมีงาน x86: Improve ERMS usage on Zen3 อยู่
โค้ดสำหรับ reproduce และข้อมูลที่เกี่ยวข้อง
- Xuanwo/when-i-find-rust-is-slow: ชุด code snippet และ script ที่ใช้
- Std::fs::read slow?: รายงานลักษณะคล้ายกันจากชุมชน Rust
- Terrible memcpy performance on Zen 3 when using rep movsb: ปัญหาประสิทธิภาพ
rep movsbบน Zen 3 ที่รายงานไปยัง Ubuntu glibc - binding/python: rust std fs is slower than python fs: issue เกี่ยวกับ OpenDAL Python binding
1 ความคิดเห็น
ความคิดเห็นจาก Hacker News
มี แฟล็กคุณสมบัติของ CPU เฉพาะถึงสองตัวที่บ่งชี้ว่า
REP STOS/MOVเร็ว และสามารถใช้เป็นลำดับคำสั่งสั้น ๆ ของmemset/memcpyได้ความเจ็บปวดที่ต้องเขียนรูทีนปรับแต่งด้วยมือใหม่ทุกครั้งที่ CPU ออกรุ่นใหม่ลากยาวมาหลายสิบปีแล้ว แต่ยังเป็นแบบนี้อยู่ ก็อดคิดไม่ได้ว่านี่ควรอยู่ในชุดทดสอบไทมิงของผู้ผลิต CPU หรือเปล่า
อาจมีปัญหากับ
rep movsแบบเร็วที่จัดแนวตามเพจ หรือมีช่องโหว่ต่อการโจมตีบางอย่างจนต้องปิดใช้งานไม่รู้ว่าการแก้ไขควรเป็นแบบไหน ต้องมีอะไรอย่าง การตรวจสอบขณะรันไทม์ หรือไม่
ถ้ามีการทำงานแบบ “ซอฟต์แวร์” ที่เร็วกว่า ก็สงสัยว่าทำไมถึงไม่ทำให้
REP MOVSทำงานแบบเดียวกันอย่างน้อยก็ในระดับ ไมโครโค้ดบั๊ก glibc ที่เกี่ยวข้องอยู่ที่นี่ แต่เคสนี้เป็น Zen 4: https://sourceware.org/bugzilla/show_bug.cgi?id=30994
ตอนแรกอ่านแล้วเตรียมจะหัวเราะเยาะว่าผู้เขียนใช้
std::fsผิด แต่จริง ๆ แล้วกลายเป็นบทความสนุกที่พาลง โพรงกระต่ายของการดีบัก และปริศนาต่อเนื่องเขียนได้ดีและน่าสนใจมาก
สมมติฐานตั้งต้นชวนสับสนนิดหน่อย นี่ไม่ได้เทียบโค้ด Python ล้วนกับโค้ด C/Rust แบบเนทีฟ แต่เป็นการเทียบเมธอดอ่านไฟล์ของ Python ซึ่งเป็นแรปเปอร์ Python บนโค้ดเนทีฟ กับ OpenDAL ซึ่งก็เป็นแรปเปอร์อีกตัวบนโค้ดเนทีฟเช่นกัน
การที่มีความต่างด้านประสิทธิภาพก็ยังน่าสนใจอยู่ แต่การเรียกว่า “ช้ากว่า Python” นั้นค่อนข้างแปลก เหมือนคาดหวังว่าไลบรารีมาตรฐานของ Python ทั้งหมดเขียนด้วย Python ล้วนอย่างนั้นหรือ ตรงกันข้าม ผมคาดว่าการ implement ฟังก์ชันในไลบรารีมาตรฐานของ Python น่าจะเป็นเนทีฟและถูกปรับแต่งอย่างมากเป็นรายฟังก์ชัน
ไม่แปลกใจที่ข้อสรุปเกี่ยวข้องกับวิธีทำงานของโค้ดเนทีฟ แต่คำตอบเฉพาะนั้นเกินคาดอยู่ดี แค่จุดเริ่มต้นทำให้สับสนเท่านั้น ตัวบทความเองน่าสนใจมาก
อีกอย่าง ชื่อ “C is slower than Python with specified offset” สำหรับเจ้าของภาษาจะอ่านได้ว่า “C ช้ากว่า Python แม้ในกรณีที่ระบุออฟเซ็ตแล้ว” แต่จริง ๆ หมายถึงตรงกันข้าม คือพอระบุออฟเซ็ตที่ใช้ใน Python ให้กับ C ด้วยแล้ว C ก็เร็วขึ้น
งานง่าย ๆ อย่างการอ่านไฟล์ที่ไลบรารีมาตรฐานของ Rust ช้ากว่าไลบรารีมาตรฐานของ Python นั้นเป็นเรื่องน่าประหลาดใจ ต่อให้รู้ว่าคอลล์ของไลบรารีมาตรฐาน Python แบบนี้เขียนด้วย C ก็ยังคาดหวังได้ว่าคอลล์ของไลบรารีมาตรฐาน Rust น่าจะเร็วใกล้เคียงกัน
ดังนั้นโดยทั่วไปคงคาดว่าใช้ผิดวิธี หรือมีพฤติกรรมแปลก ๆ ในไลบรารีมาตรฐาน Rust แต่ครั้งนี้ไม่ใช่ทั้งสองอย่าง กลับเป็น หน้าผาประสิทธิภาพ ที่เกิดจากการจัดแนวของการจัดสรรหน่วยความจำบนฮาร์ดแวร์เฉพาะ
เราคาดได้ว่าการอ่านไฟล์ใน Python น่าจะถูกปรับแต่งมาดี แต่ก็คิดว่า Rust ก็ควรเป็นเช่นเดียวกัน ดังนั้นการที่ฝั่ง Rust ช้ากว่ามากจึงน่าประหลาดใจ และยิ่งน่าประหลาดใจขึ้นเพราะมันขึ้นกับฮาร์ดแวร์และ allocator
ถ้าโค้ดที่เขียนด้วย Python ทำงานได้เร็ว สำหรับผมก็คือ Python เร็ว นั่นแหละ ไม่ค่อยสำคัญว่าที่เป็นแบบนั้นเพราะ implementation อยู่ในภาษาอื่นหรือเพราะเหตุผลอื่น
สิ่งที่เกิดขึ้นในบทความต้นทางเป็นเรื่องใกล้เคียงกับความบังเอิญล้วน ๆ โค้ด C ของ CPython ไม่ได้ใส่ใจแม้แต่ความสม่ำเสมอของ
constและมีการจัดสรรหน่วยความจำแบบไดนามิกกับคอลล์ช่วยเหลือ/อำนวยความสะดวกจำนวนมาก แม้แต่เรื่องอย่างการคำนวณเลขก็ยังมีการจัดสรรหน่วยความจำแบบไดนามิกถ้าเคยทำงานกับ CPython โดยปกติจะไม่คาดหวังว่าประสิทธิภาพจะดี เวลาต้องการปรับปรุงประสิทธิภาพก็มักจะพยายามเลี่ยงฟีเจอร์ที่มันให้มา
นอกจากนี้ Python ไม่มีมาตรฐาน ดังนั้นหากพูดอย่างเคร่งครัดก็ไม่มีไลบรารีมาตรฐาน และไลบรารีที่แจกมาด้วยส่วนใหญ่เขียนด้วย Python บางส่วนเขียนด้วย C แต่แม้ในโค้ด C เหล่านั้น ก็มีสัดส่วนไม่น้อยที่โดยสาระแล้วเป็นการย้ายโค้ด Python ไปเป็น C แบบค่อนข้างกลไก ตัวอย่างเช่น implementation ของ binary search ใน Python เดิมเขียนด้วย Python แล้วภายหลังถูกแปลเป็น C โดยใช้ Python C API
สิ่งที่พอคาดหวังได้คือ ฟีเจอร์ที่แมปกับความสามารถของระบบปฏิบัติการโดยตรงจะมีแรปเปอร์ที่ค่อนข้างบาง กล่าวคือการอ่านไฟล์โดยพื้นฐานแล้วเข้า อินเทอร์เฟซระบบ โดยตรง จึงไม่น่าต้องมีโค้ด binding มากนัก
หลังจากมีบทความทำนองนี้ขึ้นมาหลายสิบครั้ง ทุกคนก็เริ่มรู้ทันกันแล้ว
ตัวบทความเองยอดเยี่ยม และมีข้อมูลที่น่าสนใจมากมายเกี่ยวกับประเด็นนี้
แต่ส่วนที่ผมสนใจและกังวลมากกว่าคือ ประเด็นนี้ถูกรายงาน·บันทึกอย่างไร และการสื่อสารถูกจัดการอย่างไร
การรายงานเกิดขึ้นบน Discord ซึ่งเป็นสภาพแวดล้อมแบบปิด ไม่ถูกทำดัชนี ค้นหายาก และไม่ได้ถูกเก็บรักษาไว้ การอภิปรายเกิดขึ้นบน Discord และ Telegram ซึ่งในบริบทนี้ Telegram อาจจะแย่ยิ่งกว่า
บล็อกโพสต์นี้กับ GitHub repository คือร่องรอยทั้งหมดที่เหลืออยู่ ถ้า Xuanwo ไม่ได้เขียนลงบล็อก มันก็คงหายไปในไทม์ไลน์แล้ว เป็นสถานการณ์ที่น่าสนใจทีเดียว
แทบไม่มีเมสเซนเจอร์ไหนที่ทำดัชนี·ค้นหาล็อกที่เข้าถึงสาธารณะได้ตามค่าเริ่มต้นให้ ทุก IRC server ก็ไม่ได้มีล็อกสาธารณะให้ทั้งหมด และกลุ่ม Matrix ก็เช่นกัน ผมไม่เข้าใจว่าทำไมถึงมองว่าการอภิปรายที่นั่นจะไม่หายไปในไทม์ไลน์
เหตุผลที่สามารถมีล็อกสาธารณะได้ ไม่ใช่เพราะมันไม่ใช่ระบบปิด แต่เพราะมี API ที่อนุญาตให้ทำ logging ได้ Telegram ก็มี API แบบนั้น และกลุ่มอภิปรายของเราก็มีล็อกที่ค้นหาได้ดูได้ที่นี่: https://luoxu-web.vercel.app/#g=1264662201
การที่ไม่มีการทำดัชนีสาธารณะ ส่วนใหญ่เป็นเพราะ ความเป็นส่วนตัว ไม่ใช่เพราะแพลตฟอร์มเป็นระบบปิด
เมื่อก่อนสามารถค้นหาข้อความทั้งหมดได้อย่างเป็นระเบียบผ่าน DejaNews และต่อมาก็ Google
การสื่อสารสำคัญของโปรเจกต์โอเพนซอร์สสำคัญ ๆ อย่างสแตกอินเทอร์เน็ต/WWW และเครื่องมือ·ไลบรารีหลักด้านโปรแกรมมิ่ง ควรกลับไปใช้ มาตรฐานเปิด
เป็นบทความที่น่าสนใจที่สุดที่อ่านในสัปดาห์นี้ สรุปได้ยอดเยี่ยม
สิ่งที่ควรทำอย่างชัดเจนดูเหมือนจะเป็นการส่งแพตช์ไปยังเมธอดเคอร์เนล
copy_user_genericถ้าตรวจพบ CPU ที่มีปัญหาและก่อให้เกิดบั๊กที่ทำให้การจัดแนวหน่วยความจำช้าลง ก็ให้ใช้ implementation สำหรับคัดลอกหน่วยความจำ แบบอื่นแทน
การแก้ไขที่คนไม่มีประสบการณ์กับเคอร์เนลจะยอมรับได้นั้นไม่น่าจะเล็กน้อย ที่สำคัญกว่านั้น วิธีเปิดใช้ workaround ก็ดูไม่ชัดเจนเช่นกัน อาจจะดีที่สุดถ้าวัดตอนบูต ไม่อย่างนั้นก็ไม่แน่ว่าจะรู้ได้อย่างไรว่าโมเดลและ stepping ไหนได้รับผลกระทบ
มาตรการบรรเทาทางซอฟต์แวร์ก็น่าจะซับซ้อนเช่นกัน เพราะเคอร์เนลไม่สามารถใช้คำสั่งเวกเตอร์ที่ปกติใช้ในเส้นทางสำรองเมื่อใช้ ERMS ไม่ได้จริง ๆ
jemallocเคยเป็น allocator ค่าเริ่มต้นของ Rust จนถึงปี 2018https://internals.rust-lang.org/t/jemalloc-was-just-removed-...
ส่วนที่บอกว่า “นักพัฒนา Rust อาจพิจารณาเปลี่ยนไปใช้
jemallocatorเพื่อเพิ่มประสิทธิภาพ” นั้นน่าสนใจไม่แน่ใจว่าใคร ๆ ก็จะได้ประสิทธิภาพเพิ่มขึ้นแทบฟรีหรือไม่ หรือมีข้อควรระวังอะไรบ้าง อยากรู้ว่า codebase ภาษา C ก็จะได้ประโยชน์ด้วยไหม และนี่เป็นประสิทธิภาพที่ตอนนี้เรากำลังพลาดไปเฉย ๆ หรือเปล่า
jemallocจะทำให้เกิดปัญหาเรื่อง observability เพราะMADV_FREEhtopจะไม่แสดงหน่วยความจำที่ใช้งานจริงได้อย่างแม่นยำอีกต่อไปhttps://github.com/jemalloc/jemalloc/issues/387#issuecomment...
https://gitlab.haskell.org/ghc/ghc/-/issues/17411
ตอนนี้ดูเหมือนว่า
jemallocจะเรียกMADV_DONTNEEDหลังจากMADV_FREEไปแล้ว 10 วินาที: https://github.com/JuliaLang/julia/issues/51086#issuecomment...ดังนั้นมันจึง “แก้” ปัญหานี้ก็จริง แต่จะมีดีเลย์ที่ทำให้สับสนระหว่างเวลาที่คืนหน่วยความจำกับเวลาที่เห็นข้อเท็จจริงนั้นใน
htopอย่างไรก็ตาม ตาม https://jemalloc.net/jemalloc.3.html สามารถตั้ง
opt.muzzy_decay_ms = 0เพื่อลบดีเลย์ได้ถึงอย่างนั้นผู้เขียน musl ก็ยังระมัดระวังต่อการใช้
jemallocเป็นค่าเริ่มต้น: https://www.openwall.com/lists/musl/2018/04/23/2ใจความคือมีปัญหาเรื่องการพองตัวอย่างรุนแรง, ASLR อ่อนลง และการปรับแต่งที่เอนเอียงไปทางทำให้เร็วที่สุดโดยไม่สนใจการใช้หน่วยความจำ แม้ค่าปรับแต่งข้างต้นอาจช่วยบรรเทาได้บ้าง แต่แนวโน้มโดยรวมว่าจะเน้นประสิทธิภาพหรือการใช้หน่วยความจำก็น่าจะยังคงเป็น trade-off อยู่ดี
อาจไม่ได้เร็วกว่าเสมอในทุกสถานการณ์ แต่ในเกือบทั้งหมดน่าจะเร็วกว่า Rust เองก็เคยใช้
jemallocเป็นค่าเริ่มต้น แต่ถูกเปลี่ยนไปเพราะมีคนมองว่ามันเป็นค่าเริ่มต้นที่น่าประหลาดใจขึ้นกับ workload มาก จึงต้องมี profiling และ benchmarking ถึงอย่างนั้นภาษา low-level อย่าง C/C++/Rust ก็ควรเลือก allocator เหล่านี้ได้
ข้อควรระวังอย่างหนึ่งคือขนาดไบนารี allocator แบบกำหนดเองจะเพิ่มจำนวนไบต์เข้าไปในไฟล์ปฏิบัติการ
jemallocเป็นค่าเริ่มต้น แต่ราวปี 2018 ก็กลับไปใช้mallocของระบบอีกครั้ง[0]ตอนนี้ Rust มี trait
GlobalAllocและ attribute#[global_allocator]แล้ว ดังนั้นถ้าแอปต้องการก็สามารถใช้jemallocเป็น allocator ได้ ไม่แน่ใจว่าผู้ใช้จะ override ด้วยวิธีอย่างLD_PRELOADได้หรือไม่jemallocไม่ได้เป็นตัวเลือกที่ดีที่สุดเสมอสำหรับทุก workload และ use case allocator ของระบบมักห่างไกลจากความสมบูรณ์แบบ แต่ อย่างน้อยก็ผ่านการทดสอบอย่างกว้างขวางในฐานะ allocator อเนกประสงค์[0] https://github.com/rust-lang/rust/issues/36963
jemallocอาจเป็นตัวเลือกที่เหมาะกับบางแอปพลิเคชัน แต่ในกรณีอื่น allocator ตัวอื่นอาจเร็วกว่า หรือแม้จะช้ากว่า แต่ก็อาจสอดคล้องกับเป้าหมายอย่าง dirty memory ที่น้อยลง, observability ที่ดีกว่า, หรือการรับประกันด้านความปลอดภัยบางอย่างได้ดีกว่าส่งเรื่องนี้ไปให้คนที่เหมาะสมแล้ว