1 ความคิดเห็น

 
GN⁺ 2023-12-04
ความคิดเห็นบน Hacker News
  • ถ้าดู ประวัติรุ่นของ ARM ที่ Raspberry Pi เคยใช้แล้ว ก็น่าทึ่งจริง ๆ ว่ามันเป็นชิปที่เก่ามาก
    แม้ในปี 2014 ตอนที่ Raspberry Pi B+ ออกมา คอร์ ARM1176 ที่ใช้ก็เป็นของปี 2003 จึงมีอายุ 11 ปีแล้ว
    ดังนั้นจึงไม่แปลกที่เวลา build บนแพลตฟอร์มอื่น เช่น Raspberry Pi รุ่นใหม่กว่า อาจต้องระบุ architecture flag เพื่อสร้างโค้ดที่เข้ากันได้
    แต่ถ้าแม้แต่การ build บน Raspberry Pi B+ เองก็ยังไม่ได้เลือกสถาปัตยกรรมที่ถูกต้องเป็นค่าเริ่มต้น ก็ดูเหมือนเป็น ข้อผิดพลาดในการตั้งค่า ฝั่งค่าเริ่มต้นของดิสโทร

    • เท่าที่จำได้ Pi รุ่นแรกใช้ชิปที่เหลือจากการทำกล่องทีวี
      ผลิตภัณฑ์แบบนั้นแทบไม่เคยใส่พลังประมวลผลมากเกินความจำเป็น เพราะเรื่องราคา
    • ตั้งแต่แรกมันก็เป็นผลิตภัณฑ์ที่ตั้งใจทำให้เป็น คอมพิวเตอร์ราคาถูก อยู่แล้ว
    • จริง ๆ แล้วไม่ได้ build บน B+
      ในบทความบอกว่า “เอาไบนารีจาก build host ที่เป็น Pi 4B ซึ่งเร็วกว่าเยอะ แล้วพยายามรันบนเครื่องเก่านี้ จึงเจอ illegal instruction”
      กรณีนี้คล้ายกับการ build ไฟล์ .EXE ด้วย MSVC รุ่นใหม่บน Windows 11 แล้วเอาไปรันบนพีซีเก่าที่ติดตั้ง Windows XP
      เป็นไปได้สูงว่าดิสโทร Pi ทั้งชุดที่รันบน Pi 4B ก็อาจรันบน B+ ไม่ได้ และแม้แต่ kernel ก็อาจถูก compile ด้วยวิธีเดียวกัน
  • เหมือนในโพสต์หรือบทความจะไม่ได้พูดให้ชัด แต่นี่ไม่ใช่ บั๊ก เหรอ?
    ลองหา bug ของ LLVM แล้วเจอรายการที่ดูเหมือนเป็นประเด็นแทบจะเดียวกัน แต่เป็น bug ตั้งแต่ปี 2012 และปิดไปแล้ว จากคอมเมนต์ท้าย ๆ ดูเหมือนว่าอาจยังไม่ได้แก้จริง ๆ ก็ได้ แต่ผมแค่อ่านผ่าน ๆ จึงอาจเข้าใจผิด
    https://github.com/llvm/llvm-project/issues/13989
    กลับไปดูอีกที ตอนท้ายบทความบอกว่าถ้าระบุ target อย่างชัดเจนก็จะได้โปรแกรมที่ทำงานได้ ถ้าอย่างนั้นก็ดูเหมือนเป็นบั๊กด้านการตั้งค่าชนิดหนึ่ง และใน Unix ผมคิดว่า target เริ่มต้นน่าจะเป็นโปรเซสเซอร์ปัจจุบัน แต่ก็ไม่แน่ใจ
    bug ที่ลิงก์ไปน่าจะเป็นปัญหาที่แม้ตั้ง target ถูกต้องแล้วก็ยังสร้างโค้ดผิด และโชคดีที่ตอนนี้ดูเหมือนจะไม่ใช่สถานการณ์นั้น

    • ใช่แล้ว bug ที่ลิงก์คือปัญหาที่สั่ง compiler ให้ target เป็น armv6 แต่กลับปล่อย คำสั่ง armv7 ออกมา
      ปัญหาของ Rachel แก้ได้ด้วยการบอก compiler ให้ target เป็น armv6 ดังนั้น bug นั้นน่าจะถูกแก้ไปแล้ว และดูเป็นคนละเรื่องกับปัญหานี้
    • แน่นอนว่าเป็นบั๊ก แต่ผู้เขียนดูเหมือนจะเลือกเขียนบล็อกโพสต์ที่ชื่อออกแนวชวนคลิกนิด ๆ แล้วจบด้วย “แปลกมาก” มากกว่าจะรายงานบั๊ก
  • ฐานข้อมูลที่ผมทำงานอยู่คือ ClickHouse พยายามพอสมควรในการรักษาความเข้ากันได้กับฮาร์ดแวร์เก่ามาก ๆ
    ไบนารี ARM มาตรฐานต้องการ Armv8.2 จากปี 2016 และใช้ได้กับ Raspberry Pi 2 เป็นต้นไป ส่วนไบนารี x86 รันได้บนฮาร์ดแวร์ราวปี 2010 ที่มีคำสั่ง SSE4.2 และ pclmul* สำหรับ CRC ที่รวดเร็ว
    เรายัง build ไบนารีสำหรับระบบที่มีแค่ Armv8.0 และ SSE2 ด้วย แต่ไม่ได้ทดสอบใน CI สคริปต์ติดตั้งแบบเร็วจะดาวน์โหลดไบนารีที่เหมาะกับ host เป้าหมายแล้วแตกไฟล์ให้
    โดยรวมรู้สึกว่าการหาสมดุลระหว่าง ความเข้ากันได้ย้อนหลัง กับการใช้ประโยชน์จากฟีเจอร์ CPU ของ AArch64 รุ่นใหม่ ๆ เป็นเรื่องยาก
    https://en.wikipedia.org/wiki/AArch64
    มีองค์กรที่งบจำกัดจำนวนมากจนน่าประหลาดใจ เช่น มหาวิทยาลัยในประเทศกำลังพัฒนา หรือผู้ใช้สายงานอดิเรกที่ไม่มีงบอัปเกรดฮาร์ดแวร์
    ในเชิงเทคนิค สิ่งที่ค่อนข้างน่ารำคาญคือ CPU flag ใน /proc/cpuinfo ไม่ได้สอดคล้องกับ flag -march= ที่ส่งให้ compiler เสมอไป เช่น แสดงต่างกันเป็น "lrcpc" กับ "rcpc"
    ถ้าจะให้ทำงานถูกต้องจริง ๆ ก็แทบต้องดูแล ชุด flag สองประเภท

    • ถ้าเป็นกรณีแบบนั้น ผมคิดว่าการมี build หลายแบบให้ลูกค้าเลือกตัวที่ใกล้กับสถาปัตยกรรมของตัวเองที่สุดน่าจะเป็นประโยชน์กับทุกฝ่าย
  • ปัญหาน่าจะมีโอกาสสูงว่าเกิดจาก target ที่ตั้งค่าไว้เปลี่ยนไป ในแพ็กเกจ clang-13 ปัจจุบันของ bookworm
    โดยเฉพาะใน bullseye กับ clang-11 ค่า target เริ่มต้นคือ armv6k-unknown-linux-gnueabihf แต่ใน bookworm กับ clang-13 คือ arm-unknown-linux-gnueabihf
    หรือไม่ก็อาจเป็นเพราะค่าเริ่มต้นของ build configuration นั้นเปลี่ยนไปในฝั่ง LLVM

    • อยากเข้าใจกระบวนการจัดการการเปลี่ยนแปลงของ Debian ให้ดีกว่านี้ ผมก็ไม่แน่ใจด้วยซ้ำว่า Raspbian ถูกดูแลอยู่ใน Debian จริง ๆ หรือไม่
      แต่เมื่อเทียบ [1] กับ [2] จะเห็นว่ามี test ที่ชัดเจนในไฟล์ rules ว่า “ถ้า DEB_HOST_ARCH เป็น armhf ให้ตั้ง LLVM_HOST_TRIPLE เป็น armv6k” ซึ่งดูเหมือนจะยืนยันการเปลี่ยนแปลงใน build configuration
      [1] http://raspbian.raspberrypi.org/raspbian/pool/main/l/llvm-to...
      [2] http://raspbian.raspberrypi.org/raspbian/pool/main/l/llvm-to...
  • ดูไม่น่าจะเป็นการเปลี่ยนแปลงโดยตั้งใจ
    อย่างที่คอมเมนต์รอบ ๆ พูดถึง /etc/env.d/gcc มีความเป็นไปได้พอสมควรว่ามันเป็นวิธีอ่านข้อมูลจากสภาพแวดล้อม
    ค่า default triple น่าจะเป็นอะไรอย่าง arm-unknown-linux ถ้า clang หา หรือไม่ได้รับข้อมูลที่เฉพาะเจาะจงกว่านี้ แต่ดูเหมือนกลไกที่บอกเป้าหมายที่เฉพาะกว่านั้นจะพัง
    นี่อาจหมายความว่าไม่มี ARMv6 buildbot หรืออาจมี buildbot อยู่ แต่การตั้งค่าแบบ implicit ที่นั่นยังทำงานได้ดีก็ได้
    LLVM เป็น cross compiler ที่ดีมากจริง ๆ สามารถ build จากเป้าหมายใดไปยังเป้าหมายใดก็ได้โดยแทบไม่มีปัญหาใหญ่
    Clang น่าสนใจน้อยกว่านั้น ถ้ามันถูก build พร้อมการรองรับเป้าหมาย และสามารถบอกได้อย่างถูกต้องว่าจะ build ไปยังเป้าหมายไหน ก็น่าจะจัดการได้ถูกต้อง แม้ในบทความนี้การคาดเดาจะผิด แต่พอให้ข้อมูลเพิ่ม มันก็ทำงานได้ถูกต้อง
    สถานการณ์ของ runtime library แย่กว่านั้น ต่อให้ build สำหรับเป้าหมายอย่าง armv4 ก็ยังต้องหา libc ฯลฯ ที่ตรงกัน และอาจต้องบอกตำแหน่งของ library กับ header เหล่านั้นให้ compiler ซึ่งส่วนนี้รายละเอียดยังไม่ชัดเจน

    • distribution และ compiler ส่วนใหญ่เลิกสนับสนุน ARMv6 โดยพฤตินัยไปเมื่อหลายปีก่อนแล้ว
      เคยเจอปัญหาคล้าย ๆ กันตอน build binary สำหรับ Synology NAS รุ่นเก่า
    • ทำไม Clang ต้องอ่านข้อมูลจาก /etc/env.d/gcc ด้วย?
  • clang/clang++ อ่าน target flags และ profile จาก /etc/env.d/gcc และการดูแลให้ข้อมูลนี้ถูกต้องเป็นหน้าที่ของระบบปฏิบัติการ
    ในระบบปฏิบัติการนี้ดูเหมือนการจัดการส่วนนั้นจะไม่ได้ทำอย่างถูกต้อง
    Gentoo ARM SBC ของผมที่ใช้สถาปัตยกรรม armv4 ที่เก่ากว่านั้นยังทำงานได้ดีต่อเนื่อง แม้จะอัปเดต gcc/clang รุ่นล่าสุด
    grep CTARGET /etc/env.d/gcc -r
    /etc/env.d/gcc/armv4tl-softfloat-linux-gnueabi-11.3.0:CTARGET="armv4tl-softfloat-linux-gnueabi"

    • /etc/env.d เป็น ไดเรกทอรีเฉพาะของ Gentoo สำหรับกำหนดตัวแปรสภาพแวดล้อมพื้นฐานของ session ผู้ใช้
      Clang ไม่มีความสามารถในการอ่านไดเรกทอรีนั้นเอง ดังนั้นไม่ควรสันนิษฐานว่า distribution อื่นก็มีเหมือนกัน
      แค่การตั้งค่า compiler ของ Gentoo อ่านตัวแปรสภาพแวดล้อม CTARGET เพื่อเลือกเป้าหมาย และ Gentoo ใช้ /etc/env.d ในการตั้งค่านั้นเท่านั้น
  • ในบทความไม่ได้บอกว่าเป็น Debian หรือ Raspbian และถ้าเป็น Debian ก็ไม่ได้บอกว่าเป็นพอร์ต armel หรือ armhf
    หากไม่มีข้อมูลนั้น การถกกันว่า LLVM compile เป็น instruction set แบบไหนก็ไม่ค่อยมีความหมาย เพราะมันขึ้นอยู่กับการตั้งค่า native target ของ LLVM
    อ้างอิงเพิ่มเติม llvm-toolchaim-snapshot ของ Debian ยังรองรับ armel ที่ใช้ ARMv5T เป็น baseline อยู่ อย่างไรก็ตามตอนนี้ OpenMP library ของ LLVM มี bug แยกต่างหาก ทำให้ build ไม่สำเร็จ

    • จุดที่แปลกคือ binary ของ Clang เองถูก compile ด้วย instruction set ที่เข้ากันได้กับ Pi B+ แต่กลับไม่ได้ตั้งเป้าไปยัง instruction set ที่เข้ากันได้กับ Pi B+
      เรื่องนี้แปลกจริง ๆ ไม่ได้ให้ใช้เป็น cross compiler ดังนั้นตามทฤษฎี host กับ target ควรเหมือนกัน
      ภาพระบบน่าจะเป็น Raspbian ดูไม่มีเหตุผลที่จะไม่สันนิษฐานแบบนั้น
  • ถ้ารู้ output ของคำสั่ง dpkg-architecture และเนื้อหาไฟล์ /etc/os-release น่าจะช่วยได้
    ถ้าไม่มีข้อมูลนั้นก็ยากที่จะคอมเมนต์อะไรที่มีประโยชน์

  • ชื่อเรื่องน่าเสียดายที่ดูเร้าอารมณ์เกินไป
    นี่คือ การเปลี่ยน default target และ clang ยังสามารถ build binary สำหรับ Pi B+ ได้อยู่
    แค่ต้องระบุสถาปัตยกรรมอย่างชัดเจน ดังนั้นน่าจะปรับชื่อเรื่องเล็กน้อยให้สื่อชัดขึ้นว่าเป็นการเปลี่ยน default setting

    • ถ้า build บนเครื่องเป้าหมายเองแล้วมันยังสร้าง binary สำหรับเครื่องเป้าหมายนั้นไม่ได้ ก็ไม่ได้ดูเร้าอารมณ์ขนาดนั้นนะ
  • น่าสนใจตรงที่ดูเหมือนเวลาจะ debug ว่าทำไมโปรแกรมบน ARM ถึงรันไม่ได้ ก็น่าจะใช้แนวทางประมาณนี้
    ผมมี Unity Linux build ที่รันใน container ไม่ได้ ต่อให้ส่ง flag amd64 ตอนรัน Docker แล้ว Unity mono ก็ยังพยายามเรียก system call ที่ใช้ไม่ได้
    ผมหาทางเลี่ยงได้แล้วจึงยังไม่ได้ debug เปิด developer mode แล้วเปลี่ยน build settings ให้ไม่ใช้ mono
    สักวันคงต้องกลับไปขุดดูเพื่อเรียนรู้เพิ่มเติม