| Both sides previous revisionPrevious revisionNext revision | Previous revision |
| pl:edu:zmitac:n1z:ja:lab4 [2021/04/11 16:14] – [WPF i assembler] pczekalski | pl:edu:zmitac:n1z:ja:lab4 [2021/04/24 17:07] (current) – [Ćwiczenie 3: Integracja kodu niezarządzalnego, tworzonego w języku Assembler wraz z aplikacją typu WPF w .NET C#, instrukcje SIMD] pczekalski |
|---|
| ===== Ćwiczenie 3: Integracja kodu niezarządzalnego, tworzonego w języku Assembler wraz z aplikacją typu WPF w .NET C#, instrukcje SIMD ===== | ===== Ćwiczenie 4: Integracja kodu niezarządzalnego, tworzonego w języku Assembler wraz z aplikacją typu WPF w .NET C#, instrukcje SIMD ===== |
| |
| |
| |
| Jeśli konwersja nie może zostać dokonana, ponieważ nie da się "przetłumaczyć" łańcucha na zmienną określowego typu, zostanie zgłoszony wyjątek i wykonywanie programu zostanie przerwane. Oczywiście istnieją mechanizmy walidacji, które pozwalają na wykrycie tego typu sytuacji oraz ich obsługę, niemniej jednak wykraczają one poza ramy niniejszej instrukcji. | Jeśli konwersja nie może zostać dokonana, ponieważ nie da się "przetłumaczyć" łańcucha na zmienną określowego typu, zostanie zgłoszony wyjątek i wykonywanie programu zostanie przerwane. Oczywiście istnieją mechanizmy walidacji, które pozwalają na wykrycie tego typu sytuacji oraz ich obsługę, niemniej jednak wykraczają one poza ramy niniejszej instrukcji. |
| | |
| | Aby zaprezentować wynik, należy wykonać operację odwrotną: zamienić zmienną numeryczną na łańcuch znaków (''String'') i przypisać wartość polu ''Text'' wskazanej kontrolki. W tym celu należy użyć funkcji ''ToString()'' wywoływanej "na" wskazanej zmiennej, np. tak: |
| | <code c> |
| | ... |
| | tbC4.Text = aResults[3].ToString(); |
| | ... |
| | </code> |
| | |
| | === Pozostałe ustawienia solucji === |
| | W projekcie WPF należy włączyć możliwość kompilacji kodu typu ''unsafe'' oraz debbugowanie kodu natywnego, analogicznie jak to opisano w instrukcji laboratoryjnej [[pl:edu:zmitac:n1z:ja:lab3|Ćwiczenie 3: Integracja kodu niezarządzalnego, tworzonego w języku Assembler wraz z kodem zarządzalnym .NET C#]]. |
| | |
| | Należy też pamiętać o wybraniu wspólnego folderu do generowania wynikowego kodu z projektu w assemblerze i projektu w języku C#, analogicznie jak to opisano w instrukcji laboratoryjnej [[pl:edu:zmitac:n1z:ja:lab3|Ćwiczenie 3: Integracja kodu niezarządzalnego, tworzonego w języku Assembler wraz z kodem zarządzalnym .NET C#]]. W przypadku projektów .NET, folder, do którego wykonuje się kompilację ustawia się we właściwościach projektu (prawym przyciskiem myszy należy kliknąć nagłówek projektu, a następnie wybrać "Properties" ("Właściwości"), i dalej w sekcji "Build" w grupie "Output path:" należy wskazać docelową ścieżkę (rysunek {{ref>asm4_10}}). Aby móc wybrać folder, musi on istnieć na dysku, zatem wskazane jest przeprowadzenie "pustej" kompilacji wyłącznie projektu DLL, aby folder ten został utworzony. |
| | |
| | <figure asm4_10> |
| | {{:pl:edu:zmitac:n1z:ja:buildtargetwpf.png?600|}} |
| | <caption>Ustawienie docelowego folderu na wyniki kompilacji projektu WPF</caption> |
| | </figure> |
| | |
| | W przypadku, gdyby pomimo ustawienia wspólnego folderu wynikowego nadal były zgłaszane błędy braku biblioteki DLL, istnieje możliwość, że włączony jest system tworzenia dodatkowych podfolderów, jak to opisano poniżej w notce z uwagami. Aby usunąć ten problem, konieczne jest ręczna edycja pliku konfiguracyjnego projektu.\\ Aby otworzyć plik konfiguracyjny projektu, należy dwukrotnie klinąć nazwe projektu w drzewie. Otworzy się plik typu XML, z rozszerzeniem ''.csproj''. |
| | |
| | <note warning>Uwaga! W przypadku projektu WPF w folderze wynikowym może pojawić się podfolder z wersją frameworku .NET, co w praktyce spowoduje, że plik wykonywalny z frontside (GUI) zostanie uruchomiony w innym folderze (w podfolderze) w stosunku do wybranego w ustawieniach, skutkiem czego biblioteka DLL nie zostanie załadowana i zostanie zgłoszony wyjątek. Podfoldery te są dodawane automatycznie. Aby usunąć tę niedogodność, w pliku projektu WPF należy mieścić dodatkową sekcję((https://docs.microsoft.com/en-us/visualstudio/ide/how-to-change-the-build-output-directory?view=vs-2019)): |
| | <code xml> |
| | |
| | <PropertyGroup> |
| | <AppendTargetFrameworkToOutputPath>false</AppendTargetFrameworkToOutputPath> |
| | <AppendRuntimeIdentifierToOutputPath>false</AppendRuntimeIdentifierToOutputPath> |
| | </PropertyGroup> |
| | |
| | </code> |
| | </note> |
| | |
| | |
| |
| === Assembler === | === Assembler === |
| Do solucji należy dodać projekt w assemblerze. Kod w assemblerze należy skompilować do biblioteki DLL, a następnie dołączyć ją dynamicznie do rozwiązania w C#. Jest to dokładnie ten sam proces, który został opisany w [[pl:edu:zmitac:n1z:ja:lab3|Ćwiczenie 3: Integracja kodu niezarządzalnego, tworzonego w języku Assembler wraz z kodem zarządzalnym .NET C#]] w zakresie tworzenia i konfiguracji części assemblerowej oraz jej udostępniania po stronie C#, natomiast zamiast aplikacji konsolowej występuje aplikacja WPF. | Do solucji należy dodać projekt w assemblerze. Kod w assemblerze należy skompilować do biblioteki DLL, a następnie dołączyć ją dynamicznie do rozwiązania w C#. Jest to dokładnie ten sam proces, który został opisany w [[pl:edu:zmitac:n1z:ja:lab3|Ćwiczenie 3: Integracja kodu niezarządzalnego, tworzonego w języku Assembler wraz z kodem zarządzalnym .NET C#]] w zakresie tworzenia i konfiguracji części assemblerowej oraz jej udostępniania po stronie C#, natomiast zamiast aplikacji konsolowej występuje aplikacja WPF. |
| ==== Zadanie do wykonania ==== | ==== Zadanie do wykonania ==== |
| Należy utworzyć prosty kalkulator, który przeliczy wektorowo dla 4 zmiennych wyniki dla operacji dodawania, odejmowania, mnożenia i dzielenia (akcje na osobnych przyciskach). Wymagane jest przeliczenie więcej niż jednego zestawu danych w ramach jednej instrukcji dodawania (trzeba skorzystać z SIMD). Każde zadanie należy wykonać w dwóch wariantach: z nasyceniem i bez nasycenia. | Należy utworzyć prosty kalkulator, który przeliczy wektorowo dla 4 zmiennych wyniki dla operacji dodawania, odejmowania, mnożenia i dzielenia (akcje na osobnych przyciskach). Wymagane jest przeliczenie więcej niż jednego zestawu danych w ramach jednej instrukcji dodawania (trzeba skorzystać z SIMD). Zadanie należy wykonać na typach zmiennoprzecinkowych, pojedynczej precyzji (32 bity, po stronie C# typ ''float''). |
| |
| Należy zadeklarować po jednej funkcji assemblerowej dla każdej operacji. | Należy zadeklarować po jednej funkcji assemblerowej dla każdej operacji. |
| |
| <note tip>Powyżej dołączono kontekst: zmienne zostały umieszczone w klasie okienka. Słowo kluczowe ''partial'' w deklaracji typu klasy MainWindow oznacza, że w pliku zaimplementowana jest jedynie część klasy. Pozostała część kodu znajduje się w pliku zarządzanym automatycznie przez edytor GUI okienka. Dla dewelopera w praktyce ten mechanizm jest przezroczysty, a cały kod należy umieszczać w tym pliku (''.xaml.cs'').</note> | <note tip>Powyżej dołączono kontekst: zmienne zostały umieszczone w klasie okienka. Słowo kluczowe ''partial'' w deklaracji typu klasy MainWindow oznacza, że w pliku zaimplementowana jest jedynie część klasy. Pozostała część kodu znajduje się w pliku zarządzanym automatycznie przez edytor GUI okienka. Dla dewelopera w praktyce ten mechanizm jest przezroczysty, a cały kod należy umieszczać w tym pliku (''.xaml.cs'').</note> |
| | |
| | <note important>Część instrukcji SIMD (SSE, AVX) wymaga specyficznego ułożenia danych w pamięci, w szczególności wyrównania (umieszczenia zmiennej pod adresem podzielnym przez 16). C# nie daje gwarancji umieszczenia początkowego elementu w pamięci pod adresem zgodnym z wymaganiami kodu niezarządzalnego (pomimo wyrównywania zmiennych do 64 bitów). W związku z tym, przy dostępie do pamięci, nie należy stosować instrukcji assemblerowych, wymagających wyrównania, w szczególności np. nie należy stosować ''MOVAPS'', tylko jej wolniejszą wersję, nie wymagającą specyficznego wyrównania zmiennych w pamięci, czyli ''MOVUPS''. </note> |
| | |
| | <note warning>Użycie instrukcji wymagającej wyrównania może powodować, że program będzie losowo działał i rzucał wyjątek (nawet w kolejnych uruchomieniach będzie zachowywał się niepowtarzalnie), ponieważ może się tak zdarzyć, że zmienna akurat będzie poprawnie ułożona pod adresem podzielnym przez 16, przez przypadek.</note> |
| ==== Metoda weryfikacji wyników ==== | ==== Metoda weryfikacji wyników ==== |
| Sprawdzenie debuggerem wraz z podglądem rejestrów / stanu pamięci oraz obserwacja wyników i sprawdzenie obliczeń. | Sprawdzenie debuggerem wraz z podglądem rejestrów / stanu pamięci oraz obserwacja wyników i sprawdzenie obliczeń. |
| ==== Pomocne zasoby ==== | ==== Pomocne zasoby ==== |
| Visual Studio 2019: [[https://visualstudio.microsoft.com/vs/]] | Visual Studio 2019: [[https://visualstudio.microsoft.com/vs/]] |