Powolne działanie WebASM

Powolne działanie WebASM
AN
  • Rejestracja: dni
  • Ostatnio: dni
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.

4w0rX4t4X
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 351
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

TR
  • Rejestracja: dni
  • Ostatnio: dni
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).

AN
  • Rejestracja: dni
  • Ostatnio: dni
0

Ostatnio wróciłem do projektu, który sobie rozwijam w wolnym czasie i stwierdziłem, że rozwiązanie problemu jest proste; Wystarczy dodać parametr -O3 do wiersza polecenia kompilacji i program działa znacznie szybciej, w Chrome mniej więcej 30-50% szybkości działania na komputerze, a w Firefox nawet do 70% Nie wiem, czy to całkowite rozwiązanie, ale to bardzo dużo daje i szybkość już satysfakcjonuje.

AN
  • Rejestracja: dni
  • Ostatnio: dni
1

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

Okazuje się, że moja implementacja Z80/Z180 wcale nie jest taka zła. Wziąłem inną implementację z https://github.com/Jean-MarcHarvengt/MCUME/tree/master/MCUME_pico/pico81 i na szybko dostosowałem do zastosowania w moim projekcie. Kod wyszedł zagmatwany, ale chodziło tylko o sprawdzenie, na ile ta implementacja jest szybsza od mojej. Wyszło, że wersja z GitHuba jest szybsza jedynie o ok. 20% od mojej. Czy warto wymienić i dopasować do architektury obiektowej, to już muszę sam zdecydować, a i tak szybkość spadnie ze względu na dodanie elementów wykonywanych co rozkaz procesora, jednak przyrost o 20% jak na moje potrzeby to raczej nieduży przyrost w stosunku do na przykład przyrostu dwukrotnego.

W przypadku WebAsm na Chrome, uzyskuję szybkość ok. 20 milionów rozkazów na sekundę, więcej nie wycisnę, ale też więcej nie jest potrzebne w moim przypadku. Przed zastosowaniem -O3 było najwyżej 5 miliony rozkazów na sekundę, a w wersji skompilowanej natywnie na komputerze symulator wyciąga do 60 milionów rozkazów na sekundę na mojej implementacji Z80.

LukeJL
  • Rejestracja: dni
  • Ostatnio: dni
  • Postów: 8488
0

Czy ten kompilator wypluwa ci również JSa? (chodzi mi o gluecode, bindingi). Tam też mogą być rzeczy, które wpływają na wydajność (np. tworzenie i kopiowanie jakichś buforów).

A poza tym to:

  • czy spadek wydajności jest zauważalny w realnej sytuacji czy tylko w benchmarku?
  • co mówi profiler w dev toolsach?
AN
  • Rejestracja: dni
  • Ostatnio: dni
0

Czy ten kompilator wypluwa ci również JSa? (chodzi mi o gluecode, bindingi). Tam też mogą być rzeczy, które wpływają na wydajność (np. tworzenie i kopiowanie jakichś buforów).

Tak i ten JS umożliwia między innymi wywoływanie funkcji WASM, również takich, które przyjmują w argumentach i zwracają napisy (string), do tego umożliwia tworzenie i obsługę JS Worker.

Sposób testowania to jest uruchomienie pętli z zadaną liczba iteracji (np. milion) w Worker, zmierzenie czasu wywołania i przeliczenie na iteracje/sekunda. Jeżeli trwa np. pół sekundy, to narzut czasowy JS związany z samym uruchamianiem i wracaniem z wynikiem jest pomijalny. Nawet, jak zmniejszam iterację do sto tysięcy, to prędkość wykonania po przeliczeniu na iteracje/sekunda jest podobny. Przy 10000 obliczona prędkość jest minimalnie mniejsza, ale to oczywiście właśnie z powodu coraz większego wpływu narzutu czasowego obsługi wywoływania i wywołania zwrotnego z workera przy coraz krótszej pracy samej pętli.

czy spadek wydajności jest zauważalny w realnej sytuacji czy tylko w benchmarku?

Można powiedzieć, że postępuję odwrotnie, czyli na samym początku wstawiłem implementację samej symulacji procesora Z80 i zmierzyłem czas wywołania pewnej partii rozkazów, czyli cały czas benchmarkuję. Potem, jak dorabiam kolejne funkcjonalności, zbliżając się realnej sytuacji i ostatecznego zastosowania projektu, kontroluję, jak zmienia się czas, w praktyce spadek prędkości póki co jest minimalny, zależy od działania dodatkowej funkcjonalności.

co mówi profiler w dev toolsach?

Do pisania kodu i ewentualnego testowania kompilacji na komputerze używam Qt Creator, a do kompilacji do Wasm ma przygotowany skrypt, który kopiuje źródła do odpowiedniego katalogu i uruchamia kompilację. Nie znam takich narzędzi do profilowania, choć mniej więcej wiem, na czym polega profilowanie kodu, ale chętnie sprawdzę. do Wasm mam dodatkowe dwa pliki C++, które są tylko "glue code" pomiędzy logiką biznesową, a interfejsem WASM ze względu na inną strukturę i inną zasadę działania aplikacji WASM względem zwykłej apki desktopowej w Qt.

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.