Posts tagged ‘Windows’

Rozpoznawanie możliwości procesora

2007-12-08 17:39

Niektóre funkcje dobrze jest pisać w asemblerze. Tak, wiem że dzisiaj – w epoce języków (zbyt) wysokiego poziomu – brzmi to dziwnie, ale to prawda. To najprostszy sposób na poprawienie wydajności często wykonywanych operacji, np. kalkulacji z użyciem wektorów i macierzy.
Rzecz w tym, że korzystając bezpośrednio z zaawansowanych możliwości oferowanych przez współczesne procesory, jednocześnie uzależniamy się od nich. Przykładowo, transformację wektora przez macierz można naturalnie po prostu przetłumaczyć z odpowiedniego wzoru na instrukcje jednostki zmiennoprzecinkowej i uzyskać kod działający na każdym procesorze. Jeżeli jednak użyjemy np. SSE2, możemy uzyskać kilkakrotny wzrost wydajności – lecz wówczas nasza funkcja będzie działała tylko na nowszych procesorach.

Najlepiej byłoby więc mieć kilka wersji takiej funkcji i wybierać odpowiednią dla procesora pracującego na danej maszynie. Jak jednak wykryć, co potrafi dana jednostka? Otóż z pomocą przychodzi nam system operacyjny. W Windows na przykład istnieje funkcja o wiele mówiącej nazwie IsProcessorFeaturePresent, przy pomocy której możemy sprawdzić obecność rozszerzeń MMX, 3DNow!, SSE i SSE2.
Oczywiście, takiego sprawdzenia należy dokonać raz na początku działania programu. Jeśli jednak po prostu zapiszemy jego rezultat w formie globalnych flag boolowskich, to ich odczytywanie np. przy każdym dodawaniu wektorów będzie nie tylko kłopotliwe, ale i nieefektywne.

Lepszym rozwiązaniem jest stworzenie odpowiedniej liczby globalnych wskaźników na funkcje, inicjowanych w czasie uruchamiania programu; tak jak poniżej:

  1. typedef VEC3 (*Vec3Func)(const VEC3*, const VEC3*);
  2. Vec3Func Vec3_Add, Vec3_Sub, Vec3_Cross;
  3.  
  4. // sprawdzenie obecności rozszerzenia SSE2
  5. if (IsProcessorFeaturePresent(PF_XMMI64_INSTRUCTIONS_AVAILABLE))
  6. {
  7.    Vec3_Add = Vec3_Add_SSE2;
  8.    Vec3_Sub = Vec3_Sub_SSE2;
  9.    Vec3_Cross = Vec3_Cross_SSE2;
  10. }
  11. else
  12. {
  13.    // w przypadku jego braku, używamy funkcji zakodowanych
  14.    // na zwykłej jednostce zmiennoprzecinkowej
  15.    Vec3_Add = Vec3_Add_FPU;
  16.    Vec3_Sub = Vec3_Sub_FPU;
  17.    Vec3_Cross = Vec3_Cross_FPU;
  18. }

Dzięki temu zarówno w kodzie asemblerowym poszczególnych wersji (którego litościwie nie pokażę ;D), jak i wywołaniach, nie widać żadnego śladu po ‘magii’ wyboru funkcji dostosowanej do procesora. Narzut to rozwiązanie to naturalnie jedna dereferencja wskaźnika więcej; sprawdzanie flag (porównaniami i skokami) trwałoby znacznie dłużej.

Tags: , ,
Author: Xion, posted under Programming » 5 comments

Funkcje debugujące

2007-12-01 13:29

Kiedy już przekonamy się o korzyściach płynących z regularnego stosowania debuggera (a każdy początkujący programista powinien przekonać się o nich jak najszybciej), być może zaczniemy się zastanawiać, jakaż to “magia” sprawia, że cały ten proces w ogóle jest możliwy. W jaki sposób program śledzący potrafi dostać się do wnętrza naszej aplikacji i wylistować zawartość wszystkich zmiennych, nie mówiąc już o możliwości ustawiania punktów przerwań (breakpoints) czy pracy krokowej. Czy debuggery korzystają z jakichś nieudokumentowanych “wytrychów” do samego jądra systemu operacyjnego?…

Otóż niekoniecznie. Na przykład Windows API udostępnia zwyczajne funkcje systemowe, za pomocą których jeden proces może śledzić zachowanie innego. Obejmuje to przyłączenie się do innego procesu w charakterze debuggera, obsługę przeróżnych interesujących zdarzeń (jak np. załadowanie biblioteki DLL lub stworzenie nowego wątku przez proces, który śledzimy), a także odczytywanie zawartości pamięci procesu (jeśli mamy do tego uprawnienia) lub kontekstu jego wątku.
Naturalnie mało kto będzie pisał swój własny debugger, więc wspomniane funkcje są nieszczególnie przydatne dla większości programistów. Jednak istnieje też kilka takich, które można użytecznie stosować po drugiej stronie – w aplikacji, która jest debugowana:

  • OutputDebugString to prawdopodobnie ta najbardziej znana. Służy ona do wysyłania komunikatów do debuggera, które zwykle są wyświetlane w specjalnym okienku naszego IDE. Zazwyczaj jest to bardziej poręczne rozwiązanie niż chociażby pokazywanie okienek komunikatów, które trzeba przecież potwierdzać kliknięciami w OK. Funkcję tę można aczkolwiek zastąpić wypisywaniem na standardowe wyjście diagnostyczne (stderr, reprezentowane w iostream przez obiekty cerr lub wcerr).
  • DebugBreak działa z kolei jak punkt przerwania. Zasadniczo funkcja ta wywołuje odpowiedni wyjątek systemowy (nie mający za wiele wspólnego z wyjątkami języka C++), który każdy porządny debugger złapie. W środowisku programistycznym rezultatem będzie zawieszenie działania programu i ustawienie się z widokiem kodu źródłowego na miejsce wywołania funkcji, co oczywiście znakomicie ułatwia odnalezienie przyczyny błędu. Jeżeli jednak nikt nie śledzi naszej aplikacji, wówczas rzucony wyjątek spowoduje jej awaryjne zakończenie. Generalnie podobny efekt co DebugBreak powinno dać wywołanie przerwania numer 3 (czyli asm { int 3 }).
  • IsDebuggerPresent pozwala z kolei określić, czy aplikacja jest aktualnie debugowana przez jakiś inny proces. Dzięki temu możemy na przykład przekazywać do komunikatów diagnostycznych większą liczbę informacji, wiedząc, że ktoś “po drugiej stronie” faktycznie je odczytuje :)

Wprawdzie samo korzystanie z tych funkcji nie zastąpi dobrego systemu kontroli błędów i ich raportowania (np. zapisywania w dzienniku), lecz z pewnością może pomóc. Bardzo dobrze prezentuje się na przykład okienko z obszernym komunikatem o błędzie i trzema możliwościami decyzji: kontynuacji programu, przejścia do trybu debugowania albo awaryjnego zakończenia aplikacji. Przy takim rozwiązaniu aż chce się popełniać błędy ;)

Tags: , ,
Author: Xion, posted under Programming » Comments Off on Funkcje debugujące

Okno na pingwina

2007-09-07 17:53

Czasami przydaje się posiadanie więcej niż jednego operacyjnego na jednym komputerze. Jeżeli oba używają tego samego systemu plików, to zwykle nie ma problemu z wymianą danych.

A co zrobić, jeżeli tak nie jest – czyli na przykład chcemy dostać się z poziomu Linuxa do plików używanych w Windows lub odwrotnie? W jedną stronę jest łatwo: większość dystrybucji Linuxa obsługuje przynajmniej odczytywanie z partycji NTFS, a niektóre automatycznie montują znalezione woluminy, które korzystają z tego systemu plików.
Jeżeli zaś chodzi o operację odwrotną, to naturalne Windows nie patrzy tak przychylnie na inny system operacyjny. Wbudowana w okienka obsługa różnych systemów plików nie obejmuje ext2 i ext3, czyli tych używanych w ogromnej większości Linuksów. Tutaj mogą pomóc tylko zewnętrzne narzędzia.

Jednym z nim jest Ext2 IFS. Ma on tę zaletę, że działa jak sterownik, a nie np. wtyczka do Eksploratora, Total Commandera czy innego menedżera plików. Dzięki temu podmontowane partycje linuksowe są widoczne w całym systemie.

Partycja linuksowa pod Windows System plików ext2 pod Windows

Można z nich korzystać właściwie tak samo jak z dysków NTFS, czyli odczytywać i zapisywać pliki, katalogi, zmieniać etykiety woluminów, itp. Nie trzeba też kopiować plików tam i z powrotem, aby je modyfikować.

Sam nie używam Linuksa zbyt często, ale taki sterownik jest bardzo wygodny. Chociaż prawdopodobnie dostęp do partycji ext3 z Windows sprawia, że Linuksa uruchamiam nawet jeszcze rzadziej niż wcześniej ;)

Tags: , , ,
Author: Xion, posted under Applications » 3 comments

System GUI #5 – Okno

2007-08-28 17:43

Dawno temu w firmie Xerox wymyślono, że interfejs użytkownika można zapakować w zestaw prostokątnych, nakładających się na siebie okien. Pomysł okazał się niezwykle trafiony i zaowocował nawet wielce kreatywną nazwą pewnego systemu operacyjnego ;) Od tamtej pory trudno sobie wyobrazić zaawansowane UI posługujące się czymś innym niż właśnie zestawem okien.

Nie jest trudno otrzymać na ekranie puste okno. W środowiskach RAD – w rodzaju Visual C# czy Delphi – mamy je najczęściej dane automatycznie, gdy tworzymy nowy projekt. W przypadku programowania niewizualnego (jak np. z użyciem czystego Windows API) sprawa jest nieco bardziej skomplikowana, ale i tak zamyka się w nie więcej niż kilkudziesięciu linijkach.
Takie puste okno wydawać się może mało interesujące czy wręcz zbyt oczywiste, aby zwracać na nie uwagę. Rzadko zwracamy uwagę na to, że ten pozornie trywialny prostokąt sam w sobie potrafi bardzo wiele. Wśród typowych możliwości mamy chociażby:

  • przesuwanie za pomocą przeciągania za pasek tytułu
  • zmianę jednego z wymiarów poprzez przeciąganie brzegów
  • zmianę obu wymiarów poprzez przeciąganie rogów okna
  • Przeciąganie za pasek tytułu okna Zmiana jednego z wymiarów okna Zmiana obu wymiarów okna Przyciski sterujące oknem

  • minimalizacja, maksymalizacja i zamykanie okna przyciskami na pasku tytułu

Uzyskanie podobnej funkcjonalności, zaczynając od zera, jest bardziej pracochłonne niż może się wydawać. W moim przypadku otrzymanie czegoś, co przypomina w pełni funkcjonalne i interaktywne okno, zamknęło się w ok. dwóch tysiącach linijek kodu – nie licząc oczywiście modułu grafiki 2D, potrzebnego do rysowania okien.
To całkiem sporo. Skutkiem ubocznym tej pisaniny jest też to, że obecnie patrzę na stare poczciwe okna systemu Windows z nieco większym respektem :)

Tags: , ,
Author: Xion, posted under Programming » Comments Off on System GUI #5 – Okno

Uparte menu kontekstowe

2007-08-18 14:36

Menu kontekstowe programu mIRCProgramy rezydujące w zasobniku systemowym (system tray) są zawsze wyposażone w menu kontekstowe. Zwykle pojawia się ono po kliknięciu prawym przyciskiem myszy na ikonkę aplikacji i zawiera najczęściej używane opcje programu – co czasem oznacza też “wszystkie opcje programu” :)
Czasami jednak to menu jest uparte i jeśli nie zdecydujemy się na wybranie żadnej pozycji, ono pozostaje otwarte nawet mimo tego, że już dawno zajęliśmy się czymś innym. Zupełnie jakby Windows “zagapił się” i przeoczył moment, gdy menu utraciło fokus (wtedy właśnie powinno było zniknąć). Bywa to o tyle denerwujące, że takie osierocone menu przykrywa wszystkie inne okna w systemie.

Niekiedy pomaga wtedy ponowne kliknięcie w ikonkę programu. Jeżeli jednak to nie działa, trzeba jakoś przywrócić feralnemu menu utracony fokus, aby mogło go ponownie stracić – i, miejmy nadzieję, zniknąć na dobre. Jak to zrobić bez uaktywniania żadnej pozycji menu? Są co najmniej dwa sposoby:

  • można kliknąć w separator, czyli poziomą linię oddzielającą od siebie niektóre opcje
  • można kliknąć prawym przyciskiem myszy w dowolne miejsce menu

Kiedy następnie klikniemy w jakiekolwiek miejsce poza menu, oporna lista powinna się w końcu schować.

Tags: , ,
Author: Xion, posted under Programming » Comments Off on Uparte menu kontekstowe
 


© 2017 Karol Kuczmarski "Xion". Layout by Urszulka. Powered by WordPress with QuickLaTeX.com.