Pagpapalitan ng data gamit ang MPI. Paggawa gamit ang MPI library gamit ang halimbawa ng Intel® MPI Library. Nagpapadala ng iba't ibang uri ng data. Pangunahing Mga Pag-andar ng MPI

Mga function ng MPI

Uri ng Hinango, Mga Operasyon, Mga Uri ng Data

Bsend Buffer_attach Get_count ANY_SOURCE Sendrecv_replace ANY_TAG Probe

Allgetherv Alltoall Alltoallv Bawasan ang Rduce_scatter Scan

Binubuo ang isang derived type mula sa mga paunang natukoy na uri ng MPI at dating tinukoy na mga derived na uri gamit ang mga espesyal na function ng constructor

MPI_Type_contiguous, MPI_Type_vector, MPI_Type_hvector, MPI_Type_indexed, MPI_Type_hindexed, MPI_Type_struct.

Ang isang bagong derived type ay nakarehistro sa pamamagitan ng pagtawag sa MPI_Type_commit function. Pagkatapos lamang ng pagpaparehistro ay maaaring magamit ang isang bagong derived na uri sa mga gawain sa komunikasyon at sa pagbuo ng iba pang mga uri. Ang mga paunang natukoy na uri ng MPI ay itinuturing na nakarehistro.

Kapag ang isang nagmula na uri ay hindi na kailangan, ito ay masisira gamit ang MPI_Type_free function.

1) MPI_Init - pagpapaandar ng pagsisimula. Bilang resulta ng pagsasagawa ng function na ito, nilikha ang isang pangkat ng proseso kung saan inilalagay ang lahat ng mga proseso ng aplikasyon, at isang lugar ng komunikasyon ay nilikha, na inilarawan ng paunang natukoy na tagapagbalita na MPI_COMM_WORLD.

MPI_Type_commit - uri ng pagpaparehistro, MPI_Type_free - uri ng pagkasira

int MPI_Init(int *argc, char ***argv);

2) MPI_Finalize - Pagkumpleto ng function mga programa ng MPI. Isinasara ng function ang lahat ng proseso ng MPI at inaalis ang lahat ng lugar ng komunikasyon.

int MPI_Finalize(void);

3) Function para sa pagtukoy ng bilang ng mga proseso sa lugar ng komunikasyon MPI_Comm_size . Ibinabalik ng function ang bilang ng mga proseso sa lugar ng komunikasyon ng communicator comm.

int MPI_Comm_size(MPI_Comm comm, int *size);

4) Pag-andar ng pagtuklas ng numero ng proseso MPI_Comm_rank . Ibinabalik ng function ang bilang ng proseso na tinatawag na function na ito. Ang mga numero ng proseso ay nasa hanay na 0..size-1.

int MPI_Comm_rank(MPI_Comm comm, int *rank);

5) Pag-andar ng mensahe MPI_Send. Ang function ay nagpapadala ng mga elemento ng bilang ng datatype ng mensahe na may tag ng identifier upang iproseso ang dest sa lugar ng komunikasyon ng communicator comm.

int MPI_Send(void* buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm);

6) Function ng pagtanggap ng mensahe MPI_Recv. Ang function ay tumatanggap ng bilang ng mga elemento ng datatype ng mensahe na may tag ng identifier mula sa proseso ng pinagmulan sa lugar ng komunikasyon ng communicator comm.

int MPI_Recv(void* buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status *status)

7) Timing function (timer) MPI_Wtime. Ibinabalik ng function ang astronomical na oras sa mga segundo na lumipas mula noong ilang punto sa nakaraan (reference point).

dobleng MPI_Wtime(walang bisa)

Ang mga function para sa pagpasa ng mga mensahe sa pagitan ng mga proseso ay nahahati sa:

Prefix S (kasabay)

nangangahulugan ng kasabay na mode ng paglilipat ng data. Ang operasyon ng paghahatid ng data ay nagtatapos lamang kapag natapos ang pagtanggap ng data. Ang function ay hindi lokal.

Prefix B (buffered)

ibig sabihin ay buffered data transfer mode. Sa address space ng proseso ng pagpapadala gamit espesyal na function ang isang clipboard ay nilikha na ginagamit sa mga pagpapatakbo ng palitan. Nagtatapos ang operasyon ng pagpapadala kapag inilagay ang data sa buffer na ito. Ang function ay lokal sa kalikasan.

Prefix R (handa na)

napagkasunduan o inihandang paraan ng paghahatid ng data. Ang operasyon ng paglilipat ng data ay magsisimula lamang kapag ang tumatanggap na processor ay nagtakda ng tanda ng kahandaang tumanggap ng data, na nagsisimula sa pagtanggap ng operasyon. Ang function ay hindi lokal.

Prefix I (kaagad)

ay tumutukoy sa mga hindi pag-block na operasyon.

istraktura ng MPI_Status

Pagkatapos basahin ang isang mensahe, maaaring hindi alam ang ilang parameter, gaya ng bilang ng mga item na nabasa, message ID, at address ng nagpadala. Maaaring makuha ang impormasyong ito gamit ang parameter ng status. Ang mga variable ng katayuan ay dapat na tahasang ipahayag sa programa ng MPI. Sa wikang C, ang status ay isang istraktura ng uri ng MPI_Status na may tatlong field na MPI_SOURCE, MPI_TAG, MPI_ERROR.

8) Upang matukoy ang bilang ng mga elemento ng mensahe na aktwal na natanggap, dapat kang gumamit ng isang espesyal na function MPI_Get_count .

int MPI_Get_count (MPI_Status *status, MPI_Datatype datatype, int *count);

9) Maaari mong matukoy ang mga parameter ng natanggap na mensahe nang hindi ito binabasa gamit ang MPI_Probe function. int MPI_Probe (int source, int tag, MPI_Comm comm, MPI_Status *status);

10) Sa mga sitwasyon kung saan kailangan mong gumanap palitan ng kapwa data sa pagitan ng mga proseso, mas ligtas na gumamit ng pinagsamang operasyon MPI_Sendrecv . Sa operasyong ito, ang ipinadalang data mula sa buf array ay pinapalitan ng natanggap na data.

int MPI_Sendrecv(void *sendbuf, int sendcount, MPI_Datatype sendtype, int dest, int sendtag, void *recvbuf, int recvcount, MPI_Datatype recvtype, int source, MPI_Datatype recvtag, MPI_Comm comm, MPI_Status *status);

11) Function para sa pagsuri sa pagkumpleto ng isang non-blocking operation na MPI_Test.

int MPI_Test(MPI_Request *request, int *flag, MPI_Status *status);

Ito ay isang lokal na non-blocking na operasyon. Kung natapos na ang operasyong nauugnay sa kahilingan, ibabalik ang flag = true, at naglalaman ang status ng impormasyon tungkol sa nakumpletong operasyon. Kung hindi pa nakumpleto ang operasyong sinusuri, ibabalik ang flag = false, at ang halaga ng status ay hindi natukoy sa kasong ito.

12) Function para sa pagkansela ng isang kahilingan nang hindi naghihintay para sa pagkumpleto ng isang non-blocking operation MPI_Request_free.

int MPI_Request_free(MPI_Request *request);

Ang parameter ng kahilingan ay nakatakda sa MPI_REQUEST_NULL.

13) Ang pagkamit ng mahusay na pagpapatupad ng operasyon ng paglilipat ng data mula sa isang proseso patungo sa lahat ng proseso ng isang programa (pag-broadcast ng data) ay maaaring makamit gamit ang MPI function:

int MPI_Bcast(walang bisa *buf,int count,MPI_Datatype type,int root,MPI_Comm comm)

Ang MPI_Bcast function ay nagbo-broadcast ng data mula sa isang buffer buf na naglalaman ng mga elemento ng bilang uri ng uri mula sa prosesong may numerong ugat hanggang sa lahat ng prosesong kasama sa comm communicator.

14) Kung kailangan mong makatanggap ng mensahe mula sa sinuman ang proseso ng pagpapadala ay maaaring magkaroon ng halagang MPI_ANY_SOURCE na tinukoy para sa source na parameter

15) Kung kinakailangang makatanggap ng mensahe na may anumang tag, maaaring tukuyin ang halaga para sa parameter ng tag MPI_ANY_TAG

16) Ang parameter ng katayuan ay nagbibigay-daan sa iyo upang tukuyin ang isang bilang ng mga katangian ng natanggap na mensahe:

- katayuan.MPI_SOURCE – ranggo ang proseso ng pagpapadala ng natanggap na mensahe,

- status.MPI_TAG - tag ng natanggap na mensahe.

17) Pag-andar

MPI_Get_coun t(MPI_Status *status, MPI_Datatype type, int *count)

ibinabalik sa count variable ang bilang ng mga elemento ng uri ng uri sa natanggap na mensahe.

18) Mga operasyong naglilipat ng data mula sa lahat ng proseso patungo sa isang proseso. Sa operasyong ito sa nakolekta

ang mga halaga ay nagsasagawa ng isa o isa pang pagproseso ng data (upang bigyang-diin ang huling punto operasyong ito tinatawag ding data reduction operation)

int MPI_Reduce (void *sendbuf, void *recvbuf,int count,MPI_Datatype type, MPI_Op op,int root,MPI_Comm comm)

19) Pag-synchronize ng proseso, i.e. ang sabay-sabay na tagumpay sa pamamagitan ng mga proseso ng ilang mga punto ng proseso ng pagkalkula ay sinisiguro gamit ang MPI function: int MPI_Barrier(MPI_Comm comm); Ang MPI_Barrier function ay tumutukoy sa isang kolektibong operasyon at, samakatuwid, kapag ginamit, dapat na tawagan ng lahat ng mga proseso ng ginamit na tagapagbalita. Kapag tumatawag sa MPI_Barrier function

ang pagpapatupad ng proseso ay na-block;

20) Upang magamit ang buffered transfer mode, isang MPI memory buffer ay dapat gawin at ilipat

para sa buffering ng mensahe - ang function na ginamit para dito ay mukhang: int MPI_Buffer_attach (void *buf, int size),

- buf memory buffer para sa pag-buffer ng mga mensahe,

- laki – laki ng buffer.

21) Matapos tapusin ang pagtatrabaho sa buffer, dapat itong idiskonekta mula sa MPI gamit ang function:

int MPI_Buffer_detach (walang bisa *buf, int *laki).

22) Ang pagkamit ng mahusay at garantisadong sabay-sabay na pagpapatupad ng paghahatid ng data at mga operasyon sa pagtanggap ay maaaring makamit gamit ang MPI function:

int MPI_Sendrecv (void *sbuf,int scount,MPI_Datatype stype,int dest, int stag, void *rbuf,int rcount,MPI_Datatype

rtype,int source,int rtag, MPI_Comm comm, MPI_Status *status)

23) Kapag ang mga mensahe ay pareho ang uri, ang MPI ay may kakayahang gamitin nag-iisang buffer: intMPI_Sendrecv_replace (walang bisa *buf, int count, MPI_Datatype type, int dest,

int stag, int source, int rtag, MPI_Comm comm, MPI_Status* status)

24) Ang pangkalahatang operasyon ng pagpapadala ng data mula sa isang proseso patungo sa lahat ng proseso (pamamahagi ng data) ay naiiba sa pagsasahimpapawid dahil ang proseso ay nagpapadala ng iba't ibang data sa mga proseso (tingnan ang Fig. 4.4). Maaaring magawa ang operasyong ito gamit ang function:

int MPI_Scatter (walang bisa *sbuf,int scount,MPI_Datatype stype,

25) Ang operasyon ng pangkalahatang paglipat ng data mula sa lahat ng mga processor sa isang proseso (pagkolekta ng data) ay ang kabaligtaran ng pamamaraan ng pamamahagi ng data (tingnan ang Fig. 4.5). Upang maisagawa ang operasyong ito sa MPI mayroong isang function:

int MPI_Gather (walang bisa *sbuf,int scount,MPI_Datatype stype,

void *rbuf,int rcount,MPI_Datatype rtype, int root, MPI_Comm comm)

26) Dapat tandaan na kapag ginagamit ang MPI_Gather function, ang pagkolekta ng data ay isinasagawa lamang

sa isang proseso. Upang makuha ang lahat ng nakolektang data sa bawat isa sa mga proseso ng communicator

kailangan mong gamitin ang function ng koleksyon at pamamahagi:

int MPI_Allgather (void *sbuf, int scount, MPI_Datatype stype, void *rbuf, int rcount, MPI_Datatype rtype, MPI_Comm comm)

27) Ang paglilipat ng data mula sa lahat ng proseso patungo sa lahat ng proseso ay ang pinakakaraniwang operasyon ng paglilipat ng data (tingnan ang Larawan 4.6). Maaaring isagawa ang operasyong ito gamit ang function:

int MPI_Alltoall (walang bisa *sbuf,int scount,MPI_Datatype stype, void *rbuf,int rcount,MPI_Datatype rtype,MPI_Comm comm)

28) Ang MPI_Reduce function ay nagbibigay ng mga resulta ng pagbabawas ng data

sa isang proseso lamang. Upang makuha ang mga resulta ng pagbabawas ng data sa bawat isa sa mga proseso ng communicator, dapat mong gamitin ang reduction at distribution function:

int MPI_Allreduce (void *sendbuf, void *recvbuf,int count,MPI_Datatype type, MPI_Op op,MPI_Comm comm).

29) At isa pang bersyon ng pagkolekta ng data at pagpapatakbo ng pagproseso, na nagsisiguro na ang lahat ng mga resulta ng bahagyang pagbawas ay nakuha, ay maaaring makuha gamit ang function:

int MPI_Scan (void *sendbuf, void *recvbuf,int count,MPI_Datatype type, MPI_Op op,MPI_Comm comm).

Ang pangkalahatang execution diagram ng MPI_Scan function ay ipinapakita sa Fig. 4.7. Ang mga elemento ng mga natanggap na mensahe ay kumakatawan sa mga resulta ng pagproseso ng mga kaukulang elemento ng mga mensahe na ipinadala ng mga proseso, at upang makakuha ng mga resulta sa isang proseso na may ranggo i, 0≤i

30) Ang paunang halaga ng bufpos variable ay dapat mabuo bago magsimula ang packaging at pagkatapos ay itakda ng function MPI_Pack. Ang MPI_Pack function ay tinatawag na sunud-sunod upang i-pack ang lahat ng kinakailangang data.

int MPI_Pack_size (int count, MPI_Datatype type, MPI_Comm comm, int *size)

31) Pagkatapos i-pack ang lahat ng kinakailangang data, ang inihandang buffer ay maaaring gamitin sa mga function ng paglilipat ng data na may tinukoy na uri ng MPI_PACKED.

Pagkatapos makatanggap ng mensahe na may uri ng MPI_PACKED, maaaring i-unpack ang data gamit ang function na:

int MPI_Unpack (void *buf, int bufsize, int *bufpos, void *data, int count, MPI_Datatype type, MPI_Comm comm)

Complex Instruction Set Computer

CISC (English Complex instruction set computing, o English complex instruction set computer -

computer na may buong hanay ng mga tagubilin) ​​ay isang konsepto ng disenyo ng processor na nailalarawan sa pamamagitan ng sumusunod na hanay ng mga katangian:

medyo maliit na bilang ng mga pangkalahatang layunin na rehistro;

· isang malaking bilang ng mga tagubilin sa makina, ang ilan sa mga ito ay na-load na semantically katulad ng mga operator ng mga high-level na programming language at isinasagawa sa maraming mga cycle ng orasan;

· isang malaking bilang ng mga paraan ng pagtugon;

· isang malaking bilang ng mga format ng command ng iba't ibang laki ng bit;

· ang pamamayani ng two-address command format;

· pagkakaroon ng uri ng mga utos sa pagproseso rehistro-memorya.

Mga Kapintasan :

mataas na halaga ng hardware; kahirapan sa parallelization ng mga kalkulasyon.

Ang pamamaraan ng pagbuo ng sistema ng pagtuturo ng CISC ay kabaligtaran ng isa pang pamamaraan - RISC. Ang pagkakaiba sa pagitan ng mga konseptong ito ay nasa mga pamamaraan ng programming, hindi sa aktwal na arkitektura ng processor. Halos lahat ng mga modernong processor ay tumutulad sa mga set ng pagtuturo ng uri ng RISC at CISC.

Mga Pinababang Tagubilin Set Computer

Ito ay batay sa mga prinsipyo ng arkitektura ng RISC: fixed instruction format, register operations, single-cycle execution of instructions, simpleng addressing method, at isang malaking register file. Kasabay nito, mayroong ilang makabuluhang tampok na nakikilala ang arkitektura na ito mula sa mga arkitektura ng iba pang mga processor ng RISC. Kabilang dito ang: isang independiyenteng hanay ng mga rehistro para sa bawat isa sa mga actuator; pagsasama ng mga indibidwal na tagubiling tulad ng CISC sa system; kakulangan ng mekanismo ng "naantala na paglipat"; isang orihinal na paraan upang ipatupad ang mga conditional jump. Ang mga pangunahing aplikasyon ng mga arkitektura ng microprocessor ay mga server at supercomputer na may mataas na pagganap.

Ang ganitong mga computer ay batay sa isang arkitektura na naghihiwalay sa mga tagubilin sa pagproseso mula sa mga tagubilin sa memorya at binibigyang diin ang mahusay na pipelining. Ang sistema ng pagtuturo ay idinisenyo sa paraang ang pagpapatupad ng anumang pagtuturo ay tumagal ng isang maliit na bilang ng mga ikot ng makina (mas mabuti ang isang ikot ng makina). Ang lohika mismo para sa pagpapatupad ng mga utos upang mapataas ang pagganap ay nakatuon sa hardware kaysa sa pagpapatupad ng firmware. Upang gawing simple ang lohika ng pag-decode ng command, ginamit ang mga fixed-length na command

At nakapirming format.

SA Ano ang punto ng transition target address buffer technology?

SA Ang processor ay may mekanismo para sa dynamic na paghula ng direksyon ng mga transition. Sa pamamagitan nito

Ang target sa chip ay isang maliit na cache memory na tinatawag na branch target buffer (BTB), at dalawang independiyenteng pares ng instruction prefetch buffers (dalawang 32-bit buffer bawat pipeline). Iniimbak ng buffer ng target na address ng branch ang mga address ng mga tagubilin na nasa mga prefetch buffer. Ang pagpapatakbo ng mga prefetch buffer ay isinaayos sa paraang sa anumang oras, ang mga tagubilin ay kinukuha lamang sa isa sa mga buffer ng katumbas na pares. Kapag may nakitang operasyon ng sangay sa stream ng pagtuturo, ang kinakalkula na address ng sangay ay inihambing sa mga address na nakaimbak sa BTB. Kung may tugma, ang sangay ay hinuhulaan na magaganap at isa pang prefetch buffer ay pinagana at magsisimulang mag-isyu ng mga utos sa kaukulang pipeline para sa pagpapatupad. Kung mayroong mismatch, ipinapalagay na ang sangay ay hindi isasagawa at ang prefetch buffer ay hindi inililipat, na nagpapatuloy sa normal na command na nagbibigay ng order. Iniiwasan nito ang downtime ng conveyor

Mga salungatan sa istruktura at mga paraan upang mabawasan ang mga ito

Ang pinagsamang mode ng pagpapatupad ng command sa pangkalahatan ay nangangailangan ng pipelining ng mga functional unit at pagdoble ng mga mapagkukunan upang malutas ang lahat ng posibleng kumbinasyon ng mga command sa pipeline. Kung nabigo ang anumang kumbinasyon ng mga utos

tanggapin dahil sa salungatan sa mapagkukunan, kung gayon ang makina ay sinasabing may salungatan sa istruktura. Ang pinakakaraniwang halimbawa ng mga makina kung saan maaaring lumitaw ang mga salungatan sa istruktura ay ang mga makina na may mga functional na aparato na hindi ganap na nai-conveyorize.

Pag-minimize: Ipo-pause ng pipeline ang pagpapatupad ng isa sa mga command hanggang sa maging available ang kinakailangang device.

Mga salungatan sa data, paghinto ng pipeline at pagpapatupad ng mekanismo ng bypass

Ang isa sa mga kadahilanan na may malaking epekto sa pagganap ng mga sistema ng conveyor ay ang mga inter-instruction logical dependencies. Lumilitaw ang mga salungatan sa data kapag ang paggamit ng pipelining ay maaaring baguhin ang pagkakasunud-sunod ng mga pag-access sa mga operand upang ang pagkakasunud-sunod na ito ay iba sa pagkakasunud-sunod na sinusunod kapag ang mga tagubilin ay isinasagawa nang sunud-sunod sa isang hindi naka-pipelin na makina. Ang problema sa halimbawang ito ay maaaring malutas gamit ang isang medyo simpleng pamamaraan ng hardware na tinatawag na pagpapasa ng data, pag-bypass ng data, o kung minsan ay short-circuiting.

Mga salungatan sa data na nagiging sanhi ng pag-pause ng pipeline

Sa halip, kailangan namin ng karagdagang hardware, na tinatawag na pipeline interlook hardware, upang matiyak na gumagana nang tama ang halimbawa. Sa pangkalahatan, ang ganitong uri ng kagamitan ay nakakakita ng mga salungatan at naka-pause sa pipeline hangga't may salungatan. Sa kasong ito, ipo-pause ng hardware na ito ang pipeline simula sa pagtuturo na gustong gumamit ng data habang ang nakaraang pagtuturo, na ang resulta ay isang operand sa amin, ay naglalabas ng resultang iyon. Ang kagamitang ito ay nagiging sanhi ng paghinto ng linya ng produksyon o pagkakaroon ng "bubble" sa parehong paraan tulad ng sa kaso ng mga salungatan sa istruktura.

Mga buffer ng hula sa kondisyong sangay

Ang conditional branch prediction buffer ay isang maliit na memorya na natutugunan ng hindi bababa sa makabuluhang mga piraso ng address ng pagtuturo ng branch. Ang bawat cell ng memorya na ito ay naglalaman ng isang bit, na nagpapahiwatig kung ang nakaraang sangay ay naisakatuparan o hindi. Ito ang pinakasimpleng uri ng buffer ng ganitong uri. Wala itong mga tag at kapaki-pakinabang lamang para sa pagbabawas ng latency ng branch kung sakaling ang pagkaantala ay mas mahaba kaysa sa oras na kinakailangan upang kalkulahin ang halaga ng target na address ng branch. Ang branch prediction buffer ay maaaring ipatupad bilang isang maliit na nakalaang cache na ina-access ng address ng pagtuturo sa yugto ng instruction fetch ng pipeline (IF), o bilang isang pares ng mga bit na nauugnay sa bawat bloke ng cache ng pagtuturo at kinukuha sa bawat pagtuturo.

Nagkataon na nagkaroon ako ng malapit na pakikipagtagpo sa pag-aaral ng parallel computing at sa partikular na MPI. Marahil ang direksyong ito ay napaka-promising ngayon, kaya gusto kong ipakita sa mga hubbrowser ang mga pangunahing kaalaman ng prosesong ito.

Mga pangunahing prinsipyo at halimbawa
Ang pagkalkula ng exponential (e) ay gagamitin bilang isang halimbawa. Ang isa sa mga pagpipilian para sa paghahanap nito ay ang serye ng Taylor:
e^x=∑((x^n)/n!), kung saan ang pagsusuma ay nangyayari mula n=0 hanggang infinity.

Ang formula na ito ay madaling maiparallelize, dahil ang kinakailangang numero ay ang kabuuan ng mga indibidwal na termino at salamat dito, ang bawat indibidwal na processor ay maaaring magsimulang kalkulahin ang mga indibidwal na termino.

Ang bilang ng mga termino na kakalkulahin sa bawat indibidwal na processor ay depende sa haba ng pagitan n at sa magagamit na bilang ng mga processor k na maaaring lumahok sa proseso ng pagkalkula. Kaya, halimbawa, kung ang haba ng pagitan ay n=4, at limang processor (k=5) ang kasangkot sa mga kalkulasyon, kung gayon ang una hanggang ikaapat na processor ay makakatanggap ng isang termino bawat isa, at ang ikalima ay hindi gagamitin. Kung n=10 at k=5, ang bawat processor ay makakakuha ng dalawang termino para sa pagkalkula.

Sa una, ang unang processor, gamit ang MPI_Bcast broadcast function, ay nagpapadala sa iba ng halaga ng variable na tinukoy ng user n. Sa pangkalahatan, ang MPI_Bcast function ay may sumusunod na format:
int MPI_Bcast(void *buffer, int count, MPI_Datatype datatype, int root, MPI_Comm comm), kung saan ang buffer ay ang address ng buffer na may elemento, ang bilang ay ang bilang ng mga elemento, ang datatype ay ang kaukulang uri ng data sa MPI, ang ugat ay ang ranggo ng pangunahing processor na humahawak sa pagpapasa, at ang comm ay ang pangalan ng tagapagbalita.
Sa aking kaso, ang papel ng pangunahing processor, tulad ng nabanggit na, ay ang unang processor na may ranggo 0.

Matapos ang numero n ay matagumpay na naipadala, ang bawat processor ay magsisimulang kalkulahin ang mga termino nito. Upang gawin ito, sa bawat hakbang ng cycle, isang numero na katumbas ng bilang ng mga processor na kalahok sa mga kalkulasyon ay idadagdag sa numero i, na sa una ay katumbas ng ranggo ng processor. Kung ang numero i sa mga sumusunod na hakbang ay lumampas sa numerong na tinukoy ng user, ang loop execution para sa processor na iyon ay titigil.

Sa panahon ng pagpapatupad ng cycle, ang mga tuntunin ay idaragdag sa isang hiwalay na variable at, pagkatapos makumpleto, ang resultang halaga ay ipapadala sa pangunahing processor. Upang gawin ito, ang MPI_Reduce reduction operation function ay gagamitin. Sa pangkalahatan, ganito ang hitsura:
int MPI_Reduce(void *buf, void *resulta, int count, MPI_Datatype datatype, MPI_Op op, int root, MPI_Comm comm)

Pinagsasama nito ang mga elemento ng input buffer ng bawat proseso sa grupo gamit ang op operation at ibinabalik ang pinagsamang halaga sa output buffer ng root number ng proseso. Ang resulta ng naturang operasyon ay magiging isang solong halaga, kaya naman nakuha ng casting function ang pangalan nito.

Pagkatapos isagawa ang programa sa lahat ng mga processor, ang unang processor ay makakatanggap ng kabuuang kabuuan ng mga termino, na siyang magiging exponent value na kailangan namin.

Dapat pansinin na sa parehong parallel at sequential na pamamaraan para sa pagkalkula ng exponent, isang recursive function ang ginagamit upang mahanap ang factorial. Kapag nagpasya kung paano i-parallelize ang gawaing ginagampanan, isinasaalang-alang ko ang opsyon ng paghahanap ng factorial din sa iba't ibang mga processor, ngunit sa huli ang pagpipiliang ito ay itinuturing kong hindi makatwiran.

Ang pangunahing gawain ay ang paghahanap ng halaga ng exponent, at kung ang mga processor ay magsisimulang kalkulahin ang bawat factorial ng bawat termino nang hiwalay, maaari itong humantong sa eksaktong kabaligtaran na epekto, lalo na ang isang makabuluhang pagkawala sa pagganap at bilis ng pagkalkula.
Ito ay ipinaliwanag sa pamamagitan ng ang katunayan na sa kasong ito ay magkakaroon ng isang napakalaking pagkarga sa kapaligiran ng komunikasyon, na kung saan ay madalas na isang mahinang link sa parallel computing system. Kung pribado ang pagkalkula ng factorial sa bawat processor, magiging minimal ang load sa mga linya ng komunikasyon. Ang kasong ito ay matatawag na isang magandang halimbawa ng katotohanan na ang gawain ng parallelization ay dapat ding minsan ay may mga limitasyon.

Code Execution Algorithm
1. Ang halaga ng numero n ay inilipat mula sa visual shell sa programa, na pagkatapos ay ipinadala sa lahat ng mga processor gamit ang broadcast function.
2. Kapag nasimulan ang unang pangunahing processor, magsisimula ang isang timer.
3. Ang bawat processor ay nagpapatupad ng isang loop, kung saan ang increment value ay ang bilang ng mga processor sa system. Sa bawat pag-ulit ng loop, isang termino ang kinakalkula at ang kabuuan ng mga naturang termino ay iniimbak sa drobSum variable.
4. Pagkatapos makumpleto ang loop, ang bawat processor ay nagdaragdag ng drobSum value nito sa Result variable gamit ang MPI_Reduce reduction function.
5. Pagkatapos makumpleto ang mga kalkulasyon sa lahat ng mga processor, ihihinto ng unang pangunahing processor ang timer at ipinapadala ang resultang halaga ng variable ng Resulta sa stream ng output.
6. Ang halaga ng oras na sinusukat ng aming timer sa millisecond ay ipinapadala din sa output stream.
Listahan ng code
Ang programa ay nakasulat sa C++, ipagpalagay namin na ang mga argumento para sa pagpapatupad ay naipasa mula sa panlabas na shell. Ang code ay ganito ang hitsura:
#isama "mpi.h"
#isama
#isama
gamit ang namespace std;

dobleng Katotohanan(int n)
{
kung (n==0)
bumalik 1;
iba pa
ibalik n*Katotohanan(n-1);
}

int main(int argc, char *argv)
{
SetConsoleOutputCP(1251);
int n;
int myid;
int nuprocs;
int i;
int rc;
long double drob,drobSum=0,Resulta, sum;
double startwtime = 0.0;
double endwtime;

N = atoi(argv);

kung (rc= MPI_Init(&argc, &argv))
{
cout<< "Error sa pagsisimula, huminto ang pagpapatupad" << endl;
MPI_Abort(MPI_COMM_WORLD, rc);
}

MPI_Comm_size(MPI_COMM_WORLD,&numprocs);
MPI_Comm_rank(MPI_COMM_WORLD,&myid);

kung (myid == 0)
{

Startwtime = MPI_Wtime();
}
MPI_Bcast(&n, 1, MPI_INT, 0, MPI_COMM_WORLD);

para sa (i = myid; i<= n; i += numprocs)
{
drob = 1/Katotohanan(i);
drobSum += drob;
}

MPI_Reduce(&drobSum, &Resulta, 1, MPI_LONG_DOUBLE, MPI_SUM, 0, MPI_COMM_WORLD);
cout.precision(20);
kung (myid == 0)
{
cout<< Result << endl;
endwtime = MPI_Wtime();
cout<< (endwtime-startwtime)*1000 << endl;
}

MPI_Finalize();
bumalik 0;
}


* Ang source code na ito ay na-highlight gamit ang Source Code Highlighter.
Konklusyon
Kaya, nakatanggap kami ng isang simpleng programa para sa pagkalkula ng exponent gamit ang ilang mga processor nang sabay-sabay. Marahil, ang bottleneck ay nag-iimbak ng resulta mismo, dahil sa pagtaas ng bilang ng mga digit, ang pag-iimbak ng isang halaga gamit ang mga karaniwang uri ay hindi magiging mahalaga at ang lugar na ito ay nangangailangan ng elaborasyon. Marahil, ang isang medyo makatwirang solusyon ay ang pagsulat ng resulta sa isang file, bagaman, dahil sa purong pang-edukasyon na pag-andar ng halimbawang ito, hindi na kailangang mag-focus ng maraming pansin dito.

Ipinapakita ng tala na ito kung paano i-install ang MPI, ikonekta ito sa Visual Studio, at pagkatapos ay gamitin ito kasama ang mga tinukoy na parameter (bilang ng mga compute node). Gumagamit ang artikulong ito ng Visual Studio 2015, dahil... Ito ang problema ng aking mga mag-aaral (ang talang ito ay isinulat ng mga mag-aaral para sa mga mag-aaral), ngunit malamang na gagana rin ang mga tagubilin para sa iba pang mga bersyon.

Hakbang 1:
Dapat mong i-install ang HPC Pack 2008 SDK SP2 (sa iyong kaso ay maaaring mayroon nang ibang bersyon), na available sa opisyal na website ng Microsoft. Dapat tumugma ang bit capacity ng package at ng system.

Hakbang 2:
Kailangan mong i-configure ang mga landas upang gawin ito, pumunta sa tab na Debug - Properties:

"C:\Program Files\Microsoft HPC Pack 2008 SDK\Isama"

Sa patlang na Direktoryo ng Aklatan:

"C:\Program Files\Microsoft HPC Pack 2008 SDK\Lib\amd64"

Sa field ng library, kung mayroong 32-bit na bersyon, kailangan mong ilagay ang i386 sa halip na amd64.

Msmpi.lib

:

Hakbang 3:

Upang i-configure ang paglunsad, kailangan mong pumunta sa tab na Pag-debug at sa field ng Command tukuyin ang:

"C:\Program Files\Microsoft HPC Pack 2008 SDK\Bin\mpiexec.exe"

Sa field na Mga Pangangatwiran ng Utos, tukuyin, halimbawa,

N 4 $(TargetPath)

Ang numero 4 ay nagpapahiwatig ng bilang ng mga proseso.

Upang patakbuhin ang programa kailangan mong ikonekta ang library

Ang landas patungo sa proyekto ay hindi dapat maglaman ng Cyrillic. Kung mangyari ang mga error, maaari mong gamitin ang Microsoft MPI, na available sa website ng Microsoft.

Upang gawin ito, pagkatapos ng pag-install, ipasok lamang ang landas sa field ng Command ng tab na Pag-debug:

"C:\Program Files\Microsoft MPI\Bin\mpiexec.exe"

Gayundin, bago patakbuhin ang programa, huwag kalimutang ipahiwatig ang lalim nito:

Halimbawa ng pagpapatakbo ng isang programa na may MPI:

#isama #isama gamit ang namespace std; int main(int argc, char **argv) ( int rank, size; MPI_Init(&argc, &argv); MPI_Comm_size(MPI_COMM_WORLD, &size); MPI_Comm_rank(MPI_COMM_WORLD, &rank); cout<< "The number of processes: " << size << " my number is " << rank << endl; MPI_Finalize(); return 0; }

Pagpapatakbo ng programa sa 2 node:

Ang pagpapatakbo ng MPI application sa isang computing cluster ay posible lamang sa pamamagitan ng batch job processing system. Upang gawing simple ang paglulunsad at pagpila ng isang parallel na programa, isang espesyal na script ng mpirun ang ibinigay. Halimbawa, ang mpirun -np 20 ./first.exe ay tatakbo sa parallel program first.exe sa 20 processor, i.e. sa 5 node. (Ang bawat node ay may 2 dual-core processor). Kapansin-pansin na upang maglunsad ng isang executable na module na matatagpuan sa kasalukuyang direktoryo ($pwd), dapat mong tahasang tukuyin ang landas na "./". mpirun<аргументы mpirun><программа><аргументы программы>

Ang paghihiwalay sa program launch command mula sa program mismo ay nagbibigay ng flexibility, lalo na para sa networked at heterogenous na mga pagpapatupad. Ang pagkakaroon ng isang karaniwang mekanismo ng paglulunsad ay nagpapalawak din ng portability ng mga programa ng MPI ng isang hakbang pa sa mga command line at ang mga script na nagmamanipula sa kanila. Halimbawa, ang isang script para sa isang hanay ng mga programa sa pagpapatunay na nagpapatakbo ng daan-daang mga programa ay maaaring isang portable na script kung ito ay nakasulat gamit ang isang karaniwang mekanismo ng paglulunsad. Upang hindi malito ang ``standard'' command sa umiiral na isa sa pagsasanay, na hindi karaniwan at hindi portable sa mga pagpapatupad, tinukoy ng MPI ang mpiexec sa halip na mpirun.

Bagama't pinapabuti ng isang standardized na mekanismo ng paglulunsad ang kakayahang magamit ng MPI, ang hanay ng mga kapaligiran ay magkakaiba (halimbawa, maaaring wala man lang interface ng command line) na hindi maaaring i-utos ng MPI ang gayong mekanismo. Sa halip, tinutukoy ng MPI ang mpiexec run command at nagrerekomenda, ngunit hindi nangangailangan, bilang payo sa mga developer. Gayunpaman, kung ang isang pagpapatupad ay nagbibigay ng utos na tinatawag na mpiexec, dapat itong kunin ang form na inilarawan sa ibaba: mpiexec -n <программа>

magkakaroon ng kahit isang paraan para tumakbo<программу>na may inisyal na MPI_COMM_WORLD na naglalaman ng pangkat mga proseso. Ang iba pang mga argumento sa mpiexec ay maaaring nakadepende sa pagpapatupad.

Halimbawa 4.1 Pagpapatakbo ng 16 na pagkakataon ng myprog sa kasalukuyan o default na makina:

mpiexec -n 16 myprog

3. Sumulat ng isang programa para sa parallel na pagkalkula ng tiyak na integral ng function na 2*(x+2*x*x/1200.0) sa pagitan .

Paraan ng kaliwang parihaba

dobleng f(doble x)

(return 2*(x+2*x*x/1200);) // iskomyi integral

int main(int argc,char **argv)

Katayuan ng MPI_Status;

MPI_Init(&argc,&argv);

MPI_Comm_rank(MPI_COMM_WORLD,&ranggo);

MPI_Comm_size(MPI_COMM_WORLD,&size);

int n=1000,i,d; // 1000 - uzly

lumutang a=0, b=1, h=(b-a)/n,s=0,r=0; //a i b -nachalo i konec otrezka

kung (ranggo!=size-1) // schitaut vse processy, krome poslednego

( para sa (i=ranggo*d; i<(rank+1)*d; i++) { s=s+h*f(a+i*h); }

MPI_Send(&s,1,MPI_FLOAT,size-1,1,MPI_COMM_WORLD);)

( para sa (i=0; i

( MPI_Recv(&s,1,MPI_FLOAT,i,1,MPI_COMM_WORLD, &status); r+=s; ) )

MPI_Finalize();)

Surak

1. Mga arkitekturang nakabahagi at nakabahagi sa memorya.

Naipamahagi na nakabahaging memorya (DSM - Naipamahagi na Nakabahaging Memorya)

Ayon sa kaugalian, ang distributed computing ay batay sa isang message passing model, kung saan ang data ay ipinapasa mula sa processor patungo sa processor sa anyo ng mga mensahe. Ang mga remote procedure na tawag ay talagang parehong modelo (o napakalapit). Ang DSM ay isang virtual address space na ibinabahagi ng lahat ng node (processors) ng isang distributed system. Ang mga programa ay nag-a-access ng data sa DSM sa halos parehong paraan tulad ng pag-access nila ng data sa virtual memory ng mga tradisyonal na computer. Sa mga system na may DSM, gumagalaw ang data sa pagitan ng mga lokal na memorya ng iba't ibang mga computer sa parehong paraan kung paano ito gumagalaw sa pagitan ng RAM at external memory ng isang computer. Ang distributed shared memory configuration ay isang variant ng distributed memory. Dito, ang lahat ng mga node, na binubuo ng isa o higit pang mga processor na konektado sa pamamagitan ng isang SMP scheme, ay gumagamit ng isang karaniwang address space. Ang pagkakaiba sa pagitan ng pagsasaayos na ito at ng isang makina na may distributed memory ay na dito ang anumang processor ay maaaring ma-access ang anumang bahagi ng memorya. Gayunpaman, ang oras ng pag-access para sa iba't ibang mga seksyon ng memorya ay nag-iiba para sa bawat processor depende sa kung saan pisikal na matatagpuan ang seksyon sa cluster. Para sa kadahilanang ito, ang mga naturang pagsasaayos ay tinatawag ding mga makina na may hindi pare-parehong pag-access sa memorya (NUMA).

Mga pagkakaiba sa pagitan ng MPI at PVM.

Ang sistema ng PVM (Parallel Virtual Machine) ay nilikha upang pagsamahin ang ilang mga network na workstation sa isang solong virtual parallel computing machine. Ang system ay isang add-on sa operating system ng UNIX at ginagamit sa iba't ibang mga hardware platform, kabilang ang napakalaking parallel system. Ang pinakakaraniwang parallel programming system ngayon ay batay sa MPI (Message Parsing Interface). Ang ideya ng MPI sa una ay simple at halata. Ito ay nagsasangkot ng kumakatawan sa isang parallel na programa bilang isang set ng parallel na pagpapatupad ng mga proseso na nakikipag-ugnayan sa isa't isa sa panahon ng pagpapatupad ng paglipat ng data gamit ang mga pamamaraan ng komunikasyon. Binubuo nila ang library ng MPI. Gayunpaman, ang wastong pagpapatupad ng MPI upang suportahan ang mga inter-processor na komunikasyon ay napatunayang medyo mahirap. Ang pagiging kumplikado na ito ay nauugnay sa pangangailangan na makamit ang mataas na pagganap ng programa, ang pangangailangan na gumamit ng maraming mapagkukunan ng multicomputer, at, bilang isang resulta, isang malaking pagkakaiba-iba sa pagpapatupad ng mga pamamaraan ng komunikasyon depende sa mode ng pagproseso ng data.