Jakie jest najlepsze podejście do kodowania w wolnym środowisku kompilacji

15

Kiedyś kodowałem w języku C # w stylu TDD - pisz / lub zmieniaj mały fragment kodu, ponownie kompiluj w 10 sekund całe rozwiązanie, ponownie uruchom testy i jeszcze raz. Łatwo...

Ta metodologia programowania działała dla mnie bardzo dobrze przez kilka lat, aż do ostatniego roku, kiedy musiałem wrócić do kodowania w C ++ i naprawdę czuję, że od tego czasu moja wydajność dramatycznie spadła. C ++ jako język nie stanowi problemu - miałem całkiem spore doświadczenie dla programistów C ++ ... ale w przeszłości.

Moja produktywność jest nadal OK dla małych projektów, ale pogarsza się, gdy wraz ze wzrostem wielkości projektu i gdy czas kompilacji przekroczy 10 minut, robi się naprawdę źle. A jeśli znajdę błąd, muszę ponownie rozpocząć kompilację itp. To jest po prostu frustrujące.

Tak więc doszedłem do wniosku, że w małych fragmentach (jak poprzednio) jest nie do przyjęcia - wszelkie zalecenia, jak mogę wprowadzić się w stary nawyk kodowania przez około godzinę, podczas ręcznego przeglądania kodu (bez polegania na szybkim kompilatorze C #) , i ponowne kompilowanie / ponowne uruchamianie testów jednostkowych tylko raz na kilka godzin.

Z C # i TDD bardzo łatwo było napisać kod w sposób ewolucyjny - po kilkunastu iteracjach, które badziewie zacząłem, kończyło się na dobrym kodzie, ale po prostu nie działa dla mnie (w powolnej kompilacji środowisko).

komar
źródło
stackoverflow.com/questions/5078409/... Prawdopodobnie powinny zostać scalone / w jednym miejscu.
Ben L
Zobacz laso stackoverflow.com/questions/373142/..., aby przyspieszyć czasy kompilacji C ++.
Zaćmienie
2
Rozpocznij walkę na miecze . ; p
Steven Jeuris
Ostatni raz użyłem C ++ na poważnie, używając wstępnie skompilowanych nagłówków skracając czas kompilacji czterokrotnie.
gnasher729

Odpowiedzi:

16

Przypomina mi się kilka rzeczy:

  1. Skorzystaj z kompilacji rozproszonej . Możesz to zrobić za pomocą GCC („distCC”?) Lub VC ( Xredax IncrediBuild nie jest do końca tani, ale warty każdego wydanego na niego centa).

  2. Podziel swój projekt na dynamicznie ładowane biblioteki i staraj się minimalizować zależności od nich. Mniejsze pliki wykonywalne łączą się znacznie szybciej.

  3. Program przeciwko małym projektom testowym, a nie całej dużej aplikacji.

  4. Wykorzystaj programowanie szablonów do wykonywania algorytmów w czasie kompilacji . Tak, w rzeczywistości wydłuży to czas kompilacji, ale zmniejszy również liczbę zwrotów potrzebnych do testowania: jeśli kompilacja przebiegnie poprawnie, zostanie wykonana.

  5. Zainwestuj w sprzęt . Więcej jąder procesora (na twoim komputerze lub innych) zrobi cuda z kompilacją rozproszoną, a dużo pamięci plus szybki dysk (SSD zamiast HDD) bardzo pomoże. Jeśli masz system 64-bitowy i nieprzyzwoite ilości pamięci RAM, kompilacja na dysku RAM może zapewnić niesamowity wzrost prędkości.

sbi
źródło
1
pamięci podręczne kompilatorów są moim lepszym pomysłem niż kompilacja rozproszona.
pqnet
Mówiąc o dysku RAM vs. SSD, byłem dość zaskoczony, że nie przyniósł on tak dużego wzrostu prędkości kompilacji. Mój obecny projekt (Java na Androida) kompiluje się ze stanu czystego w około 45 sekund z dysku SSD i w około 40 sekund z dysku RAM (a cały łańcuch narzędzi znajduje się na dysku RAM, a nie tylko źródłach). Nie dramatyczny wzrost, powiedziałbym.
Haspemulator
10

Innym rozwiązaniem technicznym, o którym jeszcze nie wspomnieli, jest przejście na dyski półprzewodnikowe zamiast zwykłych dysków twardych. W poprzednim projekcie, nad którym pracowałem, dyski SSD skróciły czas kompilacji z zakresu od 30 minut do 3.

Oczywiście są one kosztowne. Dla swojego szefa oblicz cenę utraconego czasu programisty na podstawie ceny jednorazowej inwestycji. Inwestycja prawdopodobnie zwróci się za kilka miesięcy.

Péter Török
źródło
6
To interesujące. Oznacza to, że 90% czasu kompilacji to opóźnienie dysku we / wy.
Mike Dunlavey
Nie widziałem 90% spadku, ale znaczny. Wydaje się, że nie przyspiesza kompilacji, ale zdecydowanie przyspiesza łączenie. Jeśli dokonujesz drobnych zmian w dużym projekcie (więc zmiana nie zawiera dużo kompilacji) i łączysz się, możesz to uzyskać. (To jest Visual Studio 2008, przy użyciu C ++.)
David Thornley
1
To jest dobry pomysł. Również zamontowanie części pamięci RAM w systemie plików działałoby szybko i jest tanie.
Goran Jovic
2
Ramdisk jest jeszcze szybszy (i tańszy).
SK-logic
1
@John: Tak, dobrze napisany kompilator powinien (IMHO) być powiązany z I / O.
Mike Dunlavey,
3

Więcej planowania, kodowanie większych fragmentów, pisanie testów integracyjnych zamiast testów jednostkowych i uruchamianie kompilacji + zestawu testowego przez noc.

Nemanja Trifunovic
źródło
3

Długie czasy kompilacji są czasem problemem, ale wspomniana już modularyzacja może pomóc to przezwyciężyć (głównie).

Znacznie poważniejsze jest utknięcie w środowisku, w którym nie można w ogóle kompilować, w którym każda zmiana kodu musi zostać przesłana do innego działu na innym kontynencie w celu zastosowania w środowisku testowym / programistycznym. Proces ten może potrwać kilka dni.

Pracuję teraz w takim środowisku, a ten system kosztował mnie już ponad tydzień (a projekt ma budżet tylko na 4 tygodnie, zanim pieniądze się skończą) tylko po to, aby zainstalować początkową wersję naszych zmian (a następnie popełnili błędy, które powodują, że część plików nie jest pobierana przez serwer aplikacji, więc patrzymy na kilka kolejnych dni opóźnień). Każda drobna zmiana (powiedzmy, że w testach znajduje się coś, co wymaga naprawy, na przykład brakujący błąd) może spowodować opóźnienie o kolejny dzień lub więcej.

W takich warunkach próbujesz upewnić się, że nie ma żadnych błędów, zanim nawet spróbujesz skompilować kod. Czuję się prawie tak, jakbym wrócił do programowania na komputerach mainframe, gdzie mieliśmy 5 minut czasu procesora na miesiąc na wszystkie prace kompilacyjne i testowe.

jwenting
źródło
1
Chłopie, to sytuacja z piekła rodem. Pamiętam dni komputerów mainframe. Przeprowadziliśmy wiele „sprawdzania biurka” kodu. To niesamowite, jak wiele w ten sposób zrobiono, takie jak niekończące się symulacje lotów na Księżyc.
Mike Dunlavey
3

Z łatwością pamiętam, kiedy kompilacje trwały długo. Niektóre podejścia łagodzące:

  • Zbuduj system, łącząc biblioteki lub biblioteki dll. W ten sposób, gdy modyfikujesz jakiś kod, jedyną częścią, która wymaga ponownej kompilacji, jest twoja część.
  • Liczba punktów w kodzie, które należy edytować, aby zaimplementować funkcję, wpływa nie tylko na to, ile edycji trzeba wykonać, ale także na częstotliwość występowania błędów, wzmacniając pętlę kompilacji-debugowania-edycji-kompilacji. Pomaga wszystko, co zmniejsza redundancję kodu, takie jak DRY.
  • Jeśli jesteś w debugerze i możesz edytować, rekompilować i kontynuować bez opuszczania debugera, to jest naprawdę pomocne.
Mike Dunlavey
źródło
2

10+ minut na kompilację? Poważnie?

Czy używasz IDE, które tworzy przyrostowe budowanie (np. Eclipse)? Jeśli nie, prawdopodobnie powinieneś to zrobić, podstawowa kompilacja zajmie kilka sekund, a nie minut.

A może mówisz o integracji, w której musisz zbudować całą aplikację, aby przetestować zmianę? Jeśli tak, spójrz na mniejsze testy, aby upewnić się, że główne błędy nie występują w kodzie, zanim będziesz musiał wykonać pełną kompilację.

TrueDub
źródło
5
10 minut jest małe. Pracowałem nad projektem, który zajął godzinę, aby skompilować i połączyć od zera na maszynie z jednym rdzeniem, PCH i wszystkim innym. Oczywiście, z wyjątkiem automatycznych kompilacji wydania, nikt nie zbudowałby go tylko na jednym rdzeniu procesora, ale nadal ... Gdybyś musiał zmienić coś w nagłówku, który jest zawarty prawie wszędzie (manipulacja ciągami, obsługa błędów), możesz zwariować.
sbi
2
Używany do pracy (lata temu) w systemie, którego skompilowanie zajęło 48 godzin. Oczywiście pełna wersja została uruchomiona dopiero w piątek wieczorem, miejmy nadzieję, że do zrobienia, kiedy wrócimy do biura w poniedziałek. Zamiast tego zbudowaliśmy w razie potrzeby małe moduły (powiedzmy pojedynczą bibliotekę DLL).
jwenting
2
-1 do wszystkich powyższych komentarzy, gdybym mógł +1 do TrueDub. Tak, jeśli wszystko kompilujesz ponownie, może to potrwać bardzo długo. Jeśli jednak w ogóle zastanowimy się nad zarządzaniem zależnościami, normalne jest, że 10-godzinne projekty ponownej kompilacji mogą mieć kompilacje przyrostowe w mniej niż minutę. Wszyscy powinniście się wstydzić marnowania czasu pracodawców na czekanie na rekompilacje, gdy zastosowanie odrobiny inteligencji pozwoli zaoszczędzić mnóstwo czasu.
Dunk
2
A jeśli pracujesz w małym sklepie, który zdarza się, że siedzi przy projekcie kilku MLoC, oznacza to, że znaczna część kodu jest stara, rozpoczęła się dekadę temu jako wiele małych projektów, w których szybkość kompilacji nigdy nie była problemem, a zarządzanie zależnościami jest okropnie złe. Więc powiesz takiej firmie, żeby wyrzuciła to wszystko i poświęciła kolejną dekadę na jej ponowne pisanie?
sbi
2
@Dunk: To była mała firma z mniej niż tuzinem programistów pracujących nad projektem multi-MLoC. Różni się to bardzo od setek programistów: nie można od nowa niczego pisać od zera, ponieważ potrzeba na to lat. Mimo że nienawidziłem tego pomysłu, inwestowanie w kompilację rozproszoną było ekonomicznie wykonalne, a pisanie nie było. Och, i odziedziczyłem te interfejsy. :-xNie było mnie tam dziesięć lat temu, kiedy zostały wymyślone. (Zmieniłem wiele z tego kodu, aby stosować TMP, aby znaleźć więcej błędów przy kompilacji, a mniej w terenie.)
sbi
2

Po pierwsze, dlaczego tak długo zajmuje kompilacja?

  • Czy twoje środowisko (IDE, make, cokolwiek) obsługuje kompilacje przyrostowe? Upewnij się, że kompilujesz zmiany, a nie całość.
  • Jeśli masz maszynę wielordzeniową, twoje IDE może obsługiwać kompilację równoległą. Wiem na pewno, że Visual Studio to robi. Najwyraźniej robi to gcc. Zdobądź lepszą maszynę i włącz kompilację równoległą.
  • Rozważ użycie prekompilowanych nagłówków.
  • Jeśli spróbujesz tego wszystkiego, a kompilacja jest nadal powolna, sprawdź kod. Poszukaj niepotrzebnych zależności. Czy dołączasz nagłówek, w którym wystarczające byłoby przekazanie dalej? Rozważ użycie idiomu PIMPL w celu zmniejszenia zależności od nagłówków.

Jeśli po tym wszystkim czas kompilacji jest nadal wolny, rozwiąż problem: utwórz wiele małych projektów testowych i pracuj nad każdym z nich indywidualnie. Upewnij się, że masz zautomatyzowany system kompilacji nocnej, który wykonuje nową kasę, buduje wszystko i automatycznie uruchamia wszystkie testy jednostkowe.

Wreszcie, jeśli nadal zajmuje Ci dużo czasu testowanie zmian, zastanów się nad nimi. Pamiętaj, aby zrobić różnicę w systemie kontroli wersji i dokładnie przejrzyj wszystkie zmiany przed testowaniem. Krótko mówiąc, jest to bardzo podobne do rozwoju systemów wbudowanych, w których czas realizacji testu jest długi, a Twoja zdolność do badania stanu systemu jest ograniczona.

To prowadzi mnie do kolejnej myśli: instrumentuj swój kod, aby korzystać z rejestrowania. W ten sposób możesz zobaczyć, na czym polega problem, bez konieczności przebudowywania i ponownego uruchamiania kilkanaście razy.

Dima
źródło
2
Nie jestem pewien, czy GCC obsługuje kompilacje równoległe, tak samo jak fakt, że make lub podobne narzędzia uruchomią kilka kopii GCC, jeśli to powiesz.
Zachary K
1
+1 dla PIMPL. Pracowałem nad projektem, w którym czasy kompilacji wymknęły się spod kontroli. W tym projekcie nie dbałem o liczbę innych nagłówków zawartych w każdym nagłówku. W moim kolejnym projekcie postanowiłem zminimalizować to poprzez szerokie wykorzystanie PIMPL. Czasy kompilacji są nadal świetne, mimo że drugi projekt jest prawdopodobnie dwa razy większy od pierwszego.
Jason B,
1

Prawdopodobnie potrzebujesz podejścia z wieloma bolcami:

1) Szybsze systemy kompilacji. Tyle rdzeni / pamięci RAM / szybki dysk, jak możesz sobie pozwolić. W przypadku większych projektów C ++ przekonasz się, że dysk jest często ogranicznikiem, więc upewnij się, że masz szybkie.

2) Większa modularyzacja projektu. Rozbijaj rzeczy, aby zmiany nie mogły łatwo spowodować pełnej ponownej kompilacji wszystkiego. Szczerze mówiąc, umieść jak najwięcej podstawowych rzeczy w osobnych plikach dll / so, aby część projektu mogła być całkowicie oddzielona od reszty.

3) Przyrostowe kompilacje / kompilacje rozproszone / buforowanie odpowiednie dla twojego środowiska. W niektórych systemach distcc (budowanie rozproszone) i ccache (buforowanie częściowo zbudowanych rzeczy) mogą zaoszczędzić dużo czasu na kompilacji.

4) Upewnij się, że twoja kompilacja może być dobrze równoległa. Szczególnie w środowisku makefile nietrudno jest znaleźć się w sytuacji, w której przypadkowo skonfigurowałeś pliki Makefile w taki sposób, że nie możesz budować równolegle.

Michael Kohne
źródło
0

Obszerne rejestrowanie i wewnętrzna weryfikacja okazały się pomocne w przypadku długich czasów realizacji. Po zakończeniu kompilacji pojedynczy przebieg może ujawnić duży zestaw możliwych problemów naraz.

W przypadku skomplikowanych algorytmów lub księgowości pomocne może być dołączenie bardzo uproszczonej wersji równoległej do „rzeczywistej”. W każdym uruchomieniu masz przydatne dane referencyjne.

Joris Geer
źródło
0

Co powiedzieli @sbi i @Michael Kohne.

Poświęć czas i energię na sam proces kompilacji. Dawno, dawno temu mieliśmy okazały, dojrzały produkt, którego pełna wersja trwała ponad godzinę. Dużo czasu i energii poświęcono na naprawienie zależności, które twierdzą, że są kompilacjami, a następnie na naprawienie / zmniejszenie ich rzeczywistych wartości. Czas budowy spadł do ~ 30 minut.

Zmiana narzędzi do budowania upuściła go bardziej. W przypadku projektu wieloczęściowego program „scons” może wykonać wszystkie kompilacje przed wykonaniem jakichkolwiek łączy. „make” przy użyciu wielu plików makefile kompiluje jeden projekt przed łączami tego projektu, a następnie przechodzi do następnego.

To doprowadziło nas do tego, że wszystkie indywidualne polecenia kompilacji można wykonywać masowo równolegle. 'distcc' na wolnych komputerach, make / scons -j8 na komputerach wielordzeniowych. Spowodowało to pełne kompilacje do kilku minut.

W innym świetle utwórz automatyczny proces budowania co noc. W ten sposób, jeśli coś problematycznego zostanie popełnione w twoim repozytorium źródłowym, pierwsza osoba, która przyjdzie do pracy, zobaczy i rozwiąże problem, może uniemożliwić wielu osobom (ponowne) wykonanie wielu nieudanych kompilacji.

Rick Berge
źródło