
Denne artikel undersøger en case for at accelerere en browserapplikation ved at erstatte JavaScript-beregninger med WebAssembly.
WebAssembly – hvad er det?
Kort sagt, det er et binært instruktionsformat til en stakbaseret virtuel maskine. Oftest kaldes Wasm (forkortelsen) et programmeringssprog, men det er det ikke. Instruktionsformatet køres i browseren sammen med JavaScript.
Vigtigt er, at WebAssembly kan genereres ved at kompilere kildetekster på sprog som C/C++, Rust, Go. Her anvendes statisk typetegning og den såkaldte flade hukommelsesmodel. Koden, som nævnt ovenfor, opbevares i et kompakt binært format, hvilket gør, at den kører næsten lige så hurtigt, som hvis applikationen blev lanceret via kommandolinjen. Disse egenskaber har bidraget til WebAssembly's stigende popularitet.
Vi minder om: til alle læsere af 'Habr' — rabat på 10.000 rubler ved tilmelding til et hvilket som helst Skillbox-kursus med rabatkoden 'Habr'.
Skillbox anbefaler: Praktisk kursus .
I øjeblikket anvendes Wasm i mange applikationer, fra spil som Doom 3 til web-porterede applikationer som Autocad og Figma. Wasm bruges også inden for serverless beregninger.
Denne artikel præsenterer et eksempel på brugen af Wasm til at accelerere en analytisk webtjeneste. For tydelighedens skyld har vi taget en fungerende applikation skrevet i C, som kan kompileres til WebAssembly. Resultatet vil blive brugt til at erstatte mindre effektive JS-sektioner.
Transformation af applikationen
I eksemplet vil den browserbaserede tjeneste fastq.bio blive brugt, som er designet til genetikere. Værktøjet giver mulighed for at vurdere kvaliteten af sekventering (afkodning) af DNA.
Her er et eksempel på applikationen i aktion:

Detaljerne i processen behøver ikke at blive præsenteret, da de er ret komplicerede for ikke-specialister, men kort sagt kan forskerne ud fra den ovennævnte infografik forstå, om sekventeringsprocessen for DNA forløb glat og hvilke problemer der opstod.
Denne tjeneste har alternativer i form af desktopprogrammer. Men fastq.bio gør det muligt at accelerere arbejdet ved at visualisere data. I de fleste andre tilfælde skal man have erfaring med kommandolinjen, men ikke alle genetikkere har den nødvendige erfaring.
Det fungerer ganske enkelt. Inddata er oplysninger præsenteret i form af en tekstfil. Denne fil genereres af specialiserede værktøjer til sekventering. Filen indeholder en liste over DNA-sekvenser og kvalitetsvurderinger for hver nukleotid. Filformatet er .fastq, hvilket også er grunden til, at tjenesten har fået sit navn.
Implementering i JavaScript
Den første handling, en bruger skal udføre med fastq.bio, er at vælge den passende fil. Ved at bruge File-objektet læser applikationen et tilfældigt udvalg af data fra filen og behandler denne pakke. JavaScripts opgave her er at udføre enkle strengoperationer og beregne målinger. En af målingerne er antallet af nukleotider A, C, G og T i forskellige DNA-fragmenter.
Efter at de nødvendige målinger er beregnet, visualiseres de ved hjælp af Plotly.js, og tjenesten går i gang med et nyt datasæt. Opdelingen i fragmenter er lavet for at forbedre brugeroplevelsen. Hvis man arbejder med alle data samtidigt, vil processen fryse i et stykke tid, da sekventeringsresultaterne fylder flere hundrede gigabyte. Tjenesten tager derfor datastykker fra 0,5 til 1 MB og arbejder med dem trin for trin, mens der opbygges grafiske data.
Sådan fungerer det:

I den røde firkant er algoritmen for strengtransformationer til visualisering placeret. Dette er den mest beregningskrævende del af tjenesten. Det kan være en idé at prøve at erstatte den med Wasm.
Vi tester WebAssembly
For at vurdere muligheden for at bruge Wasm, gik projektteamet i gang med at søge efter eksisterende løsninger til at skabe QC-metrik (QC - quality control) baseret på .fastq-filer. Søgningen blev udført blandt værktøjer skrevet i C, C++ eller Rust, så det ville være muligt at portere koden til WebAssembly. Desuden måtte værktøjet ikke være 'råt'; der var brug for en tjeneste, der allerede var testet af forskere.
Som følge heraf blev der valgt . Applikationen er ret populær, den er open-source, og det oprindelige sprog er C.
Før konvertering til Wasm bør man se på kompileringsprincippet for seqtk til desktop. Ifølge Makefile er her, hvad der skal til:
# Compile to binary
$ gcc seqtk.c
-o seqtk
-O2
-lm
-lzI princippet kan seqtk kompileres ved hjælp af Emscripten. Hvis man ikke har det, kan man klare sig .
$ docker pull robertaboukhalil/emsdk:1.38.26
$ docker run -dt --name wasm-seqtk robertaboukhalil/emsdk:1.38.26Hvis man ønsker det, , men det kræver tid.
Inden i containeren kan man uden problemer bruge emcc som et alternativ til gcc:
# Compile to WebAssembly
$ emcc seqtk.c
-o seqtk.js
-O2
-lm
-s USE_ZLIB=1
-s FORCE_FILESYSTEM=1Minimum ændringer:
I stedet for at outputte til en binær fil, anvender Emscripten .wasm og .js til at generere filer, som bruges til at køre WebAssembly-modulet.
For at understøtte zlib-biblioteket anvendes flaget USE_ZLIB. Biblioteket er velkendt og porteret til WebAssembly, og Emscripten inkluderer det i projektet.
Den virtuelle filsystem Emscripten aktiveres. Det er , der fungerer i RAM inden i browseren. Når siden opdateres, bliver hukommelsen ryddet.
For at forstå, hvorfor et virtuelt filsystem er nødvendigt, skal man sammenligne måden at køre seqtk fra kommandolinjen på med måden at køre det kompilerede WebAssembly-modul på.
# On the command line
$ ./seqtk fqchk data.fastq
# In the browser console
> Module.callMain(["fqchk", "data.fastq"])Adgang til det virtuelle filsystem er nødvendig for ikke at skulle omskrive seqtk til string- og ikke filinput. I dette tilfælde bliver datafragmentet vist som en fil data.fastq i det virtuelle FS med et kald til main() seqtk.
Her er den nye arkitektur:

Diagrammet viser, at i stedet for beregninger i hovedtråden i browseren anvendes . Denne metode muliggør udførelse af beregninger i en baggrundstråd uden at påvirke browserens responsivitet. WebWorker-controlleren starter en Worker og håndterer dens interaktion med hovedtråden.
seqtk-kommandoen køres ved hjælp af Worker på den mountede fil. Efter at Worker er færdig, returnerer den resultater i form af et Promise. Når hovedtråden modtager beskeden, bruges resultatet til at opdatere diagrammerne. Og så videre over flere iterationer.
Hvordan står det til med WebAssembly-ydeevnen?
For at evaluere ændringen i ydeevne, brugte projektteamet parameteren antal læseoperationer pr. sekund. Tiden til at bygge interaktive diagrammer tælles ikke med, da begge implementeringer bruger JavaScript.
Ved brug af løsningen "ud af boksen" var der en performanceforøgelse på ni gange.

Det er et fremragende resultat, men som det viste sig, er der mulighed for yderligere optimering. Mange resultater fra QC-analysen anvendes ikke af seqtk, så de kan fjernes. Hvis dette gøres, forbedres resultatet i forhold til JS med 13 gange.

Det blev opnået ved simpelthen at kommentere printf()-kommandoerne ud.
Men det er ikke alt. Faktisk får fastq.bio på dette stadium analysens resultater ved at kalde forskellige funktioner i C. Hver af dem beregner sit sæt af karakteristika, så hver del af filen blev læst to gange.
For at overvinde dette problem blev det besluttet at kombinere to funktioner i én. Resultatet er, at ydeevnen er blevet forøget 20 gange.

Det skal bemærkes, at et så bemærkelsesværdigt resultat ikke altid kan opnås. I nogle tilfælde falder ydeevnen, så det er vigtigt at vurdere hver enkelt situation.
Som konklusion kan det siges, at Wasm virkelig giver mulighed for at forbedre applikationens ydeevne, men det skal bruges med omtanke.
Skillbox anbefaler:
- Toårigt praktisk kursus .
- Online kursus .
- Praktisk års kursus .
Kilde: habr.com
