Powolne działanie WebASM

1

Tworzę na własne potrzeby interpreter Z80 bazując na swoim starym projekcie https://github.com/andrzejlisek/ScriptSDCC/tree/master/src

Robię to w technice WebAssembly, wykorzystując do tego Emscripten.

Wszystko fajnie, pięknie i nie byłoby żadnego problemu, gdyby nie pewna sprawa wydajnościowa.

W nowym projekcie wykorzystuję między innymi te pliki z niewielkimi zmianami:
https://github.com/andrzejlisek/ScriptSDCC/blob/master/src/scriptmachinez180.h
https://github.com/andrzejlisek/ScriptSDCC/blob/master/src/scriptmachinez180.cpp
https://github.com/andrzejlisek/ScriptSDCC/blob/master/src/scriptmachine.cpp
https://github.com/andrzejlisek/ScriptSDCC/blob/master/src/scriptmachine.h

Tak naprawdę, to tworzę obiekt klasy ScriptMachineZ180 dziedziczący po ScriptMachine.

W ramach testów, wczytuję jakiś prosty program na Z80 do maszyny skryptowej Z180 i wykonuje w pętli "DoCommand" po 10000000 razy. Po prostu zwykła logika obliczeniowa, która operuje na jednej tablicy mającej 64k elementów, nic szczególnego się nie dzieje.

Rzecz wygląda następująco:

  1. Najpierw zrobiłem zwykły projekt w Qt Creator, który wykorzystuje te pliki na potrzeby prób i testów, żeby w ogóle ruszyć i ułatwić dostosowywanie pod nowy projekt. Test trwa ok. 0,3 sekundy.
  2. Potem w Firefox kompiluję za pomocą Emscripten wykorzystując identyczne pliki. Dokładnie ten sam kod i ten sam test wykonuje się przez ok. 1 sekundy. Tą przeglądarkę używam codziennie.
  3. W Chrome, identyczna binarka, identyczna czynność trwa już prawie 5 sekund. Na co dzień z niej nie korzystam, nawet często czyszczę w niej historię i cookiesy, bo nie mam nic do stracenia, a czasami chcę coś sprawdzić na czysto.

Z czego wynikają te różnice? Kompilację do Wasm wykonuję takim poleceniem (dla przejrzystości nie wymieniłem wszystkich plików źródłowych):

emcc -std=c++20 prog/scriptmachine.cpp prog/scriptmachinemcs51.cpp prog/scriptmachinez180.cpp progcore.cpp -s BUILD_AS_WORKER=1 -o compiled/progcore.js -s ALLOW_MEMORY_GROWTH

Identyczne polecenie wypracowałem przy tworzeniu innego projektu, a sama logika obliczeniowa jest wyniesiona do Worker, tak, że z JavaScript uruchamiam polecenie Workera, wykonuje się obliczenie i do JavaScript wraca wynik. Sama implementacja jest w taki sposób: https://stackoverflow.com/questions/32291084/minimal-working-example-for-emscripten-webworker

Ten sam kod, a tak duża różnica wydajnościowa i to między przeglądarkami. Czytałem też o kompilatorze Cheerp, z jednej strony on ponoć wytwarza lepszy i wydajniejszy kod od Emscripten, ale z drugiej strony ma bolączki takie, że nie ma "prawdziwych" wątków na wzór pthreads (akurat w tym projekcie niepotrzebne, ale w innym potrzebne) i nie ma też natywnie obsługiwanego przekazywania tekstu jako parametr funkcji i wyciągania tekstu jako wartości zwracanej, i to zarówno przy wywoływaniu C++ z JavaScript, jak i przy wywoływaniu JavaScript z C++. Da się to zapewne jakoś ominąć, ale to byłoby rozwiązanie karkołomne. A i tak, zanim doszedłem, co i jak z Emscripten, jak to zrobić, jak to działa, to zeszło dwa, trzy dni na czytaniu dokumentacji i próbowaniu tworzenia programu.

Czy zamieniając Emscripten na Cheerp, jest szansa na zyskanie dwukrotnego, czy trzykrotnego przyspieszenia? Bo jeżeli maksymalne przyspieszenie, to byłoby może o 20% przy dobrych wiatrach, to dla mnie nie ma sensu zawracać sobie tym głowy i zostaję przy Emscripten.

2

Wiem, że nie całkiem na temat ale może tu znajdziesz klika odpowiedzi lub przynajmniej inspirację:

https://floooh.github.io/visualz80remix/
https://github.com/floooh/visualz80remix

1

Znalazłem taki papier: https://weihang-wang.github.io/papers/imc21.pdf
Wydaje mi się, że tam możesz znaleźć odpowiedzi (rozdział 4.5 traktuje o różnicach pomiędzy przeglądarkami).

1 użytkowników online, w tym zalogowanych: 0, gości: 1