Hvernig við þýddum 10 milljón línur af C++ kóða yfir á C++14 staðalinn (og síðan í C++17)

Fyrir nokkru síðan (haustið 2016), við þróun næstu útgáfu 1C:Enterprise tæknivettvangsins, vaknaði spurningin innan þróunarteymisins um stuðning við nýja staðalinn C ++ 14 í kóðanum okkar. Umskipti yfir í nýjan staðal, eins og við gerðum ráð fyrir, myndi gera okkur kleift að skrifa margt glæsilegra, einfaldara og áreiðanlegra og myndi einfalda stuðning og viðhald kóðans. Og það virðist ekkert óvenjulegt í þýðingunni, ef ekki væri fyrir mælikvarða kóðagrunnsins og sérstakra eiginleika kóðans okkar.

Fyrir þá sem ekki vita er 1C:Enterprise umhverfi fyrir hraðri þróun viðskiptaforrita á milli vettvanga og keyrslutíma fyrir framkvæmd þeirra á mismunandi stýrikerfi og DBMS. Almennt séð inniheldur varan:

Við reynum að skrifa sama kóða fyrir mismunandi stýrikerfi eins mikið og hægt er - miðlarakóðagrunnurinn er 99% algengur, biðlarakóðagrunnurinn er um 95%. 1C:Enterprise tæknivettvangurinn er fyrst og fremst skrifaður í C++ og áætluð einkenni kóða eru gefin hér að neðan:

  • 10 milljón línur af C++ kóða,
  • 14 þúsund skrár,
  • 60 þúsund bekkir,
  • hálf milljón aðferðir.

Og allt þetta dót þurfti að þýða yfir á C++14. Í dag munum við segja þér hvernig við gerðum þetta og hvað við lentum í í ferlinu.

Hvernig við þýddum 10 milljón línur af C++ kóða yfir á C++14 staðalinn (og síðan í C++17)

Fyrirvari

Allt sem skrifað er hér að neðan um hæga/hraða vinnu, (ekki) mikla minnisnotkun með útfærslum á stöðluðum flokkum í ýmsum bókasöfnum þýðir eitt: þetta er satt FYRIR OKKUR. Það er alveg mögulegt að staðlaðar útfærslur henti best fyrir verkefni þín. Við byrjuðum á okkar eigin verkefnum: við tókum gögn sem voru dæmigerð fyrir viðskiptavini okkar, keyrðum dæmigerðar atburðarás á þeim, skoðuðum frammistöðu, magn minnis sem neytt er o.s.frv., og greindum hvort við og viðskiptavinir okkar værum ánægðir með slíkar niðurstöður eða ekki . Og þeir virkuðu eftir því.

Það sem við áttum

Upphaflega skrifuðum við kóðann fyrir 1C:Enterprise 8 pallinn í Microsoft Visual Studio. Verkefnið hófst snemma á 2000. áratugnum og við vorum með Windows-útgáfu eingöngu. Auðvitað, síðan þá hefur kóðinn verið virkur þróaður, mörg kerfi hafa verið fullkomlega endurskrifuð. En kóðinn var skrifaður í samræmi við 1998 staðalinn, og til dæmis voru hornsvigarnir okkar aðskildir með bilum svo að samantekt myndi heppnast, svona:

vector<vector<int> > IntV;

Árið 2006, með útgáfu vettvangsútgáfu 8.1, byrjuðum við að styðja Linux og skiptum yfir í staðlað bókasafn þriðja aðila STLPort. Ein af ástæðunum fyrir umskiptum var að vinna með breiðar línur. Í kóðanum okkar notum við std::wstring, sem er byggt á wchar_t gerðinni, í gegn. Stærð hans í Windows er 2 bæti og í Linux er sjálfgefið 4 bæti. Þetta leiddi til ósamrýmanleika á tvöfaldri samskiptareglum okkar milli viðskiptavinar og netþjóns, auk ýmissa viðvarandi gagna. Með því að nota gcc valkostina geturðu tilgreint að stærð wchar_t við söfnun sé líka 2 bæti, en þá geturðu gleymt því að nota staðlaða bókasafnið úr þýðandanum, vegna þess að það notar glibc, sem aftur er sett saman fyrir 4-bæta wchar_t. Aðrar ástæður voru betri útfærsla á stöðluðum flokkum, stuðningur við kjötkássatöflur og jafnvel eftirlíkingu merkingarfræðinnar við að flytja inn í gáma, sem við notuðum virkan. Og enn ein ástæðan, eins og þeir segja síðast en ekki síst, var strengjaflutningur. Við vorum með okkar eigin flokk fyrir strengi, því... Vegna sérstakra hugbúnaðar okkar eru strengjaaðgerðir mjög víða notaðar og fyrir okkur er þetta mikilvægt.

Strengur okkar er byggður á hugmyndum um fínstillingu strengja sem komu fram í byrjun 2000 Andrei Alexandrescu. Seinna, þegar Alexandrescu starfaði hjá Facebook, að tillögu hans, var notuð lína í Facebook vélinni sem virkaði á svipuðum nótum (sjá bókasafn heimska).

Línan okkar notaði tvær helstu hagræðingartækni:

  1. Fyrir stutt gildi er innri biðminni í strenghlutnum sjálfum notaður (þarf ekki viðbótar minnisúthlutun).
  2. Fyrir alla aðra er vélfræði notuð Afrita á Skrifa. Strengjagildið er geymt á einum stað og viðmiðunarteljari er notaður við úthlutun/breytingu.

Til að flýta fyrir samantekt á vettvangi útilokuðum við straumútfærsluna frá STLPort afbrigðinu okkar (sem við notuðum ekki), þetta gaf okkur um 20% hraðari samantekt. Í kjölfarið þurftum við að nota takmarkað Uppörvun. Boost notar streymi mikið, sérstaklega í þjónustuforritaskilum sínum (til dæmis fyrir skráningu), svo við urðum að breyta því til að fjarlægja notkun á streymi. Þetta gerði það aftur á móti erfitt fyrir okkur að flytja yfir í nýjar útgáfur af Boost.

Þriðja leiðin

Þegar við fórum yfir í C++14 staðalinn íhuguðum við eftirfarandi valkosti:

  1. Uppfærðu STLPort sem við breyttum í C++14 staðalinn. Valkosturinn er mjög erfiður vegna þess að... Stuðningur við STLPort var hætt árið 2010 og við þyrftum að búa til allan kóðann sjálf.
  2. Umskipti yfir í aðra STL útfærslu samhæft við C++14. Það er mjög æskilegt að þessi útfærsla sé fyrir Windows og Linux.
  3. Þegar þú safnar saman fyrir hvert stýrikerfi skaltu nota bókasafnið sem er innbyggt í samsvarandi þýðanda.

Fyrsta valmöguleikanum var algjörlega hafnað vegna of mikillar vinnu.

Við hugsuðum um seinni kostinn í nokkurn tíma; talinn frambjóðandi libc++, en á þeim tíma virkaði það ekki undir Windows. Til að flytja libc++ yfir í Windows þyrftirðu að leggja mikið á þig - til dæmis skrifaðu allt sjálfur sem snýr að þráðum, þráðasamstillingu og atomicity, þar sem libc++ er notað á þessum sviðum POSIX API.

Og við völdum þriðju leiðina.

Umskipti

Þannig að við þurftum að skipta um notkun STLPort fyrir bókasöfn samsvarandi þýðenda (Visual Studio 2015 fyrir Windows, gcc 7 fyrir Linux, clang 8 fyrir macOS).

Sem betur fer var kóðinn okkar skrifaður aðallega eftir leiðbeiningum og notaði ekki alls kyns snjöll brellur, þannig að flutningurinn yfir í ný bókasöfn gekk tiltölulega vel fyrir sig, með hjálp skrifta sem komu í stað nöfn tegunda, flokka, nafnarúma og innihalda í upprunanum. skrár. Flutningurinn hafði áhrif á 10 frumskrár (af 000). wchar_t var skipt út fyrir char14_t; við ákváðum að hætta að nota wchar_t, vegna þess char000_t tekur 16 bæti á öllum stýrikerfum og spillir ekki kóðasamhæfni milli Windows og Linux.

Það voru smá ævintýri. Til dæmis, í STLPort gæti iterator verið óbeint varpað á bendil á frumefni, og sums staðar í kóðanum okkar var þetta notað. Í nýjum bókasöfnum var ekki lengur hægt að gera þetta og þurfti að greina þessa kafla og endurskrifa handvirkt.

Svo, kóðaflutningnum er lokið, kóðinn er settur saman fyrir öll stýrikerfi. Það er kominn tími á próf.

Prófanir eftir umskiptin sýndu lækkun á frammistöðu (sums staðar allt að 20-30%) og aukningu á minnisnotkun (allt að 10-15%) miðað við gamla útgáfu kóðans. Þetta var einkum vegna óhagkvæmrar frammistöðu staðlaðra strengja. Þess vegna þurftum við aftur að nota okkar eigin, lítið breytta línu.

Athyglisverð eiginleiki við útfærslu gáma í innbyggðum bókasöfnum kom einnig í ljós: tómt (án þátta) std::map og std::set frá innbyggðum bókasöfnum úthluta minni. Og vegna útfærslueiginleikanna eru sums staðar í kóðanum töluvert mikið af tómum gámum af þessari gerð. Stöðluðum minnisílátum er aðeins úthlutað fyrir einn rótarþátt, en fyrir okkur reyndist þetta mikilvægt - í mörgum tilfellum lækkaði árangur okkar verulega og minnisnotkun jókst (samanborið við STLPort). Þess vegna, í kóðanum okkar, skiptum við þessum tveimur tegundum gáma úr innbyggðu bókasöfnunum út fyrir útfærslu þeirra frá Boost, þar sem þessir gámar höfðu ekki slíkan eiginleika, og þetta leysti vandamálið með hægagangi og aukinni minnisnotkun.

Eins og oft gerist eftir umfangsmiklar breytingar á stórum verkefnum virkaði fyrsta endurtekning frumkóðans ekki vandræðalaust og hér kom sérstaklega stuðningur við villuleit í endurtekningu í Windows útfærslu að góðum notum. Skref fyrir skref komumst við áfram og vorið 2017 (útgáfa 8.3.11 1C:Enterprise) var flutningnum lokið.

Niðurstöður

Umskiptin yfir í C++14 staðalinn tók okkur um 6 mánuði. Oftast vann einn (en mjög hæfur) verktaki að verkefninu og á lokastigi bættust við fulltrúar teyma sem bera ábyrgð á tilteknum sviðum - HÍ, netþjónaklasa, þróunar- og stjórnunarverkfæri o.s.frv.

Umskiptin einfaldaði mjög vinnu okkar við að flytja yfir í nýjustu útgáfur staðalsins. Þannig hefur útgáfa 1C:Enterprise 8.3.14 (í þróun, útgáfa áætluð í byrjun næsta árs) þegar verið flutt yfir í staðalinn C++17.

Eftir flutninginn hafa verktaki fleiri valkosti. Ef við höfðum áður okkar eigin breytta útgáfu af STL og eitt std nafnrými, nú höfum við staðlaða flokka úr innbyggðu þýðandasöfnunum í std nafnrýminu, í stdx nafnarýminu - línurnar okkar og ílát fínstillt fyrir verkefni okkar, í uppörvun - nýjasta útgáfan af boost. Og verktaki notar þá flokka sem henta best til að leysa vandamál hans.

„Innfædd“ útfærsla hreyfismiða hjálpar einnig við þróun (færa byggingaraðila) fyrir fjölda flokka. Ef flokkur er með flutningssmið og þessi flokkur er settur í gám, þá fínstillir STL afritun þátta inni í gámnum (til dæmis þegar gámurinn er stækkaður og nauðsynlegt er að breyta getu og endurúthluta minni).

Fly í smyrslið

Kannski er óþægilegasta (en ekki mikilvægasta) afleiðing fólksflutninga að við stöndum frammi fyrir aukningu á magni obj skrár, og heildarniðurstaða smíðinnar með öllum milliskrám fór að taka upp 60–70 GB. Þessi hegðun stafar af sérkennum nútíma staðlaðra bókasöfna, sem hafa orðið minna gagnrýnin á stærð mynda þjónustuskráa. Þetta hefur ekki áhrif á virkni samsetta forritsins, en það veldur ýmsum óþægindum í þróun, sérstaklega eykur það samantektartíma. Kröfur um laust pláss á smíðaþjónum og á þróunarvélum eru einnig að aukast. Hönnuðir okkar vinna á nokkrum útgáfum af pallinum samhliða og hundruð gígabæta af milliskrám skapa stundum erfiðleika í starfi þeirra. Vandamálið er óþægilegt en ekki mikilvægt; við höfum frestað lausn þess í bili. Við lítum á tækni sem einn af kostunum til að leysa hana einingu byggja (sérstaklega notar Google það við þróun Chrome vafrans).

Heimild: www.habr.com

Bæta við athugasemd