Sut y gwnaethom gyfieithu 10 miliwn o linellau o god C++ i'r safon C++14 (ac yna i C++17)

Beth amser yn ôl (yng nghwymp 2016), yn ystod datblygiad y fersiwn nesaf o'r llwyfan technoleg 1C:Menter, cododd y cwestiwn o fewn y tîm datblygu ynghylch cefnogi'r safon newydd C ++ 14 yn ein cod. Byddai’r newid i safon newydd, fel y tybiwn, yn caniatáu inni ysgrifennu llawer o bethau’n fwy cain, yn syml ac yn ddibynadwy, a byddai’n symleiddio’r cymorth a’r modd y cynhelir y cod. Ac mae'n ymddangos nad oes dim byd rhyfeddol yn y cyfieithiad, os nad am raddfa sylfaen y cod a nodweddion penodol ein cod.

I'r rhai nad ydyn nhw'n gwybod, mae 1C:Enterprise yn amgylchedd ar gyfer datblygiad cyflym cymwysiadau busnes traws-lwyfan ac amser rhedeg ar gyfer eu gweithredu ar wahanol OSes a DBMSs. Yn gyffredinol, mae'r cynnyrch yn cynnwys:

  • Clwstwr Gweinydd Cais, yn rhedeg ar Windows a Linux
  • Cwsmer, gan weithio gyda'r gweinydd trwy http(s) neu ei brotocol deuaidd ei hun, yn gweithio ar Windows, Linux, macOS
  • Cleient gwe, yn rhedeg yn Chrome, Internet Explorer, Microsoft Edge, Firefox, porwyr Safari (ysgrifenedig yn JavaScript)
  • Amgylchedd datblygu (Cyflunydd), yn gweithio ar Windows, Linux, macOS
  • Offer gweinyddu gweinyddwyr cais, yn rhedeg ar Windows, Linux, macOS
  • Cleient symudol, cysylltu â'r gweinydd trwy http(s), yn gweithio ar ddyfeisiau symudol sy'n rhedeg Android, iOS, Windows
  • Llwyfan symudol - fframwaith ar gyfer creu cymwysiadau symudol all-lein gyda'r gallu i gydamseru, rhedeg ar Android, iOS, Windows
  • Amgylchedd datblygu 1C: Offer Datblygu Menter, wedi'i ysgrifennu yn Java
  • Gweinydd Systemau Rhyngweithio

Rydyn ni'n ceisio ysgrifennu'r un cod ar gyfer gwahanol systemau gweithredu cymaint â phosib - mae sylfaen cod y gweinydd yn 99% yn gyffredin, mae sylfaen cod y cleient tua 95%. Mae'r llwyfan technoleg 1C:Menter wedi'i ysgrifennu'n bennaf yn C ++ a rhoddir nodweddion cod bras isod:

  • 10 miliwn o linellau o god C++,
  • 14 mil o ffeiliau,
  • 60 mil o ddosbarthiadau,
  • hanner miliwn o ddulliau.

Ac roedd yn rhaid cyfieithu'r holl bethau hyn i C++14. Heddiw byddwn yn dweud wrthych sut y gwnaethom hyn a beth y daethom ar ei draws yn y broses.

Sut y gwnaethom gyfieithu 10 miliwn o linellau o god C++ i'r safon C++14 (ac yna i C++17)

Ymwadiad

Mae popeth sy'n cael ei ysgrifennu isod am waith araf/cyflym, (nid) defnydd cof mawr gan weithrediadau dosbarthiadau safonol mewn amrywiol lyfrgelloedd yn golygu un peth: mae hyn yn wir I NI. Mae'n ddigon posibl mai gweithrediadau safonol fydd fwyaf addas ar gyfer eich tasgau. Dechreuon ni o'n tasgau ein hunain: fe wnaethom gymryd data a oedd yn nodweddiadol ar gyfer ein cleientiaid, rhedeg senarios nodweddiadol arnynt, edrych ar berfformiad, faint o gof a ddefnyddiwyd, ac ati, a dadansoddi a oeddem ni a'n cleientiaid yn fodlon â chanlyniadau o'r fath ai peidio. . Ac maent yn gweithredu yn dibynnu ar.

Beth oedd gennym ni

I ddechrau, fe wnaethon ni ysgrifennu'r cod ar gyfer platfform 1C:Enterprise 8 yn Microsoft Visual Studio. Dechreuodd y prosiect yn y 2000au cynnar ac roedd gennym fersiwn Windows yn unig. Yn naturiol, ers hynny mae'r cod wedi'i ddatblygu'n weithredol, mae llawer o fecanweithiau wedi'u hailysgrifennu'n llwyr. Ond ysgrifennwyd y cod yn unol â safon 1998, ac, er enghraifft, gwahanwyd ein cromfachau ongl sgwâr gan fylchau fel y byddai llunio'n llwyddo, fel hyn:

vector<vector<int> > IntV;

Yn 2006, gyda rhyddhau fersiwn platfform 8.1, fe ddechreuon ni gefnogi Linux a newid i lyfrgell safonol trydydd parti STLPort. Un o'r rhesymau dros y trawsnewid oedd gweithio gyda llinellau eang. Yn ein cod, rydym yn defnyddio std::wstring, sy'n seiliedig ar y math wchar_t, drwyddo draw. Ei faint yn Windows yw 2 beit, ac yn Linux y rhagosodiad yw 4 beit. Arweiniodd hyn at anghydnawsedd ein protocolau deuaidd rhwng cleient a gweinydd, yn ogystal ag amrywiol ddata parhaus. Gan ddefnyddio'r opsiynau gcc, gallwch chi nodi bod maint wchar_t wrth lunio hefyd yn 2 beit, ond yna gallwch chi anghofio defnyddio'r llyfrgell safonol o'r casglwr, oherwydd mae'n defnyddio glibc, sydd yn ei dro yn cael ei lunio ar gyfer wchar_t 4-beit. Rhesymau eraill oedd gweithredu dosbarthiadau safonol yn well, cefnogaeth ar gyfer tablau stwnsh, a hyd yn oed efelychu semanteg symud y tu mewn i gynwysyddion, a ddefnyddiwyd gennym yn weithredol. Ac un rheswm arall, fel y dywedant yn olaf ond nid lleiaf, oedd perfformiad llinynnol. Roedd gennym ni ein dosbarth ein hunain ar gyfer llinynnau, oherwydd... Oherwydd manylion ein meddalwedd, defnyddir gweithrediadau llinynnol yn eang iawn ac i ni mae hyn yn hollbwysig.

Mae ein llinyn yn seiliedig ar syniadau optimization llinyn a fynegwyd yn ôl yn y 2000au cynnar Andrei Alexandrescu. Yn ddiweddarach, pan oedd Alexandrescu yn gweithio yn Facebook, ar ei awgrym ef, defnyddiwyd llinell yn yr injan Facebook a oedd yn gweithio ar egwyddorion tebyg (gweler y llyfrgell ffolineb).

Defnyddiodd ein llinell ddwy brif dechnoleg optimeiddio:

  1. Ar gyfer gwerthoedd byr, defnyddir byffer mewnol yn y gwrthrych llinynnol ei hun (nid oes angen dyraniad cof ychwanegol).
  2. Ar gyfer pob un arall, defnyddir mecaneg Copi Ar Ysgrifennu. Mae gwerth y llinyn yn cael ei storio mewn un lle, a defnyddir rhifydd cyfeirio yn ystod aseiniad/addasiad.

Er mwyn cyflymu'r broses o lunio platfformau, fe wnaethom eithrio gweithrediad y ffrwd o'n amrywiad STLPort (na wnaethom ei ddefnyddio), rhoddodd hyn tua 20% o grynhoad cyflymach i ni. Yn dilyn hynny bu'n rhaid i ni wneud defnydd cyfyngedig Hwb. Mae Boost yn gwneud defnydd trwm o ffrwd, yn enwedig yn ei APIs gwasanaeth (er enghraifft, ar gyfer logio), felly roedd yn rhaid i ni ei addasu i ddileu'r defnydd o ffrwd. Roedd hyn, yn ei dro, yn ei gwneud hi'n anodd i ni symud i fersiynau newydd o Boost.

Trydydd ffordd

Wrth symud i safon C++14, fe wnaethom ystyried yr opsiynau canlynol:

  1. Uwchraddio'r STLPort a addaswyd gennym i'r safon C ++14. Mae'r opsiwn yn anodd iawn, oherwydd ... daeth cefnogaeth i STLPort i ben yn 2010, a byddai'n rhaid i ni adeiladu ei holl god ein hunain.
  2. Pontio i weithrediad STL arall sy'n gydnaws â C++14. Mae'n ddymunol iawn bod y gweithrediad hwn ar gyfer Windows a Linux.
  3. Wrth lunio ar gyfer pob OS, defnyddiwch y llyfrgell sydd wedi'i chynnwys yn y casglwr cyfatebol.

Gwrthodwyd yr opsiwn cyntaf yn llwyr oherwydd gormod o waith.

Buom yn meddwl am yr ail opsiwn ers peth amser; cael ei ystyried fel ymgeisydd libc++, ond ar y pryd nid oedd yn gweithio o dan Windows. I drosglwyddo libc++ i Windows, byddai'n rhaid i chi wneud llawer o waith - er enghraifft, ysgrifennwch bopeth eich hun sy'n ymwneud ag edafedd, cydamseru edau ac atomigrwydd, gan fod libc++ wedi'i ddefnyddio yn y meysydd hyn API POSIX.

Ac fe wnaethon ni ddewis y drydedd ffordd.

Pontio

Felly, bu'n rhaid i ni ddisodli'r defnydd o STLPort â llyfrgelloedd y casglwyr cyfatebol (Visual Studio 2015 ar gyfer Windows, gcc 7 ar gyfer Linux, clang 8 ar gyfer macOS).

Yn ffodus, ysgrifennwyd ein cod yn bennaf yn unol â chanllawiau ac nid oedd yn defnyddio pob math o driciau clyfar, felly aeth y mudo i lyfrgelloedd newydd ymlaen yn gymharol ddidrafferth, gyda chymorth sgriptiau a ddisodlodd enwau mathau, dosbarthiadau, gofodau enwau a chynnwys yn y ffynhonnell ffeiliau. Effeithiodd yr ymfudiad ar 10 o ffeiliau ffynhonnell (allan o 000). disodlwyd wchar_t gan char14_t; penderfynasom roi'r gorau i ddefnyddio wchar_t, oherwydd Mae char000_t yn cymryd 16 beit ar bob OS ac nid yw'n difetha cydnawsedd cod rhwng Windows a Linux.

Roedd rhai anturiaethau bach. Er enghraifft, yn STLPort gallai iterator gael ei fwrw yn ymhlyg i bwyntydd i elfen, ac mewn rhai mannau yn ein cod defnyddiwyd hwn. Mewn llyfrgelloedd newydd nid oedd yn bosibl gwneud hyn bellach, a bu'n rhaid dadansoddi'r darnau hyn a'u hailysgrifennu â llaw.

Felly, mae'r mudo cod wedi'i gwblhau, mae'r cod yn cael ei lunio ar gyfer pob system weithredu. Mae'n amser ar gyfer profion.

Dangosodd profion ar ôl y cyfnod pontio ostyngiad mewn perfformiad (hyd at 20-30% mewn rhai mannau) a chynnydd yn y defnydd o gof (hyd at 10-15%) o'i gymharu â'r hen fersiwn o'r cod. Roedd hyn, yn arbennig, oherwydd perfformiad is-optimaidd llinynnau safonol. Felly, roedd yn rhaid i ni unwaith eto ddefnyddio ein llinell ein hunain, wedi'i haddasu ychydig.

Datgelwyd hefyd nodwedd ddiddorol o weithredu cynwysyddion mewn llyfrgelloedd mewnol: gwag (heb elfennau) std::map a std::set o lyfrgelloedd adeiledig yn dyrannu cof. Ac oherwydd y nodweddion gweithredu, mewn rhai mannau yn y cod mae cryn dipyn o gynwysyddion gwag o'r math hwn yn cael eu creu. Mae cynwysyddion cof safonol yn cael eu dyrannu ychydig, ar gyfer un elfen wraidd, ond i ni daeth hyn yn hollbwysig - mewn nifer o senarios, gostyngodd ein perfformiad yn sylweddol a chynyddodd y defnydd o gof (o'i gymharu â STLPort). Felly, yn ein cod fe wnaethom ddisodli'r ddau fath hyn o gynwysyddion o'r llyfrgelloedd adeiledig gyda'u gweithrediad o Boost, lle nad oedd gan y cynwysyddion hyn y nodwedd hon, a datrysodd hyn y broblem gydag arafu a defnydd cynyddol o gof.

Fel sy'n digwydd yn aml ar ôl newidiadau ar raddfa fawr mewn prosiectau mawr, ni weithiodd iteriad cyntaf y cod ffynhonnell heb broblemau, ac yma, yn benodol, daeth cefnogaeth i iterwyr dadfygio wrth weithredu Windows yn ddefnyddiol. Cam wrth gam symudwyd ymlaen, ac erbyn gwanwyn 2017 (fersiwn 8.3.11 1C:Menter) roedd y mudo wedi'i gwblhau.

Canlyniadau

Cymerodd y newid i safon C++14 tua 6 mis i ni. Y rhan fwyaf o'r amser, bu un datblygwr (ond â chymwysterau uchel iawn) yn gweithio ar y prosiect, ac ar y cam olaf ymunodd cynrychiolwyr timau sy'n gyfrifol am feysydd penodol - UI, clwstwr gweinyddwyr, offer datblygu a gweinyddu, ac ati.

Fe wnaeth y trawsnewidiad symleiddio ein gwaith ar fudo i'r fersiynau diweddaraf o'r safon yn fawr. Felly, mae fersiwn 1C:Enterprise 8.3.14 (yn cael ei ddatblygu, rhyddhau a drefnwyd ar gyfer dechrau'r flwyddyn nesaf) eisoes wedi'i drosglwyddo i'r safon C++17.

Ar ôl y mudo, mae gan ddatblygwyr fwy o opsiynau. Pe bai gennym yn gynharach ein fersiwn wedi'i haddasu ein hunain o STL ac un gofod enw std, erbyn hyn mae gennym ddosbarthiadau safonol o'r llyfrgelloedd casglwyr adeiledig yn y gofod enwau std, yn y gofod enw stdx - mae ein llinellau a'n cynwysyddion wedi'u optimeiddio ar gyfer ein tasgau, yn hwb - y fersiwn diweddaraf o hwb. Ac mae'r datblygwr yn defnyddio'r dosbarthiadau hynny sy'n fwyaf addas i ddatrys ei broblemau.

Mae gweithrediad “brodorol” adeiladwyr symud hefyd yn helpu mewn datblygiad (symud adeiladwyr) ar gyfer nifer o ddosbarthiadau. Os oes gan ddosbarth adeiladwr symud a bod y dosbarth hwn yn cael ei roi mewn cynhwysydd, yna mae'r STL yn gwneud y gorau o gopïo elfennau y tu mewn i'r cynhwysydd (er enghraifft, pan fydd y cynhwysydd yn cael ei ehangu ac mae angen newid cynhwysedd ac ailddyrannu cof).

Llwy o dar

Efallai mai canlyniad mwyaf annymunol (ond nid tyngedfennol) mudo yw ein bod yn wynebu cynnydd yn y niferoedd ffeiliau obj, a dechreuodd canlyniad llawn yr adeiladu gyda'r holl ffeiliau canolradd gymryd 60–70 GB. Mae'r ymddygiad hwn oherwydd hynodrwydd llyfrgelloedd safonol modern, sydd wedi dod yn llai beirniadol o faint y ffeiliau gwasanaeth a gynhyrchir. Nid yw hyn yn effeithio ar weithrediad y cais a luniwyd, ond mae'n achosi nifer o anghyfleustra wrth ddatblygu, yn benodol, mae'n cynyddu amser llunio. Mae'r gofynion ar gyfer gofod disg am ddim ar weinyddion adeiladu ac ar beiriannau datblygwyr hefyd yn cynyddu. Mae ein datblygwyr yn gweithio ar sawl fersiwn o'r platfform yn gyfochrog, ac mae cannoedd o gigabeit o ffeiliau canolradd weithiau'n creu anawsterau yn eu gwaith. Mae’r broblem yn annymunol, ond nid yn hollbwysig; rydym wedi gohirio ei datrysiad am y tro. Rydym yn ystyried technoleg fel un o'r opsiynau ar gyfer ei datrys adeiladu undod (yn benodol, mae Google yn ei ddefnyddio wrth ddatblygu'r porwr Chrome).

Ffynhonnell: hab.com

Ychwanegu sylw