hadoop analyzerjr
TRANSCRIPT
Universita degli studi di salerno
Progetto di Sistemi Operativi Avanzati
2014-2015
Hadoop Analyzer JR
Autori:Amedeo LeoAlessio PetrozzielloSimone Romano
DocenteGiuseppe Cattaneo
Supervisore:Gianluca Roscigno
February 7, 2015
2
Contents
Introduzione 5
Dati da analizzare 6
1.1 Analisi dstat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.1.1 Client/server dstat . . . . . . . . . . . . . . . . . . . . . . 6
1.1.2 Analisi file ’.csv’ . . . . . . . . . . . . . . . . . . . . . . . 6
1.2 Analisi log Hadoop . . . . . . . . . . . . . . . . . . . . . . . . . . 8
1.3 Profiler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
Output 10
2.1 Java . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.1.1 Web page . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.1.2 Warning . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.1.3 Profiler . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.2 R . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.2.1 Dati formattati excel . . . . . . . . . . . . . . . . . . . . . 17
2.2.2 SpeedUp ed efficienza . . . . . . . . . . . . . . . . . . . . 17
Manuale utente 19
Caso di studio 28
4.1 Configurazione cluster . . . . . . . . . . . . . . . . . . . . . . . . 28
4.1.1 Yarn-site.xml . . . . . . . . . . . . . . . . . . . . . . . . . 28
4.2 hdfs-site.xml . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
4.3 WordCount . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
4.4 Input . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
4.4.1 Specifiche delle macchine . . . . . . . . . . . . . . . . . . 39
4.5 Test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
4.6 Risultati . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
4.6.1 Analisi Dstat . . . . . . . . . . . . . . . . . . . . . . . . . 40
4.6.2 Analisi Log Hadoop . . . . . . . . . . . . . . . . . . . . . 42
4.7 Confronto esperimenti . . . . . . . . . . . . . . . . . . . . . . . . 46
3
4 CONTENTS
Appendice 495.1 Java code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
5.1.1 Parser csv . . . . . . . . . . . . . . . . . . . . . . . . . . . 495.1.2 ChartGenerator . . . . . . . . . . . . . . . . . . . . . . . . 545.1.3 JFreeChartGenerator . . . . . . . . . . . . . . . . . . . . . 67
5.2 R code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 705.2.1 chart generator.R . . . . . . . . . . . . . . . . . . . . . . . 705.2.2 excel.R . . . . . . . . . . . . . . . . . . . . . . . . . . . . 855.2.3 graphHadoopGenerator.R . . . . . . . . . . . . . . . . . . 945.2.4 speedup.R . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
5.3 C code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1005.3.1 client.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1005.3.2 server.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1045.3.3 AllSlaves.c . . . . . . . . . . . . . . . . . . . . . . . . . . 109
Afterword 111
Introduzione
Lo studio proposto punta a realizzare uno strumento per analizzare il funziona-mento di un cluster che utilizza il framework Hadoop [9]. Diversi sono gli inputche il tool puo analizzare a seconda delle esigenze. In particolare analizza iseguenti tipi di file:
• ’.csv’ generati con dstat [6]
• ’.txt’ generati con il profiler java [7]
• ’.man’ che raccolgono i log generati dal framework Hadoop
Il tool genera grafici rappresentanti l’andamento di ciascuna macchina del clus-ter. I file ’.csv’ possono essere recuperati installando sul master e sugli slaverispettivamente un client e vari server appositamente realizzati. A tale scopoe possibile utilizzare librerie java o R[8]. In base alla modalita di generazioneselezionata dall’utente (R, java) e possibile istruire il tool al fine di generareeventuali ’warning charts’ che danno suggerimenti per utilizzare il cluster inmaniera pi efficiente. E possibile inoltre visualizzare una timeline dei task svoltidal framework Hadoop, generabile dando in input i file ’.man’ generati con unoscript python appositamente realizzato. L’output realizzato varia a secondadelle librerie selezionate dall’utente (R o java) e puo essere:
• Pagina web - java
• file pdf - R
I capitoli successivi analizzeranno in dettaglio quanto realizzato.
5
Dati da analizzare
Introduzione
In questa sezione saranno analizzati i vari dati presi in input dal tool e il relativooutput generato dal tool.
1.1 Analisi dstat
Il tool analizza dunque file ’.csv’ generati con dstat[6] su ciascuno slave e sulmaster del cluster.
1.1.1 Client/server dstat
Il tool prevede la possibilita di raccogliere, da un solo terminale, di lanciare, inmaniera parallela, il software dstat su tutte le macchine necessarie del cluster.In particolare, sono stati sviluppati un client e un server in linguaggio C: ilserver e stato settato in avvio automatico sugli slave, il quale attende su unaspecifica porta (ad esempio 8080) le richieste effettuate dal master; il client, inesecuzione sul master, puo decidere quando avviare o terminare il software dstatsugli slave.
1.1.2 Analisi file ’.csv’
I file ’.csv’ recuperati con l’applicazione client/server ’c’ possono essere dunqueanalizzati con ’Hadoop Analyzer JR’. Come anticipato cio puo essere fatto uti-lizzando due diverse librerie:
• Java (Google-JfreeChart)
• R
Alcune delle opzioni selezionabili (vedi 2.2.2) variano a seconda della libreriautilizzata.
6
1.1. ANALISI DSTAT 7
Figura 1.1: Esempio di file generato con dstat
Figura 1.2: Esempio di file preso in input dal parser
Analisi ’.csv’ java
Al fine di interpretare i file ’.csv’ generati con ’dstat’ e stato utilizzato un parser’.csv’ [3]. La classe java che si occupa di analizzare tali file e mostrata in 5.1.1.Tale classe analizza il file ’.csv’ e:
• ripulisce il file eliminando elementi superflui che danno problemi con ilparser
• ricava in automatico l’intervallo con cui ’dstat’ e stato lanciato sullemacchine del cluster
Il file che prende in input e mostrato in figura 1.1. Tale file viene dunque ripulitoper poterne effettuare il parsing. Il nuovo file e mostrato in figura 1.2. Sulnuovo file generato e dunque possibile andare ad estrarre di volta in volta lecolonne desiderate per ricavare informazioni necessarie per generare i grafici.
Analisi ’.csv’ R
E stato creato uno script in linguaggio R per la creazione dei grafici relativiall’analisi dei dati di dstat. Lo script prende in input un file di configurazionecontenente diversi campi: - Tempo espresso in secondi, minuti o ore, relativoall ’asse delle ascisse per la timeline. - Un valore per definire la scelta dellacolorazione dei grafici (in scala di grigi o colorato). - Un valore per definire la
8 CONTENTS
scelta delle linee (continue o tratteggiate). - Un valore per stabilire la presenzadel titolo nei grafici. - Un valore per scegliere come generare i grafici (un singolopdf o molteplici). - Un valore per scegliere la tipologia dei grafici (’single’,’average’, ’all nodes’). - Un valore per determinare la scelta dei valori dellaCPU desiderati (’usr’, ’sys’, ’idl’, ’wai’, ’hiq’, ’siq’). - Un valore per determinarela scelta dei valori della RAM desiderati (’used’, ’buff’, ’cach’, ’free’). - Unvalore per determinare l’upperbound della RAM desiderato. - Un valore perdeterminare la scelta di visualizzazione dell’I/O (su un solo grafico o separati).- Un valore per determinare la scelta di visualizzazione del paging, in e out (su unsolo grafico o separati). - Un valore per determinare la scelta di visualizzazionedell’utilizzo della rete, espresso in MB/s, in e out (su un solo grafico o separati).- Un valore per determinare la scelta di visualizzazione dell’utilizzo della rete,espresso in numero di pacchetti, ricevuti o inviati (su un solo grafico o separati).Attraverso il settaggio dei vari parametri, si puo avere un’ampia scelta sullagenerazione dei grafici. Dato un file dstat in formato csv, ne viene generatoun dataframe su cui, estrapolate le informazioni necessarie, saranno creati idiversi grafici. La timeline e espressa in secondi, minuti o ore a seconda dellascelta dell’utente; il delay tra le misurazioni e automaticamente riconosciutodallo script.
1.2 Analisi log Hadoop
Una parte fondamentale del nostro tool e l’analisi dei log generati dal framework.I log devono essere recuperati, in primo luogo, dall’Hadoop MapReduce HistoryServer. Le REST API dell’History Server permettono all’utente di ottenere lostatus delle applicazioni terminate. Tali risorse forniscono informazioni generalisull’History Server; attraverso delle URI e possibile ottenere dati partendo daun id specificato, Sono supportate operazioni HTTP come GET. Le rispostepossono essere in formato JSON o XML. Per recuperare i file di log, e statocreato uno script utilizzando il linguaggio Python; in particolare, dato in inputl’id del job, restituisce in output una cartella contenente solo i file utili pergenerare il grafico, in modo da evitare all’utente l’onere di scaricare a mano imolteplici file restituiti dall’History Server.
Esempio: Con l’URL http://localhost:19888/ws/v1/history/mapreduce/
jobs/job\_1419686689081\_0001 si ottengono varie informazioni sul job in in-put, come il ”submitTime”, utile per essere considerato come il tempo 0 del jobHadoop da inserire nel grafico. Con l’URL http://localhost:19888/ws/v1/
history/mapreduce/jobs/job\_1419686689081\_0001/tasks otteniamo le in-formazioni dei task di map e reduce. Effettuato il parsing della risorsa generata,si estraggono, per ogni task, alcune informazioni come gli ”attempts”: Di se-guito sono indicate le URL per estrarre le informazioni su uno specifico task esu suoi attempt.http://localhost:19888/ws/v1/history/mapreduce/jobs/job\_1419686689081\
_0001/tasks/task\_1419686689081\_0001\_m\_000001
http://localhost:19888/ws/v1/history/mapreduce/jobs/job\_1419686689081\
1.3. PROFILER 9
_0001/tasks/task\_1419686689081\\\_0001\_m\_000001/attemptsPossono esistere piu ’attempts’ per lo stesso task: infatti, occorre fare la dif-ferenza tra task che possono essere ’SUCCEEDED’, ovvero quelli che terminanola computazione, ’KILLED’ o ’FAILED’, ovvero interrotti a causa di errorinell’esecuzione. Esistono diversi motivi per cui Hadoop pu fare il ’kill’ di untask:
• Il task non segnala progressi al termine di un timeout, che di default e di10 minuti.
• Il FairScheduler o il CapacityScheduler hanno bisogno dello slot per qualchealtro compito.
• L’esecuzione speculativa provoca risultati del task non necessari, poichlesecuzione e gia stata portata a termine.
1.3 Profiler
Laddove si e presentato un warning, il tool utilizza ulteriori informazioni perdare ulteriori dettagli sul ’malfunzionamento’ del cluster. Questi ulteriori det-tagli sono generati a partire dai file eventualmente generati con ’hprof’ (sel’utente ha utilizzato il profiler al run dell’esperimento). Per abilitare il pro-filer bisogna passare come parametro alla VM:
-agentlib:hprof=cpu=times,heap=sites,depth=6,interval=10000,force=n,
thread=y,verbose=n,file=prof.output
A questo punto, viene generato un file contenente informazioni sull’utilizzo dellerisorse da parte dei metodi invocati dall’applicazione Java. Tale file conterrainformazioni su un singolo task; di conseguenza l’output generato dal tool darainformazioni sul task descritto dal file.
Output
Introduzione
In questo capitolo vengono illustrate le diverse modalita di output generabiliutilizzando il tool ’Hadoop Analyzer JR’. Tali modalita variano, ancora unavolta, in base alla libreria selezionata dall’utente (Google-JFreeChart o R).L’integrazione tra Java ed R e stata implementata richiamando sgli script dacodice Java, quindi in maniera del tutto trasparente all’utente. Nel tool si de-ciso di non utilizzare JRI, ovvero linterfaccia Java/R, che permette di eseguirecodice R all’interno di applicazioni Java. Questo perche, sebbene JRI forniscadelle API Java per R, occorre installarlo come libreria esterna.
2.1 Java
Qualora l’utente decidesse di utilizzare le librerie java (Google-JFreeChart) iltool realizzera un’applicazione web contenente i grafici generati. Per generarei grafici da java sono state utilizzate 2 librerie:
• charts4j[2]
• JFreeChart[1]
’charts4j’ consente di creare da codice grafici generabili con ’Google CHartTools’. Tale API fornisce dei metodi per generare grafici che effettuano inmaniera opportuna delle richieste Http. Cio che restituisce e dunque una url algrafico. E stato necessario utilizzare anche la lbreria JFreeChart perche quandosi tentava di generare i grafici contenenti tutti gli slave ed il master in un singolografico la libreria ’charts4j’ creava una richiesta http troppo grande lanciandol’eccezione ’Request-URI Too Large’. Le classi java che realizzano i grafici sonomostrate in 5.1.2 ed in 5.1.3.
2.1.1 Web page
I grafici generati utilizzando la modalita java saranno raccolti in una appli-cazione web divisa in sezioni. Ogni sezione raccoglie grafici relativi rispettiva-mente a:
10
2.1. JAVA 11
• Cpu
• Ram
• Swap
• Disk
• Network packet
• Network throughput
• Paging
• Context swithces
• Interrupts
• Warning
• Profiler Information
La figura 2.3 mostra un esempio di output autogenerato dal tool in modalitaGoogle-JFreeChart. Un generico grafico mostra sull’asse delle x il tempo inminuti, secondi o ore in base alla scelta dell’utente; sull’asse delle y possiamoavere:
• percentuale se il grafico e relativo alla cpu
• numero di pacchetti per network packets
• MB se il grafico e relativo a qualsiasi delle altre risorseCpu
La sezione Cpu contiene i grafici relativi all’andamento della cpu. Per la cpu,utilizzando le librerie java, viene generato un grafico per ciascuna colonna delfile ’.dstat’ dato in input (cpu, sys, idl, syq, hiq, wai). E possibile inoltre darein input una combinazione di qualsiasi colonna ed il tool ne effettuera la sommagenerando il grafico relativo. La figura 2.4 mostra un esempio di grafico relativoalla cpu generato in modalita java. Memoria
In questa sezione saranno raccolti i grafici relativi all’utilizzo della memoriaprincipale. Per tale risorsa ’dstat’ fornisce diverse informazioni:
• used
• cach
• buff
• free
Il tool genera un grafico per ciascuna delle precendenti informazioni. E possi-bile, anche qui, dare in input una combinazione di qualsiasi colonna ed il toolne effettuera la somma generando il grafico relativo. La figura 2.5 mostra unesempio di grafico relativo alla memoria ram generato in modalita java.
12 CONTENTS
Figura 2.3: Web page generata dal Hadoop Analyzer JR
2.1. JAVA 13
Figura 2.4: Grafico cpu per lo slave 29
14 CONTENTS
Figura 2.5: Grafico memoria ram per lo slave 29
2.1. JAVA 15
2.1.2 Warning
Generati i grafici risulta interessante poter automatizzare un processo di clas-sificazione di questi ultimi. E di grande aiuto per l’utente avere una categoriadi grafici di ’warning’ che evidenziano eventuali colli di bottiglia presenti nelcluster. Uno scenario possibile e descritto di seguito:
• Warning positivi: Cpu, disk I/O e RAM utilizzati poco:
– se la cpu e usata poco l’esperimento dovrebbe essere I/O bound (pergiustificare il tempo in cui la cpu non lavora) o dovrebbe consumaremolta RAM (per giustificare il fatto di non aver usato al massimo laCPU);
– se l’I/O e la RAM sono utilizzati poco la cpu dovrebbe lavorare (ilprocesso e CPU bound); SUGGERIMENTO: si potrebbe ’caricare’maggiormente ogni cpu (aumentare il numero di task per slave)
• Warning negativi:
– SWAP alto (soglia stabilita dallutente):
– Rete sovraccarica (non sfruttiamo la massima localita dei dati)
– RAM sovraccarica SUGGERIMENTO: ridurre il numero di task perslave
L’utente dara in input:
• Warning positivi: % cpu, Mbyte I/O (disco) e RAM: se la cpu ha lavoratomeno della percentuale indicata dallutente e l’I/O e la RAM sono minoridi quella specificata dall’utente i grafici relativi andranno nella sezione diwarning
• Warning negativi:
– Mbyte swap: se lo swap e superiore ai megabyte inseriti dall’utenteil grafico relativo sara contrassegnato come warning chart
– Mbyte rete: se la rete e superiore di quanto specificato dall’utente ilgrafico relativo sara contrassegnato come warning chart
– Mbyte RAM: se la RAM utilizzata e superiore di quanto specificatodall’utente il grafico relativo sara contrassegnato come warning chart
Le figure 2.6 e 2.7 mostrano l’output generato.
2.1.3 Profiler
Inserendo il file generato da hprof nella cartella di input passata al tool (comedescritto nel manuale utente), il tool ne effettuera il parsing andando a ricavarei ’trace’. Per ciascun ’trace’ verra generato un link nella pagina web generata.Cliccando su ciascun link verra mostrata una tabella (autogenerata in html)contenente le informazioni sul ’trace’. Le figure 2.8 e 2.9 mostrano un esempiodi output.
16 CONTENTS
Figura 2.6: Sezione relativa ai warning positivi dell’applicazione web autogen-erata
Figura 2.7: Sezione relativa ai warning negativi dell’applicazione web autogen-erata
Figura 2.8: Informazioni sul profiler
2.2. R 17
Figura 2.9: Informazioni sul profiler - 2
2.2 R
In questa sezione sono descritte le principali funzionalita fornite dagli script R.
2.2.1 Dati formattati excel
E stato creato uno script in linguaggio R per l’aggregazione dei dati generati dadstat. In particolare, viene creato un file excel che contiene diversi sheet, uno perogni informazione ricevuta. Ad esempio, i primi 6 sheet sono relativi all’utilizzodella CPU nelle varie modalita (utente, sistema, ecc.). L’ultimo sheet presentainvece una versione ’aggregata’ dei dati, in modo da permettere all’utente unafacile interpretazione degli stessi.
2.2.2 SpeedUp ed efficienza
Lo speedup e una metrica relativa al miglioramento delle prestazioni mentre siesegue un task. Fu stabilita dalla legge di Amdahl, il quale era particolarmenteinteressato al calcolo parallelo. Comunque, lo speedup puo essere generalmenteusato per mostrare l’incremento delle performance. e definito dalla seguenteformula:
Speedup =Tseq
Tprl
In particolare, per tempo parallelo il tool si aspetta di ricevere in input dall’utenteun array contenente i tempi impiegati da ciascuna esecuzione su insiemi differ-
18 CONTENTS
Figura 2.10: Tool per generazione speedup ed efficienza
enti di slave. L’efficienza di parallelizzazione e data da:
E = SN
dove S e lo speedup e N e il numero di slave. Dall’input dell’utente, il tool e ingrado di calcolare l’efficienza per ciascun insieme di slave. La figura 2.10 mostrala schermata dove l’utente puo inserire i parametri per lo speedup.
Manuale utente
Introduzione
In questa sezione viene spiegato come installare ed utilizzare il tool.
19
2014/2015
Amedeo Leo – Alessio Petrozziello –
Simone Romano
Progetto Sistemi Operativi Avanzati
2014/2015
Hadoop Analyzer JR User manual
Hadoop Log Analyzer JR – User manual
Hadoop Log Analyzer JR – User manual
Installazione
Per iniziare, installare R dal sito http://cran.r-project.org (scegliere la versione binaria base).
Per utenti Windows:
Installare Rtools dallo stesso sito.
Occorre fare attenzione durante la fase di installazione di Rtools. È necessario procedere come di
seguito:
Terminata l’installazione, settare la variabile PATH facendola “puntare” alla cartella dei file di R. Ad
esempio,
Hadoop Log Analyzer JR – User manual
Hadoop Log Analyzer JR – User manual
Installato Rtools, lanciare il file ‘install.bat’ presente nella cartella ’HadoopLogAnalyzer’.
Per utenti Mac:
lanciare il file ‘install.sh’ presente nella medesima cartella. Eventualmente assicurarsi che tale file
abbia i permessi di esecuzione.
E’ possibile settare tali permessi con:
chmod +x install.sh
Error
1. Nel caso in cui ‘R’ non fosse installato sulla macchina verrà mostrato a video il seguente
errore:
Si può risolvere installando R come spiegato precedentemente.
Hadoop Log Analyzer JR – User manual
Hadoop Log Analyzer JR – User manual
Manuale utente
Il tool si presenta con questa interfaccia.
Come si può notare, è divisa in dstat, sulla sinistra, e Hadoop log, sulla destra. Di seguito sono
descritte le diverse caratteristiche.
01: Inserire la cartella di input dei file di dstat più il file “prof_output.txt” eventualmente generato
con l’attivazione del profiler. Per abilitare il profiler bisogna passare alla JVM la seguente riga:
-agentlib:hprof=cpu=times,heap=sites,depth=6,interval=10000,force=n,thread=y,verbose=n,file=prof.output
02: Inserire la cartella di output.
03: Scegliere il tool da utilizzare per generare i grafici (“R” creerà dei pdf, “Google/JFreeChart” una
pagina web).
04: Creazione del file excel contenente l’aggregazione dei dati generati da dstat.
05: Generazione dei grafici di dstat.
06: Possibilità di scegliere tra le varie percentuali di utilizzo della CPU. Nel caso in cui
“Google/JFreeChart” sia spuntato, saranno mostrati un grafico per ciascuna delle sei scelte e un
altro grafico per la somma delle percentuali scelte dall’utente. Nel caso in cui “R” sia spuntato, se
nessuna scelta è selezionata, saranno generati dei grafici per ciascuna scelta; se due o più scelte
sono selezionate, sarà mostrato all’utente un grafico contenete la somma delle scelte effettuate.
Nota: la somma delle percentuali verrà sempre normalizzata a 100.
07: Possibilità di scegliere tra le varie combinazioni della RAM. Nel caso in cui “Google/JFreeChart”
sia spuntato, saranno mostrati un grafico per ciascuna delle quattro scelte e un altro grafico per la
somma delle scelte dell’utente. Nel caso in cui “R” sia spuntato, se nessuna scelta è selezionata,
saranno generati dei grafici per ciascuna scelta; se due o più scelte sono selezionate, sarà mostrato
Hadoop Log Analyzer JR – User manual
Hadoop Log Analyzer JR – User manual
all’utente un grafico contenete la somma delle scelte effettuate; inoltre viene data la possibilità di
inserire un upperbound al grafico della RAM.
08: Scelta della timeline in ore, minuti o secondi.
09: Scelta del tipo di grafico: nel caso in cui “Google/JFreeChart” sia spuntato, saranno mostrati i
grafici in una pagina web, in cui sono mostrati anche eventuali grafici di warning. Nel caso in cui
“R” sia spuntato, saranno mostrati i grafici in dei file pdf. La scelta effettuabile varia tra “Singles”,
“All in” e “Average”. Nel primo caso, se “Google/JFreeChart” è spuntato, verranno prodotti dei
grafici singoli in cui sarà mostrato il relativo slave e il master per ciascuna delle scelte effettuate;
se invece “R” è spuntato, saranno generati dei grafici singoli per ciascuno slave e per il master a
seconda delle scelte fatte. Nel caso “All in” viene generato, per ogni sezione (CPU, Memoria,
Network...) un solo grafico contenente tutti i nodi del cluster. Nel caso “Average”, infine, viene
mostrato, per ogni sezione, un grafico contenente il master e la media di tutti gli slave del cluster.
10: Scelta della colorazione del grafico (scala di grigi, di default è a colori).
11: Scelta dello stile della linea (tratteggiata, di default è continua).
12: Possibilità di inserire il titolo in ciascun grafico.
13: Altre possibilità date all’utente: dimensione del font e scelta del tipo di grafico, su un singolo
file o su più file; nel secondo caso, sarà possibile effettuare la scelta solo se “R” è stato spuntato.
14: Possibilità di scegliere se combinare in uno stesso grafico l’I/O del disco o in due grafici
separati. Sarà possibile effettuare la scelta solo se “R” è stato spuntato.
15: Possibilità di scegliere se combinare in uno stesso grafico il paging o in due grafici separati.
Sarà possibile effettuare la scelta solo se “R” è stato spuntato.
16: Possibilità di scegliere se combinare in uno stesso grafico i pacchetti ricevuti o inviati o in due
grafici separati. Sarà possibile effettuare la scelta solo se “R” è stato spuntato.
17: Possibilità di scegliere se combinare in uno stesso grafico l’utilizzo della rete in e out o in due
grafici separati. Sarà possibile effettuare la scelta solo se “R” è stato spuntato.
18: Nel caso in cui “Google/JFreeChart” sia attivato, l’utente può settare, per i grafici di warning
positivi, la percentuale di CPU, di utilizzo del disco (in MB/s) e della RAM (in GB). Se l’utilizzo di
CPU è minore della percentuale inserita dall’utente, se il disco è stato utilizzato meno di quanto ha
inserito l’utente e se la RAM è stata utilizzata meno di quanto inserito dall’utente, allora, per
ciascuno slave in cui tali assunzioni risultano vere, verrà segnalato un warning positivo.
19: Nel caso in cui “Google/JFreeChart” sia attivato, l’utente può settare, per i grafici di warning
negativi, lo swap (in MB), l’utilizzo della rete (in MB/s) e della RAM (in GB). Se almeno una delle
risorse è utilizzata più di quanto l’utente ha selezionato allora verrà dato un warning negativo.
20: Shell che mostra la computazione del tool.
21: Inserire la cartella di input dei log di Hadoop.
22: Inserire la cartella di output dei log di Hadoop.
Hadoop Log Analyzer JR – User manual
Hadoop Log Analyzer JR – User manual
23: Generazione dei grafici dei log di Hadoop.
In caso di errore controllare che nella cartella di input dei log non siano presenti file diversi da
‘attempt*’.
24: Pdf viewer per i grafici generati dal linguaggio R.
25: Possibilità di visualizzare il file precedente o successivo all’interno della stessa cartella.
26: Permette di mostrare le label con i nomi degli slave.
27: Scelta della timeline in ore, minuti o secondi per i grafici relativi ai log di Hadoop.
Nel menù, cliccando su “File”, sono presentate queste scelte.
Il tool permette di inserire una configurazione precedentemente salvata dall’utente. Cliccando su
“Open”, l’utente può scegliere il file precedentemente creato.
Se l’utente desidera salvare la nuova configurazione, cliccando su “Save” sarà automaticamente
salvata al posto della precedente. Altrimenti, l’utente deve necessariamente cliccare “Save as…”
per poter salvare la configurazione. “Exit” permette di chiudere il programma.
Hadoop Log Analyzer JR – User manual
Hadoop Log Analyzer JR – User manual
Nel menù, cliccando su “Tools”, si apre questa schermata.
Si permette all’utente di inserire i parametri di seguito descritti, in modo da generare i grafici
relativi allo speedup e all’efficienza.
01: Permette di aggiungere una riga alla tabella. In particolare, l’utente può inserire il numero di
nodi e il relativo tempo di esecuzione.
02: Permette di cancellare l’ultima riga della tabella.
03: Permette di inserire il tempo sequenziale.
04: Genera i grafici relativi a speedup e efficienza.
05: Pdf viewer per i grafici generati dal linguaggio R.
Nel menù, cliccando su “Help”, sono visualizzate due opzioni.
Hadoop Log Analyzer JR – User manual
Hadoop Log Analyzer JR – User manual
Cliccando su “Manual”, sarà scaricato il manuale che si sta leggendo.
Cliccando su “About”, viene visualizzata questa schermata.
Caso di studio
Introduzione
Per dimostrare la correttezza del tool, e stato testato su due casi d’uso: perentrambi si tratta del classico WordCount; tuttavia, nel primo sono state utiliz-zate le espressioni regolari per eliminare caratteri speciali, mentre nel secondoquesti ultimi sono stati sostituiti con dei controlli.
4.1 Configurazione cluster
Riportiamo di seguito i file ’.xml’ contenenti la configurazione del cluster durantela esecuzione dei test. E importante evidenziare che non viene utilizzata la cachedi Hadoop per il caricamento del file delle stop words utilizzate. Nei grafici dellarete mostrati si noteraun picco iniziale corrispondente al caricamento del file suivari nodi.
4.1.1 Yarn-site.xml
Di seguito il file ’yarn-site.xml’ utilizzato per l’esperimento. In particolare perciascun container sono stati predisposti 3GB di spazio.
<?xml version="1.0"?>
<!--
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied.
See the License for the specific language governing permissions and
limitations under the License. See accompanying LICENSE file.
-->
28
4.1. CONFIGURAZIONE CLUSTER 29
<configuration>
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
<property>
<name>yarn.nodemanager.aux-services.mapreduce.shuffle.class</name>
<value>org.apache.hadoop.mpred.ShuffleHandler</value>
</property>
<property>
<name>yarn.resourcemanager.address</name>
<value>slave63:8032</value>
</property>
<property>
<name>yarn.resourcemanager.scheduler.address</name>
<value>slave63:8030</value>
</property>
<property>
<name>yarn.resourcemanager.resource-tracker.address</name>
<value>slave63:8031</value>
</property>
<property>
<name>yarn.resourcemanager.admin.address</name>
<value>slave63:8033</value>
</property>
<property>
<name>yarn.resourcemanager.webapp.address</name>
<value>slave63:8088</value>
</property>
<property>
<name>mapreduce.jobhistory.webapp.address</name>
<value>slave63:19888</value>
</property>
<property>
<name>mapreduce.jobhistory.address</name>
<value>slave63:10020</value>
</property>
<!-- Site specific YARN configuration properties -->
<property>
<name>yarn.nodemanager.resource.memory-mb</name>
<value>3072</value>
</property>
</configuration>
30 CONTENTS
4.2 hdfs-site.xml
Tale file indica la size di caiascun blocco (nell’esempio 128MB) ed il numero direpliche fatte per ciascun blocco di dati (3 nell’esempio).
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
<property>
<name>dfs.replication</name>
<value>3</value>
</property>
<property>
<name>dfs.blocksize</name>
<value>128m</value>
</property>
<property>
<name>dfs.namenode.name.dir</name>
<value>file:/home/user/mydata/hdfs/namenode</value>
</property>
<property>
<name>dfs.datanode.data.dir</name>
<value>file:/home/user/mydata/hdfs/datanode</value>
</property>
</configuration>
4.3 WordCount
Mostriamo di seguito entrambi i codici ’WordCount’ utilizzati. Il successivo e ilcodice ’WordCount’ che utilizza le espressioni regolari.
package hadoop;
import java.io.IOException;
public class WordCount extends Configured implements Tool {
/*
* NLineInputFormat which splits N lines of input as one split.
* In many "pleasantly" parallel applications, each process/mapper
processes the same input file (s),
* but with computations are controlled by different
parameters.(Referred to as "parameter sweeps").
4.3. WORDCOUNT 31
* One way to achieve this, is to specify a set of parameters (one
set per line) as input in a control file
* (which is the input path to the map-reduce application, where as
the input dataset is specified via a config variable in
JobConf.).
* The NLineInputFormat can be used in such applications, that splits
the input file such that by default,
* one line is fed as a value to one map task, and key is the offset.
i.e. (k,v) is (LongWritable, Text).
* The location hints will span the whole mapred cluster.
*/
//run configurations: args[0]: INPUT args[1]:OUTPUT
public static final Integer N = 20000;
public static void main(String args[]) throws Exception {
int res = ToolRunner.run(new WordCount(), args);
System.exit(res);
}
public int run(String[] args) throws Exception {
Path inputPath = new Path(args[0]);
Path outputPath = new Path(args[1]);
Configuration conf = getConf();
Job job = Job.getInstance(conf, "word count");
FileInputFormat.setInputPaths(job, inputPath);
//NLineInputFormat.addInputPath(job, inputPath);
FileOutputFormat.setOutputPath(job, outputPath);
job.setJarByClass(this.getClass());
job.setInputFormatClass(TextInputFormat.class);
//job.setInputFormatClass(NLineInputFormat.class);
//NLineInputFormat.setNumLinesPerSplit(job, N); //Set the number
of lines per split
job.setOutputFormatClass(TextOutputFormat.class);
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(IntWritable.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
job.setMapperClass(Map.class);
job.setCombinerClass(Reduce.class);
job.setReducerClass(Reduce.class);
32 CONTENTS
return job.waitForCompletion(true) ? 0 : 1;
}
public static class Map extends Mapper<LongWritable, Text, Text,
IntWritable>{
private final static IntWritable one = new IntWritable(1);
private final Text word = new Text();
HashMap<String, String> stopWords = new HashMap<String, String>();
@Override
public void setup(Context context) throws IOException,
InterruptedException{
super.setup(context);
Scanner in;
try {
//in = new Scanner(new File("stopWords.txt"));
in = new
Scanner(Map.class.getResourceAsStream("italianStopWords.txt"));
while(in.hasNextLine()){
//word.set(in.nextLine());
//stopWords.put(word.toString(),word.toString() );
String tmp = in.nextLine();
stopWords.put(tmp, tmp);
}
in.close();
} catch(NoSuchElementException e1){
System.out.println("no such....");
}
}
@Override
public void map(LongWritable key, Text value, Context context)
throws IOException, InterruptedException {
String line = value.toString();
line = myStringSplit(line);
StringTokenizer tokenizer = new StringTokenizer(line);
while (tokenizer.hasMoreTokens()) {
String tmp = tokenizer.nextToken();
tmp = tmp.trim();
if(stopWords.get(tmp) == null){
word.set(tmp);
context.write(word, one);
4.3. WORDCOUNT 33
}
}
}
}
public static String myStringSplit(String s){
String result = s.toLowerCase();
String replacement = " ";
String regex =
"[=]|[.]|[;]|[:]|[,]|[’]|[\"]|[?]|[!]|[)]|[(]|[<]|[>]|[{]|[}]|[[]|
[\\]]|[#]|[*]|[-]|[&]|[_]|[$]|[‘]|[/]";
result = result.replaceAll(regex, replacement);
return result;
}
public static class Reduce extends Reducer<Text, IntWritable, Text,
IntWritable> {
@Override
public void reduce(Text key, Iterable<IntWritable> values, Context
context) throws IOException, InterruptedException {
int sum = 0;
for (IntWritable value : values) {
sum += value.get();
}
context.write(key, new IntWritable(sum));
}
}
}
Mostriamo ora il codice di ’WordCount’ che evita di utilizzare le espressioniregolari utilizzando il metodo dell’oggetto String ’charAt’.
package hadoop;
import java.io.IOException;
import java.io.Serializable;
import java.util.*;
import org.apache.hadoop.conf.*;
import org.apache.hadoop.fs.*;
import org.apache.hadoop.io.*;
import org.apache.hadoop.mapreduce.*;
import org.apache.hadoop.mapreduce.lib.input.*;
import org.apache.hadoop.mapreduce.lib.output.*;
import org.apache.hadoop.util.*;
public class WordCount extends Configured implements Tool {
34 CONTENTS
/*
* NLineInputFormat which splits N lines of input as one split.
* In many "pleasantly" parallel applications, each process/mapper
processes the same input file (s),
* but with computations are controlled by different
parameters.(Referred to as "parameter sweeps").
* One way to achieve this, is to specify a set of parameters (one
set per line) as input in a control file
* (which is the input path to the map-reduce application, where as
the input dataset is specified via a config variable in
JobConf.).
* The NLineInputFormat can be used in such applications, that splits
the input file such that by default,
* one line is fed as a value to one map task, and key is the offset.
i.e. (k,v) is (LongWritable, Text).
* The location hints will span the whole mapred cluster.
*/
//run configurations: args[0]: INPUT args[1]:OUTPUT
public static final Integer N = 20000;
public static void main(String args[]) throws Exception {
int res = ToolRunner.run(new WordCount(), args);
System.exit(res);
}
public int run(String[] args) throws Exception {
Path inputPath = new Path(args[0]);
Path outputPath = new Path(args[1]);
Configuration conf = getConf();
Job job = Job.getInstance(conf, "word count");
FileInputFormat.setInputPaths(job, inputPath);
//NLineInputFormat.addInputPath(job, inputPath);
FileOutputFormat.setOutputPath(job, outputPath);
job.setJarByClass(this.getClass());
job.setInputFormatClass(TextInputFormat.class);
//job.setInputFormatClass(NLineInputFormat.class);
//NLineInputFormat.setNumLinesPerSplit(job, N); //Set the number
of lines per split
4.3. WORDCOUNT 35
job.setOutputFormatClass(TextOutputFormat.class);
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(IntWritable.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
job.setMapperClass(Map.class);
job.setCombinerClass(Reduce.class);
job.setReducerClass(Reduce.class);
return job.waitForCompletion(true) ? 0 : 1;
}
public static class Map extends Mapper<LongWritable, Text, Text,
IntWritable>{
private final static IntWritable one = new IntWritable(1);
private final Text word = new Text();
HashMap<String, String> stopWords = new HashMap<String, String>();
@Override
public void setup(Context context) throws IOException,
InterruptedException{
super.setup(context);
Scanner in;
try {
//in = new Scanner(new File("stopWords.txt"));
in = new
Scanner(Map.class.getResourceAsStream("italianStopWords.txt"));
while(in.hasNextLine()){
//word.set(in.nextLine());
//stopWords.put(word.toString(),word.toString() );
String tmp = in.nextLine();
stopWords.put(tmp, tmp);
}
in.close();
} catch(NoSuchElementException e1){
System.out.println("no such....");
}
}
@Override
public void map(LongWritable key, Text value, Context context)
throws IOException, InterruptedException {
36 CONTENTS
String line = value.toString();
line = myStringSplit(line);
StringTokenizer tokenizer = new StringTokenizer(line);
while (tokenizer.hasMoreTokens()) {
String tmp = tokenizer.nextToken();
tmp = tmp.trim();
if(stopWords.get(tmp) == null){
word.set(tmp);
context.write(word, one);
}
}
}
}
public static String myStringSplit(String s){
String result = s.toLowerCase();
char replacement = ’ ’;
for(int i=0; i<s.length(); i++){
char tmp = result.charAt(i);
if(tmp == ’=’){
result.replace(result.charAt(i), replacement);
continue;
}
if(tmp == ’.’){
result.replace(result.charAt(i), replacement);
continue;
}
if(tmp == ’;’){
result.replace(result.charAt(i), replacement);
continue;
}
if(tmp == ’:’){
result.replace(result.charAt(i), replacement);
continue;
}
if(tmp == ’,’){
result.replace(result.charAt(i), replacement);
continue;
}
if(tmp == ’\’’){
result.replace(result.charAt(i), replacement);
continue;
}
if(tmp == ’\"’){
result.replace(result.charAt(i), replacement);
continue;
}
if(tmp == ’?’){
4.3. WORDCOUNT 37
result.replace(result.charAt(i), replacement);
continue;
}
if(tmp == ’!’){
result.replace(result.charAt(i), replacement);
continue;
}
if(tmp == ’(’){
result.replace(result.charAt(i), replacement);
continue;
}
if(tmp == ’)’){
result.replace(result.charAt(i), replacement);
}
if(tmp == ’<’){
result.replace(result.charAt(i), replacement);
continue;
}
if(tmp == ’>’){
result.replace(result.charAt(i), replacement);
continue;
}
if(tmp == ’{’){
result.replace(result.charAt(i), replacement);
continue;
}
if(tmp == ’}’){
result.replace(result.charAt(i), replacement);
continue;
}
if(tmp == ’[’){
result.replace(result.charAt(i), replacement);
continue;
}
if(tmp == ’]’){
result.replace(result.charAt(i), replacement);
continue;
}
if(tmp == ’#’){
result.replace(result.charAt(i), replacement);
continue;
}
if(tmp == ’*’){
result.replace(result.charAt(i), replacement);
continue;
}
if(tmp == ’-’){
result.replace(result.charAt(i), replacement);
continue;
}
38 CONTENTS
if(tmp == ’&’){
result.replace(result.charAt(i), replacement);
continue;
}
if(tmp == ’_’){
result.replace(result.charAt(i), replacement);
continue;
}
if(tmp == ’$’){
result.replace(result.charAt(i), replacement);
continue;
}
if(tmp == ’‘’){
result.replace(result.charAt(i), replacement);
continue;
}
if(tmp == ’/’){
result.replace(result.charAt(i), replacement);
continue;
}
}
//result = result.replaceAll(regex, replacement);
return result;
}
public static class Reduce extends Reducer<Text, IntWritable, Text,
IntWritable> {
@Override
public void reduce(Text key, Iterable<IntWritable> values, Context
context) throws IOException, InterruptedException {
int sum = 0;
for (IntWritable value : values) {
sum += value.get();
}
context.write(key, new IntWritable(sum));
}
}
}
4.4 Input
Il file di input utilizzato, ovvero la Divina Commedia in un file formato txt, hadimensioni 38,19GB; tale file e stato ottenuto replicando il contenuto inizialedel testo. Sono stati effettuati tre test per ciascun caso d’uso. Iniziando dallarete a disposizione, i test sono stati effettuati presso l’Universita degli Studi di
4.5. TEST 39
Salerno all’interno del Laboratorio RETI della Dipartimento di Informatica suuna griglia di 32 macchine.
4.4.1 Specifiche delle macchine
Seguono le caratteristiche hardware delle macchine utilizzate:
• SISTEMA OPERATIVO: Windows 7
• CPU: Intel(R) Celeron(R) CPU G530 @ 2.40GHz 3.0 GHz - Thread(s) percore 1, Core(s) per socket 1, Socket(s) 2 CPU MHz 3100.000 - Architecturex86 64, CPU op-mode(s) 32-bit, 64-bit, CPU(s) 2
• RAM: 4GB
• HARD DISK: 250GB
Hadoop e stato installato su una macchina virtuale VMWARE con sistemaoperativo Ubuntu Linux 12.04 LTS con 2CPU, 3100MB di RAM e HARD DISKda 120 GB. La versione di Hadoop utilizzata e 2.5.1 con Java 1.8.0 20.
4.5 Test
2 sono i casi d’uso analizzati:
• WordCount con espressioni regolari
• WordCount con controlli sui singoli caratteri
Per il primo caso d’uso sono stati effettuati 3 test che hanno impiegato24.53 minuti, 13.6 minuti, 12.55 minuti. Per il secondo caso d’uso, i test hannoimpiegato 9.29 minuti, 15.44 minuti, 8.40 minuti.
test1 test2 test3 mediaWord Count Regexp 24.53 13.60 12.55 16.89Word Count CharAt 9.29 15.44 8.40 11.04
4.6 Risultati
Di seguito sono mostrati, per ciascun sezione, i grafici generati dal tool utiliz-zando sia le librerie R che la modalita ChartsForJ/JFreeChart (librerie Java).In particolare analizzeremo il caso di studio Word Count Regexp e vedremocome, con l’aiuto del tool, si riescono ad evidenziare eventuali malfunzionamentidel cluster.
40 CONTENTS
Figura 4.11: Media utilizzo CPU
4.6.1 Analisi Dstat
Per i dati generati con dstat sono state generate le 3 modalita di grafici che iltool consente di estrarre, ovvero:
• Single charts
• Average
• All in
Sono stati generati ed analizzati in primo momento i grafici in modalita aver-age per controllare l’andamento generale dell’utilizzo delle risorse da parte delcluster. Come prevedibile, il lavoro risulta CPU bound; l’utilizzo medio dellamemoria RAM e risultato sotto i 1400MB mentre l’andamento medio della cpue stato intorno al 70-80% come si puo vedere nella figura 4.11.
Per avere un maggiore livello di dettaglio si sono analizzati i grafici contenentitutti gli slave singolarmente. I grafici sono mostrati nelle figure 4.12 e 4.13.
In tali figure si nota che uno slave ha lavorato meno degli altri restando inmedia sotto il 60%. Per scendere ulteriormente nel dettaglio sono stati generatii grafici singoli. Per tali grafici abbiamo tentato di evidenziare, con l’aiuto deltool, gli slave la cui CPU ha lavorato sotto il 70%. Sono stati generati i grafici
4.6. RISULTATI 41
Figura 4.12: Utilizzo CPU di tutti i nodi del cluster. Grafico generato conlibrerie Java.
Figura 4.13: Utilizzo CPU (campo ’usr’) di tutti i nodi del cluster. Graficogenerato con librerie R.
42 CONTENTS
Figura 4.14: Warning chart per lo slave 83. La CPU ha lavorato meno del 70%per almeno il 60% dell’esperimento.
e, come da aspettativa, il tool ha generato un warning positivo per lo slave 83(vedi figura 4.14 e figura 4.15).
E stato possibile evidenziare con la modalita warning charts, inoltre, chelo slave 56 non ha proprio lavorato durante l’esperimento (vedi figura 4.16 efigura 4.17).
4.6.2 Analisi Log Hadoop
L’utente puo scegliere se visualizzare i nomi degli slave e la timeline. In questocaso, sono presentati i nomi dei nodi e la timeline in minuti, data la duratadell’esperimento. Come si puo vedere nella legenda sulla destra del grafico infigura, i task mostrati in rosso sono i ’SUCCEEDED’, i verdi sono ’FAILED’e i blu sono i ’KILLED’. In particolare, sono rappresentati i task per ciascunoslave. Qualora i task dovessero sovrapporsi, e stata generata una nuova lineaper ciascuna sovrapposizione, in modo da distinguere la computazione.
4.6. RISULTATI 43
Figura 4.15: Warning chart per lo slave 83. La CPU ha lavorato meno del 70%per almeno il 60% dell’esperimento.
44 CONTENTS
Figura 4.16: Warning chart per lo slave 56.
slave53 / 1slave53 / 2slave53 / 3slave55 / 1slave55 / 2slave55 / 3slave58 / 1slave58 / 2slave58 / 3slave59 / 1slave59 / 2slave59 / 3slave60 / 1slave60 / 2slave60 / 3slave61 / 1slave61 / 2slave61 / 3slave62 / 1slave62 / 2slave62 / 3slave64 / 1slave64 / 2slave64 / 3slave65 / 1slave65 / 2slave65 / 3slave67 / 1slave67 / 2slave67 / 3slave69 / 1slave69 / 2slave69 / 3slave70 / 1slave70 / 2slave70 / 3slave71 / 1slave71 / 2slave71 / 3slave72 / 1slave72 / 2slave72 / 3slave73 / 1slave73 / 2slave73 / 3slave74 / 1slave74 / 2slave74 / 3slave75 / 1slave75 / 2slave75 / 3slave76 / 1slave76 / 2slave76 / 3slave77 / 1slave77 / 2slave77 / 3slave79 / 1slave79 / 2slave79 / 3slave80 / 1slave80 / 2slave80 / 3slave82 / 1slave82 / 2slave82 / 3slave83 / 1slave84 / 1slave84 / 2slave84 / 3slave85 / 1slave85 / 2slave85 / 3slave86 / 1slave86 / 2slave86 / 3slave87 / 1slave87 / 2slave87 / 3slave89 / 1slave89 / 2slave89 / 3slave94 / 1slave94 / 2slave94 / 3slave95 / 1slave95 / 2slave95 / 3
0 5 10 15 20
Time (m)
Nod
e
State
SUCCEEDED
FAILED
KILLED
Log Hadoop
46 CONTENTS
4.7 Confronto esperimenti
Come riportato in tabella 4.5 l’esecuzione di ’WordCount’ con l’utilizzo delleespressioni regolari e risultata piu lunga. Le figure 4.18 e 4.19 mostrano i graficidell’utilizzo di CPU per i entrambi i casi. Si evince che il cluster non eviden-zia malfunzionamenti in quanto le CPU lavorano in entrambi gli esperimenti.L’utilizzo delle espressioni regolari richiede piu tempo di utilizzo di CPU peressere eseguito.
4.7. CONFRONTO ESPERIMENTI 47
Figura 4.17: Warning chart per lo slave 56.
Figura 4.18: Grafico utilizzo CPU ’WordCount’ con espressioni regolari.
48 CONTENTS
Figura 4.19: Grafico utilizzo CPU ’WordCount’ con utilizzo metodo ’charAt()’.
Appendice
Introduzione
In questa sezione sono elencati estratti piu significativi del codice realizzato siaper la parte Java che per la parte di R.
5.1 Java code
Di seguito sono elencati le classi java che svolgono la parte piu significativa.
5.1.1 Parser csv
La seguente classe si occupa di analizzare i file ’.csv’ per estrarre le informazionisulle risorse utilizzate da ciascuna macchina del cluster.
package csvManipluators;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.logging.Logger;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord;
/**
*
* @author Romano Simone - www.sromano.altervista.org
* This class allows you to manipulate csv file.
*/
public class Parser {
49
50 CONTENTS
private static Logger log = Logger.getLogger("global");
private static String csvHeader =
"time,usr,sys,idl,wai,hiq,siq,used,buff,cach,free,in,out,usedSwap,
\\ freeSwap,read,writ,recv,send,int,cntsw, recvTotPkt,sendTotPkt";
private static String MY_FILE_EXTENSION = "_Cleared.hla";
/**
* Return an arraylist of record with only column defined in toGet
array.
* @param csvFilePath file to read
* @param toGet value to return
* @return arraylist of record with only column defined in toGet
array.
* @throws UnsupportedEncodingException
* @throws FileNotFoundException
*/
public ArrayList<String> getDataFromCsv(String csvFilePath,
ArrayList<String> toGet){
String clearedFilePath = csvFilePath + MY_FILE_EXTENSION;
clearCsvFile(csvFilePath, clearedFilePath);
ArrayList<String> toReturn = new ArrayList<String>();
CSVParser parser;
try{
parser = new CSVParser(new FileReader(clearedFilePath),
CSVFormat.DEFAULT.withHeader());
for (CSVRecord record : parser) {
String subRecord = "";
for (String column:toGet){
if (subRecord.length() > 0)
subRecord = subRecord + "," + record.get(column);
else subRecord = subRecord + record.get(column);
}
toReturn.add(subRecord);
}
parser.close();
}catch(Exception e){
log.severe("Exception parsing csv File: " + e.getMessage());
e.printStackTrace();
}
return toReturn;
}
/**
* This method will extract delay between 2 record
* in csv file in input.
* @param csvFilePath Path of csv cleared file.
* @return interval(in seconds) between 2 records.
*/
public int getRecordsIntervalFromCsv(String csvFilePath){
CSVParser parser;
5.1. JAVA CODE 51
try{
parser = new CSVParser(new FileReader(csvFilePath +
MY_FILE_EXTENSION), CSVFormat.DEFAULT.withHeader());
List<CSVRecord> records = parser.getRecords();
if (records.size() == 0 || records.size() == 1)
return 1;
String firstTime = records.get(0).get("time").split("
")[1].split(":")[2]; //get seconds
String secondTime = records.get(1).get("time").split("
")[1].split(":")[2]; //get seconds
parser.close();
int firstTimeVal = Integer.parseInt(firstTime);
int secondTimeVal = Integer.parseInt(secondTime);
int toReturn = secondTimeVal - firstTimeVal;
if (toReturn < 0)
toReturn = (secondTimeVal + 60) - firstTimeVal;
log.info("Finding interval between records: " + toReturn);
return toReturn;
}catch(Exception e){
log.severe("Exception parsing csv File: " + e.getMessage());
e.printStackTrace();
}
log.info("Finding interval between records: " + 0);
return 0;
}
/**
* This method will clear csv dstat file from
* extra comments.
* @param filePath path of file to clear
* @param clearedFilePath path of new file cleared
* @throws FileNotFoundException if file doesn’t exist
* @throws UnsupportedEncodingException
*/
private void clearCsvFile(String filePath, String clearedFilePath){
try{
File file = new File(filePath);
Scanner input;
try {
input = new Scanner(file);
PrintWriter writer = new PrintWriter(clearedFilePath,
"UTF-8");
boolean writingData = false;
while(input.hasNext()) {
String nextLine = input.nextLine();
if (writingData){
writer.println(nextLine);
}
else{ //we need to delete first dstat row???
if
52 CONTENTS
(nextLine.equals("\"time\",\"usr\",\"sys\",\"idl\",\"wai\",\"hiq\",\"siq\",
\\
\"used\",\"buff\",\"cach\",\"free\",\"in\",\"out\",\"used\",\"free\",\"read\",\"writ\",\"recv\",\"send\",\"int\"
\\ ,\"csw\",\"#recv\",\"#send\"") ||
nextLine.equals("\"time\",\"usr\",\"sys\",\"idl\",\"wai\",\"hiq\",\"siq\",\"used\"
\\
,\"buff\",\"cach\",\"free\",\"in\",\"out\",\"used\",\"free\",\"read\",\"writ\",\"recv\",\"send\",\"int\",\"csw\",\\
\" #recv\",\"#send\",")){
writer.println(csvHeader);
writingData = true;
}
}
}
writer.close();
input.close();
} catch (FileNotFoundException e) {
log.severe(e.getMessage());
e.printStackTrace();
return;
} catch (UnsupportedEncodingException e) {
log.severe(e.getMessage());
e.printStackTrace();
return;
}
log.info("Created cleared file: " + clearedFilePath);
}catch(Exception e){
log.severe("Exception parsing file: " + filePath);
}
}
/**
* This method makes an array of double with each string
* contained in data.
* @param data list of data as String.
* @return list of data as double array to use it as Generator method
input.
*/
public double[] generateDoubleArrayFrom(ArrayList<String> data){
double[] toReturn = new double[1];
int position = 0;
for(String r:data){
//creating cpu dataset(array of double) for ChartGeneratorCpu
toReturn[position] = Double.parseDouble(r);
position++;
if (position > toReturn.length - 1){
if(!(position > data.size()-1)){
double[] tmp = new double[position + 1];
System.arraycopy(toReturn, 0, tmp, 0, toReturn.length);
toReturn = tmp;
}
5.1. JAVA CODE 53
}
}
return toReturn;
}
/**
* This method makes an array of double with each string
* contained in data.
* @param data list of data as String where each element could
contains more data separated by ’,’.
* @param OPERATION is the operation to join each string.
* @return list of data as double array to use it as Generator method
input.
*/
public double[] generateDoubleArrayFrom(ArrayList<String> data, int
OPERATION){
ArrayList<String> toReturn = new ArrayList<String>();
for(String r:data){
String[] row = r.split(",");
double toAdd = 0;
switch (OPERATION){
case 1: //SUM
for (String s:row){
toAdd += Double.parseDouble(s);
}
toReturn.add(toAdd + "");
break;
case 2: //SUB
for (String s:row){
toAdd -= Double.parseDouble(s);
}
toReturn.add(toAdd + "");
break;
case 3: //DIV
for (String s:row){
toAdd /= Double.parseDouble(s);
}
toReturn.add(toAdd + "");
break;
case 4: //MULT
for (String s:row){
toAdd *= Double.parseDouble(s);
}
toReturn.add(toAdd + "");
break;
}
}
return generateDoubleArrayFrom(toReturn);
}
}
54 CONTENTS
5.1.2 ChartGenerator
La classe ’chartGenerator.java’ espone dei metodi per la generazione di grafici.Tali metodi prendono diversi parametri che consentono di personalizzare ilgrafico a seconda delle esigenze dell’utente.
package chartsGenerators;
import static com.googlecode.charts4j.Color.SKYBLUE;
import java.util.ArrayList;
import java.util.logging.Logger;
import chartsManager.Chart;
import chartsManager.Chart_sCollector;
import com.googlecode.charts4j.AxisLabels;
import com.googlecode.charts4j.AxisLabelsFactory;
import com.googlecode.charts4j.AxisStyle;
import com.googlecode.charts4j.AxisTextAlignment;
import com.googlecode.charts4j.Color;
import com.googlecode.charts4j.DataUtil;
import com.googlecode.charts4j.Fills;
import com.googlecode.charts4j.GCharts;
import com.googlecode.charts4j.Line;
import com.googlecode.charts4j.LineChart;
import com.googlecode.charts4j.LineStyle;
import com.googlecode.charts4j.Plots;
import csvManipluators.Parser;
/**
*
* @author Romano Simone - www.sromano.altervista.org
* This class generates chart.
*/
public class ChartGenerator implements Generator{
private static final int IF_ZERO = 50;
private static Logger log = Logger.getLogger("global");
private String url;
public static int SUM = 1, SUB = 2, DIV = 3, MULT = 4, MINUTE = 5,
SECOND = 6, HOUR = 7;
5.1. JAVA CODE 55
public String getUrl() {
return url;
}
/**
* This method generate the usage’s chart.
* @param data1 Contains value.
* @param interval Interval between each x value(in SECOND)
* @param scaleIn could be minute, second or hour and indicates
interval to show on x
* @param isPercentage if it’s true the y value will be scaled in %
* @param title title of chart
* @param dataTitle name of line
* @param yLabel label of y axis
* @param isDashedLine
* @param isGrayScale to choice greyscale mode
* @param isDashedLine to choice dashed line mode
*/
private void generateChart(double[] data,int interval, int scaleIn,
boolean isPercentage, String title, String dataTitle, String
yLabel, boolean isGreyScale, boolean isDashedLine){
//plotting data
Line line;
AxisLabels yAxis;
if (isPercentage){
if (isGreyScale){
line = Plots.newLine(DataUtil.scaleWithinRange(0,100,data),
Color.newColor("000000"), dataTitle);
yAxis = AxisLabelsFactory.newNumericRangeAxisLabels(0,100);
}
else{
line = Plots.newLine(DataUtil.scaleWithinRange(0,100,data),
Color.newColor("CA3D05"), dataTitle);
yAxis = AxisLabelsFactory.newNumericRangeAxisLabels(0,100);
}
}
else{
if (isGreyScale){
line =
Plots.newLine(DataUtil.scaleWithinRange(0,getMax(data)+(getMax(data)/10),data),
\newline Color.newColor("000000"), dataTitle);
yAxis =
AxisLabelsFactory.newNumericRangeAxisLabels(0,getMax(data));
}
else{
line =
Plots.newLine(DataUtil.scaleWithinRange(0,getMax(data)+(getMax(data)/10),data),
\newline Color.newColor("CA3D05"), dataTitle);
yAxis =
AxisLabelsFactory.newNumericRangeAxisLabels(0,getMax(data));
56 CONTENTS
}
}
line.setLineStyle(LineStyle.newLineStyle(3, 1, 0));
if(isDashedLine){
line.setLineStyle(LineStyle.MEDIUM_DOTTED_LINE);
}
// Defining chart.
LineChart chart = GCharts.newLineChart(line);
chart.setSize(600, 450);
chart.setTitle(title, Color.newColor("000000"), 14);
chart.setGrid(25, 25, 3, 2);
// Defining axis info and styles
AxisLabels xAxis, xAxis2;
if(scaleIn == MINUTE){
xAxis = AxisLabelsFactory.newNumericRangeAxisLabels(0,
data.length/(60/interval)); //to get minute of computation
xAxis2 = AxisLabelsFactory.newAxisLabels("Minutes", 50.0);
}
else if(scaleIn == SECOND){
xAxis = AxisLabelsFactory.newNumericRangeAxisLabels(0,
data.length/(1.0/interval)); //to get second of computation
xAxis2 = AxisLabelsFactory.newAxisLabels("Seconds", 50.0);
}
else if(scaleIn == HOUR){
xAxis = AxisLabelsFactory.newNumericRangeAxisLabels(0,
data.length/(3600/interval)); //to get hour of computation
xAxis2 = AxisLabelsFactory.newAxisLabels("Hours", 50.0);
}
else{
xAxis = AxisLabelsFactory.newNumericRangeAxisLabels(0,
data.length/(1.0/interval)); //to get second of computation
xAxis2 = AxisLabelsFactory.newAxisLabels("Seconds", 50.0);
log.severe("Scale in parameter: " + scaleIn + " not valid;
possible use: " + MINUTE + " for minute, "
+ SECOND + " for seconds and " + HOUR + " for hour. Used
seconds.");
}
xAxis2.setAxisStyle(AxisStyle.newAxisStyle(Color.newColor("000000"),
14, AxisTextAlignment.CENTER));
AxisLabels yAxis2 = AxisLabelsFactory.newAxisLabels(yLabel,
50.0);
yAxis2.setAxisStyle(AxisStyle.newAxisStyle(Color.newColor("000000"),
14, AxisTextAlignment.CENTER));
// Adding axis info to chart.
chart.addXAxisLabels(xAxis);
chart.addXAxisLabels(xAxis2);
chart.addYAxisLabels(yAxis);
chart.addYAxisLabels(yAxis2);
5.1. JAVA CODE 57
// Defining background and chart fills.
chart.setBackgroundFill(Fills.newSolidFill(Color.newColor("e8e8e8")));
chart.setAreaFill(Fills.newSolidFill(Color.newColor("ffffff")));
this.url = chart.toURLString();
log.info("Url for Chart generated...");
}
/**
* This method generate the chart.
* @param data1 first dataset
* @param interval Interval between each x value(in SECOND)
* @param scaleIn could be minute, second or hour and indicates
interval to show on x
* @param isPercentage if it’s true the y value will be scaled in %
* @param data2 second dataset
* @param title title of chart
* @param data1Title name of first line
* @param data2Title name of second line
* @param yLabel label of y axis
* @param isGrayScale to choice greyscale mode
* @param isDashedLine to choice dashed line mode
*/
private void generateChart(double[] data1, int interval, int scaleIn,
\\ boolean isPercentage, double[] data2, String title, String
data1Title, String data2Title, String yLabel, boolean \\
isGrayScale, boolean isDashedLine){
if (data1.length != data2.length){
log.warning("data1 and data2 has not same size! Check for time
consistence!");
}
//plotting data
Line line, line2;
AxisLabels yAxis;
if (isPercentage){
if (isGrayScale){
line = Plots.newLine(DataUtil.scaleWithinRange(0,100,data1),
Color.newColor("000000"), data1Title);
line2 = Plots.newLine(DataUtil.scaleWithinRange(0,100,data2),
Color.newColor("bbbbbb"), data2Title);
yAxis = AxisLabelsFactory.newNumericRangeAxisLabels(0,100);
}
else{
line = Plots.newLine(DataUtil.scaleWithinRange(0,100,data1),
Color.newColor("CA3D05"), data1Title);
line2 = Plots.newLine(DataUtil.scaleWithinRange(0,100,data2),
SKYBLUE, data2Title);
yAxis = AxisLabelsFactory.newNumericRangeAxisLabels(0,100);
}
}
58 CONTENTS
else{
if (isGrayScale){
line =
Plots.newLine(DataUtil.scaleWithinRange(0,getMax(data1,data2)+getMax(data1,data2)/10,data1),
Color.newColor("000000"), data1Title);
line2 =
Plots.newLine(DataUtil.scaleWithinRange(0,getMax(data1,data2)+getMax(data1,data2)/10,data2),
Color.newColor("bbbbbb"), data2Title);
yAxis =
AxisLabelsFactory.newNumericRangeAxisLabels(0,getMax(data1,data2));
}
else{
line =
Plots.newLine(DataUtil.scaleWithinRange(0,getMax(data1,data2)+getMax(data1,data2)/10,data1),
Color.newColor("CA3D05"), data1Title);
line2 =
Plots.newLine(DataUtil.scaleWithinRange(0,getMax(data1,data2)+getMax(data1,data2)/10,data2),
SKYBLUE, data2Title);
yAxis =
AxisLabelsFactory.newNumericRangeAxisLabels(0,getMax(data1,data2));
}
}
line.setLineStyle(LineStyle.newLineStyle(3, 1, 0));
line2.setLineStyle(LineStyle.newLineStyle(3, 1, 0));
if(isDashedLine){
line.setLineStyle(LineStyle.MEDIUM_DOTTED_LINE);
line2.setLineStyle(LineStyle.MEDIUM_DOTTED_LINE);
}
// Defining chart.
LineChart chart = GCharts.newLineChart(line,line2);
chart.setSize(600, 450);
chart.setTitle(title, Color.newColor("000000"), 14);
chart.setGrid(25, 25, 3, 2);
// Defining axis info and styles
AxisLabels xAxis, xAxis2;
if (data1.length > data2.length){
if(scaleIn == MINUTE){
xAxis = AxisLabelsFactory.newNumericRangeAxisLabels(0,
data1.length/(60/interval)); //to get minute of
computation
xAxis2 = AxisLabelsFactory.newAxisLabels("Minutes", 50.0);
}
else if(scaleIn == SECOND){
xAxis = AxisLabelsFactory.newNumericRangeAxisLabels(0,
data1.length/(1.0/interval)); //to get second of
computation
xAxis2 = AxisLabelsFactory.newAxisLabels("Seconds", 50.0);
}
else if(scaleIn == HOUR){
5.1. JAVA CODE 59
xAxis = AxisLabelsFactory.newNumericRangeAxisLabels(0,
data1.length/(3600/interval)); //to get hour of
computation
xAxis2 = AxisLabelsFactory.newAxisLabels("Hours", 50.0);
}
else
xAxis = AxisLabelsFactory.newNumericRangeAxisLabels(0,
data1.length/(1/interval)); //to get second of
computation
xAxis2 = AxisLabelsFactory.newAxisLabels("Seconds", 50.0);
log.severe("Scale in parameter: " + scaleIn + " not valid;
possible use: " + MINUTE + " for minute, "
+ SECOND + " for seconds and " + HOUR + " for hour.
Used Seconds.");
}
else{
if(scaleIn == MINUTE){
xAxis = AxisLabelsFactory.newNumericRangeAxisLabels(0,
data2.length/(60/interval)); //to get minute of
computation
xAxis2 = AxisLabelsFactory.newAxisLabels("Minutes", 50.0);
}
else if(scaleIn == SECOND){
xAxis = AxisLabelsFactory.newNumericRangeAxisLabels(0,
data2.length/(1.0/interval)); //to get second of
computation
xAxis2 = AxisLabelsFactory.newAxisLabels("Seconds", 50.0);
}
else if(scaleIn == HOUR){
xAxis = AxisLabelsFactory.newNumericRangeAxisLabels(0,
data2.length/(3600/interval)); //to get hour of
computation
xAxis2 = AxisLabelsFactory.newAxisLabels("Hours", 50.0);
}
else{
xAxis = AxisLabelsFactory.newNumericRangeAxisLabels(0,
data2.length/(1.0/interval)); //to get second of
computation
xAxis2 = AxisLabelsFactory.newAxisLabels("Seconds",
50.0);
log.severe("Scale in parameter: " + scaleIn + " not valid;
possible use: " + MINUTE + " for minute, "
+ SECOND + " for seconds and " + HOUR + " for hour.
Used Seconds.");
}
}
xAxis2.setAxisStyle(AxisStyle.newAxisStyle(Color.newColor("000000"),
14, AxisTextAlignment.CENTER));
AxisLabels yAxis2 = AxisLabelsFactory.newAxisLabels(yLabel,
50.0);
60 CONTENTS
yAxis2.setAxisStyle(AxisStyle.newAxisStyle(Color.newColor("000000"),
14, AxisTextAlignment.CENTER));
// Adding axis info to chart.
chart.addXAxisLabels(xAxis);
chart.addXAxisLabels(xAxis2);
chart.addYAxisLabels(yAxis);
chart.addYAxisLabels(yAxis2);
// Defining background and chart fills.
chart.setBackgroundFill(Fills.newSolidFill(Color.newColor("e8e8e8")));
chart.setAreaFill(Fills.newSolidFill(Color.newColor("ffffff")));
this.url = chart.toURLString();
log.info("Url for Chart generated...");
}
/**
* Generates all chart(data1 and all data2) in one chart.
* To generate complex charts the library ’charts4j’
* has problem becouse max request that googleApi could
* support is 2048 URL length. Then for multilines chart
* This class uses JFreeChart(http://www.jfree.org/).
* @param data1
* @param interval
* @param scaleIn
* @param isPercentage
* @param data2
* @param title
* @param data1Title
* @param yLabel
* @param isGrayScale
* @param isDashedLine
* @param fileName
*/
private void generateChart(double[] data1, int interval, int scaleIn,
boolean isPercentage, ArrayList<double[]> data2, String title,
String data1Title, String yLabel, boolean isGrayScale, boolean
isDashedLine,String output, String fileName){
JFreeChartGenerator myJFreeChart = new JFreeChartGenerator();
this.url = myJFreeChart.getChart(data1, interval, scaleIn,
isPercentage, data2, title, data1Title, yLabel, isGrayScale,
isDashedLine, output, fileName);
}
/**
* This method return max lenght between data1 and
* all list in data2.
* @param data1
* @param data2
* @return
5.1. JAVA CODE 61
*/
private int getMax(double[] data1, ArrayList<double[]> data2) {
int lengthMax = data1.length;
for(double[] data: data2){
if(data.length > lengthMax)
lengthMax = data1.length;
}
return lengthMax;
}
/**
* This method create chart from dstat Csv input.
* @param dstatFilePath
* @param columnDesired
* @param oneForLine if it’s true the columns desired will be plot in
different lines;
* else they will be sum.
* @param title
* @param lineName
* @param isPercentage if it’s true the y value will be scaled in %
* @param yLabel label of y axis
* @param scaleIn could be minute, second or hour and indicates
interval to show on x
* @param isGrayScale to choice greyscale mode
* @param isDashedLine to choice dashed line mode
* @return URL of generated chart
*/
public String getChart(String dstatFilePath, ArrayList<String>
columnDesired, String title, String lineName, boolean
isPercentage, String yLabel, int scaleIn, boolean isGreyScale,
boolean isDashedLine){
Parser p = new Parser();
ArrayList<String> result = new ArrayList<String>();
result = p.getDataFromCsv(dstatFilePath, columnDesired);
double[] dataGenerated = p.generateDoubleArrayFrom(result,
ChartGenerator.SUM);
generateChart(dataGenerated,
p.getRecordsIntervalFromCsv(dstatFilePath), scaleIn,
isPercentage, title, lineName, yLabel, isGreyScale,
isGreyScale);
Chart_sCollector.addChart(new Chart(title, lineName,
dataGenerated, yLabel, getUrl()));
return getUrl();
}
/**
* Create chart for dstatFilePath and add one line for
* each columnDesired.
* @param dstatFilePath
* @param columnDesired
62 CONTENTS
* @param oneForLine
* @param title
* @param lineName
* @param lineName2
* @param isPercentage
* @param yLabel
* @param scaleIn
* @param isGreyScale
* @param isDashedLine
* @return
*/
public String getChart(String dstatFilePath, ArrayList<String>
columnDesired, boolean oneForLine, String title, String lineName,
String lineName2, boolean isPercentage, double toDivide, String
yLabel, int scaleIn, boolean isGreyScale, boolean isDashedLine){
Parser p = new Parser();
ArrayList<String> result = new ArrayList<String>();
ArrayList<String> result2 = new ArrayList<String>();
//*****************************//
//to use method already present I define 2 arraylist for each line
//one for first columnDesired and another for the other.
ArrayList<String> columnDesiredFirst = new ArrayList<String>();
columnDesiredFirst.add(columnDesired.get(0));
ArrayList<String> columnDesiredSecond = new ArrayList<String>();
columnDesiredSecond.add(columnDesired.get(1));
//****************************//
result = p.getDataFromCsv(dstatFilePath, columnDesiredFirst);
result2 = p.getDataFromCsv(dstatFilePath, columnDesiredSecond);
double[] usageFirstCol = p.generateDoubleArrayFrom(result,
ChartGenerator.SUM);
usageFirstCol = divideAllFor(usageFirstCol, toDivide);
double[] usageSecondCol = p.generateDoubleArrayFrom(result2,
ChartGenerator.SUM);
usageSecondCol = divideAllFor(usageSecondCol, toDivide);
generateChart(usageFirstCol,
p.getRecordsIntervalFromCsv(dstatFilePath), scaleIn,
isPercentage, usageSecondCol, title, lineName, lineName2,
yLabel, isGreyScale, isDashedLine);
return getUrl();
}
/**
* This method generate chart from 2 csv input file.
* @param dstatFilePath1
* @param dstatFilePath2
* @param columnDesired
* @param title
* @param line1Name
* @param line2Name
* @param isPercentage if it’s true the y value will be scaled in %
5.1. JAVA CODE 63
* @param yLabel label of y axis
* @param scaleIn could be minute, second or hour and indicates
interval to show on x
* @param isGrayScale to choice greyscale mode
* @param isDashedLine to choice dashed line mode
* @return URL of generated chart
*/
public String getChart(String dstatFilePath1, String dstatFilePath2,
ArrayList<String> columnDesired, String title, String line1Name,
String line2Name, boolean isPercentage, double toDivide, String
yLabel, int scaleIn, boolean isGreyScale, boolean isDashedLine){
Parser p = new Parser();
ArrayList<String> result = new ArrayList<String>();
ArrayList<String> result2 = new ArrayList<String>();
result = p.getDataFromCsv(dstatFilePath1, columnDesired);
result2 = p.getDataFromCsv(dstatFilePath2, columnDesired);
double[] cpuUsageValueMaster = p.generateDoubleArrayFrom(result,
ChartGenerator.SUM);
cpuUsageValueMaster = divideAllFor(cpuUsageValueMaster, toDivide);
double[] cpuUsageValueSlave = p.generateDoubleArrayFrom(result2,
ChartGenerator.SUM);
cpuUsageValueSlave = divideAllFor(cpuUsageValueSlave, toDivide);
generateChart(cpuUsageValueMaster,
p.getRecordsIntervalFromCsv(dstatFilePath1), scaleIn,
isPercentage, cpuUsageValueSlave, title, line1Name, line2Name,
yLabel, isGreyScale, isDashedLine);
Chart_sCollector.addChart(new Chart(title, dstatFilePath1,
cpuUsageValueMaster, yLabel, getUrl()));
Chart_sCollector.addChart(new Chart(title, dstatFilePath2,
cpuUsageValueSlave, yLabel, getUrl()));
return getUrl();
}
/**
* This method compare first dstatFile with the average of
dstatFileList.
* all lines.
* @param dstatFilePath1
* @param dstatFileList
* @param columnDesired
* @param title
* @param line1Name
* @param line2Name
* @param isPercentage if it’s true the y value will be scaled in %
* @param yLabel label of y axis
* @param scaleIn could be minute, second or hour and indicates
interval to show on x
* @param isGrayScale to choice grey scale mode
* @param isDashedLine to choice dashed line mode
* @return URL of generated chart
64 CONTENTS
*/
public String getChart(String dstatFilePath1, ArrayList<String>
dstatFileList, ArrayList<String> columnDesired, String title,
String line1Name, String line2Name, boolean isPercentage, double
toDivide, String yLabel, int scaleIn, boolean isGreyScale,
boolean isDashedLine){
Parser p = new Parser();
ArrayList<String> result = new ArrayList<String>();
ArrayList<String> result2 = new ArrayList<String>();
result = p.getDataFromCsv(dstatFilePath1, columnDesired);
double[] cpuUsageValueMaster = p.generateDoubleArrayFrom(result,
ChartGenerator.SUM);
cpuUsageValueMaster = divideAllFor(cpuUsageValueMaster, toDivide);
ArrayList<double[]> slave_sUsage = new ArrayList<double[]>();
for (String dstatFile: dstatFileList){
result2 = p.getDataFromCsv(dstatFile, columnDesired);
double[] tmpSlave = p.generateDoubleArrayFrom(result2,
ChartGenerator.SUM);
tmpSlave = divideAllFor(tmpSlave, toDivide);
slave_sUsage.add(tmpSlave);
}
double[] slaveDouble_Average = getAverage(p, slave_sUsage);
generateChart(cpuUsageValueMaster,
p.getRecordsIntervalFromCsv(dstatFilePath1), scaleIn,
isPercentage, slaveDouble_Average , title, line1Name,
line2Name, yLabel, isGreyScale, isDashedLine);
return getUrl();
}
/**
* This method will generate all charts in one.
* @param dstatFilePath1
* @param dstatFileList
* @param columnDesired
* @param title
* @param line1Name
* @param line2Name
* @param isPercentage
* @param yLabel
* @param scaleIn
* @param isGreyScale
* @param isDashedLine
* @param outputPath
* @param outputFileName
* @return
*/
public String getChart(String dstatFilePath1, ArrayList<String>
dstatFileList, ArrayList<String> columnDesired, String title,
String line1Name, String line2Name, boolean isPercentage, double
toDivide, String yLabel, int scaleIn, boolean isGreyScale,
5.1. JAVA CODE 65
boolean isDashedLine, String outputPath, String fileName){
Parser p = new Parser();
ArrayList<String> result = new ArrayList<String>();
ArrayList<String> result2 = new ArrayList<String>();
result = p.getDataFromCsv(dstatFilePath1, columnDesired);
double[] cpuUsageValueMaster = p.generateDoubleArrayFrom(result,
ChartGenerator.SUM);
cpuUsageValueMaster = divideAllFor(cpuUsageValueMaster, toDivide);
ArrayList<double[]> slave_sUsage = new ArrayList<double[]>();
for (String dstatFile: dstatFileList){
result2 = p.getDataFromCsv(dstatFile, columnDesired);
double[] tmpSlave = p.generateDoubleArrayFrom(result2,
ChartGenerator.SUM);
tmpSlave = divideAllFor(tmpSlave, toDivide);
slave_sUsage.add(tmpSlave);
}
generateChart(cpuUsageValueMaster,
p.getRecordsIntervalFromCsv(dstatFilePath1), scaleIn,
isPercentage, slave_sUsage, title, line1Name, yLabel,
isGreyScale, isDashedLine, outputPath, fileName);
return getUrl();
}
/**
* Divides all element in input array for
* double toDivide value.
* @param doubleList
* @param toDivide
* @return
*/
private double[] divideAllFor(double[] doubleList, double toDivide) {
for(int i=0; i<doubleList.length; i++)
doubleList[i] = doubleList[i]/toDivide;
return doubleList;
}
private double[] getAverage(Parser p, ArrayList<double[]>
slave_sUsage) {
//get size of min slave file(we need first of the max)
int maxRecordSize = 0;
for(double[] record: slave_sUsage){
if (record.length > maxRecordSize) maxRecordSize =
record.length;
}
int minRecordSize = maxRecordSize;
for(double[] record: slave_sUsage){
if (record.length < minRecordSize) minRecordSize =
record.length;
}
ArrayList<String> averageSlave_s = new ArrayList<String>();
66 CONTENTS
for (int i=0; i<minRecordSize; i++){
double average_i = 0;
for(int k=0; k<slave_sUsage.size(); k++){
average_i += slave_sUsage.get(k)[i];
}
average_i = average_i/slave_sUsage.size();
averageSlave_s.add(average_i + "");
}
double[] cpuUsageValueSlave =
p.generateDoubleArrayFrom(averageSlave_s);
return cpuUsageValueSlave;
}
/**
* Return max value of input array.
* @param data array of double.
* @return
*/
private double getMax(double[] data){
if (data.length == 0)
return 0;
double max = data[0];
for(int i=0; i<data.length; i++){
if(data[i]>max)
max = data[i];
}
if(max == 0)
return IF_ZERO;
return max;
}
/**
* Return max value of inputs array.
* @param data1 array of double.
* @param data2 array of double.
* @return
*/
private double getMax(double[] data1, double[] data2) {
double max1 = getMax(data1);
double max2 = getMax(data2);
if(max1 > max2){
if(max1 == 0)
return IF_ZERO;
return max1;
}
if(max2 == 0)
return IF_ZERO;
return max2;
}
}
5.1. JAVA CODE 67
5.1.3 JFreeChartGenerator
La classe ’JFreeChartGenerator.java’ consente di generare grafici personalizz-abili a seconda delle esigenze dell’utente. Tale classe e stata utilizzata per lamodalita di grafici ’AllIn’ ovvero contenenti tutti gli slave ed il master nellostesso grafico.
package chartsGenerators;
import java.awt.BasicStroke;
import java.awt.Color;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.logging.Logger;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.category.LineAndShapeRenderer;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.Range;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import com.orsoncharts.util.Scale2D;
/**
*
* @author Romano Simone - www.sromano.altervista.org
* To generate complex charts the library ’charts4j’
* has problem becouse max request that googleApi could
* support is 2048 URL length. Then for multilines chart
* This class uses JFreeChart(http://www.jfree.org/).
*/
public class JFreeChartGenerator{
private static String OUTPUT_FOLDER_NAME = "png_charts";
private static Logger log = Logger.getLogger("global");
public static int MINUTE = 5, SECOND = 6, HOUR = 7;
/**
* Creates a chart dataset.
* @return chart dataset.
68 CONTENTS
*/
private XYDataset createDataset(double[] data1, ArrayList<double[]>
data2, int interval, int scaleIn, String data1Title) {
XYSeriesCollection dataset = new XYSeriesCollection();
XYSeries firstChart = new XYSeries(data1Title);
double distanceBetweenPoints = 0.0;
if (scaleIn == MINUTE)
distanceBetweenPoints = 100.0/60.0/(double)interval;
if (scaleIn == SECOND)
distanceBetweenPoints = 100.0/1.0/(double)interval;
if (scaleIn == HOUR)
distanceBetweenPoints = 100.0/3600.0/(double)interval;
//creating dataset for first chart
double actualPoint = 0.0;
for (double y:data1){
firstChart.add(actualPoint, y);
actualPoint += distanceBetweenPoints;
}
dataset.addSeries(firstChart);
//creating dataste for others dataset
actualPoint = 0.0;
int i=1;
for(double[] data:data2){
XYSeries tmp = new XYSeries("Slave_" + i);
i++;
for(double y:data){
tmp.add(actualPoint, y);
actualPoint += distanceBetweenPoints;
}
dataset.addSeries(tmp);
actualPoint = 0.0;
}
return dataset;
}
/**
* Create JFreeChart from input dataset
* @param dataset
* @return
*/
private JFreeChart createChart(XYDataset dataset, String title, int
scaleIn, String yLabel, boolean isPercentage, boolean
isDashedLine) {
// create the chart...
String xAxis = checkXAxis(scaleIn);
final JFreeChart chart = ChartFactory.createXYLineChart(
title, // chart title
5.1. JAVA CODE 69
xAxis, // x axis label
yLabel, // y axis label
dataset, // data
PlotOrientation.VERTICAL,
true, // include legend
true, // tooltips
false // urls
);
// NOW DO SOME OPTIONAL CUSTOMISATION OF THE CHART...
chart.setBackgroundPaint(Color.white);
XYPlot plot = chart.getXYPlot();
plot.setBackgroundPaint(Color.lightGray);
plot.setDomainGridlinePaint(Color.white);
plot.setRangeGridlinePaint(Color.white);
if (isDashedLine){
XYLineAndShapeRenderer renderer = (XYLineAndShapeRenderer)
plot.getRenderer();
for (int i=0; i<dataset.getSeriesCount(); i++)
renderer.setSeriesStroke(
i, new BasicStroke(
1.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND,
1.0f, new float[] {5.0f, 3.0f}, 0.0f
)
);
}
NumberAxis range = (NumberAxis) plot.getRangeAxis();
range.setLowerBound(0);
if (isPercentage)
plot.getRangeAxis().setRange(new Range(0, 100), false, true);
return chart;
}
private String checkXAxis(int scaleIn) {
String xAxis = "";
if (scaleIn == MINUTE)
xAxis = "Minutes";
if (scaleIn == SECOND)
xAxis = "Seconds";
if (scaleIn == HOUR)
xAxis = "Hours";
return xAxis;
}
private String createImg(JFreeChart chart, String outputPath, String
fileName) {
//createOutputDir
File dir = new File(outputPath + File.separator +
JFreeChartGenerator.OUTPUT_FOLDER_NAME);
70 CONTENTS
dir.mkdir();
String outputFilePath =outputPath + File.separator +
OUTPUT_FOLDER_NAME + File.separator + fileName + ".png";
File fileImg = new File(outputFilePath);
try {
ChartUtilities.saveChartAsPNG(fileImg, chart, 600, 400);
} catch (IOException e) {
log.severe("Error creating JFreeChart img: " + e.getMessage());
e.printStackTrace();
}
log.info("JFreeChart img created...");
return outputFilePath;
}
/**
* This method make chart and returns its path.
* @return
*/
public String getChart(double[] data1, int interval, int scaleIn,
boolean isPercentage, ArrayList<double[]> data2, String title,
String data1Title, String yLabel, boolean isGrayScale, boolean
isDashedLine, String outputPath, String fileName){
XYDataset dataset = createDataset(data1, data2, interval, scaleIn,
data1Title);
JFreeChart chart = createChart(dataset, title, scaleIn, yLabel,
isPercentage, isDashedLine);
String outputFile = createImg(chart, outputPath, fileName);
return outputFile;
}
}
5.2 R code
Di seguito sono elencati gli script R.
5.2.1 chart generator.R
Questo script consente di generare file pdf con grafici che mostrano l’andamentodelle macchine del cluster.
# require(scales)
# require(ggplot2)
# require(plyr)
# library(reshape2)
# library(xlsx)
loadLibrary <- function(lib){
5.2. R CODE 71
if(require(package = lib, character.only = TRUE, lib.loc=".")){
print(paste(lib,"is loaded correctly", sep= " "))
} else {
print(paste("trying to install ", lib, sep = " "))
install.packages(lib, lib=".", dependencies = TRUE)
if(require(package = lib, character.only = TRUE, lib.loc=".")){
print(paste(lib,"installed and loaded", sep = " "))
} else {
stop(paste("could not install", lib, sep = " "))
}
}
}
r <- getOption("repos") # hard code the US repo for CRAN
r["CRAN"] <- "http://cran.us.r-project.org"
options(repos = r)
#Sys.setenv(JAVA_HOME=’C:\\Program Files\\Java\\jre1.8.0_25’)
#loadLibrary("rJava")
loadLibrary("colorspace")
loadLibrary("scales")
loadLibrary("ggplot2")
loadLibrary("plyr")
loadLibrary("reshape2")
# install.packages("colorspace", lib=".", dependencies = TRUE)
# install.packages("ggplot2", lib=".", dependencies = TRUE)
#library(ggplot2, lib.loc=".")
cbind.fill <- function(...) {
transpoted <- lapply(list(...),t)
transpoted_dataframe <- lapply(transpoted, as.data.frame)
return (data.frame(t(rbind.fill(transpoted_dataframe))))
}
mettiVirgolaCsv <-function(path){
for(file in list.files(path = path, pattern = "*.csv$")){
file = paste(path, file, sep="")
prova = readLines(file)
if(length(grep(pattern = "\"#send\"," , x = prova[7])) == 0){
#print("diverso")
prova[7] = paste(prova[7], ",", sep="")
write(x = prova, file = file)
}
}
}
plotSingleNodeOther <- function(tipologiaTempo,dstat, value,.e, len,
xlabel ,ylabel, colorLine, title, geom_color, printTitle = TRUE,
colorType = color, ylimits = NULL, lineDash = FALSE,fontSize =
NULL, fontFamily = NULL){
72 CONTENTS
print(title)
p = ggplot(dstat, aes(dstat), environment = environment())
for(val in value){
p = p + geom_line(aes(x = len, y = eval(parse(text=val)), colour =
geom_color[1]))
}
if(length(value) == 1){
if(lineDash == TRUE) {
p = p + geom_line(aes(x = len, y = eval(parse(text=value[1])),
colour = geom_color[1]), linetype = "dotted")
}
else
p = p + geom_line(aes(x = len, y = eval(parse(text=value[1])),
colour = geom_color[1]))
}
else{
if(lineDash == TRUE){
p = p + geom_line(aes(x = len, y = eval(parse(text=value[1])),
colour = geom_color[1]))
p = p + geom_line(aes(x = len, y = eval(parse(text=value[2])),
colour = geom_color[2]), linetype = "dotted")
}
else{
p = p + geom_line(aes(x = len, y = eval(parse(text=value[1])),
colour = geom_color[1]))
p = p + geom_line(aes(x = len, y = eval(parse(text=value[2])),
colour = geom_color[2]))
}
}
p = p + xlab(xlabel)
p = p + ylab(ylabel)
p = p + labs(color="Legend")
p = p + scale_x_continuous(expand = c(0, 0))
if(!is.null(ylimits)){
p = p + scale_y_continuous(limits=ylimits ,expand = c(0, 0))
}
else{
p = p + scale_y_continuous(expand = c(0, 0))
}
if(length(value) == 1){
if(colorType == 0){
p = p + scale_color_manual(values="black")
}
else if(colorType == 1){
p = p + scale_color_manual(values="red")
}
}
else{
if(colorType == 0){
5.2. R CODE 73
p = p + scale_color_manual(values=c("black", "grey"))
}
else if(colorType == 1){
}
}
p = p + theme(legend.position = "top",
panel.grid.major.y = element_line(colour = "black"),
panel.background = element_rect(fill = ’white’, colour
= ’black’),
panel.grid.major.x = element_blank(),
panel.grid.minor.x = element_blank(),
axis.text = element_text(colour = "black" ,
size = fontSize))
if(printTitle){
p = p + ggtitle(title)
}
print(p)
}
takeDelay <- function(fileInput){
file = readLines(con = fileInput)
a = sub(".*csv ", "", file[4])
a = sub("\".*","", a)
a = as.numeric(a)
return <- a
}
average <- function(campo, ylabel, tipologiaTempo = "s", colorType,
printTitle = TRUE, fontSize = fontSize, ylimits = NULL){
.e <- environment()
for(file in list.files(inputFile, pattern = "*.csv$")){
title = file
file = paste(inputFile, file, sep = "")
if(length(grep(pattern = "master" , x = file)) == 1){
dstat <- read.csv(file, skip=6)
dstat <- subset(dstat, select = -X)
dstat <- dstat[-1,]
if(length(campo) != 1){
campoEval = 0
for(val in campo){
campoEval = campoEval + eval(parse(text=val))
}
master = data.frame(campoEval)
}
else{
master <- eval(parse(text=campo))
74 CONTENTS
}
}
else{
dstat <- read.csv(file, skip=6)
dstat <- subset(dstat, select = -X)
dstat <- dstat[-1,]
if(length(campo) != 1){
campoEval = 0
for(val in campo){
campoEval = campoEval + eval(parse(text=val))
}
if(exists("cpu")){
cpu <- cbind.fill(cpu, campoEval)
}
else{
cpu <- campoEval
}
}
else{
campoEval = eval(parse(text=campo))
if(exists("cpu")){
cpu <- cbind.fill(cpu, campoEval)
}
else{
cpu <- campoEval
}
}
}
}
cpu = cbind(cpu, NA)
cpu[,dim(cpu)[2]] = rowMeans(x = cpu, na.rm = TRUE)
cpu <- cbind.fill(cpu, master)
delayDSTAT = takeDelay(file)
if(tipologiaTempo == "s"){
len <- seq(0,dim(cpu)[1]-1) * delayDSTAT
xlabel = "Time (s)"
}
else if(tipologiaTempo == "m"){
len <- (seq(0,dim(cpu)[1]-1) * delayDSTAT) / 60
xlabel = "Time (m)"
}
else if(tipologiaTempo == "h"){
len <- ((seq(0,dim(cpu)[1]-1) * delayDSTAT) / 60) / 60
xlabel = "Time (h)"
}
plotSingleNodeOther(tipologiaTempo,cpu, c("dstat[, dim(dstat)[2]-1]",
5.2. R CODE 75
"dstat[, dim(dstat)[2]]"), .e , len, xlabel ,ylabel, colorLine,
title = "Average", c("slave", "master"), printTitle, colorType,
ylimits = ylimits,fontSize = fontSize)
}
AllNodes <- function(campo, ylabel, tipologiaTempo = "s", colorType,
ylimits = NULL ,printTitle = TRUE, fontSize){
.e <- environment()
for(file in list.files(inputFile, pattern = "*.csv$")){
title = file
file = paste(inputFile, file, sep = "")
delayDSTAT = takeDelay(file)
dstat <- read.csv(file, skip=6)
dstat <- subset(dstat, select = -X)
dstat <- dstat[-1,]
if(length(grep(pattern = "master" , x = file)) == 1){
if(length(campo) != 1){
campoEval = 0
for(val in campo){
campoEval = campoEval + eval(parse(text=val))
}
master = data.frame(campoEval)
}
else{
master <- eval(parse(text=campo))
}
}
else{
if(length(campo) != 1){
campoEval = 0
for(val in campo){
campoEval = campoEval + eval(parse(text=val))
}
if(exists("cpu")){
cpu <- cbind.fill(cpu, campoEval)
}
else{
cpu <- campoEval
}
}
else{
campoEval = eval(parse(text=campo))
if(exists("cpu")){
cpu <- cbind.fill(cpu, campoEval)
}
else{
cpu <- campoEval
}
}
76 CONTENTS
}
}
cpu <- cbind.fill(cpu, master)
names(cpu) <- tolower(names(cpu))
#cambiamo i nomi alle colonne con SlaveN e Master
for(numeroColonna in 1:ncol(cpu)-1) {
variabile <- paste ("Slave", numeroColonna, sep = "", collapse =
NULL)
colnames(cpu)[numeroColonna] <- variabile
}
colnames(cpu)[dim(cpu)[2]] <- "Master"
cpu = cbind(cpu, seq(1, dim(cpu)[1]))
colnames(cpu)[dim(cpu)[2]] <- paste("times")
aql <- melt(cpu, id.vars = "times")
nrow = round(dim(cpu)[2] / 12)
if(nrow == 0){
nrow = 1
}
if(tipologiaTempo == "s"){
aql$times <- aql$times * delayDSTAT
xlabel = "Time (s)"
}
else if(tipologiaTempo == "m"){
aql$times <- (aql$times * delayDSTAT) / 60
xlabel = "Time (m)"
}
else if(tipologiaTempo == "h"){
aql$times <- ((aql$times * delayDSTAT) / 60) / 60
xlabel = "Time (h)"
}
p = ggplot(aql, aes(times,value, col=variable))
p = p + geom_line()
p = p + xlab(xlabel)
p = p + ylab(ylabel)
p = p + labs(color="Legend")
p = p + scale_x_continuous(expand = c(0, 0))
p = p + guides(col = guide_legend(nrow = nrow))
p = p + theme(legend.position = "top",
panel.grid.major.y = element_line(colour = "black"),
panel.background = element_rect(fill = ’white’, colour =
’black’),
panel.grid.major.x = element_blank(),
panel.grid.minor.x = element_blank(),
axis.text = element_text(colour = "black" ,
size = fontSize))
if(!is.null(ylimits)){
p = p + scale_y_continuous(limits=ylimits ,expand = c(0, 0))
}
5.2. R CODE 77
else{
p = p + scale_y_continuous(expand = c(0, 0))
}
title = "All Nodes"
if(printTitle){
p = p + ggtitle(title)
}
print(p)
}
singleNode <- function(tipologiaTempo, value, value2 = NULL,ylabel,
geom_color ,printTitle, colorType, lineDash, ylimits, fontSize){
for(file in list.files(inputFile, pattern = "*.csv$")){
title = file
file = paste(inputFile, file, sep = "")
delayDSTAT = takeDelay(file)
dstat <- read.csv(file, skip=6)
dstat <- subset(dstat, select = -X)
dstat <- dstat[-1,]
.e <- environment()
if(tipologiaTempo == "s"){
len <- (seq(0,length(dstat$used)-1) * delayDSTAT)
xlabel = "Time (s)"
}
else if(tipologiaTempo == "m"){
len <- (seq(0,length(dstat$used)-1) * delayDSTAT) / 60
xlabel = "Time (m)"
}
else if(tipologiaTempo == "h"){
len <- ((seq(0,length(dstat$used)-1) * delayDSTAT) / 60) / 60
xlabel = "Time (h)"
}
if(is.null(value2)){
if(length(value) != 1){
campoEval = 0
for(val in value){
campoEval = campoEval + eval(parse(text=val))
}
campoEval = data.frame(campoEval)
#YLIMITS MANCANTE
plotSingleNodeOther(tipologiaTempo = tipologiaTempo, dstat =
campoEval, value = "dstat$campoEval", .e = .e, len =
len,xlabel = xlabel ,ylabel = ylabel,colorLine =
colorLine,title = title ,geom_color = geom_color, printTitle
= printTitle, colorType = colorType, ylimits = ylimits,
lineDash = lineDash ,fontSize = fontSize)
}
78 CONTENTS
else{
#YLIMITS MANCANTE
plotSingleNodeOther(tipologiaTempo,dstat, value,.e, len, xlabel
,ylabel, colorLine, title, geom_color, printTitle,
colorType, ylimits = ylimits, lineDash = lineDash, fontSize
= fontSize)
}
}
else{
#YLIMITS MANCANTE
plotSingleNodeOther(tipologiaTempo = tipologiaTempo, dstat,value =
c(value,value2), .e = .e, len = len,xlabel = xlabel ,ylabel =
ylabel,colorLine = colorLine,title = title ,geom_color =
geom_color, printTitle = printTitle, colorType = colorType,
ylimits = ylimits,lineDash = lineDash ,fontSize = fontSize)
}
}
}
result <- tryCatch({
input = readLines(’./R_script/input.hla’)
tempo = input[1] #sostituito
color = as.numeric(input[2]) #sostituito
dash = as.logical(input[3]) #sostituito
titoli = as.logical(input[4]) #sostituito
oneFilePdf = as.logical(input[5])
graphType = as.numeric(input[6]) #fatta divisione tra SINGOLI, MEDIE,
TUTTI
CPUType = input[7] #splittato in stringhe
RAMType = input[8] #splittato in stringhe
Upperbound_RAM = input[9] #fatto
IOType = as.numeric(input[10]) #la divisione e’ solo nei singoli, FATTA
PagingType = as.numeric(input[11]) #la divisione e’ solo nei singoli,
FATTA
NetType = as.numeric(input[12]) #la divisione e’ solo nei singoli, FATTA
NPacketType = as.numeric(input[13]) #la divisione e’ solo nei singoli,
FATTA
font = as.numeric(input[14]) #sostituito
inputFile <<- input[15]
output = input[16]
if(CPUType[1] == "NULL"){
CPUType = NULL
}else {
CPUType = strsplit(CPUType, split = " ")
CPUType = CPUType[[1]]
}
if(RAMType[1] == "NULL"){
RAMType = NULL
5.2. R CODE 79
}else{
RAMType = strsplit(RAMType, split = " ")
RAMType = RAMType[[1]]
}
if(Upperbound_RAM == "NULL"){
Upperbound_RAM = NULL
} else{
Upperbound_RAM = as.numeric(Upperbound_RAM)
Upperbound_RAM = c(0, Upperbound_RAM)
}
ylimits = Upperbound_RAM
#tipologiaTempo valori = "s" "m" "h"
#combCPU "" o c("dstat$usr", dstat$sys) combinazione dei campi cpu
#combRAM "" o c("dstat$used", dstat$free) combinazione dei campi RAM
#tipologiaColori 0 = grigi, 1 = colorati, 2 = linee diverse
#printTitle TRUE, FALSE
mettiVirgolaCsv(inputFile)
if(graphType == 1){
singleOutput = paste(output, "SinglePlot.pdf", sep = "")
multiOutput = paste(output, "SinglePlot%04d.pdf", sep = "")
pdf(file = ifelse(oneFilePdf, singleOutput, multiOutput), width = 10,
onefile = oneFilePdf)
#CPU
if(is.null(CPUType)){
singleNode(tipologiaTempo = tempo, value = "dstat$usr", ylabel = "CPUs
Usr(%)", geom_color= "cpu", printTitle = titoli, colorType =
color, ylimits = NULL, lineDash = dash, fontSize = font)
singleNode(tipologiaTempo = tempo, value = "dstat$sys", ylabel = "CPUs
Sys(%)", geom_color= "cpu", printTitle = titoli, colorType =
color, ylimits = NULL, lineDash = dash, fontSize = font)
singleNode(tipologiaTempo = tempo, value = "dstat$idl", ylabel = "CPUs
Idl(%)", geom_color= "cpu", printTitle = titoli, colorType =
color, ylimits = NULL, lineDash = dash, fontSize = font)
singleNode(tipologiaTempo = tempo, value = "dstat$wai", ylabel = "CPUs
Wai(%)", geom_color= "cpu", printTitle = titoli, colorType =
color, ylimits = NULL, lineDash = dash, fontSize = font)
singleNode(tipologiaTempo = tempo, value = "dstat$hiq", ylabel = "CPUs
Hiq(%)", geom_color= "cpu", printTitle = titoli, colorType =
color, ylimits = NULL, lineDash = dash, fontSize = font)
singleNode(tipologiaTempo = tempo, value = "dstat$siq", ylabel = "CPUs
Siq(%)", geom_color= "cpu", printTitle = titoli, colorType =
color, ylimits = NULL, lineDash = dash, fontSize = font)
}
else{
singleNode(tipologiaTempo = tempo, value = CPUType, ylabel = "CPUs
(%)", geom_color= "cpu", printTitle = titoli, colorType = color,
ylimits = NULL, lineDash = dash, fontSize = font)
}
#MEMORIA
80 CONTENTS
if(is.null(RAMType)){
singleNode(tipologiaTempo = tempo, value = "dstat$used/1048576",
ylabel = "Memory Used (MB)", geom_color= "memory", printTitle =
titoli, colorType = color, ylimits = ylimits, lineDash = dash,
fontSize = font)
singleNode(tipologiaTempo = tempo, value = "dstat$buff/1048576",
ylabel = "Memory Buff (MB)", geom_color= "memory", printTitle =
titoli, colorType = color, ylimits = ylimits, lineDash = dash,
fontSize = font)
singleNode(tipologiaTempo = tempo, value = "dstat$cach/1048576",
ylabel = "Memory Cach (MB)", geom_color= "memory", printTitle =
titoli, colorType = color, ylimits = ylimits, lineDash = dash,
fontSize = font)
singleNode(tipologiaTempo = tempo, value = "dstat$free/1048576",
ylabel = "Memory Free (MB)", geom_color= "memory", printTitle =
titoli, colorType = color, ylimits = ylimits, lineDash = dash,
fontSize = font)
} else{
singleNode(tipologiaTempo = tempo, value = RAMType, ylabel = "Memory
(MB)", geom_color= "memory", printTitle = titoli, colorType =
color, ylimits = ylimits, lineDash = dash, fontSize = font)
}
#PAGING
if(PagingType == 1){
singleNode(tipologiaTempo = tempo, value = "dstat$in.", ylabel =
"Paging in", geom_color= "in", printTitle = titoli, colorType =
color, ylimits = NULL, lineDash = dash, fontSize = font)
singleNode(tipologiaTempo = tempo, value = "dstat$out", ylabel =
"Paging out", geom_color= "out", printTitle = titoli, colorType
= color, ylimits = NULL, lineDash = dash, fontSize = font)
} else if(PagingType == 2){
singleNode(tipologiaTempo = tempo, value = "dstat$in.", value2 =
"dstat$out", ylabel = "Paging", geom_color= c("in", "out"),
printTitle = titoli, colorType = color, ylimits = NULL, lineDash
= dash, fontSize = font)
}
#SWAP
singleNode(tipologiaTempo = tempo, value = "dstat$used.1/1048576",
ylabel = "Swap (MB)", geom_color= "swap", printTitle = titoli,
colorType = color, ylimits = NULL, lineDash = dash, fontSize =
font)
#DISCO
if(IOType == 1){
singleNode(tipologiaTempo = tempo, value = "dstat$read/1048576",
ylabel = "Disk Usage Read (MB/s)", geom_color= "read",
printTitle = titoli, colorType = color, ylimits = NULL, lineDash
= dash, fontSize = font)
singleNode(tipologiaTempo = tempo, value = "dstat$writ/1048576",
ylabel = "Disk Usage Write (MB/s)", geom_color= "write",
5.2. R CODE 81
printTitle = titoli, colorType = color, ylimits = NULL, lineDash
= dash, fontSize = font)
} else if(IOType == 2){
singleNode(tipologiaTempo = tempo, value = "dstat$writ/1048576",
value2 = "dstat$read/1048576", ylabel = "Disk Usage (MB/s)",
geom_color= c("read", "write"), printTitle = titoli, colorType =
color, ylimits = NULL, lineDash = dash, fontSize = font)
}
#RETE - MB
if(NetType == 1){
singleNode(tipologiaTempo = tempo, value = "dstat$recv/1048576",
ylabel = "Net Usage Receive (MB/s)", geom_color= "received",
printTitle = titoli, colorType = color, ylimits = NULL, lineDash
= dash, fontSize = font)
singleNode(tipologiaTempo = tempo, value = "dstat$send/1048576",
ylabel = "Net Usage Send (MB/s)", geom_color= "sent", printTitle
= titoli, colorType = color, ylimits = NULL, lineDash = dash,
fontSize = font)
} else if(NetType == 2){
singleNode(tipologiaTempo = tempo, value = "dstat$recv", value2 =
"dstat$send",ylabel = "Network Usage (MB)", geom_color=
c("recv", "sent"), printTitle = titoli, colorType = color,
ylimits = NULL, lineDash = dash, fontSize = font)
}
#RETE - PACCHETTI
if(NPacketType == 1){
singleNode(tipologiaTempo = tempo, value = "dstat$X.recv", ylabel =
"Net Packets Receive (#)", geom_color= "Pks. received",
printTitle = titoli, colorType = color, ylimits = NULL, lineDash
= dash, fontSize = font)
singleNode(tipologiaTempo = tempo, value = "dstat$X.send", ylabel =
"Net Packets Send (#)", geom_color= "Pks. sent", printTitle =
titoli, colorType = color, ylimits = NULL, lineDash = dash,
fontSize = font)
} else if(NPacketType == 2){
singleNode(tipologiaTempo = tempo, value = "dstat$X.send", value2 =
"dstat$X.recv", ylabel = "Net Packets (#)", geom_color= c("Pks.
received", "Pks. sent"), printTitle = titoli, colorType = color,
ylimits = NULL, lineDash = dash, fontSize = font)
}
#INTERRUPT
#singleNode(tipologiaTempo = tempo, value = "dstat$int", ylabel =
"Interrupts (#)", geom_color= "Interrupts", printTitle = titoli,
colorType = color, lineDash = dash, fontSize = font)
#CONTEXT SWITCHES
#singleNode(tipologiaTempo = tempo, value = "dstat$csw", ylabel =
"Context Switches (#)", geom_color= "Context Switches",
printTitle = titoli, colorType = color, lineDash = dash, fontSize
82 CONTENTS
= font)
dev.off()
} else if(graphType == 2){
singleOutput = paste(output, "AveragePlot.pdf", sep = "")
multiOutput = paste(output, "AveragePlot%04d.pdf", sep = "")
pdf(file = ifelse(oneFilePdf, singleOutput, multiOutput), width = 10,
onefile = oneFilePdf)
if(is.null(CPUType)){
average("dstat$usr", ylabel = "CPUs Usr (%)", tipologiaTempo =
tempo, colorType = color, printTitle = titoli, fontSize = font,
ylimits = NULL)
average("dstat$sys", ylabel = "CPUs Sys (%)", tipologiaTempo =
tempo, colorType = color, printTitle = titoli, fontSize = font,
ylimits = NULL)
average("dstat$idl", ylabel = "CPUs Idl (%)", tipologiaTempo =
tempo, colorType = color, printTitle = titoli, fontSize = font,
ylimits = NULL)
average("dstat$wai", ylabel = "CPUs Wai (%)", tipologiaTempo =
tempo, colorType = color, printTitle = titoli, fontSize = font,
ylimits = NULL)
average("dstat$hiq", ylabel = "CPUs Hiq (%)", tipologiaTempo =
tempo, colorType = color, printTitle = titoli, fontSize = font,
ylimits = NULL)
average("dstat$siq", ylabel = "CPUs Siq (%)", tipologiaTempo =
tempo, colorType = color, printTitle = titoli, fontSize = font,
ylimits = NULL)
} else{
average(campo = CPUType, ylabel = "CPUs (%)", tipologiaTempo =
tempo, colorType = color, printTitle = titoli, fontSize = font)
}
if(is.null(RAMType)){
average("dstat$used/1048576", ylabel = "Memory Used (MB/s)",
tipologiaTempo = tempo, colorType = color, printTitle = titoli,
fontSize = font, ylimits = ylimits)
average("dstat$buff/1048576", ylabel = "Memory Buffer (MB/s)",
tipologiaTempo = tempo, colorType = color, printTitle = titoli,
fontSize = font, ylimits = ylimits)
average("dstat$cach/1048576", ylabel = "Memory Cache (MB/s)",
tipologiaTempo = tempo, colorType = color, printTitle = titoli,
fontSize = font, ylimits = ylimits)
average("dstat$free/1048576", ylabel = "Memory Free (MB/s)",
tipologiaTempo = tempo, colorType = color, printTitle = titoli,
fontSize = font, ylimits = ylimits)
} else{
average(campo = RAMType, ylabel = "Memory (MB/s)", tipologiaTempo =
tempo, colorType = color, printTitle = titoli, fontSize = font,
5.2. R CODE 83
ylimits = ylimits)
}
average("dstat$in./1048576", ylabel = "Paging In", tipologiaTempo =
tempo, colorType = color, printTitle = titoli, fontSize = font,
ylimits = NULL)
average("dstat$out/1048576", ylabel = "Paging Out", tipologiaTempo =
tempo, colorType = color, printTitle = titoli, fontSize = font,
ylimits = NULL)
average("dstat$used.1/1048576", ylabel = "Swap (MB)", tipologiaTempo =
tempo, colorType = color, printTitle = titoli, fontSize = font,
ylimits = NULL)
average("dstat$read/1048576", ylabel = "Disk usage Read (MB/s)",
tipologiaTempo = tempo, colorType = color, printTitle = titoli,
fontSize = font, ylimits = NULL)
average("dstat$writ/1048576", ylabel = "Disk usage Write (MB/s)",
tipologiaTempo = tempo, colorType = color, printTitle = titoli,
fontSize = font, ylimits = NULL)
average("dstat$recv/1048576", ylabel = "Net Usage Received (MB/s)",
tipologiaTempo = tempo, colorType = color, printTitle = titoli,
fontSize = font, ylimits = NULL)
average("dstat$send/1048576", ylabel = "Net Usage Sent (MB/s)",
tipologiaTempo = tempo, colorType = color, printTitle = titoli,
fontSize = font, ylimits = NULL)
average("dstat$X.recv", ylabel = "Packets Received (#)",
tipologiaTempo = tempo, colorType = color, printTitle = titoli,
fontSize = font, ylimits = NULL)
average("dstat$X.send", ylabel = "Packets Sent (#)", tipologiaTempo =
tempo, colorType = color, printTitle = titoli, fontSize = font,
ylimits = NULL)
dev.off()
average("dstat$int", ylabel = "Interrupts (#)", tipologiaTempo =
tempo, colorType = color, printTitle = titoli, fontSize = font)
average("dstat$csw", ylabel = "Context Switches (#)", tipologiaTempo =
tempo, colorType = color, printTitle = titoli, fontSize = font)
} else if(graphType == 3){
singleOutput = paste(output, "AllNodesPlot.pdf", sep = "")
multiOutput = paste(output, "AllNodesPlot%04d.pdf", sep = "")
pdf(file = ifelse(oneFilePdf, singleOutput, multiOutput), width = 10,
onefile = oneFilePdf)
if(is.null(CPUType)){
AllNodes("dstat$usr", ylabel = "CPUs Usr (%)", tipologiaTempo =
tempo, colorType = color, ylimits = NULL, printTitle = titoli,
fontSize = font)
AllNodes("dstat$sys", ylabel = "CPUs Sys (%)", tipologiaTempo =
84 CONTENTS
tempo, colorType = color, ylimits = NULL, printTitle = titoli,
fontSize = font)
AllNodes("dstat$idl", ylabel = "CPUs Idl (%)", tipologiaTempo =
tempo, colorType = color, ylimits = NULL, printTitle = titoli,
fontSize = font)
AllNodes("dstat$wai", ylabel = "CPUs Wai (%)", tipologiaTempo =
tempo, colorType = color, ylimits = NULL, printTitle = titoli,
fontSize = font)
AllNodes("dstat$hiq", ylabel = "CPUs Hiq (%)", tipologiaTempo =
tempo, colorType = color, ylimits = NULL, printTitle = titoli,
fontSize = font)
AllNodes("dstat$siq", ylabel = "CPUs Siq (%)", tipologiaTempo =
tempo, colorType = color, ylimits = NULL, printTitle = titoli,
fontSize = font)
}else{
AllNodes(CPUType, ylabel = "CPUs (%)", tipologiaTempo = tempo,
colorType = color, ylimits = NULL, printTitle = titoli, fontSize
= font)
}
if(is.null(RAMType)){
AllNodes("dstat$used/1048576", ylabel = "Memory Used (MB/s)",
tipologiaTempo = tempo, colorType = color, printTitle = titoli,
fontSize = font, ylimits = ylimits)
AllNodes("dstat$buff/1048576", ylabel = "Memory Buffer (MB/s)",
tipologiaTempo = tempo, colorType = color, printTitle = titoli,
fontSize = font, ylimits = ylimits)
AllNodes("dstat$cach/1048576", ylabel = "Memory Cache (MB/s)",
tipologiaTempo = tempo, colorType = color, printTitle = titoli,
fontSize = font, ylimits = ylimits)
AllNodes("dstat$free/1048576", ylabel = "Memory Free (MB/s)",
tipologiaTempo = tempo, colorType = color, printTitle = titoli,
fontSize = font, ylimits = ylimits)
} else{
AllNodes(RAMType, ylabel = "Memory (MB/s)", tipologiaTempo = tempo,
colorType = color, printTitle = titoli, fontSize = font, ylimits
= ylimits)
}
AllNodes("dstat$in./1048576", ylabel = "Paging In", tipologiaTempo =
tempo, colorType = color, ylimits = NULL, printTitle = titoli,
fontSize = font)
AllNodes("dstat$out/1048576", ylabel = "Paging Out", tipologiaTempo =
tempo, colorType = color, ylimits = NULL, printTitle = titoli,
fontSize = font)
AllNodes("dstat$used.1/1048576", ylabel = "Swap (MB)", tipologiaTempo
= tempo, colorType = color, ylimits = NULL, printTitle = titoli,
fontSize = font)
AllNodes("dstat$read/1048576", ylabel = "Disk usage Read (MB/s)",
tipologiaTempo = tempo, colorType = color, ylimits = NULL,
5.2. R CODE 85
printTitle = titoli, fontSize = font)
AllNodes("dstat$writ/1048576", ylabel = "Disk usage Write (MB/s)",
tipologiaTempo = tempo, colorType = color, ylimits = NULL,
printTitle = titoli, fontSize = font)
AllNodes("dstat$recv/1048576", ylabel = "Net Usage Received (MB/s)",
tipologiaTempo = tempo, colorType = color, ylimits = NULL,
printTitle = titoli, fontSize = font)
AllNodes("dstat$send/1048576", ylabel = "Net Usage Sent (MB/s)",
tipologiaTempo = tempo, colorType = color, ylimits = NULL,
printTitle = titoli, fontSize = font)
AllNodes("dstat$X.recv", ylabel = "Packets Received (#)",
tipologiaTempo = tempo, colorType = color, ylimits = NULL,
printTitle = titoli, fontSize = font)
AllNodes("dstat$X.send", ylabel = "Packets Sent (#)", tipologiaTempo =
tempo, colorType = color, ylimits = NULL, printTitle = titoli,
fontSize = font)
AllNodes("dstat$int", ylabel = "Interrupts (#)", tipologiaTempo =
tempo, colorType = color, printTitle = titoli, fontSize = font)
AllNodes("dstat$csw", ylabel = "Context Switches (#)", tipologiaTempo
= tempo, colorType = color, printTitle = titoli, fontSize = font)
dev.off()
}
}, error = function(err){
print(paste("MY_ERROR: ", err))
})
5.2.2 excel.R
Questo script consente di generare file pdf con grafici che mostrano l’andamentodelle macchine del cluster.
input = readLines(’./R_script/inputExcel.hla’)
inputFile <<- input[1]
output <<- input[2]
loadLibrary <- function(lib){
if(require(package = lib, character.only = TRUE, lib.loc=".")){
print(paste(lib,"is loaded correctly", sep= " "))
} else {
print(paste("trying to install ", lib, sep = " "))
install.packages(lib, lib=".", dependencies = TRUE)
if(require(package = lib, character.only = TRUE, lib.loc=".")){
print(paste(lib,"installed and loaded", sep = " "))
} else {
stop(paste("could not install", lib, sep = " "))
86 CONTENTS
}
}
}
r <- getOption("repos") # hard code the US repo for CRAN
r["CRAN"] <- "http://cran.us.r-project.org"
options(repos = r)
loadLibrary("openxlsx")
loadLibrary("methods")
takeDelay <- function(fileInput){
file = readLines(con = fileInput)
a = sub(".*csv ", "", file[4])
a = sub("\".*","", a)
a = as.numeric(a)
return <- a
}
createXLS <- function(){
.e <- environment()
fileOutput = output
if(file.exists(fileOutput)) {
file.remove(fileOutput)
}
for(file in list.files(inputFile, pattern = "*.csv$")){
file = paste(inputFile, file, sep = "")
delayDSTAT = takeDelay(file)
dstat <- read.csv(file, skip=6)
dstat <- subset(dstat, select = -X)
dstat <- dstat[-1,]
if(length(grep(pattern = "master" , x = file)) == 1){
cpuMasterUsr <- dstat$usr
cpuMasterSys <- dstat$sys
cpuMasterIdl <- dstat$idl
cpuMasterWai <- dstat$wai
cpuMasterHiq <- dstat$hiq
cpuMasterSiq <- dstat$siq
memoryMasterUsed <- dstat$used/1048576
memoryMasterBuff <- dstat$buff/1048576
memoryMasterCach <- dstat$cach/1048576
memoryMasterFree <- dstat$free/1048576
swapMaster <- dstat$used.1/1048576
discoReadMaster <- dstat$read/1048576
discoWriteMaster <- dstat$writ/1048576
pacchettiRicevutiMaster <- dstat$X.recv
pacchettiInviatiMaster <- dstat$X.send
5.2. R CODE 87
throughputReteRicevutiMaster <- dstat$recv/1048576
throughputReteInviatiMaster <- dstat$send/1048576
dstatMediaCPUMasterUsr <- mean(cpuMasterUsr)
dstatMediaCPUMasterSys <- mean(cpuMasterSys)
dstatMediaCPUMasterIdl <- mean(cpuMasterIdl)
dstatMediaCPUMasterWai <- mean(cpuMasterWai)
dstatMediaCPUMasterHiq <- mean(cpuMasterHiq)
dstatMediaCPUMasterSiq <- mean(cpuMasterSiq)
dstatMediaMemoriaMasterUsed <- mean(memoryMasterUsed)
dstatMediaMemoriaMasterBuff <- mean(memoryMasterBuff)
dstatMediaMemoriaMasterCach <- mean(memoryMasterCach)
dstatMediaMemoriaMasterFree <- mean(memoryMasterFree)
dstatMediaSwapMaster <- mean(swapMaster)
dstatMediaDiscoReadMaster <- mean(discoReadMaster)
dstatMediaDiscoWriteMaster <- mean(discoWriteMaster)
dstatMediaPacchettiRicevutiMaster <- mean(pacchettiRicevutiMaster)
dstatMediaPacchettiInviatiMaster <- mean(pacchettiInviatiMaster)
dstatMediaThroughputReteRicevutiMaster <-
mean(throughputReteRicevutiMaster)
dstatMediaThroughputReteInviatiMaster <-
mean(throughputReteInviatiMaster)
}
else{
#CPU
if(exists("cpuUsr")){
cpuUsr <- cbind(cpuUsr, dstat$usr)
}
else {
cpuUsr <- dstat$usr
}
if(exists("cpuSys")){
cpuSys <- cbind(cpuSys, dstat$sys)
}
else {
cpuSys <- dstat$sys
}
if(exists("cpuIdl")){
cpuIdl <- cbind(cpuIdl, dstat$idl)
}
else {
cpuIdl <- dstat$idl
}
if(exists("cpuWai")){
cpuWai <- cbind(cpuWai, dstat$wai)
}
else {
cpuWai <- dstat$wai
88 CONTENTS
}
if(exists("cpuHiq")){
cpuHiq <- cbind(cpuHiq, dstat$hiq)
}
else {
cpuHiq <- dstat$hiq
}
if(exists("cpuSiq")){
cpuSiq <- cbind(cpuSiq, dstat$siq)
}
else {
cpuSiq <- dstat$siq
}
if(exists("dstatMediaCPUUsr"))
dstatMediaCPUUsr <- cbind(dstatMediaCPUUsr, mean(cpuUsr))
else {
dstatMediaCPUUsr <- cbind(mean(cpuUsr))
}
if(exists("dstatMediaCPUSys"))
dstatMediaCPUSys <- cbind(dstatMediaCPUSys, mean(cpuSys))
else {
dstatMediaCPUSys <- cbind(mean(cpuSys))
}
if(exists("dstatMediaCPUIdl"))
dstatMediaCPUIdl <- cbind(dstatMediaCPUIdl, mean(cpuIdl))
else {
dstatMediaCPUIdl <- cbind(mean(cpuIdl))
}
if(exists("dstatMediaCPUWai"))
dstatMediaCPUWai <- cbind(dstatMediaCPUWai, mean(cpuWai))
else {
dstatMediaCPUWai <- cbind(mean(cpuWai))
}
if(exists("dstatMediaCPUHiq"))
dstatMediaCPUHiq <- cbind(dstatMediaCPUHiq, mean(cpuHiq))
else {
dstatMediaCPUHiq <- cbind(mean(cpuHiq))
}
if(exists("dstatMediaCPUSiq"))
dstatMediaCPUSiq <- cbind(dstatMediaCPUSiq, mean(cpuSiq))
else {
dstatMediaCPUSiq <- cbind(mean(cpuSiq))
}
#MEMORIA
if(exists("memoryUsed")) {
memoryUsed <- cbind(memoryUsed, dstat$used/1048576)
}
else {
memoryUsed <- dstat$used/1048576
5.2. R CODE 89
}
if(exists("memoryBuff")) {
memoryBuff <- cbind(memoryBuff, dstat$buff/1048576)
}
else {
memoryBuff <- dstat$buff/1048576
}
if(exists("memoryCach")) {
memoryCach <- cbind(memoryCach, dstat$cach/1048576)
}
else {
memoryCach <- dstat$cach/1048576
}
if(exists("memoryFree")) {
memoryFree <- cbind(memoryFree, dstat$free/1048576)
}
else {
memoryFree <- dstat$free/1048576
}
if(exists("dstatMediaMemoriaUsed"))
dstatMediaMemoriaUsed <- cbind(dstatMediaMemoriaUsed,
mean(memoryUsed))
else {
dstatMediaMemoriaUsed <- cbind(mean(memoryUsed))
}
if(exists("dstatMediaMemoriaBuff"))
dstatMediaMemoriaBuff <- cbind(dstatMediaMemoriaBuff,
mean(memoryBuff))
else {
dstatMediaMemoriaBuff <- cbind(mean(memoryBuff))
}
if(exists("dstatMediaMemoriaCach"))
dstatMediaMemoriaCach <- cbind(dstatMediaMemoriaCach,
mean(memoryCach))
else {
dstatMediaMemoriaCach <- cbind(mean(memoryCach))
}
if(exists("dstatMediaMemoriaFree"))
dstatMediaMemoriaFree <- cbind(dstatMediaMemoriaFree,
mean(memoryFree))
else {
dstatMediaMemoriaFree <- cbind(mean(memoryFree))
}
#SWAP
if(exists("swap")) {
swap <- cbind(swap, dstat$used.1/1048576)
}
90 CONTENTS
else {
swap <- dstat$used.1/1048576
}
if(exists("dstatMediaSwap"))
dstatMediaSwap <- cbind(dstatMediaSwap, mean(swap))
else {
dstatMediaSwap <- cbind(mean(swap))
}
#DISCO READ
if(exists("discoRead")) {
discoRead <- cbind(discoRead, dstat$read/1048576)
}
else {
discoRead <- dstat$read/1048576
}
if(exists("dstatMediaDiscoRead"))
dstatMediaDiscoRead <- cbind(dstatMediaDiscoRead,
mean(discoRead))
else {
dstatMediaDiscoRead <- cbind(mean(discoRead))
}
#DISCO WRITE
if(exists("discoWrite")) {
discoWrite <- cbind(discoWrite, dstat$writ/1048576)
}
else {
discoWrite <- dstat$writ/1048576
}
if(exists("dstatMediaDiscoWrite"))
dstatMediaDiscoWrite <- cbind(dstatMediaDiscoWrite,
mean(discoWrite))
else {
dstatMediaDiscoWrite <- cbind(mean(discoWrite))
}
#PACCHETTI RICEVUTI
if(exists("pacchettiRicevuti")) {
pacchettiRicevuti <- cbind(pacchettiRicevuti, dstat$X.recv)
}
else {
pacchettiRicevuti <- dstat$X.recv
}
if(exists("dstatMediaPacchettiRicevuti"))
dstatMediaPacchettiRicevuti <-
cbind(dstatMediaPacchettiRicevuti, mean(pacchettiRicevuti))
else {
dstatMediaPacchettiRicevuti <- cbind(mean(pacchettiRicevuti))
}
#PACCHETTI INVIATI
if(exists("pacchettiInviati")) {
pacchettiInviati <- cbind(pacchettiInviati, dstat$X.send)
5.2. R CODE 91
}
else {
pacchettiInviati <- dstat$X.send
}
if(exists("dstatMediaPacchettiInviati"))
dstatMediaPacchettiInviati <- cbind(dstatMediaPacchettiInviati,
mean(pacchettiInviati))
else {
dstatMediaPacchettiInviati <- cbind(mean(pacchettiInviati))
}
#THROUGHPUT RETE RICEVUTI
if(exists("throughputReteRicevuti")) {
throughputReteRicevuti <- cbind(throughputReteRicevuti,
dstat$recv/1048576)
}
else {
throughputReteRicevuti <- dstat$recv/1048576
}
if(exists("dstatMediaThroughputReteRicevuti"))
dstatMediaThroughputReteRicevuti <-
cbind(dstatMediaThroughputReteRicevuti,
mean(throughputReteRicevuti))
else {
dstatMediaThroughputReteRicevuti <-
cbind(mean(throughputReteRicevuti))
}
#THROUGHPUT RETE INVIATI
if(exists("throughputReteInviati")) {
throughputReteInviati <- cbind(throughputReteInviati,
dstat$send/1048576)
}
else {
throughputReteInviati <- dstat$send/1048576
}
if(exists("dstatMediaThroughputReteInviati"))
dstatMediaThroughputReteInviati <-
cbind(dstatMediaThroughputReteInviati,
mean(throughputReteInviati))
else {
dstatMediaThroughputReteInviati <-
cbind(mean(throughputReteInviati))
}
}
}
listMasterDstat =
list(cpuMasterUsr,cpuMasterSys,cpuMasterIdl,cpuMasterWai,cpuMasterHiq,cpuMasterSiq,memoryMasterUsed,
memoryMasterBuff, memoryMasterCach, memoryMasterFree,swapMaster,
discoReadMaster, discoWriteMaster,
pacchettiRicevutiMaster, pacchettiInviatiMaster,
92 CONTENTS
throughputReteRicevutiMaster,
throughputReteInviatiMaster)
listDstat = list(cpuUsr,cpuSys,
cpuIdl,cpuWai,cpuHiq,cpuSys,memoryUsed, memoryBuff,
memoryCach,memoryFree, swap, discoRead, discoWrite,
pacchettiRicevuti, pacchettiInviati,
throughputReteRicevuti, throughputReteInviati)
for(j in 1:17) {
listDstat[[j]] <- cbind(listMasterDstat[[j]], listDstat[[j]])
for(numeroColonna in 2:ncol(listDstat[[j]])) {
variabile <- paste ("Slave", numeroColonna-1, sep = "", collapse =
NULL)
colnames(listDstat[[j]])[numeroColonna] <- variabile
}
listDstat[[j]] <- cbind(seq(delayDSTAT,
nrow(listDstat[[j]])*delayDSTAT, delayDSTAT), listDstat[[j]])
colnames(listDstat[[j]])[1] <- "Tempo"
colnames(listDstat[[j]])[2] <- "Master"
}
dstatMedieCPUUsr <- cbind(dstatMediaCPUMasterUsr, dstatMediaCPUUsr)
dstatMedieCPUSys <- cbind(dstatMediaCPUMasterSys, dstatMediaCPUSys)
dstatMedieCPUIdl <- cbind(dstatMediaCPUMasterIdl, dstatMediaCPUIdl)
dstatMedieCPUWai <- cbind(dstatMediaCPUMasterWai, dstatMediaCPUWai)
dstatMedieCPUHiq <- cbind(dstatMediaCPUMasterHiq, dstatMediaCPUHiq)
dstatMedieCPUSiq <- cbind(dstatMediaCPUMasterSiq, dstatMediaCPUSiq)
dstatMedieMemoriaUsed <- cbind(dstatMediaMemoriaMasterUsed,
dstatMediaMemoriaUsed)
dstatMedieMemoriaBuff <- cbind(dstatMediaMemoriaMasterBuff,
dstatMediaMemoriaBuff)
dstatMedieMemoriaCach <- cbind(dstatMediaMemoriaMasterCach,
dstatMediaMemoriaCach)
dstatMedieMemoriaFree <- cbind(dstatMediaMemoriaMasterFree,
dstatMediaMemoriaFree)
dstatMedieSwap <- cbind(dstatMediaSwapMaster, dstatMediaSwap)
5.2. R CODE 93
dstatMedieDiscoRead <- cbind(dstatMediaDiscoReadMaster,
dstatMediaDiscoRead)
dstatMedieDiscoWrite <- cbind(dstatMediaDiscoWriteMaster,
dstatMediaDiscoWrite)
dstatMediePacchettiRicevuti <-
cbind(dstatMediaPacchettiRicevutiMaster,
dstatMediaPacchettiRicevuti)
dstatMediePacchettiInviati <- cbind(dstatMediaPacchettiInviatiMaster,
dstatMediaPacchettiInviati)
dstatMedieThroughputReteRicevuti <-
cbind(dstatMediaThroughputReteRicevutiMaster,
dstatMediaThroughputReteRicevuti)
dstatMedieThroughputReteInviati <-
cbind(dstatMediaThroughputReteInviatiMaster,
dstatMediaThroughputReteInviati)
dstatMedieTotali <-
rbind(dstatMedieCPUUsr,dstatMedieCPUSys,dstatMedieCPUIdl,dstatMedieCPUWai,dstatMedieCPUHiq,dstatMedieCPUSiq,
dstatMedieMemoriaUsed,dstatMedieMemoriaBuff,dstatMedieMemoriaCach,dstatMedieMemoriaFree,dstatMedieSwap,dstatMedieDiscoRead,
dstatMedieDiscoWrite,dstatMediePacchettiRicevuti,dstatMediePacchettiInviati,
dstatMedieThroughputReteRicevuti,dstatMedieThroughputReteInviati)
colnames(dstatMedieTotali)[1] <- "Master"
dstatMediaNomi = rbind("CPU USR","CPU SYS","CPU IDL","CPU WAI","CPU
HIQ","CPU SIQ","MEMORIA USED","MEMORIA BUFF","MEMORIA
CACH","MEMORIA FREE","SWAP","DISCO LETTURA","DISCO SCRITTURA",
"PACCHETTI RETE RICEVUTI","PACCHETTI RETE
INVIATI",
"THROUGHPUT RETE RICEVUTI","THROUGHPUT RETE
INVIATI")
dstatMedieTotali = cbind(dstatMediaNomi, dstatMedieTotali)
colnames(dstatMedieTotali)[1] <- "Informazione"
for(numeroColonna in 3:ncol(dstatMedieTotali)) {
variabile <- paste ("Slave", numeroColonna-2, sep = "", collapse =
NULL)
colnames(dstatMedieTotali)[numeroColonna] <- variabile
}
output = paste(output, "excelDstat", sep="")
l = list("CPU USR" = listDstat[[1]], "CPU SYS" = listDstat[[2]], "CPU
IDL" = listDstat[[3]], "CPU WAI" = listDstat[[4]], "CPU HIQ" =
listDstat[[5]], "CPU SIQ" = listDstat[[6]], "MEMORIA USED" =
listDstat[[7]], "MEMORIA BUFF" = listDstat[[8]], "MEMORIA CACH" =
listDstat[[9]], "MEMORIA FREE" = listDstat[[10]], "SWAP" =
listDstat[[11]], "DISCO LETTURA" = listDstat[[12]], "DISCO
SCRITTURA" = listDstat[[13]], "PACCHETTI RICEVUTI" =
listDstat[[14]], "PACCHETTI INVIATI" = listDstat[[15]],
"THROUGHPUT RETE RICEVUTI" = listDstat[[16]], "THROUGHPUT RETE
INVIATI" = listDstat[[17]], "Aggregato" = dstatMedieTotali)
94 CONTENTS
write.xlsx(x = l, file = output, colNames = TRUE)
}
result <- tryCatch({
createXLS()
}, error = function(err){
print(paste("MY_ERROR: ", err))
})
5.2.3 graphHadoopGenerator.R
Questo script consente di generare il pdf con il grafico relativo alla timeline deitask di Hadoop
#require(ggplot2)
#library(XML)
#library(intervals)
argv <- commandArgs(trailingOnly = TRUE)
print("Inizialiting Environment...")
loadLibrary <- function(lib){
if(require(package = lib, character.only = TRUE, lib.loc=".")){
print(paste(lib,"is loaded correctly", sep= " "))
} else {
print(paste("trying to install ", lib, sep = " "))
install.packages(lib, lib=".", dependencies = TRUE)
if(require(package = lib, character.only = TRUE, lib.loc=".")){
print(paste(lib,"installed and loaded", sep = " "))
} else {
stop(paste("could not install", lib, sep = " "))
}
}
}
r <- getOption("repos") # hard code the US repo for CRAN
r["CRAN"] <- "http://cran.us.r-project.org"
options(repos = r)
#Sys.setenv(JAVA_HOME=’C:\\Program Files\\Java\\jre1.8.0_25’)
loadLibrary("ggplot2")
loadLibrary("XML")
loadLibrary("intervals")
printf <- function(...)print(sprintf(...))
print("Progress..")
tablehead = c("startTime", "finishTime", "elapsedTime", "progress",
"id", "rack", "state", "status", "nodeHttpAddress", "diagnostics",
"type", "assignedContainerId")
for(file in list.files(argv[1])) {
file = paste(argv[1], file, sep = "")
5.2. R CODE 95
content = readLines(file)
pagetree <- xmlInternalTreeParse(content, error=function(...){},
useInternalNodes = TRUE)
tablehead = c("StartTime", "FinishTime", "ElapsedTime", "Progress",
"Attempt", "Rack", "State", "Status", "Node", "Note", "Type",
"AssignedContainerId")
tablebody = xpathSApply(pagetree, "//*/taskAttempt/*", xmlValue)
if(length(tablebody) == 0){
next;
}
tabella = matrix(tablebody, ncol = length(tablehead), byrow = TRUE)
newframe = data.frame(tabella)
colnames(newframe) <- tablehead
newframe <- subset(newframe, select =
c(Attempt,State,Status,Node,StartTime,FinishTime,ElapsedTime,Note))
if(exists("miaVariabile")){
miaVariabile <- rbind(miaVariabile, newframe)
}else{
miaVariabile <- newframe
}
}
miaVariabile$StartTime =
levels(miaVariabile$StartTime)[miaVariabile$StartTime]
#miaVariabile$StartTime = strptime(miaVariabile$StartTime, "%a, %d %b %Y
%H:%M:%S")
miaVariabile$FinishTime =
levels(miaVariabile$FinishTime)[miaVariabile$FinishTime]
#miaVariabile$FinishTime = strptime(miaVariabile$FinishTime, "%a, %d %b
%Y %H:%M:%S")
miaVariabile$StartTime= as.numeric(miaVariabile$StartTime)
miaVariabile$FinishTime = as.numeric(miaVariabile$FinishTime)
miaVariabile$FinishTime = miaVariabile$FinishTime -
miaVariabile$StartTime
miaVariabile$StartTime = miaVariabile$StartTime -
min(miaVariabile$StartTime)
miaVariabile$FinishTime = miaVariabile$FinishTime +
miaVariabile$StartTime
#importare la libreria Intervals
print("Progress....")
nuovoFrame = subset(x = miaVariabile, select = c(Node, StartTime,
FinishTime))
nuovoFrame = nuovoFrame[with(nuovoFrame, order(Node)), ]
invisible(by(data = nuovoFrame, INDICES = nuovoFrame$Node, FUN =
function(x){
96 CONTENTS
mat = matrix(data = c(x$StartTime, x$FinishTime), ncol = 2)
A = Intervals(mat)
ol <<-interval_overlap(A,A)
# ord <- order(mat[,1], decreasing = TRUE)
# mat = mat[ord,]
#
# print(mat)
#TODO
# interval_overlap(Aint, Aint)
mat1 = mat
mat1 = cbind(mat1, NA)
diff = list()
for(i in 1:dim(mat1)[1]){
diff[[i]] = setdiff(seq(1,dim(mat1)[1]),ol[[i]])
}
num = 0
for(i in 1:length(diff)){
flag = FALSE
visitati = c()
if(is.na(mat1[i,3])){
num = num + 1
mat1[i,3] = num
if(length(diff[[i]]) == 0){
#print("la lunghezza e’ zero")
}
else{
for(j in 1:length(diff[[i]])){
#printf("j = %d", j)
#print(flag)
if(flag == FALSE){
if(is.na(mat1[diff[[i]][j],3])){
mat1[diff[[i]][j],3] = num
#print("mat1")
#printf("mat1[%d][%d] = %d", diff[[i]][j], 3,
mat1[diff[[i]][j],3])
#print(mat1[diff[[i]][j],3])
visitati = c(visitati, diff[[i]][j])
flag = TRUE
}
}
else{
for(l in 1:length(visitati)){
#printf("visitati[%d] = %d", l, visitati[l])
#printf("diff[[%d]][%d] = %d", i, l, diff[[i]][j])
differenza = setdiff(diff[[i]][visitati[l]], diff[[i]][j])
5.2. R CODE 97
#print("differenza")
#print(differenza)
if(length(differenza) == 0){
#print("ok la differenza e’ 0 e posso aggiungere sulla
stessa linea")
if(is.na(mat1[diff[[i]][j],3])){
mat1[diff[[i]][j],3] = num
visitati = c(visitati, diff[[i]][j])
}
}
}
}
}
}
}
}
print("Progress......")
#mat1 = cbind(levels(x$Node), mat1)
#print(x$Node)
#print(mat1)
if(!exists("matComp")){
matComp <<- mat1
} else{
matComp <<- rbind(matComp,mat1)
}
}
))
frameP = data.frame(matComp)
frameP = cbind(frameP, nuovoFrame$Node)
frameP = cbind(frameP, miaVariabile$State)
colnames(frameP) = c("StartTime", "FinishTime", "LineNumber", "Node",
"State")
frameP$Node = sub(".*/","",frameP$Node)
frameP$Node = sub(":.*","", frameP$Node)
frameP$Node = paste(frameP$Node, "/")
frameP$Node = paste(frameP$Node, frameP$LineNumber)
# ggplot(frameP, aes(colour=State)) +
# geom_segment(aes(x=StartTime, xend=FinishTime, y=Node, yend=Node),
size=6, position = "identity", lineend = "round") +
# xlab("Duration")
plotLogHadoop <- function(tipologiaTempo,dstat, .e, len, title,
printTitle = TRUE, fontSize = NULL){
#print(frameP)
p = ggplot(frameP, aes(colour=State), environment = environment())
p = p + geom_segment(aes(x=StartTime, xend=FinishTime, y=Node,
98 CONTENTS
yend=Node), size=6, position = "identity", lineend = "round")
p = p + xlab("Duration")
p = p + scale_x_continuous(expand = c(0, 0))
#p = p + scale_y_discrete(limits = rev(frameP$Node), expand = c(0.1,0))
p = p + theme(legend.position = "right",
panel.grid.major.y = element_line(colour = "black"),
panel.background = element_rect(fill = ’white’, colour =
’black’),
panel.grid.major.x = element_blank(),
panel.grid.minor.x = element_blank(),
axis.text = element_text(colour = "black" ,
size = fontSize))
if(printTitle){
p = p + ggtitle(title)
}
print(p)
}
output = argv[2]
output = paste(output, "hadoopGraph.pdf", sep = "")
pdf(file = output, width = 10, height = 10)
plotLogHadoop(tipologiaTempo = "s",dstat = frameP, .e = environment(),
title = "Log Hadoop", printTitle = TRUE, fontSize = 10)
invisible(dev.off())
print("Hadoop Graph Generated...Done!")
5.2.4 speedup.R
Questo script consente di generare file pdf con grafici che mostrano l’andamentodello speedup e dell’efficienza del cluster
argv <- commandArgs(trailingOnly = TRUE)
alarm()
loadLibrary <- function(lib){
if(require(package = lib, character.only = TRUE, lib.loc=".")){
print(paste(lib,"is loaded correctly", sep= " "))
} else {
print(paste("trying to install ", lib, sep = " "))
install.packages(lib, lib=".", dependencies = TRUE)
if(require(package = lib, character.only = TRUE, lib.loc=".")){
print(paste(lib,"installed and loaded", sep = " "))
} else {
stop(paste("could not install", lib, sep = " "))
}
}
}
5.2. R CODE 99
r <- getOption("repos") # hard code the US repo for CRAN
r["CRAN"] <- "http://cran.us.r-project.org"
options(repos = r)
#Sys.setenv(JAVA_HOME=’C:\\Program Files\\Java\\jre1.8.0_25’)
#loadLibrary("rJava")
loadLibrary("colorspace")
loadLibrary("scales")
loadLibrary("ggplot2")
loadLibrary("plyr")
loadLibrary("reshape2")
speedUp <- function(TempoSequenziale, VettoreTempiHadoop,
vettoreNodiUsati, output){
su = TempoSequenziale / VettoreTempiHadoop
efficienza = su / vettoreNodiUsati
#plot(vettoreNodiUsati, su, type=c("l"))
df = data.frame(VettoreTempiHadoop, vettoreNodiUsati, su, efficienza)
p = ggplot(df, aes(df), environment = environment())
p = p + geom_line(aes(x = vettoreNodiUsati, y = su), colour = "red")
p = p + xlab("# nodes")
p = p + ylab("Speedup")
p = p + scale_x_continuous(expand = c(0, 0))
p = p + scale_y_continuous(expand = c(0, 0))
p = p + theme(panel.grid.major.y = element_line(colour = "black"),
panel.background = element_rect(fill = ’white’, colour =
’black’),
panel.grid.major.x = element_blank(),
panel.grid.minor.x = element_blank(),
axis.text = element_text(colour = "black"))
p = p + ggtitle("Speedup Chart")
outputSU = paste(output, "speedup_efficiency.pdf", sep = "")
pdf(file = outputSU, width = 10, height = 10)
print(p)
p = ggplot(df, aes(df), environment = environment())
p = p + geom_line(aes(x = vettoreNodiUsati, y = efficienza), colour =
"red")
p = p + xlab("# nodes")
p = p + ylab("Speedup")
p = p + scale_x_continuous(expand = c(0, 0))
p = p + scale_y_continuous(expand = c(0, 0))
p = p + theme(panel.grid.major.y = element_line(colour = "black"),
panel.background = element_rect(fill = ’white’, colour =
’black’),
panel.grid.major.x = element_blank(),
panel.grid.minor.x = element_blank(),
100 CONTENTS
axis.text = element_text(colour = "black"))
p = p + ggtitle("Efficiency Chart")
print(p)
dev.off()
}
result <- tryCatch({
output = argv[1]
dati = as.matrix(read.csv(file = ’./R_script/speedup.hla’, header =
FALSE, sep = ","))
speedUp(TempoSequenziale = dati[3,1], VettoreTempiHadoop = dati[2,],
vettoreNodiUsati = dati[1,], output)
}, error = function(err){
print(paste("MY_ERROR: ", err))
})
5.3 C code
Di seguito sono elencati gli script C.
5.3.1 client.c
Questo script lanciato sul master permette di invocare metodi remoti ai varislave per avviare e stoppare Dstat in maniera parallela
#include "basic.h"
void client_echo(FILE *fp, int sockfd);
int hostname_to_ip(char * , char *);
/***************************************************************************
* gestisci_zombie
* chiama waitpid per eliminare gli zombie.
* Deve essere registrata con signal per il segnale SIGCHLD
***************************************************************************/
void gestisci_zombie(int signo) {
pid_t pid;
int stat;
while ( (pid = waitpid(-1,&stat,WNOHANG)) > 0) {
printf("Child %d terminated\n",pid);
}
}
/***************************************************************************
5.3. C CODE 101
* reti_read
* legge tutti i dati disponibili nel buffer in una sola volta e poi li
* esamina un byte per volta. La read, invece, legge un byte per volta.
***************************************************************************/
ssize_t reti_read(int fd, char *ptr) {
static int read_cnt = 0; /* numero di byte letti */
static char read_buf[MAXLINE]; /* buffer per mantenere i dati
letti */
static char *read_ptr; /* puntatore al prossimo byte da
leggere */
if (read_cnt <= 0) {
/* se non ci sono byte disponibili nel buffer chiama la
read. */
while ( (read_cnt = read(fd, read_buf, sizeof(read_buf)))
< 0)
/* se la read fallisce perch non ci sono sufficienti
dati riprova, altrimenti esce. */
if (errno != EINTR)
return(-1);
if (read_cnt == 0)
return(0);
read_ptr = read_buf;
}
/* legge il prossimo byte dal buffer e decrementa il numero dei
byte
disponibili */
read_cnt--;
*ptr = *read_ptr++;
return(1);
}
ssize_t reti_readline(int fd, void *vptr, size_t maxlen) {
int n, rc;
char c, *ptr;
ptr = vptr;
for (n = 1; n < maxlen; n++) {
if ( (rc = reti_read(fd, &c)) == 1) {
*ptr++ = c;
if (c == ’\n’)
break; /* legge il newline, come la fgets() */
}
else
if (rc == 0) {
if (n == 1)
return(0); /* EOF, non ha letto nulla */
102 CONTENTS
else
break; /* EOF, ha letto qualcosa */
}
else
return(-1); /* errore, errno settato dalla
read() */
}
*ptr = 0; /* inserisce uno 0 per indicare la fine
dell’input, coma la fgets() */
return(n);
/* restituisce il numero di byte letti */
}
/***************************************************************************
* reti_writen
* scrive n byte sul descrittore fd. Riprova fino a quando i dati non
* vengono effettivamenti scritti.
***************************************************************************/
ssize_t reti_writen(int fd, const void *vptr, size_t n) {
size_t nleft; /* byte anora da scrivere */
ssize_t nwritten; /* byte scritti dall’ultima write */
const char *ptr;
ptr = vptr;
nleft = n;
while (nleft > 0) {
if ( (nwritten = write(fd, ptr, nleft)) <= 0) {
if (errno == EINTR)
/* richiama la write se la funzione fallita perch
nel buffer ptr non ci sono sufficienti byte. */
nwritten = 0;
else
return(-1);
}
nleft -= nwritten;
ptr += nwritten;
}
return(n);
/* restituisce il numero di byte scritti. */
}
int main(int argc, char **argv) {
int sockfd, n;
struct sockaddr_in servaddr;
if (argc != 4) {
printf("usage: %s <indirizzoIP> <porta> <comando> \n",argv[0]);
5.3. C CODE 103
exit(1);
}
if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("Socket error\n");
exit(1);
}
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(atoi(argv[2])); /* echo server */
if (inet_pton(AF_INET, argv[1], &servaddr.sin_addr) <= 0) {
char *hostname = argv[1];
char ip[100];
hostname_to_ip(hostname , ip);
printf("%s resolved to %s\n" , hostname , ip);
if(inet_pton(AF_INET,ip,&servaddr.sin_addr) <= 0) {
printf("inet_pton error for %s", argv[1]);
exit(1);
}
}
if (connect(sockfd, (struct sockaddr *) &servaddr, sizeof(servaddr))
< 0) {
printf("connect error");
exit(1);
}
char cmd[80];
strcpy (cmd, argv[3]);
strcat (cmd, "\n");
//printf("comanda abilitati: startDstat, stopDstat, getPid (il pid
viene stampato sul server)\n");
//client_echo(stdin, sockfd); /* svolge tutto il lavoro del client */
char sendline[MAXLINE], recvline[MAXLINE];
reti_writen(sockfd, cmd, strlen(cmd));
if (reti_readline(sockfd, recvline, MAXLINE) == 0) {
printf("%s: server terminated prematurely",__FILE__);
exit(1);
}
fputs(recvline, stdout);
exit(0);
}
104 CONTENTS
void client_echo(FILE *fp, int sockfd) {
char sendline[MAXLINE], recvline[MAXLINE];
while (fgets(sendline, MAXLINE, fp) != NULL) {
reti_writen(sockfd, sendline, strlen(sendline));
if (reti_readline(sockfd, recvline, MAXLINE) == 0) {
printf("%s: server terminated prematurely",__FILE__);
exit(1);
}
fputs(recvline, stdout);
}
}
int hostname_to_ip(char *hostname , char *ip)
{
int sockfd;
struct addrinfo hints, *servinfo, *p;
struct sockaddr_in *h;
int rv;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC; // use AF_INET6 to force IPv6
hints.ai_socktype = SOCK_STREAM;
if ( (rv = getaddrinfo( hostname , "http" , &hints , &servinfo)) !=
0)
{
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
// loop through all the results and connect to the first we can
for(p = servinfo; p != NULL; p = p->ai_next)
{
h = (struct sockaddr_in *) p->ai_addr;
strcpy(ip , inet_ntoa( h->sin_addr ) );
}
freeaddrinfo(servinfo); // all done with this structure
return 0;
}
5.3.2 server.c
Questo script lanciato sugli slave si mette in ascolto in attesa di ordini da partedel master per avviare e stoppare Dstat
5.3. C CODE 105
#include "basic.h"
pid_t server_echo(int sockfd, pid_t pid);
/***************************************************************************
* gestisci_zombie
* chiama waitpid per eliminare gli zombie.
* Deve essere registrata con signal per il segnale SIGCHLD
***************************************************************************/
void gestisci_zombie(int signo) {
pid_t pid;
int stat;
while ( (pid = waitpid(-1,&stat,WNOHANG)) > 0) {
printf("Child %d terminated\n",pid);
}
}
/***************************************************************************
* reti_read
* legge tutti i dati disponibili nel buffer in una sola volta e poi li
* esamina un byte per volta. La read, invece, legge un byte per volta.
***************************************************************************/
ssize_t reti_read(int fd, char *ptr) {
static int read_cnt = 0; /* numero di byte letti */
static char read_buf[MAXLINE]; /* buffer per mantenere i dati
letti */
static char *read_ptr; /* puntatore al prossimo byte da
leggere */
if (read_cnt <= 0) {
/* se non ci sono byte disponibili nel buffer chiama la
read. */
while ( (read_cnt = read(fd, read_buf, sizeof(read_buf)))
< 0)
/* se la read fallisce perch\‘e non ci sono
sufficienti
dati riprova, altrimenti esce. */
if (errno != EINTR)
return(-1);
if (read_cnt == 0)
return(0);
read_ptr = read_buf;
}
/* legge il prossimo byte dal buffer e decrementa il numero dei
byte
disponibili */
106 CONTENTS
read_cnt--;
*ptr = *read_ptr++;
return(1);
}
ssize_t reti_readline(int fd, void *vptr, size_t maxlen) {
int n, rc;
char c, *ptr;
ptr = vptr;
for (n = 1; n < maxlen; n++) {
if ( (rc = reti_read(fd, &c)) == 1) {
*ptr++ = c;
if (c == ’\n’)
break; /* legge il newline, come la fgets() */
}
else
if (rc == 0) {
if (n == 1)
return(0); /* EOF, non ha letto nulla */
else
break; /* EOF, ha letto qualcosa */
}
else
return(-1); /* errore, errno settato dalla
read() */
}
*ptr = 0; /* inserisce uno 0 per indicare la fine
dell’input, coma la fgets() */
return(n);
/* restituisce il numero di byte letti */
}
/***************************************************************************
* reti_writen
* scrive n byte sul descrittore fd. Riprova fino a quando i dati non
* vengono effettivamenti scritti.
***************************************************************************/
ssize_t reti_writen(int fd, const void *vptr, size_t n) {
size_t nleft; /* byte anora da scrivere */
ssize_t nwritten; /* byte scritti dall’ultima write */
const char *ptr;
pid_t childpid;
ptr = vptr;
nleft = n;
while (nleft > 0) {
5.3. C CODE 107
if ( (nwritten = write(fd, ptr, nleft)) <= 0) {
if (errno == EINTR)
/* richiama la write se la funzione \‘e fallita
perch\‘e
nel buffer ptr non ci sono sufficienti byte. */
nwritten = 0;
else
return(-1);
}
nleft -= nwritten;
ptr += nwritten;
}
return(n);
/* restituisce il numero di byte scritti. */
}
int main(int argc, char **argv) {
pid_t childpid;
int listenfd, connfd;
struct sockaddr_in servaddr, cliaddr;
socklen_t cliaddr_len;
char hostname[1024];
hostname[1023] = ’\0’;
gethostname(hostname, 1023);
printf("Hostname: %s\n", hostname);
if (argc != 2) {
printf("Uso: %s <porta>\n",argv[0]);
exit(1);
}
if( (listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
printf("Socket error");
exit(1);
}
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(atoi(argv[1]));
if( (bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr)))
< 0) {
printf("bind error\n");
exit(1);
}
if( listen(listenfd, 5) < 0 ) {
printf("listen error\n");
exit(1);
108 CONTENTS
}
childpid = 0;
for ( ; ; ) {
/*attesa di connessione accetta connessione */
cliaddr_len = sizeof(cliaddr);
if( (connfd = accept(listenfd, (struct sockaddr *) &cliaddr,
&cliaddr_len)) < 0) {
printf("Accept error");
exit(1);
}
childpid = server_echo(connfd, childpid); /* svolge tutto il
lavoro del server */
close(connfd);
}
}
pid_t server_echo(int sockfd, pid_t pid) {
ssize_t n;
char line[MAXLINE];
pid_t childpid;
for ( ; ; ) {
if ( (n = reti_readline(sockfd, line, MAXLINE)) == 0)
return pid; /* connection closed by other
end */
if(strcmp(line, "startDstat\n") == 0){
if( (pid = fork()) == 0 ) {
pid = getpid();
//execl("/usr/bin/dstat",
"/usr/bin/dstat","-tcmgsdny", "--net-packets",
"--float", "--noheaders" ,"--output
/home/user/Scrivania/clientServer/dstatOutput.csv",
"10", (char*) 0);
execl("/usr/bin/dstat", "/usr/bin/dstat","-tcmgsdny",
"--net-packets", "--float", "--noheaders" ,"--output",
"/home/user/Scrivania/clientServer/dstatOutput.csv",
"10", (char*) 0);
}
else
printf("PADRE\n");
}
if(strcmp(line, "getPid\n") == 0){
/*stampa il pid, utile solo per debug*/
printf("Il pid e’ %d\n", pid);
fflush(stdin);
}
if(strcmp(line, "stopDstat\n") == 0){
5.3. C CODE 109
/*uccide il figlio*/
int err = kill(pid, SIGKILL);
pid = 0;
}
if(strcmp(line, "getDstat\n") == 0){
printf("QUI VA LA FUNZIONE CHE PRENDE I VALORI DA
DSTAT\n");
fflush(stdin);
}
reti_writen(sockfd, line, n);
}
}
5.3.3 AllSlaves.c
Questo script lanciato sul master permette di lanciare in modo automatico uncomando su tutti gli slave
#include "basic.h"
int main(int argc, char **argv) {
if (argc != 5) {
printf("Inserire i seguenti parametri: <start> <stop> <porta>
<comando> \n");
exit(1);
}
int start = atoi(argv[1]);
int stop = atoi(argv[2]);
char buf[100];
pid_t pid;
printf("%d %d\n", start, stop);
for(int i = start; i <= stop; i++){
sprintf(buf, "slave%d", i); // puts string into buffer
printf("%s\n", buf);
if( (pid = fork()) == 0 ) {
execl("./echocli","./echocli",buf, argv[3], argv[4],(char*) 0);
exit(0);
}
}
}
Bibliography
[1] JFreeChart http://www.jfree.org/jfreechart/
[2] charts4j https://code.google.com/p/charts4j/
[3] Apache Commons CSV https://commons.apache.org/proper/
commons-csv/
[4] icePdf http://www.icesoft.org/java/home.jsf
[5] Bootstrap http://getbootstrap.com/
[6] Dstat http://dag.wiee.rs/home-made/dstat/
[7] Java profiler http://docs.oracle.com/javase/7/docs/technotes/
samples/hprof.html
[8] R language http://www.r-project.org/
[9] Hadoop http://hadoop.apache.org/
[10] Python http://www.python.it/
110
Afterword
Il progetto proposto e stato realizzato da Amedeo Leo, Alessio Petrozziello e Si-mone Romano per il progetto di Sistemi Operativi Avanzati tenuto dal professorGiuseppe Cattaneo.
111