Monitorowanie OPS
• tech • 654 słowa • 4 minuty czytania
W poprzedniej notce, namawiałem do eksperymentów, które mogłyby uprościć proces i implementację przedstawionego tam sposobu limitowania operacji. Wspomniałem o możliwości dodania adekwatnego mechanizmu, który byłby w stanie monitorować dane operacje i wyznaczać wartość określającą ilość wykonywanych operacji (np. na sekundę), czyli mierzenie przepustowości.
Obecnie nie planuję implementacji takiego mechanizmu monitorowania, ale temat wydaje się ciekawy, wiec notka ta będzie jedynie krótkim (może nieco dłuższym) komentarzem do tego tematu. Troche o tym myślałem, ale aktualnie nie mam czasu, a nawet nie jest mi takowy potrzebny, wiec skupiłem się tylko na teoretycznych dywagacjach.
Podobnie, jak w przypadku limitowania, oprzyjmy się o sieciowy przykład. Najprościej wyznaczyć szybkość transferu, na podstawie czasu wysłania określonej liczby danych (pakietu), który można otrzymać monitorując czas działania funkcji wysyłającej danej. Jeśli wiemy, ile wysłaliśmy danych $D$, i w jakim czasie $T$ to dokonaliśmy, to szybkość transferu możemy wyznaczyć z poniższej zależności:
$$ S=D*T $$
Mierząc czas w sekundach, a rozmiar danych w bajtach, otrzymujemy szybkość w bajtach na sekundę (bs, bps). Oczywiście, bardziej realne wydaje się skorzystanie z mili- lub mikro- sekund, wtedy trzeba odpowiednio przeskalować czas, dla milisekund, wzór ten przyjmuje następującą postać:
$$ S=D*(1000/T) $$
Wykorzystując TimePolicy
z poprzedniej notki, posiadając funkcję send
wysyłająca dane, możemy powyższy wzór zapisać w postaci kodu:
Time start = TimePolicy::time();
int size = send(buffer, length);
Time end = TimePolicy::time();
uint64_t speed = size* (1000 * 1000 / (end - start));
Nic prostszego. Wyniki otrzymane w ten sposób, przy dużych buforach mogą powodować bardzo rzadkie i powolne zmiany wartości wyznaczanej prędkości. Chcąc otrzymać bardziej dynamiczne pomiary i większą rozdzielczość zmian, należy rozdzielić wysyłanie danych na mniejsze porcje i dla każdej wyznaczać szybkość. Czyli standardowo prosta pętelka:
const size_t chunk = length / 10;
while (length > 0) {
Time start = TimePolicy::time();
size_t size = std::min(chunk, length);
size = send(buffer, size);
Time end = TimePolicy::time();
speed = size * (1000 * 1000 / (end - start));
buffer += size;
length -= size;
}
Zmienna speed
zawiera poszczególne próbki zmierzonej szybkości transferu, agreguje ona poszczególne przypisania. Wartości wprawdzie przybierają aktualną szybkość wysyłania danych, ale lepszym rozwiązaniem może być prezentacja średniej prędkości. Taką średnią wartość można wyliczać z kilku pomiarów za pomocą kilku metod - standardowa średnia arytmetyczna, średnia ważona lub średnia krocząca.
Typ zmiennej przechowującej poszczególne pomiary powinien spełniać założenia buforu cyklicznego, na bazie kolejki FIFO lub typowego vectora lub tablicy. Żądana wartość szybkość należy wyliczać z określonych ostatnich $N$ elementów, gdzie wartość $N$ należy dobrać tak, aby wynik przedstawiał sensowne wyniki w pełnym spectrum szybkości, od małych do dużych. Przy dużych prędkościach N może być stosunkowo niskie, dla powolnych prędkości N powinno być zdecydowanie wyższe, aby uniknąć fluktuacji wartości prędkości, co często się zdarza, przy powolnych transmisjach i uniknąć tym samym niepoprawnych, myślnych wyników.
W zaprezentowanym wyżej kodzie, dzielono bufor na 10 części. Idealnym rozwiązaniem byłoby zastosowanie jakiegoś algorytmu lub metody służącej do dynamicznego i adaptacyjnego określania wartości tego współczynnika. Pomogłoby to zachować jako taką granicę i równowagę miedzy odpowiednim tempem, dynamika zmian szybkości monitorowanych operacji, a dodatkowym narzutem na dzielenie operacji, co dla małych buforów byłoby bardzo dotkliwe i odczuwalne.
Dla poprawy wydajności, zaproponowane wyżej typy średnich możliwych do zastosowania przy obliczaniu prędkości, można tak zapisać i zaimplementować, aby przyrostowo wyliczać bieżącą wartość na podstawie poprzedniej, unikając operacji na całym wektorze danych.
Należy pamiętać, ze pomiar prędkości tą metoda jest idealny, gdy znamy początek i koniec przesyłanych danych, w transferach, gdzie nie można stwierdzić takich granic, może być kłopotliwe realne ustalenie szybkości. Musimy wiedzieć, kiedy wyzerować szybkość.
Jak wspomniałem, są to moje proste dywagacje i teoretyczne przemyślenia, poparte tylko małymi eksperymentami, wszystko w nawiązaniu do tematu przedstawianego w poprzedniej notce. Eksperymenty były bardzo proste, nie powstała żadna implementacja, ani modyfikacja kodu limitera wzbogacającego o takowe mechanizmy monitorowania. Głównym powodem to brak potrzeby i użyteczności, ale musze się przyznać, że chodzi mi po głowie pomysł stworzenia prostego programu do limitowania i monitorowania transmisji sieciowej w systemie Windows. Może kiedyś cos z tego wyniknie dobrego :)
Komentarze (0)