diff options
Diffstat (limited to 'src')
35 files changed, 1805 insertions, 0 deletions
diff --git a/src/g5k/README.md b/src/g5k/README.md new file mode 100644 index 0000000..15969f8 --- /dev/null +++ b/src/g5k/README.md @@ -0,0 +1,12 @@ +# G5K Simulation Scripts + +- client.py is run by utils.sh +- setup-mysql.sql used by utils.sh to configure server database +- utils.sh contains functionnality to: + - Subscribe in G5K + - Kill all VMs on the subscribed nodes + - Inspect the database + - Purge the database +- run-sim.sh use utils.sh to run all the simulations +- record-energy.sh fetch energy csv files from G5K +- energyFromLogs.sh use record-energy.sh to fetch energy data using run-sim.sh logs diff --git a/src/g5k/clients.py b/src/g5k/clients.py new file mode 100755 index 0000000..db40996 --- /dev/null +++ b/src/g5k/clients.py @@ -0,0 +1,48 @@ +#!/usr/bin/python +from __future__ import division +import os,sys,random, time,datetime +from subprocess import Popen + +# Check script argument +if len(sys.argv) != 6: + print("Usage: "+sys.argv[0]+" <mysqlServerIp> <nbSensors> <nbSensorsFactor> <requestPerSensor> <sendInterval>") + exit(1) + +# Init script parameters +serverIp=sys.argv[1] +nbSensors=int(sys.argv[2]) +nbSensorsFactor=int(sys.argv[3]) +effectiveNbSensors=nbSensors*nbSensorsFactor +requestPerSensor=int(sys.argv[4]) +sendInterval=int(sys.argv[5]) +avgSiteTemp=list() +for i in range(0,effectiveNbSensors): + avgSiteTemp.append(random.randint(-10,30)) + + +def insert(sensorId, value): + """ Send value of sensorId into the database """ + stamp=int(time.mktime(datetime.datetime.today().timetuple())) + insertCMD = "mysql -u user --password=mysql --host="+serverIp+" experiment -e" + insertCMD=insertCMD.split() + insertCMD.append("INSERT INTO temperature (id,stamp,val) VALUES("+str(sensorId)+","+str(stamp)+","+str(value)+");") + Popen(insertCMD) # Run command asynchronously + +def send(): + """ Send temperature of each sensors into the database """ + for i in range(0,effectiveNbSensors): + insert(i,random.gauss(avgSiteTemp[i], 3)) + + +# Print infos +print("Launching clients with:") +print(" - Mysql Server IP {:>20}".format(serverIp)) +print(" - Number of sensors {:>18}".format(effectiveNbSensors)) +print(" - Number of request per sensor {:>7}".format(effectiveNbSensors)) + +# Send data +for i in range(0, requestPerSensor): + send() + time.sleep(sendInterval) # We assume send() take no time + + diff --git a/src/g5k/energyFromLogs.sh b/src/g5k/energyFromLogs.sh new file mode 100755 index 0000000..0336f03 --- /dev/null +++ b/src/g5k/energyFromLogs.sh @@ -0,0 +1,26 @@ +#!/bin/bash + + +logFile="$(dirname $(readlink -f $0))"/simLogs.txt + + +getValue () { + line=$(echo "$1" | grep "Simulation para"|sed "s/Simulation parameters: //g") + key=$2 + echo "$line"|awk 'BEGIN{RS=" ";FS=":"}"'$key'"==$1{gsub("\n","",$0);print $2}' +} + +IFS=$'\n' +for cmd in $(cat $logFile|grep "Simulation parameters") +do + nodeName=$(getValue $cmd serverNodeName) + from=$(getValue $cmd simStart) + to=$(getValue $cmd simEnd) + vmSize=$(getValue $cmd vmSize) + nbSensors=$(getValue $cmd nbSensors) + simKey=$(getValue $cmd simKey) + delayStart=$(getValue $cmd delayStart) + ./recordEnergy.sh nova $nodeName $from $to "${simKey}_${vmSize}VMSIZE_${nbSensors}NBSENSORS_${from}${to}.csv" + ./recordEnergy.sh nova $nodeName $delayStart $from "${simKey}_${vmSize}VMSIZE_${nbSensors}NBSENSORS_${from}${to}_IDLE.csv" +done + diff --git a/src/g5k/recordEnergy.sh b/src/g5k/recordEnergy.sh new file mode 100755 index 0000000..c345136 --- /dev/null +++ b/src/g5k/recordEnergy.sh @@ -0,0 +1,42 @@ +#!/bin/bash + +# Parse argument +[ $# != 5 ] && { echo "Usage: $0 <cluster-name> <node-name> <from> <to> <output-file>"; exit 1; } + +# Init arguments +clusterName="$1" +nodeName="$2" +outputFile="$5" +wattmeter=$(curl -s https://api.grid5000.fr/stable/sites/lyon/clusters/${clusterName}/nodes/${nodeName}.json | jq -r '.sensors.power.via.pdu[0].uid') +port=$(curl -s https://api.grid5000.fr/stable/sites/lyon/pdus/${wattmeter}.json | jq -r '.ports|to_entries|map(select(.value=="'${nodeName}'"))[0].key') +energyEntry=$(( 5 + port )) # Define the entry in the CSV that correspond to the correct energy value + +if [ -z $wattmeter ] || [ -z $port ] +then + echo -ne "\nCannot find energy informations (wattmeter/port) for node $nodeName\n" + echo -ne "\nCheck the node name (do not use hostname! only node name ex: nova-7)\n" + exit 1 +fi + +echo "Node ${nodeName} is connected on wattmeter ${wattmeter} on port ${port}" + +# Fetching energy and save in csv format +from=$(date -d "@$3" "+%s") +to=$(date -d "@$4" "+%s") +echo "ts,energy" > $outputFile # Write CSV header +for time in $(seq $from 3600 $to) +do + # We need gz extension if it is not the current hour + [ $(date -d "@$time" "+%Y-%m-%dT%H") != $(date "+%Y-%m-%dT%H") ] && ext='.gz' || ext='' + powerFilename=$(date -d "@$time" "+power.csv.%Y-%m-%dT%H${ext}") + url="http://wattmetre.lyon.grid5000.fr/data/${wattmeter}-log/${powerFilename}" + echo "- Fetching logs from ${url}" + + # Fetch logs data + [ ! -z $ext ] && csvContent=$(curl -s "${url}" | zcat) || csvContent=$(curl -s "${url}") + + # Parse data and extract the right values in csv format + toSave=$(echo "$csvContent" | awk -F, 'int($3)>='$from'&& int($3)<='$to'{printf "%s,%s\n",$3,$5+'$port'};') + echo "$toSave" >> $outputFile # Save data in csv +done +echo "Done" diff --git a/src/g5k/run-sim.sh b/src/g5k/run-sim.sh new file mode 100755 index 0000000..9274677 --- /dev/null +++ b/src/g5k/run-sim.sh @@ -0,0 +1,39 @@ +#!/bin/bash + +# Parameters +delay=60 # Delay before starting simulation (let CPU energy going down on the server) +nbSensors=20 # Number of sensors that will send request to de server +nbSensorsFactor=3 # nbSensors*nbSensorFactor +simulationTime=300 # Approximative +sensorsSendInterval=10 # Delay between sensors requests +# requestPerSensor dynamically computed inside init-nodes +vmSize=2048 # Number of alocated ram +simKey="NONE" + +# Where script is located +simScript=$(dirname $(readlink -f "$0"))/utils.sh + +# Build a function using the script +initNodes () { + source "$simScript" +} + + +##### Test VM RAM ##### +simKey="vmSize" +for vmSize in $(echo 1024 2048 4096) +do + initNodes deploy + initNodes kill # Kill all vms (do not forget :D) +done + +vmSize=2048 # Reset vmSize + +simKey="nbSensors" +##### Test number of sensors ##### +for nbSensors in $(echo 20 100 300) +do + initNodes deploy + initNodes kill # Kill all vms +done + diff --git a/src/g5k/setup-mysql.sql b/src/g5k/setup-mysql.sql new file mode 100644 index 0000000..05042a3 --- /dev/null +++ b/src/g5k/setup-mysql.sql @@ -0,0 +1,8 @@ +create DATABASE IF NOT EXISTS experiment; +use experiment; +create TABLE IF NOT EXISTS temperature (id INTEGER,stamp INTEGER, val INTEGER); + +use mysql; +CREATE USER 'user'@'%' IDENTIFIED BY 'mysql'; +GRANT ALL ON experiment.* TO 'user'@'%'; + diff --git a/src/g5k/utils.sh b/src/g5k/utils.sh new file mode 100755 index 0000000..cf7ca23 --- /dev/null +++ b/src/g5k/utils.sh @@ -0,0 +1,137 @@ +#!/bin/bash + +##### Parameters ##### +if [ -z ${nbSensors+x} ] # If nbSensors exists, so all parameters are already define +then + delay=60 # Delay before starting simulation (let CPU energy going down on the server) + nbSensors=30 # Number of sensors that will send request to de server + nbSensorsFactor=3 # nbSensors*nbSensorFactor + simulationTime=300 # Approximative + sensorsSendInterval=10 # Delay between sensors requests + vmSize=2048 # Number of alocated ram + simKey="NONE" +fi +nHours=3 # Reservation dutation +requestPerSensor=$(( simulationTime / sensorsSendInterval )) # Theorical simulation time is $requestPerSensor*$sensorsSendInterval +###################### + + +logFile="./simLogs.txt" +log () { + echo -e "\033[0;34m$@\033[0m" +} + +sshWait () { + log "Waiting for for an ssh connection to a vm ($1)" + error=255 + until [ $error -eq 0 ] + do + ssh -q root@$1 echo "Connected to $(hostname)" + error=$? + sleep 4 + done +} + +if [ "$1" = "subscribe" ] && [ $# -eq 1 ] +then + log "Subscribing..." + oarsub -l slash_22=1+{"virtual!='NO' AND cluster='nova'"}/nodes=2,walltime=$nHours 'sleep "10d"' # On node send request to the other +# oarsub -l slash_22=1+{"virtual!='NO'"}/nodes=2,walltime=$nHours 'sleep "10d"' # On node send request to the other + +elif [ "$1" = "deploy" ] && [ $# -eq 1 ] +then + # Get machine mac address + serverSubnet=$(g5k-subnets -im|sed "1q;d") + serverMac=$(echo "$serverSubnet"|sed "s/^.*\t//g") + serverIp=$(echo "$serverSubnet"|sed "s/\t.*$//g") + clientIp=$(hostname) # Not really a IP but :P + clientNode=$(hostname) + serverNode=$(cat $OAR_NODE_FILE|uniq|sed "s/$clientNode//g"|sed "s/ //g"|tr -d '\n') + onS="oarsh $serverNode" # For convenience + + + # Init vm images + log "Create server vm image" + $onS cp -n /grid5000/virt-images/debian9-x64-base.qcow2 /tmp/ + $onS qemu-img create -f qcow2 -o backing_file=/tmp/debian9-x64-base.qcow2 /tmp/img.qcow2 + sleep 1 # Wait for fun + + # Build cloud init iso (to have ssh access witouth password + log "Create server cloud-init image" + $onS cp /grid5000/virt-images/cloud-init-example.sh /tmp/ + $onS "cd /tmp && export cloud_init_key=\$(cat ~/.ssh/id_rsa.pub) && ./cloud-init-example.sh" + $onS "cd /tmp && genisoimage -output cloud-init-data.iso -volid cidata -joliet -rock cloud-init-data/user-data cloud-init-data/meta-data" + + # Launch vm + log "Launch server vm" + $onS kvm -m ${vmSize}M -hda /tmp/img.qcow2 -netdev bridge,id=br0 -device virtio-net-pci,netdev=br0,id=nic1,mac=$serverMac -cdrom /tmp/cloud-init-data.iso -display none -daemonize & + + + ##### Server ##### + onS="ssh root@$serverIp" # Don't forget to use vm + sshWait $serverIp + # One apt-get update seems to be not enought to get mysql-server + $onS "apt-get update && apt-get update" + $onS apt-get -y install mysql-server + # Enable mysql connection from outside + $onS sed -i "s/bind-address/#bind-address/g" /etc/mysql/mariadb.conf.d/50-server.cnf + $onS 'echo -e "[mysqld]\nmax_connections = 100000" >> /etc/mysql/my.cnf' # Otherwise you will have the error "TOO MANY CONNECTION" + $onS systemctl restart mysql + rsync -avh setup-mysql.sql root@$serverIp:/tmp/ # Send mysl setup script + $onS "mysql < /tmp/setup-mysql.sql" # Then execute it + + ##### Start Simulation ##### + serverNodeName=$(echo $serverNode|grep -o ^.*[-][0-9]*|tr -d '\n') # For logging + log "Simulation will start in ${delay}s" + delayStart=$(date "+%s") # Used to compute the idle energy consumption + sleep $delay + simStart=$(date "+%s") + echo "---------- Simulation (key=${simKey}) start at $simStart ($(date -d @${simStart}))" >> $logFile + python ./clients.py $serverIp $nbSensors $nbSensorsFactor $requestPerSensor $sensorsSendInterval + simEnd=$(date "+%s") + echo "Simulation parameters: serverNode:$serverNode serverIp:$serverIp serverMac:$serverMac clientNode:$clientNode clientNode:$clientNode clientMac:$clientMac delay:$delay delayStart:${delayStart} nbSensors:$nbSensors nbSensorsFactor:$nbSensorsFactor requestPerSensors:$requestPerSensor sensorsSendInterval:${sensorsSendInterval} simKey:${simKey} simStart:${simStart} simEnd:${simEnd} duration:$(( simEnd - simStart )) serverNodeName:${serverNodeName} vmSize:${vmSize}" >> $logFile + echo "./recordEnergy.sh nova $serverNodeName $simStart $simEnd energy_${simKey}_${nbSensors}NS_${vmSize}vmSize_${simStart}_${simEnd}.csv" >> $logFile + echo -e "---------- Simulation (key=${simKey}) end at ${simEnd} ($(date -d @${simEnd}))\n" >> $logFile + log "Simulation end ! Please see $logFile for more infos" + ##### End Simulation ##### + + ##### Print some infos ##### + log "Network Settings:" + log " - Server $serverNode, $serverIp, $serverMac" + log " - Client $clientNode, $clientIp, $clientMac" + log "Simulation Settings:" + log " - Simulation delay ${delay}s" + log " - Number of sensors $(( nbSensors * nbSensorsFactor))" + log " - Number of request per sensors $requestPerSensor" + log " - Number of request per seconds on eachsensors $sensorsRequestPerSec" + +elif [ "$1" = "kill" ] && [ $# -eq 1 ] +then + ##### Kill all kvm on the subscribed nodes ##### + isServer=1 + finished=0 + for node in $(cat $OAR_NODE_FILE|uniq) + do + [ $isServer -eq 1 ] && { curMac=$serverMac; isServer=0; serverNode=$node; } || { curMac=$clientMac; finished=1; clientNode=$node; } + log "Killing vm on node $node" + oarsh $node pkill -9 qemu & + [ $finished -eq 1 ] && break + done +elif [ "$1" = "inspect" ] && [ $# -eq 2 ] +then + ##### Show content of the database ##### + mysql --host="$2" -u user --password="mysql" experiment -e "SELECT * FROM temperature;" +elif [ "$1" = "flush" ] && [ $# -eq 2 ] +then + ##### Flush content of the temperature table ##### + log "Cleaning database table..." + mysql --host="$2" -u user --password="mysql" experiment -e "TRUNCATE TABLE temperature;" +else + echo "Usage:" + echo " - $0 subscribe" + echo " - $0 deploy" + echo " - $0 kill" + echo " - $0 inspect <serverIP>" + echo " - $0 flush <serverIP>" +fi + diff --git a/src/ns3/Rplots.pdf b/src/ns3/Rplots.pdf Binary files differnew file mode 100644 index 0000000..3cf2c9b --- /dev/null +++ b/src/ns3/Rplots.pdf diff --git a/src/ns3/a.org b/src/ns3/a.org new file mode 100644 index 0000000..903b21c --- /dev/null +++ b/src/ns3/a.org @@ -0,0 +1,12 @@ +-1,1622.11 +0,3422.92 +1,3600 +2,3600 +3,3600 +4,3600 +5,3600 +6,3600 +7,3600 +8,3600 +9,1800 + diff --git a/src/ns3/g5k-root.sh b/src/ns3/g5k-root.sh new file mode 100755 index 0000000..92903ee --- /dev/null +++ b/src/ns3/g5k-root.sh @@ -0,0 +1,267 @@ +#!/bin/bash +##### Arguments ##### +nHost=20 # At least 20 host x) +nProcesses=3 # Max number of parrallel simulations (don't go too high, your process will be killed (arround 8)) +nHours=4 # Reservation duration +simArgsLoc=~/args/ # Don't change this path witouth changing it in workder scripts +finishedFile="$simArgsLoc/finished-microBenchmarks.txt" +logsFinalDst=~/logs/ +##################### + +# Check +[ "$1" == "subscribe" ] && subscribe=1 ||subscribe=0 +[ "$1" == "deploy" ] && deploy=1 || deploy=0 +[ "$1" == "-p" ] && progress=1 || progress=0 +[ "$1" == "scan" ] && scan=1 || scan=0 + +handleSim () { + [ -z "${argId}" ] && argId=1 || argId=$(( argId + 1 )) + outF="$simArgsLoc/${argId}.sh" # Args file based on host name (avoid conflict) + + # Add Shebang + echo '#!/bin/bash' > $outF + echo "finishedFile=\"$finishedFile\"" >> $outF + echo "nProcesses=$nProcesses" >> $outF + echo "logsFinalDst=\"$logsFinalDst\"" >> $outF + # Save arguments + echo "sensorsSendInterval=${sensorsSendInterval}" >> $outF + echo "sensorsPktSize=${sensorsPktSize}" >> $outF + echo "nbHop=${nbHop}" >> $outF + echo "simKey=\"${simKey}\"" >> $outF + echo "sensorsNumber=${sensorsNumber}" >> $outF + echo "linksLatency=${linksLatency}" >> $outF + echo "sensorsNumber=${sensorsNumber}" >> $outF + echo "linksBandwidth=${linksBandwidth}" >> $outF + echo "positionSeed=${positionSeed}" >> $outF +} + + +# Start subscribe/deploy +if [ $subscribe -eq 1 ] +then + echo "Starting oarsub..." + oarsub -l host=$nHost,walltime=$nHours 'sleep "10d"' # Start reservation + echo "Please join your node manually when your reservation is ready by using oarsub -C <job-id>" + exit 0 +elif [ $deploy -eq 1 ] +then + echo "Starting deployment..." + + ##### Usefull Variables ##### + wai=$(dirname "$(readlink -f $0)") # Where Am I ? + hostList=($(cat $OAR_NODE_FILE | uniq)) + ############################# + + # Initialize logsFinalDst + mkdir -p $logsFinalDst + rm -rf $logsFinalDst/* # Clean log dst just in case (it is dangerous but avoid conflict) + mkdir -p $simArgsLoc + rm -rf $simArgsLoc/* # Clean old args + + # Add your simulation code block here + simulator="simulator/simulator" + parseEnergyScript="./parseEnergy.awk" + parseDelayScript="./parseDelay.awk" + logFolder="logs/" + export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${NS3_PATH}/build/lib + + # Default Parameters + sensorsSendInterval=1 # DON'T GO BELOW 1 SECONDS !!!!!!! Simulator will stay stuck + sensorsPktSize=192 # 1 byte temperature (-128 à +128 °C) and 4Byte sensorsId + sensorsNumber=5 + nbHop=10 # Cf paper AC/Yunbo + linksBandwidth=10000 # 10Ge links (to be coherent with energy values of ECOFEN/literature) + linksLatency=11 + positionSeed=5 + simKey="NOKEY" + + run () { + # If another function want to handle simulation (tipically used on g5k) + type -t handleSim > /dev/null && { handleSim; return; } + + local logFile="${logFolder}/${simKey}_${sensorsSendInterval}SSI_${sensorsPktSize}SPS_${sensorsNumber}SN_${nbHop}NH_${linksBandwidth}LB_${linksLatency}LL_${positionSeed}PS.org" + [ -f "$logFile" ] && return + local simCMD="$simulator --sensorsSendInterval=${sensorsSendInterval} --sensorsPktSize=${sensorsPktSize} --sensorsNumber=${sensorsNumber} --nbHop=${nbHop} --linksBandwidth=${linksBandwidth} --linksLatency=${linksLatency} --positionSeed=${positionSeed} 2>&1" + local log=$(bash -c "$simCMD") + + # Compute some metrics + energyLog=$(echo "$log" | $parseEnergyScript) + avgDelay=$(echo "$log" | $parseDelayScript) + totalEnergy=$(echo "$energyLog" | awk 'BEGIN{power=0;FS=","}NR!=1{power+=$2}END{print(power)}') + sensorsEnergy=$(echo "$energyLog" |awk -F',' 'BEGIN{sumW=0}$1<0{sumW+=$2}END{print sumW}') + networkEnergy=$(echo "$energyLog" |awk -F',' 'BEGIN{sumN=0}$1>=0{sumN+=$2}END{print sumN}') + nbPacketCloud=$(echo "$log"|grep -c "CloudSwitch receive") + nbNodes=$(echo "$log"|awk '/Simulation used/{print($3)}') + ns3Version=$(echo "$log"|awk '/NS-3 Version/{print($3)}') + + # Save logs + echo -e "#+TITLE: $(date) ns-3 (version ${ns3Version}) simulation\n" > $logFile + echo "* Environment Variables" >> $logFile + env >> $logFile + echo "* Full Command" >> $logFile + echo "$simCMD" >> $logFile + echo "* Output" >> $logFile + echo "$log" >> $logFile + echo "* Energy CSV (negative nodeId = WIFI, 0 = AP (Wireless+Wired), positive nodeId = ECOFEN" >> $logFile + echo "$energyLog" >> $logFile + echo "* Metrics" >> $logFile + echo "-METRICSLINE- sensorsSendInterval:${sensorsSendInterval} sensorsPktSize:${sensorsPktSize} sensorsNumber:${sensorsNumber} nbHop:${nbHop} linksBandwidth:${linksBandwidth} linksLatency:${linksLatency} totalEnergy:$totalEnergy nbPacketCloud:$nbPacketCloud nbNodes:$nbNodes avgDelay:${avgDelay} ns3Version:${ns3Version} simKey:${simKey} positionSeed:${positionSeed} sensorsEnergy:${sensorsEnergy} networkEnergy:${networkEnergy}" >> $logFile + } + + simKey="NBSENSORS" + for sensorsNumber in $(seq 1 15) + do + run + done + simulator="simulator/simulator" + parseEnergyScript="./parseEnergy.awk" + parseDelayScript="./parseDelay.awk" + logFolder="logs/" + export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${NS3_PATH}/build/lib + + # Default Parameters + sensorsSendInterval=1 # DON'T GO BELOW 1 SECONDS !!!!!!! Simulator will stay stuck + sensorsPktSize=192 # 1 byte temperature (-128 à +128 °C) and 4Byte sensorsId + sensorsNumber=5 + nbHop=10 # Cf paper AC/Yunbo + linksBandwidth=10000 # 10Ge links (to be coherent with energy values of ECOFEN/literature) + linksLatency=11 + positionSeed=5 + simKey="NOKEY" + + run () { + # If another function want to handle simulation (tipically used on g5k) + type -t handleSim > /dev/null && { handleSim; return; } + + local logFile="${logFolder}/${simKey}_${sensorsSendInterval}SSI_${sensorsPktSize}SPS_${sensorsNumber}SN_${nbHop}NH_${linksBandwidth}LB_${linksLatency}LL_${positionSeed}PS.org" + [ -f "$logFile" ] && return + local simCMD="$simulator --sensorsSendInterval=${sensorsSendInterval} --sensorsPktSize=${sensorsPktSize} --sensorsNumber=${sensorsNumber} --nbHop=${nbHop} --linksBandwidth=${linksBandwidth} --linksLatency=${linksLatency} --positionSeed=${positionSeed} 2>&1" + local log=$(bash -c "$simCMD") + + # Compute some metrics + energyLog=$(echo "$log" | $parseEnergyScript) + avgDelay=$(echo "$log" | $parseDelayScript) + totalEnergy=$(echo "$energyLog" | awk 'BEGIN{power=0;FS=","}NR!=1{power+=$2}END{print(power)}') + sensorsEnergy=$(echo "$energyLog" |awk -F',' 'BEGIN{sumW=0}$1<0{sumW+=$2}END{print sumW}') + networkEnergy=$(echo "$energyLog" |awk -F',' 'BEGIN{sumN=0}$1>=0{sumN+=$2}END{print sumN}') + nbPacketCloud=$(echo "$log"|grep -c "CloudSwitch receive") + nbNodes=$(echo "$log"|awk '/Simulation used/{print($3)}') + ns3Version=$(echo "$log"|awk '/NS-3 Version/{print($3)}') + + # Save logs + echo -e "#+TITLE: $(date) ns-3 (version ${ns3Version}) simulation\n" > $logFile + echo "* Environment Variables" >> $logFile + env >> $logFile + echo "* Full Command" >> $logFile + echo "$simCMD" >> $logFile + echo "* Output" >> $logFile + echo "$log" >> $logFile + echo "* Energy CSV (negative nodeId = WIFI, 0 = AP (Wireless+Wired), positive nodeId = ECOFEN" >> $logFile + echo "$energyLog" >> $logFile + echo "* Metrics" >> $logFile + echo "-METRICSLINE- sensorsSendInterval:${sensorsSendInterval} sensorsPktSize:${sensorsPktSize} sensorsNumber:${sensorsNumber} nbHop:${nbHop} linksBandwidth:${linksBandwidth} linksLatency:${linksLatency} totalEnergy:$totalEnergy nbPacketCloud:$nbPacketCloud nbNodes:$nbNodes avgDelay:${avgDelay} ns3Version:${ns3Version} simKey:${simKey} positionSeed:${positionSeed} sensorsEnergy:${sensorsEnergy} networkEnergy:${networkEnergy}" >> $logFile + } + + simKey="SENDINTERVAL" + for sensorsNumber in $(seq 5 2 15) + do + for sensorsSendInterval in $(seq 10 10 100) + do + run + done + done + simulator="simulator/simulator" + parseEnergyScript="./parseEnergy.awk" + parseDelayScript="./parseDelay.awk" + logFolder="logs/" + export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${NS3_PATH}/build/lib + + # Default Parameters + sensorsSendInterval=1 # DON'T GO BELOW 1 SECONDS !!!!!!! Simulator will stay stuck + sensorsPktSize=192 # 1 byte temperature (-128 à +128 °C) and 4Byte sensorsId + sensorsNumber=5 + nbHop=10 # Cf paper AC/Yunbo + linksBandwidth=10000 # 10Ge links (to be coherent with energy values of ECOFEN/literature) + linksLatency=11 + positionSeed=5 + simKey="NOKEY" + + run () { + # If another function want to handle simulation (tipically used on g5k) + type -t handleSim > /dev/null && { handleSim; return; } + + local logFile="${logFolder}/${simKey}_${sensorsSendInterval}SSI_${sensorsPktSize}SPS_${sensorsNumber}SN_${nbHop}NH_${linksBandwidth}LB_${linksLatency}LL_${positionSeed}PS.org" + [ -f "$logFile" ] && return + local simCMD="$simulator --sensorsSendInterval=${sensorsSendInterval} --sensorsPktSize=${sensorsPktSize} --sensorsNumber=${sensorsNumber} --nbHop=${nbHop} --linksBandwidth=${linksBandwidth} --linksLatency=${linksLatency} --positionSeed=${positionSeed} 2>&1" + local log=$(bash -c "$simCMD") + + # Compute some metrics + energyLog=$(echo "$log" | $parseEnergyScript) + avgDelay=$(echo "$log" | $parseDelayScript) + totalEnergy=$(echo "$energyLog" | awk 'BEGIN{power=0;FS=","}NR!=1{power+=$2}END{print(power)}') + sensorsEnergy=$(echo "$energyLog" |awk -F',' 'BEGIN{sumW=0}$1<0{sumW+=$2}END{print sumW}') + networkEnergy=$(echo "$energyLog" |awk -F',' 'BEGIN{sumN=0}$1>=0{sumN+=$2}END{print sumN}') + nbPacketCloud=$(echo "$log"|grep -c "CloudSwitch receive") + nbNodes=$(echo "$log"|awk '/Simulation used/{print($3)}') + ns3Version=$(echo "$log"|awk '/NS-3 Version/{print($3)}') + + # Save logs + echo -e "#+TITLE: $(date) ns-3 (version ${ns3Version}) simulation\n" > $logFile + echo "* Environment Variables" >> $logFile + env >> $logFile + echo "* Full Command" >> $logFile + echo "$simCMD" >> $logFile + echo "* Output" >> $logFile + echo "$log" >> $logFile + echo "* Energy CSV (negative nodeId = WIFI, 0 = AP (Wireless+Wired), positive nodeId = ECOFEN" >> $logFile + echo "$energyLog" >> $logFile + echo "* Metrics" >> $logFile + echo "-METRICSLINE- sensorsSendInterval:${sensorsSendInterval} sensorsPktSize:${sensorsPktSize} sensorsNumber:${sensorsNumber} nbHop:${nbHop} linksBandwidth:${linksBandwidth} linksLatency:${linksLatency} totalEnergy:$totalEnergy nbPacketCloud:$nbPacketCloud nbNodes:$nbNodes avgDelay:${avgDelay} ns3Version:${ns3Version} simKey:${simKey} positionSeed:${positionSeed} sensorsEnergy:${sensorsEnergy} networkEnergy:${networkEnergy}" >> $logFile + } + + simKey="SENSORSPOS" + for sensorsNumber in $(seq 5 2 15) + do + for positionSeed in $(seq 1 10) + do + run + done + done + + # Distribute argument according to subsribed nodes + cd $simArgsLoc + curHostId=0 + for file in $(find ./ -type f) + do + [ $curHostId -eq $nHost ] && curHostId=0 + mv -- ${file} ${hostList[$curHostId]}-$(basename ${file}) + curHostId=$(( curHostId + 1 )) + done + cd - + + + # Run simulations + echo "Host who finished their work:" > $finishedFile + for host in ${hostList[@]} + do + echo "Start simulations on node $host" + oarsh lguegan@$host bash g5k-worker.sh & + done + + exit 0 +elif [ $progress -eq 1 ] +then + alreadyFinished=$(cat $finishedFile| tail -n +2| wc -l) + percent=$(echo $alreadyFinished $nHost| awk '{print $1/$2*100}') + echo "Progression: " $alreadyFinished/$nHost "(${percent}%)" +elif [ $scan -eq 1 ] +then + for host in $(cat $OAR_NODE_FILE|uniq) + do + proc=$(oarsh $host "ps -e|grep -i simulator") + [ ! -z "$proc" ] && { echo "- Processes for node $host:"; echo "$proc"; } + done +else + echo "Invalid arguments, make sure you know what you are doing !" + exit 1 +fi diff --git a/src/ns3/g5k-worker.sh b/src/ns3/g5k-worker.sh new file mode 100755 index 0000000..402a1a5 --- /dev/null +++ b/src/ns3/g5k-worker.sh @@ -0,0 +1,75 @@ +#!/bin/bash +export NS3_PATH=~/.bin/ns-3/ns-3.29/ +g5kLogFolder="/tmp/logs/" +mkdir -p $g5kLogFolder # Create log folder just in case +rm -rf $g5kLogFolder/* # Clean previous logs just in case + +hostname=$(hostname) + +# Run simulations with sourced arguments :D +simArgsLoc=~/args/ # Don't change this path without changing it in root scripts + +argsId=0 +argsFile="$simArgsLoc/${hostname}-args-${argsId}.sh" # Arguments generated by Root Node +curNProcesses=0 # Start with no processes +for argsFile in $(find $simArgsLoc -type f -name "$hostname*") +do + simulator="simulator/simulator" + parseEnergyScript="./parseEnergy.awk" + parseDelayScript="./parseDelay.awk" + logFolder="logs/" + export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${NS3_PATH}/build/lib + + # Default Parameters + sensorsSendInterval=1 # DON'T GO BELOW 1 SECONDS !!!!!!! Simulator will stay stuck + sensorsPktSize=192 # 1 byte temperature (-128 à +128 °C) and 4Byte sensorsId + sensorsNumber=5 + nbHop=10 # Cf paper AC/Yunbo + linksBandwidth=10000 # 10Ge links (to be coherent with energy values of ECOFEN/literature) + linksLatency=11 + positionSeed=5 + simKey="NOKEY" + + run () { + # If another function want to handle simulation (tipically used on g5k) + type -t handleSim > /dev/null && { handleSim; return; } + + local logFile="${logFolder}/${simKey}_${sensorsSendInterval}SSI_${sensorsPktSize}SPS_${sensorsNumber}SN_${nbHop}NH_${linksBandwidth}LB_${linksLatency}LL_${positionSeed}PS.org" + [ -f "$logFile" ] && return + local simCMD="$simulator --sensorsSendInterval=${sensorsSendInterval} --sensorsPktSize=${sensorsPktSize} --sensorsNumber=${sensorsNumber} --nbHop=${nbHop} --linksBandwidth=${linksBandwidth} --linksLatency=${linksLatency} --positionSeed=${positionSeed} 2>&1" + local log=$(bash -c "$simCMD") + + # Compute some metrics + energyLog=$(echo "$log" | $parseEnergyScript) + avgDelay=$(echo "$log" | $parseDelayScript) + totalEnergy=$(echo "$energyLog" | awk 'BEGIN{power=0;FS=","}NR!=1{power+=$2}END{print(power)}') + sensorsEnergy=$(echo "$energyLog" |awk -F',' 'BEGIN{sumW=0}$1<0{sumW+=$2}END{print sumW}') + networkEnergy=$(echo "$energyLog" |awk -F',' 'BEGIN{sumN=0}$1>=0{sumN+=$2}END{print sumN}') + nbPacketCloud=$(echo "$log"|grep -c "CloudSwitch receive") + nbNodes=$(echo "$log"|awk '/Simulation used/{print($3)}') + ns3Version=$(echo "$log"|awk '/NS-3 Version/{print($3)}') + + # Save logs + echo -e "#+TITLE: $(date) ns-3 (version ${ns3Version}) simulation\n" > $logFile + echo "* Environment Variables" >> $logFile + env >> $logFile + echo "* Full Command" >> $logFile + echo "$simCMD" >> $logFile + echo "* Output" >> $logFile + echo "$log" >> $logFile + echo "* Energy CSV (negative nodeId = WIFI, 0 = AP (Wireless+Wired), positive nodeId = ECOFEN" >> $logFile + echo "$energyLog" >> $logFile + echo "* Metrics" >> $logFile + echo "-METRICSLINE- sensorsSendInterval:${sensorsSendInterval} sensorsPktSize:${sensorsPktSize} sensorsNumber:${sensorsNumber} nbHop:${nbHop} linksBandwidth:${linksBandwidth} linksLatency:${linksLatency} totalEnergy:$totalEnergy nbPacketCloud:$nbPacketCloud nbNodes:$nbNodes avgDelay:${avgDelay} ns3Version:${ns3Version} simKey:${simKey} positionSeed:${positionSeed} sensorsEnergy:${sensorsEnergy} networkEnergy:${networkEnergy}" >> $logFile + } + + logFolder=$g5kLogFolder # Don't forget override default g5kLogFolder + source $argsFile # Fetch argument + run & # Run async + ((curNProcesses+=1)) # Increase by 2 + [ $curNProcesses -ge $nProcesses ] && { curNProcesses=0; wait; } +done +wait # Wait until the end of all simulations + +cp -r $g5kLogFolder/* "$logsFinalDst" # Fetch log from tmp into nfs +echo $(hostname) >> $finishedFile # Just say I finished diff --git a/src/ns3/nix/default.nix b/src/ns3/nix/default.nix new file mode 100644 index 0000000..62dea05 --- /dev/null +++ b/src/ns3/nix/default.nix @@ -0,0 +1,58 @@ +{ + pkgs ? (import (fetchTarball "https://github.com/NixOS/nixpkgs/archive/19.03.tar.gz") {}) +}: + +with pkgs; rec { + + ns3 = stdenv.mkDerivation rec { + ##### Configure NIX ##### + name="ns3"; + sourceRoot="ns-allinone-3.29/ns-3.29/"; # Since we have 2 source tarball (ns-3 & ECOFEN) nix need to know which one to use + + ##### Fetch ns-3 And ECOFEN ##### + src = [ + (fetchurl { + url = https://www.nsnam.org/releases/ns-allinone-3.29.tar.bz2; + sha256 = "0m9dpmby116qk1m4x645i1p92syn30yzn9dgxxji5i25g30abpsd"; + }) + + (fetchurl { + url = http://people.irisa.fr/Anne-Cecile.Orgerie/ECOFEN/ecofen-v2.tar.bz2; + sha256 = "1dnmm20ihas6hwwb8qbx8sr3h66nrg8h55x6f2aqpf3xima29dyh"; + }) + ]; + + ##### Configure Dependencies ##### + buildInputs= [ python gsl ]; + + ##### Configure Phases ##### + postUnpack=''mv ecofen-module-v2 ${sourceRoot}/contrib/ecofen''; + configurePhase='' + export CXXFLAGS="-Wall -g -O0" # Don't treat warning as error when compiling ns-3 + python2 waf configure + ''; + buildPhase=''python2 waf''; + installPhase='' + mkdir -p $out/include + cp -r ./build/lib $out/ + cp -r ./build/ns3 $out/include + ''; + }; + + simulator= stdenv.mkDerivation rec { + ##### Configure NIX ##### + name="simulator"; + src=./simulator; + + ##### Export ns3 location ##### + NS3_PATH=ns3; + + ##### Configure Phases ##### + buildPhase=''make''; + installPhase='' + mkdir -p $out/bin + install -D -t $out/bin simulator + ''; + + }; +} diff --git a/src/ns3/nix/simulator/Makefile b/src/ns3/nix/simulator/Makefile new file mode 100644 index 0000000..63c0141 --- /dev/null +++ b/src/ns3/nix/simulator/Makefile @@ -0,0 +1,26 @@ + +EXEC=simulator + +##### NS3 g++ Arguments +NS3_ARGS= -D NS3_LOG_ENABLE -L ${NS3_PATH}/lib -I ${NS3_PATH}/include +NS3_ARGS+=$(addprefix -l, $(subst lib,,$(subst .so,,$(notdir $(wildcard ${NS3_PATH}/lib/libns3*.so))))) +NS3_VERSION="3.29" + + +##### Source Files +SRC=main.cc modules/platform.cc modules/energy.cc modules/callbacks.cc + + +all: $(EXEC) + +$(EXEC): $(SRC) + @echo -e "\e[32mDon't forget to define NS3_PATH env variable !\e[0m" + g++ -g -D NS3_VERSION=${NS3_VERSION} $(NS3_ARGS) $(SRC) -o $@ + @echo -e "\e[32mRun the following command before running $(EXEC):\e[0m" + @echo -e "\e[32mexport LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${NS3_PATH}/lib\e[0m" + +clean: + - rm $(EXEC) + + +.PHONY: clean diff --git a/src/ns3/nix/simulator/main.cc b/src/ns3/nix/simulator/main.cc new file mode 100644 index 0000000..8857414 --- /dev/null +++ b/src/ns3/nix/simulator/main.cc @@ -0,0 +1,85 @@ +#include "modules/modules.hpp" +#ifndef NS3_VERSION +#define NS3_VERSION "unknown" +#endif + +NS_LOG_COMPONENT_DEFINE ("WIFISensorsSimulator"); + + +/** + * To get more details about functions please have a look at modules/modules.hpp + */ +int main(int argc, char* argv[]){ + + uint32_t sensorsFrequency=1; // One pkt every second + uint32_t sensorsPktSize=192; // 128 bits for sensors id and 32 bit for the temperature (an arbitrary Integer) and a timestamp (32bits) + uint32_t sensorsNumber=5; + uint32_t nbHop=10; + uint32_t linksBandwidth=10000; + uint32_t linksLatency=11; // 10 hops => 9 links => 11.1ms of latency => end-to-end latency==100ms + uint32_t positionSeed=5; // arbitrary + + CommandLine cmd; + cmd.AddValue ("sensorsSendInterval", "Number of sensors measurement per second", sensorsFrequency); + cmd.AddValue ("sensorsPktSize", "Sensors packet size (bytes)", sensorsPktSize); + cmd.AddValue ("sensorsNumber", "Number of sensors connected to AP", sensorsNumber); + cmd.AddValue ("nbHop", "Number of hop between AP and Cloud", nbHop); + cmd.AddValue ("linksBandwidth", "Links bandwidth between AP and Cloud", linksBandwidth); + cmd.AddValue ("linksLatency", "Links latency between AP and Cloud", linksLatency); + cmd.AddValue ("positionSeed", "RandomRectangle Sensors placement seed", positionSeed); + cmd.Parse (argc, argv); + + // Check sensors frequency + if(sensorsFrequency<1){ + NS_LOG_UNCOND("SensorsSendInterval too small: " << sensorsFrequency << " (it should be >1)." ); + exit(1); + } + + //LogComponentEnable("UdpEchoClientApplication", LOG_LEVEL_INFO); + //LogComponentEnable("PacketSink", LOG_LEVEL_INFO); + + // ---------- Setup Simulations ---------- + CloudInfos cloud=createCloud(nbHop,linksBandwidth,linksLatency); // Create cloud P2P node chain o--o--o--o--o + setupCloudEnergy(cloud); // DO IT JUST AFTER createCloud !!!!! Otherwise you will be in trouble + Cell cell=createCell(sensorsNumber,cloud.first.Get(0),positionSeed); // Use first cloud node as Access Point + setupScenario(cell,cloud,sensorsPktSize,sensorsFrequency); // Send data from Sensors to Cloud + DeviceEnergyModelContainer wifi=setupCellEnergy(cell); + + // Don't forget the following + Ipv4GlobalRoutingHelper::PopulateRoutingTables (); + + // Setup Logs + uint32_t nNode=ns3::NodeList::GetNNodes(); + FlowMonitorHelper flowmon; + Ptr<FlowMonitor> monitor = flowmon.InstallAll(); + Ptr<Ipv4FlowClassifier> classifier = DynamicCast<Ipv4FlowClassifier> (flowmon.GetClassifier ()); + + // Run Simulations + Simulator::Stop (Seconds (SIM_TIME)); + Simulator::Run (); + + // Print logs + NS_LOG_UNCOND("NS-3 Version " << NS3_VERSION); + NS_LOG_UNCOND("Simulation used "<< nNode << " nodes"); + std::map<FlowId, FlowMonitor::FlowStats> stats = monitor->GetFlowStats (); + for (std::map< FlowId, FlowMonitor::FlowStats>::iterator flow=stats.begin(); flow!=stats.end(); flow++) + { + Ipv4FlowClassifier::FiveTuple t = classifier->FindFlow(flow->first); + NS_LOG_UNCOND("Flow " <<t.sourceAddress<< " -> "<< t.destinationAddress << " delay = " <<flow->second.delaySum.GetSeconds()); + } + + + // Trace + DeviceEnergyModelContainer::Iterator it=wifi.Begin(); + int i=0; // Note that node 0 is the AP + while(it!=wifi.End()){ + NS_LOG_UNCOND ("Node " << i << " consumes " <<(*it)->GetTotalEnergyConsumption()); + it++; + i--; // Edge device will have id < 0 and ap will have id 0 + } + + + // Finish + Simulator::Destroy (); + return(0); +} diff --git a/src/ns3/nix/simulator/modules/callbacks.cc b/src/ns3/nix/simulator/modules/callbacks.cc new file mode 100644 index 0000000..4ae0c97 --- /dev/null +++ b/src/ns3/nix/simulator/modules/callbacks.cc @@ -0,0 +1,12 @@ + +#include "modules.hpp" + +void PktReceived(std::string nodeName,Ptr< const Packet > packet, const Address &address){ + NS_LOG_UNCOND("Node " << nodeName << " receive a packet" << " at time " << Simulator::Now ().GetSeconds () << "s"); +} + +void EnergyUpdated(std::string nodeName,double oldValue, double newValue){ + double currentTime=Simulator::Now ().GetSeconds (); + double energyConsumes=newValue-oldValue; + NS_LOG_UNCOND("Node " << nodeName << " consumes " << energyConsumes << "J" << " at time " << currentTime << "s"); +} diff --git a/src/ns3/nix/simulator/modules/energy.cc b/src/ns3/nix/simulator/modules/energy.cc new file mode 100644 index 0000000..56c38e5 --- /dev/null +++ b/src/ns3/nix/simulator/modules/energy.cc @@ -0,0 +1,68 @@ + +#include "modules.hpp" + +DeviceEnergyModelContainer setupCellEnergy(Cell cell){ + NodeContainer nodes(cell.first.first,cell.first.second); + NetDeviceContainer nodesNetDev(cell.second.first,cell.second.second); + + // Install energy source + BasicEnergySourceHelper edgeBasicSourceHelper; + edgeBasicSourceHelper.Set ("BasicEnergySourceInitialEnergyJ", DoubleValue (BASICENERGYSOURCEINITIALENERGYJ)); + edgeBasicSourceHelper.Set ("BasicEnergySupplyVoltageV", DoubleValue (BASICENERGYSUPPLYVOLTAGEV)); + EnergySourceContainer apEdgeNodesSources = edgeBasicSourceHelper.Install (cell.first.first); + EnergySourceContainer wifiEdgeNodesSources = edgeBasicSourceHelper.Install (cell.first.second); + + // Install device energy model + WifiRadioEnergyModelHelper radioEnergyHelper; + radioEnergyHelper.Set ("TxCurrentA", DoubleValue (TXCURRENTA)); + radioEnergyHelper.Set ("RxCurrentA", DoubleValue (RXCURRENTA)); + radioEnergyHelper.Set ("IdleCurrentA", DoubleValue (IDLECURRENTA)); + DeviceEnergyModelContainer edgeApDeviceModels = radioEnergyHelper.Install (cell.second.first, apEdgeNodesSources); + DeviceEnergyModelContainer edgeDeviceModels = radioEnergyHelper.Install (cell.second.second, wifiEdgeNodesSources); + + + // Trace + // DeviceEnergyModelContainer::Iterator it=edgeDeviceModels.Begin(); + //int i=1; // Node 0 will be AP, other node will have negative id (cf following while) + // This is usefull in logs, in fact ECOFEN nodes will have positive ID and WIFI energy nodes negative id + // AP will have id 0 in ECOFEN and WIFI (in order to combine their energy value when parsing logs + // while(it!=edgeDeviceModels.End()){ + // (*it)->TraceConnect ("TotalEnergyConsumption", std::to_string(0-i),MakeCallback (&EnergyUpdated)); + // it++; + // i++; + // } + // // AP will have id 0 + // (*edgeApDeviceModels.Begin())->TraceConnect ("TotalEnergyConsumption", std::to_string(0),MakeCallback (&EnergyUpdated)); + + // Ptr<BasicEnergySource> basicSourcePtr0 = DynamicCast<BasicEnergySource> (wifiEdgeNodesSources.Get (0)); + // //basicSourcePtr0->TraceConnectWithoutContext ("RemainingEnergy", MakeCallback (&RemainingEnergy)); + // //device energy model + // Ptr<DeviceEnergyModel> basicRadioModelPtr0 = + // basicSourcePtr0->FindDeviceEnergyModels ("ns3::WifiRadioEnergyModel").Get (0); + // NS_ASSERT (basicRadioModelPtr0 != NULL); + // basicRadioModelPtr0->TraceConnectWithoutContext ("TotalEnergyConsumption", MakeCallback (&TotalEnergy)); + return(DeviceEnergyModelContainer(edgeApDeviceModels,edgeDeviceModels)); +} + +void setupCloudEnergy(CloudInfos cloudInfos){ + NodeContainer cloudNodes=cloudInfos.first; + + // Install basic energy + ns3::BasicNodeEnergyHelper basicNodeEnergy; + basicNodeEnergy.Set("OnConso", ns3::DoubleValue (ONCONSO)); + basicNodeEnergy.Set("OffConso", ns3::DoubleValue (OFFCONSO)); + basicNodeEnergy.Install (cloudNodes); + + ns3::CompleteNetdeviceEnergyHelper completeNetdeviceEnergy; + completeNetdeviceEnergy.Set ("OffConso", ns3::DoubleValue (OFFCONSO)); + completeNetdeviceEnergy.Set ("IdleConso", ns3::DoubleValue (IDLECONSO)); + completeNetdeviceEnergy.Set ("RecvByteEnergy", ns3::DoubleValue (RECVBYTEENERGY)); + completeNetdeviceEnergy.Set ("SentByteEnergy", ns3::DoubleValue (SENTBYTEENERGY)); + completeNetdeviceEnergy.Set ("RecvPktEnergy", ns3::DoubleValue (RECVPKTENERGY)); + completeNetdeviceEnergy.Set ("SentPktEnergy", ns3::DoubleValue (SENTPKTENERGY)); + completeNetdeviceEnergy.Install(cloudNodes); + + ns3::ConsumptionLogger conso; + conso.NodeConso(ns3::Seconds (ECOFEN_LOG_EVERY), ns3::Seconds(SIM_TIME), cloudNodes); +} + diff --git a/src/ns3/nix/simulator/modules/modules.hpp b/src/ns3/nix/simulator/modules/modules.hpp new file mode 100644 index 0000000..7c38ad7 --- /dev/null +++ b/src/ns3/nix/simulator/modules/modules.hpp @@ -0,0 +1,103 @@ + +#ifndef MODULES_HPP +#define MODULES_HPP + +#include "ns3/command-line.h" +#include "ns3/config.h" +#include "ns3/string.h" +#include "ns3/log.h" +#include "ns3/yans-wifi-helper.h" +#include "ns3/ssid.h" +#include "ns3/mobility-helper.h" +#include "ns3/on-off-helper.h" +#include "ns3/yans-wifi-channel.h" +#include "ns3/mobility-model.h" +#include "ns3/packet-sink.h" +#include "ns3/packet-sink-helper.h" +#include "ns3/udp-echo-helper.h" +#include "ns3/tcp-westwood.h" +#include "ns3/internet-stack-helper.h" +#include "ns3/ipv4-address-helper.h" +#include "ns3/ipv4-global-routing-helper.h" +#include "ns3/constant-position-mobility-model.h" +#include "ns3/energy-module.h" +#include "ns3/wifi-radio-energy-model-helper.h" +#include "ns3/point-to-point-helper.h" +#include "ns3/ecofen-module.h" +#include "ns3/node-list.h" +#include "ns3/flow-monitor-module.h" + +// C++ library +#include <iostream> // Why not ? +#include <utility> // To use std::pair +#include <iomanip> // To use std::setw + +#define SIM_TIME 1800 // 30mins simulations +#define RECT_SIZE 20 // Sensors random rectangle position size +#define MAX_PACKET_BY_SENSOR 900000 // Reasonable big number (in order that simulation end before sensors stop sending packets) + +// ECOFEN +#define ECOFEN_LOG_EVERY 0.5 + +// WIFI Energy Values +#define BASICENERGYSOURCEINITIALENERGYJ 10000000 +#define BASICENERGYSUPPLYVOLTAGEV 3.3 +#define TXCURRENTA 0.38 +#define RXCURRENTA 0.313 +#define IDLECURRENTA 0.273 + +// Cloud Energy Values +#define ONCONSO 0 +#define OFFCONSO 0 +#define IDLECONSO 1 +#define RECVBYTEENERGY 3.4 +#define SENTBYTEENERGY 3.4 +#define RECVPKTENERGY 192.2 +#define SENTPKTENERGY 192.2 + +using namespace ns3; + +// ---------- Data types ---------- +typedef std::pair<NodeContainer,NodeContainer> CellNodes; // Format (APNode, SensorsNodes) +typedef std::pair<NetDeviceContainer,NetDeviceContainer> CellNetDevices; // Format (APNetDev, SensorsNetDev) +typedef std::pair<CellNodes,CellNetDevices> Cell; +typedef std::pair<Ipv4Address,int> EndPoint; // Format (IP,Port) +typedef std::pair<NodeContainer,EndPoint> CloudInfos; // Format (CloudHops,CloudEndPoint), here data sent to CloudEndPoint + + +// ---------- platform.cc ---------- +/** + * Create a WIFI cell paltform composed of nbSensors sensors and ap as an access point + */ +Cell createCell(uint32_t nbSensors, Ptr<ns3::Node> ap,int positionSeed); + +/** + * Build P2P network composed of nbHop hops (to simulate edge->cloud communications) + * Note: Cloud Servers are not considered here and completely ignored ! + */ +CloudInfos createCloud(int nbHop, uint32_t bandwidth, uint32_t latency); +/** + * Setup simulation scenario on the platforms. Sensors in cell will send packets of sensorsPktSize size every + * sensorsSensInterval second to the cloud using cloudInfos. + */ +void setupScenario(Cell cell, CloudInfos cloudInfos, int sensorsPktSize, int sensorsSendInterval); + + +// ---------- energy.cc ---------- +/* + * Configure WIFI energy module for cell + */ +DeviceEnergyModelContainer setupCellEnergy(Cell cell); +/* + * Configure link/port energy using ecofen + */ +void setupCloudEnergy(CloudInfos cloudInfos); + + +// ---------- callbacks.cc ---------- +void PktReceived(std::string nodeName,Ptr< const Packet > packet, const Address &address); +void EnergyUpdated(std::string nodeName,double oldValue, double newValue); + + + +#endif diff --git a/src/ns3/nix/simulator/modules/platform.cc b/src/ns3/nix/simulator/modules/platform.cc new file mode 100644 index 0000000..7cfc2b9 --- /dev/null +++ b/src/ns3/nix/simulator/modules/platform.cc @@ -0,0 +1,137 @@ +#include "modules.hpp" +#include "ns3/pointer.h" + +/** + * Create a sensors cell base on + * nbSensors Number of temperature sensors in the cell + * ap the Access Point (usually linked to the cloud) + */ +Cell createCell(uint32_t nbSensors, Ptr<ns3::Node> ap,int positionSeed){ + // Create sensors + NodeContainer sensors; + sensors.Create(nbSensors); + + + // Define sensors position/mobility + MobilityHelper mobility; + mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel"); // Sensors are fixed + Ptr<UniformRandomVariable> X = CreateObject<UniformRandomVariable> (); + X->SetAttribute ("Min", DoubleValue (0)); + X->SetAttribute ("Max", DoubleValue (RECT_SIZE)); + X->SetAttribute("Stream",IntegerValue(positionSeed)); + Ptr<UniformRandomVariable> Y = CreateObject<UniformRandomVariable> (); + Y->SetAttribute ("Min", DoubleValue (0)); + Y->SetAttribute ("Max", DoubleValue (RECT_SIZE)); + Y->SetAttribute("Stream",IntegerValue(positionSeed+1)); + mobility.SetPositionAllocator("ns3::RandomRectanglePositionAllocator", + "X",PointerValue(X), + "Y",PointerValue(Y)); + mobility.Install(NodeContainer(ap,sensors)); + + // To apply XXWifiPhy and WifiMac on sensors + WifiHelper wifiHelper; + wifiHelper.SetStandard (WIFI_PHY_STANDARD_80211n_5GHZ); + + /* Set up Legacy Channel */ + YansWifiChannelHelper wifiChannel; + wifiChannel.SetPropagationDelay ("ns3::ConstantSpeedPropagationDelayModel"); + wifiChannel.AddPropagationLoss ("ns3::FriisPropagationLossModel", "Frequency", DoubleValue (5e9)); + + /* Setup Physical Layer */ + YansWifiPhyHelper wifiPhy = YansWifiPhyHelper::Default (); + wifiPhy.SetChannel (wifiChannel.Create ()); + wifiPhy.Set ("TxPowerStart", DoubleValue (10.0)); + wifiPhy.Set ("TxPowerEnd", DoubleValue (10.0)); + wifiPhy.Set ("TxPowerLevels", UintegerValue (1)); + wifiPhy.Set ("TxGain", DoubleValue (0)); + wifiPhy.Set ("RxGain", DoubleValue (0)); + wifiPhy.Set ("RxNoiseFigure", DoubleValue (10)); + wifiPhy.Set ("CcaMode1Threshold", DoubleValue (-79)); + wifiPhy.Set ("EnergyDetectionThreshold", DoubleValue (-79 + 3)); + // wifiPhy.SetErrorRateModel ("ns3::YansErrorRateModel"); + wifiHelper.SetRemoteStationManager ("ns3::ConstantRateWifiManager", + "DataMode", StringValue ("HtMcs7"), + "ControlMode", StringValue ("HtMcs0")); + /* Configure AP */ + Ssid ssid = Ssid ("network"); + WifiMacHelper wifiMac; + wifiMac.SetType ("ns3::ApWifiMac", "Ssid", SsidValue (ssid)); + NetDeviceContainer apNetDevice; + apNetDevice = wifiHelper.Install (wifiPhy, wifiMac, ap); + /* Configure STA */ + wifiMac.SetType ("ns3::StaWifiMac", "Ssid", SsidValue (ssid)); + NetDeviceContainer sensorsNetDevices; + sensorsNetDevices = wifiHelper.Install (wifiPhy, wifiMac, sensors); + + return(std::make_pair(std::make_pair(ap,sensors),std::make_pair(apNetDevice,sensorsNetDevices))); +} + +/** + * Install network stack and applications + */ +void setupScenario(Cell cell, CloudInfos cloudInfos, int sensorsPktSize, int sensorsSendInterval){ + NodeContainer ap=cell.first.first; + NodeContainer sensors=cell.first.second; + NetDeviceContainer apNetDev= cell.second.first; + NetDeviceContainer sensorsNetDev= cell.second.second; + + // 6. Install TCP/IP stack & assign IP addresses + InternetStackHelper internet; + // internet.Install (ap); + internet.Install (sensors); + Ipv4AddressHelper ipv4; + ipv4.SetBase ("10.0.0.0", "255.255.0.0"); + Ipv4InterfaceContainer apInt,sensorsInt; + apInt=ipv4.Assign(apNetDev); + sensorsInt=ipv4.Assign(sensorsNetDev); + + UdpEchoClientHelper echoClientHelper (InetSocketAddress (cloudInfos.second.first, cloudInfos.second.second)); + echoClientHelper.SetAttribute ("Interval", TimeValue (Seconds (sensorsSendInterval))); + echoClientHelper.SetAttribute ("PacketSize", UintegerValue (sensorsPktSize)); + echoClientHelper.SetAttribute ("MaxPackets", UintegerValue (MAX_PACKET_BY_SENSOR)); + ApplicationContainer pingApps; + + // again using different start times to workaround Bug 388 and Bug 912 + for(int i=0;i<sensors.GetN();i++){ + echoClientHelper.SetAttribute ("StartTime", TimeValue (MilliSeconds (1+i))); + echoClientHelper.Install (sensors.Get(i)); + } +} + + +CloudInfos createCloud(int nbHop, uint32_t bandwidth, uint32_t latency){ + + NodeContainer HopNodes; + HopNodes.Create(nbHop); + InternetStackHelper stack; + stack.Install(HopNodes); + + Ipv4Address cloudIP; // Will be fill in the following for loop + int cloudPort=80; + for(int i=0;i<nbHop-1;i++){ + NodeContainer curNodes(HopNodes.Get(i),HopNodes.Get(i+1)); + + PointToPointHelper pointToPoint; + pointToPoint.SetDeviceAttribute ("DataRate", StringValue ((std::to_string(bandwidth)+"Mbps").c_str())); + pointToPoint.SetChannelAttribute ("Delay", StringValue ((std::to_string(latency)+"ms").c_str())); + + NetDeviceContainer p2pDevices; + p2pDevices = pointToPoint.Install (curNodes); + + Ipv4AddressHelper address; + address.SetBase (("10."+std::to_string(i+1)+".0.0").c_str(), "255.255.0.0"); // Remember: 10.0.0.0 is used by WIFI + Ipv4InterfaceContainer p2pInterfaces; + p2pInterfaces = address.Assign (p2pDevices); + + if(i==nbHop-2){ // If we are on the last for loop (before last node) + cloudIP=p2pInterfaces.GetAddress (1); // Get Last node interface + PacketSinkHelper apSink("ns3::UdpSocketFactory",InetSocketAddress (Ipv4Address::GetAny (), cloudPort)); + ApplicationContainer sinkApp=apSink.Install(curNodes.Get(1)); // Instal sink on last node + sinkApp.Get(0)->TraceConnect("Rx","CloudSwitch",MakeCallback(&PktReceived)); + sinkApp.Start (Seconds (0)); + } + } + + return(std::make_pair(HopNodes,std::make_pair(cloudIP,cloudPort))); + +} diff --git a/src/ns3/parseDelay.awk b/src/ns3/parseDelay.awk new file mode 100755 index 0000000..7a4edc6 --- /dev/null +++ b/src/ns3/parseDelay.awk @@ -0,0 +1,20 @@ +#!/usr/bin/awk -f + +BEGIN { + delaySum=0 + delayCount=0 +} + +/delay =/ { + gsub("ns","",$7) + gsub("+","",$7) + delaySum+=$7 + delayCount+=1 +} + +END { + if(delayCount>0) + print(delaySum/delayCount) + else + print(0) +} diff --git a/src/ns3/parseEnergy.awk b/src/ns3/parseEnergy.awk new file mode 100755 index 0000000..6c5cce8 --- /dev/null +++ b/src/ns3/parseEnergy.awk @@ -0,0 +1,55 @@ +#!/usr/bin/awk -f + +BEGIN { + durationECOFEN=0 + sum=0 +} + +# For ECOFEN energy model +/Node [0-9]+ Conso/ { + if (!($4 in energyECOFEN)){ + energyECOFEN[$4]=$6 + countECOFEN[$4]=1 + } + else { + energyECOFEN[$4]=$6+energyECOFEN[$4] + countECOFEN[$4]++ + } + durationECOFEN=$2 +} + +# For WIFI ns-3 energy model +/Node -?[0-9]+ consumes/ { + gsub("J","",$4) # Remove trailling Joule symbol + energyWIFI[$2]=$4 +} + + + +END { + # Extract ECOFEN energy + for(key in energyECOFEN){ + if (countECOFEN[key]>0){ # Otherwise: 0 division + overallEnergy[key]=energyECOFEN[key]/countECOFEN[key]*durationECOFEN + } + else { + overallEnergy[key]=0 + } + } + + # Extract WIFI energy + for(key in energyWIFI){ + if(key in overallEnergy){ # Combine WIFI+ECOFEN + overallEnergy[key]+=energyWIFI[key] # Add wifi to ECOFEN + } + else { + overallEnergy[key]=energyWIFI[key] # Only add WIFI since there is no ECOFEN value + } + } + + # CSV output + print("nodeId,energy") + for(key in overallEnergy){ + print(key "," overallEnergy[key]) + } +} diff --git a/src/ns3/plot-final.png b/src/ns3/plot-final.png Binary files differnew file mode 100644 index 0000000..6262316 --- /dev/null +++ b/src/ns3/plot-final.png diff --git a/src/ns3/plots/NBSENSORS-sensorsNumber_totalEnergy.png b/src/ns3/plots/NBSENSORS-sensorsNumber_totalEnergy.png Binary files differnew file mode 100644 index 0000000..6e4c8c6 --- /dev/null +++ b/src/ns3/plots/NBSENSORS-sensorsNumber_totalEnergy.png diff --git a/src/ns3/plots/SENDINTERVAL-sensorsSendInterval_energyWifi.png b/src/ns3/plots/SENDINTERVAL-sensorsSendInterval_energyWifi.png Binary files differnew file mode 100644 index 0000000..6b4060d --- /dev/null +++ b/src/ns3/plots/SENDINTERVAL-sensorsSendInterval_energyWifi.png diff --git a/src/ns3/plots/SENDINTERVAL-sensorsSendInterval_networkEnergy.png b/src/ns3/plots/SENDINTERVAL-sensorsSendInterval_networkEnergy.png Binary files differnew file mode 100644 index 0000000..f96d640 --- /dev/null +++ b/src/ns3/plots/SENDINTERVAL-sensorsSendInterval_networkEnergy.png diff --git a/src/ns3/plots/SENDINTERVAL-sensorsSendInterval_sensorsEnergy.png b/src/ns3/plots/SENDINTERVAL-sensorsSendInterval_sensorsEnergy.png Binary files differnew file mode 100644 index 0000000..06e7228 --- /dev/null +++ b/src/ns3/plots/SENDINTERVAL-sensorsSendInterval_sensorsEnergy.png diff --git a/src/ns3/plots/SENDINTERVAL-sensorsSendInterval_totalEnergy.png b/src/ns3/plots/SENDINTERVAL-sensorsSendInterval_totalEnergy.png Binary files differnew file mode 100644 index 0000000..04c9da0 --- /dev/null +++ b/src/ns3/plots/SENDINTERVAL-sensorsSendInterval_totalEnergy.png diff --git a/src/ns3/plots/SENSORSPOS-positionSeed_avgDelay.png b/src/ns3/plots/SENSORSPOS-positionSeed_avgDelay.png Binary files differnew file mode 100644 index 0000000..70d4d90 --- /dev/null +++ b/src/ns3/plots/SENSORSPOS-positionSeed_avgDelay.png diff --git a/src/ns3/plots/SENSORSPOS-positionSeed_totalEnergy.png b/src/ns3/plots/SENSORSPOS-positionSeed_totalEnergy.png Binary files differnew file mode 100644 index 0000000..fb131a1 --- /dev/null +++ b/src/ns3/plots/SENSORSPOS-positionSeed_totalEnergy.png diff --git a/src/ns3/plots/plots.org b/src/ns3/plots/plots.org new file mode 100644 index 0000000..05debb3 --- /dev/null +++ b/src/ns3/plots/plots.org @@ -0,0 +1,25 @@ +#+TITLE: Analysis +#+LATEX_HEADER: \usepackage{fullpage} +#+OPTIONS: toc:nil +\begin{center} +\begin{tabular}{lr} +Parameters & Values\\ +\hline +sensorsPktSize & 5 bytes\\ +sensorsSendInterval & 10s\\ +sensorsNumber & 10\\ +nbHop & 10\\ +linksBandwidth & 10Mbps\\ +linksLatency & 2ms\\ +\end{tabular} +\newline +\end{center} +\includegraphics[width=0.5\linewidth]{SENDINTERVAL-sensorsSendInterval_networkEnergy.png} +\includegraphics[width=0.5\linewidth]{SENDINTERVAL-sensorsSendInterval_sensorsEnergy.png} +\includegraphics[width=0.5\linewidth]{SENSORSPOS-positionSeed_avgDelay.png} +\includegraphics[width=0.5\linewidth]{NBSENSORS-sensorsNumber_totalEnergy.png} +\includegraphics[width=0.5\linewidth]{SENDINTERVAL-sensorsSendInterval_totalEnergy.png} +\includegraphics[width=0.5\linewidth]{SENDINTERVAL-sensorsSendInterval_energyWifi.png} +\includegraphics[width=0.5\linewidth]{sensorsSendInterval-net.png} +\includegraphics[width=0.5\linewidth]{SENSORSPOS-positionSeed_totalEnergy.png} +\includegraphics[width=0.5\linewidth]{sensorsSendInterval-wifi.png} diff --git a/src/ns3/plots/plots.pdf b/src/ns3/plots/plots.pdf Binary files differnew file mode 100644 index 0000000..054173a --- /dev/null +++ b/src/ns3/plots/plots.pdf diff --git a/src/ns3/plots/plots.tex~ b/src/ns3/plots/plots.tex~ new file mode 100644 index 0000000..5ea850d --- /dev/null +++ b/src/ns3/plots/plots.tex~ @@ -0,0 +1,52 @@ +% Created 2019-05-15 mer. 15:23 +% Intended LaTeX compiler: pdflatex +\documentclass[11pt]{article} +\usepackage[utf8]{inputenc} +\usepackage[T1]{fontenc} +\usepackage{graphicx} +\usepackage{grffile} +\usepackage{longtable} +\usepackage{wrapfig} +\usepackage{rotating} +\usepackage[normalem]{ulem} +\usepackage{amsmath} +\usepackage{textcomp} +\usepackage{amssymb} +\usepackage{capt-of} +\usepackage{hyperref} +\usepackage{fullpage} +\date{\today} +\title{Analysis} +\hypersetup{ + pdfauthor={}, + pdftitle={Analysis}, + pdfkeywords={}, + pdfsubject={}, + pdfcreator={Emacs 26.2 (Org mode 9.1.9)}, + pdflang={English}} +\begin{document} + +\maketitle +\begin{center} +\begin{tabular}{lr} +Parameters & Values\\ +\hline +sensorsPktSize & 5 bytes\\ +sensorsSendInterval & 10s\\ +sensorsNumber & 10\\ +nbHop & 10\\ +linksBandwidth & 10Mbps\\ +linksLatency & 2ms\\ +\end{tabular} +\newline +\end{center} +\includegraphics[width=0.5\linewidth]{SENDINTERVAL-sensorsSendInterval_networkEnergy.png} +\includegraphics[width=0.5\linewidth]{SENDINTERVAL-sensorsSendInterval_sensorsEnergy.png} +\includegraphics[width=0.5\linewidth]{SENSORSPOS-positionSeed_avgDelay.png} +\includegraphics[width=0.5\linewidth]{NBSENSORS-sensorsNumber_totalEnergy.png} +\includegraphics[width=0.5\linewidth]{SENDINTERVAL-sensorsSendInterval_totalEnergy.png} +\includegraphics[width=0.5\linewidth]{SENDINTERVAL-sensorsSendInterval_energyWifi.png} +\includegraphics[width=0.5\linewidth]{sensorsSendInterval-net.png} +\includegraphics[width=0.5\linewidth]{SENSORSPOS-positionSeed_totalEnergy.png} +\includegraphics[width=0.5\linewidth]{sensorsSendInterval-wifi.png} +\end{document} diff --git a/src/ns3/plots/sensorsSendInterval-net.png b/src/ns3/plots/sensorsSendInterval-net.png Binary files differnew file mode 100644 index 0000000..f3ed7e6 --- /dev/null +++ b/src/ns3/plots/sensorsSendInterval-net.png diff --git a/src/ns3/plots/sensorsSendInterval-wifi.png b/src/ns3/plots/sensorsSendInterval-wifi.png Binary files differnew file mode 100644 index 0000000..7dc3508 --- /dev/null +++ b/src/ns3/plots/sensorsSendInterval-wifi.png diff --git a/src/ns3/simulate.org b/src/ns3/simulate.org new file mode 100644 index 0000000..b6674d4 --- /dev/null +++ b/src/ns3/simulate.org @@ -0,0 +1,498 @@ + + + +* Run simulations + To run all the simulations, execute the following call: + #+NAME: runSim + #+CALL: runBW(lat=runLat(nbSens=runNbSensors(nbHop=runNbHop()))) + + #+RESULTS: runSim + +** Experiments + +*** Sensors Position + #+NAME: runSensorsPos + #+BEGIN_SRC bash :noweb yes :results output + <<singleRun>> + simKey="SENSORSPOS" + for sensorsNumber in $(seq 5 2 15) + do + for positionSeed in $(seq 1 10) + do + run + done + done + #+END_SRC + +*** Sensors Send Interval + #+NAME: runSendInterval + #+BEGIN_SRC bash :noweb yes :results output + <<singleRun>> + simKey="SENDINTERVAL" + for sensorsNumber in $(seq 5 2 15) + do + for sensorsSendInterval in $(seq 10 10 100) + do + run + done + done + #+END_SRC + +*** Bandwidth + #+NAME: runBW + #+BEGIN_SRC bash :noweb yes :results output + <<singleRun>> + simKey="BW" + for sensorsNumber in $(seq 1 10) + do + for linksBandwidth in $(seq 10 20 100) + do + run + done + done + #+END_SRC + + #+RESULTS: runBW + + #+RESULTS: + +*** Latency + #+NAME: runLat + #+BEGIN_SRC bash :noweb yes :results output + <<singleRun>> + simKey="LATENCY" + for sensorsNumber in $(seq 1 10) + do + for linksLatency in $(seq 1 1 10) + do + run + done + done + #+END_SRC + + #+RESULTS: runLat + + #+RESULTS: + +*** Number of sensors + #+NAME: runNbSensors + #+BEGIN_SRC bash :noweb yes :results output + <<singleRun>> + simKey="NBSENSORS" + for sensorsNumber in $(seq 1 15) + do + run + done + #+END_SRC + + #+RESULTS: + +*** Number of Hop + #+NAME: runNbHop + #+BEGIN_SRC bash :noweb yes :results output + <<singleRun>> + simKey="NBHOP" + for sensorsNumber in $(seq 1 10) + do + for nbHop in $(seq 1 10) + do + run + done + done + #+END_SRC + + #+RESULTS: runNbHop + + +** Single Run + + #+NAME: singleRun + #+BEGIN_SRC bash :eval never :noweb yes :results output + simulator="simulator/simulator" + parseEnergyScript="./parseEnergy.awk" + parseDelayScript="./parseDelay.awk" + logFolder="logs/" + export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${NS3_PATH}/build/lib + + # Default Parameters + sensorsSendInterval=1 # DON'T GO BELOW 1 SECONDS !!!!!!! Simulator will stay stuck + sensorsPktSize=192 # 1 byte temperature (-128 à +128 °C) and 4Byte sensorsId + sensorsNumber=5 + nbHop=10 # Cf paper AC/Yunbo + linksBandwidth=10000 # 10Ge links (to be coherent with energy values of ECOFEN/literature) + linksLatency=11 + positionSeed=5 + simKey="NOKEY" + + run () { + # If another function want to handle simulation (tipically used on g5k) + type -t handleSim > /dev/null && { handleSim; return; } + + local logFile="${logFolder}/${simKey}_${sensorsSendInterval}SSI_${sensorsPktSize}SPS_${sensorsNumber}SN_${nbHop}NH_${linksBandwidth}LB_${linksLatency}LL_${positionSeed}PS.org" + [ -f "$logFile" ] && return + local simCMD="$simulator --sensorsSendInterval=${sensorsSendInterval} --sensorsPktSize=${sensorsPktSize} --sensorsNumber=${sensorsNumber} --nbHop=${nbHop} --linksBandwidth=${linksBandwidth} --linksLatency=${linksLatency} --positionSeed=${positionSeed} 2>&1" + local log=$(bash -c "$simCMD") + + # Compute some metrics + energyLog=$(echo "$log" | $parseEnergyScript) + avgDelay=$(echo "$log" | $parseDelayScript) + totalEnergy=$(echo "$energyLog" | awk 'BEGIN{power=0;FS=","}NR!=1{power+=$2}END{print(power)}') + sensorsEnergy=$(echo "$energyLog" |awk -F',' 'BEGIN{sumW=0}$1<0{sumW+=$2}END{print sumW}') + networkEnergy=$(echo "$energyLog" |awk -F',' 'BEGIN{sumN=0}$1>=0{sumN+=$2}END{print sumN}') + nbPacketCloud=$(echo "$log"|grep -c "CloudSwitch receive") + nbNodes=$(echo "$log"|awk '/Simulation used/{print($3)}') + ns3Version=$(echo "$log"|awk '/NS-3 Version/{print($3)}') + + # Save logs + echo -e "#+TITLE: $(date) ns-3 (version ${ns3Version}) simulation\n" > $logFile + echo "* Environment Variables" >> $logFile + env >> $logFile + echo "* Full Command" >> $logFile + echo "$simCMD" >> $logFile + echo "* Output" >> $logFile + echo "$log" >> $logFile + echo "* Energy CSV (negative nodeId = WIFI, 0 = AP (Wireless+Wired), positive nodeId = ECOFEN" >> $logFile + echo "$energyLog" >> $logFile + echo "* Metrics" >> $logFile + echo "-METRICSLINE- sensorsSendInterval:${sensorsSendInterval} sensorsPktSize:${sensorsPktSize} sensorsNumber:${sensorsNumber} nbHop:${nbHop} linksBandwidth:${linksBandwidth} linksLatency:${linksLatency} totalEnergy:$totalEnergy nbPacketCloud:$nbPacketCloud nbNodes:$nbNodes avgDelay:${avgDelay} ns3Version:${ns3Version} simKey:${simKey} positionSeed:${positionSeed} sensorsEnergy:${sensorsEnergy} networkEnergy:${networkEnergy}" >> $logFile + } + + #+END_SRC + +** Grid 5000 +*** Master Node Script + This code generate and distribute simulation argument to the slave worker nodes and + run start their simulations processes: + #+BEGIN_SRC sh :tangle ./g5k-root.sh :shebang "#!/bin/bash" :noweb yes + ##### Arguments ##### + nHost=20 # At least 20 host x) + nProcesses=3 # Max number of parrallel simulations (don't go too high, your process will be killed (arround 8)) + nHours=4 # Reservation duration + simArgsLoc=~/args/ # Don't change this path witouth changing it in workder scripts + finishedFile="$simArgsLoc/finished-microBenchmarks.txt" + logsFinalDst=~/logs/ + ##################### + + # Check + [ "$1" == "subscribe" ] && subscribe=1 ||subscribe=0 + [ "$1" == "deploy" ] && deploy=1 || deploy=0 + [ "$1" == "-p" ] && progress=1 || progress=0 + + handleSim () { + [ -z "${argId}" ] && argId=1 || argId=$(( argId + 1 )) + outF="$simArgsLoc/${argId}.sh" # Args file based on host name (avoid conflict) + + # Add Shebang + echo '#!/bin/bash' > $outF + echo "finishedFile=\"$finishedFile\"" >> $outF + echo "nProcesses=$nProcesses" >> $outF + echo "logsFinalDst=\"$logsFinalDst\"" >> $outF + # Save arguments + echo "sensorsSendInterval=${sensorsSendInterval}" >> $outF + echo "sensorsPktSize=${sensorsPktSize}" >> $outF + echo "nbHop=${nbHop}" >> $outF + echo "simKey=\"${simKey}\"" >> $outF + echo "sensorsNumber=${sensorsNumber}" >> $outF + echo "linksLatency=${linksLatency}" >> $outF + echo "sensorsNumber=${sensorsNumber}" >> $outF + echo "linksBandwidth=${linksBandwidth}" >> $outF + echo "positionSeed=${positionSeed}" >> $outF + } + + + # Start subscribe/deploy + if [ $subscribe -eq 1 ] + then + echo "Starting oarsub..." + oarsub -l host=$nHost,walltime=$nHours 'sleep "10d"' # Start reservation + echo "Please join your node manually when your reservation is ready by using oarsub -C <job-id>" + exit 0 + elif [ $deploy -eq 1 ] + then + echo "Starting deployment..." + + ##### Usefull Variables ##### + wai=$(dirname "$(readlink -f $0)") # Where Am I ? + hostList=($(cat $OAR_NODE_FILE | uniq)) + ############################# + + # Initialize logsFinalDst + mkdir -p $logsFinalDst + rm -rf $logsFinalDst/* # Clean log dst just in case (it is dangerous but avoid conflict) + mkdir -p $simArgsLoc + rm -rf $simArgsLoc/* # Clean old args + + # Add your simulation code block here + <<runNbSensors>> + <<runSendInterval>> + <<runSensorsPos>> + + # Distribute argument according to subsribed nodes + cd $simArgsLoc + curHostId=0 + for file in $(find ./ -type f) + do + [ $curHostId -eq $nHost ] && curHostId=0 + mv -- ${file} ${hostList[$curHostId]}-$(basename ${file}) + curHostId=$(( curHostId + 1 )) + done + cd - + + + # Run simulations + echo "Host who finished their work:" > $finishedFile + for host in ${hostList[@]} + do + echo "Start simulations on node $host" + oarsh lguegan@$host bash g5k-worker.sh & + done + + exit 0 + elif [ $progress -eq 1 ] + then + alreadyFinished=$(cat $finishedFile| tail -n +2| wc -l) + percent=$(echo $alreadyFinished $nHost| awk '{print $1/$2*100}') + echo "Progression: " $alreadyFinished/$nHost "(${percent}%)" + else + echo "Invalid arguments, make sure you know what you are doing !" + exit 1 + fi + #+END_SRC +*** Worker Node Script + Almost like the [[microBenchmarksSingle][single run script]] but with additionnal code to handle g5k simulation platform (arguments,logs etc..). + #+BEGIN_SRC sh :tangle ./g5k-worker.sh :shebang "#!/bin/bash" :noweb yes + export NS3_PATH=~/.bin/ns-3/ns-3.29/ + g5kLogFolder="/tmp/logs/" + mkdir -p $g5kLogFolder # Create log folder just in case + rm -rf $g5kLogFolder/* # Clean previous logs just in case + + hostname=$(hostname) + + # Run simulations with sourced arguments :D + simArgsLoc=~/args/ # Don't change this path without changing it in root scripts + + argsId=0 + argsFile="$simArgsLoc/${hostname}-args-${argsId}.sh" # Arguments generated by Root Node + curNProcesses=0 # Start with no processes + for argsFile in $(find $simArgsLoc -type f -name "$hostname*") + do + <<singleRun>> + logFolder=$g5kLogFolder # Don't forget override default g5kLogFolder + source $argsFile # Fetch argument + run & # Run async + ((curNProcesses+=1)) # Increase by 2 + [ $curNProcesses -ge $nProcesses ] && { curNProcesses=0; wait; } + done + wait # Wait until the end of all simulations + + cp -r $g5kLogFolder/* "$logsFinalDst" # Fetch log from tmp into nfs + echo $(hostname) >> $finishedFile # Just say I finished + #+END_SRC + +* Logs Analysis + To Generate all the plots, please execute the following line: + #+NAME: runAnalysis + #+CALL: plotToPDF(plots=genAllPlots(data=logToCSV())) + + #+RESULTS: runAnalysis + +** R Scripts +*** Generate all plots script + Available variables: + |---------------------| + | Name | + |---------------------| + | sensorsSendInterval | + | sensorsPktSize | + | sensorsNumber | + | nbHop | + | linksBandwidth | + | linksLatency | + | totalEnergy | + | nbPacketCloud | + | nbNodes | + | avgDelay | + | simKey | + |---------------------| + + #+NAME: genAllPlots + #+BEGIN_SRC R :noweb yes :results output + <<RUtils>> +# easyPlotGroup("linksLatency","totalEnergy", "LATENCY","sensorsNumber") +# easyPlotGroup("linksBandwidth","totalEnergy", "BW","sensorsNumber") + easyPlot("sensorsNumber","totalEnergy", "NBSENSORS") + easyPlotGroup("positionSeed", "totalEnergy","SENSORSPOS","sensorsNumber") + easyPlotGroup("positionSeed", "avgDelay","SENSORSPOS","sensorsNumber") + easyPlotGroup("sensorsSendInterval","sensorsEnergy","SENDINTERVAL","sensorsNumber") + easyPlotGroup("sensorsSendInterval","networkEnergy","SENDINTERVAL","sensorsNumber") + + #+END_SRC + + #+RESULTS: genAllPlots + +*** R Utils + RUtils is intended to load logs (data.csv) and providing + simple plot function for them. + + #+NAME: RUtils + #+BEGIN_SRC R :eval never + library("tidyverse") + + # Fell free to update the following + labels=c(nbNodes="Number of nodes",sensorsNumber="Number of sensors",totalEnergy="Total Energy (J)", + nbHop="Number of hop (AP to Cloud)", linksBandwidth="Links Bandwidth (Mbps)", avgDelay="Average Application Delay (s)", + linksLatency="Links Latency (ms)", sensorsSendInterval="Sensors Send Interval (s)", positionSeed="Position Seed", + sensorsEnergy="Sensors Wifi Energy Consumption (J)", networkEnergy="Network Energy Consumption (J)") + + # Load Data + data=read_csv("logs/data.csv") + + # Get label according to varName + getLabel=function(varName){ + if(is.na(labels[varName])){ + return(varName) + } + return(labels[varName]) + } + + easyPlot=function(X,Y,KEY){ + curData=data%>%filter(simKey==KEY) + stopifnot(NROW(curData)>0) + ggplot(curData,aes_string(x=X,y=Y))+geom_point()+geom_line()+xlab(getLabel(X))+ylab(getLabel(Y)) + ggsave(paste0("plots/",KEY,"-",X,"_",Y,".png")) + } + + easyPlotGroup=function(X,Y,KEY,GRP){ + curData=data%>%filter(simKey==KEY) %>% mutate(!!GRP:=as.character(UQ(rlang::sym(GRP)))) # %>%mutate(sensorsNumber=as.character(sensorsNumber)) + stopifnot(NROW(curData)>0) + ggplot(curData,aes_string(x=X,y=Y,color=GRP,group=GRP))+geom_point()+geom_line()+xlab(getLabel(X))+ylab(getLabel(Y)) + labs(color = getLabel(GRP)) + ggsave(paste0("plots/",KEY,"-",X,"_",Y,".png")) + } + #+END_SRC + +** Plots -> PDF + Merge all plots in plots/ folder into a pdf file. + #+NAME: plotToPDF + #+BEGIN_SRC bash :results output :noweb yes + orgFile="plots/plots.org" + <<singleRun>> # To get all default arguments + + # Write helper function + function write { + echo "$1" >> $orgFile + } + + echo "#+TITLE: Analysis" > $orgFile + write "#+LATEX_HEADER: \usepackage{fullpage}" + write "#+OPTIONS: toc:nil" + # Default arguments + write '\begin{center}' + write '\begin{tabular}{lr}' + write 'Parameters & Values\\' + write '\hline' + write "sensorsPktSize & ${sensorsPktSize} bytes\\\\" + write "sensorsSendInterval & ${sensorsSendInterval}s\\\\" + write "sensorsNumber & ${sensorsNumber}\\\\" + write "nbHop & ${nbHop}\\\\" + write "linksBandwidth & ${linksBandwidth}Mbps\\\\" + write "linksLatency & ${linksLatency}ms\\\\" + write '\end{tabular}' + write '\newline' + write '\end{center}' + + for plot in $(find plots/ -type f -name "*.png") + do + write "\includegraphics[width=0.5\linewidth]{$(basename ${plot})}" + done + + # Export to pdf + emacs $orgFile --batch -f org-latex-export-to-pdf --kill + #+END_SRC + + #+RESULTS: + +** Log -> CSV + logToCSV extract usefull data from logs and put them into logs/data.csv. + + #+NAME: logToCSV + #+BEGIN_SRC bash :results none + csvOutput="logs/data.csv" + + # First save csv header line + aLog=$(find logs/ -type f -name "*.org"|head -n 1) + metrics=$(cat $aLog|grep "\-METRICSLINE\-"|sed "s/-METRICSLINE-//g") + echo $metrics | awk '{for(i=1;i<=NF;i++){split($i,elem,":");printf(elem[1]);if(i<NF)printf(",");else{print("")}}}' > $csvOutput + + # Second save all values + for logFile in $(find logs/ -type f -name "*.org") + do + metrics=$(cat $logFile|grep "\-METRICSLINE\-"|sed "s/-METRICSLINE-//g") + echo $metrics | awk '{for(i=1;i<=NF;i++){split($i,elem,":");printf(elem[2]);if(i<NF)printf(",");else{print("")}}}' >> $csvOutput + done + #+END_SRC + + + + + + +** Custom Plots + + #+NAME: ssiNet + #+BEGIN_SRC R :noweb yes :results graphics :file plots/sensorsSendInterval-net.png + <<RUtils>> + + data%>%filter(simKey=="SENDINTERVAL",sensorsNumber==20) %>% ggplot(aes(x=sensorsSendInterval,y=networkEnergy))+xlab(getLabel("sensorsSendInterval"))+ylab(getLabel("networkEnergy"))+ + geom_line()+labs(title="For 20 sensors") + ggsave("plots/sensorsSendInterval-net.png",dpi=80) + #+END_SRC + + #+RESULTS: + [[file:plots/sensorsSendInterval-net.png]] + + + #+NAME: ssiWifi + #+BEGIN_SRC R :noweb yes :results graphics :file plots/sensorsSendInterval-wifi.png + <<RUtils>> + data%>%filter(simKey=="SENDINTERVAL",sensorsNumber==20) %>% ggplot(aes(x=sensorsSendInterval,y=sensorsEnergy))+xlab(getLabel("sensorsSendInterval"))+ylab(getLabel("sensorsEnergy"))+ + geom_line() + geom_line()+labs(title="For 20 sensors") + ggsave("plots/sensorsSendInterval-wifi.png",dpi=80) + #+END_SRC + + #+RESULTS: ssiWifi + [[file:plots/sensorsSendInterval-wifi.png]] + + #+RESULTS: + [[file:plots/sensorsSendInterval.png]] + + + + + + + #+BEGIN_SRC R :results graphics :noweb yes :file plot-final.png :session *R* + <<RUtils>> + simTime=1800 + + # Network + data=read_csv("logs/data.csv") + data=data%>%filter(simKey=="NBSENSORS") + dataC5=data%>%filter(sensorsNumber==5)%>% mutate(energy=networkEnergy/simTime) %>%select(energy,sensorsNumber) + dataC10=data%>%filter(sensorsNumber==10)%>%mutate(energy=networkEnergy/simTime) %>%select(energy,sensorsNumber) + dataNet=rbind(dataC5,dataC10)%>%mutate(type="Network") + + # Network + dataS5=data%>%filter(sensorsNumber==5)%>% mutate(energy=sensorsEnergy/simTime) %>%select(energy,sensorsNumber) + dataS10=data%>%filter(sensorsNumber==10)%>%mutate(energy=sensorsEnergy/simTime) %>%select(energy,sensorsNumber) + dataS=rbind(dataS5,dataS10)%>%mutate(type="Sensors") + + data=rbind(dataNet,dataS)%>%mutate(sensorsNumber=as.character(sensorsNumber)) + + ggplot(data)+geom_bar(aes(x=sensorsNumber,y=energy,fill=type),stat="identity")+xlab("Sensors Number")+ylab("Power Consumption (W)")+guides(fill=guide_legend(title="Part")) + ggsave("plot-final.png",dpi=80) + + #+END_SRC + + #+RESULTS: + [[file:plot-final.png]] + diff --git a/src/ns3/simulator/simulator b/src/ns3/simulator/simulator Binary files differnew file mode 100755 index 0000000..06e6322 --- /dev/null +++ b/src/ns3/simulator/simulator |
