CAPITOLO 5 VALIDAZIONE SPERIMENTALE
5.1 P REMESSE
5.2.2 Sperimentazione remota
Il caso remoto è più complesso poiché entrano molte dinamiche in gioco che avremo modo di sviscerare lungo la sperimentazione.
La risoluzione del problema dato aveva come discriminante il numero di valori as- segnati ad ogni task prima che quest’ultimo potesse essere spedito al corrispondente worker. La dimensionalità del task diventa uno dei fattori critici dell’applicativo, da cui prescindono i parametri di valutazione delle performance, sia nel campo locale dove la soluzione ottimale prevedeva di assegnare a ciascuno di essi NW+1 elementi alla volta, ma ancora di più nel campo remoto. Qui, poiché i vari task devono viaggiare in rete, per aumentare la granularità si è deciso di aumentare le dimensioni di ognuno ottenendo due possibili scenari per il testing:
Nel primo avremo task di dimensione variabile funzione del numero di worker attivi come nel caso locale ma di dimensione maggiorata.
Nel secondo andiamo a valutare le performance sotto la premessa di task di dimensioni prefissate. Anche se questo soffre dello stesso problema ana- lizzato nel caso sequenziale, ossia l’aumento delle performance tende a stagnare quando raggiungiamo un certo numero di worker.
Oppure possiamo usare la versione con la MAP. In questo caso si creano tanti task quanti sono il numero di workerNode disponibili così da minimiz- zare il più possibile i tempi di overhead relativi alla trasmissione del task verso ciascun nodo remoto. Ovviamente è meglio spedire un task di 100Kb che 100 task di 1Kb ciascuno poiché i tempi necessari a compattare e crea- re il task (serializzazione) per essere avviato sulla rete e a scompattarlo sul nodo remoto si vanno a sommare ai normali tempi di overhead introdotti dalla parallelizzazione.
Cerchiamo di capire qual è l’approccio migliore che possiamo seguire e quali sono i vantaggi e svantaggi di ognuno.
Cominciamo il primo test considerando task di dimensioni variabili, ecco le carat- teristiche:
Client: [N5] OTTAVINAREALE: 8 core fisici
Nodi Server: [N1] TITANIC: 24 core fisici
[N2] PIANOSA: 16 core fisici Parametri Input 40000777787779 MinNW 1 MaxNW 48 Fast true Version 1 Mode “remote”
Dimensione task Variabile = NW*25
Risultati: nw 𝑻𝒑𝒏𝒘 𝑺𝒑𝒏𝒘 𝑺𝒄𝒏𝒘 𝑬𝒇𝒏𝒘 𝑻𝒔 = 𝟗𝟔𝟗𝟐𝟗 𝒎𝒔 3 [1+1+1] 45688 2,121541762 2,252232534 0,707180587 6 [2+2+2] 22320 4,342697133 4,610215054 0,723782855 12 [4+4+4] 11808 8,208756775 8,714430894 0,684063065 24 [8+8+8] 5929 16,34828808 17,3553719 0,68117867 48 [16+16+16] 4741 20,44484286 21,7042818 0,425934226
Nonostante i tempi di overhead introdotti dalla parallelizzazione e quelli relativi al- la sommissione di ciascun task prima sulla rete e poi a ciascun nodo remoto, l’efficienza parallela risulta essere valida fino a quando non otteniamo un tempo di completamento troppo basso per nascondere i tempi di comunicazione, ragion per cui bisogna provare con interi più grandi. Il principale problema nella computazione remota riguarda il fatto che ciascun server, a fronte del medesimo task da eseguire, impiega un tempo di esecu- zione differente in relazione alla propria velocità di clock: questo problema, accentuato dalla politica ROUND-ROBIN di sottomissione e smistamento dei task fra server, non fa al- tro che generare uno sbilanciamento nella valutazione delle performance parallele. Que-
sto deficit viene alleviato in questo esperimento dalla dimensione giusta e variabile dei task.
Secondo esperimento con un intero più grande:
Client: [N5] OTTAVINAREALE: 8 core fisici
Nodi Server: [N1] TITANIC: 24 core fisici
[N4] PIANOSAU: 16 core fisici [N2] PIANOSA: 16 core fisici
Parametri Input 4000077776487779 MinNW 1 MaxNW 48 Fast true Version 1 Mode “remote”
Dimensione task Variabile = NW*25
Risultati: nw 𝑻𝒑𝒏𝒘 𝑺𝒑𝒏𝒘 𝑺𝒄𝒏𝒘 𝑬𝒇𝒏𝒘 𝑻𝒔 = 𝟗𝟑𝟖𝟑𝟓𝟑 𝒎𝒔 1 967902 0,969471083 1 0,969471083 3 451619 2,077753593 2,143182638 0,692584531 6 200176 4,687639877 4,835254976 0,781273313 12 96057 9,768710245 10,07632968 0,814059187 24 48464 19,36185622 19,97156652 0,806744009 48 37044 25,33076882 26,12844185 0,52772435
Le prestazioni parallele confermano che l’approccio attuale è quello maggiormen- te adatto ad un cluster formato da nodi eterogenei per velocità di clock, con un’efficienza al di sotto della soglia accettata solo alla fine con NW=48. Si noti in questo caso come da
sperimentazioni parallele alla medesima, incrementando in maniera super lineare la di- mensione dei task generati in funzione di NW (e non lineare) si ottengono risultati ancora migliori, quasi ideali.
Il medesimo esperimento condotto con task di dimensioni fisse vanta risultati mol- to simili considerando però una task size molto grande (ad esempio 1000 unità). Si è nota- to come in questa tipologia di sperimentazioni si assiste ad uno sprint iniziale delle per- formance parallele anche superiore al caso precedente per poi stagnare su un valore co- stante (ci si riferisce al tempo di completamento), più grandi sono i task più lentamente ciò accade ma in maniera inevitabile. Vediamo un esempio:
Client: [N5] OTTAVINAREALE: 8 core fisici
Nodi Server: [N1] TITANIC: 24 core fisici
[N4] PIANOSAU: 16 core fisici [N2] PIANOSA: 16 core fisici
Parametri Input 4000077776487779 MinNW 1 MaxNW 48 Fast true Version 1 Mode “remote”
Dimensione task Fissa = 100
nw 𝑻𝒑𝒏𝒘 𝑺𝒑𝒏𝒘 𝑺𝒄𝒏𝒘 𝑬𝒇𝒏𝒘 𝑻𝒔 = 𝟗𝟑𝟖𝟑𝟓𝟑 𝒎𝒔 1 967902 0,969471083 1 0,969471083 3 419939 2,234498344 2,304863325 0,744832781 6 217357 4,317105039 4,453051892 0,719517507 12 132369 7,0889181 7,312150126 0,590743175 24 121603 7,716528375 7,959524025 0,321522016 48 120720 7,77297051 8,017743539 0,161936886
Come volevasi dimostrare. D’altro canto la sperimentazione condotta su una sud- divisione dei task nel numero di worker disponibili è stata fallimentare con prestazioni molto al di sotto di quelle ideali a causa, presumibilmente, dello sbilanciamento indotto dall’utilizzo di nodi eterogenei. E’ ovvio che in questo caso la computazione termina quando il nodo più lento (in termini di velocità di clock) ha terminato l’esecuzione dei task
ad esso associati. I risultati non vengono rappresentati ma solo descritti per una questio- ne di brevità.
Qualche considerazione finale sulla base dei dati raccolti che mostrano le criticità e le caratteristiche del modulo Server di Muskel 2:
1) Se i task sono troppo piccoli, a fronte di un numero elevato di worker, si hanno due problemi: 1] gli overhead necessari alla trasmissione dei task sui nodi remoti aumentano inutilmente (tempo di emissione maggiore di quello di esecuzione), 2] la dimensione ristretta dei task, il loro intrinseco sbilanciamento (data la natura del problema) e la tecnica di emissione usata (round robin) fanno si che i worker non risultano essere sempre tutti in esecuzione ergo non si raggiunge, o si rag- giunge in modo altalenante, lo steady state: tutto il tempo perso rende impossibi- le il raggiungimento dello speed-up ideale.
2) Se i task sono troppo grandi il primo problema precedente non si verifica ma risul- ta forse ancora più grave il secondo problema poiché essendo di dimensioni mag- giori la possibile distanza di durata fra due task cresce proporzionalmente e quindi i tempi persi aumentano (come si può notare dai test comunque un incremento della velocità di esecuzione sussiste ma non quella ideale).
3) Da tenere in considerazione anche che quando aumentiamo il numero di thread aumentano i costi di emissione poiché abbiamo più worker coi quali comunicare i vari task quindi è ovvio che aumentare i costi di esecuzione (task più grandi) giova al raggiungimento dello steady state; non riesco a mantenere lo speed-up ideale per sempre perché tutte queste problematiche non si escludono a vicenda.
Siccome i tempi di emissione sono sempre bassi non c’è il rischio che un worker al proprio turno non veda arrivare il prossimo task in tempo quindi il collo di bottiglia a mio avviso è causato dallo sbilanciamento dei task, cosa che potrebbe essere risolta con la tecnica di emissione ON DEMAND. Poi ovviamente lo scaling ideale nel caso remoto deve sottostare anche alla velocità di connessione e a tempi di overhead che non possono es- sere evitati come la gestione dei nodi remoti, la serializzazione/deserializzazione dei task per la loro trasmissione, i costi di collezione dei dati sul calcolatore master e così via.
5.3 Risoluzione di sistemi lineari
Vediamo quali sono i parametri di ingresso per l’esecuzione del secondo applicati- vo:
Parametri Tipo di dato Valori ammissibili
Dimension (dimensione della matrice quadrata A nonché del vettore dei termini noti b e del vettore soluzione x)
<Integer>
MinNW (il testing viene effettuato in parallelo considerando progressivamente un numero di worker crescente contenuto nel range [MinNW,MaxNW])
<Integer> Default: 1
MaxNW <Integer> Default: massimo # CPU
Fast (il valore di verità di questa variabile prescinde se conside- rare nel testing un numero di worker progressivamente poten- za di 2 oppure no)
<Boolean> Default: true
Version (indica la versione parallela su cui condurre il testing fra quelle disponibili viste nel paragrafo 3.3)
<Integer> [1: row-based, 2: col- umn-based, 3: column translated-based]
Mode (indica al compilatore dove condurre il testing) <String> [“local”: il test viene fat- to su un unico nodo, “remote”: sul cluster]
Dal paragrafo 3.3 ricordiamo come la soluzione del problema fosse di natura itera- tiva volta alla trasformazione della matrice aggiunta [A|I] nella matrice [I|A-1] così da po- ter risolvere il sistema più agevolmente. Il procedimento iterativo si componeva di N (pa- rametro Dimension) cicli in ognuno dei quali andava opportunamente modificata una sot- tomatrice B con numero di righe decrescenti. Ebbene proprio in ciascun ciclo avveniva il
tentativo di parallelizzazione suddividendo equamente le righe o le colonne di B fra i wor- ker disponibili. Erano state generate tre versioni parallele:
1. La prima effettuava la parallelizzazione per righe 2. Nella seconda la parallelizzazione avveniva per colonne
3. Quindi la terza avveniva ancora sulle colonne ma questa volta trasposte così da divenire righe, ottenendo un bilanciamento fra task migliore.
5.3.1 Sperimentazione locale
Nel primo esperimento andiamo a considerare uno specifico istanziamento dell’applicazione implementato sulle tre versioni parallele al fine di coglierne le differenze in fatto di performance. Comando ese- guito da termi- nale mvn exec:java -Dexec.mainClass= "it.reactive.muskel.examples.SolvingSystem" -Dexec.args="500 1 32 True 1 local"
Nodo usato [N2] PIANOSA: 16 core fisici
Parametri Dimension 500 MinNW 2 MaxNW 32 Fast true Version 1 Mode “local”
Dalla prima versione otteniamo i seguenti risultati:
nw 𝑻𝒑𝒏𝒘 𝑺𝒑𝒏𝒘 𝑺𝒄𝒏𝒘 𝑬𝒇𝒏𝒘 𝑻𝒔 = 𝟏𝟗𝟕𝟓𝟗𝟓 𝒎𝒔 1 202936 0,973681 1,000000 0,973681 2 102889 1,920468 1,972378 0,960234 4 78915 2,503897 2,571577 0,625974 8 46052 4,290693 4,406671 0,536337 16 44246 4,465827 4,586539 0,279114 32 42275 4,674039 4,800378 0,146064
Tralasciando per un attimo l’efficienza vediamo come i tempi di esecuzione paral- lela scalano nella misura ideale fino a NW=4, da quel momento in poi il miglioramento ri- mane pressoché costante. Questo è causato dalla problematica già esposta nel paragrafo 4.3 ossia i tempi che riusciamo a parallelizzare in ciascun ciclo iterativo tendono a dimi- nuire man mano che l’iterazione procede, d’altro canto i tempi di overhead introdotti dal- la parallelizzazione in ogni ciclo rimangono costanti. Ciò causa una progressiva diminuzio- ne della granularità e il tutto si palesa nei risultati mostrati. Ora tirando in ballo l’efficienza possiamo dire che nonostante tutto l’algoritmo ha delle performance parallele accettabili.
Vediamo ora cosa succede usando il secondo metodo:
Comando ese- guito da termi- nale mvn exec:java -Dexec.mainClass= "it.reactive.muskel.examples.SolvingSystem" -Dexec.args="500 1 32 True 2 local"
Nodo usato [N2] PIANOSA: 16 core fisici
Parametri Dimension 500 MinNW 2 MaxNW 32 Fast true Version 2 Mode “local” nw 𝑻𝒑𝒏𝒘 𝑺𝒑𝒏𝒘 𝑺𝒄𝒏𝒘 𝑬𝒇𝒏𝒘 𝑻𝒔 = 𝟐𝟗𝟓𝟑𝟒𝟐 𝒎𝒔 1 338110 0,873509 1 0,873509 2 178414 1,655375 1,895087 0,827687 4 89083 3,315358 3,795449 0,828839 8 50235 5,879208 6,730566 0,734901 16 40146 7,356698 8,42201 0,459794 32 30562 9,6637 11,063085 0,301991
Risultati:
Il secondo metodo scala allo stesso modo del precedente, tuttavia come prean- nunciato, a parità di dimensioni matriciali il tempo di esecuzione parallelo e seriale è maggiore. Questo accade poiché in ogni ciclo iterativo tentiamo di modificare la sottoma- trice B ripartendo, fra i worker disponibili, le colonne piuttosto che le righe, contravve- nendo alla natura con cui Java itera sugli array multidimensionali.
Vediamo infine il terzo metodo che ottimizza la procedura riducendo ulteriormen- te la serial fraction nella parallelizzazione di ogni ciclo iterativo, procedendo sì per colon- ne, nella ripartizione fra i vari worker, (in questo modo otteniamo task più bilanciati) ma traslate così da seguire la natura di Java.
Comando ese- guito da termi- nale mvn exec:java -Dexec.mainClass= "it.reactive.muskel.examples.SolvingSystem" -Dexec.args="500 1 32 True 3 local"
Nodo usato [N2] PIANOSA: 16 core fisici
Parametri Dimension 500 MinNW 2 MaxNW 32 Fast true Version 3 Mode “local” nw 𝑻𝒑𝒏𝒘 𝑺𝒑𝒏𝒘 𝑺𝒄𝒏𝒘 𝑬𝒇𝒏𝒘 𝑻𝒔 = 𝟐𝟏𝟒𝟒𝟎𝟖 𝒎𝒔 1 248289 0,863542 1,000000 0,863542 2 131793 1,626854 1,883932 0,813427 4 65421 3,277357 3,795249 0,819339
8 35733 6,000280 6,948451 0,750035 16 28515 7,519130 8,707312 0,469946 32 22643 9,469063 10,965376 0,295908
I parametri alla fine risultano più che soddisfacenti considerando che l’algoritmo contiene pur sempre due loop sequenziali di dimensioni N, la cui computazione interna si è cercato di parallelizzare al meglio possibile. Inoltre esso deve calcolare la trasposizione della matrice A-1, nonché la matrice identica I iniziale più altre componenti seriali che con- corrono all’impossibilità di ridurre oltre un certo limite il tempo di esecuzione anche a fronte di un numero molto elevato di worker, semplicemente perché il loro tempo di computazione non può essere abbattuto. Inoltre come al solito maggiore è il numero di worker disponibili più è difficile raggiungere lo steady state quando il mainloop lavora con un N molto alto impedendo sempre più il raggiungimento dello speed-up ideale. I rapporti aumentano leggermente se imposto N=1000. Per matrici molto piccole invece, come no- to, i costi di overhead superano quelli di computazione rendendo vana, se non contro- producente, la parallelizzazione dell’algoritmo e lo sfruttamento di un numero sempre maggiore di thread.
Quando abbiamo problemi del genere in cui andiamo a ripartire un insieme di- screto di N elementi su un numero di worker crescenti a risentirne maggiormente è la scalabilità e ciò si ripercuote anche sull’efficienza parallela e gli altri parametri, come si nota dal grafico. Aumentare le risorse non produce un aumento delle prestazioni rima- nendo N costante. Questo vale anche per l’applicativo 4 e 5 nei quali la procedura di pa- rallelizzazione è la medesima.
Infine viene mostrato un grafico riassuntivo dei costi di computazione delle tre versioni parallele proposte, dai quali si evince come il più bilanciato ed efficiente sia il me- todo finale.
5.3.2 Sperimentazione remota
A causa della propria natura iterativa non conviene parallelizzare in remoto l’algoritmo proposto: sappiamo infatti che in tale ambito affinché possiamo avere qualche vantaggio dalla parallelizzazione i task da inviare ai vari nodi remoti devono essere suffi- cientemente grandi in maniera tale che il tempo necessario a computarli sia superiore al tempo necessario a trasferire la serializzazione del task sul nodo stesso. Nel caso dell’approccio in questione sappiamo che possiamo parallelizzare solamente ogni singola iterazione del main loop: questa parallelizzazione è fatta nell’ultimo metodo, sulle colon- ne N della matrice. Abbiamo visto, in locale, come ripartendo equamente le colonne fra i vari processori disponibili, affinché su ognuna di esse si realizzasse la medesima computa- zione, portasse un vantaggio in fatto di parametri paralleli. Tutto ciò non funziona nel ca- so remoto poiché se ripartiamo allo stesso modo le colonne (in ogni passo iterativo) fra i vari worker remoti, a meno che non abbiamo a disposizione una matrice enorme (N>10000), è più il tempo necessario a trasferire ogni task ai vari worker che il tempo ef- fettivo di computazione di quest’ultimi. Vari esperimenti hanno dimostrato come il tempo
di esecuzione (ad esempio con N=2000) sia molto più basso se, ad ogni passo iterativo, spediamo la totalità delle colonne su un unico worker remoto piuttosto che se frastaglia- mo tali colonne ergo task fra più nodi remoti. In altre parole maggiore è il numero di task che dobbiamo spedire sulla rete maggiore è l’overhead di computazione, ma questo non è tutto poiché meno colonne contiene ciascun task più la sua computazione sul nodo re- moto sarà rapida ottenendo un rapporto overhead/computazione sempre più piccolo. L’approccio migliore consisterebbe nel rendere i task sempre più grandi al crescere dei worker disponibili ma ciò ci viene impedito dalla natura iterativa dell’algoritmo e dalla scelta implementativa che obbliga una siffatta parallelizzazione: essa ci consente di paral- lelizzare al più N colonne, ad ogni passaggio, della stessa matrice sulle quali andiamo ad eseguire operazioni banali e non affatto onerose. Se potessimo parallelizzare a livello di fasi iterative piuttosto che all’interno di ognuna di esse allora l’approccio remoto potreb- be ancora essere usato. Detto ciò il tempo migliore di esecuzione si ottiene quando usia- mo un unico worker ma comunque resta molto superiore al tempo di esecuzione della medesima istanza in locale (ad esempio per N=200 e NW=1 il metodo impiega 6500 ms), tutto questo tempo è per la stragrande maggioranza tempo di overhead necessario a se- rializzare, spedire e deserializzare 200 task (uno per ogni iterazione del loop che va da 0 a N) + altri 200 (generati dalla back phase) sulla rete, a fronte di un tempo di computazione degli stessi irrisorio. Per tutti questi motivi la sperimentazione remota non viene mostra- ta.
5.4 K-nearest neighbor
Vediamo innanzitutto, come nei casi precedenti, quali sono l’insieme dei parame- tri necessari ad eseguire l’algoritmo risolvente.
Parametri Tipo di dato Valori ammissibili
KValue (granularità della classificazione di un nuovo punto sul- la base dello spazio multidimensionale originato dal dataset)
<Integer> Intero piccolo positivo
MinNW (il testing viene effettuato in parallelo considerando progressivamente un numero di worker crescente contenuto nel range [MinNW,MaxNW])
<Integer> Default: 1
Fast (il valore di verità di questa variabile prescinde se conside- rare nel testing un numero di worker progressivamente poten- za di 2 oppure no)
<Boolean> Default: true
Version (indica la versione parallela su cui condurre il testing fra quelle disponibili viste nel paragrafo 3.4)
<Integer> [1: map-based, 2: farm- based]
Mode (indica al compilatore dove condurre il testing) <String> [“local”: il test viene fat- to su un unico nodo, “remote”: sul cluster]
Dataset (Full path del file contenente il dataset correttamente classificato: per ipotesi si lavora su uno spazio dimensionale di numeri REALI)
<String>
Metric (Metrica usata nel calcolo della distanza fra due punti nello spazio dimensionale considerato)
<String> [“Euclidean”: metrica euclidea…]
RemoteDataset (Questo parametro viene usato solo nel campo remoto e indica il full path, si presume generico, della copia del dataset generata sui nodi server)
<String>
Come è facile ricordare questo problema prevedeva di classificare un nuovo punto appartenente ad uno spazio dimensionale di numeri reali in funzione della classe massi- mamente presente fra i k punti limitrofi all’input. Venivano fornite due diverse implemen- tazioni parallele:
1. La prima nella quale si usa concettualmente lo skeleton MAP 2. La seconda dove invece si usa una FARM.
5.4.1 Sperimentazione locale
Cominciamo con un raffronto fra le due metodologie usate; Per quanto riguarda il dataset considerato esso contiene più di 7000 sequenze di DNA distribuite in uno spazio vettoriale di numeri interi a 180 dimensioni. Il punto da classificare è una lista di zeri e uni ottenuto casualmente da un apposito algoritmo. Una siffatta scelta computazionale, che ovviamente vale per ogni altro esperimento su questo applicativo, non corrompe mini- mamente la valutazione delle prestazioni.
Comando ese-
guito da termi- nale
mvn exec:java -
Dexec.mainClass="it.reactive.muskel.examples.Knn" - Dexec.args="15 1 32 True local ./dna_train euclidian 1/2"
Nodo usato [N1] TITANIC: 24 core fisici Parametri KValue 15 MinNW 1 MaxNW 32 Fast true Version 1/2 Mode “local” Dataset ./dna_train Metric euclidian RemoteDataset “”
Soluzione con la MAP:
nw 𝑻𝒑𝒏𝒘 𝑺𝒑𝒏𝒘 𝑺𝒄𝒏𝒘 𝑬𝒇𝒏𝒘 𝑻𝒔 = 𝟓𝟔𝟎𝟕𝟕 𝒎𝒔 1 53682 1,048415 1,000000 1,048415 2 27367 2,056528 1,961560 1,028264 4 14405 3,907046 3,726623 0,976762 8 7692 7,316823 6,978939 0,914603 16 4527 12,432295 11,858184 0,777018 32 3496 16,098684 15,355263 0,503084
Caso con la FARM:
nw 𝑻𝒑𝒏𝒘 𝑺𝒑𝒏𝒘 𝑺𝒄𝒏𝒘 𝑬𝒇𝒏𝒘 𝑻𝒔 = 𝟓𝟔𝟐𝟖𝟏 𝒎𝒔 1 53682 1,048415 1,000000 1,048415 2 27367 2,056528 1,961560 1,028264 4 14405 3,907046 3,726623 0,976762 8 7692 7,316823 6,978939 0,914603 16 4527 12,432295 11,858184 0,777018 32 3496 16,098684 15,355263 0,503084
Come possiamo notare ambo le metodologie ottengono risultati pressoché identi- ci ma soprattutto ottimi, gli algoritmi scalano alla perfezione ottenendo dei parametri di efficienza parallela al di sotto del 75% solo con NW=32, cosa di per sé normale dato che stiamo lavorando su un’architettura dotata di soli 24 core. Molto più interessante risulte- rà essere la sperimentazione remota volta a comprendere la validità dell’algoritmo a fron- te di un numero molto superiore di unità logiche disponibili.
Vediamo un esperimento più complesso condotto su un’altra architettura con K=20 e con un dataset contenente più di 40000 valori distribuiti in uno spazio 10 – di- mensionale di numeri reali. Il punto da classificare ancora una volta è ottenuto in maniera casuale. Vediamo l’input nel dettaglio:
Comando ese-
guito da termi- nale
mvn exec:java -
Dexec.mainClass="it.reactive.muskel.examples.Knn" - Dexec.args="20 1 32 True 1 local ./vowel_train euclidian"
Nodo usato [N2] PIANOSA: 16 core fisici
Parametri KValue 20 MinNW 1 MaxNW 32 Fast true Version 1 Mode “local” Dataset ./vowel_train Metric euclidian RemoteDataset “” Ecco i risultati: nw 𝑻𝒑𝒏𝒘 𝑺𝒑𝒏𝒘 𝑺𝒄𝒏𝒘 𝑬𝒇𝒏𝒘 𝑻𝒔 = 𝟐𝟕𝟎𝟓𝟔𝟒 𝒎𝒔 1 267771 1,010431 1,000000 1,010431 2 136153 1,987206 1,966692 0,993603 4 68533 3,947937 3,907183 0,986984 8 35033 7,723118 7,643393 0,965390 16 21754 12,437437 12,309047 0,777340 32 18472 14,647250 14,496048 0,457727
Le proporzioni ottenute nell’esperimento precedente vengono mantenute in quel- lo attuale, esiste un leggero calo delle performance con NW=16, sebbene minimale indica come l’aumento dei costi di gestione di un più grande numero di thread e la componente seriale non abbattuta completamente, degradino, anche se di poco, le prestazioni. Poi al solito l’efficienza cala con NW=32 dato che N2 possiede sì 32 core, ma logici, quelli veri sono solo 16.
5.4.2 Sperimentazione remota
Nel caso della sperimentazione remota la miglior opzione consiste nel ripartire equamente il dataset in questione nel numero di workerNode a cui facciamo riferimento. Come già anticipato ad ogni nodo server viene fornita una copia del training set che verrà da esso utilizzata in maniera totalmente esclusiva senza il rischio di side effect. Vediamo i risultati dell’esperimento condotto su un cluster composto da due nodi.
Client: [N5] OTTAVINAREALE: 8 core fisici
Nodi Server: [N1] TITANIC: 24 core fisici
[N2] PIANOSA: 16 core fisici
Parametri KValue 20 MinNW 1 MaxNW 32 Fast true Version 1 Mode “remote” Dataset ./vowel_test