Programowanie w języku Matlab Optymalizacja czasowa kodu
M-file Profiler uzyskuje się informację m. in. o czasie i liczbie wykonań poszczególnych fragmentów kodu sposób użycia: >> profile on, profile clear >> badany kod >> profile report
Dane dostarczone przez M-file Profiler - badana funkcja: function result = example1(Count) for k = 1:Count result(k) = sin(k/50); if result(k) < -0.9 result(k) = gammaln(k); end środowisko Matlab 7.5.0.342 komputer PC z procesorem Pentium 4, 2.8 GHz, 2 GB RAM, system operacyjny Windows 2000 z Service Pack 4 - funkcja wywołana raz, z argumentem Count = 5000
Sposoby optymalizacji czasowej odpowiednie użycie danych, stosowanie konstrukcji, których działanie przyspiesza JIT-Accelerator, wektoryzacja kodu, inne.
Odpowiednie użycie danych rezerwacja pamięci na tablicę o znanych wymiarach function result = example1(Count) result = zeros(1, Count); for k = 1:Count result(k) = sin(k/50); % 0.002s if result(k) < -0.9 result(k) = gammaln(k); end odpowiedni dobór typu liczb – operacja na liczbach całkowitych są wykonywane szybciej niż na liczbach rzeczywistych
unikanie tworzenia niepotrzebnych zmiennych 1. function y = modfun1(x) y = 1.2*x; 2. function x = modfun2(x) x = 1.2*x; Czas wykonania dla tablicy o wymiarach 3000 x 3000: 2.731s 0.219s zachowanie typów zmiennych
przetwarzanie elementów tablic po kolumnach 1. for r = 1:N for c = 1:N if x(r,c) > 0 y(r,c) = x(r,c); end 2. for c = 1:N for r = 1:N if x(r,c) > 0 y(r,c) = x(r,c); end Czas wykonania przy: N = 3000, 4497523 elementach niezerowych i wcześniejszej rezerwacji pamięci na tablicę y: 3.11s 0.755s
Jeśli algorytm na to pozwala – traktować tablicę jako wektor i stosować indeksowanie liniowe for k = 1:N*N if x(k) > 0 y(k) = x(k); end Czas wykonania: 0.672s.
Stosowanie konstrukcji, których działanie przyspiesza JIT-Accelerator Od wersji 6.5 Matlab zawiera tzw. JIT-Accelerator, który znacznie skraca czas wykonywania kodu. Trzeba jednak przestrzegać kilku zasad: zmienne muszą być typu: double, complex, logical, char, int8, uint8, int16, uint16, int32, uint32; nie są przyspieszane operacje na: komórkach, strukturach, tablicach rzadkich oraz z użyciem uchwytów do funkcji, tablice mogą mieć co najwyżej trzy wymiary, nie może następować zmiana rozmiaru ani typu zmiennej, używane funkcje mogą być tylko funkcjami wbudowanymi Matlaba, wynik wyrażenia w instrukcjach: if, switch i while musi być skalarem, zmienna sterująca pętli for musi przyjmować wartości skalarne, wszystkie instrukcje w pętli muszą być napisane zgodnie z podanymi zasadami.
Wektoryzacja kodu Wektoryzacja - zastępowanie, o ile to możliwe, pętli, w których przetwarzane są pojedyncze elementy tablic, odpowiednimi operacjami tablicowymi. Przy wektoryzacji wykorzystywane są: operator dwukropka – do tworzenia tablic, przy odwołaniach do całych wierszy i kolumn oraz fragmentów tablic indeksowanie logiczne przy odwołaniach do elementów tablic, arytmetyczne operatory tablicowe, standardowe funkcje operujące na tablicach np. sum, prod, any, all, find, sort. Po wprowadzeniu JIT-Accelerator wektoryzacja już nie zawsze przynosi korzyści – hasło ,,życie jest za krótkie, żeby je spędzać na pisaniu pętli for’’ straciło na znaczeniu.
Utworzenie tablicy z wartościami funkcji cosinus dla t od 0 do 100 radianów, zmieniającym się co 0.0 1. k = 0; for t = 0:.01:100 k = k + 1; y(k) = cos(t); end 2. y = cos(0:.01:100); Czas wykonania: 0.209s bez rezerwacji pamięci na tablicę wyników, 0.115s z rezerwacją 0.024s
Utworzenie tablicy y z elementów tablicy x, przy czym elementy nieujemne mają pozostać, pozostałe mają być zastąpione 0 1. for c = 1:N for r = 1:N if x(r,c) > 0 y(r,c) = x(r,c); end 2. y = zeros(N); t = x > 0; y(t) = x(t); Czas wykonania (warunki pomiaru jak wcześniej): 0.755s 0.823s
Obliczenie sumy ciągu: 1 + 1/2 + 1/3 + ... + 1/n 1. suma = 0; for k = 1:n suma = suma + 1/k; end 2. suma = sum(1./(1:n)); Czas wykonania przy n = 100000: 0.001s 0.006s
Obliczenie sumy elementów leżących na przekątnej głównej tablicy 1. m = size(A,1); suma = 0; for k = 1:m suma = suma + A(k,k); end 2. suma = sum(diag(A)); Czas wykonania przy tablicy A o wymiarach 1000 x 1000: 0.00013s 0.00028s
Inne sposoby: napisanie fragmentów kodu w języku C lub Fortran i korzystanie z ich skompilowanych wersji zapisanych w mex-plikach, korzystanie z funkcji zaprojektowanych do wykonywania operacji na liczbach rzeczywistych, gdy przetwarzane są tylko dane tego typu (np.: realpow, realsqrt, reallog), odpowiednia konstrukcja wyrażeń warunkowych w instrukcjach: if i while - gdy używane są w nich operatory && oraz || nie zawsze zachodzi potrzeba obliczania wartości całego wyrażenia, unikanie przeciążania wbudowanych funkcji Matlaba, stosowanie m-plików funkcyjnych zamiast skryptowych, stosowanie, o ile to możliwe, funkcji load i save zamiast fread i fwrite.