1 คะแนน โดย GN⁺ 2024-04-07 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • หากต้องการนำ โค้ดเชิงตัวเลข Fortran ซึ่งเป็นทรัพย์สินการคำนวณทางวิทยาศาสตร์และวิศวกรรมที่มีมายาวนานมาไว้ในเบราว์เซอร์ จำเป็นต้องมีเส้นทางคอมไพล์ไปยัง WebAssembly และ webR ใช้ flang-new ของ LLVM ที่ผ่านการแพตช์
  • f2c, LFortran, Dragonegg, Classic Flang และ LLVM Flang ต่างก็ยังมีข้อจำกัดด้าน การรองรับ Fortran สมัยใหม่, สถาปัตยกรรมเป้าหมาย, และความสามารถในการบำรุงรักษา จึงยังไม่มีคำตอบมาตรฐานที่เรียบง่าย
  • LLVM Flang ยังไม่รองรับเป้าหมาย wasm32-unknown-emscripten โดยตรง จึงต้องเพิ่ม TargetWasm32 และในขั้นตอนลิงก์รันไทม์ก็มีปัญหาเรื่อง ขนาด long ที่ต่างกันระหว่างโฮสต์กับเป้าหมาย
  • เมื่อนำ flang-new ที่แพตช์แล้ว, Emscripten และไลบรารีสแตติกของ Fortran runtime มารวมกัน ก็สามารถเรียกใช้ซับรูทีน Fortran จาก C หรือ JavaScript ได้ และยังจัดการ PRINT, ALLOCATE, และอาร์กิวเมนต์ CHARACTER ได้ด้วย
  • มีการบิลด์ BLAS 3.12.0 และ LAPACK 3.12.0 เวอร์ชันอ้างอิงเป็นไลบรารีสแตติกของ WebAssembly เพื่อรันเดโม จำแนกตัวเลขลายมือ และ อินเตอร์โพเลชันพหุนาม ในเบราว์เซอร์

นำโค้ดเชิงตัวเลข Fortran เดิมมาไว้ในเบราว์เซอร์

  • Fortran เป็นภาษาที่เก่าแก่ เปิดตัวในปี 1957 แต่ถูกใช้มายาวนานในการคำนวณทางวิทยาศาสตร์และวิศวกรรม และ Fortran สมัยใหม่ก็หลุดพ้นจากข้อจำกัดรูปแบบตายตัวของ Fortran 77 ไปมากแล้ว
  • เป้าหมายคือคอมไพล์รูทีน Fortran สมัยใหม่เป็น WebAssembly เพื่อให้รันในเบราว์เซอร์ รับอาร์กิวเมนต์เชิงตัวเลข คำนวณด้วยรูทีน BLAS·LAPACK แล้วส่งผลลัพธ์กลับหรือพิมพ์ออกคอนโซล
  • แนวทางนี้ช่วยให้สภาพแวดล้อมการเขียนโปรแกรมระดับสูงที่พึ่งพา BLAS·LAPACK เช่น SciPy หรือ R สามารถถูกนำขึ้นเว็บได้
  • ไม่จำเป็นต้องเขียนรูทีนเชิงตัวเลขใหม่ด้วย JavaScript หรือ Rust แต่ใช้เครื่องมือและไลบรารีที่ผ่านการพิสูจน์แล้วซึ่งอิงกับ Fortran ได้เลย
  • โปรเจ็กต์ webR คอมไพล์โค้ด Fortran เป็น WebAssembly ด้วยคอมไพเลอร์ flang-new ของ LLVM ที่ผ่านการแพตช์
  • วิธีในปัจจุบันยังพึ่งพาการแฮ็กอยู่มาก และหากไม่มีความช่วยเหลือจากนักพัฒนาคอมไพเลอร์ที่มีประสบการณ์มากกว่า ก็ยากที่จะส่งการเปลี่ยนแปลงกลับเข้า LLVM

สถานะของเครื่องมือ Fortran→WebAssembly

  • ณ ปี 2024 มีเครื่องมือและ toolchain อยู่หลายตัว แต่ยังไม่มีวิธีที่เรียบง่ายและ ฟังก์ชันครบถ้วน
  • f2c

    • f2c แปลง Fortran 77 เป็นโค้ด C และ Emscripten สามารถคอมไพล์โค้ดนั้นต่อเป็น WebAssembly ได้
    • Pyodide ใช้วิธีนี้เวลาคอมไพล์แพ็กเกจ Python ที่มีโค้ด Fortran รวมอยู่
    • แม้แต่ในโรดแมปของ Pyodide เอง วิธีนี้ก็ถูกประเมินว่า “ทำงานได้ไม่ดีนัก”
    • มันไม่เหมาะกับโค้ด Fortran สมัยใหม่ และหลังการแปลงก็มักยังเกิดข้อผิดพลาดร้ายแรงและต้องแพตช์จำนวนมาก
  • LFortran

    • LFortran มีความสามารถเพิ่มขึ้นมากในช่วงไม่กี่ปีที่ผ่านมา และคอมไพล์ไปยัง WebAssembly ได้โดยตรง
    • แต่ยังอยู่ใน ขั้นอัลฟา และนักพัฒนาก็ระบุเองว่าคาดว่าจะมีปัญหาเมื่อคอมไพล์โค้ดจริง
    • บางโปรเจ็กต์อย่าง MINPACK คอมไพล์ได้ แต่โปรเจ็กต์ขนาดใหญ่กว่านั้นอาจล้มเหลวเพราะยังไม่รองรับสเปก Fortran ทั้งหมด
    • เป้าหมายการพัฒนาคือรองรับ Fortran 2018 ทั้งหมด และฟีเจอร์เด่นคือ REPL สำหรับ Fortran แบบโต้ตอบคล้าย Jupyter
  • Dragonegg

    • Dragonegg เป็นปลั๊กอินของ GCC ที่ใช้ฟรอนต์เอนด์ของ GCC เพื่อส่งออก LLVM IR
    • มันสามารถใช้ LLVM backend เพื่อสร้างเอาต์พุต WebAssembly ได้ และเป็นวิธีที่ webR ใช้คอมไพล์ซอร์ส Fortran เป็น WebAssembly ครั้งแรก
    • แต่เวอร์ชันที่รองรับล่าสุดคือ gcc-4.8 และ llvm-3.3 จึงต้องใช้ GCC·LLVM ที่เก่ามาก
    • ผู้ใช้ส่วนใหญ่จึงต้องพึ่ง VM หรือ Docker container และ LLVM IR ที่ Dragonegg ส่งออกก็ยังต้องผ่านการประมวลผลเพิ่มเติมเพื่อให้สร้างเอาต์พุต WebAssembly ได้
    • ในปี 2020 นี่แทบเป็นวิธีเดียวที่ใช้ได้จริงในการคอมไพล์โค้ด Fortran เป็น WebAssembly
  • Classic Flang

    • Classic Flang เป็นคอมไพเลอร์ Fortran สำหรับ LLVM ที่อิงกับ pgfortran ของ PGI/NVIDIA ซึ่งถูกโอเพนซอร์ส
    • มันไม่รองรับเอาต์พุต 32 บิต จึงใช้กับเป้าหมาย wasm32 ไม่ได้
    • Firefox, Chrome และ Node รองรับ wasm64 ณ เวลาที่เขียน แต่ยังถูกซ่อนไว้หลัง feature flag
    • เอกสารของโปรเจ็กต์เองก็ระบุว่าการเลือก Classic Flang สำหรับโปรเจ็กต์ใหม่อาจไม่ใช่ความคิดที่ดีนัก
  • LLVM Flang

    • LLVM Flang เป็นโปรเจ็กต์ที่เขียนฟรอนต์เอนด์ Fortran สำหรับ LLVM ขึ้นใหม่ทั้งหมด และถูกรวมเข้าในโปรเจ็กต์ LLVM ตั้งแต่ LLVM 11
    • มันยังไม่ถือว่าพร้อมสำหรับ production แต่ flang-new เวอร์ชันก่อน production ก็ใช้งานได้ดีพอสมควรกับการคอมไพล์โค้ด Fortran จริง
    • ในสถานะปกติ มันยังสร้างเอาต์พุต WebAssembly ไม่ได้
    • แต่ด้วยการออกแบบแบบโมดูลาร์ของ LLVM จึงสามารถใช้ฟรอนต์เอนด์ Flang ร่วมกับ WebAssembly backend ของ LLVM ได้
    • ในปี 2020 ก็พอทำได้เช่นกัน แต่ต้องใช้แพตช์ LLVM ที่ใหญ่กว่าเดิม, การแทรกรูทีนคณิตศาสตร์แบบกำหนดเอง, และขั้นตอนคอมไพล์หลายชั้น
    • ปัจจุบัน ด้วยการพัฒนาฟรอนต์เอนด์ flang-new จึงสามารถสร้างคอมไพเลอร์ Fortran→WebAssembly ได้ด้วยการแก้ซอร์ส LLVM เพียงเล็กน้อย

บิลด์ LLVM Flang สำหรับ WebAssembly

  • LLVM ที่ติดตั้งผ่านแพ็กเกจเมเนเจอร์อาจไม่มีไบนารี flang-new รวมมาให้
    • ตัวอย่างเช่น LLVM v17.0.6 จาก Homebrew บน macOS ไม่พบคำสั่ง flang-new
  • เนื่องจากต้องแก้ซอร์สของ LLVM Flang จึงทำการบิลด์ซอร์ส LLVM v18.1.1 ด้วยตนเอง
  • การตั้งค่า CMake กำหนด target triple เริ่มต้นเป็น wasm32-unknown-emscripten และเปิดใช้งาน target WebAssembly กับโปรเจ็กต์ clang;flang;mlir
  • เมื่อบิลด์เสร็จแล้ว สามารถตรวจสอบข้อมูลต่อไปนี้ได้จาก build/bin/flang-new --version
    • เวอร์ชัน: flang-new version 18.1.1
    • เป้าหมาย: wasm32-unknown-emscripten
    • โมเดลเธรด: posix

ปัญหาแรก: ยังไม่มีการติดตั้งใช้งาน target wasm32

  • เมื่อลองคอมไพล์ซับรูทีน Fortran ง่าย ๆ foo.f08 ด้วย flang-new จะพบข้อผิดพลาดดังนี้
    • not yet implemented: target not implemented
  • สาเหตุคือใน flang-new ยังไม่ได้ติดตั้งใช้งาน target triple wasm32-unknown-emscripten
  • วิธีแก้คือแพตช์เพิ่มคุณลักษณะเป้าหมาย TargetWasm32 ใน flang/lib/Optimizer/CodeGen/Target.cpp
    • ตั้งค่าความกว้างเริ่มต้นเป็น 32
    • กำหนด marshalling สำหรับแปลงอาร์กิวเมนต์และชนิดคืนค่าของจำนวนเชิงซ้อนให้เป็นชนิด LLVM ฝั่ง WebAssembly
    • เชื่อม TargetWasm32 เข้ากับ branch ของ llvm::Triple::ArchType::wasm32
  • หลังแพตช์แล้วบิลด์ใหม่ ซอร์ส Fortran ก็จะคอมไพล์เป็นออบเจ็กต์ WebAssembly ได้
    • ผลของ file foo.o: WebAssembly (wasm) binary module version 0x1 (MVP)
    • สามารถตรวจสอบสัญลักษณ์ foo_ ได้จาก llvm-nm foo.o

เรียกซับรูทีน Fortran จาก C และ JavaScript

  • รูทีน Fortran โดยทั่วไปส่งอาร์กิวเมนต์แบบ อ้างอิง และสามารถประกาศวิธีการใช้อาร์กิวเมนต์ด้วย INTENT() ได้
  • ตัวอย่างซับรูทีน Fortran foo รับอาร์กิวเมนต์จำนวนเต็ม x, y, z และทำ z = x + y
  • ในการบิลด์แบบเนทีฟ เมื่อรัน gfortran -c foo.f08 -o foo.o ชื่อสัญลักษณ์อาจมีขีดล่างต่อท้ายเช่น foo_
  • เมื่อต้องเรียกจาก C ต้องประกาศสัญลักษณ์ภายนอกเป็น extern void foo_(int*, int*, int*); และส่งอาร์กิวเมนต์เป็นแอดเดรส
  • บน WebAssembly สามารถใช้ Emscripten ลิงก์ foo.o ที่สร้างด้วย flang-new เข้ากับโค้ด C ได้
    • emcc main.c foo.o -o main.js
    • ผลลัพธ์จาก node main.js: 1 + 1 = 2
  • เรียกจาก JavaScript โดยตรง

    • สามารถเรียกซับรูทีน Fortran จาก JavaScript โดยตรงได้โดยไม่ต้องมีโค้ด C
    • ในขั้นตอนลิงก์ของ Emscripten ให้ export _foo_, _malloc, _free
    • emcc foo.o -sEXPORTED_FUNCTIONS=_foo_,_malloc,_free -o foo.js
    • JavaScript จะจัดสรรพื้นที่เก็บจำนวนเต็มด้วย Module._malloc() เขียนค่าลงใน Module.HEAPU32 แล้วเรียก Module._foo_(x, y, z)
    • ผลการรันมีดังนี้
    • x = 123
    • y = 456
    • x + y = 579
    • ในเบราว์เซอร์ สามารถโหลด foo.js และ standalone.js ใน HTML เพื่อดูผลลัพธ์เดียวกันได้จาก JavaScript console

ปัญหาที่สอง: ไลบรารีรันไทม์ของ Fortran

  • หากบิลด์ซับรูทีน Fortran ที่มี PRINT *, "Hello, World!" จะเกิดข้อผิดพลาดในขั้นตอนลิงก์ว่าหาสัญลักษณ์รันไทม์ไม่เจอ
    • _FortranAioBeginExternalListOutput
    • _FortranAioOutputAscii
    • _FortranAioEndIoStatement
  • สาเหตุคือยังไม่ได้คอมไพล์ไลบรารีรันไทม์ของ LLVM Fortran สำหรับ WebAssembly
  • ไลบรารีรันไทม์เขียนด้วย C++ อยู่ใน llvm-project/flang/runtime ของซอร์สทรี LLVM
  • หากบิลด์ซอร์สรันไทม์ด้วย em++ และ emar ของ Emscripten ก็จะสร้างไลบรารีสแตติก build/flang/runtime/libFortranRuntime.a ได้
  • เมื่อลิงก์ไลบรารีนี้เข้าไป การบิลด์ Hello, World! จะเดินหน้าต่อได้ แต่ช่วงแรกจะมีคำเตือนเรื่องฟังก์ชันซิกเนเจอร์ไม่ตรงกัน

ปัญหาที่สาม: ขนาด long ต่างกันระหว่างโฮสต์กับเป้าหมาย

  • เมื่อลิงก์ hello.o กับไลบรารีรันไทม์ของ Fortran จะมีคำเตือนว่าซิกเนเจอร์ของ _FortranAioOutputAscii ไม่ตรงกัน
    • ฝั่งออบเจ็กต์ Fortran คาดหวัง (i32, i32, i64) -> i32
    • ฝั่งรันไทม์ที่บิลด์ด้วย Emscripten ถูกกำหนดเป็น (i32, i32, i32) -> i32
  • บน WebAssembly ชนิดของอาร์กิวเมนต์และค่าคืนของสัญลักษณ์ที่นิยามข้ามหลาย compilation unit ต้องสอดคล้องกัน
  • ปัญหานี้ไม่ได้จบแค่คำเตือน เพราะเมื่อรันบน Node จะล้มเหลวด้วย RuntimeError: unreachable
  • ใน RTBuilder.h ของ LLVM Flang มีคอมเมนต์ TODO ว่าการใช้ sizeof นั้นตั้งสมมติฐานว่า build == host == target
  • บนโฮสต์สมัยใหม่ตระกูล Unix แบบ 64 บิต sizeof(long) มีค่า 8 ไบต์ แต่บนเป้าหมาย wasm32-unknown-emscripten ควรเป็น 4 ไบต์
  • เมื่อส่งอาร์กิวเมนต์ชนิด CHARACTER ของ Fortran เข้าไปยังฟังก์ชันหรือซับรูทีน อาจมีการเพิ่ม อาร์กิวเมนต์ซ่อนเร้น สำหรับส่งความยาวสตริง
  • ในไลบรารีรันไทม์ของ Fortran อาร์กิวเมนต์ความยาวนี้ประกาศเป็น size_t และผ่าน chain ของ typedef จนเท่ากับ unsigned long
  • ความต่างของขนาดอาร์กิวเมนต์ซ่อนเร้นนี้เองที่ทำให้เกิดความไม่ตรงกันระหว่าง i64 และ i32

แพตช์ชั่วคราว: บังคับให้ใช้ค่า 4 ไบต์

  • วิธีแก้ที่เหมาะสมที่สุดคือให้ flang-new ส่งออก i32 หรือ i64 ที่ตรงกับสถาปัตยกรรมและ data model ของเป้าหมาย โดยไม่ขึ้นกับโฮสต์ แม้ในกรณี cross compile
  • แต่ตอนนี้ใช้แพตช์ที่ hardcode ให้ขนาด long เป็น 4 ไบต์ตาม wasm32 และ Emscripten
  • รายละเอียดของแพตช์มีสองส่วน
    • ใน RTBuilder.h บังคับ model type ของ long และ unsigned long ให้เป็น 8 * 4 แทน 8 * sizeof(...)
    • ใน CodeGen.cpp สร้างอาร์กิวเมนต์ของการเรียก malloc() เป็นจำนวนเต็ม 32 บิตแทน 64 บิต และ cast ขนาดการจองหน่วยความจำเป็น i32
  • การเปลี่ยนแปลงนี้ยังช่วยแก้การจัดสรรหน่วยความจำแบบไดนามิกที่อิงกับ ALLOCATE() ซึ่งถูกเพิ่มเข้ามาใน Fortran 90 ด้วย
  • หลังบิลด์ใหม่แล้ว เมื่อนำ hello.f08 และ hello.c ไปลิงก์กับไลบรารีรันไทม์ ก็จะบิลด์ผ่านโดยไม่มีคำเตือน และเมื่อรันบน Node จะได้ผลลัพธ์ดังนี้
    • Hello, World!

บิลด์ BLAS เป็น WebAssembly

  • BLAS คือชุดรูทีนระดับล่างสำหรับการดำเนินการทั่วไปของพีชคณิตเชิงเส้น เช่น การคูณเมทริกซ์และเวกเตอร์
  • รูทีน BLAS ดั้งเดิมเผยแพร่ครั้งแรกในปี 1979 และเป็นมาตรฐานโดยพฤตินัยในงานคำนวณเชิงตัวเลข
  • BLAS 3.12.0 เวอร์ชันอ้างอิงเขียนด้วย Fortran 90 และดาวน์โหลดได้จาก netlib
  • ใน make.inc มีการกำหนดเครื่องมือดังนี้
    • FC = ../build/bin/flang-new
    • FFLAGS = -O2
    • AR = emar
    • RANLIB = emranlib
  • ผลลัพธ์ของการบิลด์คือไลบรารีสแตติก blas_LINUX.a
  • รูทีน Fortran ตัวอย่าง bar เรียกใช้รูทีน BLAS ระดับ 2 ZGEMV()
  • ZGEMV() ใช้สำหรับคำนวณเมทริกซ์-เวกเตอร์เชิงซ้อน โดยตัวอย่างนี้ใช้อาร์กิวเมนต์ COMPLEX(KIND=8) และอาร์กิวเมนต์ตั้งค่าชนิด CHARACTER ค่า 'N'
  • โปรแกรม C จะสร้างอาร์เรย์เชิงซ้อน ส่งเข้าไปยังรูทีน Fortran แล้วพิมพ์ผลลัพธ์ออกมา
  • ผลลัพธ์เมื่อรันบน Node มีดังนี้
    • Y[0]: 23.000000 + 6.000000i
    • Y[1]: 18.000000 + 10.000000i
    • Y[2]: 6.000000 + 16.000000i
  • ผลลัพธ์นี้ยืนยันได้ว่า BLAS ที่คอมไพล์จากซอร์ส Fortran 90 สามารถทำงานบน WebAssembly ได้

ตัวอย่างบนเบราว์เซอร์: ตัวจำแนกตัวเลขลายมือ

  • เดโมนี้ใช้โครงข่ายประสาทเทียม Multilayer Perceptron (MLP) เพื่อจำแนกตัวเลข 0–9 ที่ผู้ใช้เขียนด้วยมือ
  • ผู้ใช้สามารถวาดตัวเลขด้วยเมาส์หรือหน้าจอสัมผัส และกราฟด้านขวาจะแสดงความน่าจะเป็นสัมพัทธ์ที่เครือข่ายคาดการณ์
  • น้ำหนักของโมเดลถูกฝึกล่วงหน้าด้วย Python แต่การจำแนกจะทำในเบราว์เซอร์ขณะรันจริงด้วย JavaScript และ WebAssembly
  • กระบวนการจำแนกของ MLP โดยพื้นฐานคือการบวกและคูณเมทริกซ์-เวกเตอร์ซ้ำ ๆ
  • งานคำนวณหนักถูกจัดการโดยซับรูทีน Fortran ตัวเดียวที่ใช้รูทีน BLAS ระดับ 2 DGEMV()

บิลด์ LAPACK เป็น WebAssembly

  • LAPACK เป็นไลบรารีซอฟต์แวร์สำหรับแก้ปัญหาพีชคณิตเชิงเส้นเชิงตัวเลข โดยสร้างอยู่บน BLAS
  • LAPACK 3.12.0 เวอร์ชันอ้างอิงจัดหาโดย netlib และเผยแพร่ภายใต้ไลเซนส์ BSD แบบดัดแปลง
  • ให้คัดลอก make.inc.example เป็น make.inc แล้วแก้ค่าต่อไปนี้
    • กำหนด FC เป็นพาธเต็มของ flang-new ที่บิลด์ไว้
    • FFLAGS = -O2
    • AR = emar
    • RANLIB = emranlib
    • TIMER = INT_CPU_TIME
  • คำสั่ง make lib จะสร้างไลบรารีสแตติกของ WebAssembly ชื่อ liblapack.a
  • จากนั้นก็สามารถเรียกใช้รูทีนของ LAPACK ได้ในลักษณะคล้ายกับตัวอย่าง BLAS

ตัวอย่างบนเบราว์เซอร์: อินเตอร์โพเลชันพหุนามด้วยพีชคณิตเชิงเส้น

  • เดโมนี้หาพหุนามอินเตอร์โพเลชันสำหรับชุดของจุด และแสดงให้เห็นว่ารูทีน LAPACK ทำงานในเบราว์เซอร์ได้
  • เมื่อผู้ใช้คลิกบนกราฟเพื่อเพิ่มจุดใหม่ ระบบจะหาพหุนามอินเตอร์โพเลชันที่ผ่านทุกจุด
  • วิธีที่ใช้คือ Vandermonde’s method
  • สมการพีชคณิตเชิงเส้นที่ได้จากวิธีนี้จะถูกแก้เชิงตัวเลขด้วยรูทีน DGELS() ของ LAPACK
  • สามารถหาพหุนามดีกรี n-1 ที่ผ่านจุดข้อมูล n จุดได้อย่างแม่นยำเสมอ
  • เมื่อ n มีค่ามากขึ้น อาจเกิดปรากฏการณ์ Runge ที่พหุนามแกว่งอย่างรุนแรงระหว่างจุดข้อมูลที่ต่อเนื่องกัน และสามารถหลีกเลี่ยงได้ด้วย spline interpolation

งานที่ยังเหลือและเครื่องมือที่มีให้

  • เมื่อใช้ LLVM Flang ที่ผ่านการแพตช์ ก็สามารถคอมไพล์โค้ด Fortran สมัยใหม่เป็นออบเจ็กต์ WebAssembly ได้
  • ข้อดีของแนวทางนี้คือสามารถใช้เครื่องมือและไลบรารี Fortran ที่มีอยู่แล้วได้ โดยไม่ต้องเขียนอัลกอริทึมเชิงตัวเลขสำหรับเว็บขึ้นใหม่ด้วย JavaScript
  • หาก flang-new รองรับ WebAssembly อย่างเป็นทางการ ภาระในการดูแล LLVM fork สำหรับ webR และแพ็กเกจ R ก็จะลดลง
  • ตอนนี้ยังต้องการแนวทางที่ดีกว่านี้เพื่อแก้ปัญหา LLVM Flang และ cross compile ให้ถูกต้องสำหรับทุกเป้าหมาย
  • สำหรับผู้ใช้ที่ไม่สะดวกหรือไม่ต้องการบิลด์ LLVM Flang เอง มี Docker container ของไบนารี LLVM Flang ที่แพตช์แล้ว ให้ใช้งานผ่าน GitHub Container Registry

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

 
GN⁺ 2024-04-07
ความคิดเห็นบน Hacker News
  • ขอเสริมบริบทเล็กน้อย การ สำรวจ Fortran ครั้งนี้เป็นส่วนหนึ่งของงาน WebR อันยอดเยี่ยมที่ George กำลังทำเพื่อให้ R รันในเบราว์เซอร์ได้
    ในซอร์สของ R มีโค้ด Fortran อยู่ค่อนข้างมาก และเท่าที่รู้ เดิมที WebR ใช้ f2c คอมไพล์ Fortran เป็น C ก่อน แล้วจึงคอมไพล์ C นั้นเป็น wasm
    ด้วยแพตช์ LLVM Flang ทำให้สามารถบิลด์ WebR ด้วยคอมไพเลอร์ Fortran จริง ๆ ได้แล้ว
    George ไม่ได้พูดตรง ๆ ในบล็อกโพสต์ แต่เคยบอกว่าอยากให้ Flang รับแพตช์นี้ หรือไม่ก็อิมพลีเมนต์ด้วยวิธีที่ดีกว่า
    ถ้าเป็นเช่นนั้นก็ไม่ต้องคอยดูแลแพตช์แยก และ Flang แบบไม่แก้ไขก็จะคอมไพล์ไปเป็น wasm ได้ ซึ่งเป็นประโยชน์ต่อโปรเจกต์อื่น ๆ ที่ใช้ Fortran ด้วย
    https://docs.r-wasm.org/webr/latest/

    • ยินดีรับ pull request เสมอ (https://github.com/llvm/llvm-project) และถ้าต้องการความช่วยเหลือก็สามารถติดต่อชุมชนนักพัฒนา LLVM Fortran ได้ (https://discourse.llvm.org/c/subprojects/flang/33)
      แต่ตอนนี้ผมต้องโฟกัสกับงานที่จำเป็นต่อการพัฒนาผลิตภัณฑ์ Fortran ของ Nvidia ให้เสร็จ จึงไม่มีเวลาเหลือสำหรับงานแบบนี้
    • การย้าย F77 ไปเป็น JavaScript ด้วยการแปลงจากซอร์สถึงซอร์สก็ทำได้ค่อนข้างดีอยู่แล้ว แต่ WASM ดีกว่า
  • เมื่อ 20 ปีก่อนเคยทำงานเกี่ยวกับ การคอมไพล์ FORTRAN ที่ Xilinx สิ่งเดียวที่จำได้คือในไฟล์เฮดเดอร์ f2c.h มีนิยาม barf อยู่
    /* f2c.h -- Standard Fortran to C header file /
    /* barf [ba:rf] 2. "He suggested using FORTRAN, and everybody barfed."
    (https://www.netlib.org/clapack/f2c.h)

    • การที่ผมเขียน FORTRAN เป็นตัวพิมพ์ใหญ่ทั้งหมด มันบอกอะไรเกี่ยวกับตัวผมหรือเปล่า? ในสายตาผม Fortran ดูแปลก ๆ
  • ชอบมากที่ใช้ ตัวอย่างไม่ธรรมดาที่เรียบง่ายที่สุด เป็นวิธีอธิบาย
    บทความตั้งอยู่บนปัญหาที่เป็นรูปธรรมอย่าง “เรียกฟังก์ชัน BLAS จาก JavaScript” เลยรู้สึกว่าได้เรียนรู้อะไรเยอะ และเป็นบทความที่ยอดเยี่ยม

  • ไม่รู้ว่าควรทึ่งหรือควรตะลึงดี และอาจจะทั้งสองอย่าง
    เวลาบิลด์ f18 แนะนำให้ใช้ ซอร์สล่าสุดของ llvm-project/main
    โปรเจกต์เคลื่อนเร็วมาก ถ้าเสียเวลาไปดีบักปัญหาที่แก้ไปแล้ว หรือพลาดฟีเจอร์ที่อิมพลีเมนต์แล้ว ก็จะเป็นการเสียเวลา

    • ผมไม่เข้าใจซอร์สของ LLVM พอ เลยจับใจความได้ยาก
      นี่คือกำลังทำพอร์ต WebAssembly เพื่อให้ intermediate code ไปถึงจุดที่ทำงานกับ Fortran ได้ใช่ไหม?
  • ผมไม่ค่อยรู้เรื่องการพัฒนา WebAssembly
    ในมุมผู้บริโภค ตอนนี้ WebAssembly ให้อะไรกับเราบ้าง? หรือมันใกล้เคียงกับงานวางรากฐานเพื่ออนาคตที่โปรแกรมจะพกพาได้อย่างแท้จริงมากกว่า?
    เคยได้ยินว่าอุปกรณ์ WebAssembly ทำให้จำกัดการเข้าถึงอย่างเครือข่ายหรือไฟล์ได้ง่ายขึ้น แต่ไม่รู้ว่านี่เป็นแค่ทฤษฎีหรืออิมพลีเมนต์แล้ว

    • โดยพื้นฐานแล้ว Wasm คือ virtual machine และคล้าย JVM มากในแง่ความพกพาได้
      ความแตกต่างหลักคือ Wasm เองไม่มีทั้ง standard library และไม่ได้เปิดเผยฟังก์ชันอินพุต/เอาต์พุต
      ดังนั้นโฮสต์ ซึ่งก็คือคุณที่สร้าง VM เอง สามารถเปิดเผยฟังก์ชันให้ไบนารี Wasm นำไปใช้ได้ และไบนารี Wasm จะเข้าถึงโลกภายนอกได้ผ่านฟังก์ชันเหล่านั้นเท่านั้น
      ข้อดีอีกอย่างคือรูปแบบไบนารีไม่ใช่ของปิด และมีสเปก ทำให้ใคร ๆ ก็อิมพลีเมนต์ Wasm VM ได้
      แต่ตอนนี้ยังถือว่าสถานะยังไม่ดีนัก ยังเร็วเกินไป มีฟีเจอร์ใหม่จำนวนมากที่กำลังถูกทำให้เป็นมาตรฐานโดยกลุ่มคล้าย W3C และกระบวนการก็ช้ามาก
    • ถ้าคุณเป็นนักพัฒนาหรือเป็นฝ่ายที่ปล่อยผลิตภัณฑ์ และต้องการ sandboxing ที่แข็งแรง WASM ก็ใกล้เคียงกับตัวเลือกที่ดีที่สุดที่ใช้ได้ตอนนี้
      นอกจากนี้ยังมีวิธีดีพลอยไปยังเป้าหมายส่วนใหญ่หรือทำ cross-compile ได้
    • ถ้าอิมพลีเมนต์ถูกต้อง ฝั่งลูกค้าก็ไม่ควรสังเกตเห็น
      คล้ายกับที่ปกติเราไม่รู้และไม่ได้สนใจมากนักว่า CPU ของคอมพิวเตอร์เป็น ARM หรือ x86
      ดังนั้นถ้าคุณไม่ได้สนใจรายละเอียดว่าโค้ดรันแบบ native หรือรันบน VM อย่าง JVM, .NET, WASM ก็ยากจะบอกว่ามันให้อะไรเพิ่มกว่าวิธีอื่น
      โดยทั่วไปเรามักเห็นแต่กรณีแย่ ๆ แล้วมันก็กลายเป็นมีมอย่าง “โปรแกรม Electron ทุกตัวคือปีศาจตัวบวมที่กินทรัพยากร และแอป native ทุกตัวคือสิ่งมหัศจรรย์แห่งวิศวกรรมซอฟต์แวร์ที่มีประสิทธิภาพโดยอัตโนมัติ”
  • เสียดาย ถ้าเก็บ โค้ด Fortran 78 ที่เขียนไว้เมื่อปี 1981/82 ไว้ ก็คงได้ลองทดสอบว่ามันรันบนนี้ได้ไหม
    มันเป็นตัวจัดรูปแบบซอร์สโค้ดของภาษาโปรแกรม Jovial ซึ่งจริง ๆ ไม่ใช่งานที่ควรทำด้วย Fortran แต่ตอนนั้นมีทางเลือกแค่นั้น

    • เคยทำงานที่ Hughes ใน Orange County หรือเปล่า?
  • มี ระบบนิเวศ linear algebra ที่พร้อมใช้งานระดับ production สำหรับ JavaScript อยู่บ้างไหม?
    ลองค้นดูแล้วส่วนใหญ่เจอแต่พอร์ต JavaScript ของไลบรารีที่คุ้นเคยซึ่งอายุราว 10 ปี เช่นพอร์ตผ่าน emscripten เลยสงสัยว่าผมพลาดอะไรไปหรือเปล่า

    • มีอะไรที่เทียบเท่า BLAS บน WebGPU หรือ WebNN ไหม?
  • แปลกที่ไม่ได้ลงลึกเรื่อง LFortran มากกว่านี้
    มีตัวอย่าง WASM ที่ยอดเยี่ยมและน่าทึ่งซึ่งรันออนไลน์ได้ด้วย
    https://dev.lfortran.org/

    • ในบทความเขียนไว้ว่า compiler ของ LFortran พัฒนาขึ้นมากในช่วงไม่กี่ปีที่ผ่านมา
      ในปี 2020 ยังขาดฟีเจอร์ไปมาก และรองรับเพียง subset ขนาดเล็กมากของ Fortran แต่ตอนนี้รองรับฟีเจอร์ของภาษาที่กว้างขึ้นมาก และสามารถคอมไพล์โค้ด Fortran ได้ค่อนข้างมาก
      ยังสามารถคอมไพล์เป็น WebAssembly ได้แบบ native ด้วย
      อย่างไรก็ตาม นักพัฒนาระบุว่ายังมีจุดที่ยังไม่เรียบร้อยสำหรับการใช้งาน LFortran โปรเจกต์นี้ปัจจุบันถือว่าอยู่ในขั้น alpha และอาจเกิดปัญหาเมื่อคอมไพล์โค้ดจริง
      โปรเจกต์บางตัวอย่างเช่น MINPACK สามารถคอมไพล์ได้สำเร็จ แต่เพราะยังไม่รองรับสเปกทั้งหมดของ Fortran โปรเจกต์ขนาดใหญ่จำนวนมากจึงยังคอมไพล์ไม่ได้
      นักพัฒนา LFortran ตั้งเป้ารองรับ Fortran 2018 อย่างสมบูรณ์ และฟีเจอร์ที่โดดเด่นคือ REPL ของ Fortran แบบโต้ตอบได้คล้าย Jupyter
      หากพัฒนาต่อไปอีกสักไม่กี่ปี ก็น่าจะเป็นตัวเลือกที่ยอดเยี่ยมสำหรับการคอมไพล์โค้ด Fortran ไปใช้กับ WebAssembly
      นอกจากนี้ยังบอกให้ดูเดโม LFortran ที่ https://dev.lfortran.org ซึ่งน่าประทับใจมาก แต่การลองครั้งแรกของผมที่เปลี่ยน x * 2 เป็น x * 3 นั้น code generator ปัจจุบันยังไม่รองรับ
  • ยังมี Fortran บน .NET และ Java ด้วย
    https://www.silverfrost.com/14/ftn95/ftn95_fortran_95_for_microsoft_dotnet_features.aspx
    https://dl.acm.org/doi/10.1145/376656.376833

  • ตอนทำงานเกี่ยวกับ https://medium.com/@tomasreimers/compiling-tensorflow-for-the-browser-f3387b8e1e1c ผมคิดว่าโชคดีจริง ๆ ที่ TensorFlow ใช้ Eigen ไม่ใช่ BLAS/Lapack ซึ่งเป็นไลบรารีคณิตศาสตร์ยอดนิยมที่เขียนด้วย Fortran
    ไม่อย่างนั้นงานคงเยอะกว่านี้มาก