Z minut do sekund: diagnoza wykładniczego spowolnienia w produkcyjnym oprogramowaniu CAD

Kiedy klient mówi, że pojedyncza operacja w jego produkcyjnym oprogramowaniu trwa “kilka minut, czasem więcej”, odruchem jest sięgnięcie po profiler i przyjrzenie się najwolniejszej funkcji. To rozsądny pierwszy krok, ale w jednym z ostatnich projektów sam w sobie nie wystarczył - prawdziwa historia ujawniła się dopiero, gdy zestawiliśmy czas przetwarzania ze złożonością modelu.

Objawem nie była wolna funkcja, tylko wolna krzywa

Aplikacja, o której mowa, generuje trójwymiarowy model szyny prądowej, a następnie animuje działanie maszyny gnącej na tym modelu. Operatorzy zgłaszali, że oba etapy wyraźnie zwalniają wraz ze wzrostem złożoności zamówień, ale skargi były niespójne - czasem szybko, czasem bardzo wolno. Ta niespójność była pierwszą wskazówką: gdyby pojedyncza funkcja była po prostu wolna, oczekiwanie skalowałoby się przewidywalnie wraz z rozmiarem modelu. Zamiast tego mieliśmy do czynienia z czymś bliższym wzrostowi wykładniczemu.

Zbudowaliśmy macierz testów obejmującą modele od 10 do 300 otworów i od 1 do 3 gięć, mierząc czas spędzony na każdym etapie: ładowaniu modelu, generowaniu otworów, renderowaniu klatek animacji i walidacji kolizji. Wzorzec, który się wyłonił, był jasny po zwizualizowaniu - czas przetwarzania rósł nieliniowo wraz z liczbą otworów, podczas gdy liczba gięć miała znikomy wpływ. Przy 300 otworach samo generowanie modelu 3D zajmowało ponad 13 minut.

Nieliniowy wzrost niemal zawsze oznacza problem algorytmiczny, nie sprzętowy

Gdy krzywa stała się widoczna, przyczynę źródłową dało się łatwiej wyizolować: otwory były tworzone sekwencyjnie, jedna operacja geometryczna na raz, z pełną przebudową modelu kolizji po każdej pojedynczej zmianie. To problem o kształcie O(n²) ukryty za czymś, co wyglądało na “po prostu duży model”. Żadna aktualizacja sprzętu by tego nie naprawiła - poprawka musiała być algorytmiczna.

Rekomendacją było zastąpienie sekwencyjnego tworzenia otworów pojedynczą operacją wsadową, cache’owanie walidacji kolizji zamiast przebudowywania jej przy każdej zmianie oraz przeniesienie generowania modelu i animacji poza wątek UI, tak by operatorzy nie czekali zablokowani na pełny podgląd. Prognozowany efekt: redukcja czasu przetwarzania o 75-85% w obu obszarach.

Ogólna lekcja

Jeśli skarga na wydajność jest niespójna, a nie równomiernie wolna, nie profiluj tylko najwolniejszego przebiegu - zestaw czas z parametrem, który faktycznie zmienia się między przypadkami “szybko” i “wolno”. Kształt tej krzywej zwykle wskaże wprost na algorytm wykonujący niepotrzebną, powtarzaną pracę, na długo zanim trzeba będzie dotknąć infrastruktury.

“Jeśli skarga na wydajność jest niespójna, a nie równomiernie wolna, nie profiluj tylko najwolniejszego przebiegu - zestaw czas z parametrem, który faktycznie zmienia się między przypadkami "szybko" i "wolno".”

Mateusz Konicki