Wéi mir 10 Millioune Linnen vum C++ Code an den C++14 Standard iwwersat hunn (an dann op C++17)

Virun enger Zäit (am Hierscht 2016), während der Entwécklung vun der nächster Versioun vun der 1C:Enterprise Technologie Plattform, ass d'Fro am Entwécklungsteam opgestan iwwer d'Ënnerstëtzung vum neie Standard C ++ 14 an eisem Code. Den Iwwergank zu engem neie Standard, wéi mir ugeholl hunn, erlaabt eis vill Saachen méi elegant, einfach an zouverlässeg ze schreiwen an d'Ënnerstëtzung an den Ënnerhalt vum Code ze vereinfachen. An et schéngt näischt aussergewéinleches an der Iwwersetzung ze sinn, wann net fir d'Skala vun der Codebasis an déi spezifesch Features vun eisem Code.

Fir déi, déi net wëssen, 1C: Enterprise ass en Ëmfeld fir déi séier Entwécklung vu Cross-Plattform Geschäftsapplikatiounen a Runtime fir hir Ausféierung op verschidden OSen an DBMSs. Am Allgemengen, enthält de Produit:

  • Applikatioun Server Cluster, leeft op Windows a Linux
  • Client, schafft mam Server iwwer http(en) oder säin eegene binäre Protokoll, funktionnéiert op Windows, Linux, macOS
  • Web Client, Lafen a Chrome, Internet Explorer, Microsoft Edge, Firefox, Safari Browser (geschriwwe a JavaScript)
  • Entwécklung Ëmfeld (Konfigurator), funktionnéiert op Windows, Linux, macOS
  • Administratioun Tools Applikatiounsserver, lafen op Windows, Linux, macOS
  • Mobile Client, Verbindung mam Server iwwer http(en), funktionnéiert op mobilen Apparater mat Android, iOS, Windows
  • Mobil Plattform - e Kader fir offline mobil Uwendungen ze kreéieren mat der Fäegkeet fir ze synchroniséieren, lafen op Android, iOS, Windows
  • Entwécklung Ëmfeld 1C: Enterprise Entwécklung Tools, op Java geschriwwen
  • Server Interaktioun Systemer

Mir probéieren de selwechte Code fir verschidde Betribssystemer sou vill wéi méiglech ze schreiwen - d'Servercodebasis ass 99% heefeg, d'Clientcodebasis ass ongeféier 95%. D'1C: Enterprise Technologie Plattform ass haaptsächlech an C ++ geschriwwe ginn an ongeféier Code Charakteristiken ginn hei ënnen uginn:

  • 10 Millioune Linnen C++ Code,
  • 14 dausend Dateien,
  • 60 dausend Klassen,
  • eng hallef Millioun Methoden.

An all dës Saachen hu missen an C++14 iwwersat ginn. Haut wäerte mir Iech soen wéi mir dëst gemaach hunn a wat mir am Prozess begéint hunn.

Wéi mir 10 Millioune Linnen vum C++ Code an den C++14 Standard iwwersat hunn (an dann op C++17)

Verzichterklärung

Alles geschriwwen ënnert iwwer lues / séier Aarbecht, (net) grousse Erënnerung Konsum vun Implementatioune vun Standard Klassen a verschiddene Bibliothéiken heescht eng Saach: dëst ass wouer FIR US. Et ass ganz méiglech datt Standardimplementatiounen am Beschten fir Är Aufgaben passend sinn. Mir hunn vun eisen eegenen Aufgaben ugefaang: mir hunn Daten geholl, déi typesch fir eise Clienten waren, hunn typesch Szenarie dorop ausgefouert, d'Leeschtung gekuckt, d'Quantitéit u verbraucht Erënnerung, asw., an analyséiert ob mir an eis Clienten mat esou Resultater zefridden waren oder net . A si hunn ofhängeg gehandelt.

Wat mir haten

Am Ufank hu mir de Code fir d'1C: Enterprise 8 Plattform geschriwwen mat Microsoft Visual Studio. De Projet huet am fréien 2000er ugefaang a mir haten eng Windows-nëmmen Versioun. Natierlech, zënterhier ass de Code aktiv entwéckelt, vill Mechanismen sinn komplett nei geschriwwe ginn. Awer de Code gouf nom 1998 Standard geschriwwen, an zum Beispill, eis richtege Wénkel Klammern goufen duerch Plazen getrennt, sou datt d'Kompilatioun geléngt, sou:

vector<vector<int> > IntV;

Am Joer 2006, mat der Verëffentlechung vun der Plattform Versioun 8.1, hu mir ugefaang Linux z'ënnerstëtzen an op eng Drëtt-Partei Standardbibliothéik gewiesselt STLPort. Ee vun de Grënn fir den Iwwergang war mat breet Linnen ze schaffen. An eisem Code benotze mir std :: wstring, dee baséiert op dem wchar_t Typ, uechter. Seng Gréisst am Windows ass 2 Bytes, a Linux ass de Standard 4 Bytes. Dëst huet zu Inkompatibilitéit vun eise binäre Protokoller tëscht Client a Server gefouert, souwéi verschidde persistent Daten. Mat de gcc Optiounen kënnt Dir spezifizéieren datt d'Gréisst vum wchar_t wärend der Compilatioun och 2 Bytes ass, awer da kënnt Dir vergiessen d'Standardbibliothéik vum Compiler ze benotzen, well et benotzt glibc, deen am Tour fir e 4-Byte wchar_t kompiléiert ass. Aner Grënn waren eng besser Ëmsetzung vun Standard Klassen, Ënnerstëtzung fir Hash Dëscher, an esouguer Emulatioun vun der Semantik vun Plënneren bannent Container, déi mir aktiv benotzt. An ee méi Grond, wéi se soen lescht awer net zulescht, war String Leeschtung. Mir haten eis eege Klass fir Sträicher, well ... Wéinst de Spezifizitéite vun eiser Software gi Stringoperatioune ganz wäit benotzt a fir eis ass dëst kritesch.

Eis String baséiert op Stringoptimiséierungsideen, déi an de fréien 2000er ausgedréckt goufen Andrei Alexandrescu. Méi spéit, wéi den Alexandrescu bei Facebook geschafft huet, gouf op sengem Virschlag eng Zeil am Facebook-Moteur benotzt, déi op ähnleche Prinzipien geschafft huet (kuckt Bibliothéik Dommheet).

Eis Linn huet zwee Haaptoptimiséierungstechnologien benotzt:

  1. Fir kuerz Wäerter gëtt en internen Puffer am Stringobjekt selwer benotzt (erfuerdert keng zousätzlech Erënnerungsallokatioun).
  2. Fir all aner gëtt Mechanik benotzt Kopie op Schreiwen. De Stringwäert gëtt op enger Plaz gespäichert, an e Referenzteller gëtt während der Aufgab / Ännerung benotzt.

Fir d'Plattformkompiléierung ze beschleunegen, hu mir d'Streamimplementatioun aus eiser STLPort Variant ausgeschloss (déi mir net benotzt hunn), dëst huet eis ongeféier 20% méi séier Kompiléierung ginn. Duerno hu mir limitéiert Notzung misse maachen Schwong. Boost mécht schwéier Notzung vu Stream, besonnesch a senge Service APIs (zum Beispill fir Logging), also hu mir et missen änneren fir d'Benotzung vum Stream ze läschen. Dëst, am Tour, huet et schwéier gemaach fir eis op nei Versioune vu Boost ze migréieren.

Drëtte Wee

Wann Dir op de C ++ 14 Standard plënnert, hu mir déi folgend Optiounen ugesinn:

  1. Upgrade de STLPort, dee mir op den C ++ 14 Standard geännert hunn. D'Optioun ass ganz schwéier, well ... Ënnerstëtzung fir STLPort gouf gestoppt an 2010, a mir mussen all seng Code selwer bauen.
  2. Iwwergank op eng aner STL Implementatioun kompatibel mat C ++ 14. Et ass héich wënschenswäert datt dës Implementatioun fir Windows a Linux ass.
  3. Wann Dir fir all OS kompiléiert, benotzt d'Bibliothéik déi am entspriechende Compiler gebaut ass.

Déi éischt Optioun gouf wéinst ze vill Aarbecht direkt refuséiert.

Mir hunn iwwer déi zweet Optioun fir eng Zäit geduecht; als Kandidat ugesinn libc++, awer deemools huet et net ënner Windows geschafft. Fir libc++ op Windows ze portéieren, musst Dir vill Aarbecht maachen - zum Beispill alles selwer schreiwen wat mat Threads, Thread Synchroniséierung an Atomizitéit ze dinn huet, well libc++ an dëse Beräicher benotzt gëtt POSIX API.

A mir hunn den drëtte Wee gewielt.

Iwwergank

Also hu mir d'Benotzung vu STLPort duerch d'Bibliothéike vun den entspriechende Compileren ersat (Visual Studio 2015 fir Windows, gcc 7 fir Linux, clang 8 fir macOS).

Glécklecherweis ass eise Code haaptsächlech no Richtlinnen geschriwwe ginn an huet net all Zorte vu schlau Tricken benotzt, sou datt d'Migratioun an nei Bibliothéike relativ glat verlaf ass, mat Hëllef vu Scripten déi d'Nimm vun Typen, Klassen, Nummraim ersat hunn an an der Quell enthalen Fichieren. D'Migratioun beaflosst 10 Quelldateien (vun 000). wchar_t gouf duerch char14_t ersat; mir decidéiert de Gebrauch vun wchar_t opginn, well char000_t hëlt 16 Bytes op all OSen a verwinnt keng Codekompatibilitéit tëscht Windows a Linux.

Et waren e puer kleng Aventuren. Zum Beispill, an STLPort kann en Iterator implizit op e Pointer op en Element gegoss ginn, an op e puer Plazen an eisem Code gouf dëst benotzt. An neie Bibliothéike war dat net méi méiglech, an dës Passagen hu misse manuell analyséiert a nei geschriwwe ginn.

Also, d'Codemigratioun ass fäerdeg, de Code ass fir all Betribssystemer kompiléiert. Et ass Zäit fir Tester.

Tester nom Iwwergank weisen e Réckgang vun der Leeschtung (op e puer Plazen bis zu 20-30%) an eng Erhéijung vum Erënnerungsverbrauch (bis zu 10-15%) am Verglach mat der aler Versioun vum Code. Dëst war virun allem wéinst der suboptimaler Leeschtung vun Standard Saiten. Dofir hu mir nees missen eis eege liicht verännert Linn benotzen.

Eng interessant Feature vun der Ëmsetzung vu Container an embedded Bibliothéike gouf och opgedeckt: eidel (ouni Elementer) std :: Kaart an std :: Set aus agebaute Bibliothéiken allocéieren Erënnerung. A wéinst den Implementéierungsfeatures ginn op e puer Plazen am Code zimlech vill eidel Container vun dësem Typ erstallt. Standard Gedächtniscontainer ginn e bëssen zougewisen, fir ee Root-Element, awer fir eis huet dëst kritesch erausgestallt - an enger Rei Szenarie ass eis Leeschtung wesentlech erofgaang an de Gedächtnisverbrauch ass eropgaang (am Verglach zum STLPort). Dofir hu mir an eisem Code dës zwou Aarte vu Container aus den agebaute Bibliothéiken ersat mat hirer Ëmsetzung vu Boost, wou dës Container net sou eng Feature hunn, an dëst huet de Problem mat der Verlängerung an dem verstäerkten Erënnerungsverbrauch geléist.

Wéi oft geschitt no grousser Skala Verännerungen a grousse Projeten, huet déi éischt Iteratioun vum Quellcode net ouni Probleemer geschafft, an hei ass besonnesch d'Ënnerstëtzung fir Debugging Iteratoren an der Windows Implementatioun praktesch. Schrëtt fir Schrëtt si mir no vir geplënnert, a vum Fréijoer 2017 (Versioun 8.3.11 1C:Enterprise) war d'Migratioun ofgeschloss.

Resultater

Den Iwwergank zum C++14 Standard huet eis ongeféier 6 Méint gedauert. Déi meescht vun der Zäit huet een (awer ganz héichqualifizéierten) Entwéckler um Projet geschafft, an op der leschter Etapp hunn Vertrieder vun den Teams verantwortlech fir spezifesch Beräicher matgemaach - UI, Servercluster, Entwécklungs- an Administratiounsinstrumenter, etc.

Den Iwwergank huet eis Aarbecht fir d'Migratioun op déi lescht Versioune vum Standard staark vereinfacht. Also ass d'Versioun 1C:Enterprise 8.3.14 (an der Entwécklung, Verëffentlechung geplangt fir fréi d'nächst Joer) schonn op de Standard transferéiert ginn C++17.

No der Migratioun hunn d'Entwéckler méi Méiglechkeeten. Wa mir fréier eis eege modifizéiert Versioun vu STL an engem std Nummraum haten, hu mir elo Standardklassen aus den agebaute Compilerbibliothéiken am std Nummraum, am stdx Nummraum - eis Linnen a Container optimiséiert fir eis Aufgaben, am Boost - den lescht Versioun vum Boost. An den Entwéckler benotzt déi Klassen déi optimal ugepasst sinn fir seng Problemer ze léisen.

Déi "gebierteg" Ëmsetzung vu Bewegungskonstruktoren hëlleft och bei der Entwécklung (plënneren constructors) fir eng Rei Klassen. Wann eng Klass e Beweegungskonstruktor huet an dës Klass an engem Container plazéiert ass, optiméiert de STL d'Kopie vun Elementer am Container (zum Beispill wann de Container erweidert ass an et néideg ass d'Kapazitéit z'änneren an d'Erënnerung ëmzegoen).

Fly op der Sallef

Vläicht déi onsympathesch (awer net kritesch) Konsequenz vun der Migratioun ass datt mir mat enger Erhéijung vum Volume konfrontéiert sinn obj Dateien, an dat vollt Resultat vum Bau mat all de Mëtteldateien huet ugefaang 60-70 GB opzehuelen. Dëst Verhalen ass wéinst de Besonderheete vun de modernen Standardbibliothéiken, déi manner kritesch ginn fir d'Gréisst vun de generéierte Servicedateien. Dëst beaflosst net d'Operatioun vun der kompiléierter Applikatioun, awer et verursaacht eng Zuel vun Onbequemlechkeeten an der Entwécklung, besonnesch et erhéicht d'Kompilatiounszäit. D'Ufuerderunge fir fräi Plaatz op Build Serveren an op Entwéckler Maschinnen ginn och erop. Eis Entwéckler schaffen op verschidde Versioune vun der Plattform parallel, an Honnerte vu Gigabyte vun Zwëschendateien erstellen heiansdo Schwieregkeeten an hirer Aarbecht. De Problem ass désagréabel, awer net kritesch; mir hunn hir Léisung fir de Moment ofgesot. Mir betruechten Technologie als eng vun den Optiounen fir se ze léisen Eenheet bauen (besonnesch Google benotzt et beim Entwécklung vum Chrome Browser).

Source: will.com

Setzt e Commentaire