Utafiti wa kitaaluma, lugha inayoeleweka

Verianla | Akademik Araştırmalardan Türkçe Ekonomi ve Bilim İçerikleri

27 Septemba 2026, Jumapili
VERİANLAUchapishaji huru wa sayansi
Fungua au funga menyu
...
Home / Sayansi Tumizi / Sayansi ya Kompyuta / Miundo ya Usanifu wa C++ kwa Programu zenye Ucheleweshaji Mdogo na Biashara ya Masafa ya Juu
Sayansi ya Kompyuta

Miundo ya Usanifu wa C++ kwa Programu zenye Ucheleweshaji Mdogo na Biashara ya Masafa ya Juu

Uboreshaji wa C++ wenye ucheleweshaji mdogo ni mbinu ya uhandisi wa utendaji inayopanga kwa utaratibu gharama za kiwango cha CPU, kama vile ufikiaji wa kumbukumbu, matumizi ya cache, hesabu za wakati wa ukompaili, matawi, mpangilio wa data, utekelezaji sambamba na mawasiliano kati ya thread, kwa lengo la kupunguza si muda wa wastani wa utekelezaji pekee bali pia utofauti wa ucheleweshaji.

16/09/2026  Veri Anla Imetazamwa mara 92
Miundo ya Usanifu wa C++ kwa Programu zenye Ucheleweshaji Mdogo na Biashara ya Masafa ya Juu

Uboreshaji wa C++ wenye ucheleweshaji mdogo ni mbinu ya uhandisi wa utendaji inayopanga kwa utaratibu gharama za kiwango cha CPU, kama vile ufikiaji wa kumbukumbu, matumizi ya cache, hesabu za wakati wa ukompaili, matawi, mpangilio wa data, utekelezaji sambamba na mawasiliano kati ya thread, kwa lengo la kupunguza si muda wa wastani wa utekelezaji pekee bali pia utofauti wa ucheleweshaji. Utafiti wa Paul Bilokon na Burak Gunduz unachunguza mbinu hii katika tabaka tatu: Low-Latency Programming Repository inayofanyia benchmark mbinu nyingi za uboreshaji wa C++ moja moja, algoriti ya backtest ya pairs-trading isiyoegemea upande wa soko ambamo mbinu hizi zimetumika, na muundo wa LMAX Disruptor uliotekelezwa kwa C++ kwa mawasiliano ya producer–consumer.

Katika chanzo, ongezeko kubwa zaidi la kasi lililoripotiwa kwenye microbenchmark zilizotengwa lilikuwa takriban %90 kwa cache warming na constexpr, %72,24 kwa loop unrolling, takriban %63 kwa kihesabu cha atomic lock-free, kwa maneno ya waandishi wa chanzo takriban %52 katika mfano uliopima kutochanganya aina za float/double, takriban %50 kwa short-circuiting na takriban %49 kwa uongezaji wa safu kwa SIMD. Kwa upande mwingine, inlining ilionyesha %20,5, prefetching %23,5, compile-time dispatch takriban %26, branch reduction %36, slowpath removal %12 na ulinganisho husika wa signed/unsigned takriban %12,15 ya uboreshaji. Asilimia hizi zinatokana na microbenchmark tofauti; haziwezi kujumlishwa katika programu moja na kutafsiriwa kama asilimia ya jumla ya kuongeza kasi.

Katika programu ya pairs-trading, wakati SIMD/AVX2, loop unrolling, matumizi ya safu yenye ukubwa usiobadilika na inlining vilipounganishwa, tathmini iliyotokana na mizunguko 10 ya benchmark ilionyesha ucheleweshaji wa wastani ukishuka kutoka takriban 517.559 ns hadi 65.588 ns, na chanzo kiliripoti hili kama uboreshaji wa ucheleweshaji wa %87,38. Mkengeuko sanifu pia ulipungua kutoka 4.233 ns hadi 400 ns. Hata hivyo, jaribio hili lilifanywa kwenye msimbo wa backtest unaotumia data za kihistoria; mtiririko hai wa data ya soko, network latency, muunganisho wa soko na tabia ya Order Management System halisi hazijajumuishwa katika matokeo haya.

Katika tabaka la tatu la utafiti, C++ Disruptor ililinganishwa na queue ya kawaida inayotumia mutex na condition variable. Kadiri idadi ya event ilivyoongezeka, faida iliyopimwa ya Disruptor kwa ujumla iliongezeka; chanzo kiliripoti katika Jedwali 4 kuongeza kasi kwa %11,9 kwa event 10, %48,8 kwa event 1.000, %55,2 kwa event 10.000 na %38,7 kwa event 1.000.000. Katika jaribio tofauti la mizunguko 20 la event 1.000, ucheleweshaji wa wastani ulitolewa kama 931.255 ns kwa Simple Queue na 74.908 ns kwa Disruptor, huku t-statistic ya tofauti ikiwa 22,596 na p-value ikiwa \(1.243\times10^{-23}\). Kwa kuwa nyakati kamili zinatofautiana na mfululizo uliopita wa benchmark, seti hizi mbili za data hazipaswi kuunganishwa kana kwamba ni mfululizo mmoja wa kipimo.

Utafiti unajaribu kutatua tatizo gani?

Katika mifumo ya biashara ya masafa ya juu, haitoshi kwa programu kufanya uamuzi sahihi pekee; ucheleweshaji ambao uamuzi huo unafanywa nao na kiasi ambacho ucheleweshaji huo hubadilika kutoka mzunguko mmoja hadi mwingine pia ni muhimu. Kwa hiyo, utafiti unalenga kupima kwa vipimo halisi katika kiwango cha CPU uboreshaji unaoonekana kuwa mdogo katika msimbo wa C++.

Msukumo mkuu wa waandishi ni kwamba sehemu muhimu ya uhandisi wa ucheleweshaji mdogo katika sekta ya HFT haipatikani kwa undani katika fasihi ya wazi ya kitaaluma kwa sababu ya ushindani na usiri. Ili kupunguza pengo hili, Low-Latency Programming Repository iliundwa si kama orodha inayotaja tu mbinu, bali kama hifadhi ya vitendo yenye msimbo wa benchmark na vipimo.

Kwa Nini Cache Warming ni Muhimu katika C++ yenye Ucheleweshaji Mdogo?

Cache warming ni kuweka data au maagizo muhimu kwa utendaji tayari katika cache ya CPU kwa kuyafikia kabla hayajahitajika kikweli. Kwa kuwa “hot path” katika HFT, hata ikiwa haitumiki mara nyingi, inapaswa kuwa ya haraka sana inapochochewa, utafiti unaonyesha kuwa kuendesha au kusoma mapema data na msimbo husika wa injini ya utekelezaji na kuuweka ndani ya cache kunaweza kupunguza ucheleweshaji wa ufikiaji wa kumbukumbu.

Chanzo kiliunda hali mbili tofauti za Google Benchmark. BM_CacheCold hufikia seti kubwa ya data kwa nasibu na kuunda spatial locality dhaifu, ilhali BM_CacheWarm hufikia data kwa mpangilio kabla na wakati wa benchmark.

KipimoBM_CacheColdBM_CacheWarm
Muda267.685.006 ns25.635.035 ns
Instruction4.931.929.48912.013.354.366
Cache reference146.264.56261.306.992
Cache miss / cache reference%73,964%71,559

Waandishi wanatafsiri tofauti ya muda kama takriban %90 ya uboreshaji wa kasi. Jambo la kuvutia ni kwamba, ingawa kiwango cha cache-miss kilipungua kutoka %73,964 hadi %71,559 pekee, jumla ya cache reference ilipungua kwa kiasi kikubwa. Matokeo haya yanaonyesha kuwa uboreshaji wa cache hauwezi kutafsiriwa kwa kuangalia “asilimia ya miss” pekee; mpangilio wa ufikiaji, jumla ya memory traffic na kiasi cha kazi kinachofanywa ndani ya muda uleule pia ni muhimu.

Compile-time dispatch

Runtime dispatch hutegemea kuchagua kazi itakayotekelezwa wakati programu inaendelea, ilhali compile-time dispatch hufanya uamuzi huo katika hatua ya ukompaili. Katika benchmark ya chanzo, mifano miwili ya runtime-dispatch ilipimwa kwa 2,60 ns na 2,15 ns, huku matoleo ya compile-time yakikuwa 1,92 ns katika hali zote mbili. Tathmini ya jumla ya utafiti inahusisha mbinu hii na takriban %26 ya uboreshaji wa kasi.

Constexpr

constexpr huruhusu misemo inayofaa kutathminiwa wakati wa ukompaili badala ya runtime. Katika utafiti, toleo la constexpr la hesabu ya factorial 10 lilipimwa kwa takriban 0,245 ns, huku toleo la runtime recursive likiwa 2,69 ns, na chanzo kikiripoti tofauti ya kasi ya takriban %90,88.

Waandishi hawawasilishi matokeo haya kama kanuni ya jumla kwamba “constexpr daima huharakisha kwa %90.” Compiler za kisasa zinaweza pia kuboresha msimbo usio wa constexpr. Tofauti katika jaribio hili ilitokea chini ya msimbo huu mahususi na tabia ya compiler.

Inlining

Inlining hulenga kuweka mwili wa kazi mahali pa wito badala ya kufanya wito wa kazi. Jaribio lililotumia always_inline lilichukua takriban 1,90 ns, kazi ya kawaida takriban 2,39 ns, na chanzo kiliripoti takriban %20,5 ya uboreshaji. Hata hivyo, inlining kupita kiasi inaweza kuongeza ukubwa wa executable na kuzorotesha tabia ya instruction cache.

Loop unrolling

Loop unrolling hufanya shughuli kadhaa wazi katika iteresheni moja ili kupunguza idadi ya marudio ya udhibiti wa kitanzi. Katika jaribio la chanzo, kitanzi cha kawaida kilichukua 4.539 ns na kitanzi cha unrolled cha hatua nne 1.260 ns, huku uboreshaji wa %72,24 ukiripotiwa.

Mbinu hii pia haina uwezo wa kupanuka bila kikomo. Binary kubwa zaidi, shinikizo la instruction cache na mizigo ya kazi ya memory-bound inaweza kupunguza faida.

Short-circuiting

Short-circuiting ni kutofanya hesabu zisizohitajika mara tu matokeo ya usemi wa Boolean yanapokuwa yameamuliwa. Katika chanzo, kwenye majaribio tofauti kati ya iteresheni 8 na 8.192, toleo la short-circuit lilifanya kazi kwa takriban nusu ya muda wa toleo la kawaida; maboresho yaliripotiwa kati ya %49,53 na %52,83.

Slowpath removal

Slowpath removal huhamisha uchakataji wa hitilafu, logging au msimbo wa hali nadra nje ya hot path inayoendelea kufanya kazi. Katika benchmark ya chanzo ambapo hot path ilifanya kazi %90 na slow path %10, msimbo wa slowpath uliopachikwa moja kwa moja ulichukua 28.074 ns, toleo lililohamishwa kwenye kazi tofauti ya HandleError likachukua 24.755 ns, na uboreshaji wa takriban %12 ukaonekana.

Branch reduction

Branch reduction hulenga kupunguza idadi ya branch kwa kuunganisha hali za hitilafu, kwa mfano ndani ya bit mask, badala ya kufanya ukaguzi mwingi mfululizo katika hot path ileile. Katika jaribio la chanzo, muundo wa kawaida ulichukua 7,35 ns, muundo uliopunguza branch 4,68 ns, na uboreshaji wa takriban %36 ukaripotiwa.

Prefetching

Katika jaribio kubwa la uongezaji wa vekta lililotumia __builtin_prefetch, toleo lisilotumia prefetch lilichukua 8.235.924 ns na toleo linalotumia prefetch 6.301.400 ns. Chanzo kinaripoti hili kama faida ya utendaji ya takriban %23,5. Faida hutegemea uwezo wa kutabiri ufikiaji wa data, ukubwa wa data na usanifu wa prosesa.

Ulinganisho wa signed na unsigned integer

Katika jaribio maalum la chanzo, kazi inayotumia signed integer ilipimwa kwa 0,282 ns na toleo la unsigned kwa 0,321 ns, na faida ya kasi ya takriban %12,15 ikakokotolewa kwa toleo la signed. Sababu ni kwamba katika mfano huo compiler ilitoa maagizo ya ziada ya assembly ili kuhifadhi hali ya unsigned overflow.

Matokeo haya hayawezi kujumlishwa kuwa “signed daima ni haraka kuliko unsigned.” Chanzo chenyewe kinapima microbenchmark yenye kitanzi maalum na semantiki maalum ya overflow.

Kuchanganya aina za float na double

Kushughulikia thamani ya float kwa literal kama 1.23, ambayo kwa chaguo-msingi ni double, kunaweza kuunda ubadilishaji wa float → double → float. Katika chanzo, toleo la mixed lilipimwa kwa 21,6 ns na toleo linalotumia float pekee kwa 1.23f kwa 14,2 ns, na waandishi wakasema toleo la unmixed ni takriban %52 haraka zaidi.

SIMD

Single Instruction, Multiple Data (SIMD) huruhusu shughuli sambamba kwenye vipengele vingi vya data kwa amri moja ya CPU. Katika jaribio la array-addition lililotumia SSE2, toleo la kawaida lilichukua 21.447 ns na toleo la SIMD 10.929 ns; kupungua kwa muda wa operesheni kwa takriban %49 kuliripotiwa.

Programu ya Lock-free

Utafiti ulilinganisha shughuli za atomiki na usawazishaji unaotegemea mutex. Kwa increment 10.000, toleo la atomic lilichukua takriban 65.369 ns na toleo la mutex 175.904 ns, huku chanzo kikiripoti takriban %63 ya uboreshaji wa utendaji kwa mbinu ya atomiki.

Programu ya lock-free si “bure” licha ya kutotumia kufuli. Gharama za Atomics, CAS, memory ordering na cache-coherence zinaendelea kuwepo; pia kutekeleza muundo sahihi wa lock-free kunaweza kuwa changamano zaidi kuliko msimbo unaotegemea mutex.

Kernel bypass

Kernel bypass haikufanyiwa benchmark ndani ya utafiti huu. Mbinu hiyo inalenga kufanya user space iwasiliane na NIC kwa njia ya moja kwa moja zaidi badala ya kupitisha paketi za mtandao kupitia kernel networking stack. Chanzo kinataja teknolojia kama OpenOnload, VMA na DPDK kama mifano, lakini hakiwasilishi utendaji wake kama jaribio la utafiti huu.

Kwa Nini LMAX Disruptor ni Tofauti na Foleni ya Kawaida?

LMAX Disruptor ni usanifu wa ujumbe wenye ucheleweshaji mdogo unaosimamia uhamishaji wa data kati ya producer na consumer kwa kutumia ring buffer iliyotengewa mapema, nambari za sequence zinazoendelea kuongezeka na wait strategy inayoweza kuchaguliwa. Tofauti yake kuu na mbinu ya kawaida ya mutex/condition-variable queue ni kupunguza kadiri iwezekanavyo gharama za runtime memory allocation na lock contention, ili producer na consumer wafikie data ya pamoja kupitia mpangilio wa kumbukumbu unaotabirika zaidi.

Ring buffer

Ring buffer ni muundo wa data wenye ukubwa usiobadilika unaotumiwa tena kwa mzunguko. Kwa kuwa kumbukumbu hutengwa mwanzoni, hakuna haja ya allocation/deallocation mpya kwa kila event. Hii hufanya matumizi ya kumbukumbu kuwa yanayotabirika zaidi na inaweza pia kutoa faida kwa cache locality.

Sequencer

Sequencer hufuatilia kwa nambari za sequence ni slot zipi za ring-buffer zinazoweza kuandikwa na producer na kusomwa na consumer. Baada ya producer kuandika event, huchapisha sequence husika; consumer hufuatilia hatua yake ya maendeleo kupitia sequence.

Sequence Barrier na Wait Strategy

Sequence Barrier humwezesha consumer kuamua kama event inaweza kusomwa kwa usalama. Ikiwa data bado haipatikani, Wait Strategy huanza kutumika. Busy-spin inaweza kulenga latency ya chini kabisa lakini hutumia CPU nyingi; sleeping inaweza kutumia CPU kidogo huku ikisababisha latency ya juu zaidi.

Wait strategy iliyotumika katika benchmark za utafiti ni yield wait. Hakukuwa na ulinganisho wa kimfumo na busy-spin, sleeping au mikakati mingine. Kwa hiyo, thamani za latency za Disruptor si matokeo ya jumla kwa usanidi wote unaowezekana.

Mbinu na Matokeo ya Utafiti

Tabaka la kwanza la majaribio: Low-Latency Programming Repository

Waandishi walikusanya uboreshaji chini ya vichwa vya compile-time features, optimisation techniques, data handling, concurrency na system programming. Google Benchmark ilikuwa zana kuu ya kupima muda; Linux perf ilitumika hasa kwa uchambuzi wa cache-reference na cache-miss.

MbinuUboreshaji wa takriban ulioripotiwa katika chanzoUtaratibu mkuu
Cache warming%90Kuleta data/agizo kwenye cache mapema
Constexpr%90,88Kuhamisha hesabu kutoka runtime hadi compile-time
Loop unrolling%72,24Kupunguza mzigo wa udhibiti wa kitanzi
Atomic / lock-free counter%63Kupunguza gharama za mutex na context-switch
Kutochanganya Float/doubleKwa maneno ya chanzo %52Kuondoa implicit conversion
Short-circuitingTakriban %50Kutotekeleza hesabu zisizohitajika za Boolean
SIMD array additionTakriban %49Kuchakata vipengele vingi vya data kwa amri moja
Branch reduction%36Kupunguza idadi ya branch ndani ya hot path
Compile-time dispatchTakriban %26Kuondoa uamuzi wa Runtime dispatch
Prefetching%23,5Kuomba data kwenye cache kabla ya kutumiwa
Inlining%20,5Kupunguza mzigo wa wito wa kazi
Mfano wa Signed vs unsigned%12,15Maagizo machache ya assembly katika benchmark maalum
Slowpath removal%12Kutenganisha msimbo nadra na instruction hot path

Jedwali hili halipaswi kutafsiriwa kama orodha ya “uboreshaji upi ni bora zaidi?” Kila mstari una operesheni, ukubwa wa data, tabia ya compiler na muundo wa benchmark tofauti. Kwa mfano, matokeo ya 90% ya cache-warming yanatokana na benchmark kubwa ya memory-access, ilhali matokeo ya 90,88% ya constexpr yanatokana na mfano wa factorial 10.

Tabaka la pili la majaribio: pairs trading

Ili kuona uboreshaji katika programu iliyo karibu zaidi na uhalisia, utafiti ulitumia backtest ya statistical-arbitrage pairs-trading kwenye data za adjusted-close za kila siku za miaka mitano za hisa za Goldman Sachs Group Inc. (GS) na Morgan Stanley (MS).

Cointegration Inamaanisha Nini katika Mkakati wa Pairs Trading?

Cointegration ni hali ambapo mchanganyiko fulani wa mstari wa misururu miwili ya muda ambayo kila mmoja ni non-stationary huwa stationary. Katika utafiti huu, kupima misururu ya adjusted-close ya GS na MS kwa mbinu ya hatua mbili ya Engle–Granger kulitumiwa kutoa ushahidi wa takwimu kwamba kulikuwa na uhusiano wa muda mrefu wa usawaziko kati ya misururu ya bei katika kipindi cha miaka mitano kilichochunguzwa.

Katika uwasilishaji wa dhana wa chanzo, misururu miwili:

\[ Y_t=\rho Y_{t-1}+\epsilon_{Y_t} \]
\[ X_t=\beta X_{t-1}+\epsilon_{X_t} \]

huchukuliwa kwa namna hii. Ikiwa:

\[ Z_t=Y_t-\gamma X_t \]

mchanganyiko ni stationary, basi \(Y_t\) na \(X_t\) hutathminiwa kuwa cointegrated. Hapa \(\gamma\) inawakilisha uhusiano wa muda mrefu wa mstari kati ya misururu miwili.

Katika jaribio la Engle–Granger kwa GS–MS, chanzo kinaripoti p≈0,0149 na t≈−3,7684. Katika kiwango cha significance cha \(0,05\), no-cointegration null hypothesis ilikataliwa. Matokeo haya yanatoa ushahidi wa takwimu wa cointegration; hayathibitishi kwamba uhusiano hautabadilika siku zijazo au kwamba mkakati wa trading utakuwa na faida kwa uhakika.

Uzalishaji wa ishara kwa Z-score

Algoriti husanifisha spread ya sasa kwa kutumia rolling mean na standard deviation ya spread:

\[ Z=\frac{X-\mu}{\sigma} \]

Hapa \(Z\) ni z-score, \(X\) ni spread ya sasa, \(\mu\) ni rolling spread mean na \(\sigma\) ni thamani ya rolling spread standard deviation.

Katika mkakati wa chanzo:

  • \(Z>1.0\): GS huchukuliwa kuwa ghali kwa kulinganisha; ishara ya GS short, MS long hutolewa.
  • \(Z<-1.0\): GS huchukuliwa kuwa nafuu kwa kulinganisha; ishara ya GS long, MS short hutolewa.
  • \(|Z|<0.8\): kwa dhana kwamba spread imerudi kwenye wastani, nafasi iliyo wazi hufungwa.
  • Katika maeneo mengine hakuna ishara mpya ya biashara inayotolewa.

Matokeo ya kifedha ya Backtest

Katika backtest ya chanzo, jalada huanza na dola za Marekani 1.000.000 na kumalizika na dola za Marekani 1.328.581. Sharpe ratio iliyoripotiwa ni 1,09.

\[ \text{Sharpe Ratio}=\frac{R_p-R_f}{\sigma_p} \]

\(R_p\) ni mapato ya jalada, \(R_f\) ni mapato yasiyo na hatari na \(\sigma_p\) ni thamani ya standard deviation ya excess-return ya jalada.

Kulingana na maelezo ya utafiti wenyewe, tathmini kamili ya mafanikio ya kifedha ya algoriti ya trading si lengo kuu la utafiti. Matokeo haya yanatokana na backtest ya data za kihistoria na hayawakilishi transaction cost, execution quality halisi, order-book dynamics, slippage, network delay na hitilafu zote za soko hai.

Uboreshaji wa CPU katika algoriti ya Pairs-trading

AVX2 ilitumika katika hesabu ya rolling spread mean na standard-deviation ya algoriti. Ndani ya register ya 256-bit __m256d, thamani nne za double zilichakatwa kwa wakati mmoja, huku jumla ya spread na jumla ya miraba zikihesabiwa sambamba. Mpangilio huu pia unatekeleza loop unrolling kwa hatua za vipengele vinne.

Kikomo muhimu ambacho chanzo kinataja kwa programu hii ni hitaji kwamba window size iwe kizidishi cha nne. Hii inatokana na muundo wa AVX2 uliotumika.

Mabadiliko ya pili muhimu ni kutumia array yenye ukubwa usiobadilika na rolling index badala ya dynamic container. Spread mpya inapokuja, kipengele cha zamani zaidi hubadilishwa katika nafasi ileile ndani ya array; hivyo hitaji la dynamic memory allocation inayorudiwa hupunguzwa.

Inlining pia ilitumika kwa kazi za kuhesabu mean na standard-deviation.

MuundoLatencyUboreshaji ulioripotiwa katika chanzo
Inlining406.709 ns%21,41
SIMD + loop unrolling355.618 ns%31,28
Fixed array266.146 ns%48,58
Combined65.580 ns%87,33

Katika sehemu ya baadaye ya evaluation ya mizunguko 10, chanzo kinatoa wastani wa 517.559 ns na standard deviation ya 4.233 ns kwa algoriti isiyoboreshwa; na wastani wa 65.588 ns na standard deviation ya 400 ns kwa algoriti iliyoboreshwa. Kwa hivyo, upungufu wa latency ulioripotiwa ni %87,38.

Katika sehemu ya awali ya mbinu pia kuna thamani ya 519.772 ns kwa baseline. Kwa kuwa chanzo hakielezi wazi tofauti ndogo kati ya nambari hizi mbili za baseline, thamani hizo hazijalazimishwa kuunganishwa kuwa nambari moja.

Idadi ya Instruction na tabia ya Cache-miss

MbinuInstructionCache misses / cache references
Bila uboreshaji6,01 bilioni%16,001
Combined3,27 bilioni%33,879
Fixed array8,27 bilioni%19,089
Inlining9,07 bilioni%19,151
SIMD + loop unrolling8,35 bilioni%16,829

Jedwali hili linafanya matokeo muhimu yaonekane: asilimia ndogo ya cache-miss au idadi ndogo ya instruction peke yake haimaanishi programu ya haraka zaidi. Ingawa toleo la Combined lilikuwa na asilimia kubwa zaidi ya cache-miss, lilitoa latency ya chini zaidi. Utendaji wa CPU ni matokeo ya pamoja ya instruction-level parallelism, memory layout, branch behavior, uboreshaji wa compiler na mpangilio wa ufikiaji wa data.

Jaribio la takwimu

Katika benchmark za pairs-trading, kila muundo uliendeshwa mara 10 na paired t-test ikatumika kwa vipimo vya latency vilivyoboreshwa/isivyoboreshwa. Chanzo kinaripoti t-statistics kubwa sana na p-values ndogo sana, na kinaeleza kuwa uwezekano wa tofauti iliyopimwa ya latency kuelezwa tu na mabadiliko ya nasibu ni mdogo.

Hata hivyo, chanzo kinakubali wazi kuwa kutumia pointi 10 tu za data ni kizuizi na kinaeleza kuwa vipimo zaidi vinaweza kuongeza usahihi.

Tafsiri ya faida inapaswa kubaki ndani ya mpaka gani?

Chanzo kinaunganisha latency ya chini na fasihi kwa hoja kwamba inaweza kuwa na manufaa ya kifedha kwa sababu ya uwezo wa kuitikia mapema fursa za soko za muda mfupi. Pia, kwa kutumia uhusiano ulioripotiwa katika utafiti mwingine kati ya latency na kukabiliwa na mabadiliko hasi ya order-book, kinatoa hesabu inayolinganishwa ongezeko la kasi la %87,32 na takriban %78,59 ya exposure ndogo zaidi.

Thamani hii ya %78,59 si matokeo yaliyopimwa moja kwa moja na utafiti katika soko hai. Ni makadirio yanayotokana na chanzo kwa kuunganisha kwa mstari uhusiano wa regresheni wa utafiti mwingine na faida ya latency ya backtest ya utafiti huu. Haijaonyeshwa kwamba upungufu huo huo wa exposure hutokea katika mfumo halisi wa HFT.

Tabaka la tatu la majaribio: C++ Disruptor

Utekelezaji wa C++ Disruptor umeundwa kutokana na vipengele producer, ring buffer, sequencer, event processor, sequence barrier, event na wait strategy. Katika muktadha wa HFT, event inaweza kuwa kitu cha order; katika benchmark ya chanzo event rahisi ya string ilitumika.

Muundo wa kulinganisha una thread mbili. Katika toleo la Disruptor, producer huchapisha data kwenye ring buffer na consumer huichakata katika thread tofauti kulingana na nambari za sequence. Katika toleo la Simple Queue, std::queue<std::string>, std::mutex na std::condition_variable hutumika.

EventSimple QueueDisruptorKuongeza kasi kulikoripotiwa katika chanzo
1020.646 ns18.182 ns%11,9
10099.458 ns64.686 ns%35,0
1.000881.092 ns451.251 ns%48,8
10.0009.735.102 ns4.361.096 ns%55,2
100.00090.088.609 ns52.562.872 ns%41,7
1.000.000884.871.405 ns543.171.556 ns%38,7

Chanzo kinaeleza kwamba kadiri idadi ya event inavyoongezeka, tofauti kamili ya muda kati ya miundo miwili inaongezeka. Kwa event 10 tofauti ya wastani iliripotiwa kuwa 2.464 ns, na kwa event 1.000.000 kuwa 341.699.849 ns.

Tabia ya cache ya Disruptor

Katika mizigo midogo kama event 10 na 100, kiwango cha cache-miss cha Disruptor kilikuwa juu kidogo kuliko Simple Queue. Katika masafa ya event 1.000–1.000.000, uhusiano huo uligeuka na Disruptor ikaonyesha viwango vya chini vya cache-miss. Hii inaashiria kuwa ring buffer inaweza kutoa tabia bora zaidi ya memory-access katika mitiririko mikubwa ya event.

Katika jaribio la 10-event, Disruptor ilitekeleza takriban 586.000 instruction chache. Chanzo kinaunganisha hili na kupungua kwa lock contention, kumbukumbu ya ring-buffer iliyotengwa mapema na mawasiliano ya producer–consumer yanayotabirika zaidi.

Jaribio la Utendaji wa Takwimu la Disruptor Linaonyesha Nini?

Katika jaribio tofauti la chanzo la mizunguko 20 na event 1.000, Simple Queue ilipimwa kuwa na latency ya wastani ya 931.255 ns na standard deviation ya 453.766 ns; Disruptor latency ya wastani ya 74.908 ns na standard deviation ya 53.600 ns. Kwa kuwa matokeo ya T-test yaliripotiwa kama \(t=22.596\) na \(p=1.243\times10^{-23}\), ndani ya seti hii ya majaribio tofauti ya latency ya wastani iliyopimwa kati ya miundo miwili ni yenye nguvu kitakwimu.

Matokeo haya yana nyakati kamili zinazotofautiana na thamani za 1.000-event katika Jedwali 4. Chanzo kinawasilisha hizi kama tathmini tofauti za benchmark lakini hakielezi kwa kina chanzo cha tofauti ya usanidi au kipimo. Kwa hiyo, 451.251 ns na 74.908 ns hazipaswi kupunguzwa kuwa thamani moja “sahihi” ya Disruptor latency.

Vikwazo vya tathmini ya Disruptor

Benchmark imelenga hasa kasi ya inter-thread communication. Memory consumption na CPU load hazikulinganishwa kwa kina. Aidha, yield wait strategy pekee ndiyo iliyotumika; busy-spin, sleep na wait strategy nyingine hazikujaribiwa kwa utaratibu. Kwa hiyo, matokeo yaliyopimwa hayawakilishi usanidi wote wa Disruptor.

Tathmini ya watumiaji wa Low-Latency Repository

Repository ilikaguliwa na jumla ya washiriki 17 kutoka vyuo vikuu vinne: Imperial College London, University College London, King's College London na University of Oxford. Washiriki 11 walikuwa katika sayansi ya kompyuta; sita katika hisabati, fizikia au uhandisi.

KategoriaWastaniChini zaidiJuu zaidi
Comprehensiveness8,36,59,1
Clarity8,77,88,9

Tathmini hii si ushahidi wa utendaji wa programu, bali ni sampuli ndogo ya watumiaji kuhusu matumizi ya repository katika elimu.

Matokeo yanayoungwa mkono na utafiti

Chanzo kinaonyesha kwamba katika mazingira ya benchmark yaliyokaguliwa, mpangilio wa data katika kiwango cha C++, matumizi ya cache, hesabu za compile-time, kupunguza branch, SIMD, atomics na mikakati ya allocation vinaweza kuwa na athari inayopimika kwenye latency. Benchmark ya pairs-trading iliyotumia uboreshaji kadhaa pamoja ilitoa upungufu mkubwa zaidi wa jumla wa latency kuliko uboreshaji mmoja mmoja. Utekelezaji wa C++ Disruptor ulipimwa kuwa wa haraka zaidi kuliko mutex/condition-variable queue katika mizigo ya producer–consumer iliyojaribiwa.

Ujumla ambao utafiti hauuungi mkono

Utafiti hauonyeshi kwamba faida za asilimia katika benchmark zitarudiwa sawa kwenye CPU, compiler, mfumo wa uendeshaji au muundo wa data mwingine. Haiwezi kuhitimishwa kwamba cache warming itatoa %90 katika kila mzigo wa kazi, constexpr %90 katika kila hesabu au SIMD %49 katika kila algoriti. Vivyo hivyo, kupungua kwa latency ya backtest hakuwezi kusawazishwa moja kwa moja na faida ya live trading, na benchmark ya Disruptor haipimi end-to-end latency ya OMS kamili halisi.

Mapendekezo ya kazi ya baadaye

Chanzo kinapendekeza mwelekeo mkuu mitatu. Kwanza, kupanua repository kwa mbinu mpya kama variadic templates, kernel bypass na networking optimisations. Pili, kujaribu algoriti ya pairs-trading kwenye live market-data feed. Tatu, kuunganisha Disruptor na algoriti ya trading na kuunda benchmark pana zaidi ya trading-system ambamo vitu vya order huhamishwa kupitia ring buffer.

Maelezo ya Chanzo na Mbinu

Kichwa kamili cha asili: C++ design patterns for low-latency applications including high-frequency trading

Waandishi: Paul Bilokon; Burak Gunduz.

Uhusiano wa taasisi: Paul Bilokon — Departments of Computing and Mathematics, Imperial College London; Burak Gunduz — Department of Computing, Imperial College London.

Aina ya chanzo: Preprint.

Tarehe iliyoandikwa kwenye Manuscript: 11 Septemba 2023.

Tarehe ya toleo la kwanza la arXiv: 8 Septemba 2023.

arXiv: 2309.04259v1 [cs.PF].

DOI: 10.48550/arXiv.2309.04259.

Jukwaa: arXiv / CoRR.

Hali ya mapitio ya kitaalamu: Katika rekodi za bibliografia zilizothibitishwa, kazi inaonekana kama preprint / informal publication; toleo la jarida lililopitiwa na wataalamu halijathibitishwa.

Artefakti ya programu: Chanzo kinaeleza kwamba Low-Latency Programming Repository, msimbo wa pairs-trading na utekelezaji wa Disruptor zimetolewa katika hazina ya 0burak/imperial_hft.

Leseni: Kwa kuwa hakuna leseni wazi ya maudhui iliyogunduliwa katika PDF iliyopakiwa, hakuna Creative Commons maalum au leseni inayofanana iliyoainishwa.

Ufadhili: Hakuna taarifa tofauti ya ufadhili iliyogunduliwa katika preprint iliyopakiwa.

Mgongano wa maslahi: Hakuna taarifa tofauti ya mgongano wa maslahi iliyogunduliwa katika preprint iliyopakiwa.

CRediT / michango ya waandishi: Hakuna taarifa tofauti ya CRediT iliyoripotiwa.

Zana kuu za mbinu: Kipimo cha muda kwa Google Benchmark; tabia ya cache kwa Linux perf; microbenchmark za C++ zenye ucheleweshaji mdogo; jaribio la Engle–Granger cointegration na pairs-trading backtest kwa data za adjusted-close za GS–MS; uboreshaji wa AVX2/SIMD; ulinganisho wa C++ ring-buffer/Disruptor; paired t-test.

Vikwazo kuu: Sehemu muhimu ya benchmark ziko katika kiwango cha CPU na programu. Mtandao kamili wa uzalishaji wa HFT, co-location, exchange order flow, hardware timestamping na hali za live market-data hazikupimwa pamoja. Algoriti ya pairs-trading ni backtest ya data za kihistoria. Uboreshaji wa AVX2 unahitaji hardware inayounga mkono na, katika utekelezaji wa utafiti, window size ambayo ni kizidishi cha nne. Katika jaribio la Disruptor, memory consumption na CPU load hazikutathminiwa kwa kina; wait strategy mbadala hazikulinganishwa.

Maelezo ya uadilifu wa nambari ndani ya chanzo: Muda wa pairs-trading baseline unaonekana kama 519.772 ns katika sehemu ya mbinu na 517.559,10 ns katika sehemu ya baadaye ya evaluation. Aidha, thamani za 1.000-event za Disruptor zinatofautiana kati ya Jedwali 4 na jaribio la baadaye la takwimu la mizunguko 20. Verianla haijarekebisha kimya kimya thamani mojawapo au kuibadilisha na nyingine.


Shiriki:

Maoni huchapishwa baada ya kukaguliwa.Maoni yako yatapitia mchakato wa idhini na yataonekana yakikubaliwa.

Acha maoni

Anwani yako ya barua pepe haitachapishwa. Sehemu za lazima zimewekewa alama ya *

Your experience on this site will be improved by allowing cookies Cookie Policy