Mõni aeg tagasi (2016. aasta sügisel), kui arendati tehnoloogilise platvormi 1C: Ettevõte uut versiooni, kerkis arendusmeeskonnas küsimus uue standardi toetamise kohta meie koodis. Üleminek uuele standardile, nagu me oletame, võimaldaks meil kirjutada paljusid asju elegantsemalt, lihtsamalt ja usaldusväärsemalt, lihtsustades koodi toetust ja hooldust. Ja tõlkes ei tundu olevat midagi erakordset, kui mitte arvestada koodibaasi ulatust ja meie koodi spetsiifilisi omadusi.
Neile, kes ei tea, 1C: Ettevõte on keskkond kiireks mitmeplatvormiliste ärianalüüside arendamiseks ja nende käitamiseks erinevates opsüsteemides ja andmebaasides. Üldiselt kuuluvad toote koosseisu:
- , töötab Windowsil ja Linuxil
- , mis suhtleb serveriga http(s) kaudu või oma binaarprotokolli kaudu, töötab Windowsil, Linuxil, macOS-il
- , töötab brauserites Chrome, Internet Explorer, Microsoft Edge, Firefox, Safari (kirjutatud JavaScriptis)
- Arenduskeskkond (), töötab Windowsil, Linuxil, macOS-il
- Mobiiliklient
- , serveriga http(s) kaudu ühendatav, töötab Androidi, iOSi ja Windowsi töötavatel mobiilseadmetel
- — raamistiku mobiilirakenduste loomiseks, mis töötavad Androidi, iOSi ja Windowsi seadmetes ning pakuvad sünkroonimise võimalust
- Arenduskeskkond , kirjutatud Java keeles
- Server
Püüame maksimaalselt kirjutada ühte koodi erinevatele operatsioonisüsteemidele – serveri koodibaas on 99% ühine, kliendi oma umbes 95%. Tehnoloogiline platvorm 1C: Ettevõte on enamasti kirjutatud C++ keeles ja allpool on ligikaudsed koodi omadused:
- 10 miljonit C++ koodi rida,
- 14 tuhat faili,
- 60 tuhat klassi,
- poole miljoni meetodit.
Ja kogu see süsteem tuli C++14 peale üle viia. Kuidas me seda tegime ja millega me protsessi käigus silmitsi seisime, räägime täna.

Vastutusest loobumine
All the text below about slow/fast performance and (non)trivial memory consumption of standard class implementations in various libraries means one thing: this is true FOR US. It is quite possible that the standard implementations suit your tasks best. We based our work on our needs: we took typical data from our clients, ran typical scenarios on them, observed performance, memory consumption, and so forth, and analyzed whether such results satisfied us and our clients or not. We then acted accordingly.
What we had
Initially, we wrote the code for the 1C:Enterprise 8 platform using Microsoft Visual Studio. The project started in the early 2000s, and we only had a version for Windows. Naturally, since then the code has evolved significantly, and many mechanisms have been completely rewritten. However, the code was written according to the 1998 standard, and, for example, the right angle brackets were spaced to allow for successful compilation, like this:
vector<vector > IntV;In 2006, with the release of version 8.1 of the platform, we began supporting Linux and switched to a third-party standard library. . Üks põhjuseid üleminekuks oli töötamine laiade laudadega. Meie koodis kasutame laialdaselt std::wstring, mis põhineb tüübile wchar_t. Selle suurus Windowsis on 2 bitti, Linuxis aga vaikimisi 4 bitti. See põhjustas meie binaarsete protokollide ühilduvuse probleemid kliendi ja serveri vahel, samuti erinevate püsivate andmete osas. Gcc valikute abil saab määrata, et wchar_t suurus kompileerimisel oleks samuti 2 bitti, kuid siis võib standardse raamatukogu kasutamisest unustada, kuna see kasutab glibc't, mis on omakorda kompileeritud 4-bitiseks wchar_t-ks. Muudeks põhjusteks olid paremad standardklasside rakendused, häshtabelite tugi ja isegi konteinerite sees liikumise semantika emuleerimine, mida me aktiivselt kasutasime. Ja veel üks põhjus, nagu öeldakse, last but not least, oli stringide jõudlus. Meil oli oma klass stringide jaoks, kuna meie tarkvara eripära tõttu kasutame stringi operatsioone väga laialdaselt ja see on meie jaoks kriitiline.
Meie string põhineb stringide optimeerimise ideedel, mis väljendati juba 2000. aastate alguses . Hiljem, kui Alexandrescu töötas Facebookis, kasutati tema ettepanekul Facebooki mootoris sarnase põhimõttega rida (vt raamatukogu ).
Meie real kasutati kahte peamist optimeerimistehnoloogiat:
- Lühikeste väärtuste jaoks kasutatakse sisemist puhversäilitust, mis asub stringi objekti enda sees (mis ei nõua täiendavat mälu eraldamist).
- Kõikide teiste jaoks kasutatakse mehaanikat . Stringi väärtus salvestatakse ühte kohta, selle määramisel/modifitseerimisel kasutatakse viidatud loendurit.
Kuna meie platformi kompileerimist kiirusme tõhustamiseks väljastasime STLPorti variandi voogude teostuse (mida me ei kasutanud), andis see meile ligikaudu 20% kiirusme tõhususe. Hiljem pidime kergelt kasutama . Boost kasutab aktiivselt vooge, kaasa arvatud oma teeninduse API-des (näiteks logimise jaoks), seetõttu pidime seda modifitseerima, et välistada voogude kasutamine. See omakorda raskendas meil uutele Boosti versioonidele üleminekut.
Kolmas tee
C++14 standardile ülemisel arutasime selliseid variante:
- Kohandame meie modifitseeritud STLPorti standardile C++14. See valik on äärmiselt keeruline, kuna STLPorti tugi lõpetati 2010. aastal ja selle kogu koodi taastamine oleks pidanud meie poolt toimuma.
- Üleminekisele teisele STL-implementatsioonile, mis on ühilduv C++14-ga. Eelistatavalt peaks see implementatsioon olema Windowsi ja Linuxi jaoks.
- Kasutame iga operatsioonisüsteemi kompileerimisel vastava kompilaatori sisseehitatud teeki.
Esimene variant lükati kohe tagasi liiga suure töömahu tõttu.
Mõtlesime mõnda aega teisele võimalusele; kandidaadina vaatasime , kuid sel ajal ei töötanud see Windowsi all. Libc++ portimiseks Windowsi, oleks pidanud palju tööd tegema — näiteks kirjutama ise kõik, mis puudutab lõime, lõimede sünkroniseerimist ja atomaarset käitumist, kuna libc++-is kasutati nendes valdkondades .
Ja me valisime kolmanda variandi.
Üleminek
Seega pidime asendama STLPorti kasutamise vastavate kompilaatorite teekidega (Visual Studio 2015 Windowsi jaoks, gcc 7 Linuxi jaoks, clang 8 macOS-i jaoks).
Õnneks oli meie kood peamiselt kirjutatud juhiste järgi ega kasutanud igasuguseid kavalusi, nii et migratsioon uutele raamatukogudele kulges suhteliselt sujuvalt, kasutades skripte, mis asendasid lähtefailides tüüpide, klasside, nimede ja lisade nimed. Migratsioon hõlmas 10 000 lähtefaili (kokku 14 000). wchar_t asendati char16_t-ga; otsustasime loobuda wchar_t kasutamisest, kuna char16_t võtab kõikides opsüsteemides 2 baiti ja ei rikku koodi ühilduvust Windowsi ja Linuxi vahel.
Ilma väikeste seiklusteta ei saanud hakkama. Näiteks STLPort'is võisit iteraatori implitsiitselt elemendi pointeriks castida, ja mõnes meie koodi osas see toimis. Uutes raamatukogudes see enam ei toiminud, seega tuli neid kohti analüüsida ja käsitsi ümber kirjutada.
Nii et koodi migratsioon on lõpule viidud, kood kompileerub kõigis opsüsteemides. On saanud aeg testimiseks.
Üleminekust tehtud testid näitasid, et jõudlus langes (kohati 20-30%) ja mälu tarbimine suurenes (10-15%) võrreldes vana koodiversiooniga. See oli peamiselt tingitud standardsete konteinerite ebapiisavast toimimisest. Seetõttu pidime taas oma, veidi täiustatud versiooni kasutama.
Samuti ilmus välja huvitav omadus konteinerite rakendamisel sisseehitatud raamatukogudes: tühjad (ilma elementideta) std::map ja std::set sisseehitatud raamatukogudes eraldavad mälu. Meie koodi eripära tõttu luuakse mõnes kohas üsna palju selliseid tühje konteinerite. Standardsete konteinerite mälutarve on väike, ühe juureelemendi jaoks, kuid meie jaoks osutus see kriitiliseks – mitmes stsenaariumis langes meie jõudlus oluliselt ja mälu tarbimine suurenes (võrreldes STLPortiga). Seetõttu asendasime meie koodis need kaks tüüpi konteinerit sisseehitatud raamatukogudest Boosti rakendustena, kus sellist omadust ei olnud, ja see lahendas probleemi aeglustumise ja suurenenud mälu tarbimisega.
Nagu sageli juhtub suurte projektide ulatuslike muutuste järel, ei töötanud esialgne versioon probleemideta. Siin tuli meile väga abiks Windowsi rakenduste silumisiteratorite tugi. Samm-sammult liikudes olime kevadeks 2017 (versioon 8.3.11 1C:Enterprise) migratsiooni lõpetanud.
Kokkuvõte
Üleminek standardile C++14 võttis meil umbes 6 kuud. Enamiku ajast töötas projekti kallal üks (kuid väga kvalifitseeritud) arendaja, ning lõppfaasis liitusid projektiga valdkondade esindajad — UI, serverikluster, arendus- ja haldustooted jne.
Üleminek lihtsustas meie tööd uusimate versioonide standardisse migreerimisel. Näiteks versioon 1C:Enterprise 8.3.14 (arenduses, vabanemine on planeeritud järgmise aasta alguses) on juba standardile .
Pärast migreerimist on arendajatel rohkem võimalusi. Kui varem oli meil oma täiendatud versioon STL-ist ja üks nimede ruum std, siis nüüd asuvad nimede ruumis std kompilatori sisseehitatud raamatukogude standardklassid, nimede ruumis stdx – meie, meie ülesannete jaoks optimeeritud stringid ja konteinerid, boost-is – värske boost'i versioon. Ja arendaja kasutab neid klasse, mis sobivad tema ülesannete lahendamiseks kõige paremini.
Arendamist aitab samuti ka "looduslik" reaaliseerimine liikumiseks konstruktoritest () mitmete klasside jaoks. Kui klassil on liikumiseks konstruktor ja see klass paigutatakse konteinerisse, siis STL optimeerib elementide kopeerimist konteineri sees (näiteks siis, kui konteiner laiendab ja tuleb muuta võimsust ning reallocate (taaskäitatav) mälu).
Tõrva lusikas
Võib-olla kõige ebameeldivam (aga mitte kriitiline) tagajärg migreerimisest — me oleme kokku puutunud obj-failide mahu suurenemisega , ja kogu ehitusresultaat koos kõigi vahefailidega hakkas võtma 60–70 GB. Selline käitumine on seotud kaasaegsete standardraamatukogude eripäradega, mis on hakanud vähem kriitiliselt suhtuma genereeritud abifailide mahusse. See ei mõjuta kompileeritud rakenduse tööd, kuid tekitab arenduses mitmeid ebamugavusi, sealhulgas pikendab kompileerimisaega. Suurenevad ka nõudmised vaba ruumi osas kettal ehitusteenustes ja arendajate masinates. Meie arendajad töötavad paralleelselt mitme platvormi versiooniga ning sadade gigabaitide vahefailid loomulikult toovad mõningaid raskusi. Probleem on ebameeldiv, kuid mitte kriitiline, selle lahendamine on seni edasi lükatud. Üheks võimalikuks lahendusteks kaalume tehnikat (seda kasutab näiteks Google, kui ta arendab Chrome'i brauserit).
Allikas: habr.com
