Mõni aeg tagasi (sügisel 2016) tekkis 1C:Enterprise tehnoloogilise platvormi järgmise versiooni arendamise käigus arendustiimis küsimus uue standardi toetamisest meie koodis. Üleminek uuele standardile, nagu me eeldasime, võimaldaks meil kirjutada paljusid asju elegantselt, lihtsalt ja usaldusväärselt ning lihtsustaks koodi hooldust ja toetust. Tõlkes ei paista olevat midagi erakordset, kui mitte arvestada koodibaasi ulatust ja meie koodi spetsiifilisi jooni.
Neile, kes ei tea, 1C:Enterprise on keskkond kiireks ristplatvormiliste ärirakenduste arendamiseks ja nende käitamiseks erinevates operatsioonisüsteemides ja andmebaasides. Toote koosseisus on üldiselt:
- , töötab Windowsis ja Linuxis
- , suhtleb serveriga http(s) kaudu või oma binaarse protokolli kaudu, töötab Windowsis, Linuxis, macOS-is
- , töötab brauserites Chrome, Internet Explorer, Microsoft Edge, Firefox, Safari (kirjeldatud JavaScriptis)
- Arenduskeskkond (), töötab Windowsis, Linuxis, macOS-is
- rakenduste serverite jaoks, töötavad Windowsis, Linuxis, macOS-is
- , ühendub serveriga http(s) kaudu, töötab mobiilseadmetes Androidi, iOSi, Windowsi all
- — raamistik оффлаин mobiilirakenduste loomiseks, millel on sünkroniseerimise võimalus, töötavad Androidis, iOSis, Windowsis
- Arenduskeskkond , on kirjutatud Java keeles
- Server
Püüame maksimaalselt kirjutada ühte koodi erinevatele operatsioonisüsteemidele — serveri koodibaas on 99% jagatud, kliendi oma umbes 95%. Tehnoloogiline platvorm 1C:Enterprise on peamiselt kirjutatud C++ keeles ja allpool on ligikaudsed koodi omadused:
- 10 miljonit rida C++ koodi,
- 14 tuhat faili,
- 60 tuhat klassi,
- pool miljonit meetodit.
Ja see kõik tuli viia C++14 peale. Täna räägime, kuidas me seda tegime ja millega me protsessi käigus kokku puutusime.

Märkus
All that is written below about the slow/fast performance and (not) significant memory consumption of standard class implementations in various libraries means one thing: this is true FOR US. It is quite possible that standard implementations are best suited for your tasks. We, however, based our conclusions on our own tasks: we took typical data from our clients, ran standard scenarios on them, observed their performance, memory consumption, etc., and analyzed whether we and our clients were satisfied with such results or not. And we acted accordingly.
What We Had
Initially, we wrote the code for the 1C:Enterprise 8 platform in Microsoft Visual Studio. The project started in the early 2000s, and we only had a version for Windows. Naturally, the code has significantly evolved since then, and many mechanisms have been completely rewritten. However, the code was written according to the standards of 1998, and, for example, right angle brackets were separated by spaces to ensure successful compilation, like this:
vector<vector> IntV;In 2006, with the release of platform version 8.1, we began supporting Linux and switched to a third-party standard library . One of the reasons for the transition was working with wide strings. In our code, we widely use std::wstring, based on the wchar_t type. Its size is 2 bytes in Windows, but by default 4 bytes in Linux. This led to incompatibility in our binary protocols between client and server, as well as various persistent data. The gcc options can specify that the size of wchar_t during compilation should also be 2 bytes, but then you can forget about using the standard library from the compiler, as it uses glibc, which in turn is compiled for a 4-byte wchar_t. Other reasons included a better implementation of standard classes, support for hash tables, and even emulation of move semantics within containers, which we actively used. And another reason, as they say, last but not least, was the performance of strings. We had our own class for strings, as, due to the specifics of our software, string operations are used very widely and are critical for us.
Our string is based on ideas for string optimization expressed back in the early 2000s . Hiljem, kui Alexandrescu töötas Facebookis, kasutati tema algatusel Facebooki mootoris rida, mis toimib sarnaste põhimõtete alusel (vt raamatukogu ).
Meie reas kasutati kahte peamist optimeerimistehnoloogiat:
- Lühikeste väärtuste jaoks kasutatakse sisemist puhvrit stringi objekti sees (mis ei vaja täiendavat mälu eraldamist).
- Kõikide teiste puhul kasutatakse mehhanismi . Stringi väärtus salvestatakse ühte kohta, omistamisel/muundamisel kasutatakse viidete arvestust.
Kuna me tahtsime platvormi kompileerimist kiirendada, jätsime oma STLPorti variandist välja streami teostuse (mida me ei kasutanud), see andis meile kompileerimise kiirusetõusu umbes 20%. Hiljem pidime piiratud määral kasutama . Boost kasutab aktiivselt streami, eriti oma teenuste API-des (näiteks logimise jaoks), seetõttu pidime seda modifitseerima, välistades streami kasutamise. See omakorda raskendas meil üleminekut uutele Boosti versioonidele.
Kolmas tee
C++14 standardile üleminekul kaalume selliseid võimalusi:
- Tõsta meie modifitseeritud STLPort C++14 standardile. See valik on väga keeruline, kuna STLPorti toetamist lõpetati 2010. aastal ja kogu selle koodi tõstmine tuli meil iseseisvalt teha.
- Üleminek teisele STL-i teostusele, mis oleks C++14 ühilduv. Eriti soovitav oleks, et see teostus oleks Windowsis ja Linuxis.
- Kasutada iga opsüsteemi kompileerimisel vastava kompilaatori sisseehitatud teeki.
Esimene valik lükati kohe tagasi liiga suure töömahu tõttu.
Mõtlesime mõnda aega teisele valikule; kandidaadina kaalume , kuid sel hetkel ei töötanud see Windowsis. libc++ portimiseks Windowsile peaks palju tööd tegema — näiteks kirjutama ise kõik, mis puudutab niite, niitide sünkroniseerimist ja aatomilisust, kuna libc++-is kasutati nendes valdkondades .
Ja valisime kolmanda tee.
Üleminek
Nii et meie ülesanne oli asendada STLPorti kasutamine vastava kompilaatori teekidega (Visual Studio 2015 Windowsi jaoks, gcc 7 Linuxi jaoks, clang 8 macOS-i jaoks).
Õnneks kirjutati meie kood põhiliselt vastavalt juhistele ja ei kasutatud igasuguseid nutikaid trikke, seega migrations uutele raamatukogudele kulges suhteliselt sujuvalt, skriptide abil, mis asendasid algfailides tüüpide, klasside, nimede ja sissetoodud elementide nimed. Migratsioon puudutas 10 000 algfaili (14 000-st). wchar_t asendati char16_t-ga; otsustasime loobuda wchar_t kasutamisest, kuna char16_t peab kõikides operatsioonisüsteemides 2 baiti ja ei riku koodi ühilduvust Windowsi ja Linuxi vahel.
Ei möödunud ka väikeste seiklusteta. Näiteks STLPortis sai iteratorit kaudsetena lihtsalt elementide pointeriks castida, ja meie koodi mõnes kohas seda ka kasutati. Uutes raamatukogudes ei saanud seda enam teha, ja neid kohti tuli analüüsida ja käsitsi ümber kirjutada.
Nii et koodi migratsioon on lõppenud, kood kompileerub kõikidele operatsioonisüsteemidele. On aeg testideks.
Üleminekujärgsed testid näitasid jõudluse langust (kohati kuni 20-30%) ja suurenenud mälutarvet (kuni 10-15%) võrreldes vana koodi versiooniga. See oli osaliselt seotud standardsete stringide mitteoptimaalse toimimisega. Seega pidime jälle oma stringe kasutama, pisut kohandatuna.
Samuti tuli välja huvitav aspekt konteinerite rakendamisest sisseehitatud raamatukogudes: tühjad (ilma elementideta) std::map ja std::set sisseehitatud raamatukogudest eraldavad mälu. Ja meie koodis loodi teatud kohtades üsna palju selliseid tühje konteinerite tüüpe. Standardsete konteinerite eraldusmälu oli veidi, ühe juurelemendi jaoks, kuid meie jaoks osutus see kriitiliseks – mitmete stsenaariumitega langes meie jõudlus ja suurenes mälu tarbimine (STLPortiga võrreldes). Seetõttu asendasime meie koodis need kaks tüüpi konteinerit sisseehitatud raamatukogudest Boosti rakendusega, kus need konteinerid ei omanud sellist omadust, ja see lahendas aeglustumise ja suurenenud mälu tarbimise probleemi.
Nagu sageli juhtub suurtel muudatustel suurtes projektides, esimene allikate versioon ei töötanud probleemideta ja siin tulid meile väga abiks, sealhulgas Windowsi rakenduse silumisi iteratorite tugi. Samm-sammult liikusime edasi ning 2017. aasta kevadel (versioon 8.3.11 1C:Äri) oli migratsioon lõppenud.
Summary
C++14 standard transition took us about 6 months. Most of the time, a single highly qualified developer worked on the project, and at the final stage, team representatives responsible for specific areas—UI, server cluster, development and administration tools, etc.—joined in.
The transition greatly simplified our migration to the latest versions of the standard. The version 1C:Enterprise 8.3.14 (in development, release planned for early next year) has already been translated to the standard. .
After the migration, developers have more opportunities. Previously, we had our own modified version of STL and one namespace std, but now standard classes from the compiler's built-in libraries reside in namespace std, while our optimized strings and containers for our tasks are in namespace stdx, and the fresh version of boost is in boost. Developers use the classes that are optimally suited for solving their tasks.
The 'native' implementation of move constructors also helps in development () for some classes. If a class has a move constructor and this class is placed in a container, STL optimizes the copying of elements within the container (for instance, when the container expands and needs to change capacity and reallocate memory).
A fly in the ointment
Perhaps the most unpleasant (but not critical) consequence of the migration is that we encountered an increase in the volume of , and the full result of the build with all intermediate files took up 60 to 70 GB. This behavior is related to the peculiarities of modern standard libraries, which have become less critical regarding the volume of generated auxiliary files. It does not affect the operation of the compiled application, but creates a number of inconveniences in development, particularly increasing compilation time. It also raises the requirements for free disk space on build servers and developers' machines. Our developers are working on several platform versions simultaneously, and hundreds of gigabytes of intermediate files sometimes create difficulties in work. This issue is unpleasant but not critical, and we have postponed its resolution for now. One of the potential solutions we are considering is the technique of (seda, sealhulgas kasutab Google oma Chrome'i brauseri arendamisel).
Allikas: habr.com
