Cumu avemu traduttu 10 milioni di linee di codice C++ à u standard C++14 (è dopu à C++17)

Qualchì tempu fà (in u vaghjimu di u 2016), durante u sviluppu di a prossima versione di a piattaforma tecnologica 1C: Enterprise, a quistione hè stata in u squadra di sviluppu nantu à u sustegnu di u novu standard. C ++ 14 in u nostru codice. A transizione à un novu standard, cum'è avemu presumitu, ci permettenu di scrive assai cose più eleganti, simplicità è affidabile, è simplificà u supportu è u mantenimentu di u codice. È ùn pare micca esse nunda di straordinariu in a traduzzione, se micca per a scala di a basa di codice è e caratteristiche specifiche di u nostru codice.

Per quelli chì ùn sanu micca, 1C: Enterprise hè un ambiente per u sviluppu rapidu di l'applicazioni cummerciale multipiattaforma è runtime per a so esecuzione in diversi OS è DBMS. In generale, u pruduttu cuntene:

Pruvemu di scrive u listessu codice per i diversi sistemi operativi quant'è pussibule - a basa di u codice di u servitore hè 99% cumuni, a basa di u codice cliente hè di circa 95%. A piattaforma tecnologica 1C: Enterprise hè principalmente scritta in C ++ è e caratteristiche di u codice apprussimativu sò date quì sottu:

  • 10 milioni di linee di codice C++,
  • 14 mila schedari,
  • 60 mila classi,
  • mezzo milione di metudi.

E tutte queste cose anu da esse tradutte in C ++ 14. Oghje vi diceremu cumu avemu fattu questu è ciò chì avemu scontru in u prucessu.

Cumu avemu traduttu 10 milioni di linee di codice C++ à u standard C++14 (è dopu à C++17)

Disclaimer

Tuttu ciò chì hè scrittu quì sottu nantu à u travagliu lento / veloce, (micca) grande cunsumu di memoria da implementazioni di classi standard in diverse biblioteche significa una cosa: questu hè veru PER NOI. Hè abbastanza pussibule chì implementazioni standard seranu più adattati per i vostri compiti. Avemu principiatu da i nostri propri compiti: avemu pigliatu dati chì era tipicu per i nostri clienti, eseguimu scenarii tipici nantu à elli, fighjemu u rendiment, a quantità di memoria cunsumata, etc., è analizà se noi è i nostri clienti eranu soddisfatti di tali risultati o micca. . E anu agitu secondu.

Chì avemu avutu

Inizialmente, avemu scrittu u codice per a piattaforma 1C: Enterprise 8 in Microsoft Visual Studio. U prugettu hà iniziatu à l'iniziu di l'anni 2000 è avemu avutu una versione solu per Windows. Naturalmente, da tandu u codice hè statu sviluppatu attivamente, assai miccanismi sò stati completamente riscritti. Ma u codice hè statu scrittu secondu u standard di u 1998, è, per esempiu, i nostri parentesi anguli dritti sò stati separati da spazii per chì a compilazione riesce, cusì:

vector<vector<int> > IntV;

In u 2006, cù a liberazione di a versione 8.1 di a piattaforma, avemu principiatu à sustene Linux è cambiatu à una biblioteca standard di terzu. Port STL. Unu di i mutivi di a transizione era di travaglià cù linee largu. In u nostru codice, usemu std::wstring, chì hè basatu annantu à u tipu wchar_t, in tuttu. A so dimensione in Windows hè 2 byte, è in Linux hè 4 byte per difettu. Questu hà purtatu à l'incompatibilità di i nostri protokolli binari trà u cliente è u servitore, è ancu parechji dati persistenti. Utilizendu l'opzioni gcc, pudete specificà chì a dimensione di wchar_t durante a compilazione hè ancu di 2 bytes, ma allora pudete scurdà di utilizà a biblioteca standard da u compilatore, perchè usa glibc, chì à u turnu hè compilatu per un wchar_t di 4 byte. L'altri ragiuni eranu una megliu implementazione di classi standard, supportu per i tavulini di hash, è ancu l'emulazione di a semantica di muvimentu in cuntenituri, chì avemu attivamente utilizatu. È un altru mutivu, cum'è dicenu l'ultimu ma micca menu, era u rendiment di corda. Avemu avutu a nostra propria classe di corde, perchè... A causa di e specifiche di u nostru software, l'operazioni di stringa sò usate assai largamente è per noi questu hè criticu.

A nostra stringa hè basatu annantu à l'idee di ottimisazione di stringa espresse in u principiu di l'anni 2000 Andrei Alexandrescu. In seguitu, quandu Alexandrescu hà travagliatu in Facebook, à u so suggerimentu, una linea hè stata utilizata in u mutore di Facebook chì hà travagliatu nantu à principii simili (vede a biblioteca scimità).

A nostra linea hà utilizatu duie tecnulugia di ottimisazione principali:

  1. Per i valori brevi, un buffer internu in l'ughjettu di a stringa stessu hè utilizatu (ùn hè micca bisognu di assignazione di memoria supplementaria).
  2. Per tutti l'altri, a meccanica hè aduprata Copia nantu à scrittura. U valore di stringa hè guardatu in un locu, è un contatore di riferimentu hè utilizatu durante l'assignazione / mudificazione.

Per accelerà a compilazione di a piattaforma, avemu esclusu l'implementazione di u flussu da a nostra variante STLPort (chì ùn avemu micca usatu), questu ci hà datu circa 20% di compilazione più veloce. Dopu avemu avutu à fà un usu limitatu rilancià. Boost faci un usu pesante di u flussu, in particulare in i so API di serviziu (per esempiu, per logging), cusì avemu avutu a mudificà per sguassà l'usu di u flussu. Questu, à u turnu, hà fattu difficiule per noi di migrà à novi versioni di Boost.

Terzu modu

Quandu si move à u standard C ++ 14, avemu cunsideratu e seguenti opzioni:

  1. Aghjurnate u STLPort chì avemu mudificatu à u standard C ++ 14. L'opzione hè assai difficiule, perchè ... U supportu per STLPort hè statu discontinuatu in u 2010, è avemu avutu da custruisce tuttu u so codice.
  2. Transizione à una altra implementazione STL cumpatibile cù C++ 14. Hè assai desideratu chì sta implementazione sia per Windows è Linux.
  3. Quandu compile per ogni OS, utilizate a biblioteca integrata in u compilatore currispundente.

A prima opzione hè stata rifiutata per via di troppu travagliu.

Avemu pensatu à a seconda opzione per qualchì tempu; cunsideratu cum'è un candidatu libc++, ma à quellu tempu ùn hà micca travagliatu sottu Windows. Per portà libc++ à Windows, avete da fà assai travagliu - per esempiu, scrivite tuttu ciò chì hà da fà cù i fili, a sincronizazione di i fili è l'atomicità, postu chì libc++ utilizatu in questi spazii. API POSIX.

È avemu sceltu u terzu modu.

Transizione

Dunque, avemu avutu a rimpiazzà l'usu di STLPort cù e librerie di i compilatori currispondenti (Visual Studio 2015 per Windows, gcc 7 per Linux, clang 8 per macOS).

Fortunatamente, u nostru codice hè statu scrittu principarmenti secondu e linee guida è ùn hà micca utilizatu ogni tipu di trucchi intelligenti, cusì a migrazione à e novi biblioteche hà procedutu relativamente bè, cù l'aiutu di scripts chì rimpiazzavanu i nomi di tipi, classi, spazii di nomi è includenu in a fonte. i schedari. A migrazione hà affettatu 10 000 fugliali fonte (da 14 000). wchar_t hè statu rimpiazzatu da char16_t; avemu decisu di abbandunà l'usu di wchar_t, perchè char16_t pigghia 2 bytes in tutti i OS è ùn sguassate micca a cumpatibilità di codice trà Windows è Linux.

Ci era qualchi picculi avventure. Per esempiu, in STLPort un iteratore puderia esse implícitamente cast à un punteru à un elementu, è in certi lochi in u nostru codice hè stata utilizata. In e biblioteche novi ùn era più pussibule di fà questu, è questi passaggi anu da esse analizati è riscritti manualmente.

Allora, a migrazione di codice hè cumpleta, u codice hè compilatu per tutti i sistemi operativi. Hè u tempu di teste.

I testi dopu a transizione dimustranu una calata di u rendiment (in certi lochi finu à 20-30%) è un aumentu di u cunsumu di memoria (finu à 10-15%) cumparatu cù a versione antica di u codice. Questu era, in particulare, per via di a prestazione subottimali di corde standard. Dunque, avemu avutu di novu aduprà a nostra propria linea ligeramente mudificata.

Una caratteristica interessante di l'implementazione di cuntenituri in biblioteche integrate hè stata ancu revelata: viotu (senza elementi) std::map è std::set da biblioteche integrate allocate memoria. È per via di e funziunalità di implementazione, in certi lochi in u codice sò creati assai cuntenituri vacanti di stu tipu. I cuntenituri di memoria standard sò attribuiti un pocu, per un elementu radicali, ma per noi questu hè diventatu criticu - in una quantità di scenarii, u nostru rendimentu hè cascatu significativamente è u cunsumu di memoria hè aumentatu (paragunatu à STLPort). Per quessa, in u nostru codice avemu rimpiazzatu sti dui tipi di cuntenituri da e librerie integrate cù a so implementazione da Boost, induve sti cuntenituri ùn anu micca sta funziunalità, è questu risolve u prublema cù a rallentazione è u cunsumu di memoria aumentatu.

Cum'è spessu succede dopu à cambiamenti à grande scala in grandi prughjetti, a prima iterazione di u codice fonte ùn hà micca travagliatu senza prublemi, è quì, in particulare, u supportu per iteratori di debugging in l'implementazione di Windows hè stata utile. Passu à passu avemu avanzatu, è da a primavera di 2017 (versione 8.3.11 1C: Enterprise) a migrazione hè stata cumpletata.

Risultati

A transizione à u standard C++ 14 ci hà pigliatu circa 6 mesi. A maiò parte di u tempu, un sviluppatore (ma assai altamente qualificatu) hà travagliatu nantu à u prugettu, è in u stadiu finali rapprisintanti di squadre rispunsevuli di spazii specifichi uniti in - UI, cluster di servitori, strumenti di sviluppu è amministrazione, etc.

A transizione hà simplificatu assai u nostru travagliu nantu à a migrazione à l'ultime versioni di u standard. Cusì, a versione 1C: Enterprise 8.3.14 (in sviluppu, liberazione prevista per u principiu di l'annu prossimu) hè digià stata trasferita à u standard. C ++ 17.

Dopu a migrazione, i sviluppatori anu più opzioni. Se prima avemu avutu a nostra propria versione mudificata di STL è un spaziu di nomi std, avà avemu classi standard da e biblioteche di compilatori integrati in u spaziu di nomi std, in u spaziu di nomi stdx - e nostre linee è cuntenituri ottimizzati per i nostri compiti, in boost - u l'ultima versione di boost. È u sviluppatore usa quelli classi chì sò ottimali adattati per risolve i so prublemi.

L'implementazione "nativa" di i custruttori di muvimentu aiuta ancu in u sviluppu (move i custruttori) per parechje classi. Se una classa hà un custruttore di muvimentu è sta classa hè posta in un containeru, u STL ottimisimu a copia di elementi in u containeru (per esempiu, quandu u containeru hè allargatu è hè necessariu cambià a capacità è riassignà a memoria).

Vola in l'ingudu

Forsi a cunsiquenza più dispiacevule (ma micca critica) di a migrazione hè chì avemu affruntatu cù un aumentu di u voluminu. i schedari obj, è u risultatu sanu di a custruzzione cù tutti i schedarii intermedi cuminciaru à piglià 60-70 GB. Stu cumpurtamentu hè dovutu à e peculiarità di e librerie standard muderni, chì sò diventati menu critichi di a dimensione di i schedarii di serviziu generati. Questu ùn affetta micca u funziunamentu di l'applicazione compilata, ma causa una quantità di inconvenienti in u sviluppu, in particulare, aumenta u tempu di compilazione. I requisiti per u spaziu di discu liberu nantu à i servitori di custruzzione è in e macchine di sviluppatore sò ancu in crescita. I nostri sviluppatori travaglianu in parechje versioni di a piattaforma in parallelu, è centinaie di gigabytes di schedarii intermedii qualchì volta creanu difficultà in u so travagliu. U prublema hè dispiacevule, ma micca criticu; avemu pospostu a so suluzione per avà. Avemu cunsiderà a tecnulugia cum'è una di l'opzioni per risolve custruì l'unità (in particulare, Google l'adopra quandu u sviluppu di u navigatore Chrome).

Source: www.habr.com

Add a comment