Fortran ที่ทำงานบน WebAssembly
(gws.phd)- หากต้องการนำ โค้ดเชิงตัวเลข 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 อยู่หลายตัว แต่ยังไม่มีวิธีที่เรียบง่ายและ ฟังก์ชันครบถ้วน
-
f2cf2cแปลง 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 สำหรับโปรเจ็กต์ใหม่อาจไม่ใช่ความคิดที่ดีนัก
- Classic Flang เป็นคอมไพเลอร์ Fortran สำหรับ LLVM ที่อิงกับ
-
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 v17.0.6 จาก Homebrew บน macOS ไม่พบคำสั่ง
- เนื่องจากต้องแก้ซอร์สของ LLVM Flang จึงทำการบิลด์ซอร์ส LLVM v18.1.1 ด้วยตนเอง
- การตั้งค่า CMake กำหนด target triple เริ่มต้นเป็น
wasm32-unknown-emscriptenและเปิดใช้งาน targetWebAssemblyกับโปรเจ็กต์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 triplewasm32-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 = 123y = 456x + 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
- ฝั่งออบเจ็กต์ Fortran คาดหวัง
- บน 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-newFFLAGS = -O2AR = emarRANLIB = emranlib
- ผลลัพธ์ของการบิลด์คือไลบรารีสแตติก
blas_LINUX.a - รูทีน Fortran ตัวอย่าง
barเรียกใช้รูทีน BLAS ระดับ 2ZGEMV() ZGEMV()ใช้สำหรับคำนวณเมทริกซ์-เวกเตอร์เชิงซ้อน โดยตัวอย่างนี้ใช้อาร์กิวเมนต์COMPLEX(KIND=8)และอาร์กิวเมนต์ตั้งค่าชนิดCHARACTERค่า'N'- โปรแกรม C จะสร้างอาร์เรย์เชิงซ้อน ส่งเข้าไปยังรูทีน Fortran แล้วพิมพ์ผลลัพธ์ออกมา
- ผลลัพธ์เมื่อรันบน Node มีดังนี้
Y[0]: 23.000000 + 6.000000iY[1]: 18.000000 + 10.000000iY[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 = -O2AR = emarRANLIB = emranlibTIMER = 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 ความคิดเห็น
ความคิดเห็นบน 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/
แต่ตอนนี้ผมต้องโฟกัสกับงานที่จำเป็นต่อการพัฒนาผลิตภัณฑ์ Fortran ของ Nvidia ให้เสร็จ จึงไม่มีเวลาเหลือสำหรับงานแบบนี้
เมื่อ 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)
ชอบมากที่ใช้ ตัวอย่างไม่ธรรมดาที่เรียบง่ายที่สุด เป็นวิธีอธิบาย
บทความตั้งอยู่บนปัญหาที่เป็นรูปธรรมอย่าง “เรียกฟังก์ชัน BLAS จาก JavaScript” เลยรู้สึกว่าได้เรียนรู้อะไรเยอะ และเป็นบทความที่ยอดเยี่ยม
[1] https://en.m.wikipedia.org/wiki/The_Theoretical_Minimum
ไม่รู้ว่าควรทึ่งหรือควรตะลึงดี และอาจจะทั้งสองอย่าง
เวลาบิลด์ f18 แนะนำให้ใช้ ซอร์สล่าสุดของ llvm-project/main
โปรเจกต์เคลื่อนเร็วมาก ถ้าเสียเวลาไปดีบักปัญหาที่แก้ไปแล้ว หรือพลาดฟีเจอร์ที่อิมพลีเมนต์แล้ว ก็จะเป็นการเสียเวลา
นี่คือกำลังทำพอร์ต WebAssembly เพื่อให้ intermediate code ไปถึงจุดที่ทำงานกับ Fortran ได้ใช่ไหม?
ผมไม่ค่อยรู้เรื่องการพัฒนา WebAssembly
ในมุมผู้บริโภค ตอนนี้ WebAssembly ให้อะไรกับเราบ้าง? หรือมันใกล้เคียงกับงานวางรากฐานเพื่ออนาคตที่โปรแกรมจะพกพาได้อย่างแท้จริงมากกว่า?
เคยได้ยินว่าอุปกรณ์ WebAssembly ทำให้จำกัดการเข้าถึงอย่างเครือข่ายหรือไฟล์ได้ง่ายขึ้น แต่ไม่รู้ว่านี่เป็นแค่ทฤษฎีหรืออิมพลีเมนต์แล้ว
ความแตกต่างหลักคือ Wasm เองไม่มีทั้ง standard library และไม่ได้เปิดเผยฟังก์ชันอินพุต/เอาต์พุต
ดังนั้นโฮสต์ ซึ่งก็คือคุณที่สร้าง VM เอง สามารถเปิดเผยฟังก์ชันให้ไบนารี Wasm นำไปใช้ได้ และไบนารี Wasm จะเข้าถึงโลกภายนอกได้ผ่านฟังก์ชันเหล่านั้นเท่านั้น
ข้อดีอีกอย่างคือรูปแบบไบนารีไม่ใช่ของปิด และมีสเปก ทำให้ใคร ๆ ก็อิมพลีเมนต์ Wasm VM ได้
แต่ตอนนี้ยังถือว่าสถานะยังไม่ดีนัก ยังเร็วเกินไป มีฟีเจอร์ใหม่จำนวนมากที่กำลังถูกทำให้เป็นมาตรฐานโดยกลุ่มคล้าย W3C และกระบวนการก็ช้ามาก
นอกจากนี้ยังมีวิธีดีพลอยไปยังเป้าหมายส่วนใหญ่หรือทำ cross-compile ได้
คล้ายกับที่ปกติเราไม่รู้และไม่ได้สนใจมากนักว่า CPU ของคอมพิวเตอร์เป็น ARM หรือ x86
ดังนั้นถ้าคุณไม่ได้สนใจรายละเอียดว่าโค้ดรันแบบ native หรือรันบน VM อย่าง JVM, .NET, WASM ก็ยากจะบอกว่ามันให้อะไรเพิ่มกว่าวิธีอื่น
โดยทั่วไปเรามักเห็นแต่กรณีแย่ ๆ แล้วมันก็กลายเป็นมีมอย่าง “โปรแกรม Electron ทุกตัวคือปีศาจตัวบวมที่กินทรัพยากร และแอป native ทุกตัวคือสิ่งมหัศจรรย์แห่งวิศวกรรมซอฟต์แวร์ที่มีประสิทธิภาพโดยอัตโนมัติ”
เสียดาย ถ้าเก็บ โค้ด Fortran 78 ที่เขียนไว้เมื่อปี 1981/82 ไว้ ก็คงได้ลองทดสอบว่ามันรันบนนี้ได้ไหม
มันเป็นตัวจัดรูปแบบซอร์สโค้ดของภาษาโปรแกรม Jovial ซึ่งจริง ๆ ไม่ใช่งานที่ควรทำด้วย Fortran แต่ตอนนั้นมีทางเลือกแค่นั้น
มี ระบบนิเวศ linear algebra ที่พร้อมใช้งานระดับ production สำหรับ JavaScript อยู่บ้างไหม?
ลองค้นดูแล้วส่วนใหญ่เจอแต่พอร์ต JavaScript ของไลบรารีที่คุ้นเคยซึ่งอายุราว 10 ปี เช่นพอร์ตผ่าน emscripten เลยสงสัยว่าผมพลาดอะไรไปหรือเปล่า
แปลกที่ไม่ได้ลงลึกเรื่อง LFortran มากกว่านี้
มีตัวอย่าง WASM ที่ยอดเยี่ยมและน่าทึ่งซึ่งรันออนไลน์ได้ด้วย
https://dev.lfortran.org/
ในปี 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
ไม่อย่างนั้นงานคงเยอะกว่านี้มาก