Blog Kokosa

.NET i okolice, wydajność, architektura i wszystko inne

NAVIGATION - SEARCH

Konkurs - .NET Developer Days 2016

Pisałem na początku lipca, czemu to warto wybrać się w październiku do Warszawy na konferencję .NET Developer Days. Obiecałem też wtedy konkurs, w którym wygrać będzie można jedną wejściówkę na to zacne wydarzenie.

Najwyższa pora ten konkurs ogłosić. Myślałem, myślałem, co by tu zrobić by nie było nudno. I wymyśliłem. Obecność m.in. Jona Skeeta i Teda Newarda, a zwłaszcza przedkonferencyjny warsztat całodniowy tego drugiego, to bliski mojemu sercu temat "internalsów" .NETa. W związku z tym, konkurs będzie zabawą w tym obszarze, a konkretnie próbą napisania jak najgorszsego kodu ukazującego problem ukrytych alokacji. Poprzez taką paradoksalną zabawę trochę się pouczymy, a ktoś wygra wejściówkę o wartości 1200 PLN!

Ukryte alokacje to rzecz niefajna. O ile alokowanie obiektu na stercie jest tanie, albo bardzo tanie, to potrzeba sprzątania wielu niepotrzebnych, tymczasowych obiektów tworzyć może spory narzut na Garbage Collector. Klasycznym przykładem ukrytej alokacji jest boxing, czyli sytuacja gdy value object musi zostać opakowany w typ referencyjny (stąd potrzeba tymczasowej alokacji na stercie). Możemy go doświadczyć za pomocą popularnej metody:

string string.Format(string format, object arg0);

Jeśli przekażemy jako argument np. wartość liczbową, zostanie ona opakowana i mamy alokację! Inne przykłady to konkatenacja stringów, domknięcia itp. Poszukajcie, poczytajcie, nie będę podpowiadał Smile 

Do sprawdzania problemu alokacji używać można np. znakomitego narzędzia BenchmarkDotNet, w którym definiuje się testy wydajnościowe podobnie jak to robimy w testach jednostkowych. Poniżej przykład, który sprawdza wydajność dwóch różnych metod. Pierwsza nie robi nic, więc tym bardziej nie alokuje obiektów. Druga zawiera wspomniany wcześniej boxing. Konfiguracja i uruchomienie tych testów jest chyba samo tłumaczące się:

namespace TestConsoleApplication
{
    public class SampleBenchmark
    {
        [Benchmark]
        public int NoAllocations()
        {
            return 0;
        }

        [Benchmark]
        public int HiddenAllocation()
        {
            return int.Parse(string.Format("{0}", 0));
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var test = BenchmarkRunner.Run<SampleBenchmark>(
                            ManualConfig.Create(DefaultConfig.Instance)
                                        .With(new MemoryDiagnoser()));
        }
    }
}

Po uruchomieniu i chwili cierpliwości uzyskujemy wynik, w którym m.in. poznamy zanotowany Bytes Allocated/Op, czyli uśrednioną liczbę bajtów zaalokowanych w jednym wykonaniu testowej metody i to właśnie ta wartość najbardziej nas interesuje:

benchmark

Co zrobić aby wygrać? Wymyśleć kod w C#, który najbardziej napsuje pod kątem dużej ilości ukrytych alokacji - im większa wartość Bytes Allocated/Op tym lepiej! Wygrywa ten, kto napsuje najbardziej. Ale uwaga - żeby było zabawniej nie można w kodzie użyć ani jednej jawnej alokacji. Odpada zatem new czy używanie Reflection i m.in. Activator.CreateInstance. Tylko ukryte alokacje! I by trzeba było pogłówkować, kod może mieć maksymalnie 128 znaków długości.

Podsumowując zasady:

  1. Jako komentarz do tego wpisu publikujecie swój kod o długości maksymalnie 128 znaków (w tym białych), który ma zwracać int, przy okazji generującego jak największą liczbę ukrytych alokacji. Kod musi być oczywiście poprawny, by dało się go skompilować w ramach testu. Jako przykład wklejam swój kod i wynik. BTW. aby w komentarzu ładnie sformatować kod trzeba go objąć tagami <pre><code> </code></pre>.
  2. Update: Kod nie tylko musi się kompilować, ale musi też umożliwiać wykonanie testu. M.in. jego czas wykonania powinien być skończony:) By nie manipulować czasem wykonania (wiadomo, że kod wykonujący się godzinę będzie więcej alokował), dodaje drugie ograniczenie - całość testu musi się zamknąć w 10 minutach - tak jak to widać na powyższym screenie, gdzie test trwał niecałe 8 minut.
  3. Kod z Waszych komentarzy sukcesywnie benchmarkuję za pomocą powyższego narzędzia, wklejając go do metody HiddenAllocation i publikując Wasz wynik jako odpowiedź do komentarza. Parametry testu: framework .NET 4.6.1, kompilacja Release, 64 bit, GC w trybie Concurrent Worksation.
  4. Zabawa trwa do końca przyszłego tygodnia (18 września o godz. 23:59:59).
  5. Każda osoba może zgłosić maksymalnie 3 propozycje - by dać szansę na ripostę wobec czyichś pomysłów, ale by też nie ciągnęło się to w nieskończoność.
  6. Już po północy 19 września będzie jasne kto jest szczęśliwym zwycięzcą!

Kombinujcie, bardzo jestem ciekawy co ciekawego wymyślicie i jaki będzie rekord!


blog comments powered by Disqus