Università degli Studi di Perugia
FACOLTÀ DI SCIENZE MATEMATICHE, FISICHE E NATURALI
Corso di Laurea in Informatica
Tesi di Laurea
Sviluppo di uno strumento per l’analisi
e l’ottimizzazione delle politiche di scheduling
di un cluster
Candidato
Relatore
Claudio Tanci
Prof. Leonello Servoli
Correlatore
Mirko Mariotti
Anno Accademico 2008–2009
Ai miei genitori
Ringraziamenti
Desidero rivolgere un sentito ringraziamento al Prof.
Leonello Servoli per la
costante disponibilità e l’opportunità di lavorare ad un progetto stimolante e divertente, a Mirko Mariotti e Francesco Cantini per aver posto le basi per questo lavoro,
per il supporto garantito ma soprattutto per l’amicizia dimostrata. Insieme a loro un
grazie particolare va a Flavio, Igor, Riccardo, per le mille risate e il tempo trascorso
insieme, un grazie allargato alle tante persone con cui ho condiviso pranzi, partite e
pause caffè che a vario titolo frequentano il Dipartimento di Fisica, che è diventata
per un poco una seconda casa, e ai compagni di università vecchi e nuovi, Daniele,
Luca, Mattia, Simone e Tiziano.
Grazie a Francesco e a tutti gli ex compagni di squadra, ex compagni di scuola che
ancora mi sopportano per una birra o due chiacchere, grazie a Silvia, che c’è sempre
ci sia bisogno di parlare o fare spellcheck.
Grazie ai miei genitori, a Laura e a tutta la famiglia per troppe cose da ricordare
qui.
Grazie a tutti quelli che hanno avuto pazienza e sono stati da sprone.
V
Indice
Introduzione
1
1 Sistemi batch
5
1.1
Nascita ed evoluzione del calcolatore elettronico . . . . . . . . . . . . .
5
1.2
L’elaborazione batch . . . . . . . . . . . . . . . . . . . . . . . . . . . .
6
1.3
Il calcolatore oggi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7
1.4
Batch computing reprise . . . . . . . . . . . . . . . . . . . . . . . . . .
9
2 Cluster
11
2.1
Computer a grappolo . . . . . . . . . . . . . . . . . . . . . . . . . . . .
11
2.2
Cluster per il calcolo: Architettura . . . . . . . . . . . . . . . . . . . .
12
2.3
Cluster per il calcolo: Software . . . . . . . . . . . . . . . . . . . . . .
12
2.3.1
Client delle user interface . . . . . . . . . . . . . . . . . . . . .
12
2.3.2
Il resource manager . . . . . . . . . . . . . . . . . . . . . . . .
12
2.3.3
Lo scheduler . . . . . . . . . . . . . . . . . . . . . . . . . . . .
13
3 Virtualizzazione
15
3.1
L’astrazione delle risorse . . . . . . . . . . . . . . . . . . . . . . . . . .
15
3.2
Tipologie di virtualizzazione . . . . . . . . . . . . . . . . . . . . . . . .
15
3.3
Xen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
17
4 Algoritmi genetici
4.1
19
Funzionamento degli algoritmi genetici . . . . . . . . . . . . . . . . . .
5 Il cluster INFN Perugia
19
23
5.1
L’architettura hardware . . . . . . . . . . . . . . . . . . . . . . . . . .
24
5.2
Alcune particolarità del cluster . . . . . . . . . . . . . . . . . . . . . .
26
5.3
La configurazione software . . . . . . . . . . . . . . . . . . . . . . . . .
26
VII
6 TORQUE/Maui
31
6.1
TORQUE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
31
6.2
Maui . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
32
6.2.1
Il concetto di priorità . . . . . . . . . . . . . . . . . . . . . . .
32
6.2.2
Allocazione dei nodi . . . . . . . . . . . . . . . . . . . . . . . .
33
6.2.3
Meccanismi di Fairness
. . . . . . . . . . . . . . . . . . . . . .
35
6.2.4
Controllo dell’accesso alle risorse . . . . . . . . . . . . . . . . .
36
6.2.5
Ottimizzazione del comportamento dello scheduler . . . . . . .
37
6.2.6
Log e simulazioni . . . . . . . . . . . . . . . . . . . . . . . . . .
38
7 L’infrastruttura di analisi, simulazione e ottimizzazione
39
7.1
Alcuni problemi da affrontare . . . . . . . . . . . . . . . . . . . . . . .
39
7.2
Metriche di sistema . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
41
7.2.1
Metrica di equità . . . . . . . . . . . . . . . . . . . . . . . . . .
42
7.2.2
Metrica di efficienza . . . . . . . . . . . . . . . . . . . . . . . .
42
Anatomia dell’infrastruttura . . . . . . . . . . . . . . . . . . . . . . . .
43
7.3.1
La farm di produzione . . . . . . . . . . . . . . . . . . . . . . .
43
7.3.2
La farm di test . . . . . . . . . . . . . . . . . . . . . . . . . . .
44
7.3.3
Il repository server . . . . . . . . . . . . . . . . . . . . . . . . .
44
7.3.4
Le macchine di simulazione . . . . . . . . . . . . . . . . . . . .
47
7.3.5
Stazioni di controllo e analisi . . . . . . . . . . . . . . . . . . .
47
Fisiologia e software dell’infrastruttura . . . . . . . . . . . . . . . . . .
47
7.4.1
I run . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
48
7.4.2
Il sottosistema delle feature . . . . . . . . . . . . . . . . . . . .
48
7.4.3
Sottomettere un run: run.conf e command.sh . . . . . . . . . .
50
7.4.4
Tool per la gestione dell’infrastruttura . . . . . . . . . . . . . .
50
7.4.5
Tool di preparazione tracce . . . . . . . . . . . . . . . . . . . .
54
7.4.6
Tool di simulazione, test e ottimizzazione . . . . . . . . . . . .
57
7.4.7
Tool di analisi
60
7.3
7.4
. . . . . . . . . . . . . . . . . . . . . . . . . . .
8 Test e simulazioni
63
8.1
Test sul Fairshare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
63
8.2
Simulazione sul Fairshare n.1 . . . . . . . . . . . . . . . . . . . . . . .
64
8.3
Simulazione sul Fairshare n.2 . . . . . . . . . . . . . . . . . . . . . . .
65
8.4
Simulazione sul Fairshare n.3 . . . . . . . . . . . . . . . . . . . . . . .
66
8.5
Simulazione sul Fairshare n.4 . . . . . . . . . . . . . . . . . . . . . . .
66
8.6
Simulazione sul Fairshare n.5 . . . . . . . . . . . . . . . . . . . . . . .
67
8.7
Test di ottimizzazione genetica . . . . . . . . . . . . . . . . . . . . . .
68
Conclusioni
75
VIII
Appendici
79
A File di configurazione
79
run.conf . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
79
config-simul-template . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
81
File di traccia Maui . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
82
File delle risorse Maui . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
84
B Sorgenti
85
functions.sh . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
85
launch.sh . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
87
ls-feat.sh . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
98
ls-traces.sh . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
99
resolve-users.sh . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
resolve-queues.sh . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
resolve-schedule.sh . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
run.sh . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
simulate.sh . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
superexecute.sh . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
sync-traces.sh . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
visualize.sh . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144
Bibliografia
149
IX
Elenco delle figure
1
Mainframe, cluster e griglie computazionali. . . . . . . . . . . . . . . .
2
3.1
L’architettura di Xen . . . . . . . . . . . . . . . . . . . . . . . . . . . .
17
4.1
Schema di evoluzione genetica . . . . . . . . . . . . . . . . . . . . . . .
20
5.1
Topologia della rete del cluster INFN di Perugi . . . . . . . . . . . . .
25
6.1
Interfaccia Maui/TORQUE . . . . . . . . . . . . . . . . . . . . . . . .
32
7.1
L’infrastruttura hardware . . . . . . . . . . . . . . . . . . . . . . . . .
43
7.2
Struttura del repository rsync . . . . . . . . . . . . . . . . . . . . . . .
46
7.3
Struttura logica dell’infrastruttura di ottimizzazione . . . . . . . . . .
49
7.4
Ciclo di esecuzione di superexecute.sh . . . . . . . . . . . . . . . . . .
52
7.5
Ciclo di esecuzione di run.sh . . . . . . . . . . . . . . . . . . . . . . . .
57
7.6
Ciclo di esecuzione di launch.sh . . . . . . . . . . . . . . . . . . . . . .
58
7.7
Ciclo di esecuzione di simulate.sh . . . . . . . . . . . . . . . . . . . . .
60
7.8
Timeline di scheduling generata da trace-timeliner.pl . . . . . . . . . .
61
8.1
Test sul fairshare, tempo di attesa medio. . . . . . . . . . . . . . . . .
70
8.2
Simulazione sul fairshare n.1, tempo di attesa medio. . . . . . . . . . .
70
8.3
Fairshare, test e simulazione n.1 a confronto. . . . . . . . . . . . . . .
71
8.4
Simulazione sul fairshare n.2, tempo di attesa medio. . . . . . . . . . .
71
8.5
Simulazione sul fairshare n.3, tempo di attesa medio. . . . . . . . . . .
72
8.6
Simulazione sul fairshare n.4, tempo di attesa medio. . . . . . . . . . .
72
8.7
Simulazione sul fairshare n.5, tempo di attesa medio. . . . . . . . . . .
73
8.8
Simulazione sul fairshare n.3 e n.5 a confronto. . . . . . . . . . . . . .
73
8.9
Evoluzione genetica dei valori di priorità. . . . . . . . . . . . . . . . .
74
8.10 Evoluzione genetica dei valori di fitness. . . . . . . . . . . . . . . . . .
74
XI
Elenco delle tabelle
5.1
Risorse hardware apportate dai vari gruppi di ricerca . . . . . . . . . .
25
5.2
Principali code locali attive e relativi walltime . . . . . . . . . . . . . .
28
5.3
Principali code grid attive e relativi walltime . . . . . . . . . . . . . .
29
6.1
Componenti e sottocomponenti per il calcolo della priorità in Maui.
34
XIII
.
Introduzione
Sopra la scrivania o sulle ginocchia abbiamo computer che quindici anni fa sarebbero entrati di diritto nella lista dei sistemi più potenti al mondo, eppure rimane per
molti il bisogno di avere il massimo che sia disponibile e a portata di budget: astrofisica, fisica nucleare, fluidodinamica, chimica, metereologia, genetica, economia, finanza
e tutte le discipline dove le simulazioni sono un importante strumento di ricerca e
analisi sono affamate di risorse computazionali.
Enti di ricerca, istituti finanziari, forze armate di vari paesi sono sempre alla ricerca
di un’espansione delle loro capacità di calcolo:
• L’acceleratore di particelle LHC in costruzione presso il CERN vicino a Ginevra
produrrà ogni anno a regime collisioni protone-protone i cui risultati, registrati
da vari esperimenti attivi 24 ore su 24, saranno pari a circa 15 Petabyte di dati
da analizzare.[2]
• Google processa oltre 20 Petabyte di dati al giorno.[4]
• Il Lawrence Livermore National Laboratory in California, che si occupa delle valutazioni sulle performance, sulla sicurezza e l’affidabilità nel tempo del munizionamento nucleare per il Dipartimento della Difesa USA ospita un’installazione
IBM BlueGene/L da 131 072 unità di calcolo.[5]
L’architettura dei moderni supercomputer è modellata da questi requisiti, dall’evoluzione dei processi industriali (è nota l’osservazione di Moore sulla crescita esponenziale del numero di transistor in un singolo circuito integrato) e da forze di mercato
come le economie di scala che penalizzano architetture e sistemi ad-hoc computazionalmente più efficienti per un uso specifico in favore di soluzioni generalizzate dai minori
costi di sviluppo e gestione.[7]
L’evoluzione storica ha cosı̀ visto succedersi vari modelli di architetture: negli anni
’60 la CDC fece da pioniere introducendo quello che può essere considerato il primo
supercomputer, il CDC 6600, essenzialmente un mainframe molto efficiente. L’introduzione di processori vettoriali, capaci di operare in parallelo sui dati ha dominato
1
Figura 1: Mainframe, cluster e griglie computazionali.
Dimensioni e velocità di
interconnessione a confronto
la scena negli anni ’70, per poi lasciare a sua volta il passo a sistemi che introducevano la parallelizzazione non più (o non solo) all’interno della CPU ma a livello di
macchine. Lo sviluppo di sistemi cluster, sistemi collegati in rete locale e gestiti in
maniera associata, ma ognuno con una propria copia del sistema operativo, ha permesso cosı̀ di superare i limiti alla crescita dei singoli computer, portando alla nascita
nei centri di calcolo di farm, vere e proprie “fattorie” di computer. La necessità di
capacità di calcolo ancora superiori è stata infine soddisfatta (per il momento) dalle
cosiddette computing grid o griglie computazionali, che raggruppano sistemi geograficamente distanti tipicamente tramite Internet. Da notare in questa successione è il
progressivo allontanamento tra unità di elaborazione, che rende adatti supercomputer
di tipo mainframe isolati, cluster di calcolatori e griglie computazionali a diversi problemi e paradigmi di calcolo: dove c’è la necessità di comunicazioni veloci e frequenti
tra le varie componenti software un veloce calcolatore singolo sarà necessariamente la
scelta giusta, viceversa problemi ed algoritmi “a grana grossa”, in cui le comunicazioni
tra componenti assumono importanza più ridotta si possono adattare bene alle quasi
illimitate capacità di calcolo delle griglie computazionali, non risentendo più di tanto
della lentezza delle comunicazioni e di sporadiche disconnessioni (fig. 1).
I sistemi cluster hanno conosciuto una fortuna crescente dalla loro introduzione, a
Novembre 2007 406 sistemi su 500 nella lista TOP500 sono classificati come cluster.1 [6]
Ancora maggiore è l’utilizzo in ambienti dalle minori esigenze computazionali dato il
minor costo comparato ad un singolo calcolatore di capacità equivalente, la possibilità
di usare hardware off-the-shelf nonchè di natura eterogenea e le notevoli possibilità di
upgrade nel tempo.
1 il
progetto Top500 pubblica ogni 6 mesi la lista dei 500 supercomputer più potenti secondo il
benchmark HPL (http://www.netlib.org/benchmark/hpl/) che è possibile consultare presso http:
//top500.org
2
Nonostante le loro qualità i sistemi cluster rimangono difficili da gestire in modo
efficiente, soprattutto in ambienti con hardware misto e carico di lavoro variabile nel
tempo. Un esempio, anche se forse non proprio tipico, può essere dato dal cluster del
Dipartimento di Fisica e I.N.F.N. di Perugia, che oltre a servire vari gruppi di ricerca
locali, che partecipano in varia misura con fondi e hardware alla sua costituzione, fa
parte della griglia di calcolo europea EGEE.2 La progettazione e la messa a punto
del sistema, alla ricerca di un bilanciamento tra le varie e spesso contrastanti esigenze
degli utenti in un ambiente eterogeneo con la necessità di un utilizzo efficiente della
capacità di calcolo, si rivela una difficile arte, dove l’adeguamento delle configurazioni
ai mutevoli carichi di lavoro consiste necessariamente in un graduale aggiustamento dell’esistente; troppo alti infatti i rischi in perdita di produttività per consentire
l’esplorazione di scelte più radicali.
In questo scenario lo sviluppo di una infrastruttura per la simulazione permette
la creazione di un ambiente di test separato dal cluster di produzione, fornendoci la
possibilità di studiare la risposta del sistema a variazioni nell’hardware, nella configurazione del software di gestione e nei carichi di lavoro. L’uso di algoritmi genetici
permette l’automazione del processo di ottimizzazione della farm e apre scenari di
risposta quasi in tempo reale ai cambiamenti nel carico di lavoro.
Struttura della tesi
La tesi, composta da otto capitoli a cui si aggiungono le conclusioni e le appendici,
può essere idealmente suddivisa in tre parti: la prima parte, comprendente i primi
quattro capitoli, introduce concetti e tecnologie alla base del progetto, la seconda
parte in due capitoli illustra il cluster INFN di Perugia e il software utilizzato per la
sua gestione mentre l’ultima parte presenta l’infrastruttura di analisi, simulazione e
ottimizzazione del cluster sviluppata e alcuni risultati preliminari ottenuti.
Capitolo primo. Un’introduzione all’elaborazione batch, una panoramica storica e
la rilevanza attuale dei sistemi batch per la computazione.
Capitolo secondo. Descrizione e classificazione di sistemi cluster, con particolare
accento sui cluster di calcolo e le loro componenti.
Capitolo terzo. Un’introduzione alla astrazione hardware dei sistemi e a Xen, la
piattaforma di virtualizzazione scelta per il progetto.
Capitolo quarto. Vengono esposti brevemente il funzionamento degli algoritmi genetici e le varie fasi in cui si articola la loro esecuzione.
2 Per
ulteriori informazioni consultare i rispettivi siti internet:http://grid.pg.infn.it/ e http:
//www.eu-egee.org/
3
Capitolo quinto. Una presentazione del sistema batch del sito INFN di Perugia, con
una discussione sulle particolarità che lo contraddistinguono da altre installazioni
simili.
Capitolo sesto. Descrizione e configurazione dei software TORQUE e Maui, resource
manager e scheduler scelti per il sistema batch INFN di Perugia.
Capitolo settimo. Presentazione e implementazione dell’infrastruttura di analisi,
simulazione e ottimizzazione con una descrizione dei concetti chiave e delle sue
componenti.
Capitolo ottavo. Alcuni test realizzati grazie all’infrastruttura e i risultati preliminari di analisi.
in Appendice A si descrive il formato dei file di configurazione dello scheduler Maui
e degli script per la sottomissione di test e simulazioni all’infrastruttura.
in Appendice B è riportato il codice sorgente degli script sviluppati nel corso della
tesi.
4
Capitolo 1
Sistemi batch
Computers in the future may weigh
no more than 1.5 tons.
Popular Mechanics (1949)
1.1
Nascita ed evoluzione del calcolatore elettronico
Dalla nascita della geometria e della matematica in Egitto e in Grecia ci si è sempre scontrati con la difficoltà del loro utilizzo per la soluzione di problemi pratici. Nei
lunghi calcoli manuali un singolo errore può facilmente inficiare la validità del risultato
compromettendo tutto lo sforzo fatto. Per questo motivo dispositivi che aiutassero e
velocizzassero le ripetitive operazioni di calcolo sono stati l’obbiettivo di inventori e
matematici, portando alla nascita, nel tempo, di tutta una serie di “aiutanti meccanici” come abaci, calcolatrici meccaniche e, più recentemente, calcolatori programmabili. Il fatto che quest’ultima classe di dispositivi sia cosı̀ identificata ne sottolinea
la peculiarità essenziale: la grande utilità dei calcolatori programmabili, rispetto ad
altri dispositivi di calcolo, risiede nella loro versatilità, dovuta alla separazione di
due componenti distinte precedentemente non riconosciute come tali, l’hardware, la
componente fisica dell’apparecchiatura e il software, la sua logica di funzionamento.
L’hardware, per sua stessa natura, è soggetto a un lento e costoso processo di
progettazione, sviluppo e produzione.
È caratterizzato da funzioni immutabili o
comunque difficilmente espandibili, ma progettando un hardware aperto, spostando
la parte di logica di funzionamento nel software e riconoscendone la diversa natura
immateriale ci si può liberare, almeno in parte, da queste limitazioni:
• Si può usare lo stesso hardware per una varietà di problemi differenti.
• Si può ottimizzare e riscrivere velocemente il software nel tempo.
5
• Il costo della correzione di eventuali errori in software si presenta molto minore.
Nonostante questa importante evoluzione i primi calcolatori programmabili comportavano per gli standard di oggi numerosi problemi. Il lavoro di programmazione,
immissione dei dati e preparazione della macchina per uno specifico problema vedeva
infatti l’utente-tecnico di turno impegnarsi in lunghe e faticose procedure durante le
quali la macchina rimaneva in attesa con conseguente sottoutilizzo di prezione risorse
di calcolo.
La soluzione al problema fu di prendere in prestito una modalità di produzione
tipica di alcuni processi industriali detta produzione a lotti o “batch production”,
che si basa sull’idea di riordinare in lotti omogenei i prodotti da processare, cosı̀ da
minimizzare i tempi morti nelle operazioni di preparazione della catena produttiva al
cambio di prodotto.
Applicata all’informatica quest’idea si traduce nel raggruppare i processi da eseguire insieme ai loro dati di input e tutto quanto possa servire alla loro esecuzione
prima della loro sottomissione alla macchina.
Il lavoro tipico dell’utente-programmatore consisteva cosı̀ nel preparare lotti di
schede perforate contenenti i comandi necessari al caricamento del programma in
memoria e alla sua inizializzazione. Il programma principale e i suoi dati di input già
pronti aspettavano il loro turno di utilizzo del calcolatore e la stampa dei risultati. Con
l’introduzione di memorie ausiliare come nastri e dischi magnetici e la nascita di unità
satellite al calcolatore principale per la sottomissione e memorizzazione dei job vennero
abbattuti ulteriormente i tempi di preparazione. Lo spostamento della coda dei lavori
in attesa dalla scrivania dell’operatore di macchina all’interno del calcolatore permise
finalmente la possibilità di una sua gestione automatizzata indipendente dall’ordine
di arrivo dei job.
1.2
L’elaborazione batch
Il paradigma di elaborazione a lotti o “batch computing” sorse quindi come soluzione
naturale e perfettamente adeguata all’ambiente e alle problematiche dell’informatica
degli anni ’50 e ’60, il costo dei rari computer dell’epoca poteva infatti essere giustificato solo con un loro uso continuo e con il minimo spreco delle limitate risorse di calcolo
disponibili. In questo scenario le caratteristiche dell’elaborazione batch si prestano in
modo ottimale allo scopo:
• In fasi di utilizzo elevato del sistema di calcolo permette di posticipare l’esecuzione di job a momenti in cui le risorse siano meno occupate uniformando il
carico di lavoro nel tempo.
6
• La fase di esecuzione dei job non viene ritardata da attese di interazione con
l’utente.
• Massimizzando l’uso del sistema, permette un più velocemente ammortizzamento
dei costi di acquisto e gestione dello stesso.
D’altro canto la necessaria scelta di privilegiare l’efficienza del sistema a discapito
di altre qualità ha profonde conseguenze sulle modalità di utilizzo dello stesso, molte
delle quali non necessariamente gradite da parte degli utenti:
• Le fasi di preparazione e postproduzione dei job sono a carico dell’utente.
• I tempi di attesa dei risultati sono incerti.
• Il sistema non si presta ad un utilizzo interattivo.
• Eventuali errori di programmazione si rivelano solo al momento dell’effettiva
esecuzione del codice, complicando le attività di sviluppo e debug.
1.3
Il calcolatore oggi
L’esperienza descritta fin qui potrebbe sembrare aliena all’utente odierno, la continua rivoluzione informatica ha cambiato il volto del calcolatore e ha favorito la sua
evoluzione in diverse direzioni per adattarsi a una molteplicità di scopi e utilizzi. Partendo dal familiare personal computer in un grossolano ordinamento per dimensioni e
prestazioni decrescenti possiamo evidenziare alcune classi:
• Personal Computer desktop o portatili.
• Palmari e telefoni cellulari avanzati.
• Embedded computer.
Come ci si può aspettare, ad ogni classe evidenziata corrispondono differenti modalità
d’uso che si riflettono nel progetto hardware e software dei dispositivi. L’invenzione
dei microprocessori nei primi anni ’70, con la crescente integrazione di componenti,
ha reso possibile la nascita del Personal Computer, dove, come evidenziato dal nome,
l’attenzione non è più puntata sulle necessità della macchina ma su quelle dell’utente,
aprendo scenari impensabili fino a quel momento: il nuovo paradigma fa corrispondere
una macchina per ogni utente, a sua completa disposizione per tutto il tempo necessario con un’interfaccia amichevole e dotata di capacità multimediali. Il computer
torna ad aspettare i lenti tempi umani, ma ora questo non costituisce più un problema dato il costo dell’hardware ridotto di molti ordini di grandezza rispetto al passato.
7
Palmari e Smartphone, insieme ai progetti di ricerca su computer “indossabili” e altri dispositivi ultra-portabili, spingono ancora di più il mercato verso un’informatica
personale dove molti dispositivi con interfacce e compiti diversi sono sempre a disposizione. Chip inseriti in tutti i tipi di oggetti quotidiani portano promesse di pervasive
computing, un futuro di oggetti intelligenti, consapevoli dell’ambiente circostante e
sempre collegati e in comunicazione tra di loro per soddisfare le necessità dell’utente.
La discesa dal Personal Computer a dispositivi sempre più piccoli non è però
l’unica direzione percorsa dall’evoluzione dei sistemi informatici, salendo verso sistemi
più grandi e costosi le prospettive cambiano nuovamente:
• Personal Computer, Workstation e piccoli Server.
• Mainframe.
• Cluster.
• Griglie computazionali.
Qui le distinzioni si fanno meno nette e numerose sovrapposizioni possono esistere
a seconda delle caratteristiche scelte per la classificazione. I Mainframe sono quanto di
più vicino ai primi computer elettronici si possa trovare sul mercato, le più grandi macchine disponibili con l’esclusione di calcolatori “one-of-a-kind” progettati su misura e
richiesta del cliente. Per questa classe di macchine, più importanti della potenza di
calcolo sono le capacità riguardo l’I/O dei dati e le caratteristiche di affidabilità totale
derivanti, lato hardware, da una progettazione senza compromessi con un alto grado
di ridondanza e controllo dei dati e, lato software, dall’uso massiccio di tecnologie di
partizionamento del sistema e di virtualizzazione. Queste caratteristiche rendono i
Mainframe adatti ad una serie di applicazioni critiche quali censimenti, transazioni
finanziarie e applicazioni ERP (Enterprise Resource Planning o Pianificazione delle
risorse d’impresa).1
La classe dei Cluster comprende una eterogeneità di sistemi dalle prestazioni e costi
molto variabili la cui caratteristica comune è quella di essere formati da un insieme di
computer indipendenti collegati tra loro in rete locale che lavorano in accordo presentando agli utenti molte delle caratteristiche di un singolo computer. Questo permette
la progettazione di Cluster che garantiscono, tramite la ridondanza di macchine, un’alta affidabilità, oppure che sfruttino le molteplici risorse per raggiungere prestazioni
non ottenibili da un singolo computer, per quanto potente, oppure semplicemente che
ne garantiscano il livello di prestazioni equivalente associato ad una riduzione dei costi
hardware.
1 Con
ERP si identificano sistemi di gestione automatizzata che integrano tutti gli aspetti del
business aziendale.
8
La richiesta di prestazioni non si ferma al livello, seppur elevato, che i Cluster
rendono disponibile; applicazioni computazionalmente molto intense ma che possono
essere suddivise in molte parti indipendenti che non necessitino di condividere grandi quantità di dati sono adatte a girare su sistemi “Grid” o griglie computazionali.
I sistemi Grid portano ad un livello superiore di scala l’idea di parallelizzazione e
distribuzione del calcolo propria già dei sistemi Cluster, connettendo tra loro risorse
geograficamente distanti gestite in modo autonomo da singole istituzioni.
1.4
Batch computing reprise
Come abbiamo visto l’elaborazione batch è ormai scomparsa dai computer che ci
circondano negli uffici e nelle case. Come è cambiato l’hardware per adattarsi alle
nuove e molteplici esigenze cosı̀ sono sorti diversi paradagmi di calcolo e di interfaccia
con l’utente. Andando ad analizzare la situazione di macchine Mainframe e grandi
sistemi Cluster possiamo, tuttavia, riconoscere che le problematiche e le priorità non
sono cosı̀ differenti da quelle che portarono alla nascita del batch computing. Gli
elevati costi d’acquisto e gestione possono infatti essere giustificati solamente con una
effettiva necessità di risorse di calcolo e con l’utilizzo pieno di queste ultime, anche a
discapito dell’esperienza utente cui viene chiesto nuovamente di farsi carico, almeno
in parte, dei costi e delle difficoltà derivanti dalla complessità del sistema.
L’elaborazione batch dà soluzione in modo eccellente a queste problematiche e per
questo non è mai uscita di scena nonostante l’evoluzione tecnologica dell’architettura
sottostante.
9
Capitolo 2
Cluster
A supercomputer is a device for
turning compute-bound problems
into I/O-bound problems.
Ken Batcher
2.1
Computer a grappolo
La caratteristica di un cluster, quella di essere costituito da un insieme di computer
distinti (i nodi del cluster) collegati tra loro in un’integrazione più o meno stretta,
può essere sfruttata per vari fini. Una distinzione importante può essere fatta tra
cluster per l’alta disponibilità (High Availability cluster) e cluster per il calcolo (High
Performance Computing cluster):
Cluster per l’alta disponibilità. La ridondanza di componenti del cluster evita
single point of failure e aumenta l’affidabilità generale del sistema, politiche di
bilanciamento del carico possono inoltre assicurare uno sfruttamento omogeneo
dei vari nodi.
Cluster per il calcolo. I nodi del cluster vengono utilizzati per aumentare le capacità di calcolo del sistema.
Come si pone un cluster di calcolo rispetto a un supercomputer classico, costituito
da una singola macchina molto veloce? Per quanto riguarda le prestazioni i cluster
si prestano bene, per loro natura, a risolvere problemi parallelizzabili mentre soffrono
per problemi con una forte componente seriale. Utilizzando hardware off the shelf
si possono limitare i costi, a scapito di prestazioni, spazio e consumo energetico, ma
soprattutto i cluster possono scalare in prestazioni ben oltre i livelli raggiungibili da
una singola macchina.
11
2.2
Cluster per il calcolo: Architettura
La distinzione tra HA cluster e HPC cluster si riflette nella loro architettura, mentre
per i cluster di alta disponibilità obbiettivi di ridondanza portano sostanzialmente ad
una moltiplicazione dei nodi che forniscono i servizi richiesti, per i cluster di calcolo
diventa necessaria una maggiore specializzazione delle componenti. Tipicamente si
possono riscontrare:
Central manager. Occupandosi della gestione di tutto il sistema di calcolo costituisce il “cervello” del cluster; su questo nodo, essenziale al funzionamento del
cluster, è in esecuzione il software che governa l’accettazione e l’esecuzione dei
job utente e la gestione delle risorse. In sistemi particolarmente estesi queste
funzionalità sono suddivise in più nodi di management.
Nodi di esecuzione. Questa classe di nodi costituisce la forza lavoro del cluster,
dove vengono eseguiti i job utente. I nodi di esecuzione possono essere anche
di natura eterogenea, ad esempio quando il cluster è cresciuto nel tempo o per
l’utilizzo di macchine specializzate.
User interface. Rispetto agli altri nodi presumibilmente non accessibili agli utenti
l’interfaccia utente del cluster è costituita dai nodi di frontiera cui gli utenti
accreditati possono accedere per lavorare sul cluster, immettere job e ricevere i
risultati dei calcoli.
Nodi di checkpoint. Non sempre presenti, rappresentano una salvaguardia per eventuali errori che potrebbero vanificare il lavoro di job particolarmente lunghi salvandone lo stato ad intervalli regolari per un loro successivo eventuale ripristino.
2.3
Cluster per il calcolo: Software
Dal lato software un cluster per il calcolo implementa un tipico schema di lavoro
batch.
2.3.1
Client delle user interface
Il software che prende in carico i job sulle user interface. Costituisce l’interfaccia
del cluster verso gli utenti autenticati sul sistema, verso i quali mette a disposizione
comandi per le sottomissioni e il controllo dei job in corso.
2.3.2
Il resource manager
Il resource manager, come indica il nome, è il programma che gestisce le risorse (i
nodi di calcolo) del cluster. Necessariamente si tratta di un programma distribuito:
12
una parte gira sui nodi di esecuzione per la gestione e monitoraggio dei job locali
e delle stesse macchine, un’altra sul nodo manager per il coordinamento dell’intero
cluster, le comunicazioni con i serventi locali e l’interfaccia con lo scheduler e i client.
2.3.3
Lo scheduler
La gestione di tipo batch dei job sottomessi porta ad avere una coda di lavori
in attesa prima della loro esecuzione. Compito dello Scheduler è quello di gestire
le politiche di riordino temporale e spaziale dei job in coda, richiamando il resource
manager per la loro effettiva messa in opera per un efficiente utilizzo delle risorse del
cluster ed una generale soddisfazione delle esigenze degli utenti.
13
Capitolo 3
Virtualizzazione
You have a hardware or a software
problem.
Manuale di manutenzione della
stampante Gestetner 3240
3.1
L’astrazione delle risorse
Il concetto di astrazione riveste un ruolo di primo piano nelle scienze informatiche,
sia come guida alla comprensione di sistemi complessi e delle interazioni tra componenti sia come vero e proprio principio di progettazione che accomuna la programmazione
orientata agli oggetti con architetture software stratificate come il modello per l’interconnessione ISO/OSI o i componenti di un sistema operativo.1 Seguendo la stessa
linea di pensiero si è presto pensato, appena la tecnologia lo ha permesso, che fosse possibile astrarre le stesse risorse hardware fornendone una loro versione software
“virtuale” più flessibile.
3.2
Tipologie di virtualizzazione
A seconda del livello a cui avviene la virtualizzazione e quali risorse coinvolge è
possibile identificare varie modalità di virtualizzazione:
Virtualizzazione a livello di macchina. Introdotta dall’IBM già alla fine degli anni ’60 con il System/360 Model 67 e il relativo software CP/CMS consiste nell’astrazione delle periferiche hardware, nel caso l’intera architettura di sistema
1 L’Open
dardization
Systems Interconnection è uno standard dell’International Organization for Stanche
stabilisce
uno
standard
di
riferimento
aperti.
15
per
l’interconnessione
di
sistemi
venga coinvolta si parla di virtualizzazione “piena”, che permette l’esecuzione
di sistemi operativi non modificati all’interno delle macchine virtuali, se invece esistono istruzioni macchina privilegiate e non virtualizzate si parla di di
“para-virtualizzazione”, in genere più semplice da implementare e dalle migliori
prestazioni, al costo però di necessarie modifiche al sistema operativo ospite.2
L’astrazione delle risorse viene implementata da un software denominato virtual
machine monitor o hypervisor che può interfacciarsi direttamente con l’hardware (hypervisor di tipo 1 o bare-metal ) come nel caso di VMware ESX Server,
Xen o KVM o consistere in un software in esecuzione in un sistema operativo tradizionale (hypervisor di tipo 2 o “hosted”) come VMware Workstation,
QEMU o VirtualBox.3
Virtualizzazione a livello di sistema operativo. Questo tipo di virtualizzazione
fornisce un isolamento e partizionamento delle risorse da parte del sistema operativo che prevede “ambienti virtuali” di esecuzione. Esempi di questa tecnologia
usata principalmente come misura di sicurezza sono le “zone” supportate da Solaris, le “jail” di FreeBSD e su ambiente Linux l’uso del comando “chroot” e i
server virtuali di VServer.
Virtualizzazione a livello di applicazione. Una macchina virtuale al supporto di
un singolo processo, creata al suo avvio e distrutta al suo completamento. Lo
scopo della virtualizzazione a livello di applicazione è quello di fornire un ambiente per il processo indipendente dalla piattaforma in uso implementando un
paradigma di compatibilità multipiattaforma “write once, run anywhere” diffuso
da ambienti di programmazione come Java o .NET che prevedono la creazione di
“bytecode”, codice intermedio per una generica macchina virtuale interpretato
o compilato “just in time” al momento dell’esecuzione.
Particolare rilevanza per servizi di elaborazione dati assume la virtualizzazione a livello
di macchina che, nata in ambito mainframe, riveste una sempre maggiore importanza
in molti scenari. Le macchine virtuali si prestano ad essere “sandbox” naturali dove il
codice non può interferire con il sistema sottostante o altre macchine virtuali. Questa
caratteristica si rivela utile sia in sistemi di produzione, come misura di limitazione dei
privilegi, sia nello sviluppo di sistemi operativi e software di basso livello facilitando
il debugging del sistema. In un’ottica di QOS, affidabilità e disponibilità delle risorse
le tecnologie di virtualizzazione permettono l’implementazione di architetture dalle
componenti ridondanti dove è possibile la migrazione “a caldo”, senza interruzione di
2 Per
3 per
macchina virtuale si intende l’implementazione software di un computer.
informazioni sui prodotti menzionati è possibile consultare i rispettivi siti web: http://www.
vmware.com, http://xen.org, http://kvm.qumranet.com/kvmwiki, http://bellard.org/qemu, http:
//www.virtualbox.org, http://linux-vserver.org.
16
Figura 3.1: L’architettura di Xen
servizio, degli ambienti virtuali. Per quanto riguarda prospettive di riduzione dei costi
è chiaro come la crescenti capacità dell’hardware si possano sfruttare per il consolidamento di macchine e servizi garantendo risparmi nelle risorse e nei costi di gestione
loro associati.
3.3
Xen
Xen è un progetto di virtualizzazione “FLOSS”.4 Inizialmente sviluppato presso
l’università di Cambridge supporta le architetture x86, x86 64, IA64 e PowerPC e
un’ampia gamma di sistemi operativi guest come Linux, Solaris e Windows. Come si
può osservare in fig. 3.1 l’hypervisor Xen implementa l’interfaccia virtuale tra l’hardware e i sistemi operativi, responsabile dello scheduling della CPU e del partizionamento della memoria tra le varie macchine virtuali; non si occupa però della gestione
generale dei dispositivi video, storage, rete o altro il cui controllo è demandato ad
una speciale macchina virtuale denominata Domain 0, in genere un kernel modificato
Linux. L’uso del Domain 0 permette a Xen di sfruttare l’ampia disponibilità di driver del kernel Linux e di presentare all’utente una interfaccia familiare agli strumenti
di controllo e gestione delle macchine virtuali. Le altre macchine virtuali vengono
identificate nella terminologia Xen come Domain U e possono consistere in sistemi
paravirtualizzati o pienamente virtualizzati, se supportati dall’architettura hardware
sottostante. Le caratteristiche evidenziate di Xen, il supporto a Linux come Domain 0
e sistema guest, insieme a funzioni avanzate come la migrazione “live” delle macchine
4 Per
FLOSS, Free/Libre/Open Source Software, si intende una metodologia di sviluppo in cui il
codice sorgente dei programmi è a libera disposizione degli utenti e la cui licenza di copyright tuteli
alcuni diritti verso gli utenti tra cui l’uso, la modifica e la ridistribuzione del software. Per una
definizione più dettagliata si rimanda a quella della Open Source Initiative che è possibile trovare
all’indirizzo http://www.opensource.org/docs/osd.
17
e al suo riconoscimento come soluzione matura e dalle buone prestazioni hanno indotto
a selezionarlo come soluzione per le esigenze sorte in campo di virtualizzazione per la
farm di calcolo e altri servizi all’interno del Dipartimento di Fisica dell’Università di
Perugia.
18
Capitolo 4
Algoritmi genetici
I love fools’ experiments. I am
always making them.
Charles Darwin
Gli algoritmi genetici costituiscono una classe di metodi per problemi di ricerca
e ottimizzazione, il loro nome deriva dall’implementazione di alcune idee ispirate alla
teoria dell’evoluzione e in modo particolare alla genetica. Gli algoritmi genetici si
rivelano utili nell’affrontare una varietà di problemi per cui non è possibile stabilire a
priori la forma di una soluzione e lo spazio di ricerca è particolarmente esteso. Data la
natura euristica del loro funzionamento gli algoritmi genetici non forniscono certezze
sulle soluzioni o sui tempi necessari ma spesso si rivelano efficienti, in particolare
quando ci si può accontentare anche di soluzioni quasi-ottimali. Insieme alle procedure gli algoritmi genetici prendono in prestito dalla natura anche una buona parte
della terminologia di descrizione, si parlerà quindi nel prosieguo ad esempio di geni,
popolazioni o individui ; dove il significato non sia immediatamente comprensibile si
procederà alla descrizione dei termini utilizzati nel caso specifico.
Un algoritmo genetico richiede la definizione di alcuni elementi dipendenti dal dominio di applicazione: una rappresentazione adeguata degli elementi del dominio delle
soluzioni del problema (i geni ) e una funzione obbiettivo o di fitness per la valutazione
della loro “bontà”, che permetta di calcolare una distanza tra i geni considerati e la
soluzione desiderata.
4.1
Funzionamento degli algoritmi genetici
Nel funzionamento di un algoritmo genetico si può tipicamente osservare una
successione di stadi reiterati (fig. 4.1 nella pagina seguente):
19
Figura 4.1: Schema di evoluzione genetica
Generazione della popolazione iniziale. Una popolazione iniziale di potenziali
soluzioni può essere generata in maniera totalmente casuale o scegliendo alcuni individui come “semina”. Il numero ottimale di elementi della popolazione
dipende dal problema in esame, tipicamente sull’ordine delle centinaia o migliaia, mentre la scelta delle strutture dati per la codifica degli individui ricade
solitamente su alberi o vettori.
Valutazione e selezione. Ad ogni individuo viene associato un valore di idoneità
calcolato dalla funzione di fitness. Gli individui con un valore di idoneità basso
vengono scartati, quelli con valore di idoneità alto vengono selezionati come
“genitori” per la successiva generazione.
Evoluzione: crossover e mutazioni. Con operazioni di crossover e mutazione sugli individui genitori si genera la nuova popolazione di potenziali soluzioni. L’operazione di crossover consiste nel creare nuovi individui figli a partire da porzioni
di codice dei genitori in analogia con il ruolo che la riproduzione sessuata svolge
nel campo biologico. Nel caso più semplice di crossover “single point” viene
scelta in modo casuale una singola posizione dove i geni di due genitori vengono tagliati e le parti, invertite, vengono riassemblate in due nuovi geni figli.
Tramite mutazioni casuali in singoli geni si cerca invece di evitare convergenze
premature su ottimi locali migliorando l’esplorazione dello spazio delle soluzioni.
La nuova popolazione di potenziali soluzioni cosı̀ ottenuta può essere sottoposta
nuovamente a valutazione e selezione fino al raggiungimento di un numero prefissato di generazioni, all’individuazione di una soluzione o di un altro criterio
di arresto.
20
Alcune difficoltà nell’applicazione di algoritmi genetici derivano dalla loro natura
aleatoria e probabilistica e dalla scelta dei parametri per la selezione degli individui,
di crossover e dei tassi di mutazione, legati tra loro da relazioni non lineari, che risulta
dipendente dalle condizioni specifiche del dominio di applicazione dell’algoritmo.[8]
Spesso può diventare problematica anche la scelta della funzione di fitness, che deve
riuscire ad esprimere in modo matematico l’obbiettivo dell’ottimizzazione o la descrizione della soluzione. Ciò nonostante gli algoritmi genetici hanno trovato ampia applicazione in campi disparati per tutta una classe di problemi per cui non si conoscono
algoritmi efficienti. La ricerca di politiche di scheduling ottimale ne costituisce un esempio emblematico, con l’elevato numero di elementi che contribuiscono al risultato
finale, e che si influenzano tra loro in maniera complessa, che le contraddistingue.
21
Capitolo 5
Il cluster INFN Perugia
Marco Polo descrive un ponte,
pietra per pietra.
“Ma qual è la pietra che sostiene il
ponte?” chiede Kublai Kan.
“Il ponte non è sostenuto da questa
o quella pietra”, risponde Marco,
“ma dalla linea dell’arco che esse
formano.”
Kublai Kan rimane silenzioso,
riflettendo. Poi soggiunge: “Perché
mi parli delle pietre? È solo
dell’arco che mi importa.”
Polo risponde: “Senza pietre non c’è
arco.”
Italo Calvino
Il cluster INFN di Perugia non è l’espressione di un unico soggetto, è stato infatti
costituito quando da vari gruppi di ricerca locali è stata presa la decisione di accentrare
e mettere in condivisione le proprie risorse di calcolo. L’accentramento delle capacità
di calcolo ha significato come prevedibile una certa perdita di flessibilità da parte dei
singoli gruppi in modo particolare per quanto riguarda la scelta del sistema operativo
e dei programmi e librerie a disposizione degli utenti, su cui i vari gruppi ora afferenti
alla struttura devono necessariamente trovare un compromesso, d’altra parte si sono
concretizzati numerosi vantaggi: in primo luogo le dimensioni di un cluster unico
fanno si che l’impatto dei naturali cambiamenti nel tempo dell’attività dei singoli
gruppi sia più facilmente ammortizzato, inoltre dato che difficilmente tutti i gruppi
richiedono contemporaneamente la totalità della loro percentuale di risorse le risorse
23
disponibili in ogni dato istante sono tipicamente superiori a quelle di ogni singolo
gruppo. Ulteriori vantaggi sia di natura economica che di efficienza derivano poi dalla
gestione e manutenzione unificata delle risorse. Nella tab. 5.1 nella pagina successiva
sono riportate le quote e le tipologie di risorse in carico al cluster anteriormente alla
migrazione nella nuova sala farm avvenuta nell’estate 2009.
È interessante notare come le economie di scala non si sono fermate a livello locale,
dal 2004 il cluster INFN di Perugia partecipa alla griglia di calcolo nazionale INFN che
si inserisce nei progetti di griglia EGEE, diventando cosı̀ parte di una rete di calcolo
che si compone di circa 300 siti in 50 paesi diversi.
5.1
L’architettura hardware
Analizzando il cluster INFN (tab. 5.1 a fronte) possiamo riconoscere alcune tipologie di nodi introdotte precedentemente nella descrizione di un cluster generico insieme
ad alcuni nodi specifici dell’installazione. Una distinzione da tenere in considerazione
entrando nello specifico di un sistema reale come quello in questione è quella tra nodi
interni e nodi di frontiera, le macchine del cluster infatti non sono tutte accessibili
direttamente dagli utenti per questioni di sicurezza. I nodi interni sono essenzialmente
di due tipi: nodi di tipo file server per lo storage dei dati e nodi di esecuzione, in questo
contesto denominati worker node. Per quanto riguarda i nodi di frontiera accessibili
agli utenti troviamo una maggiore varietà: le user interface sono le stazioni interattive
dove gli utenti del cluster possono sottomettere job e analizzarne i risultati, un install
server, che rende più semplici e veloci le operazioni di manutenzione automatizzando
l’installazione e la configurazione del software sui numerosi nodi del cluster, e infine
il nodo central manager, chiamato computing element, che ospita TORQUE, Maui e,
dato che il sito fa parte della griglia di calcolo INFN, gli opportuni programmi per
interfacciarsi con la stessa ed accettarne i job. La griglia prevede anche la presenza
di nodi storage element con funzione di storage dati, qui implementati principalmente
come interfacce trasparenti ai nodi interni di tipo file server. I nodi del sistema sono
collegati tramite una lan standard ethernet in una struttura a stella a due livelli di
profondità con uno switch primario a cui sono collegati alcuni nodi e switch secondari
(fig. 5.1 nella pagina successiva).
L’origine non univoca del cluster e i suoi successivi ampliamenti hanno prodotto
un ambiente molto eterogeneo sia per quanto riguarda le caratteristiche hardware dei
nodi, che spaziano da macchine in fase di dismissione dotate di cpu Intel Pentium III
a macchine da 8 core e 16Gb di ram, sia per quanto riguarda le velocità di connessione
di vari segmenti di rete, fast ethernet da 100Mbit/s o gigabit ethernet da 1Gbit/s.
24
Figura 5.1: Topologia della rete del cluster INFN di Perugia[3]
Esperimento
File
Spazio User in-
Nodi di
Altri
Totale
Totale
server
disco
calcolo
nodi
mac-
core
terface
chine
(TB)
GRID
0
1,5
0
17
5
22
44
BABAR
1
0,75
1
1
0
3
6
CMS
3
10+
2
13
5
22
44
GLAST
3
10+
1
8
0
18
36
NA48
3
5,5
2
13
0
18
36
Teorici
0
0
1
4
0
5
10
Virgo
0
0
1
6
0
7
14
Altri fondi
0
0
0
0
1
1
2
Risorse totali
8
25+
8
62
11
89
178
Tabella 5.1: Risorse hardware apportate dai vari gruppi di ricerca
25
5.2
Alcune particolarità del cluster
La particolare genesi del cluster INFN di Perugia si riflette nelle scelte organizzative e architetturali che hanno portato alla sua configurazione attuale, in risposta alle
necessità peculiari del sito sono state infatti studiate alcune scelte implementative che
lo differenziano da altri siti di calcolo. Innanzitutto occorre considerare che nonostante la compartecipazione al cluster la titolarità dell’hardware messo a disposizione
rimane agli stessi gruppi di ricerca e questo si traduce in legittime richieste di utilizzo
delle risorse di cui tenere conto in fase di configurazione e valutazione dei risultati.
Altri aspetti specifici della farm di calcolo derivano dalla sua doppia natura di cluster dipartimentale e sito grid. In genere a un sito grid si può accedere solamente se
autorizzati e autenticati da una virtual organization di grid; questo ha posto alcuni
problemi per quanto riguarda il sito di Perugia, dato che alcuni gruppi di ricerca che
compartecipano al cluster non fanno parte ne avrebbero necessità di aderire a virtual
organization per l’accesso alla griglia di calcolo INFN o EGEE.1 La soluzione a questo
problema è stata l’implementazione di una duplice interfaccia al cluster, una interna
attraverso le user interface e una di griglia tramite il computing element, creando
cosı̀ una farm ibrida. Un ulteriore problema nato dall’ingresso in griglia del cluster
sorse dal requisito che tutti i nodi del cluster disponessero di indirizzi ip pubblici da
parte della versione del middleware grid allora in uso.2 Si sono cosı̀ rese necessarie
modifiche al codice per poter configurare i worker node in rete privata, sia per una
maggior sicurezza sia per il limitato numero di indirizzi ipv4 disponibili, modifiche che
sono state successivamente accettate e sono riconfluite nel ramo di sviluppo principale
del middleware grid. Un’ultima peculiarità dell’installazione consiste nell’uso pervasivo di tecnologie di virtualizzazione, numerosi nodi ospitano macchine Xen di test o
di produzione, garantendo maggiore flessibilità, una generale praticità di gestione e
downtime ridotti in caso di problemi.
5.3
La configurazione software
La partecipazione al progetto INFN GRID ha comportato alcune limitazioni sulle
scelte di implementazione del cluster, in modo particolare per quanto riguarda la scelta
dello scheduler e del resource manager ci si è dovuti attenere a soluzioni supportate
dal middleware di griglia. La scelta è caduta come resource manager su TORQUE e
come scheduler su Maui. L’accoppiata TORQUE/Maui è considerata una soluzione
1 Per
Virtual Organization si intendono qui organizzazioni che coordinano al loro interno le politiche
di accesso e condivisione delle risorse.
2 Con middleware si intende un insieme di programmi con funzione di intermediazione, raccordo e
supporto tra applicazioni.
26
matura dalle adeguate caratteristiche tecniche, in uso presso molti centri di calcolo,
non da ultimo la disponibilità dei codici sorgenti di entrambi i software contribuisce a
rassicurare sulle future possibilità di aggiornamento, manutenzione ed adeguamento.
Non si è optato per un rigido partizionamento del cluster, a tutti i gruppi e utenti
è infatti consentito l’uso di qualsiasi risorsa del cluster. Come si può osservare in
tab. 5.2 nella pagina seguente la suddivisione delle risorse secondo i gruppi partecipanti
si rispecchia invece nella configurazione delle code di sottomissione dei job al batch
system di TORQUE, dove per la sottomissione di job locali sono a disposizione degli
utenti quattro code per ogni gruppo che differiscono per valore di walltime e priorità,
in modo da assicurare priorità ai job di durata minore su quelli a lunga esecuzione.3
In tab. 5.3 nella pagina 29 si può vedere come una quinta coda per gruppo copra i job
sottomessi via grid mentre altre code permettono l’esecuzione ad alta priorità di job
di amministrazione e dei job di certificazione di grid che riportano lo stato corrente
del sistema.
Gli altri parametri di configurazione delle politiche di scheduling messi a disposizione da Maui sono stati via via impostati e sottoposti a verifica con l’intento generale di massimizzare l’efficenza del cluster e nel contempo far corrispondere sul lungo
periodo la quota di utilizzo del cluster per ogni gruppo con la quota di risorse computazionali messe a disposizione, cercando di minimizzare i tempi di risposta per gli
utenti.
3 Il
walltime di un job è un valore temporale che corrisponde al tempo massimo a disposizione del
job per terminare la sua esecuzione passato il quale il sistema provvede a terminarlo forzatamente.
27
Esperimento
Coda
babar-short
BABAR
24:00:00
babar-long
52:00:00
cms-short
cms-long
52:00:00
glast-medium
glast-long
glast-infinite
na48-short
2:00:00
24:00:00
52:00:00
780:00:00
2:00:00
24:00:00
na48-long
52:00:00
theo-short
780:00:00
2:00:00
theo-medium
24:00:00
theo-long
52:00:00
theo-infinite
virgo-short
Virgo
780:00:00
na48-medium
na48-infinite
Teorici
2:00:00
24:00:00
glast-short
NA48
780:00:00
cms-medium
cms-infinite
GLAST
2:00:00
babar-medium
babar-infinite
CMS
Walltime
780:00:00
2:00:00
virgo-medium
24:00:00
virgo-long
52:00:00
virgo-infinite
test
780:00:00
24:00:00
Tabella 5.2: Principali code locali attive e relativi walltime
28
Coda
Walltime
babar
72:00:00
cms
120:00:00
na48
120:00:00
theophys
72:00:00
virgo
120:00:00
grid
72:00:00
cert
72:00:00
Tabella 5.3: Principali code grid attive e relativi walltime
29
Capitolo 6
TORQUE/Maui
The goal of a scheduler in the
broadest sense is to make users,
administrators, and managers
happy.
Maui Administrator’s Guide
TORQUE e Maui costituiscono un’implementazione dell’accoppiata resource manager/scheduler che ha conosciuto molta fortuna ed è quella scelta per la farm INFN
di Perugia.
6.1
TORQUE
TORQUE è un resource manager open source sviluppato da Cluster Resources il
cui codice deriva dal progetto PBS, un resource manager creato originariamente per
la N.A.S.A. nei primi anni novanta.1 Anche se dispone per finalità di test di un programma di scheduling minimale TORQUE viene tipicamente affiancato da programmi
scheduler più specializzati, mentre a TORQUE rimangono le funzionalità di avvio,
cancellazione e monitoraggio dei job e delle risorse hardware. TORQUE prevede due
modalità distinte di esecuzione, in genere selezionate al momento della compilazione,
che girano come demoni sul nodo central manager (pbs_server) e sui nodi di calcolo
(pbs_mom), mentre i comandi utente per la sottomissione e gestione dei job risiedono,
se presenti, sui nodi con funzione di interfaccia utente.2
1 Maggiori
informazioni su Cluster Resources e lo sviluppo di TORQUE si possono trovare sul sito
http://clusterresources.com.
2 In sistemi multitasking un demone è un programma costantemente in esecuzione in background.
31
pbs mom. Il demone TORQUE che risiede sui nodi di calcolo del cluster. pbs_mom
riceve istruzioni da pbs_server e si preoccupa di gestire il singolo nodo di calcolo
e i job di sua appartenenza.
pbs server. Risiede sul nodo con funzionalità di central manager, ricevendo istruzioni
dallo scheduler coordina l’attività dei pbs_mom e riporta allo scheduler e all’utente informazioni sullo stato dei nodi e dei job.
6.2
Maui
Maui è uno scheduler open source per cluster e supercomputer come TORQUE
sviluppato e supportato da Cluster Resources che commercializza anche una sua versione commerciale dal nome Moab attualmente utilizzata sui primi due e su undici
dei venti supercomputer più potenti al mondo.3 Maui può interfacciarsi a diversi
resource manager per l’effettiva gestione dei job e mette a disposizione un’ampia gamma di strumenti e possibilità di configurazione per le proprie politiche di scheduling
(fig. 6.1).
6.2.1
Il concetto di priorità
Spesso molteplici obbiettivi indipendenti vengono individuati per il batch system
come massimizzare l’utilizzo del sistema, assegnare precedenze a particolari utenti o
limitare i tempi di esecuzione di alcuni job, Maui risolve il problema di rappresentare
e gestire queste varie esigenze assegnando ad ognuna di esse un peso che contribuisce
al calcolo di un valore di priorità unico per ogni job. A questo punto i job potranno
essere messi in coda in attesa di esecuzione nel loro ordine di priorità rispettando i
vincoli dati.
3 lista
top500 06/2008, http://top500.org
Figura 6.1: Interfaccia Maui/TORQUE
32
I vari elementi che Maui considera nel calcolo della priorità sono per una più
facile gestione raggruppati in una gerarchia ad albero a due livelli di componenti e
sottocomponenti come riportato nella tab. 6.1 nella pagina successiva, a cui possono
essere associati pesi distinti e valori massimali.4 il contributo al valore di priorità di
ogni sottocomponente è calcolato come
peso componente ∗ peso sottocomponente ∗ valore associato al sottocomponente.
Per le impostazioni di default il valore dei pesi delle componenti è impostato a 1 e
quello delle sottocomponenti a 0 con l’eccezione della sottocomponente QUEUETIME il
cui peso è impostato a 1. Se non altrimenti specificato quindi Maui adotterà una
semplice politica FIFO per la gestione della coda dei job.5
6.2.2
Allocazione dei nodi
Oltre che preoccuparsi di gestire temporalmente i job in attesa compito dello scheduler è anche quello di gestire l’allocazione delle risorse disponibili decidendo su quali
nodi del cluster ogni particolare job debba essere eseguito. L’allocazione delle risorse
presenta particolare criticità in caso di hardware eterogeneo o in presenza di politiche
di prenotazione o di garanzia del servizio e Maui mette a disposizione diversi algoritmi
allo scopo:
CPULOAD Sono selezionati i nodi con la massima capacità di calcolo disponibile,
utile per sistemi in timeshare.
FIRSTAVAILABLE I nodi sono allocati nell’ordine in cui sono presentati dal rerource
manager.
LASTAVAILABLE Assegna i job più opportuni nell’intervallo tra prenotazioni successive della stessa risorsa implementando un best fit temporale che minimizza
l’impatto di politiche di prenotazione.6
PRIORITY Permette di specificare un set di priorità per i vari attributi statici e
dinamici dei nodi da rispettare.
MINRESOURCE Alloca i nodi scegliendo quelli con le risorse minime possibili.
CONTIGUOUS Implementa un algoritmo di allocazione lineare richiesto su alcuni
sistemi di marca HP.
4 Il
livello delle componenti è composto dai seguenti gruppi: CRED gruppo delle credenziali, FS
Fairshare, RES Risorse, SERV Livello di servizio corrente, TARGET Obbiettivi, USAGE Risorse in uso, solo
per job in esecuzione.
5 First In, First Out: i job sono accodati per tempo di sottomissione.
6 Una strategia “best fit” prevede che i job vengano inseriti nella partizione di tempo con dimensione
più vicina alla durata stimata del job.
33
Componente
Sottocomponente
Metrica
CRED
USER
GROUP
ACCOUNT
QOS
CLASS
Priorità
Priorità
Priorità
Priorità
Priorità
FSUSER
FSGROUP
FSACCOUNT
FSQOS
FSCLASS
Uso storico dell’utente
Differenziale sull’uso storico
Differenziale sull’uso storico
Differenziale sull’uso storico
QOS
Differenziale sull’uso storico
RES
NODE
PROC
MEM
SWAP
DISK
PS
PE
WALLTIME
Numero di nodi richiesti
Numero di processori richiesti
Memoria totale richiesta (in MB)
Memoria virtuale richiesta (in MB)
Spazio disco richiesto (in MB)
Processori-secondi richiesti
Processori equivalenti richiesti
Valore di walltime richiesto (in secondi)
SERV
QUEUETIME
XFACTOR
BYPASS
Permanenza in coda (in minuti)
Fattore di espansione minimo
Numero di volte che il job è stato
sorpassato tramite backfill
TARGETQUEUETIME
Tempo rimanente al raggiungimento dell’obbiettivo di permanenza in coda
(esponenziale)
Distanza dall’obbiettivo di espansione
(esponenziale)
FS
TARGET
TARGETXFACTOR
USAGE
CONSUMED
REMAINING
PERCENT
dell’utente
del gruppo
dell’account
relativa alla QOS
della coda
del gruppo
dell’account
relativo alla
della coda
Processori-secondi dedicati
Processori-secondi rimanenti
Tempo del walltime richiesto consumata
(in percentuale)
Tempo dall’avvio del job (in secondi)
EXECUTIONTIME
Tabella 6.1: Componenti e sottocomponenti per il calcolo della priorità in Maui.
34
MAXBALANCE Cerca di allocare ad un job un set di nodi il più possibile bilanciato, in genere riguardo alla velocità di calcolo.
FASTEST Alloca i nodi in ordine di velocità se l’informazione è presente.
LOCAL Se nessuno degli algoritmi proposti risultasse adeguato è prevista la possibilità di interfacciarsi a programmi di allocazione esterni appositamente realizzati.
6.2.3
Meccanismi di Fairness
Come per la vita reale cosı̀ per le decisioni di scheduling ognuno ha una propria
definizione o sensazione di cosa è giusto o non è giusto fare. Mentre Maui non ci può
aiutare nella decisione prettamente politica di scegliere una definizione di giustizia
o fairness il più possibile condivisa con gli utenti del batch system ci offre però
un’ampia gamma di strumenti per la sua implementazione.
Politiche di “throttling”
Le politiche di throttling specificano limiti all’uso del sistema da parte di utenti,
gruppi, account, classi QOS o code. Questi limiti possono riguardare una molteplicità
di aspetti quali il numero di job già in esecuzione, il numero di processori o la memoria
occupata e altri, per partire un job deve rispettare tutti i limiti imposti. È permesso
anche l’utilizzo di coppie di limiti, un primo limite di tipo hard e un secondo limite
di tipo soft meno stretto da utilizzare in condizioni di basso carico del cluster per
mitigare il rischio che strette politiche di throttling riducano l’efficenza complessiva
del cluster.
Fairshare
I meccanismi di Fairshare introducono una visione storica dell’uso delle risorse tra
i fattori che influenzano la priorità dei job. Un amministratore può impostare specifici
target percentuali di utilizzo delle risorse per utenti, gruppi, account, classi QOS e code
insieme alla durata e al numero di finestre temporali da tenere in considerazione. I
parametri a livello di sistema da considerare sono la durata e il numero delle finestre, il
loro apporto al calcolo del valore di fairshare (un fattore di decadimento permette di far
“pesare” maggiormente le finestre più recenti) e la metrica da utilizzare. La finestra
temporale corrente viene aggiornata fino al raggiungimento della durata impostata
quando il sistema la chiude e ne inizia una nuova e le statistiche sui dati cosı̀ compilati
vengono salvate su disco per una futura consultazione da parte dell’amministratore.
Nel caso si voglia intervenire se l’utilizzo di una certa risorsa risultasse minore o
35
maggiore di un dato livello il sistema di fairshare prevede inoltre la possibilità di
impostare valori di floor o caps oltre che valori target.
Manager delle allocazioni
Un manager delle allocazioni (detto anche banca delle allocazioni o banca di cpu)
implementa un meccanismo simile al sistema bancario per la gestione dei limiti d’uso
delle risorse a lungo termine. Una volta specificato come il sistema debba ripartire le
risorse in una finestra temporale abbastanzanza lunga ad ogni account o gruppo di account del sistema viene assegnato un numero di “gettoni” corrispondenti e monitorato
il loro utilizzo. I gettoni di allocazione possono riguardare la totalità del sistema o
specifiche risorse e presentare date di attivazione e scadenza. Possono inoltre essere
previsti “sconti” o maggiorazioni per l’utilizzo delle risorse in particolari fasce orarie
o l’impostazione di requisiti elevati.
6.2.4
Controllo dell’accesso alle risorse
Prenotazioni
Il sistema di prenotazioni (advance reservation) permette di garantire la disponibilità di alcune risorse ad un dato istante futuro nel tempo. Ogni prenotazione consiste
in una lista delle risorse da prenotare, un intervallo temporale di prenotazione e una
lista di accesso alle risorse.
Partizioni
In sistemi particolarmente grandi o complessi si possono riscontrare suddivisioni
interne al cluster per motivi tecnici come la topologia scelta per la rete di collegamento o politici (il cluster è stato formato da gruppi indipendenti che mantengono il
controllo sulle proprie risorse); Maui permette di rispettare i confini di queste suddivisioni forzando i job a non utilizzare risorse che appartengano a partizioni diverse
e consentendo differenti politiche di gestione, limiti e anche algoritmi di scheduling
per partizione. Se non altrimenti specificato una singola partizione di default coprirà
l’intero intervallo di risorse del cluster.
QOS
L’ultimo meccanismo di controllo di accesso implementato da Maui è quello denominato Quality of Service, una serie di liste di privilegi riguardanti priorità e eccezioni
sulle politiche di accesso alle risorse a cui gli utenti, i gruppi, gli account o le code
possono accedere. L’utente aventene diritto può quindi richiedere una specifica classe
di QOS alla sottomissione di un job e la sua successiva modifica.
36
6.2.5
Ottimizzazione del comportamento dello scheduler
Backfill
Il sistema di backfill, se abilitato, permette eccezioni alla regola che l’avvio dei
job eleggibili per l’esecuzione segua il loro valore di priorità. Poichè tutti i job e le
prenotazioni possiedono un valore limite al loro tempo di esecuzione Maui può stimare
quanto tempo potrà passare prima che il job in coda in cima alla lista di priorità abbia
a disposizione le risorse richieste, mentre normalmente non sarebbe possibile avviare
altri job in questo periodo di attesa a backfill attivato si può procedere a creare una
prenotazione per il momento in cui le risorse si libereranno e lanciare altri job che
non interferiscano con la prenotazione. Dovendosi affidare per una stima di durata
dei job ai valori massimi dati dal loro tempo limite il sistema tende per sua natura a
favorire job di breve durata che richiedono poche risorse che più facilmente possono
entrare nelle finestre di backfill mentre può rallentare l’esecuzione di grandi job ad
alta priorità. Questo effetto tipicamente viene però più che compensato dall’aumento
di efficienza del sistema che porta spesso anche i job che sono penalizzati ad essere
eseguiti in un tempo precedente a quello ipotizzabile senza l’intervento del backfill. Per
quanto riguarda la scelta dell’algoritmo da utilizzare per selezionare il job da eseguire
in una data finestra di backfill Maui propone varie alternative, tra cui best-fit e
first-fit. Un’altro parametro da considerare è quello riguardante la profondità
delle prenotazioni dalla lista di priorità da effettuare, dove valori alti garantiscono che
job ad alta priorità non vengano scavalcati mentre valori bassi (il valore predefinito è
1) portano ad un backfill più efficiente.
Set di nodi
In presenza di cluster eterogenei job di natura parallela possono soffrire se non
effettuano un adeguato bilanciamento del carico di lavoro tra processi e si conformano
alle prestazioni dei nodi più lenti, per evitare questo problema e forzare i job su nodi
omogenei possono essere richiesti degli insiemi di nodi dotati di caratteristiche simili
senza che ci sia bisogno di specificarne i valori.
Job preemption
Spesso job a lunga esecuzione non richiedono criticità temporali di esecuzione e
potrebbero rilasciare almeno temporaneamente le risorse da loro occupate ad altri job
dalle richieste più pressanti. Questo meccanismo non è solo prerogativa dei sistemi
multitasking ma può essere utile anche in sistemi batch dove calcoli a lungo termine si
alternano a job ad altissima priorità o dove i nodi di calcolo siano ad esempio computer
desktop riadattati a risorse del cluster quando non utilizzati per il loro scopo primario.
37
La preemption di un job può essere iniziata attraverso l’intervento manuale, le politiche
di QOS o l’uso di un algoritmo di backfill che lo preveda. La sorte del job sottoposto
a preemption può essere la sua sospensione sul nodo, l’inizializzazione di un suo punto
di checkpoint se sono presenti nodi di checkpoint o la sua cancellazione con o senza la
sua reimmissione in coda processi.
6.2.6
Log e simulazioni
Data la flessibilità e la complessità dei vari meccanismi che influenzano il comportamento dello scheduler una precisa raccolta di informazioni risulta chiaramente
un passo necessario per ogni valutazione sul sistema e su eventuali modifiche alla
configurazione. Al fine di consentire un’analisi approfondita dello storico i comandi
diagnostici che Maui mette a disposizione per l’interrogazione dello stato del cluster
e dei job non sono sufficienti, per questo il sistema di fairshare, anche se non abilitato, salva su disco le statistiche d’uso per ogni finestra temporale e ogni job, una
volta terminato, viene registrato come record in un file di tracce di lavoro (workload
traces) insieme alle risorse richieste e utilizzate, le credenziali associate, i tempi di
sottomissione e lancio e altre informazioni, permettendo la compilazione di statistiche
dettagliate sull’uso del batch system e sulle scelte dello scheduler.
Una caratteristica di Maui rilevante è il suo supporto alle simulazioni. Una volta attivata la modalità di simulazione Maui non effettuerà più chiamate al resource
manager nè avrà bisogno di occupare risorse di calcolo ma andrà a simulare in tempi
molto condensati l’andamento dello scheduling. La simulazione dovrà essere per forza
di cose non interattiva, Maui si aspetta infatti di trovare oltre al proprio file di configurazione un file delle risorse del batch system simulato (resourse trace) e un file con i
job da lanciare in sequenza (workload trace). Sia il formato del file di descrizione delle
risorse sia quello dei job da lanciare corrisponde a quello che i due file hanno in caso di
uso reale del sistema e questo permette (superando qualche problema riscontrato) di
ri-simulare situazioni riscontrate nella realtà oltre che situazioni di test ipotetiche.
38
Capitolo 7
L’infrastruttura di analisi,
simulazione e ottimizzazione
Mi domando che cosa facciano ora
tutti questi server, se nessuno è più
qui ad usarli?
Questo dice che offre una stabilità
del 99,9% garantita!
È quasi il 100%!
il Cartellonista Virtuale
7.1
Alcuni problemi da affrontare
Osservando il numero delle variabili di configurazione e di meccanismi di regolazione che mette a disposizione un software di scheduling come Maui si possono
immediatamente apprezzare la potenza e la flessibilità messe al servizio dell’amministratore. Queste caratteristiche, necessarie per affrontare le problematiche di progettazione e gestione di un sistema batch, portano in dote d’altra parte anche una
notevole complessità. Una volta che le decisioni “politiche” sugli obiettivi di gestione
del sistema batch siano state prese, come quote di utilizzo, percentuali di efficenza
complessiva del sistema e varie particolari esigenze, una questione questa che può essere già di suo problematica e delicata ma al di fuori del quadro tecnico vero e proprio
preso qui in esame, rimane da stabilire con quali mezzi e regole queste debbano essere
implementate. In questo contesto la configurazione del sistema batch e in particolare delle complesse politiche di scheduling può rivelarsi spesso un’arte più che una
scienza, dove l’esperienza dell’amministratore fa da guida empirica e, in mancanza di
39
un ambiente di test simile a quello di produzione, improponibile per i costi associati,
trovata una soluzione più o meno soddisfacente si procede per piccoli e graduali aggiustamenti, per non compromettere la produttività del sistema in uso. La vastità
dello spazio di configurazioni in gioco, insieme alla necessità di mantenere stabile il
sistema batch preclude quindi l’esplorazione di scelte radicali nella configurazione e
limita fortemente la reattività dell’ottimizzazione del sistema alla variabilità nel tempo
dei carichi di lavoro.
Un inizio di soluzione al problema ci viene offerto da Maui e dalla modalità di
simulazione di scheduling che questo supporta. In linea di principio Maui consente in
una frazione del tempo e senza l’utilizzo effettivo delle risorse di calcolo di procedere
alla simulazione di situazioni ipotetiche o effettivamente affrontate dallo scheduler,
permettendo l’osservazione delle conseguenze sulla simulazione di variazioni dei job in
input, delle risorse hardware a disposizione, o della configurazione dello stesso Maui.
L’effettiva utilità di tutto questo è però subordinata ad alcune precondizioni:
• Una validazione del simulatore. Una necessaria confidenza nei risultati delle simulazioni è stata acquisita tramite un’analisi di confronto per alcune configurazioni
tra un ambiente di test reale e uno simulato e una successiva validazione di tipo
Monte Carlo.1 Il precedente lavoro di confronto ha messo in luce una divergenza tra casi reali e simulati che è possibile addebitare soprattutto a fenomeni di
quantizzazione dei tempi e overhead presente nei sistemi reali.2 Anche se questi
fenomeni non permettono una coincidenza uno a uno delle assegnazioni job-nodo
effettuate dallo scheduler d’altra parte non inficiano la validità delle simulazioni
per quanto riguarda previsioni a scale più grandi, quelle più interessanti per una
valutazione delle politiche di scheduling.[3]
• Alcuni problemi non documentati sono stati riscontrati durante le predette analisi del simulatore Maui. Una prima difficoltà è sorta quando ci si è resi conto
che importando schemi di sottomissione di job prelevati da log, una traccia reale
dalla farm o dal sistema di test per esempio, tutti i tempi fanno riferimento al
passato e il simulatore al suo avvio si comporta come se le sottomissioni fossero
già tutte effettive, anche se nella realtà erano presenti distanze temporali anche
1I
metodi Monte Carlo costituiscono una classe di algoritmi che sfruttano una campionatura
casuale.
2 La quantizzazione dei tempi deriva dal fatto che Maui permette di impostare una risoluzione
temporale minima di un secondo tra le interrogazioni al resource manager e questo si riflette in tempi
discreti nello scheduling e nei log. Il fenomeno risulta via via più modesto all’aumentare del rapporto
tra tempi di esecuzione dei job e risoluzione temporale e si rivela trascurabile per le durate in termini
di ore o giorni tipiche di sistemi batch reali. Per overhead si intende qui l’insieme di tutti i tempi
necessari al completamento di una operazione non derivanti dalla computazione vera e propria ma
da limitazioni di velocità di componenti come i dischi e la rete alcuni dei quali sono naturalmente
assenti in una simulazione.
40
notevoli. Questo non succede se i riferimenti temporali sono nel futuro rispetto
all’ora di sistema. Un secondo problema sorge dalla sfortunata circostanza che
in simulazione Maui si aspetta di trovare i job in ordine di sottomissione ma al
momento della scrittura delle tracce di log questi vengono scritti solo quando il
sistema dispone di tutti i parametri presenti sulla traccia, cosa che accade solamente alla chiusura del job. Nella realtà quindi i job vengono registrati secondo
l’ordine di fine di esecuzione.[3] Questi inconvenienti compromettono il lavoro
del simulatore proprio nella sua modalità più interessante e promettente, quando cioè si vuole simulare una precedente situazione reale con gli stessi parametri
per assicurarsi della bontà del simulatore, o con una differente configurazione
per valutarne l’impatto. Un uso efficace del simulatore non può prescindere
dalla soluzione di queste problematiche, è stato necessario quindi lo sviluppo
di tool per il riordino delle tracce e per lo spostamento dei relativi riferimenti
temporali.[3]
• Il simulatore richiede alcune procedure manuali per il suo set-up e un’analisi difficoltosa dei risultati a partire dalle tracce di output, per questo risulta utile per
simulazioni sporadiche ma mal si pone per un suo uso intensivo. Lo sviluppo di
un’infrastruttura di automazione costituisce quello che potrebbe essere chiamato
in termini militari un “moltiplicatore di forze” per il simulatore Maui consentendone invece l’utilizzo in estese campagne di simulazione. Questa infrastruttura,
che in un certo modo finisce per reimplementare un batch system specializzato, affianca alla simulazione strumenti per l’analisi e l’ottimizzazione tramite
algoritmi genetici permettendo lo studio del sistema al variare di configurazioni
hardware, parametri di scheduling e carichi di lavoro e la sua ottimizzazione,
aprendo scenari di risposta quasi in tempo reale ai cambiamenti nel carico di
lavoro.
7.2
Metriche di sistema
Ogni utente ha in genere la propria opinione su quanto il sistema batch funzioni più
o meno bene ma per analizzare in modo obiettivo e procedere poi ad un’ottimizzazione
del sistema occorre passare da una valutazione informale ad una misura per quanto
possibile oggettiva della qualità di funzionamento dello scheduler. A questo scopo è
necessario individuare una o più “unità di misura” o metriche che ci possano aiutare
nella quantificazione dei vari aspetti del problema.
41
7.2.1
Metrica di equità
Una prima metrica che è stata proposta è stata quella di equità, che si propone
di misurare quanto il sistema riesca a rispettare le percentuali di risorse attribuite
ad ogni utente o gruppo, un importante parametro di soddisfazione degli utenti.[3]
L’equità del sistema verso un utente (o gruppo) viene definita come “piena” o uguale
a 1 se per ogni dato istante almeno la quota di risorse di cui ha diritto è assegnata a
suoi job, o non ci sono suoi job in coda. É definita come “nulla” o uguale a 0 quando
non ha risorse allocate e ci sono suoi job in coda. Per il calcolo dell’equità si procede
innanzitutto a calcolare un’equità “elementare” per ogni intervallo di tempo ∆Ti senza
nuove assegnazioni o rilasci di risorse secondo la formula
min(Q, ris − R)
(7.1)
ris
dove Q è il numero di job in coda di attesa, ris il numero di risorse (nodi di calcolo)
Eq = 1 −
che spettano all’utente o gruppo in esame, R il numero di job in esecuzione.
Ora è possibile definire l’equità globale del sistema come
n
P
Eqi ∆Ti
Eq = i=1P
n
∆Ti
(7.2)
i=1
dove n è il numero di intervalli temporali presi in considerazione.
7.2.2
Metrica di efficienza
La metrica di efficienza cerca di misurare il grado di utilizzo del sistema in condizioni di carico. L’efficienza è definita come piena o uguale a 1 quando tutti i nodi
di calcolo sono impegnati nell’esecuzione di job e nulla quando nessun job è in stato
di esecuzione nonostante esistano job in coda.[3]
L’efficienza elementare, in ogni intervallo temporale, è definita come il rapporto
tra i job in esecuzione e le risorse di sistema:
job
(7.3)
ris
Per ogni job viene inoltre definita l’“efficienza relativa alla sua attesa” come piena se
Ef fi =
il suo tempo di attesa in coda è stato nullo
Ef fjob = 1
(7.4)
o come media pesata sulla durata degli intervalli di tempo ∆T passato in coda delle
efficienza elementari negli altri casi
m
P
Ef fjob =
Ef fi ∆Ti
i=1
m
P
i=1
42
(7.5)
∆Ti
Figura 7.1: L’infrastruttura hardware
Definitito come ∆Q il tempo in coda per ogni processo l’efficienza complessiva del
sistema risulta essere
n
P
Ef f =
Ef fjobi ∆Qi
i=1
n
P
(7.6)
∆Qi
i=1
7.3
Anatomia dell’infrastruttura
L’implementazione dell’infrastruttura visibile in fig. 7.1 ha comportato la preparazione
di alcune macchine, sia reali che virtuali, per una serie di mansioni: un cluster di test
TORQUE/Maui consistente di 4 nodi per i test e la validazione del simulatore, una
macchina con funzione di repository per conservare le tracce di scheduling reali, quelle
simulate e le direttive al sistema di simulazione e un numero variabile di macchine
virtuali per le simulazioni vere e proprie.
7.3.1
La farm di produzione
La farm di produzione consiste nel cluster della sede locale INFN precedentemente descritto. Il cluster costituisce sia una fonte di preziosi dati da analizzare
derivanti da un uso reale “sul campo” di TORQUE e Maui sia l’obbiettivo ultimo delle ottimizzazioni delle politiche di scheduling generate con l’infrastruttura di
ottimizzazione.
43
7.3.2
La farm di test
Il valore e il limite dei dati generati dalla farm locale INFN risiede proprio nella
sua natura di cluster di produzione, se da un lato fornisce tracce “reali” che non
sarebbe possibile ottenere altrimenti e che forniscono un necessario riscontro tra la
teoria delle simulazioni e la pratica di un batch system “vero” dall’altro per la sua
complessità non si presta a una facile comprensione dei meccanismi che legano i carichi
di lavoro e i parametri di configurazioni alle decisioni dello scheduler. Per questo si
è resa necessaria l’implementazione di un cluster di test che costituisca un ambiente
semplificato da usare come modello su cui mettere alla prova e verificare semplici
configurazioni, non rinunciando al contempo alla genuinità di un sistema reale.
Il cluster di test è costituito da una macchina central manager e 4 nodi di tipo
worker node in rete locale, lo stesso central manager viene usato per il ruolo di user interface del cluster, mentre non sono necessari nodi con funzioni di file server o
checkpoint dato il compito esclusivo di ricerca e valutazione. Come sistema operativo
per i 5 nodi è stato scelta la distribuzione GNU/Linux Debian 4.0, avendo scelto il
protocollo SSH per i trasferimenti file tra i nodi del cluster si è poi provveduto a
installare e configurare su tutti i nodi OpenSSH in modalità host based authentication
che prevede l’autenticazione per tutti gli utenti a livello di macchine tramite chiavi
crittografiche pre-distribuite, senza bisogno di password o chiavi crittografiche distinte
per ogni utente.3 Conclusa la configurazione dell’ambiente operativo si è passati alla
installazione del batch system vero e proprio. TORQUE versione 2.3.0 è stato installato con supporto per i trasferimenti tramite scp, nel nodo centrale nella sola modalità
server con le opzioni di compilazione --disable-mom e --with-scp, nei nodi di esecuzione è stato disabilitato il demone server e abilitato il client con --disable-server
e --with-scp, per quanto riguarda la sua configurazione è poi bastato impostare i nomi dei worker node nel file nodes sul central manager e il nome della macchina central
manager su server_name sui worker node. Sul central manager è poi stato compilato
ed installato come scheduler Maui nella versione 3.2.6p19, configurato per interfacciarsi con il demone TORQUE server locale con la direttiva di compilazione --with-pbs
e le apposite opzioni nel file maui.cfg.
7.3.3
Il repository server
La macchina di repository costituisce il cuore dell’infrastruttura hardware, tra i
suoi compiti ricadono i servizi di gestione e deposito delle tracce reali e simulate, viene
inoltre usato per l’avvio e la sincronizzazione delle operazioni e per servizi di comunicazione del resto dell’infrastruttura. Come server di repository è stata allestita una
3 SSH
o Secure Shell è un protocollo di rete per lo scambio di dati su connessioni criptate, OpenSSH
è una suite di programmi che implementano il protocollo sviluppati all’interno del progetto OpenBSD.
44
macchina con sistema operativo GNU/Linux Debian. Per poter assolvere alla funzione
di deposito di tracce Maui si è scelto di implementare un repository rsync. rsync è
un programma di trasferimento file sviluppato come alternativa più sicura ed efficente
a rcp che, dove possibile, trasferisce solamente le differenze tra file minimizzando il
volume di dati. Usato sul repository server in modalità demone accetta connessioni
da macchine remote per servizi di trasferimento file anche con connessioni sicure usando il protocollo ssh.4 Allo stesso modo ssh viene usato in modalità demone come
interfaccia dei tool di gestione al repository.
Struttura del repository
Il repository rsync si occupa dell’immagazzinamento sia delle tracce di log Maui,
derivate dalla farm di produzione, dal cluster di test o da simulazioni, sia delle direttive
alle macchine di simulazione. Per la gestione di queste differenti informazioni è stato
necessario prevedere una precisa struttura logica del repository illustrata in fig. 7.2
nella pagina successiva.
traces. Contiene alcune sottodirectory speciali e tutte le directory con gli input e
output del sistema di simulazione. La directory di ogni lavoro di simulazione
contiene alcuni file di configurazione e le eventuali sottodirectory con le tracce.
traces/000000-production-farm. La prima directory speciale contiene in sottodirectory, il cui nome segue la convenzione ANNO-MM-GG, le tracce reali provenienti dalla farm di produzione, opportunamente compresse. Viene popolata
giornalmente da uno script in cron sul CE.
traces/000000-jobqueue. Una seconda directory speciale che contiene una serie di
direttive per le macchine di simulazione, raggruppate in un singolo run. All’interno delle sottodirectory un file denominato command.sh contiene i comandi
da eseguire e, a loro esecuzione terminata, gli eventuali output ed errori delle
macchine di simulazione coinvolte sotto forma di file dal nome corrispondente
all’identificativo della macchina ed estensione .o (gli output) e .e (gli errori).
traces/test-foo. Una tipica directory contenente un lavoro di simulazione od ottimizzazione. Al suo interno possiamo trovare alcuni file di configurazione da
preparare anticipatamente e una serie di sottodirectory, una per ogni singola
simulazione o test effettuato. Nel file di configurazione run.conf andremo a
scrivere le necessarie opzioni del run, resources specifica le risorse del cluster
nel formato richiesto da Maui, config-simul-template è un template del file
4 Un
programma demone è un programma di servizio in genere in esecuzione in background dal
momento di avvio della macchina al suo arresto. ssh o secure shell è un protocollo e un programma
per la connessione remota che fornendo un canale criptato per la comunicazione.
45
Figura 7.2: Struttura del repository rsync
46
di configurazione dove opportune variabili verranno poi sostituite per la generazione dei file di configurazione Maui per ogni simulazione o test del run,
workload-real-unscaled è l’eventuale file di log di traccia da ridare in pasto
al simulatore. Le sottodirectory create via via che l’esecuzione del run procede
vengono denominate concatenando ad un prefisso comune il genotipo identificativo della singola simulazione o test, cioè l’effettivo valore assunto dalle variabili
del template di configurazione. All’interno delle sottodirectory si trovano tutti
i file necessari alla simulazione o test in esame come i file config e resources
generati a partire dal template e dal file resources del run, un file denominato
duration con il tempo di esecuzione della simulazione o test e i file di traccia
workload reali e simulati nelle varie versioni riordinate o meno, spostate o meno
nel tempo. Come si vedrà ad ogni lavoro e ad ogni simulazione o test sono ulteriormente associate alcune proprietà che ne descrivono tipologia, stato e altri
parametri.
7.3.4
Le macchine di simulazione
Le macchine di simulazione sono macchine virtuali xen lanciate e fermate alla
bisogna su cui è stato installato lo scheduler Maui e gli script di interfaccia con il
server di repository. Possono eseguire job di simulazione e test dello scheduling o
qualsiasi altra direttiva impartita loro impostando run nel repository. Le macchine
di simulazione sono impostate per lanciare all’avvio lo script superexecute.sh che
interroga ad intervalli regolari il server di repository alla ricerca di job.
7.3.5
Stazioni di controllo e analisi
Qualsiasi macchina su cui siano stati installati i comandi client forniti da Maui e
i necessari script sviluppati può essere utilizzata per il lancio di job di simulazione o
ottimizzazione e per la successiva analisi dei risultati.
7.4
Fisiologia e software dell’infrastruttura
L’ambiente unix tipico delle installazioni TORQUE/Maui offre una vasta scelta di
linguaggi di script e potenti comandi di sistema di cui è possibile avvalersi, il software
per l’infrastruttura di analisi, simulazione e ottimizzazione è stato quindi implementato
sotto la forma di una nutrita serie di script interagenti tra loro, la maggioranza dei
quali si è scelto di implementare in linguaggio di shell Bash o in Perl per considerazioni
47
di standardizzazione dei requisiti software e praticità nel richiamare comandi e utility
di sistema.5
7.4.1
I run
Con il nome di “run” si è chiamato una serie automatizzata di job di test o simulazione in correlazione tra loro ma corrispondenti a specifiche variazioni nella configurazione di scheduling. Un numero variabile di run di vario tipo coesiste nel repository
server in vari stadi di avanzamento:
fulltree run. Un run di tipo fulltree o enumerativo implementa l’idea di simulare
tutte le possibili combinazioni di una o più variabili di configurazione, con l’intento di esaminarne successivamente l’impatto sul sistema. Necessariamente ci
si dovrà limitare a un numero di variabili limitato dato che al crescere delle variabili da considerare il numero di configurazioni da simulare cresce velocemente
fino a oltrepassare facilmente le risorse di simulazione e il tempo realisticamente
disponibile. I run di tipo fulltree possono essere eseguiti in modalità locale
(l’intera esecuzione avviene sulla macchina locale e i risultati rimangono a disposizione in locale) o remota, nel qual caso i risultati vengono caricati sul server
di repository e l’esecuzione può essere coordinata in collaborazione in parallelo
tra più macchine di simulazione.
random run. Un run random consiste di un certo numero di configurazioni di combinazioni casuali per le variabili date. L’idea è quella di sottoporre una serie
di configurazioni casuali a sistemi di simulazione e sistemi cluster di test per la
successiva comparazione dei risultati e un’eventuale validazione Monte Carlo del
simulatore Maui limitatamente ai parametri selezionati.
genetic run. Il tipo di run genetico, raffigurato in fig. 7.3 a fronte è quello più interessante per quanto riguarda l’obbiettivo finale di ottimizzazione del cluster di
produzione: si tratta infatti di un run di ottimizzazione genetica sulle variabili
date. Particolare cura deve essere posta alla scelta della funzione di fitness che
deve rispecchiare la totalità degli obbiettivi desiderati rappresentandoli in modo
matematico.
7.4.2
Il sottosistema delle feature
Allo scopo di memorizzare lo stato di avanzamento di run e tracce e alcuni altri
parametri e meta-dati loro associati è stato sviluppato un sistema per impostare per
5 Bash
(Bourne Again SHell) è una shell unix scritta per il progetto GNU della Free Software
Foundation usata in molte distribuzioni linux come shell predefinita di sistema. Perl è un potente
linguaggio interpretato di scripting.
48
Figura 7.3: Struttura logica dell’infrastruttura di ottimizzazione
ogni directory sul server di repository delle feature o caratteristiche a cui sono associati
uno o più stati a piacere.6 La natura arbitraria delle feature e degli stati associati
assicura la versatilità del sistema e la possibilità di accomodare facilmente successive
espansioni. Dato che le feature sono una proprietà di tracce e job che risiedono sul
server e non hanno un corrispettivo locale sulle macchine di simulazione o analisi sono
state implementate sotto la forma di file di testo nascosti sulle directory del repository
corrispondenti il cui nome è del tipo .\{nome-feature}-status.lock e il cui contenuto corrisponde agli stati associati alla feature, uno per riga se multipli. L’interfaccia
alle feature per l’utente e gli script delle macchine di simulazione è costituita dagli
script sync-traces.sh, con il quale è possibile leggere, scrivere e cancellare gli stati
relativi alle feature e ls-feat.sh che ritorna una lista di tracce con uno specifico stato
di una feature a scelta. L’uso delle feature nel sistema di simulazione e ottimizzazione
coinvolge i job in traces/000000-jobqueue, gli alberi delle tracce di ogni singolo run
e le tracce al loro interno.
Per quanto riguarda i job la prima feature letta dal sistema è type, che indica
se il run è da eseguirsi in modo parallelo o meno. Gli script per la gestione dei
job tengono poi traccia dei stati di avanzamento attraverso la feature status, che
può assumere i valori ready, per un job pronto ad essere eseguito, running, per un
job di tipo parallelo in fase di esecuzione, taken, per un job non parallelo già preso
in carico e in esecuzione, exitwait, usato durante l’esecuzione di job paralleli per
segnalare un lock temporaneo da parte di una macchina di simulazione e ok che indica
l’avvenuta esecuzione e completamento del job. Con la feature crunning vengono
infine memorizzati via via gli identificativi delle macchine che hanno in esecuzione il
job.
Per i run viene invece utilizzata la feature status, che assume i valori ready, pronto, generating, in fase di creazione dell’albero delle tracce, running, in lavorazione,
runned, completato, le feature startgenerating e stopgenerating con le date di
inizio e fine generazione dell’albero delle tracce, start{idclient} e stop{idclient}
con le date di start e stop per ogni client e nuovamente crunning con gli identificativi
delle macchine che stanno eseguendo il run.
6 Per
meta-dati, “dati sui dati”, si intendono gli attributi e le informazioni descrittive dei dati veri
e propri, nel caso specifico tracce e run.
49
Alle singole tracce sono infine associate le feature status che assume i valori ready,
simulating e simulated in successive fasi, clid con l’identificativo della macchina
che simula la traccia, duration con la durata in secondi della simulazione. In caso
di ottimizzazioni genetiche è poi presente la feature fitness con indicato il valore di
fitness della traccia.
7.4.3
Sottomettere un run: run.conf e command.sh
La sottomissione di un run all’infrastruttura inizia con la creazione di una directory locale con all’interno gli eventuali file di traccia necessari, il file scheletro di
configurazione di Maui config-simul-template, il file delle risorse Maui resources
e un file chiamato run.conf che contiene tutte le informazioni sul tipo e i parametri
del run. Per la descrizione delle opzioni di configurazione, che prendono la forma
OPZIONE=valore, si rimanda all’appendice A. Una volta completata la directory di
base del run quest’ultima deve essere immessa in traces nel server di repository con
sync-traces.sh.
command.sh è il file che le macchine di simulazione andranno a scaricare ed eseguire. Si tratta di un semplice file eseguibile, in genere un batch file che richiama
lo script run.sh passandogli i parametri opportuni come la directory di base del run
precedentemente creata e il server di repository. Il file command.sh va a sua volta
caricato nel repository, in una directory all’interno di traces/000000-jobqueue.
Una volta caricati tutti i file nel repository l’unica cosa che rimane da fare è
impostare a ready la feature status della directory di base del run, a parallel la
feature type della directory del job dentro traces/000000-jobqueue che contiene il
file command.sh se il tipo di job è parallelo, e, successivamente, a ready la sua feature
status. Le macchine di simulazione procederanno autonomamente all’individuazione
e all’esecuzione dei nuovi job sottomessi.
7.4.4
Tool per la gestione dell’infrastruttura
functions.sh
La necessità di raggruppare alcune funzioni che implementano operazioni comuni
in vari script ha portato alla nascita di questo script con funzioni di libreria che mette
a disposizione le seguenti subroutine:
check prerequisite(). Controlla l’esistenza di un file su disco, anche in formato
compresso.
check variable(). Controlla se una variabile è vuota.
50
check status(). Controlla se lo stato di una feature di traccia sul repository server
corrisponde allo stato dato.
set status(). Imposta uno specifico stato per una data feature di traccia sul repository server.
unset status(). Cancella, se esiste, uno specifico stato per una data feature di traccia
sul repository server.
flush status(). Cancella tutti gli stati per una data feature di traccia sul repository
server.
superexecute.sh
Lanciato una volta effettuato il boot dalle macchine di simulazione, contatta ad intervalli il repository server per cercare nuovi job di simulazione o test a cui la macchina
può partecipare, quando ne trova disponibili provvede a scaricarli in locale ed eseguirli,
preoccupandosi poi di ricaricare sul server gli output e gli eventuali errori (fig. 7.4 nella
pagina successiva). Le operazioni di interrogazione e aggiornamento dal server dei job
vengono effettuate in mutua esclusione con le altre macchine di simulazione tramite l’utilizzo di procedure di lock/unlock richiamando scripts/manager/client.py, le operazioni di interrogazione, impostazione e lettura dello stato dei job e trasferimento file
si appoggiano invece a scripts/utils/ls-traces.sh, scripts/utils/ls-feat.sh
e scripts/utils/sync-traces.sh.
scripts/manager/client.py e scripts/manager/scheduler.py
L’accesso parallelo delle macchine impegnate in simulazioni ed ottimizzazioni può
costituire un pericolo per l’integrità dello stato e la correttezza dei dati nel repository,
se l’uso delle feature tiene aggiornati i vari client sullo stato corrente di job e tracce
rimangono finestre temporali critiche nell’accesso vero e proprio al repository che, per
quanto strette, potrebbero portare a risultati imprevedibili in caso di alcune sfortunate
operazioni simultanee se non protette. A questo scopo è stato implementato un sistema
di messaggi tra client per l’accesso in mutua esclusione al repository scritto in python
che sfrutta la libreria Spread.7
client.py costituisce la parte client del sistema di messaggistica in esecuzione sulle
macchine di simulazione, scheduler.py la parte server in esecuzione sulla macchina di
repository, accetta connessioni dalle macchine di simulazione e implementa una coda
di accesso alla risorsa.
7 Spread
è un toolkit per il message passing, per maggiori informazioni è possibile consultare il sito
web del progetto all’indirizzo http://www.spread.org.
51
Figura 7.4: Ciclo di esecuzione di superexecute.sh
scripts/utils/ls-feat.sh
A little script to list remote traces with a specific feature/characteristic.
Usage: ./scripts/utils/ls-feat.sh [-t trace] [-s server] -f feature -c characteristic [-n num] [-h]
-t target trace pathname (default: root)
-s server remote traces server (default: mauirep.fisica.unipg.it)
-f feature feature
-c characteristic characteristic
-n num max number of trace to return
-h this help.
Riporta una lista di tracce presenti sul repository server caratterizzate dallo specifico
stato di una feature richiesto. Il numero di risultati ottenuti può essere limitato.
Questo script viene sfruttato da superexecute.sh per l’interrogazione del server di
repository sull’esistenza di job in stato ready o running e collaborativi, viene inoltre
richiamato da run.sh in caso di run con esecuzione di tipo parallelo per la selezione
di un lancio o simulazione da eseguire.
scripts/utils/ls-traces.sh
A little script to list remote traces.
Usage: ./scripts/utils/ls-traces.sh [-r] [-g] [-t trace] [-s server] [-h]
-t target trace pathname (default: root)
-s server remote traces server (default: mauirep.fisica.unipg.it)
52
-r recursive
-g graph, output a tree like vista
-h this help.
Uno script che riporta una lista di tracce remote disponibili sul repository server.
Accetta opzioni per la richiesta di elencare in modo ricorsivo le sottodirectory o per
generare una vista ad albero simile a quella messa a disposizione dal comando unix
tree.
scripts/utils/sync-traces.sh
Usage: ./scripts/utils/sync-traces.sh [-g|-p] [-d] [-n] [-q] -t trace -s server [-h]
./scripts/utils/sync-traces.sh -e [-q] -t trace -s server [-h]
./scripts/utils/sync-traces.sh -r [-q] -t trace [-h]
./scripts/utils/sync-traces.sh [-S|-U] [-q] -c char -f feat -t trace -s server [-h]
./scripts/utils/sync-traces.sh -R [-q] -f feat -t trace -s server [-h]
./scripts/utils/sync-traces.sh -A [-q] -t trace -s server [-h]
Perform various tasks relative to traces syncronization.
-s server remote traces server.
-t target name of the trace.
-g get, download remote trace from server.
-p put, upload trace to the remote server.
-d delete on sync, files not present on source will be removed from destination.
-n do NOT sync subdirectories.
-r remove, delete a local trace.
-e exists, check if target exists on remote server, -s, -t required.
-q quiet, output only error messages.
-f
-c
-S
-U
-R
feature feature to set, unset or read.
characteristic value of the feature to set, unset.
set, set a characteristic of a feature, -f, -c, -s, -t required.
unset, remove a characteristic of a feature, -f, -c, -s, -t required.
read, report the characteristics of a feature, -f, -c, -s, -t required.
-A read all, report all the characteristics of all the features, -s, -t required.
-h this help.
Usage examples:
to get target from server: ./scripts/utils/sync-traces.sh -g -t target -s server
to put target in server: ./scripts/utils/sync-traces.sh -p -t target -s server
to remove a local target: ./scripts/utils/sync-traces.sh -r -t target
to check existance of a target on server: ./scripts/utils/sync-traces.sh -e -t target -s server
to set a characteristc of a feature: ./scripts/utils/sync-traces.sh -S -c char -f feat -t target
-s server
to unset a characteristc of a feature: ./scripts/utils/sync-traces.sh -U -c char -f feat -t target
-s server
53
to
-s
to
-s
read the characteristcs of a feature: ./scripts/utils/sync-traces.sh -R -f feat -t target
server
read the characteristcs of all the features: ./scripts/utils/sync-traces.sh -A -t target
server
sync-traces.sh implementa l’interfaccia al repository, pensato per essere lanciato
direttamente dall’utente in fase di preparazione e in fase di analisi o richiamato da
altri script mette a disposizione funzioni che è possibile raggruppare in due tipologie:
la sincronizzazione delle tracce e la gestione delle feature loro associate. Per quanto
riguarda la sincronizzazione delle tracce viene supportato l’upload e il download tra la
macchina locale e il repository, interrogazioni al repository e cancellazioni locali, per
quanto riguarda le feature è possibile la lettura, la scrittura e la cancellazione degli
stati associati a una feature o l’interrogazione di tutte le feature impostate con i loro
stati associati. Al suo interno lo script usa ssh per eseguire comandi sul repository e
rsync per le operazioni di trasferimento file.
scripts/utils/trace-uploader.pl
Un uploader di file di traccia, specificati direttamente o selezionati indicando la data desiderata, dalla macchina locale al repository server. Viene utilizzato per l’update
giornaliero delle tracce dal cluster di produzione al repository.
7.4.5
Tool di preparazione tracce
Le macchine di un cluster di calcolo necessitano di una configurazione armonizzata
per quanto riguarda batch system, utenti e gruppi. Questa famiglia di script si preoccupa della configurazione del cluster e della preparazione dei file di traccia prima di
procedere alla fase di esecuzione.
scripts/batch-utils/make-queues.sh
Richiamando il comando di Maui qmgr questo tool resetta la configurazione corrente delle code nell’istallazione locale dello scheduler e le ricrea a partire da un file
di configurazione passato come parametro.
scripts/launcher/clear-master-node
Cancella sulla macchina locale i file di log, le tracce e le directory degli utenti del
batch system.
54
scripts/launcher/farm prerequisites.sh
Dopo aver letto una lista di nodi del cluster da un file passato come parametro
accerta che i nodi siano raggiungibili, che accettino comandi e che gli orologi di sistema
siano sincronizzati.
scripts/launcher/sleep-launcher.sh
Si rivela utile spesso per la realizzazione di test la creazione di job di tipo sleep
di durata a piacere, la cui unica funzione è quella di occupare tempo di cpu. Questo
script legge da un file una sequenza di sottomissione specifica e procede a sottomettere
i job sleep a tempo appropriato.
scripts/users-utils/users-get.sh
Stampa la lista di utenti e gruppi del sistema locale, per procedere successivamente
alla loro clonazione sulle altre macchine del cluster come richiesto dal batch system.
scripts/users-utils/users-make.sh
Crea utenti e gruppi da un file di input sulla macchina locale. Lo script permette la
creazione di utenti e gruppi con medesimo uid e gid su tutte le macchine del cluster.
scripts/utils/resolve-users.sh
Generate a random config-users file from run.conf directives
Usage: ./scripts/utils/resolve-users.sh tracedir
Sulla base delle direttive NUMGROUPS e USERSPERGROUP nel file locale run.conf procede
alla creazione di una configurazione di utenti e gruppi del batch system in loro accordo.
Le direttive su utenti e gruppi possono specificare valori assoluti o range di valori, nel
qual caso lo script sceglie casualmente un numero di utenti o gruppi nei range dati.
scripts/utils/resolve-queues.sh
Generate a random queues file from run.conf directives to pass to make-queues.sh
Usage: ./scripts/utils/resolve-queues.sh tracedir
In modo speculare allo script precedente genera una configurazione casuale delle
code del batch system secondo i valori o i range impostati nelle direttive QUEUES e
QUEUEWALLTIME presenti nel file locale run.conf.
scripts/utils/resolve-schedule.sh
Generate a random schedule file from run.conf directives to pass to sleep-launcher.sh
Usage: ./scripts/utils/resolve-schedule.sh tracedir
55
Come terzo script di generazione di configurazioni casuali resolve-schedule.sh si
occupa della generazione di uno schedule di lancio da passare a sleep-launcher.sh.
Le direttive interessate in run.conf sono JOBS per il numero di job, JOBSTARTTIME
per i tempi di lancio dei job e JOBLIFESPAN per la loro durata, ad ognuna delle quali
è possibile associare un valore specifico o un range di possibilità.
scripts/utils/resolve-variables.pl
Questo script interpretando il file run.conf risolve le direttive di tipo VARINTERVAL
e VARENUM che specificano range o insiemi di valori per le variabili usati per i run di
ottimizzazione genetica e per quelli di tipo fulltree.
scripts/utils/run-at.pl
Lancia lo scheduler Maui al raggiungimento di una data e ora specificata come
argomento dello script.
scripts/utils/trace-assembler.pl
Concatenando tracce giornaliere, come quelle provenienti dalla farm di produzione,
crea una nuova traccia Maui.
scripts/utils/workload-clean.pl
Le tracce che scrive Maui contengono alcuni commenti e altri elementi non essenziali, questo script ripulisce una traccia in modo da renderla utilizzabile per l’analisi
o il suo utilizzo nel simulatore.
scripts/utils/workload-first-submitted.pl
Individua e scrive in output il più piccolo tra i tempi di accodamento dei job nella
traccia passata come argomento allo script.
scripts/utils/workload-time-updater.pl
Questo script prende in input il nome di un file di traccia, ne sposta i riferimenti
temporali di un offset indicato come opzione e salva un nuovo file di traccia. Questa
operazione risulta necessaria per ovviare alle limitazioni ad operare con file di traccia che presentino riferimenti temporali passati da parte di Maui quando usato in
simulazione.
56
Figura 7.5: Ciclo di esecuzione di run.sh
7.4.6
Tool di simulazione, test e ottimizzazione
run.sh
Usage: ./run.sh
-r|-l -t trace [-s server] [-h]
-s server
-t trace
remote traces server.
name of the trace.
-r|-l
remote or local operations.
-h
this help.
Usage examples:
local operations: ./run.sh -l -t trace
remote operations: ./run.sh -r -t target -s server
Lo script che si preoccupa della gestione ad alto livello dei run. Come si può osservare
in fig. 7.5 quando run.sh viene lanciato dalle macchine di simulazione su di un run
procede a leggere configurazione e tipo del run dal file run.conf e il suo stato di
esecuzione leggendo le feature dal server di repository. In caso di run di tipo fulltree
ad esecuzione locale o remota non parallela, o in caso di run ad esecuzione parallela
collaborativa in cui la macchina che esegue lo script è la prima macchina a prendersi
carico del run è necessario che lo script generi l’intera struttura di tracce corrispondenti
alle possibili combinazioni delle variabili del run. Una volta che l’albero delle tracce sia
stato generato run.sh può lanciare simulate.sh o launch.sh su ogni singola traccia
Maui per procedere alle effettive simulazioni o test.
launch.sh
Usage: ./launch.sh [-l|-r|-p|-k] [-u] -t trace [-s server] [-h]
-t target pathname of target
-s server remote traces server
-r, -l download target from remote server or use local target
-p put result on remote server
-k do not erase local target on exit
57
Figura 7.6: Ciclo di esecuzione di launch.sh
-u check & set launching/ed status
-h this help.
Usage examples:
launch from local to local: ./launch.sh -l -k -t target
launch from remote server to local: ./launch.sh -r -k -t target -s server
launch from local to remote server: ./launch.sh -l -p -t target -s server
launch from local to remote server and keep a local copy: ./launch.sh -l -p -k -t target -s server
launch from remote server to remote server: ./launch.sh -r -p -t target -s server
launch from remote server to remote server and keep a local copy: ./launch.sh -r -p -k -t target
-s server
Lo script launch.sh esegue un test di scheduling Maui sulle macchine di test gestendone le fasi pre e post esecuzione. Sia per quanto riguarda le tracce in input sia per
quanto riguarda l’archiviazione dei risultati si può operare in locale o appoggiarsi al
server di repository. La sequenza di lancio prevede prima del lancio dello scheduler il
controllo dello stato della traccia di esecuzione da lanciare con la lettura della feature
“status” corrispondente sul repository, allo scopo di evitare il lancio di test già in
corso o precedentemente effettuati, il controllo dei file di traccia e di configurazione
necessari all’esecuzione di Maui e il controllo dello stato dei nodi di calcolo indicati
in configurazione e la loro riconfigurazione. Terminata l’esecuzione di Maui lo script
imposta a lauched la feature “status” sul repository e, se richiesto, procede all’upload
dei risultati (fig. 7.6).
58
simulate.sh
Usage: ./simulate.sh [-l|-r|-p|-k] [-u] -t trace [-s server] [-h]
-t target pathname of target
-s server remote traces server
-r, -l download target from remote server or use local target
-p put result on remote server
-k do not erase local target on exit
-u check & set simulating/ed status
-h this help.
Usage examples:
simulate from local to local: ./simulate.sh -l -k -t target
simulate from remote server to local: ./simulate.sh -r -k -t target -s server
simulate from local to remote server: ./simulate.sh -l -p -t target -s server
simulate from local to remote server and keep a local copy: ./simulate.sh -l -p -k -t target
-s server
simulate from remote server to remote server: ./simulate.sh -r -p -t target -s server
simulate from remote server to remote server and keep a local copy: ./simulate.sh -r -p -k
-t target -s server
Uno script parallelo a launch.sh per il lancio di Maui come simulatore che accetta le
stesse opzioni per l’interfaccia con il server di repository. Si può vedere in fig. 7.7 nella
pagina seguente come i controlli che simulate.sh effettua sulle tracce siano simili a
quelli di launch.sh, ulteriori operazioni sia in fase di preparazione che in fasi di postsimulazione sono però necessarie a causa delle limitazioni della modalità di simulazione
Maui. Per ottenere da una traccia di log una traccia usabile in input dal simulatore
devono essere prima richiamati in sequenza workload-first-submitted.pl, per riordinare i job in ordine di sottomissione, e workload-time-updater.pl, per spostare in
avanti i riferimenti temporali, mentre a simulazione terminata workload-time-updater.pl
e workload-clean.pl devono essere applicati alla traccia in output per reimpostare
i riferimenti temporali originali e pulirla da commenti e dati non essenziali.
scripts/genetic/analyze-generation.pl
Questo è il primo di una coppia di script che implementano le procedure per la
selezione ed evoluzione per run di ottimizzazione genetica. analyze-generation.pl
legge i parametri genetici del run dal file run.conf per poi usare la procedura di
calcolo della fitness indicata dalla istruzione FITNESS lı̀ contenuta per il calcolo del
valore di fitness per ogni individuo della popolazione corrente.
scripts/genetic/generate-generation.pl
Dopo aver letto le opzioni genetiche del run dal file di configurazione run.conf
(variabili da evolvere e tassi di crossover e mutazione) e i valori di fitness di ogni indi59
Figura 7.7: Ciclo di esecuzione di simulate.sh
viduo precedentemente calcolati da analyze-generation.pl provvede alle operazioni
di crossover e mutazione degli individui presi in esame e genera una nuova popolazione
di potenziali soluzioni.
7.4.7
Tool di analisi
visualize.sh
Usage: ./visualize.sh [-k] [-p plug-in] [-s server] -t trace [-h] [plug-in options]
Trace visualizer.
-k keep trace after download and visualization.
-p visualizer plug-in. [default timeliner].
-s server remote traces server.
-t trace name of the trace.
-h this help.
Other options will be passed to the plug-in.
Usage examples:
to visualize a local trace: ./visualize.sh -t trace [-p timeliner] [plug-in options]
to visualize a remote trace: ./visualize.sh -s server -t trace [-p timeliner] [plug-in options]
to visualize and keep a local copy of a remote trace: ./visualize.sh -k -s server -t trace
[-p timeliner] [plug-in options]
60
Figura 7.8: Timeline di scheduling generata da trace-timeliner.pl
Lo script visualize.sh genera grafici a partire da tracce Maui locali o sul server di repository. Grazie ad una struttura a plug-in varie tipologie di grafici possono essere supportate, ad esempio la visualizzazione di timeline di tracce tramite
trace-timeliner.pl come si può vedere in fig. 7.8.
scripts/run-analyzer.pl
Un tool sviluppato per l’analisi dei run sottomessi all’infrastruttura, richiama
workload-analyzer sulle singole tracce del run per l’estrazione dei dati di traccia
da visualizzare direttamente o usare per il calcolo di valori aggregati relativi all’intero
run.
scripts/workload-analyzer.pl
Uno strumento molto potente che permette l’estrazione, la manipolazione e l’analisi
dei contenuti informativi racchiusi nella traccia di Maui. Lo script supporta operazioni
di selezione di record e campi della traccia, sorting dei risultati, calcolo di valori medi
semplici e aggregati su altri campi e il calcolo delle metriche per l’analisi dei risultati.
scripts/trace-timeliner.pl
Un tool per il confronto grafico che a partire da file di traccia Maui genera grafici
2d con linee temporali di attività dei nodi del cluster. I grafici, costruiti richiamando
il pacchetto Gnuplot, presentano sulle ascisse lo scorrere del tempo e sulle ordinate i
nodi di calcolo, dove sono disposti i vari segmenti di linea corrispondenti ai tempi di
esecuzione e terminazione e alla durata di ogni job. L’utilizzo di questa particolare
visualizzazione permette facilmente di valutare fenomeni di overhead ed eventuali
errori nel caso di simulazioni.
61
scripts/workload-compare.pl
Un semplice script che permette di calcolare lo scarto quadratico medio nel tempo
di attesa in coda tra i job di due tracce Maui.
62
Capitolo 8
Test e simulazioni
Essentially, all models are wrong,
but some are useful.
George E. P. Box
Una serie di test dell’infrastruttura sono stati eseguiti allo scopo di verificarne
l’implementazione e avviare uno studio sull’impatto di vari parametri e configurazioni
relativi al meccanismo di fairshare di Maui.
8.1
Test sul Fairshare
Un primo test sull’impatto del Fairshare sul tempo di attesa medio dei job effettuato sulla farm di test.
Configurazione
Per osservare e misurare l’impatto del fairshare si sono studiati una serie di casi
semplici in ambiente controllato. In questo caso lo scheduler della farm di test è stato
impostato con due soli utenti, il primo ha valore di FSTARGET fisso a 50 e tutti i
possibili valori di FSTARGET tra 1 e 100 per il secondo utente sono stati testati. Per
far si che la politica di scheduling risponda esclusivamente ai valori di target per il
fairshare tutti gli altri parametri sono stati impostati come non influenti. Le finestre
di analisi dell’algoritmo di fairshare sono impostate a 10 secondi, con decadimento
quasi nullo a 0.01. La sequenza di lancio dei job per i due utenti è la stessa: ogni 10
secondi viene sottomesso un job della durata di 30 secondi.
FSWEIGHT
1
FSPOLICY
DEDICATEDPS
63
FSDEPTH
6
FSINTERVAL
10
FSDECAY
0.01
USERCFG[red]
FSTARGET=50
USERCFG[blue]
FSTARGET=[1..100]
Osservazioni
Come si può osservare in fig. 8.1 nella pagina 70 i tempi di attesa media registrati
per i job dei due utenti sono sostanzialmente equivalenti per valori di FSTARGET
dell’utente blue inferiori a 50. Per valori superiori lo scheduler dà maggiore priorità
all’utente blue e si assiste ad una crescente divergenza tra i valori di attesa.
8.2
Simulazione sul Fairshare n.1
Con gli stessi parametri del test precedente è stata effettuata una simulazione per
confrontare i risultati.
Configurazione
I parametri di configurazione sono i medesimi del test effettuato con il cluster di
test: un cluster di 4 nodi con due utenti, il primo con FSTARGET=50, il secondo
con FSTARGET variabile tra 1 e 100, FSINTERVAL=10 e FSDECAY=0.01, stessa
sequenza di lancio job per entrambi gli utenti con job da 30 secondi sottomessi ogni
10 secondi.
FSWEIGHT
1
FSPOLICY
DEDICATEDPS
FSDEPTH
6
FSINTERVAL
10
FSDECAY
0.01
USERCFG[red]
FSTARGET=50
USERCFG[blue]
FSTARGET=[1..100]
Osservazioni
In fig. 8.2 nella pagina 70 sono riportati i tempi di attesa media registrati per i
job dei due utenti. Equivalenti per valori di FSTARGET dell’utente blue inferiori a
64
50; per valori superiori si assiste ancora ad una crescente divergenza tra i valori di
attesa. Si può osservare in fig. 8.3 nella pagina 71, dove sono riportati anche i risultati
del test precedente, l’accordo tra il simulatore e la realtà della farm di test, con
l’interessante eccezione di una maggiore efficienza generale del batch system riportata
dalla simulazione, riconducibile a overhead dell’hardware “reale”.
8.3
Simulazione sul Fairshare n.2
Simile alla prima simulazione, sono stati usati gli stessi parametri di configurazione
ma una sequenza di lancio dei job più lunga e casuale (la stessa per i due utenti) allo
scopo di introdurre un tipo di sottomissione dei job più realistica e limitare eventuali
effetti di risonanza.
Configurazione
Due utenti, il primo con FSTARGET=50, il secondo con FSTARGET variabile
tra 1 e 100.
FSINTERVAL=10 e FSDECAY=0.01
Cluster di 4 nodi.
Sequenza di lancio job casuale uguale per entrambi gli utenti.
FSWEIGHT
1
FSPOLICY
DEDICATEDPS
FSDEPTH
6
FSINTERVAL
10
FSDECAY
0.01
USERCFG[red]
FSTARGET=50
USERCFG[blue]
FSTARGET=[1..100]
Osservazioni
In fig. 8.4 nella pagina 71 sono riportati i tempi di attesa media registrati per i
job dei due utenti. Si nota la sostanziale equivalenza con i risultati della precedente
simulazione, la maggior durata delle sequenze di lancio dei job permette di ottenere
risultati meno soggetti ad oscillazioni casuali.
65
8.4
Simulazione sul Fairshare n.3
In un tentativo di approfondire la conoscenza sull’impatto del parametro FSTARGET sulla simulazione si è ripetuta una simulazione con sequenza di lancio job lunga
e FSTARGET del primo utente fisso a 20.
Configurazione
Due utenti, il primo con FSTARGET=20, il secondo con FSTARGET variabile
tra 1 e 100.
FSINTERVAL=10 e FSDECAY=0.01
Cluster di 4 nodi.
Sequenza di lancio job casuale uguale per entrambi gli utenti.
FSWEIGHT
1
FSPOLICY
DEDICATEDPS
FSDEPTH
6
FSINTERVAL
10
FSDECAY
0.01
USERCFG[red]
FSTARGET=20
USERCFG[blue]
FSTARGET=[1..100]
Osservazioni
L’abbassamento del valore di FSTARGET dell’utente red non modifica in modo
significativo i tempi di attesa per valori di FSTARGET dell’utente blue minori di 80,
per valori superiori l’aumento di priorità è tale che tutti i job sottomessi dall’utente
blue vengono eseguiti immediatamente, scavalcando completamente i job sottomessi
dall’utente red (fig. 8.5 nella pagina 72).
8.5
Simulazione sul Fairshare n.4
Una nuova simulazione, ancora con gli stessi parametri di configurazione e sequenza
di lancio dei job ma FSTARGET del primo utente fisso a 80.
Configurazione
Due utenti, il primo con FSTARGET=80, il secondo con FSTARGET variabile
tra 1 e 100.
FSINTERVAL=10 e FSDECAY=0.01
66
Cluster di 4 nodi.
Sequenza di lancio job casuale uguale per entrambi gli utenti.
FSWEIGHT
1
FSPOLICY
DEDICATEDPS
FSDEPTH
6
FSINTERVAL
10
FSDECAY
0.01
USERCFG[red]
FSTARGET=80
USERCFG[blue]
FSTARGET=[1..100]
Osservazioni
La parte più a sinistra del grafico in fig. 8.6 nella pagina 72 (FSTARGET dell’utente
blue ¡ 20 e FSTARGET dell’utente red = 80) rispecchia in modo speculare la parte
più a destra del grafico precedente (fig. 8.5 nella pagina 72) come ci si aspettava, qui
con i job dell’utente red con attese in coda praticamente nulle. Al crescere del valore
di FAIRSHARE dell’utente blue i tempi di attesa medi si avvicinano per poi invertirsi
quando i valori di FSTARGET per i due utenti sono uguali.
8.6
Simulazione sul Fairshare n.5
La simulazione n.3 con valore di FAIRSHARE dell’utente blue a 20 è stata replicata
con diversi valori di configurazione per le finestre temporali prese in considerazione.
Il parametro FSINTERVAL da 10 è stato portato a 60, il parametro FSDECAY da
0.01 a 0.1.
Configurazione
Due utenti, il primo con FSTARGET=20, il secondo con FSTARGET variabile
tra 1 e 100.
FSINTERVAL=10 e FSDECAY=0.01
Cluster di 4 nodi.
Sequenza di lancio job casuale uguale per entrambi gli utenti.
FSWEIGHT
1
FSPOLICY
DEDICATEDPS
FSDEPTH
6
FSINTERVAL
60
67
FSDECAY
0.1
USERCFG[red]
FSTARGET=20
USERCFG[blue]
FSTARGET=[1..100]
Osservazioni
In fig. 8.7 nella pagina 73 sono riportati i tempi di attesa media registrati per i job
dei due utenti, come si può vedere in fig. 8.8 nella pagina 73, dove sono messi a confronto con i tempi di attesa relativi alla simulazione n.3 la variazione dei parametri relativi
alle finestre temporali da considerare non ha provocato significativi cambiamenti nello
scheduling per quanto riguarda la situazione semplificata simulata.
8.7
Test di ottimizzazione genetica
Allo scopo di testare l’algoritmo genetico e l’intera infrastruttura di ottimizzazione
si è deciso di sottomettere al sistema un semplice problema per il quale fosse nota la
configurazione ottimale. Fissata una medesima sequenza di lancio per tutti gli utenti
e la priorità per il primo utente si è lasciata al sistema l’ottimizzazione delle priorità
degli altri utenti con l’obbiettivo di minimizzare le differenze tra le medie dei tempi in
coda dei processi di ogni utente. La soluzione ottimale prevista vede tutte le priorità
equivalenti a quella fissata.
Configurazione
La configurazione prevede otto utenti su di un sistema consistente di quattro nodi
da un processore per nodo, una sequenza di lancio dei job generata casualmente è stata
impostata per essere la medesima per tutti gli utenti. La priorità del primo utente è
stata fissata ad un valore di 50, le altre priorità sono state lasciate libere di evolvere
per venti generazioni ognuna con una popolazione di cento individui.
BACKFILLPOLICY
FIRSTFIT
RESERVATIONPOLICY
CURRENTHIGHEST
NODEALLOCATIONPOLICY
MINRESOURCE
CREDWEIGHT 1
USERWEIGHT 1
USERCFG[Group_01_User_01] PRIORITY=50
68
USERCFG[Group_01_User_02] PRIORITY=<<prio1>>
USERCFG[Group_01_User_03] PRIORITY=<<prio2>>
USERCFG[Group_01_User_04] PRIORITY=<<prio3>>
USERCFG[Group_01_User_05] PRIORITY=<<prio4>>
USERCFG[Group_01_User_06] PRIORITY=<<prio5>>
USERCFG[Group_01_User_07] PRIORITY=<<prio6>>
USERCFG[Group_01_User_08] PRIORITY=<<prio7>>
L’eq. (8.1) riporta il tempo medio in coda dei job per l’utente i-esimo, dove n è il
numero di job dell’utente i-esimo e Qij il tempo in coda per il job j-esimo per l’utente
i-esimo, la funzione di fitness scelta è riportata in eq. (8.2) dove u è il numero degli
utenti e n e m indici di utenti.
n
P
Qi =
Qij
j=1
n
u X
u
X
|Qn − Qm |
F itness = 1 −
2
n=1 m=1
(8.1)
(8.2)
Osservazioni
Come si può osservare in fig. 8.9 nella pagina 74 e fig. 8.10 nella pagina 74 con
il passare del tempo le soluzioni selezionate dall’algoritmo genetico si avvicinano all’ottimo teorico mentre l’evoluzione temporale del valore di massima fitness tende a 1
come ci si aspetta. Il test ci rassicura quindi sulla bontà dell’implementazione e sulla
solidità dell’infrastruttura di ottimizzazione.
69
Figura 8.1: Test sul fairshare, tempo di attesa medio dei job al crescere del target di
fairshare per l’utente blue.
Figura 8.2: Simulazione n.1, tempo di attesa medio dei job al crescere del target di
fairshare per l’utente blue.
70
Figura 8.3: Risultati del test a confronto con quelli della simulazione n.1.
Figura 8.4: Simulazione n.2, tempo di attesa medio dei job al crescere del target di
fairshare per l’utente blue.
71
Figura 8.5: Simulazione n.3, tempo di attesa medio dei job al crescere del target di
fairshare per l’utente blue.
Figura 8.6: Simulazione n.4, tempo di attesa medio dei job al crescere del target di
fairshare per l’utente blue.
72
Figura 8.7: Simulazione n.5, tempo di attesa medio dei job al crescere del target di
fairshare per l’utente blue.
Figura 8.8: Risultati della simulazione n.5 a confronto con quelli della n.3.
73
Figura 8.9: Evoluzione temporale dei valori di priorità per la configurazione di massima
fitness.
Figura 8.10: Evoluzione temporale del valore di massima fitness.
74
Conclusioni
L’opportunità di svolgere il tirocinio e di lavorare al progetto di tesi presso il Dipartimento di Fisica si è rivelata preziosa dal punto di vista professionale e umano
e ha permesso di affrontare una serie di argomenti e problematiche stimolanti. L’architettura della infrastruttura, che coinvolge operazioni di analisi, simulazione e ottimizzazione, ha richiesto un approfondimento delle tecnologie di virtualizzazione e di
Xen in particolare per la sua realizzazione, mentre la fase di ottimizzazione basata su
algoritmi genetici mi ha permesso di apprezzare le potenzialità della programmazione
genetica. Per quanto riguarda i sistemi batch, la preparazione di una farm di test con
l’installazione di TORQUE e Maui ha apportato conoscenze pratiche e l’analisi dei
risultati dei primi test mi ha fatto comprendere la complessità della gestione e delle
interdipendenze tra le numerose variabili che intervengono nel funzionamento e nei
risultati di un sistema batch. La possibilità di interagire giornalmente con persone
preparate e disponibili nello sviluppo del progetto ha permesso una crescita personale
e una grande soddisfazione per il lavoro di gruppo svolto.
Al momento la fase di sviluppo del progetto continua, si sta procedendo alla
definizione di nuove metriche, in uno sforzo di quantificare ulteriormente i molteplici
aspetti relativi a un sistema batch e fornire supporto alle decisioni degli amministratori, ulteriori validazioni del simulatore Maui sono necessarie e verranno portate
avanti grazie al supporto ai test Monte Carlo dell’infrastruttura. Per quanto riguarda
le prospettive di sviluppo e ricerca future si può pensare ad una generalizzazione degli
elementi legati a Maui e all’ottimizzazione genetica per svincolare l’infrastruttura dal
particolare problema che ha portato alla sua realizzazione, rimanendo invece nel campo di applicazione interessato si aprono interessanti scenari di studio sulle politiche di
scheduling ma anche sull’impatto di cambiamenti hardware e di topologia di rete.
Un ambizioso obbiettivo rimane, una volta ottenuta la necessaria confidenza nel
simulatore e nell’infrastruttura, il monitoraggio e l’ottimizzazione quasi-realtime della
farm di produzione.
75
Appendici
77
Appendice A
File di configurazione
run.conf
Il file run.conf raccoglie le opzioni di configurazione del run nella forma
opzione=valore.
Opzione
Possibili Valori
Dettagli
RUNTYPE
fulltree, random o genetic
RUNFEATURES
parallel o altro
MAXPROC
INTERO
MAXWORLDS
INTERO
GENERATIONS
INTERO
POPULATION
INTERO
MUTATIONRATE
INTERO DA 0 a 100
CROSSOVERRATE
INTERO DA 0 a 100
Il tipo di run da lanciare: completa
esplorazione dello spazio delle variabili, test di validazione Monte Carlo oppure ottimizzazione genetica.
Se parallel il run verrà eseguito
in modo parallelo, altrimenti verrà
eseguito da un’unica macchina.
Se il run è di tipo parallelo indica
il numero massimo di macchine che
possono contemporaneamente lavorare sul run. Se uguale a 0 non esiste
un limite al numero di macchine.
In run di ottimizzazione genetica indica il numero di esplorazioni dello spazio delle soluzioni da eseguire
per considerare completato il run.
Se uguale a 0 il run continua fino a quando non viene fermato
manualmente.
In run genetici indica il numero di
generazioni da generare.
In run genetici indica il numero di
elementi della popolazione in ogni
generazione.
Probabilità di mutazione per run
genetici (in percentuale).
Probabilità di crossover per run
genetici (in percentuale).
79
Opzione
Possibili Valori
Dettagli
GENOTYPE
foo[:bar]. . .
VARINTERVAL foo
VALORE1..VALORE2
VARENUM bar
VALORE[:VALORE]. . .
FITNESS
PATH
RUNPREFIX
STRINGA
NUMGROUPS
INTERO o INTERO..INTERO
USERSPERGROUP
INTERO o INTERO..INTERO
GROUPSLIST
INTERO[:INTERO]. . .
QUEUES
INTERO o INTERO..INTERO
QUEUEWALLTIME
INTERO o INTERO..INTERO
JOBS
INTERO o INTERO..INTERO
JOBSTARTTIME
INTERO o INTERO..INTERO
JOBLIFESPAN
INTERO o INTERO..INTERO
Il genotipo del run: una serie di variabili di configurazione i cui valori
vengono calcolati a partire dalle corrispondenti direttive VARINTERVAL e
VARENUM.
L’intervallo di variazione della variabile “foo”.
Una serie di valori da assumere per
la variabile “bar”, separati da “:”.
Percorso dell’eseguibile che calcola il
valore di fitness per gli individui di
un run genetico.
Un prefisso da aggiungere al nome
dei run.
In run di tipo random il numero di
gruppi da creare o un intervallo tra
cui scegliere casualmente il numero
di gruppi.
In run di tipo random il numero
di utenti per gruppo da creare o
un intervallo tra cui scegliere casualmente il numero di utenti per
gruppo.
In run di tipo random una lista con
il numero di utenti dei vari gruppi,
separati da “:”.
In run di tipo random il numero delle code del batch system
da creare o un intervallo tra cui
scegliere casualmente il numero delle
code.
In run di tipo random i valori di
WALLTIME delle code del batch system o un intervallo tra cui scegliere
casualmente per ogni coda.
In run di tipo random il numero di
job da lanciare o un intervallo tra
cui scegliere casualmente.
In run di tipo random il tempo di
lancio dei job o un intervallo tra cui
scegliere casualmente per ogni job.
In run di tipo random il tempo di esecuzione dei job o un intervallo tra
cui scegliere casualmente per ogni
job.
80
config-simul-template
config-simul-template è un file di tipo template per il file di configurazione di
Maui maui.cfg. Accetta tutti i parametri accettati da maui.cfg e supporta l’uso
di variabili tra doppi segni di minore e maggiore per indicare una loro successiva
sostituzione, secondo le istruzioni in run.conf. Si riporta qui un esempio di file
di configurazione di run tramite config-simul-template, per le principali opzioni di
configurazione si rimanda alla sezione 6.2 e per una trattazione esaustiva dei parametri
accettati da Maui alla “Maui Administrator’s Guide”, appendice F.[1]
RMPOLLINTERVAL
00:00:01
LOGFILE
LOGFILEMAXSIZE
LOGLEVEL
maui.log
10000000
0
QUEUETIMEWEIGHT
1
BACKFILLPOLICY
RESERVATIONPOLICY
FIRSTFIT
CURRENTHIGHEST
NODEALLOCATIONPOLICY
MINRESOURCE
CREDWEIGHT 1
USERWEIGHT 1
USERCFG[Group_01_User_01]
USERCFG[Group_01_User_02]
USERCFG[Group_01_User_03]
USERCFG[Group_01_User_04]
USERCFG[Group_01_User_05]
USERCFG[Group_01_User_06]
USERCFG[Group_01_User_07]
USERCFG[Group_01_User_08]
PRIORITY=50
PRIORITY=<<prio1>>
PRIORITY=<<prio2>>
PRIORITY=<<prio3>>
PRIORITY=<<prio4>>
PRIORITY=<<prio5>>
PRIORITY=<<prio6>>
PRIORITY=<<prio7>>
81
File di traccia Maui
Ogni traccia consiste in una singolo record da 44 campi delimitati da spazi contenente il log dei job terminati in caso di sistemi reali o da simulare per sistemi in
simulazione.[1]
Nome
Indice Formato
Default
JobID
Nodes Requested
1
2
STRINGA
INTERO
[NESSUNO]
0
Tasks Requested
3
INTERO
User Name
Group Name
4
5
STRINGA
STRINGA
Wallclock Limit
6
INTERO
Job Completion
State
7
STRINGA
Required Class
Submission Time
Dispatch Time
8
9
10
STRINGA
INTERO
INTERO
Start Time
11
INTERO
Completion Time
12
INTERO
Required Network
Adapter
Required
Node
Architecture
Required
Node
Operating System
Required
Node
Memory
Comparison
Required
Node
Memory
Required
Node
Disk Comparison
13
STRINGA
14
STRINGA
15
STRINGA
16
uno tra >, ≥, =, ≤, <
17
INTERO
18
uno tra >, ≥, =, ≤, <
Required
Node
Disk
Required
Node
Attributes
System
Queue
Time
19
INTERO
20
STRINGA
21
INTERO
Tasks Allocated
22
INTERO
Required
Per Node
23
INTERO
Tasks
82
Note
Nome del job
Numero di nodi richiesti
1
Numero di task richiesti
[NESSUNO]
Nome dell’utente
[NESSUNO]
Gruppo primario dell’utente
1
Durata massima del
job permessa (in sec.)
Completed
Stato
di
completamento,
uno
tra
Completed, Removed,
NotRun
[DEFAULT:1] Classe richiesta
0
Data di sottomissione
0
Data di invio per
l’esecuzione
0
Data effettiva di esecuzione
0
Data
di
fine
esecuzione
[NONE]
Interfaccia di rete del
nodo richiesta
[NONE]
Architettura del nodo
richiesta
[NONE]
Sistema operativo del
nodo richiesto
≥
Operatore di comparazione
per
la
memoria
0
Memoria richiesta (in
MB)
≥
Operatore di comparazione
per
lo
spazio disco locale
0
Spazio disco locale
richiesto
[NONE]
Lista delle feature del
nodo richieste
0
Data di riscontro positivo alle politiche di
fairness
TASK
Numero di task alloRICHIESTI
cati
-1
Numero di task per
nodo richiesti
Nome
Indice Formato
Default
Note
QOS
24
STRINGA[:STRINGA]
[NONE]
JobFlags
25
STRINGA[:STRINGA]... [NONE]
Account Name
26
STRINGA
[NONE]
Executable
Comment
27
28
STRINGA
STRINGA
[NONE]
[NONE]
Bypass Count
29
INTERO
-1
ProcSeconds Utilized
Partition Name
30
DOUBLE
0
31
STRINGA
[DEFAULT]
Dedicated Processors per Task
Dedicated Memory per Task
Dedicated
Disk
per Task
32
INTERO
1
33
INTERO
0
34
INTERO
0
Dedicated
per Task
35
INTERO
0
Start Date
36
INTERO
0
End Date
37
INTERO
0
Allocated
Host
List
Resource Manager Name
Required
Host
Mask
Reservation
38
STRINGA[:STRINGA]... [NONE]
Livello
di
QOS
richiesto
Lista di attributi del
job
Account associato al
job
Nome dell’eseguibile
Lista di attributi del
job fornita dal resource manager
Numero di volte in cui
il job è stato scavalcato tramite backfill
Secondi*Processore
utilizzati
Partizione
di
esecuzione
Processori
richiesti
per task
Memoria richiesta per
task (in MB)
Spazio disco locale
richiesto per task (in
MB)
Memoria
virtuale
richiesta per task (in
MB)
Data di esecuzione
presunta minima
Data
di
fine
esecuzione massima
Nodi allocati
39
STRINGA
40
STRINGA[STRINGA]... [NONE]
41
STRINGA
[NONE]
Set Description
42
[NONE]
Application Simutator Data
RISERVATO
43
STRINGA:STRINGA
[:STRING]
STRINGA[:STRINGA]
[NONE]
44
STRINGA
[NONE]
Swap
[NONE]
83
Nome del resource
manager
Nodi richiesti dal job
Reservation richiesta
dal job
Restrizioni richieste
dal job
Modulo
di
simulazione
File delle risorse Maui
Il file delle risorse resources descrive tutti gli aspetti delle risorse computazionali
di un batch system Maui reale o simulato. Ogni riga del file descrive un singolo nodo
di calcolo con le informazioni relative in 21 campi delimitati da spazi.[1]
Nome
Indice Formato
Default
Resource Type
Event Type
1
2
COMPUTENODE Unico valore ammissibile
[NONE]
Il nodo partirà rispettivamente in stato Idle,
Down, o Drained
Event Time
Resource ID
Resource Manager Name
Configured Swap
3
4
5
COMPUTENODE
uno tra AVAILABLE,
DEFINED,
o
DRAINED
EPOCHTIME
STRINGA
STRINGA
6
INTERO
1
7
INTERO
1
8
INTERO
1
9
INTERO
1
10
INTERO
1
11
INTERO
1
12
INTERO
1
13
STRINGA
[NONE]
Usato in ambienti IBM
SP2
Usato in ambienti IBM
SP2
Usato in ambienti IBM
SP2
Sistema operativo
14
STRINGA
[NONE]
Architettura del nodo
15
STRINGA
[NONE]
Features
16
STRINGA
[batch:1]
Classi associate
17
STRINGA
[NONE]
Interfacce di rete
18
DOUBLE
1.0
Velocità relativa del nodo
19
20
21
STRINGA
STRINGA
STRINGA
[NONE]
[NONE]
[NONE]
Configured Memory
Configured Disk
Configured
Processors
Resource Frame
Location
Resource Slot Location
Resource Slot Use
Count
Node Operating
System
Node
Architecture
Configured Node
Features
Configured Run
Classes
Configured
Network
Adapters
Relative Resource
Speed
RISERVATO
RISERVATO
RISERVATO
84
1
N/A
[NONE]
Note
ignorato
Nome del nodo
Nome del resource manager che gestisce il nodo
Memoria virtuale (in
MB)
Memoria (in MB)
Spazio disco locale (in
MB)
Numero di processori
Appendice B
Sorgenti
functions.sh
#!/bin/bash
SYNC TRACES SCRIPT="./scripts/utils/sync-traces.sh"
RSYNC USER="maui"
SERVER URL="mauirep.fisica.unipg.it"
RSYNC DIR="/rep/"
check prerequisite() {
RETURN=0
if [ −f "$1" ]
then
if [ $QUIET ==
elif [ −f "$1.gz" ]
then
if [ $QUIET ==
gzip −d $1.gz
elif [ −f "$1.bz" ]
then
if [ $QUIET ==
bzip2 −d $1.gz
else
if [ $QUIET ==
RETURN=1
fi
}
10
0 ]; then echo " . . Found."; fi
0 ]; then echo " . . Found."; fi
0 ]; then echo " . . Found."; fi
20
0 ]; then echo " . . Not found."; fi
check variable() {
RETURN=0
if [ "a$1" == "a" ]
then
if [ $QUIET == 0 ]; then echo " . . Not found."; fi
RETURN=1
else
if [ $QUIET == 0 ]; then echo " . . Found."; fi
fi
}
85
30
# check status trace feature status
check status() {
# is feature set to status on this trace?
if [ −z "$1" ] | | [ −z "$2" ] | | [ −z "$3" ]
40
# parameters of zero length or no parameter passed.
then
return 2
else
$SYNC TRACES SCRIPT −R −f $2 −t $1 −s $SERVER URL | egrep "^${3}$"
RCHECK=$?
return $RCHECK # 0 founded, 1 not founded, 2 error
fi
}
50
# set status trace feature status
set status() {
if [ −z "$1" ] | | [ −z "$2" ] | | [ −z "$3" ]
# parameters of zero length or no parameter passed.
then
return 2
else
RETURN=0
$SYNC TRACES SCRIPT −e −t $1 −s $SERVER URL # exists on server?
RETURN=$?
60
case $RETURN in
0)# trace exists, set feature
$SYNC TRACES SCRIPT −S −c $3 −f $2 −t $1 −s $SERVER URL
RETURN=$?
return $RETURN;;
2)# trace does not exists, create trace. .
ssh −− $RSYNC USER@$SERVER URL mkdir −p −− $RSYNC DIR/$1
RETURN=$?
if [ $RETURN != 0 ]
then
70
# error
return 1
fi
# . .and set feature
$SYNC TRACES SCRIPT −S −c $3 −f $2 −t $1 −s $SERVER URL
RETURN=$?
return $RETURN;;
*)# error
return 1;;
esac
80
fi
}
# unset status trace feature status
unset status() {
if [ −z "$1" ] | | [ −z "$2" ] | | [ −z "$3" ]
# parameters of zero length or no parameter passed.
then
return 2
else
90
RETURN=0
$SYNC TRACES SCRIPT −q −U −c $3 −f $2 −t $1 −s $SERVER URL
RETURN=$?
86
return $RETURN # 0 unset ok, 1 unset error
fi
}
# flush a feature
flush status() {
if [ −z "$1" ] | | [ −z "$2" ]
# parameters of zero length or no parameter passed.
then
return 2
else
RETURN=0
for i in ‘$SYNC TRACES SCRIPT −R −f $2 −t $1 −s $SERVER URL‘
do
$SYNC TRACES SCRIPT −q −U −c $i −f $2 −t $1 −s $SERVER URL
RETURN=$?
if [ $RETURN != 0 ]
then
return $RETURN # 0 unset ok, 1 unset error
fi
done
return $RETURN
fi
}
100
110
launch.sh
#!/bin/bash
# NOTE:
# DONE: do not upload if trace is in similating/ed state
#
added -u option to check if trace is in launching/ed status
#
set checking
source "./functions.sh"
# INITIALIZATION
SYNC TRACES SCRIPT="./scripts/utils/sync-traces.sh" # path of sync-traces script
# Path of the scripts
SCRIPTS PATH="./scripts"
ERROR CODE=39
# default error code
HELP="Usage: $0 [-l|-r|-p|-k] [-u] -t trace [-s server] [-h]\n\n
-t target pathname of target\n
-s server remote traces server\n
-r, -l
download target from remote server or use local target\n
-p
put result on remote server\n
-k
do not erase local target on exit\n\n
-u
check & set launching/ed status\n\n
-h
this help.\n\n
Usage examples:\n
launch from local to local: $0 -l -k -t target\n
launch from remote server to local: $0 -r -k -t target -s server\n
launch from local to remote server: $0 -l -p -t target -s server\n
87
10
20
launch from local to remote server and keep a local copy:
30
$0 -l -p -k -t target -s server\n
launch from remote server to remote server: $0 -r -p -t target -s server\n
launch from remote server to remote server and keep a local copy:
$0 -r -p -k -t target -s server\n"
# Var initialization
NO ARGS=0
SERVER VAR=0
TARGET VAR=0
40
REMOTE VAR=0
LOCAL VAR=0
PUT VAR=0
KEEP VAR=0
QUIET=0
VERBOSE=0
STATUS VAR=0
CLIENTNAME="randomize"
50
if [ $CLIENTNAME == "randomize" ]
then
TEMP=‘echo $USER $HOSTNAME $RANDOM | md5sum | cut −d" " −f1‘
CLIENTNAME=${TEMP:24}
fi
launch() {
if [ $STATUS VAR == 1 ]
then
60
# Lock
$SCRIPTS PATH/manager/client.py −l −c $CLIENTNAME
CHECK=2
# check status return 0 if found, 1 if not found, 2 if an error occur
check status $LOCAL PATH status launching > /dev/null
CHECK=$?
if [ $CHECK == 0 ]
then
if [ $QUIET == 0 ]; then echo " Trace $LOCAL_PATH is already launching" ; fi
70
# Unlock
$SCRIPTS PATH/manager/client.py −u −c $CLIENTNAME
return 2 # trace in launching state
fi
CHECK=2
# check status return 0 if found, 1 if not found, 2 if an error occur
check status $LOCAL PATH status launched > /dev/null
CHECK=$?
if [ $CHECK == 0 ]
80
then
if [ $QUIET == 0 ];
then echo " Trace $LOCAL_PATH already launched" ; fi
# Unlock
$SCRIPTS PATH/manager/client.py −u −c $CLIENTNAME
return 2 # trace in launching state
88
fi
CHECK=0
# Check for $LOCAL PATH existence
90
$SYNC TRACES SCRIPT −q −e −t $LOCAL PATH −s $SERVER URL
CHECK=$?
if [ $CHECK == 2 ]
then
if [ $QUIET == 0 ];
then echo " Trace $LOCAL_PATH does not exits: assuming lready" ; fi
# trace not in launching/ed state yet, locking now setting status=launching
set status $LOCAL PATH status launching > /dev/null
100
# Unlock
$SCRIPTS PATH/manager/client.py −u −c $CLIENTNAME
else
CHECK=2
# check status return 0 if found, 1 if not found, 2 if an error occur
check status $LOCAL PATH status lready > /dev/null
CHECK=$?
110
if [ $CHECK == 0 ]
then
if [ $QUIET == 0 ]; then echo " Trace $LOCAL_PATH: lready" ; fi
# trace not in launching/ed state yet, locking now setting status=launching
set status $LOCAL PATH status launching > /dev/null
# Unlock
$SCRIPTS PATH/manager/client.py −u −c $CLIENTNAME
else
120
if [ $QUIET == 0 ]; then echo " Trace $LOCAL_PATH: unknown status" ; fi
# Unlock
$SCRIPTS PATH/manager/client.py −u −c $CLIENTNAME
return 1 # trace in error state
fi
fi
fi
# now proper launch
130
if [ $QUIET == 0 ]; then echo " Checking headers"; fi
if [ $QUIET == 0 ]; then echo " Checking datadir: $LOCAL_PATH"; fi
if [ $QUIET == 0 ];
then echo −n " Checking the existence of a resources trace: \
$LOCAL_PATH/resources . ."; fi
check prerequisite "$LOCAL_PATH/resources"
if [ $RETURN != 0 ]
then
return 1
else
140
WORKLOAD RESOURCES="$LOCAL_PATH/resources"
fi
89
if [ $QUIET == 0 ]; then echo " Checking the farm prerequisites . ."; fi
RETURN=0
$SCRIPTS PATH/launcher/farm prerequisites.sh −p " " \
−r $WORKLOAD RESOURCES | | RETURN=1
if [ $RETURN != 0 ]
then
return 1
150
fi
if [ $QUIET == 0 ]; then echo −n " Checking the existence of a config \
file: $LOCAL_PATH/config . ."; fi
check prerequisite "$LOCAL_PATH/config"
if [ $RETURN != 0 ]
then
return 1
else
CONFIG RESOURCES="$LOCAL_PATH/config"
160
fi
if [ $QUIET == 0 ]; then echo −n " Checking the existence of a header \
config file: $LOCAL_PATH/config-real-header . ."; fi
check prerequisite "$LOCAL_PATH/config-real-header"
if [ $RETURN != 0 ]
then
if [ $QUIET == 0 ]; then echo −n " Checking the existence of a header \
config file: traces/config-real-header . ."; fi
check prerequisite "traces/config-real-header"
170
if [ $RETURN != 0 ]
then
return 1
else
CONFIG REAL HEADER="traces/config-real-header"
fi
else
CONFIG REAL HEADER="$LOCAL_PATH/config-real-header"
fi
if [ $QUIET == 0 ]; then echo −n " Checking the existence of a user/group \
180
config file: $LOCAL_PATH/config-users . ."; fi
check prerequisite "$LOCAL_PATH/config-users"
if [ $RETURN != 0 ]
then
return 1
else
CONFIG USERS="$LOCAL_PATH/config-users"
fi
if [ $QUIET == 0 ]; then echo −n " Checking the existence of a batch \
190
system config file: $LOCAL_PATH/config-batch . ."; fi
check prerequisite "$LOCAL_PATH/config-batch"
if [ $RETURN != 0 ]
then
return 1
else
CONFIG BATCH="$LOCAL_PATH/config-batch"
fi
if [ $QUIET == 0 ]; then echo −n " Checking the existence of launch \
90
200
schedule file: $LOCAL_PATH/schedule . ."; fi
check prerequisite "$LOCAL_PATH/schedule"
if [ $RETURN != 0 ]
then
return 1
else
CONFIG SCHEDULE="$LOCAL_PATH/schedule"
fi
WORKLOAD REAL UNSCALED=$LOCAL PATH/workload−real−unscaled
210
if [ $QUIET == 0 ]; then echo " Starting pre launch tasks:"; fi
# Getting the farm nodes
if [ $QUIET == 0 ]; then echo " Getting the farm nodes from \
$WORKLOAD_RESOURCES" ; fi
NODES=‘cat $WORKLOAD RESOURCES | grep COMPUTENODE | \
cut −d" " −f 4‘
if [ $QUIET == 0 ]
then
220
for i in $NODES
do
echo "
Node $i"
done
fi
if [ $QUIET == 0 ]; then echo " Starting nodes users reconfiguration:"; fi
# Coping files to nodes
if [ $QUIET == 0 ]; then echo " Copying scripts to nodes" ; fi
230
for i in $NODES
do
scp $CONFIG USERS $i:/root/config−users > /dev/null 2>&1
if [ $QUIET == 0 ]; then echo " $CONFIG_USERS -> Node $i"; fi
scp $SCRIPTS PATH/users−utils/users−make.sh $i:/root/users−make.sh > \
/dev/null 2>&1
if [ $QUIET == 0 ]; then echo " $SCRIPTS_PATH/users-utils/users-make.sh -> \
Node $i"; fi
done
240
# Configuring users
if [ $QUIET == 0 ]; then echo " Appling changes" ; fi
for i in $NODES
do
ssh $i "chmod a+xr /root/users-make.sh ; /root/users-make.sh /root/config-users"
if [ $QUIET == 0 ]; then echo " Changing users on node $i"; fi
done
# Removing files from nodes
if [ $QUIET == 0 ]; then echo " Removing scripts from nodes" ; fi
for i in $NODES
do
ssh $i "rm -f /root/users-make.sh"
if [ $QUIET == 0 ]; then echo " Removing \
users-make.sh from node $i"; fi
ssh $i "rm -f /root/config-users"
if [ $QUIET == 0 ]; then echo " Removing config-users from node $i"; fi
91
250
done
if [ $QUIET == 0 ]; then echo " Starting server users reconfiguration . ."; fi
260
$SCRIPTS PATH/users−utils/users−make.sh $CONFIG USERS
if [ $QUIET == 0 ]; then echo " Changing users on server"; fi
if [ $QUIET == 0 ]; then echo " Cleaning old files"; fi
rm −f maui.cfg stats/*
if [ $QUIET == 0 ]; then echo " Starting server queues reconfiguration:"; fi
$SCRIPTS PATH/batch−utils/make−queues.sh −p " " −r $CONFIG BATCH
if [ $QUIET == 0 ]; then echo " Copying configuration"; fi
270
cat $CONFIG REAL HEADER $CONFIG RESOURCES > maui.cfg
if [ $QUIET == 0 ]; then echo " Restarting scheduler"; fi
killall maui ; sleep 2 ; maui
CURRENTTIME=‘date +%s‘;
STARTTIME=$(($CURRENTTIME))
if [ $QUIET == 0 ]; then echo −n " Starting launch at "; echo $STARTTIME ; fi
280
$SCRIPTS PATH/launcher/sleep−launcher.sh $CONFIG SCHEDULE
ENDTIME=‘date +%s‘
if [ $QUIET == 0 ]; then echo " Writing launch duration:"; fi
let "SIMTIME= $ENDTIME - $STARTTIME"
echo $SIMTIME > $LOCAL PATH/duration
if [[ $CHECKED == "s2s" | | $CHECKED == "l2s" ]]
then
290
# Lock
$SCRIPTS PATH/manager/client.py −l −c $CLIENTNAME
flush status $LOCAL PATH duration > /dev/null
set status $LOCAL PATH duration $SIMTIME > /dev/null
# Unlock
$SCRIPTS PATH/manager/client.py −u −c $CLIENTNAME
fi
300
if [ $QUIET == 0 ]; then echo " Starting post launch tasks:"; fi
if [ $QUIET == 0 ]; then echo " Moving results"; fi
cat stats/* * * * | sort −n > $WORKLOAD REAL UNSCALED
if [ $QUIET == 0 ]; then echo " Creating Human readable formats:"; fi
$SCRIPTS PATH/utils/workload−clean.pl \
$WORKLOAD REAL UNSCALED $LOCAL PATH/workload−real−unscaled−cleaned
310
if [ $QUIET == 0 ]; then echo " Cleaning files"; fi
if [ $VERBOSE == 0 ]
then
rm −f maui.cfg stats/*
92
else
rm −fv maui.cfg stats/*
fi
# Compressing results
if [ $QUIET == 0 ]; then echo " Compressing files" ; fi
320
if [ $VERBOSE == 0 ]
then
gzip −fq $LOCAL PATH/workload*
else
gzip −f $LOCAL PATH/workload*
fi
if [ $STATUS VAR == 1 ]
then
# Lock
330
$SCRIPTS PATH/manager/client.py −l −c $CLIENTNAME
# setting status=launched
set status $LOCAL PATH status launched > /dev/null
# now we can unset status launching
unset status $LOCAL PATH status launching > /dev/null
# Unlock
$SCRIPTS PATH/manager/client.py −u −c $CLIENTNAME
fi
340
}
clean local() {
if [ $QUIET == 0 ]; then echo " Cleaning $LOCAL_PATH"; fi
$SYNC TRACES SCRIPT −q −r −t $LOCAL PATH
RETURN=$?
if [[ $RETURN != 0 ]]; then echo " Error: cleaning $LOCAL_PATH error"; fi
}
# checkinput, check input variables, reporting “bad” or a code for each command
350
checkinput() {
CHECKED="bad"
if (( $TARGET VAR + $LOCAL VAR == 2 )) && (( $SERVER VAR + \
$REMOTE VAR + $PUT VAR == 0 ))
then
# from local to local
CHECKED="l2l"
fi
if (( $TARGET VAR + $SERVER VAR + $REMOTE VAR == 3 )) && \
(( $LOCAL VAR + $PUT VAR == 0 ))
360
then
# from server to local
CHECKED="s2l"
fi
if (( $TARGET VAR + $SERVER VAR + $LOCAL VAR + $PUT VAR == 4 )) && \
(( $REMOTE VAR == 0 ))
then
# from local to server (remove local target)
CHECKED="l2s"
fi
370
if (( $TARGET VAR + $SERVER VAR + $REMOTE VAR + $PUT VAR == 4 )) && \
93
(( $LOCAL VAR == 0 ))
then
# from server to server (remove local target)
CHECKED="s2s"
fi
}
l2l() {
# local to local launch
380
if [ $QUIET == 0 ]; then echo "Local to local launching $LOCAL_PATH"; fi
launch
RETURN=$?
if [[ $RETURN != 0 ]]; then echo "Error: launching $LOCAL_PATH error"; fi
}
s2l() {
# server to local launch
if [ $QUIET == 0 ]; then echo "Server to local launching $LOCAL_PATH \
from $SERVER_URL"; fi
390
if [ $QUIET == 0 ]; then echo "Downloading $LOCAL_PATH from $SERVER_URL"; fi
$SYNC TRACES SCRIPT −g −t $LOCAL PATH −s $SERVER URL
RETURN=$?
# Simulate
if [ $RETURN == 0 ]
then
launch
RETURN=$?
if [[ $RETURN != 0 ]]; then echo "Error: launching $LOCAL_PATH"; fi
400
else
echo "Error: Downloading $LOCAL_PATH from $SERVER_URL failed"
fi
}
l2s() {
# local to server launch
if [ $QUIET == 0 ]; then echo "Local to server launching $LOCAL_PATH \
to $SERVER_URL"; fi
# launch
410
launch
RETURN=$?
# check launch return (0 ok, 1 error, 2 launching/ed)
if [ $RETURN == 1 ]
then
echo "Error: launching $LOCAL_PATH error"
return $RETURN
fi
420
if [ $RETURN == 2 ]
then
if [ $QUIET == 0 ]; then echo " $LOCAL_PATH already launching/ed"; fi
UPLOAD="no"
fi
# Check for $LOCAL PATH existence
$SYNC TRACES SCRIPT −q −e −t $LOCAL PATH −s $SERVER URL
94
RETURN=$?
430
# if trace exist do not perform a clean, print a warning
if [ $RETURN == 1 ]
then
echo "Error: cannot check trace on server, upload aborted, local \
launched trace not deleted"
return $RETURN
fi
# upload to server
if [ "a$UPLOAD" != "ano" ]
440
then
if [ $QUIET == 0 ]; then echo "Uploading trace to server"; fi
$SYNC TRACES SCRIPT −q −p −t $LOCAL PATH −s $SERVER URL
RETURN=$?
if [ $RETURN == 0 ]
then
if [ $QUIET == 0 ]; then echo "Uploading ok"; fi
# clean local if requested
if [ $KEEP VAR == 0 ]; then clean local; fi
450
else
echo "Error: Uploading failed"
fi
else
if [ $QUIET == 0 ]; then echo "Skipping uploading trace to server"; fi
RETURN=0
fi
}
460
s2s() {
# server to server launch
if [ $QUIET == 0 ]; then echo "Server to server launching - local \
path=$LOCAL_PATH; server=$SERVER_URL"; fi
# Control status to save time
if [ $STATUS VAR == 1 ]
then
# Lock
$SCRIPTS PATH/manager/client.py −l −c $CLIENTNAME
470
CHECK=2
# check status return 0 if found, 1 if not found, 2 if an error occur
check status $LOCAL PATH status launching > /dev/null
CHECK=$?
if [ $CHECK == 0 ]
then
if [ $QUIET == 0 ]; then echo " Trace is already launching" ; fi
# Unlock
$SCRIPTS PATH/manager/client.py −u −c $CLIENTNAME
return 0 # not an error but trace is in launching state -> exit
fi
CHECK=2
# check status return 0 if found, 1 if not found, 2 if an error occur
95
480
check status $LOCAL PATH status launched > /dev/null
CHECK=$?
if [ $CHECK == 0 ]
then
if [ $QUIET == 0 ]; then echo " Trace already launched" ; fi
490
# Unlock
$SCRIPTS PATH/manager/client.py −u −c $CLIENTNAME
return 0 # not an error but trace is in launched state -> exit
fi
# Unlock
$SCRIPTS PATH/manager/client.py −u −c $CLIENTNAME
fi
# download from server
500
$SYNC TRACES SCRIPT −g −t $LOCAL PATH −s $SERVER URL
RETURN=$?
# launch
if [ $RETURN == 0 ]
then
launch
RETURN=$?
else
echo "Error: downloading error"
fi
510
# check launch return (0 ok, 1 error, 2 launching/ed)
if [ $RETURN == 1 ]
then
echo "Error: launching $LOCAL_PATH error"
return $RETURN
fi
if [ $RETURN == 2 ]
then
if [ $QUIET == 0 ]; then echo " $LOCAL_PATH already launching/ed"; fi
520
if [ $QUIET == 0 ]; then echo " Skipping uploading trace to server"; fi
RETURN=0
fi
if [ $RETURN == 0 ]
then
# upload to server
$SYNC TRACES SCRIPT −p −t $LOCAL PATH −s $SERVER URL
RETURN=$?
# 4) clean local
530
if [ $RETURN == 0 ]
then
if [ $KEEP VAR == 0 ]; then clean local; fi
RETURN=$?
else
echo "Error: uploading error"
fi
if [[ $RETURN != 0 ]]; then echo "Error: local cleaning error"; fi
fi
}
540
if [ $# -eq “$NO ARGS” ] # Script invoked with no command-line args.
96
then
echo −e $HELP
exit $ERROR CODE # Exit and explain usage, if no argument(s) given.
fi
while getopts "s:t:rlpkuhvq" Option
# Command arguments:
# -t target (local path)
550
# -s server
# -r, -l download target from remote server or use local path for target
# -p put result on remote server
# -k do not erase local target on exit
# -u check launching/ed status
do
case $Option in
s ) SERVER VAR=1
SERVER URL=$OPTARG;;
560
t ) TARGET VAR=1
LOCAL PATH=$OPTARG
TARGET=‘basename $OPTARG‘;;
r ) REMOTE VAR=1;;
l ) LOCAL VAR=1;;
p ) PUT VAR=1;;
k ) KEEP VAR=1;;
v ) VERBOSE=1;;
q ) QUIET=1;;
u ) STATUS VAR=1;;
570
h ) echo −e $HELP
exit 1;;
* ) echo −e $HELP
exit 1;;
esac
done
checkinput
if [ $CHECKED == "bad" ]
then
580
echo "Error: bad parameters"
echo −e $HELP
exit 1
else
if [ $CHECKED == "l2l" ]
then
l2l
if [[ $QUIET == 0 && $RETURN == 0 ]]; \
then echo "Local to Local simulation ok"; fi
exit $RETURN
fi
if [ $CHECKED == "s2l" ]
then
s2l
if [[ $QUIET == 0 && $RETURN == 0 ]]; \
then echo "Server to local simulation ok"; fi
exit $RETURN
97
590
fi
600
if [ $CHECKED == "l2s" ]
then
l2s
if [[ $QUIET == 0 && $RETURN == 0 ]]; \
then echo "Local to server simulation ok"; fi
exit $RETURN
fi
if [ $CHECKED == "s2s" ]
then
s2s
if [[ $QUIET == 0 && $RETURN == 0 ]]; \
then echo "Server to server simulation ok"; fi
exit $RETURN
fi
610
fi
ls-feat.sh
#!/bin/bash
# NOTE: A little script to list remote traces with a specific feature/characteristic
# version 0.1
#
source "./functions.sh"
# initialization
RSYNC USER="maui"
RSYNC DIR="/rep"
LSTRACE="./scripts/utils/ls-traces.sh"
SYNCTRACE="./scripts/utils/sync-traces.sh"
FEATURE VAR=0
CHARACTERISTIC VAR=0
# defaults
SERVER URL="mauirep.fisica.unipg.it"
TARGET="/"
ALL="yes"
NUM=0
10
20
HELP="A little script to list remote traces with a specific feature/characteristic.\n
Usage: $0 [-t trace] [-s server] -f feature -c characteristic [-n num] [-h]\n\n
-t target
-s server
trace pathname (default: root)\n
remote traces server (default: $SERVER_URL)\n\n
-f feature
feature\n
-c characteristic characteristic\n\n
-n num
-h
30
max number of trace to return\n\n
this help.\n"
98
while getopts "s:t:f:c:n:h" Option
do
case $Option in
s ) SERVER URL=$OPTARG;;
t ) TARGET=$OPTARG;;
f ) FEATURE VAR=1
FEATURE=$OPTARG;;
c ) CHARACTERISTIC VAR=1
CHARACTERISTIC=$OPTARG;;
n ) ALL="no"
NUM=$OPTARG;;
h ) echo −e $HELP
exit 1;;
* ) echo −e $HELP
exit 1;;
esac
done
40
50
if (( $CHARACTERISTIC VAR + $FEATURE VAR == 2 ))
then
for i in ‘$LSTRACE −r −t $TARGET‘
do
if [[ $ALL == "yes" | | $NUM != 0 ]]
then
check status $i $FEATURE $CHARACTERISTIC>/dev/null
CHECK=$?
if [ $CHECK == 0 ]
then
echo $i
NUM=$(( $NUM − 1 ))
fi
if [ $CHECK == 2 ]
then
echo "Error"
fi
fi
done
else
echo −e $HELP
fi
60
70
ls-traces.sh
#!/bin/bash
# NOTE: A little script to list remote traces
# version 0.1
#
# initialization
RSYNC USER="maui"
RSYNC DIR="/rep"
10
# defaults
SERVER URL="mauirep.fisica.unipg.it"
99
TARGET=""
RECURSIVE=0
GRAPH=0
HELP="A little script to list remote traces.\n
Usage: $0 [-r] [-g] [-t trace] [-s server] [-h]\n\n
-t target trace pathname (default: root)\n
-s server remote traces server (default: $SERVER_URL)\n
-r
recursive\n
-g
graph, output a tree like vista\n\n
-h
20
this help.\n"
while getopts "s:t:rgh" Option
do
case $Option in
s ) SERVER URL=$OPTARG;;
t ) TARGET=$OPTARG;;
r ) RECURSIVE=1;;
g ) GRAPH=1;;
h ) echo −e $HELP
exit 1;;
* ) echo −e $HELP
exit 1;;
esac
done
30
40
if [ $RECURSIVE == 0 ]
then
ssh −− $RSYNC USER@$SERVER URL ls −− $RSYNC DIR/$TARGET
else
if [ $GRAPH == 0 ]
then
ssh −− $RSYNC USER@$SERVER URL "tree -d -i -f $RSYNC_DIR/$TARGET | \
sed -e ’s/\’$RSYNC_DIR’//’ | sed -e ’s/\///’ "
else
ssh −− $RSYNC USER@$SERVER URL "tree -d $RSYNC_DIR/$TARGET"
fi
fi
50
resolve-users.sh
#!/bin/bash
# NOTE: version 0.1
# CHANGES: 0.1: support for direct and range value for NUMGROUPS and \
USERSPERGROUP directives in run.conf
# initialization
NO ARGS=0 # var initialization
# run.conf parameters
NUMGROUPS="" # number of groups ex. NUMGROUPS=3 or NUMGROUPS=3. .10 \
for a range (max 9999 groups)
USERSPERGROUP="" # users per group ex. USERSPERGROUP=12 or \
100
10
USERSPERGROUP=50. .100 (max 9999 users)
#
note: every user belongs to a single group
GROUPSLIST="" # groups, extended version ex. GROUPSLIST=3:1:12:3
# defaults
ERROR CODE=39 # default error code
20
HELP="Generate a random config-users file from run.conf directives\n
Usage: $0 tracedir\n\n
Note: use either NUMGROUPS+USERSPERGROUP or GROUPSLIST directives in \
run.conf,\n"
if [ $# -eq “$NO ARGS” ] # script invoked with no command-line args
then
echo −e $HELP
exit $ERROR CODE # exit and explain usage, if no argument(s) given
fi
30
RUNCONF=$1
if [ −f $RUNCONF/run.conf ] # run.conf found, parse it
then
NUMGROUPS=‘cat $RUNCONF/run.conf|egrep \
"^NUMGROUPS=[0-9]{1,4}(\.\.[0-9]{1,4})?$"‘ # extract NUMGROUPS
NUMGROUPS=${NUMGROUPS#NUMGROUPS=}
#echo $NUMGROUPS
40
USERSPERGROUP=‘cat $RUNCONF/run.conf|egrep \
"^USERSPERGROUP=[0-9]{1,4}(\.\.[0-9]{1,4})?$"‘ # extract USERSPERGROUP
USERSPERGROUP=${USERSPERGROUP#USERSPERGROUP=}
#echo $USERSPERGROUP
GROUPSLIST=‘cat $RUNCONF/run.conf|egrep \
"^GROUPSLIST=([0-9]+:)*[0-9]+$"‘ # extract GROUPSLIST
GROUPSLIST=${GROUPSLIST#GROUPSLIST=}
#echo $GROUPSLIST
50
if [[ $NUMGROUPS && $USERSPERGROUP ]] && [[ ! $GROUPSLIST ]]
then
# if NUMGROUPS is a range, \
if [[ ‘echo "$NUMGROUPS"|egrep "\.\."‘ ]]
select a random number of groups in that range
then
BASE=$(( ‘echo "$NUMGROUPS"|egrep −o "^[0-9]*"‘ ))
RANGE=$(( ‘echo "$NUMGROUPS"|egrep −o "[0-9]*$"‘ − $BASE ))
NUMGROUPS=$[ ( $RANDOM % ( RANGE + 1 ) ) + $BASE ]
60
fi
# now NUMGROUPS is properly defined
G=0
while (( $G <= $NUMGROUPS ))
do
FORMATTEDG=$G # Formatted GRUOUP number (ex. 13 -> 0013)
while (( ${#FORMATTEDG} < 4 ))
70
101
do
FORMATTEDG=0$FORMATTEDG
done
if [[ ‘echo "$USERSPERGROUP"|egrep "\.\."‘ ]] # if USERSPERGROUP is a range, \
select a random number of groups in that range
then
BASE=$(( ‘echo "$USERSPERGROUP"|egrep −o "^[0-9]*"‘ ))
RANGE=$(( ‘echo "$USERSPERGROUP"|egrep −o "[0-9]*$"‘ − $BASE ))
NEWUSERSPERGROUP=$[ ( $RANDOM % ( RANGE + 1 ) ) + $BASE ]
else
NEWUSERSPERGROUP=$USERSPERGROUP
fi
80
# now USERSPERGROUP is properly defined as NEWUSERSPERGROUP \
for this group
U=0
while (( $U <= $NEWUSERSPERGROUP ))
do
FORMATTEDU=$U
while (( ${#FORMATTEDU} < 4 ))
do
FORMATTEDU=0$FORMATTEDU
done
echo "g${FORMATTEDG}u${FORMATTEDU} : g$FORMATTEDG"
U=$((U + 1))
done
G=$((G + 1))
done
elif [[ ! $NUMGROUPS && ! $USERSPERGROUP ]] && [[ $GROUPSLIST ]]
then
echo "GROUPSLIST directive not yet implemented, sorry."
exit 2
else
echo "users/group directives not found in $RUNCONF/run.conf"
exit 2
fi
else
echo "$RUNCONF/run.conf not found" # run.conf not found
exit 1
fi
resolve-queues.sh
resolve-schedule.sh
#!/bin/bash
# NOTE: version 0.1
# CHANGES: 0.1: support for direct and range value for JOBS, JOBSTARTTIME \
102
90
100
110
and JOBLIFESPAN directives in run.conf
# initialization
NO ARGS=0 # var initialization
# run.conf parameters
10
JOBS="" # number of jobs ex. NUMJOBS=3 or NUMJOBS=3. .10 for a \
range (max 99999 jobs)
JOBSTARTTIME="" # start time for every job ex. JOBSTARTTIME=12 or \
JOBSTARTTIME=50. .100 (max 99999 start time)
JOBLIFESPAN="" # groups, extended version ex. JOBLIFESPAN=123 or \
JOBLIFESPAN=100. .1000 (max 99999 life span time)
# defaults
ERROR CODE=39 # default error code
20
HELP="Generate a random schedule file from run.conf directives to pass \
to sleep-launcher.sh\n
Usage: $0 tracedir\n\n"
if [ $# -eq “$NO ARGS” ] # script invoked with no command-line args
then
echo −e $HELP
exit $ERROR CODE # exit and explain usage, if no argument(s) given
fi
30
RUNCONF=$1
if [ −f $RUNCONF/run.conf ] # run.conf found, parse it
then
JOBS=‘cat $RUNCONF/run.conf|egrep \
"^JOBS=[0-9]{1,5}(\.\.[0-9]{1,5})?$"‘ # extract JOBS
JOBS=${JOBS#JOBS=}
#echo $JOBS
40
JOBSTARTTIME=‘cat $RUNCONF/run.conf|egrep \
"^JOBSTARTTIME=[0-9]{1,5}(\.\.[0-9]{1,5})?$"‘ # extract JOBSTARTTIME
JOBSTARTTIME=${JOBSTARTTIME#JOBSTARTTIME=}
#echo $JOBSTARTTIME
JOBLIFESPAN=‘cat $RUNCONF/run.conf|egrep \
"^JOBLIFESPAN=[0-9]{1,5}(\.\.[0-9]{1,5})?$"‘ # extract JOBLIFESPAN
JOBLIFESPAN=${JOBLIFESPAN#JOBLIFESPAN=}
#echo $JOBLIFESPAN
50
if [[ $JOBS && $JOBSTARTTIME && $JOBLIFESPAN ]]
then
if [[ ‘echo "$JOBS"|egrep "\.\."‘ ]] \
# if JOBS is a range, select a random number of jobs in that range
then
BASE=$(( ‘echo "$JOBS"|egrep −o "^[0-9]*"‘ ))
RANGE=$(( ‘echo "$JOBS"|egrep −o "[0-9]*$"‘ − $BASE ))
JOBS=$[ ( $RANDOM % ( RANGE + 1 ) ) + $BASE ]
fi
103
60
# now JOBS is properly defined as a specific number
#echo $JOBS
while (( $JOBS >= 0 ))
do
if [[ ‘echo "$JOBSTARTTIME"|egrep "\.\."‘ ]] \
# if JOBSTARTTIME is a range, select a random number in that range
then
BASE=$(( ‘echo "$JOBSTARTTIME"|egrep −o "^[0-9]*"‘ ))
RANGE=$(( ‘echo "$JOBSTARTTIME"|egrep −o "[0-9]*$"‘ − $BASE ))
NEWJOBSTARTTIME=$[ ( $RANDOM % ( RANGE + 1 ) ) + $BASE ]
else
NEWJOBSTARTTIME=$JOBSTARTTIME
fi
70
# now JOBSTARTTIME is properly defined as NEWJOBSTARTTIME for this job
80
if [[ ‘echo "$JOBLIFESPAN"|egrep "\.\."‘ ]] \
# if JOBSLIFESPAN is a range, select a random number in that range
then
BASE=$(( ‘echo "$JOBLIFESPAN"|egrep −o "^[0-9]*"‘ ))
RANGE=$(( ‘echo "$JOBLIFESPAN"|egrep −o "[0-9]*$"‘ − $BASE ))
NEWJOBLIFESPAN=$[ ( $RANDOM % ( RANGE + 1 ) ) + $BASE ]
else
NEWJOBLIFESPAN=$JOBLIFESPAN
fi
90
# now JOBSLIFESPAN is properly defined as NEWJOBSLIFESPAN for this job
echo "user ${NEWJOBSTARTTIME} queue ${NEWJOBLIFESPAN}"
JOBS=$JOBS−1
done
else
echo "job schedule directives not found in $RUNCONF/run.conf"
exit 2
fi
else
echo "$RUNCONF/run.conf not found" # run.conf not found
exit 1
fi
run.sh
#!/bin/bash
source "./functions.sh"
# INITIALIZATION
SYNC TRACES SCRIPT="./scripts/utils/sync-traces.sh" # path of sync-traces script
SCRIPTS PATH="./scripts"
104
100
REPSERVER="mauirep.fisica.unipg.it"
CLIENTNAME="randomize"
10
if [ $CLIENTNAME == "randomize" ]
then
TEMP=‘echo $USER $HOSTNAME $RANDOM | md5sum | cut −d" " −f1‘
CLIENTNAME=${TEMP:24}
fi
ERROR CODE=39
# default error code
HELP="Usage: $0 -r|-l -t trace [-s server] [-h]
20
-s server
remote traces server.
-t trace
name of the trace.
-r|-l
remote or local operations.
-h
this help.
Usage examples:
local operations: $0 -l -t trace\
remote operations: $0 -r -t target -s server"
30
# Var initialization
NO ARGS=0
SERVER VAR=0
TARGET VAR=0
REMOTE VAR=0
LOCAL VAR=0
QUIET=0
IAMTHEFIRST=0
40
COLLAB=0
run() {
if [ ! −f whatami ]
then
echo "Node type not defined"
return 1
fi
50
WHATAMI=‘cat whatami‘
if [ "a$WHATAMI" != "asimulator" ]
then
echo "Not running on a simulator"
return 1
fi
echo "Checking datadir: $LOCAL_PATH"
60
if [ $QUIET == 0 ]; then echo −n " Checking the existence of the \
configuration file: $LOCAL_PATH/run.conf . ."; fi
check prerequisite "$LOCAL_PATH/run.conf"
if [ $RETURN != 0 ]
105
then
return 1
else
RUN CONF="$LOCAL_PATH/run.conf"
fi
70
# Importing all the needed variables from the configuration file
source $RUN CONF
if [ "a$RUNFEATURES" == "aparallel" ]
then
if [ "a$MAXPROC" == "a" ]
then
if [ $QUIET == 0 ]; then echo "Collaborative run without client limit" ; fi
MAXPROC=0
fi
80
fi
# Different type of run:
if [ $RUNTYPE == "fulltree" ]
then
echo "Starting fulltree run:"
if [ $CHECKED == "remote" ]
then
90
# Lock
$SCRIPTS PATH/manager/client.py −l −c $CLIENTNAME
STATUS=‘$SCRIPTS PATH/utils/sync−traces.sh −q −R −f status −t \
$LOCAL PATH −s $REPSERVER‘
if [ "a$STATUS" == "aready" ]
then
if [ $QUIET == 0 ]; then echo "Run ready to be done"; fi
100
# The job is ready for computation
if [ $QUIET == 0 ]; then echo " Switching $LOCAL_PATH: ready -> generating"; fi
$SCRIPTS PATH/utils/sync−traces.sh −q −U −f status −c ready \
−t $LOCAL PATH −s $REPSERVER
$SCRIPTS PATH/utils/sync−traces.sh −q −S −f status −c generating \
−t $LOCAL PATH −s $REPSERVER
flush status $LOCAL PATH startgenerating
$SCRIPTS PATH/utils/sync−traces.sh −q −S −f startgenerating \
−c ‘date +%s‘ −t $LOCAL PATH −s $REPSERVER
110
flush status $LOCAL PATH start$CLIENTNAME
$SCRIPTS PATH/utils/sync−traces.sh −q −S −f start$CLIENTNAME \
−c ‘date +%s‘ −t $LOCAL PATH −s $REPSERVER
if [ "a$RUNFEATURES" == "aparallel" ]
then
if [ $MAXPROC == 0 ]
then
if [ $QUIET == 0 ]; then echo "Generating a collaborative \
run (no client limit)"; fi
106
120
$SCRIPTS PATH/utils/sync−traces.sh −q −S −f crunning \
−c $CLIENTNAME −t $LOCAL PATH −s $REPSERVER
else
if [ $QUIET == 0 ]; then echo "Generating a collaborative run"; fi
$SCRIPTS PATH/utils/sync−traces.sh −q −S −f crunning \
−c $CLIENTNAME −t $LOCAL PATH −s $REPSERVER
fi
COLLAB=1
fi
130
# Unlock
$SCRIPTS PATH/manager/client.py −u −c $CLIENTNAME
IAMTHEFIRST=1
elif [ "a$STATUS" == "arunned" ]
then
if [ $QUIET == 0 ]; then echo "Someone has already runned"; fi
140
# Unlock
$SCRIPTS PATH/manager/client.py −u −c $CLIENTNAME
if [ $QUIET == 0 ]; then echo "Cleaning local copy"; fi
$SCRIPTS PATH/utils/sync−traces.sh −q −r −t $LOCAL PATH
exit 0
elif [ "a$STATUS" == "agenerating" ]
then
150
if [ $QUIET == 0 ]; then echo "Someone is generating traces" ; fi
# Unlock
$SCRIPTS PATH/manager/client.py −u −c $CLIENTNAME
if [ $QUIET == 0 ]; then echo "Cleaning local copy"; fi
$SCRIPTS PATH/utils/sync−traces.sh −q −r −t $LOCAL PATH
exit 0
160
elif [ "a$STATUS" == "arunning" ]
then
if [ "a$RUNFEATURES" != "aparallel" ]
then
if [ $QUIET == 0 ]; then echo "Not a collaborative run and someone \
is already running it" ; fi
# Unlock
$SCRIPTS PATH/manager/client.py −u −c $CLIENTNAME
170
if [ $QUIET == 0 ]; then echo "Cleaning local copy"; fi
$SCRIPTS PATH/utils/sync−traces.sh −q −r −t $LOCAL PATH
exit 0
else
if [ $MAXPROC == 0 ]
then
if [ $QUIET == 0 ]; then echo "Join collaborative run (no client limit)" ; fi
107
COLLAB=1
180
$SCRIPTS PATH/utils/sync−traces.sh −q −S −f crunning \
−c $CLIENTNAME −t $LOCAL PATH −s $REPSERVER
flush status $LOCAL PATH start$CLIENTNAME
$SCRIPTS PATH/utils/sync−traces.sh −q −S −f start$CLIENTNAME \
−c ‘date +%s‘ −t $LOCAL PATH −s $REPSERVER
# Unlock
$SCRIPTS PATH/manager/client.py −u −c $CLIENTNAME
190
else
RUNNINGPROC=‘$SCRIPTS PATH/utils/sync−traces.sh −q −R −f crunning \
−t $LOCAL PATH −s $REPSERVER | wc −l‘
if [ $MAXPROC −gt $RUNNINGPROC ]
then
if [ $QUIET == 0 ]; then echo "Join collaborative run" ; fi
COLLAB=1
$SCRIPTS PATH/utils/sync−traces.sh −q −S −f crunning \
200
−c $CLIENTNAME −t $LOCAL PATH −s $REPSERVER
flush status $LOCAL PATH start$CLIENTNAME
$SCRIPTS PATH/utils/sync−traces.sh −q −S −f start$CLIENTNAME \
−c ‘date +%s‘ −t $LOCAL PATH −s $REPSERVER
# Unlock
$SCRIPTS PATH/manager/client.py −u −c $CLIENTNAME
else
if [ $QUIET == 0 ]; then echo "Collaborative run already full \
210
of clients" ; fi
# Unlock
$SCRIPTS PATH/manager/client.py −u −c $CLIENTNAME
if [ $QUIET == 0 ]; then echo "Cleaning local copy"; fi
$SCRIPTS PATH/utils/sync−traces.sh −q −r −t $LOCAL PATH
exit 0
fi
220
fi
fi
else
if [ $QUIET == 0 ]; then echo "Unknown status"; fi
# Unlock
$SCRIPTS PATH/manager/client.py −u −c $CLIENTNAME
exit 0
230
fi
fi
108
if [[ $IAMTHEFIRST == 1 | | $CHECKED != "remote" ]]
then
if [ $QUIET == 0 ]; then echo −n " Checking the existence of a config \
240
template file: $LOCAL_PATH/config-simul-template . ."; fi
check prerequisite "$LOCAL_PATH/config-simul-template"
if [ $RETURN != 0 ]
then
return 1
else
CONFIG SIMUL TEMPLATE=\
"$LOCAL_PATH/config-simul-template"
fi
250
echo " Generating run config files:"
$SCRIPTS PATH/utils/resolve−variables.pl $CONFIG SIMUL TEMPLATE \
$RUN CONF $LOCAL PATH
echo " Generating run datadirs and moving config files:"
cd $LOCAL PATH
for i in $RUNPREFIX*
do
mkdir datadir−$i
mv $i datadir−$i/config
260
cp resources datadir−$i
cp workload−real−unscaled datadir−$i
mv datadir−$i $i
done
cd $OLDPWD
if [ $CHECKED == "remote" ]
then
if [ "a$RUNFEATURES" == "aparallel" ]
270
then
if [ $QUIET == 0 ]; then echo " Syncing local-generated traces \
with server for parallel execution"; fi
$SCRIPTS PATH/utils/sync−traces.sh −q −p −t $LOCAL PATH \
−s $REPSERVER
# Lock
$SCRIPTS PATH/manager/client.py −l −c $CLIENTNAME
if [ $QUIET == 0 ]; then echo " Setting ready flags on all traces"; fi
280
for i in $LOCAL PATH/$RUNPREFIX*
do
if [ $QUIET == 0 ]; then echo " $i: -> ready"; fi
$SCRIPTS PATH/utils/sync−traces.sh −q −S −f status −c ready \
−t $i −s $REPSERVER
done
# Unlock
$SCRIPTS PATH/manager/client.py −u −c $CLIENTNAME
290
else
if [ $QUIET == 0 ]; then echo " local-generated traces will not \
109
be propagated to server until simulated."; fi
fi
# Lock
$SCRIPTS PATH/manager/client.py −l −c $CLIENTNAME
# Set the job ready for computation
if [ $QUIET == 0 ]; then echo " Switching $LOCAL_PATH: \
300
generating -> running"; fi
$SCRIPTS PATH/utils/sync−traces.sh −q −U −f status \
−c generating −t $LOCAL PATH −s $REPSERVER
$SCRIPTS PATH/utils/sync−traces.sh −q −S −f status \
−c running −t $LOCAL PATH −s $REPSERVER
flush status $LOCAL PATH stopgenerating
$SCRIPTS PATH/utils/sync−traces.sh −q −S −f stopgenerating \
−c ‘date +%s‘ −t $LOCAL PATH −s $REPSERVER
310
# Unlock
$SCRIPTS PATH/manager/client.py −u −c $CLIENTNAME
fi
fi
if [ $CHECKED == "remote" ]
then
if [ "a$RUNFEATURES" == "aparallel" ]
then
if [ $QUIET == 0 ]; then echo " Starting server to server simulations:" ; fi
320
while [ 1 ]
do
# Lock
$SCRIPTS PATH/manager/client.py −l −c $CLIENTNAME
NEXTREADY=‘$SCRIPTS PATH/utils/ls−feat.sh −t $LOCAL PATH \
−f status −c ready −n 1‘
if [ "a$NEXTREADY" != "a" ]
330
then
if [ $QUIET == 0 ]; then echo " Switching $NEXTREADY: ready -> simulating"; fi
$SCRIPTS PATH/utils/sync−traces.sh −q −U −f status −c ready \
−t $NEXTREADY −s $REPSERVER
$SCRIPTS PATH/utils/sync−traces.sh −q −S −f status −c simulating \
−t $NEXTREADY −s $REPSERVER
# Unlock
$SCRIPTS PATH/manager/client.py −u −c $CLIENTNAME
340
if [ $QUIET == 0 ]; then echo " " ; \
echo "Entering simulate.sh:"; fi
./simulate.sh −t $NEXTREADY −s $REPSERVER −r −p
if [ $QUIET == 0 ]; then echo "Exiting simulate.sh" ; echo " " ; fi
# Lock
$SCRIPTS PATH/manager/client.py −l −c $CLIENTNAME
if [ $QUIET == 0 ]; then echo " Switching $NEXTREADY: \
110
simulating -> simulated"; fi
350
$SCRIPTS PATH/utils/sync−traces.sh −q −U −f status −c simulating \
−t $NEXTREADY −s $REPSERVER
$SCRIPTS PATH/utils/sync−traces.sh −q −S −f status −c simulated \
−t $NEXTREADY −s $REPSERVER
# Unlock
$SCRIPTS PATH/manager/client.py −u −c $CLIENTNAME
else
RUNNINGPROC=‘$SCRIPTS PATH/utils/sync−traces.sh −q −R −f crunning \
360
−t $LOCAL PATH −s $REPSERVER | wc −l‘
flush status $LOCAL PATH stop$CLIENTNAME
$SCRIPTS PATH/utils/sync−traces.sh −q −S −f stop$CLIENTNAME \
−c ‘date +%s‘ −t $LOCAL PATH −s $REPSERVER
if [ $RUNNINGPROC == 1 ]
then
if [ $QUIET == 0 ]; then echo " I am the last client exiting and \
cleaning"; fi
370
$SCRIPTS PATH/utils/sync−traces.sh −q −U −f crunning −c $CLIENTNAME \
−t $LOCAL PATH −s $REPSERVER
if [ $QUIET == 0 ]; then echo " Switching $LOCAL_PATH: running -> \
runned"; fi
$SCRIPTS PATH/utils/sync−traces.sh −q −U −f status −c running \
−t $LOCAL PATH −s $REPSERVER
$SCRIPTS PATH/utils/sync−traces.sh −q −S −f status −c runned \
−t $LOCAL PATH −s $REPSERVER
380
MIN=‘date +%s‘
MAX=0
for i in ‘ssh −− $RSYNC USER@$REPSERVER \
ls /rep/$LOCAL PATH/.start*.lock‘ \
‘ssh −− $RSYNC USER@$REPSERVER ls /rep/$LOCAL PATH/.stop*.lock‘
do
CURR=‘ssh −− $RSYNC USER@$REPSERVER cat $i‘
if [[ $CURR < $MIN ]]
then
390
MIN=$CURR
fi
if [[ $CURR > $MAX ]]
then
MAX=$CURR
fi
done
let "TOTAL=MAX-MIN"
400
if [ $QUIET == 0 ]; then echo "--" ; echo " " ; echo "Overall duration: \
$TOTAL"; fi
else
if [ $QUIET == 0 ]; then echo " Other clients working exiting"; fi
$SCRIPTS PATH/utils/sync−traces.sh −q −U −f crunning −c $CLIENTNAME \
111
−t $LOCAL PATH −s $REPSERVER
fi
# Unlock
410
$SCRIPTS PATH/manager/client.py −u −c $CLIENTNAME
if [ $QUIET == 0 ]; then echo " Cleaning $LOCAL_PATH"; fi
$SCRIPTS PATH/utils/sync−traces.sh −q −r −t $LOCAL PATH
break
fi
done
else
420
if [ $QUIET == 0 ]; then echo " Starting local to server simulations:" ; fi
for i in $LOCAL PATH/$RUNPREFIX*
do
if [ $QUIET == 0 ]; then echo " " ; echo "Entering simulate.sh:"; fi
./simulate.sh −t $i −s $REPSERVER −l −p −u
if [ $QUIET == 0 ]; then echo "Exiting simulate.sh" ; echo " " ; fi
done
# Lock
$SCRIPTS PATH/manager/client.py −l −c $CLIENTNAME
430
# Set the job ready for computation
if [ $QUIET == 0 ]; then echo " Switching $LOCAL_PATH: running -> runned"; fi
$SCRIPTS PATH/utils/sync−traces.sh −q −U −f status −c running \
−t $LOCAL PATH −s $REPSERVER
$SCRIPTS PATH/utils/sync−traces.sh −q −S −f status −c runned \
−t $LOCAL PATH −s $REPSERVER
# Unlock
$SCRIPTS PATH/manager/client.py −u −c $CLIENTNAME
440
if [ $QUIET == 0 ]; then echo " Cleaning $LOCAL_PATH"; fi
$SCRIPTS PATH/utils/sync−traces.sh −q −r −t $LOCAL PATH
fi
else
echo " Starting only local simulations:"
for i in $LOCAL PATH/$RUNPREFIX*
do
if [ $QUIET == 0 ]; then echo " " ; echo "Entering simulate.sh:"; fi
./simulate.sh −t $i −l −k
450
if [ $QUIET == 0 ]; then echo "Exiting simulate.sh" ; echo " " ; fi
done
fi
elif [ $RUNTYPE == "random" ]
then
echo "Starting random run:"
460
elif [ $RUNTYPE == "genetic" ]
then
112
echo "Starting genetic run:"
# Variables existence
if [ $QUIET == 0 ]; then echo −n " Checking the existence of the GENOTYPE . ."; fi
check variable $GENOTYPE
if [ $RETURN != 0 ]
then
return 1
470
fi
if [ $QUIET == 0 ]; then echo −n " Checking the existence of the \
GENERATIONS variable . ."; fi
check variable $GENERATIONS
if [ $RETURN != 0 ]
then
return 1
fi
480
if [ $QUIET == 0 ]; then echo −n " Checking the existence of the \
POPULATION variable . ."; fi
check variable $POPULATION
if [ $RETURN != 0 ]
then
return 1
fi
if [ $QUIET == 0 ]; then echo −n " Checking the existence of the \
MUTATIONRATE variable . ."; fi
490
check variable $MUTATIONRATE
if [ $RETURN != 0 ]
then
return 1
fi
if [ $QUIET == 0 ]; then echo −n " Checking the existence of the \
CROSSOVERRATE variable . ."; fi
check variable $CROSSOVERRATE
if [ $RETURN != 0 ]
500
then
return 1
fi
if [ $QUIET == 0 ]; then echo −n " Checking the existence of the \
SHIFTRATE variable . ."; fi
check variable $SHIFTRATE
if [ $RETURN != 0 ]
then
return 1
510
fi
# File check
if [ $QUIET == 0 ]; then echo −n " Checking the existence of a config \
template file: $LOCAL_PATH/config-simul-template . ."; fi
check prerequisite "$LOCAL_PATH/config-simul-template"
if [ $RETURN != 0 ]
then
return 1
else
520
113
CONFIG SIMUL TEMPLATE="$LOCAL_PATH/config-simul-template"
fi
if [ $CHECKED == "remote" ]
then
# Lock
$SCRIPTS PATH/manager/client.py −l −c $CLIENTNAME
STATUS=‘$SCRIPTS PATH/utils/sync−traces.sh −q −R −f status \
−t $LOCAL PATH −s $REPSERVER‘
530
if [ "a$STATUS" == "aready" ]
then
if [ $QUIET == 0 ]; then echo "Run ready to be done"; fi
# The job is ready for computation
if [ $QUIET == 0 ]; then echo " Switching $LOCAL_PATH: ready -> running"; fi
$SCRIPTS PATH/utils/sync−traces.sh −q −U −f status −c ready \
−t $LOCAL PATH −s $REPSERVER
$SCRIPTS PATH/utils/sync−traces.sh −q −S −f status −c running \
540
−t $LOCAL PATH −s $REPSERVER
STATUS="running"
fi
if [ "a$STATUS" == "arunning" ]
then
RUNNINGPROC=‘$SCRIPTS PATH/utils/sync−traces.sh −q −R −f crunning \
−t $LOCAL PATH −s $REPSERVER | wc −l‘
RUNNEDPROC=‘$SCRIPTS PATH/utils/sync−traces.sh −q −R −f crunned \
550
−t $LOCAL PATH −s $REPSERVER | wc −l‘
if [ "a$RUNNINGPROC" == "a" ]; then RUNNINGPROC=0 ; fi
if [ "a$RUNNEDPROC" == "a" ]; then RUNNEDPROC=0 ; fi
let "TOTAL=RUNNINGPROC+RUNNEDPROC"
if [ $MAXWORLDS == 0 ]
then
if [ $QUIET == 0 ]; then echo "Running forever" ; fi
560
else
if [ $TOTAL −ge $MAXWORLDS ]
then
if [ $QUIET == 0 ]; then echo "Worlds limit reached" ; fi
# Unlock
$SCRIPTS PATH/manager/client.py −u −c $CLIENTNAME
exit 0
fi
fi
570
if [ $MAXPROC == 0 ]
then
if [ $QUIET == 0 ]; then echo "Join collaborative run (no client limit)" ; fi
$SCRIPTS PATH/utils/sync−traces.sh −q −S −f crunning −c $CLIENTNAME \
−t $LOCAL PATH −s $REPSERVER
114
flush status $LOCAL PATH start$CLIENTNAME
$SCRIPTS PATH/utils/sync−traces.sh −q −S −f start$CLIENTNAME \
580
−c ‘date +%s‘ −t $LOCAL PATH −s $REPSERVER
# Unlock
$SCRIPTS PATH/manager/client.py −u −c $CLIENTNAME
else
if [ $MAXPROC −gt $RUNNINGPROC ]
then
if [ $QUIET == 0 ]; then echo "Join collaborative run" ; fi
590
$SCRIPTS PATH/utils/sync−traces.sh −q −S −f crunning −c $CLIENTNAME \
−t $LOCAL PATH −s $REPSERVER
flush status $LOCAL PATH start$CLIENTNAME
$SCRIPTS PATH/utils/sync−traces.sh −q −S −f start$CLIENTNAME \
−c ‘date +%s‘ −t $LOCAL PATH −s $REPSERVER
# Unlock
$SCRIPTS PATH/manager/client.py −u −c $CLIENTNAME
600
else
if [ $QUIET == 0 ]; then echo "Collaborative run already full of clients" ; fi
# Unlock
$SCRIPTS PATH/manager/client.py −u −c $CLIENTNAME
exit 0
fi
fi
else
610
if [ $QUIET == 0 ]; then echo "Run status: $STATUS. Nothing to do" ; fi
# Unlock
$SCRIPTS PATH/manager/client.py −u −c $CLIENTNAME
exit 0
fi
fi
for j in ‘seq −w 1 $GENERATIONS‘
620
do
let "k=j-1"
echo " Population analysis on generation: $k"
./scripts/genetic/analyze−generation.pl \
$CONFIG SIMUL TEMPLATE $RUN CONF $LOCAL PATH
if [ −f avgfitness ]
then
630
avgfit=‘cat avgfitness‘
if [ $CHECKED == "remote" ]
115
then
# Lock
$SCRIPTS PATH/manager/client.py −l −c $CLIENTNAME
set status $LOCAL PATH gfit−$k−$CLIENTNAME $avgfit
640
# Lock
$SCRIPTS PATH/manager/client.py −u −c $CLIENTNAME
fi
echo $avgfit > $LOCAL PATH/gfit−$k
rm −f avgfitness
fi
if [ −f numgenotypes ]
650
then
popsize=‘cat numgenotypes‘
if [ $CHECKED == "remote" ]
then
# Lock
$SCRIPTS PATH/manager/client.py −l −c $CLIENTNAME
set status $LOCAL PATH pops−$k−$CLIENTNAME $popsize
660
# Lock
$SCRIPTS PATH/manager/client.py −u −c $CLIENTNAME
fi
echo $popsize > $LOCAL PATH/pops−$k
rm −f numgenotypes
fi
670
echo " New generation: $j"
./scripts/genetic/generate−generation.pl $CONFIG SIMUL TEMPLATE \
$RUN CONF $LOCAL PATH
echo " Starting simulations:"
echo "
Generating run datadirs and moving config files:"
for i in $LOCAL PATH/$RUNPREFIX*
do
680
if [ $CHECKED == "remote" ]
then
# Lock
$SCRIPTS PATH/manager/client.py −l −c $CLIENTNAME
STATUS=‘$SCRIPTS PATH/utils/sync−traces.sh −q −R −f status \
−t $i −s $REPSERVER‘
CLIID=‘$SCRIPTS PATH/utils/sync−traces.sh −q −R −f cliid \
−t $i −s $REPSERVER‘
690
if [[ "a$STATUS" == "asimulated" | | "a$STATUS" == "asimulating" ]]
116
then
if [ $QUIET == 0 ]; then echo " " ; echo "Genotype already \
simulated/simulating, skip simulate"; fi
if [[ "a$CLIID" == "a$CLIENTNAME" ]]
then
if [ $QUIET == 0 ]; then echo " " ; echo " Genotype is on \
my population"; fi
else
700
if [ $QUIET == 0 ]; then echo " " ; echo " Genotype is not \
on my population, removing it"; fi
$SCRIPTS PATH/utils/sync−traces.sh −q −r −t $i
fi
# Unlock
$SCRIPTS PATH/manager/client.py −u −c $CLIENTNAME
else
if [ $QUIET == 0 ]; then echo " Switching $i: ready -> simulating"; fi
flush status $i status
710
set status $i status simulating
set status $i cliid $CLIENTNAME
# Unlock
$SCRIPTS PATH/manager/client.py −u −c $CLIENTNAME
if [ $QUIET == 0 ]; then echo " Copying resurces and workload to $i"; fi
cp $LOCAL PATH/resources "$i"
cp $LOCAL PATH/workload−real−unscaled "$i"
720
if [ $QUIET == 0 ]; then echo " " ; echo "Entering simulate.sh:"; fi
./simulate.sh −t $i −l −k −p −s $REPSERVER
if [ $QUIET == 0 ]; then echo "Exiting simulate.sh" ; echo " " ; fi
FITNESSVALUE=‘$LOCAL PATH/$FITNESS $i/workload−simul−unscaled‘
echo $FITNESSVALUE > "$i/fitness"
# Lock
$SCRIPTS PATH/manager/client.py −l −c $CLIENTNAME
730
if [ $QUIET == 0 ]; then echo " Switching $i: simulating -> simulated"; fi
unset status $i status simulating
set status $i status simulated
set status $i fitness $FITNESSVALUE
# Unlock
$SCRIPTS PATH/manager/client.py −u −c $CLIENTNAME
fi
else
if [ $QUIET == 0 ]; then echo " Copying resurces and workload to $i"; fi
cp $LOCAL PATH/resources "$i"
cp $LOCAL PATH/workload−real−unscaled "$i"
if [ $QUIET == 0 ]; then echo " " ; echo "Entering simulate.sh:"; fi
./simulate.sh −t $i −l −k
if [ $QUIET == 0 ]; then echo "Exiting simulate.sh" ; echo " " ; fi
echo " Evaluating fitness:"
117
740
FITNESSVALUE=‘$LOCAL PATH/$FITNESS $i/workload−simul−unscaled‘
750
echo $FITNESSVALUE > "$i/fitness"
fi
done
done
if [ $CHECKED == "remote" ]
then
# Lock
$SCRIPTS PATH/manager/client.py −l −c $CLIENTNAME
760
flush status $LOCAL PATH stop$CLIENTNAME
$SCRIPTS PATH/utils/sync−traces.sh −q −S −f stop$CLIENTNAME \
−c ‘date +%s‘ −t $LOCAL PATH −s $REPSERVER
$SCRIPTS PATH/utils/sync−traces.sh −q −U −f crunning \
−c $CLIENTNAME −t $LOCAL PATH −s $REPSERVER
$SCRIPTS PATH/utils/sync−traces.sh −q −S −f crunned \
−c $CLIENTNAME −t $LOCAL PATH −s $REPSERVER
770
if [ $MAXWORLDS != 0 ]
then
RUNNEDPROC=‘$SCRIPTS PATH/utils/sync−traces.sh −q −R −f crunned \
−t $LOCAL PATH −s $REPSERVER | wc −l‘
if [ "a$RUNNEDPROC" == "a" ]; then RUNNEDPROC=0 ; fi
if [ $RUNNEDPROC −ge $MAXWORLDS ]
then
if [ $QUIET == 0 ]; then echo "Genetic simulation done" ; fi
780
if [ $QUIET == 0 ]; then echo " Switching $LOCAL_PATH: running -> runned"; fi
$SCRIPTS PATH/utils/sync−traces.sh −q −U −f status −c running \
−t $LOCAL PATH −s $REPSERVER
$SCRIPTS PATH/utils/sync−traces.sh −q −S −f status −c runned \
−t $LOCAL PATH −s $REPSERVER
fi
fi
# Unlock
790
$SCRIPTS PATH/manager/client.py −u −c $CLIENTNAME
$SCRIPTS PATH/utils/sync−traces.sh −q −r −t $LOCAL PATH
fi
fi
}
# checkinput, check input variables, reporting “bad” or a code for each command
checkinput() {
800
# echo “$TARGET VAR $LOCAL VAR $KEEP VAR $SERVER VAR $REMOTE VAR $PUT VAR”
CHECKED="bad"
if (( $TARGET VAR + $LOCAL VAR == 2 )) && \
(( $SERVER VAR + $REMOTE VAR == 0 ))
then
118
# from local to local
CHECKED="localr"
fi
if (( $TARGET VAR + $SERVER VAR + $REMOTE VAR == 3 )) && \
(( $LOCAL VAR == 0 ))
810
then
# from server to local
CHECKED="remote"
fi
}
localr() {
run
RETURN=$?
if [ $RETURN == 0 ]
820
then
if [ $QUIET == 0 ]; then echo "Run successfully done"; fi
else
echo "Error: Run failed"
fi
}
remote() {
# 1) download from server the main run directory (sub excluded)
if [ $QUIET == 0 ]; then echo "Downloading pre-run trace"; fi
830
$SYNC TRACES SCRIPT −q −n −g −t $LOCAL PATH −s $SERVER URL
RETURN=$?
# 2) run
if [ $RETURN == 0 ]
then
if [ $QUIET == 0 ]; then echo " Pre-run trace successfully downloaded"; fi
run
RETURN=$?
if [ $RETURN == 0 ]
then
840
if [ $QUIET == 0 ]; then echo "Run successfully done"; fi
else
echo "Error: Run failed"
fi
else
echo "Error: Downloading failed"
fi
}
if [ $# -eq “$NO ARGS” ] # Script invoked with no command-line args.
850
then
echo −e "$HELP"
exit $ERROR CODE # Exit and explain usage, if no argument(s) given.
fi
while getopts "s:t:lr" Option
# Command arguments:
# -t target (local path)
# -s server
# -r, -l remote or local operations
860
do
119
case $Option in
s ) SERVER VAR=1
SERVER URL=$OPTARG;;
t ) TARGET VAR=1
LOCAL PATH=$OPTARG;;
r ) REMOTE VAR=1;;
l ) LOCAL VAR=1;;
h ) echo −e $HELP
exit 1;;
* ) echo −e $HELP
exit 1;;
esac
done
870
checkinput
if [ $CHECKED == "bad" ]
then
echo "Error: bad parameters"
echo −e $HELP
exit 1
else
880
if [ $CHECKED == "localr" ]
then
localr
if [[ $QUIET == 0 && $RETURN == 0 ]]; then echo "Local run ok"; fi
exit $RETURN
fi
890
if [ $CHECKED == "remote" ]
then
remote
if [[ $QUIET == 0 && $RETURN == 0 ]]; then echo "Remote run ok"; fi
exit $RETURN
fi
fi
simulate.sh
#!/bin/bash
# NOTE:
#
#
source "./functions.sh"
# INITIALIZATION
SYNC TRACES SCRIPT="./scripts/utils/sync-traces.sh" # path of sync-traces script
SCRIPTS PATH="./scripts"
# Path of the scripts
ERROR CODE=39 # default error code
HELP="Usage: $0 [-l|-r|-p|-k] [-u] -t trace [-s server] [-h]\n\n
-t target pathname of target\n
-s server remote traces server\n
-r, -l
download target from remote server or use local target\n
120
10
-p
put result on remote server\n
-k
do not erase local target on exit\n\n
-u
check & set simulating/ed status\n\n
-h
this help.\n\n
20
Usage examples:\n
simulate from local to local: $0 -l -k -t target\n
simulate from remote server to local: $0 -r -k -t target -s server\n
simulate from local to remote server: $0 -l -p -t target -s server\n
simulate from local to remote server and keep a local copy: $0 -l -p -k \
-t target -s server\n
simulate from remote server to remote server: $0 -r -p -t target -s server\n
30
simulate from remote server to remote server and keep a local copy: $0 -r -p -k \
-t target -s server\n"
# Var initialization
NO ARGS=0
SERVER VAR=0
TARGET VAR=0
REMOTE VAR=0
LOCAL VAR=0
40
PUT VAR=0
KEEP VAR=0
QUIET=0
VERBOSE=0
STATUS VAR=0
CLIENTNAME="randomize"
if [ $CLIENTNAME == "randomize" ]
then
50
TEMP=‘echo $USER $HOSTNAME $RANDOM | md5sum | cut −d" " −f1‘
CLIENTNAME=${TEMP:24}
fi
simulate() {
if [ $STATUS VAR == 1 ]
then
# Lock
$SCRIPTS PATH/manager/client.py −l −c $CLIENTNAME
60
CHECK=2
# check status return 0 if found, 1 if not found, 2 if an error occur
check status $LOCAL PATH status simulating > /dev/null
CHECK=$?
if [ $CHECK == 0 ]
then
if [ $QUIET == 0 ]; then echo " Trace $LOCAL_PATH is already simulating" ; fi
# Unlock
$SCRIPTS PATH/manager/client.py −u −c $CLIENTNAME
return 2 # trace in simulating state
fi
121
70
CHECK=2
# check status return 0 if found, 1 if not found, 2 if an error occur
check status $LOCAL PATH status simulated > /dev/null
CHECK=$?
if [ $CHECK == 0 ]
then
if [ $QUIET == 0 ]; then echo " Trace $LOCAL_PATH already simulated" ; fi
80
# Unlock
$SCRIPTS PATH/manager/client.py −u −c $CLIENTNAME
return 2 # trace in simulating state
fi
CHECK=0
# Check for $LOCAL PATH existence
$SYNC TRACES SCRIPT −q −e −t $LOCAL PATH −s $SERVER URL
CHECK=$?
90
if [ $CHECK == 2 ]
then
if [ $QUIET == 0 ]; then echo " Trace $LOCAL_PATH does not exits: \
assuming ready" ; fi
# trace not in simulating/ed state yet, locking now setting status=simulating
set status $LOCAL PATH status simulating > /dev/null
# Unlock
$SCRIPTS PATH/manager/client.py −u −c $CLIENTNAME
100
else
CHECK=2
# check status return 0 if found, 1 if not found, 2 if an error occur
check status $LOCAL PATH status ready > /dev/null
CHECK=$?
if [ $CHECK == 0 ]
then
if [ $QUIET == 0 ]; then echo " Trace $LOCAL_PATH: ready" ; fi
110
# trace not in simulating/ed state yet, locking now setting status=simulating
set status $LOCAL PATH status simulating > /dev/null
# Unlock
$SCRIPTS PATH/manager/client.py −u −c $CLIENTNAME
else
if [ $QUIET == 0 ]; then echo " Trace $LOCAL_PATH: unknown status" ; fi
# Unlock
$SCRIPTS PATH/manager/client.py −u −c $CLIENTNAME
120
return 1 # trace in error state
fi
fi
fi
# now proper simulate
if [ $QUIET == 0 ]; then echo " Checking headers"; fi
if [ $QUIET == 0 ]; then echo " Checking datadir: $LOCAL_PATH"; fi
if [ $QUIET == 0 ]; then echo −n " Checking the existence of a workload trace: \
122
130
$LOCAL_PATH/workload-real-unscaled . ."; fi
check prerequisite "$LOCAL_PATH/workload-real-unscaled"
if [ $RETURN != 0 ]
then
return 1
else
WORKLOAD REAL UNSCALED="$LOCAL_PATH/workload-real-unscaled"
fi
if [ $QUIET == 0 ]; then echo −n " Checking the existence of a resources trace: \
140
$LOCAL_PATH/resources . ."; fi
check prerequisite "$LOCAL_PATH/resources"
if [ $RETURN != 0 ]
then
return 1
else
WORKLOAD RESOURCES="$LOCAL_PATH/resources"
fi
if [ $QUIET == 0 ]; then echo −n " Checking the existence of a config file: \
150
$LOCAL_PATH/config . ."; fi
check prerequisite "$LOCAL_PATH/config"
if [ $RETURN != 0 ]
then
return 1
else
CONFIG RESOURCES="$LOCAL_PATH/config"
fi
if [ $QUIET == 0 ]; then echo −n " Checking the existence of a header config file: \
160
$LOCAL_PATH/config-simul-header . ."; fi
check prerequisite "$LOCAL_PATH/config-simul-header"
if [ $RETURN != 0 ]
then
if [ $QUIET == 0 ]; then echo −n " Checking the existence of a header config file: \
traces/config-simul-header . ."; fi
check prerequisite "traces/config-simul-header"
if [ $RETURN != 0 ]
then
return 1
170
else
CONFIG SIMUL HEADER="traces/config-simul-header"
fi
else
CONFIG SIMUL HEADER="$LOCAL_PATH/config-simul-header"
fi
if [ $QUIET == 0 ]; then echo " Starting pre simulation tasks:"; fi
if [ $QUIET == 0 ]; then echo " Cleaning old files"; fi
rm −fv resources maui.cfg workload stats/simstat.out
if [ $QUIET == 0 ]; then echo " Copying configuration"; fi
cat $CONFIG SIMUL HEADER $CONFIG RESOURCES > maui.cfg
if [ $QUIET == 0 ]; then echo " Copying resources trace file"; fi
cat $WORKLOAD RESOURCES > resources
FIRST REAL RUN=‘./scripts/utils/workload−first−submitted.pl \
$WORKLOAD REAL UNSCALED‘
123
180
CURRENTTIME=‘date +%s‘;
STARTTIME=$(($CURRENTTIME + 3))
OFFSET=$(($STARTTIME − $FIRST REAL RUN))
190
WORKLOAD REAL SCALED=$LOCAL PATH/workload−real−scaled
WORKLOAD SIMUL SCALED=$LOCAL PATH/workload−simul−scaled
WORKLOAD SIMUL UNSCALED=$LOCAL PATH/workload−simul−unscaled
if [ $QUIET == 0 ]; then echo " Shifting workload in the future"; fi
$SCRIPTS PATH/utils/workload−time−updater.pl $WORKLOAD REAL UNSCALED \
$WORKLOAD REAL SCALED $OFFSET
if [ $QUIET == 0 ]; then echo " Ordering workload"; fi
cat $WORKLOAD REAL SCALED | sort −n > $LOCAL PATH/temp workload
200
mv −f $LOCAL PATH/temp workload $WORKLOAD REAL SCALED
if [ $QUIET == 0 ]; then echo " Copying workload"; fi
cat $WORKLOAD REAL SCALED > workload
if [ $QUIET == 0 ]; then echo −n " Starting simulation at "; echo $STARTTIME ; fi
$SCRIPTS PATH/utils/run−at.pl $STARTTIME
ENDTIME=‘date +%s‘
210
if [ $QUIET == 0 ]; then echo " Writing simulation duration:"; fi
let "SIMTIME= $ENDTIME - $STARTTIME"
echo $SIMTIME > $LOCAL PATH/duration
if [[ $CHECKED == "s2s" | | $CHECKED == "l2s" ]]
then
# Lock
$SCRIPTS PATH/manager/client.py −l −c $CLIENTNAME
220
flush status $LOCAL PATH duration > /dev/null
set status $LOCAL PATH duration $SIMTIME > /dev/null
# Unlock
$SCRIPTS PATH/manager/client.py −u −c $CLIENTNAME
fi
if [ $QUIET == 0 ]; then echo " Starting post simulation tasks:"; fi
230
if [ $QUIET == 0 ]; then echo " Moving results"; fi
cat stats/simstat.out > $WORKLOAD SIMUL SCALED
if [ $QUIET == 0 ]; then echo " Shifting simulation in the past"; fi
$SCRIPTS PATH/utils/workload−time−updater.pl $WORKLOAD SIMUL SCALED \
$WORKLOAD SIMUL UNSCALED "-$OFFSET"
if [ $QUIET == 0 ]; then echo " Creating Human readable formats:"; fi
$SCRIPTS PATH/utils/workload−clean.pl $WORKLOAD SIMUL SCALED \
$LOCAL PATH/workload−simul−scaled−cleaned
$SCRIPTS PATH/utils/workload−clean.pl $WORKLOAD REAL SCALED \
$LOCAL PATH/workload−real−scaled−cleaned
$SCRIPTS PATH/utils/workload−clean.pl $WORKLOAD REAL UNSCALED \
$LOCAL PATH/workload−real−unscaled−cleaned
124
240
$SCRIPTS PATH/utils/workload−clean.pl $WORKLOAD SIMUL UNSCALED \
$LOCAL PATH/workload−simul−unscaled−cleaned
if [ $QUIET == 0 ]; then echo " Cleaning files"; fi
if [ $VERBOSE == 0 ]
then
250
rm −f resources maui.cfg workload stats/simstat.out
else
rm −fv resources maui.cfg workload stats/simstat.out
fi
# Compressing results
if [ $QUIET == 0 ]; then echo " Compressing files" ; fi
if [ $VERBOSE == 0 ]
then
gzip −fq $LOCAL PATH/workload*
260
else
gzip −f $LOCAL PATH/workload*
fi
if [ $STATUS VAR == 1 ]
then
# Lock
$SCRIPTS PATH/manager/client.py −l −c $CLIENTNAME
# setting status=simulated
270
set status $LOCAL PATH status simulated > /dev/null
# now we can unset status simulating
unset status $LOCAL PATH status simulating > /dev/null
# Unlock
$SCRIPTS PATH/manager/client.py −u −c $CLIENTNAME
fi
}
clean local() {
280
if [ $QUIET == 0 ]; then echo " Cleaning $LOCAL_PATH"; fi
$SYNC TRACES SCRIPT −q −r −t $LOCAL PATH
RETURN=$?
if [[ $RETURN != 0 ]]; then echo " Error: cleaning $LOCAL_PATH error"; fi
}
# checkinput, check input variables, reporting “bad” or a code for each command
checkinput() {
# echo “$TARGET VAR $LOCAL VAR $KEEP VAR $SERVER VAR $REMOTE VAR $PUT VAR”
CHECKED="bad"
290
if (( $TARGET VAR + $LOCAL VAR == 2 )) && \
(( $SERVER VAR + $REMOTE VAR + $PUT VAR == 0 ))
then
# from local to local
CHECKED="l2l"
fi
if (( $TARGET VAR + $SERVER VAR + $REMOTE VAR == 3 )) && \
(( $LOCAL VAR + $PUT VAR == 0 ))
then
# from server to local
300
CHECKED="s2l"
125
fi
if (( $TARGET VAR + $SERVER VAR + $LOCAL VAR + $PUT VAR == 4 )) && \
(( $REMOTE VAR == 0 ))
then
# from local to server (remove local target)
CHECKED="l2s"
fi
if (( $TARGET VAR + $SERVER VAR + $REMOTE VAR + $PUT VAR == 4 )) && \
(( $LOCAL VAR == 0 ))
310
then
# from server to server (remove local target)
CHECKED="s2s"
fi
}
l2l() {
# local to local simulate
if [ $QUIET == 0 ]; then echo "Local to local simulating $LOCAL_PATH"; fi
simulate
320
RETURN=$?
if [[ $RETURN != 0 ]]; then echo "Error: simulating $LOCAL_PATH error"; fi
}
s2l() {
# server to local simulate
if [ $QUIET == 0 ]; then echo "Server to local simulating $LOCAL_PATH from \
$SERVER_URL"; fi
if [ $QUIET == 0 ]; then echo "Downloading $LOCAL_PATH from $SERVER_URL"; fi
330
$SYNC TRACES SCRIPT −g −t $LOCAL PATH −s $SERVER URL
RETURN=$?
# Simulate
if [ $RETURN == 0 ]
then
simulate
RETURN=$?
if [[ $RETURN != 0 ]]; then echo "Error: simulating $LOCAL_PATH"; fi
else
echo "Error: Downloading $LOCAL_PATH from $SERVER_URL failed"
340
fi
}
l2s() {
# local to server simulate
if [ $QUIET == 0 ]; then echo "Local to server simulating $LOCAL_PATH to \
$SERVER_URL"; fi
# simulate
simulate
RETURN=$?
350
# check simulate return (0 ok, 1 error, 2 simulating/ed)
if [ $RETURN == 1 ]
then
echo "Error: simulating $LOCAL_PATH error"
return $RETURN
fi
126
if [ $RETURN == 2 ]
then
360
if [ $QUIET == 0 ]; then echo " $LOCAL_PATH already simulating/ed"; fi
UPLOAD="no"
fi
# Check for $LOCAL PATH existence
$SYNC TRACES SCRIPT −q −e −t $LOCAL PATH −s $SERVER URL
RETURN=$?
# if trace exist do not perform a clean, print a warning
if [ $RETURN == 1 ]
370
then
echo "Error: cannot check trace on server, upload aborted, local simulated trace \
not deleted"
return $RETURN
fi
# upload to server
if [ "a$UPLOAD" != "ano" ]
then
if [ $QUIET == 0 ]; then echo "Uploading trace to server"; fi
380
$SYNC TRACES SCRIPT −q −p −t $LOCAL PATH −s $SERVER URL
RETURN=$?
if [ $RETURN == 0 ]
then
if [ $QUIET == 0 ]; then echo "Uploading ok"; fi
# clean local if requested
if [ $KEEP VAR == 0 ]; then clean local; fi
else
echo "Error: Uploading failed"
390
fi
else
if [ $QUIET == 0 ]; then echo "Skipping uploading trace to server"; fi
RETURN=0
fi
}
s2s() {
# server to server simulate
400
if [ $QUIET == 0 ]; then echo "Server to server simulating - local path=$LOCAL_PATH; \
server=$SERVER_URL"; fi
# Control status to save time
if [ $STATUS VAR == 1 ]
then
# Lock
$SCRIPTS PATH/manager/client.py −l −c $CLIENTNAME
CHECK=2
410
# check status return 0 if found, 1 if not found, 2 if an error occur
check status $LOCAL PATH status simulating > /dev/null
CHECK=$?
if [ $CHECK == 0 ]
then
127
if [ $QUIET == 0 ]; then echo " Trace is already simulating" ; fi
# Unlock
$SCRIPTS PATH/manager/client.py −u −c $CLIENTNAME
return 0 # not an error but trace is in simulating state -> exit
fi
420
CHECK=2
# check status return 0 if found, 1 if not found, 2 if an error occur
check status $LOCAL PATH status simulated > /dev/null
CHECK=$?
if [ $CHECK == 0 ]
then
if [ $QUIET == 0 ]; then echo " Trace already simulated" ; fi
# Unlock
$SCRIPTS PATH/manager/client.py −u −c $CLIENTNAME
430
return 0 # not an error but trace is in simulated state -> exit
fi
# Unlock
$SCRIPTS PATH/manager/client.py −u −c $CLIENTNAME
fi
# download from server
$SYNC TRACES SCRIPT −g −t $LOCAL PATH −s $SERVER URL
RETURN=$?
440
# simulate
if [ $RETURN == 0 ]
then
simulate
RETURN=$?
else
echo "Error: downloading error"
fi
# check simulate return (0 ok, 1 error, 2 simulating/ed)
if [ $RETURN == 1 ]
450
then
echo "Error: simulating $LOCAL_PATH error"
return $RETURN
fi
if [ $RETURN == 2 ]
then
if [ $QUIET == 0 ]; then echo " $LOCAL_PATH already simulating/ed"; fi
if [ $QUIET == 0 ]; then echo " Skipping uploading trace to server"; fi
RETURN=0
460
fi
if [ $RETURN == 0 ]
then
# upload to server
$SYNC TRACES SCRIPT −p −t $LOCAL PATH −s $SERVER URL
RETURN=$?
# 4) clean local
if [ $RETURN == 0 ]
then
470
if [ $KEEP VAR == 0 ]; then clean local; fi
RETURN=$?
128
else
echo "Error: uploading error"
fi
if [[ $RETURN != 0 ]]; then echo "Error: local cleaning error"; fi
fi
}
if [ $# -eq “$NO ARGS” ] # Script invoked with no command-line args.
480
then
echo −e $HELP
exit $ERROR CODE # Exit and explain usage, if no argument(s) given.
fi
while getopts "s:t:rlpkuhvq" Option
# Command arguments:
# -t target (local path)
# -s server
# -r, -l download target from remote server or use local path for target
490
# -p put result on remote server
# -k do not erase local target on exit
# -u check simulating/ed status
do
case $Option in
s ) SERVER VAR=1
SERVER URL=$OPTARG;;
t ) TARGET VAR=1
LOCAL PATH=$OPTARG
500
TARGET=‘basename $OPTARG‘;;
r ) REMOTE VAR=1;;
l ) LOCAL VAR=1;;
p ) PUT VAR=1;;
k ) KEEP VAR=1;;
v ) VERBOSE=1;;
q ) QUIET=1;;
u ) STATUS VAR=1;;
h ) echo −e $HELP
exit 1;;
510
* ) echo −e $HELP
exit 1;;
esac
done
checkinput
if [ $CHECKED == "bad" ]
then
echo "Error: bad parameters"
echo −e $HELP
520
exit 1
else
if [ $CHECKED == "l2l" ]
then
l2l
if [[ $QUIET == 0 && $RETURN == 0 ]]; \
then echo "Local to Local simulation ok"; fi
exit $RETURN
129
fi
530
if [ $CHECKED == "s2l" ]
then
s2l
if [[ $QUIET == 0 && $RETURN == 0 ]]; \
then echo "Server to local simulation ok"; fi
exit $RETURN
fi
if [ $CHECKED == "l2s" ]
then
l2s
if [[ $QUIET == 0 && $RETURN == 0 ]]; \
then echo "Local to server simulation ok"; fi
exit $RETURN
fi
if [ $CHECKED == "s2s" ]
then
s2s
if [[ $QUIET == 0 && $RETURN == 0 ]]; \
then echo "Server to server simulation ok"; fi
exit $RETURN
fi
540
550
fi
superexecute.sh
#!/bin/bash
source "./functions.sh"
# INITIALIZATION
SYNC TRACES SCRIPT="./scripts/utils/sync-traces.sh" # path of sync-traces script
SCRIPTS PATH="./scripts"
JOBQUEUE="traces/000000-jobqueue"
REPSERVER="mauirep.fisica.unipg.it"
CLIENTNAME="randomize"
10
if [ $CLIENTNAME == "randomize" ]
then
TEMP=‘echo $USER $HOSTNAME $RANDOM | md5sum | cut −d" " −f1‘
CLIENTNAME=${TEMP:24}
fi
while [ 1 ]
do
# Lock
$SCRIPTS PATH/manager/client.py −l −c $CLIENTNAME
20
NEXTREADY=‘$SCRIPTS PATH/utils/ls−feat.sh −t $JOBQUEUE −f status \
−c ready −n 1‘
if [ "a$NEXTREADY" != "a" ]
then
130
$SCRIPTS PATH/utils/sync−traces.sh −q −U −f status −c ready \
−t $NEXTREADY −s $REPSERVER
TYPE=‘$SCRIPTS PATH/utils/sync−traces.sh −q −R −f type \
30
−t $NEXTREADY −s $REPSERVER‘
if [ "a$TYPE" == "aparallel" ]
then
$SCRIPTS PATH/utils/sync−traces.sh −q −S −f status −c running \
−t $NEXTREADY −s $REPSERVER
else
$SCRIPTS PATH/utils/sync−traces.sh −q −S −f status −c taken \
−t $NEXTREADY −s $REPSERVER
fi
40
$SCRIPTS PATH/utils/sync−traces.sh −q −g −t $NEXTREADY −s $REPSERVER
fi
# Unlock
$SCRIPTS PATH/manager/client.py −u −c $CLIENTNAME
# Execute the given job
if [ "a$NEXTREADY" != "a" ]
then
50
echo
echo "First execution of $NEXTREADY"
$NEXTREADY/command.sh >> $NEXTREADY/$CLIENTNAME.o 2> \
$NEXTREADY/$CLIENTNAME.e
echo "Execution of $NEXTREADY done"
echo
if [ "a$TYPE" == "aparallel" ]
then
60
while [ 1 ]
do
# Lock
$SCRIPTS PATH/manager/client.py −l −c $CLIENTNAME
$SCRIPTS PATH/utils/sync−traces.sh −q −U −f status −c running \
−t $NEXTREADY −s $REPSERVER
$SCRIPTS PATH/utils/sync−traces.sh −q −S −f status −c exitwait \
−t $NEXTREADY −s $REPSERVER
70
RUNNINGPROC=1
RUNNINGPROC=‘$SCRIPTS PATH/utils/sync−traces.sh −q −R −f crunning \
−t $NEXTREADY −s $REPSERVER | wc −l‘
if [ $RUNNINGPROC == 0 ]
then
break
else
# UnLock
80
$SCRIPTS PATH/manager/client.py −u −c $CLIENTNAME
fi
sleep 5
131
done
$SCRIPTS PATH/utils/sync−traces.sh −q −U −f status −c exitwait \
−t $NEXTREADY −s $REPSERVER
else
# Lock
$SCRIPTS PATH/manager/client.py −l −c $CLIENTNAME
90
$SCRIPTS PATH/utils/sync−traces.sh −q −U −f status −c taken \
−t $NEXTREADY −s $REPSERVER
fi
$SCRIPTS PATH/utils/sync−traces.sh −q −S −f status −c ok \
−t $NEXTREADY −s $REPSERVER
$SCRIPTS PATH/utils/sync−traces.sh −q −p −t $NEXTREADY −s $REPSERVER
$SCRIPTS PATH/utils/sync−traces.sh −q −r −t $NEXTREADY
100
# Unlock
$SCRIPTS PATH/manager/client.py −u −c $CLIENTNAME
fi
# Lock
$SCRIPTS PATH/manager/client.py −l −c $CLIENTNAME
NEXTRUNNING=‘$SCRIPTS PATH/utils/ls−feat.sh −t $JOBQUEUE −f status \
−c running −n 1‘
110
if [ "a$NEXTRUNNING" != "a" ]
then
$SCRIPTS PATH/utils/sync−traces.sh −q −S −f crunning −c $CLIENTNAME \
−t $NEXTRUNNING −s $REPSERVER
$SCRIPTS PATH/utils/sync−traces.sh −q −g −t $NEXTRUNNING −s $REPSERVER
fi
# Unlock
120
$SCRIPTS PATH/manager/client.py −u −c $CLIENTNAME
if [ "a$NEXTRUNNING" != "a" ]
then
echo
echo "Collaborating with $NEXTRUNNING"
$NEXTRUNNING/command.sh >> $NEXTRUNNING/$CLIENTNAME.o 2> \
$NEXTRUNNING/$CLIENTNAME.e
echo "Stop collaborating with $NEXTRUNNING"
echo
130
# Lock
$SCRIPTS PATH/manager/client.py −l −c $CLIENTNAME
$SCRIPTS PATH/utils/sync−traces.sh −q −U −f crunning −c $CLIENTNAME \
−t $NEXTRUNNING −s $REPSERVER
# Unlock
$SCRIPTS PATH/manager/client.py −u −c $CLIENTNAME
140
132
$SCRIPTS PATH/utils/sync−traces.sh −q −p −t $NEXTRUNNING −s $REPSERVER
$SCRIPTS PATH/utils/sync−traces.sh −q −r −t $NEXTRUNNING
fi
# rpmpollintervall
sleep 10
done
sync-traces.sh
#!/bin/bash
# NOTE: version 1.3.1
# CHANGES: 1.3.1: better usage output
#
1.3: -n option to NOT sync subdirectories
# 1.2: -d option to delete on sync
# 1.1: rsync with –exclude=“.*”
#
features files on server are now hidden files
# 1.0a: added check on target existance before get, if target does not exist exit with 1
RSYNC USER="maui" # rsync remote user
RSYNC DOMAIN="maui" # rsync remote domain
RSYNC DIR="/rep/" # rsync remote directory in $RSYNC DOMAIN
ERROR CODE=39 # Default error code
HELP="Usage:\t$0 [-g|-p] [-d] [-n] [-q] -t trace -s server [-h]\n
\t$0 -e [-q] -t trace -s server [-h]\n
\t$0 -r [-q] -t trace [-h]\n
\t$0 [-S|-U] [-q] -c char -f feat -t trace -s server [-h]\n
\t$0 -R [-q] -f feat -t trace -s server [-h]\n
\t$0 -A [-q] -t trace -s server [-h]\n\n
10
20
Perform various tasks relative to traces syncronization.\n\n
-s server\t\tremote traces server.\n
-t target\t\tname of the trace.\n\n
-g\t\t\tget, download remote trace from server.\n
-p\t\t\tput, upload trace to the remote server.\n\n
-d\t\t\tdelete on sync, files not present on source will be removed from destination.\n
-n\t\t\tdo NOT sync subdirectories.\n\n
30
-r\t\t\tremove, delete a local trace.\n\n
-e\t\t\texists, check if target exists on remote server, -s, -t required.\n\n
-q\t\t\tquiet, output only error messages.\n\n
-f feature\t\tfeature to set, unset or read.\n
-c characteristic\tvalue of the feature to set, unset.\n
-S\t\t\tset, set a characteristic of a feature, -f, -c, -s, -t required.\n
-U\t\t\tunset, remove a characteristic of a feature, -f, -c, -s, -t required.\n
-R\t\t\tread, report the characteristics of a feature, -f, -c, -s, -t required.\n\n
-A\t\t\tread all, report all the characteristics of all the features, -s, -t required.\n\n
133
40
-h\t\t\tthis help.\n\n
Usage examples:\n
to get target from server: $0 -g -t target -s server\n
50
to put target in server: $0 -p -t target -s server\n
to remove a local target: $0 -r -t target\n
to check existance of a target on server: $0 -e -t target -s server\n
to set a characteristc of a feature: $0 -S -c char -f feat -t target -s server\n
to unset a characteristc of a feature: $0 -U -c char -f feat -t target -s server\n
to read the characteristcs of a feature: $0 -R -f feat -t target -s server\n
to read the characteristcs of all the features: $0 -A -t target -s server\n"
NO ARGS=0 # Var initialization
GET VAR=0
60
PUT VAR=0
CLEAN=0
EXISTS=0
QUIET=0
SERVER VAR=0
TARGET VAR=0
FEATURE POP=0
70
FEATURE PUSH=0
FEATURE READ=0
FEATURE READALL=0
CHAR VAR=0
FEAT VAR=0
DELETING=0
FULLTREE=1
RETURN=0
FEATURE=0
80
STATUS=0
# checkinput, check input var, reporting “bad” or a code for each command
checkinput() {
CHECKED="bad"
if (( $GET VAR + $SERVER VAR + $TARGET VAR == 3 )) && \
(( $PUT VAR + $CLEAN + $EXISTS + $FEATURE PUSH + $FEATURE POP + \
$FEATURE READ + $FEATURE READALL + $CHAR VAR + $FEAT VAR == 0 ))
then
# program will make a “get target from server”
90
CHECKED="get"
fi
if (( $PUT VAR + $SERVER VAR + $TARGET VAR == 3 )) && \
(( $GET VAR + $CLEAN + $EXISTS + $FEATURE PUSH + $FEATURE POP + \
$FEATURE READ + $FEATURE READALL + $CHAR VAR + $FEAT VAR == 0 ))
then
# program will make a “put target on server”
CHECKED="put"
fi
if (( $CLEAN + $TARGET VAR == 2 )) && (( $PUT VAR + $GET VAR + \
$SERVER VAR + $EXISTS + $FEATURE PUSH + $FEATURE POP + \
$FEATURE READ + $FEATURE READALL + $CHAR VAR + $FEAT VAR == 0 ))
then
134
100
# program will make a “clean local target”
CHECKED="clr"
fi
if (( $EXISTS + $SERVER VAR + $TARGET VAR == 3 )) && \
(( $PUT VAR + $GET VAR + $CLEAN + $FEATURE PUSH + $FEATURE POP + \
$FEATURE READ + $FEATURE READALL + $CHAR VAR + $FEAT VAR == 0 ))
then
110
# program will make a “exists remote target?”
CHECKED="exist"
fi
if (( $FEATURE PUSH + $SERVER VAR + $TARGET VAR + $CHAR VAR + \
$FEAT VAR == 5 )) && (( $PUT VAR + $GET VAR + $CLEAN + $EXISTS + \
$FEATURE POP + $FEATURE READ + $FEATURE READALL == 0 ))
then
# program will make a “set feature”
CHECKED="set"
fi
120
if (( $FEATURE POP + $SERVER VAR + $TARGET VAR + $CHAR VAR + \
$FEAT VAR == 5 )) && (( $PUT VAR + $GET VAR + $CLEAN + $EXISTS + \
$FEATURE PUSH + $FEATURE READ + $FEATURE READALL == 0 ))
then
# program will make a “unset feature”
CHECKED="unset"
fi
if (( $FEATURE READ + $SERVER VAR + $TARGET VAR + \
$FEAT VAR == 4 )) && (( $PUT VAR + $GET VAR + $CLEAN + $EXISTS + \
$FEATURE PUSH + $FEATURE POP + $FEATURE READALL + $CHAR VAR == 0 ))
130
then
# program will make a “read feature”
CHECKED="read"
fi
if (( $FEATURE READALL + $SERVER VAR + $TARGET VAR == 3 )) && \
(( $PUT VAR + $GET VAR + $CLEAN + $EXISTS + $FEATURE PUSH + \
$FEATURE POP + $FEATURE READ + $CHAR VAR + $FEAT VAR == 0 ))
then
# program will make a “read all features”
CHECKED="readall"
140
fi
}
# check, return if a file/dir exists on remote server
check() {
if [ −z "$1" ] # parameter #1 of zero length or no parameter passed.
then
ISTHERE="error"
else
ISTHERE=0
150
ssh −− $RSYNC USER@$SERVER URL ls −− $RSYNC DIR/$1&>/dev/null
RETURN=$?
if [ $RETURN == 0 ]
then
ISTHERE="yes"
else
if [ $RETURN == 2 ]
then
ISTHERE="no"
else
160
135
ISTHERE="error"
fi
fi
fi
}
read() {
READ RETURN=""
if [ −z "$1" ] # parameter #1 of zero length or no parameter passed.
then
170
READ RETURN=""
else
FEATURE=$1
check $TARGET
if [ $ISTHERE == "yes" ] # $TARGET exists on $SERVER URL
then
READ RETURN=‘ssh −− $RSYNC USER@$SERVER URL cat −− \
$RSYNC DIR/$TARGET/.$FEATURE−status.lock 2> /dev/null‘
else
READ RETURN=""
180
fi
fi
}
read all() {
READ RETURN=""
check $TARGET
if [ $ISTHERE == "yes" ] # $TARGET exists on $SERVER URL
then
# return content of all .lock files on $TARGET
190
READ RETURN=$(ssh −− $RSYNC USER@$SERVER URL "for i in \
\‘ls $RSYNC_DIR/$TARGET/.*.lock\‘; do echo \$i\‘cat \$i\‘ | \
sed -e ’s/-status\.lock/: /’ | sed -e ’s/.*$TARGET.//’ | \
sed -e ’s/[.]//g’; done")
else
READ RETURN=""
fi
}
200
# push, set $FEATURE as $STATUS in $TARGET on $SERVER URL
push() {
PUSH RETURN=0
if [ −z "$1" ] | | [ −z "$2" ] # parameter #1 or #2 of zero length or no parameter passed.
then
PUSH RETURN=1
else
FEATURE=$1
STATUS=$2
check $TARGET
210
if [ $ISTHERE == "yes" ] # $TARGET exists on $SERVER URL
then
ssh −− $RSYNC USER@$SERVER URL "grep -- \
$STATUS $RSYNC_DIR/$TARGET/.$FEATURE-status.lock &> /dev/null"
RETURN=$?
if [ $RETURN == 0 ] # $FEATURE is already on $STATUS
then
136
PUSH RETURN=0
else
if [ $RETURN == 1 ] | | [ $RETURN == 2 ] # $STATUS missing (1) \
220
or $FEATURE−status.lock missing (2)
then
ssh −− $RSYNC USER@$SERVER URL "echo -e $STATUS >> \
$RSYNC_DIR/$TARGET/.$FEATURE-status.lock 2> /dev/null"
RETURN=$?
if [ $RETURN == 0 ]
then
PUSH RETURN=0
else
PUSH RETURN=1
230
fi
else
# grep or comunication error
PUSH RETURN=1
fi
fi
else
# connection error OR $TARGET missing on $SERVER URL
if [ $ISTHERE == "no" ]
then
240
# there is no $TARGET on $SERVER URL.
PUSH RETURN=1
else
# a connection error maybe?
PUSH RETURN=1
fi
fi
fi
}
250
# pop, remove a $STATUS of a $FEATURE in $TARGET on $SERVER URL
pop() {
POP RETURN=0
if [ −z "$1" ] | | [ −z "$2" ] # parameter #1 or #2 of zero length or no parameter passed.
then
POP RETURN=1
else
FEATURE=$1
STATUS=$2
check $TARGET
260
if [ $ISTHERE == "yes" ] # $TARGET exists on $SERVER URL
then
check $TARGET/.$FEATURE−status.lock
if [ $ISTHERE == "yes" ] # $TARGET/.$FEATURE-status.lock exists \
on $SERVER URL
then
read $FEATURE $STATUS
if [ READ RETURN == "" ]
then
POP RETURN=0 # no action to perform
else
ISEMPTY=‘ssh −− $RSYNC USER@$SERVER URL wc −l \
$RSYNC DIR/$TARGET/.$FEATURE−status.lock |cut −d " " −f 1‘
if [ $ISEMPTY == "1" ]
137
270
then # delete $FEATURE-status.lock
ssh −− $RSYNC USER@$SERVER URL rm −f −− \
$RSYNC DIR/$TARGET/.$FEATURE−status.lock
RETURN=$?
if [ $RETURN == 0 ]
then
280
POP RETURN=0
else
POP RETURN=1
fi
else # create .tmp
ssh −− $RSYNC USER@$SERVER URL "egrep -v -- \
"^$STATUS$" $RSYNC_DIR/$TARGET/.$FEATURE-status.lock > \
$RSYNC_DIR/$TARGET/.$FEATURE-status.tmp"
RETURN=$?
if [ $RETURN == 0 ]
290
then # rm .lock
ssh −− $RSYNC USER@$SERVER URL rm −f −− \
$RSYNC DIR/$TARGET/.$FEATURE−status.lock
RETURN=$?
if [ $RETURN == 0 ]
then # move .tmp in .lock
ssh −− $RSYNC USER@$SERVER URL "mv -- \
$RSYNC_DIR/$TARGET/.$FEATURE-status.tmp \
$RSYNC_DIR/$TARGET/.$FEATURE-status.lock"
RETURN=$?
300
if [ $RETURN == 0 ]
then
POP RETURN=0
else
POP RETURN=1
fi
else
POP RETURN=1
fi
else
310
POP RETURN=1
fi
fi
fi
else
if [ $ISTHERE == "no" ] # no action to perform
then
POP RETURN=0
else
POP RETURN=1
320
fi
fi
else
if [ $ISTHERE == "no" ] # no action to perform
then
POP RETURN=0
else
POP RETURN=1
fi
fi
330
fi
138
}
if [ $# -eq “$NO ARGS” ] # Script invoked with no command-line args.
then
echo −e $HELP
exit $ERROR CODE # Exit and explain usage, if no argument(s) given.
fi
while getopts "s:t:gpluvrqef:c:SRAUdhn" Option
340
# Command arguments:
# -s server
# -t target
# -g, -p, get, put
## -l lock
## -u unlock
## -v verify lock
# -r remove
# -q quiet
# -e exists
350
# -R read feature
# -A read all feature
# -S set feature
# -U unset feature
# -d delete on sync
# -n DO NOT sync subdirectory
do
case $Option in
s ) SERVER VAR=1
SERVER URL=$OPTARG;;
360
t ) TARGET VAR=1
LOCAL PATH=$OPTARG
TARGET=$OPTARG;;
g ) GET VAR=1;;
p ) PUT VAR=1;;
r ) CLEAN=1;;
q ) QUIET=1;;
e ) EXISTS=1;;
f ) FEAT VAR=1
FEATURE=$OPTARG;;
370
c ) CHAR VAR=1
CHAR=$OPTARG;;
S ) FEATURE PUSH=1;;
R ) FEATURE READ=1;;
A ) FEATURE READALL=1;;
U ) FEATURE POP=1;;
d ) DELETING=1;;
n ) FULLTREE=0;;
h ) echo −e $HELP
exit 1;;
380
* ) echo −e $HELP
exit 1;;
esac
done
checkinput
if [ $CHECKED == "bad" ]
then
139
echo "Error: bad parameters"
echo −e $HELP
390
exit 1
else
if [ $CHECKED == "get" ]
then
# get $TARGET trace from the remote rsync server $SERVER URL.
# does $TARGET exists?
check $TARGET
if [ $ISTHERE == "yes" ]
then
400
# no local dir $TARGET? we create it.
if [ ! −d $LOCAL PATH ]
then
mkdir −p −− $LOCAL PATH/
RETURN=$?
fi
if [ $RETURN == 0 ]
then
if [ $DELETING == 1 ]
then
410
if [ $FULLTREE == 1 ]
then
# download $TARGET with –del, -r options
rsync −rlpt −−exclude=".*" −−del −q −e ssh −− \
$RSYNC USER@$SERVER URL::$RSYNC DOMAIN/$LOCAL PATH/ \
$LOCAL PATH/
RETURN=$?
else
# download $TARGET with –del option, without -r
rsync −lpt −−exclude=".*" −−del −q −e ssh −− \
420
$RSYNC USER@$SERVER URL::$RSYNC DOMAIN/$LOCAL PATH/* \
$LOCAL PATH/
RETURN=$?
fi
else
if [ $FULLTREE == 1 ]
then
# download $TARGET with -r option
rsync −rlpt −−exclude=".*" −q −e ssh −− \
$RSYNC USER@$SERVER URL::$RSYNC DOMAIN/$LOCAL PATH/ \
430
$LOCAL PATH/
RETURN=$?
else
# download $TARGET without -r option
rsync −lpt −−exclude=".*" −q −e ssh −− \
$RSYNC USER@$SERVER URL::$RSYNC DOMAIN/$LOCAL PATH/* \
$LOCAL PATH/
RETURN=$?
fi
fi
440
if [ $RETURN != 0 ]
then
ERROR CODE=$RETURN
echo "rsync error: $RETURN"
exit $RETURN
140
fi
if [ $QUIET == 0 ]; then echo "all seems ok"; fi
ERROR CODE=$RETURN
exit $ERROR CODE
else
450
# something wrong with mkdir
echo "error making local directory: $RETURN"
exit $RETURN
fi
else
if [ $ISTHERE == "no" ]
then
if [ $QUIET == 0 ]; then echo "$TARGET does not exists on $SERVER_URL"; fi
exit 1
else
460
echo "ssh error?"
exit 1
fi
fi
fi
if [ $CHECKED == "put" ]
then
# put $TARGET trace on the remote rsync server $SERVER URL.
# first we test if there is $TARGET on $SERVER URL.
470
check $LOCAL PATH
if [ $ISTHERE != "yes" ]
then
# a connection error OR $TARGET is missing on $SERVER URL
if [ $ISTHERE == "no" ]
then
# if there is no $TARGET on $SERVER URL we make it.
ssh −− $RSYNC USER@$SERVER URL mkdir −p −− \
$RSYNC DIR/$LOCAL PATH
RETURN=$?
480
if [ $RETURN != 0 ]
then
# or not :)
echo "error making remote dir $TARGET: $RETURN"
exit $RETURN
fi
else
# probably there is a connection error.
echo "ssh error: $RETURN"
exit 1
490
fi
fi
# finally we rsync $TARGET.
if [ $DELETING == 1 ]
then
# rsync $TARGET with –del option
rsync −rlpt −−exclude=".*" −−del −q −e ssh \
$LOCAL PATH/ $RSYNC USER@$SERVER URL::$RSYNC DOMAIN/\
$LOCAL PATH/
RETURN=$?
500
else
# rsync $TARGET $TARGET
141
rsync −rlpt −−exclude=".*" −q −e ssh \
$LOCAL PATH/ $RSYNC USER@$SERVER URL::$RSYNC DOMAIN/\
$LOCAL PATH/
RETURN=$?
fi
if [ $DELETING == 1 ]
then
510
if [ $FULLTREE == 1 ]
then
# rsync $TARGET with –del, -r options
rsync −rlpt −−exclude=".*" −−del −q −e ssh \
$LOCAL PATH/ $RSYNC USER@$SERVER URL::$RSYNC DOMAIN/\
$LOCAL PATH/
RETURN=$?
else
# rsync $TARGET with –del option, without -r
rsync −lpt −−exclude=".*" −−del −q −e ssh \
520
$LOCAL PATH/* $RSYNC USER@$SERVER URL::$RSYNC DOMAIN/\
$LOCAL PATH/
RETURN=$?
fi
else
if [ $FULLTREE == 1 ]
then
# rsync $TARGET with -r option
rsync −rlpt −−exclude=".*" −q −e ssh \
$LOCAL PATH/ $RSYNC USER@$SERVER URL::$RSYNC DOMAIN/\
530
$LOCAL PATH/
RETURN=$?
else
# rsync $TARGET without -r option
rsync −lpt −−exclude=".*" −q −e ssh \
$LOCAL PATH/* $RSYNC USER@$SERVER URL::$RSYNC DOMAIN/\
$LOCAL PATH/
RETURN=$?
fi
fi
540
if [ $RETURN != 0 ]
then
echo "rsync error: $RETURN"
exit $RETURN
fi
if [ $QUIET == 0 ]; then echo "all seems ok"; fi
ERROR CODE=$RETURN
exit $ERROR CODE
fi
550
if [ $CHECKED == "clr" ]
then
# clean a local $TARGET trace.
rm −rf −− $LOCAL PATH/
RETURN=$?
if [ $RETURN != 0 ]
then
echo "rm error: $RETURN"
142
exit $RETURN
560
else
if [ $QUIET == 0 ]; then echo "all seems ok"; fi
ERROR CODE=$RETURN
exit $ERROR CODE
fi
fi
if [ $CHECKED == "exist" ]
then
check $TARGET
570
if [ $ISTHERE == "yes" ]
then
if [ $QUIET == 0 ]; then echo "$TARGET exists on $SERVER_URL"; fi
exit 0
else
if [ $ISTHERE == "no" ]
then
if [ $QUIET == 0 ]; then echo "$TARGET does not exists on $SERVER_URL"; fi
exit 2
else
580
echo "ssh error?"
exit 1
fi
fi
fi
if [ $CHECKED == "set" ]
then
push $FEATURE $CHAR
if [ $PUSH RETURN == 0 ]
590
then
if [ $QUIET == 0 ]; then echo "all seems ok"; fi
exit 0
else
echo "Set feature error"
exit 1
fi
fi
if [ $CHECKED == "unset" ]
600
then
pop $FEATURE $CHAR
if [ $POP RETURN == 0 ]
then
if [ $QUIET == 0 ]; then echo "all seems ok"; fi
exit 0
else
echo "Unset feature errorr"
exit 1
fi
610
fi
if [ $CHECKED == "read" ]
then
read $FEATURE
if [ "$READ_RETURN" != "" ]; then echo "$READ_RETURN"; fi
143
exit 0
fi
if [ $CHECKED == "readall" ]
then
read all $FEATURE
if [ "$READ_RETURN" != "" ]; then echo "$READ_RETURN"; fi
exit 0
fi
620
fi
visualize.sh
#!/bin/bash
# NOTE: version 0.2
# CHANGES: 0.2: bugfix release
# plug-ins
timeliner="./branch/trace-timeliner.pl --analyzpath ./scripts"\
# –analyzpath ./scripts = path of workload-analyzer
# initialization
DOWNLOADER="./scripts/utils/sync-traces.sh"
SERVER URL=""
TARGET=""
KEEP VAR="0"
PLUGIN="timeliner"
PAR="" # plugin parameters
10
# defaults
ERROR CODE=39 # default error code
HELP="Usage:\t$0 [-k] [-p plug-in] [-s server] -t trace [-h] [plug-in options]\n
Trace visualizer.\n\n
20
-k keep trace after download and visualization.\n\n
-p visualizer plug-in. [default timeliner].\n\n
-s server\t\tremote traces server.\n
-t trace\t\tname of the trace.\n\n
30
-h this help.\n\n
Other options will be passed to the plug-in.\n\n
Usage examples:\n
to visualize a local trace: $0 -t trace [-p timeliner] [plug-in options]\n
to visualize a remote trace: $0 -s server -t trace [-p timeliner] [plug-in options]\n
to visualize and keep a local copy of a remote trace: $0 -k -s server \
-t trace [-p timeliner] [plug-in options]\n
"
40
if [ $# -eq 0 ] # script invoked with no command-line args
then
144
echo −e $HELP
exit $ERROR CODE # exit and explain usage, if no argument(s) given
fi
while getopts ":s:t:p:kh" Option
# Command arguments:
# -s server
# -t target
50
# -k keep target, do not erase it from disk
# -p visualizer plug-in to use
do
case $Option in
s ) SERVER URL=$OPTARG;;
t ) TARGET=$OPTARG;;
#TARGET=‘basename $OPTARG‘;;
k ) KEEP VAR=1;;
f ) PLUGIN=$OPTARG;;
h ) echo −e $HELP
60
exit 1;;
\?) ;;
esac
done
# copy plugin parameter in $PAR (everything except visualize.sh arguments)
STATUS="ok"
for i in $*
do
if [[ "$STATUS" == "ok" ]]
70
then
if [[ "$i" == "-s" ]]
then
STATUS="miss" # to bypass next argument also
elif [[ "$i" == "-t" ]]
then
: # nothing to do to, next argument will be passed to the plugin as is \
(hopefully a directory)
elif [[ "$i" == "-p" ]]
then
80
STATUS="miss" # to bypass next argument also
elif [[ "$i" == "-k" ]]
then
:
# nothing to do
else
PAR="$PAR $i"
fi
else
# current argument bypassed
STATUS="ok"
fi
90
done
RETURN=0
eval COMMAND=\$$PLUGIN
if [[ "$SERVER_URL" == "" ]] && [[ "$TARGET" != "" ]] && \
[[ "$KEEP_VAR" == "0" ]] # local trace
then
# unzip
145
for j in ‘tree −if $TARGET|egrep "unscaled.gz$"‘
100
do
gzip −d $j
done
RETURN=$?
if [[ $RETURN != 0 ]]
then
echo "$TARGET DECOMPRESSING ERROR: $RETURN"
exit $RETURN
else
echo "unzip fase ok"
110
# visualize with plug-in
$COMMAND $PAR
RETURN=$?
if [[ $RETURN != 0 ]]
then
echo "$COMMAND ERROR: $RETURN"
exit $RETURN
fi
# all seems ok
echo "plug-in launched"
120
fi
elif [[ "$SERVER_URL" != "" ]] && [[ "$TARGET" != "" ]] && \
[[ "$KEEP_VAR" == "0" ]] # remote trace: download, visualize, erase
then
# download
$DOWNLOADER −g −t $TARGET −s $SERVER URL
RETURN=$?
if [[ $RETURN != 0 ]]
then
echo "$TARGET DOWNLOADING ERROR: $RETURN"
130
exit $RETURN
else
# unzip
for j in ‘tree −if $TARGET|egrep "unscaled.gz$"‘
do
gzip −d $j
done
RETURN=$?
if [[ $RETURN != 0 ]]
then
140
echo "$TARGET DECOMPRESSING ERROR: $RETURN"
exit $RETURN
else
echo "unzip fase ok"
# visualize with plug-in
$COMMAND $PAR
RETURN=$?
if [[ $RETURN != 0 ]]
then
echo "$COMMAND ERROR: $RETURN"
150
echo "$TARGET state may be incorrect, please check and remove"
exit $RETURN
else
# all seems ok
echo "plug-in launched"
# remove trace
146
rm −rI −− $TARGET
RETURN=$?
if [[ $RETURN != 0 ]]
then
160
echo "DELETING $TARGET ERROR: $RETURN"
echo "$TARGET state may be incorrect, please check and remove"
exit $RETURN
else
echo "$TARGET deleted as requested"
fi
fi
fi
fi
elif [[ "$SERVER_URL" != "" ]] && [[ "$TARGET" != "" ]] && \
170
[[ "$KEEP_VAR" == "1" ]] # remote trace: download, visualize
then
# download
$DOWNLOADER −g −t $TARGET −s $SERVER URL
RETURN=$?
if [[ $RETURN != 0 ]]
then
echo "$TARGET DOWNLOADING ERROR: $RETURN"
exit $RETURN
else
180
# unzip
for j in ‘tree −if $TARGET|egrep "unscaled.gz$"‘
do
gzip −d $j
done
RETURN=$?
if [[ $RETURN != 0 ]]
then
echo "$TARGET DECOMPRESSING ERROR: $RETURN"
exit $RETURN
190
else
echo "unzip fase ok"
# visualize with plug-in
$COMMAND $PAR
RETURN=$?
if [[ $RETURN != 0 ]]
then
echo "$COMMAND ERROR: $RETURN"
exit $RETURN
fi
200
# all seems ok
echo "plug-in launched"
fi
fi
else
echo −e "ERROR: bad arguments\n"
echo −e $HELP
fi
210
147
148
Bibliografia
[1] Maui Administrator’s Guide, maui 3.2, may 16 edizione, Maggio 2008.
[2] I. Bird, K. Bos, N. Brook, D. Duellmann, C. Eck, I. Fisk, D. Foster, B. Gibbard,
M. Girone, C. Grandi, e altri. Lhc computing grid technical design report.
[3] F. Cantini, L. Servoli, e M. Mariotti. Studio delle prestazioni di un batch system
basato su torque/maui, 2007.
[4] J. Dean e S. Ghemawat. Mapreduce: Simplified data processing on large clusters.
COMMUNICATIONS OF THE ACM, 51(1):107, 2008.
[5] G. Dozsa, M. Farreras, P. Luk, e T. Spelce. xlupc/bluegene class ii submission to
the hpc challenge award competition. 2006.
[6] H. W. Meuer. The top500 project: Looking back over 15 years of supercomputing
experience. Informatik Spektrum, 31:203–222, 2008.
[7] E. Moore Gordon.
Cramming more components onto integrated circuits.
Electronics, 38(8):114–117, 1965.
[8] R. Poli, W. B. Langdon, e N. F. McPhee. A Field Guide to Genetic Programming.
Lulu Press, 2008.
149
Scarica

Sviluppo di uno strumento per l`analisi e l