commit 4411d5800eddf536866515c184cd7589ca5c9b0b Author: Gaetan Longree Date: Fri May 11 15:51:48 2018 +0200 First commit diff --git a/BENCHMARKING/README.md b/BENCHMARKING/README.md new file mode 100644 index 0000000..5fdd0b2 --- /dev/null +++ b/BENCHMARKING/README.md @@ -0,0 +1,62 @@ +# Benchmarking + +This section provides the script to launch and reproduce the benchmarks perfromed for this project (and whoses results are posted on the root README file). + +## Preparing the environment + +Prior to launching the benchmarks, you must launch the [pre deployment script](https://git.cetic.be/stages/unikernels/blob/feature/stagelongree2018/DEPLOYMENT/pre_deployment_installation.sh) provided in the DEPLOYMENT folder. + +Then you must install the benchmarking tools using the [install\_bench\_tools.sh](https://git.cetic.be/stages/unikernels/blob/feature/stagelongree2018/BENCHMARKING/install_bench_tools.sh) script. +This script will install the following tools: +* dnsperf and its dependencies for the DNS benchmark (by Nominum) +* wrk2 for the web server benchmark (by Gil Tene, based on original wrk by Will Glozer) + +## Launching the target instance + +To launch an instance to benchmark, launch the **bench_*.sh** scripts: +* bench\_container\_dns.sh +* bench\_container\_web.sh +* bench\_unikernel\_dns.sh +* bench\_unikernel\_web.sh + +The scripts will: +* build the unikernel/container +* stop all running VMs and containers +* launch the unikernel/container, attaching it to the default network + +If you're launching a container, the ports will be mapped on launch. +If you're launching a unikernel, two rules will be inserted in iptables to allow port forwarding to the internal network. + +## Launching the benchmark + +The benchmark scripts are written in python and make use of the tools installed with the install\_bench\_tools.sh script. + +The web and DNS server benchmarking scripts are written to use 4 threads and simulate 100 virtual connections to the target server. + +### Web server benchmark + +To launch the web server, user `python3 web_unik_benchmark.py [server_ip_address]`. + +The benchmark will send HTTP requests to the server for 5 minutes, starting at a pace of 100 queries per second. After 5 minutes it will save the data in a .csv file and then will relaunch the process incrementing by another 100 queries per second. + +### DNS server benchmark + +To launch the web server, user `python3 web__benchmark.py [server_ip_address]`. + +The benchmark will send DNS requests to the server for 5 minutes, starting at a pace of 100 queries per second. After 5 minutes it will save the data in a .csv file and then will relaunch the process incrementing by another 100 queries per second. + +### Boot time benchmark + +To launch the web server, user `python3 startup__benchmark.py [starting number of instances]`. + +The benchmark will start by building and launching the given number of VM or container instances. Then, for 20 minutes, it will send the stop a random instance, send the start command and calculate the time between the start command being sent, and when the target instance responds to a single ping. For each stop/start process, the recorded time is then inserted into a csv file. After 20 minutes, the number of instances is incremented by 10 and the process is repeated. This process repeats itself until 140 instances are launched. + +## Cleaning up the environment + +The individual instance scripts do not stop the instances launched, this needs to be done manually. + +However, each instance start script will stop the currently running containers and virtual machines, as will the boot time benchmark scripts. + +To clean up the iptable rules created for the unikernels use the `./bench_unikernel_cleanup.sh` script. + +To clean up all the instances and iptable rule use the `./cleanup_all.sh` script. diff --git a/BENCHMARKING/RESULTS/combined.xlsx b/BENCHMARKING/RESULTS/combined.xlsx new file mode 100644 index 0000000..3c68fca Binary files /dev/null and b/BENCHMARKING/RESULTS/combined.xlsx differ diff --git a/BENCHMARKING/RESULTS/dns_cont_benchmark.csv b/BENCHMARKING/RESULTS/dns_cont_benchmark.csv new file mode 100644 index 0000000..2c51b2b --- /dev/null +++ b/BENCHMARKING/RESULTS/dns_cont_benchmark.csv @@ -0,0 +1,28 @@ +TEST_RUN,QUERIES_SENT,QUERIES_COMPLETED,QUERIES_LOST,QUERIES_PER_SECOND,AVG_LATENCY_SECONDS,MIN,MAX,LATENCY_STD_DEV_SECONDS +1,30300,30300,0,100.999942,0.000435,0.000677,0.038042,0.000463 +2,60600,60600,0,201.999868,0.000413,0.000548,0.045776,0.000575 +3,90900,90900,0,302.999799,0.000410,0.000522,0.045355,0.000601 +4,120000,120000,0,399.999763,0.000469,0.000531,0.047507,0.000620 +5,150300,150300,0,500.999641,0.000401,0.000499,0.050776,0.000639 +6,180600,180600,0,601.999573,0.000399,0.000448,0.048009,0.000649 +7,210900,210900,0,702.999531,0.000397,0.000436,0.048220,0.000649 +8,240000,240000,0,799.999397,0.000457,0.000530,0.050598,0.000664 +9,270300,270300,0,900.999381,0.000405,0.000447,0.049469,0.000682 +10,300600,300600,0,1001.999476,0.000387,0.000452,0.048770,0.000673 +11,330900,330900,0,1102.999158,0.000385,0.000463,0.051058,0.000625 +12,360000,360000,0,1199.999244,0.000468,0.000455,0.064912,0.000742 +13,390300,390300,0,1300.999553,0.000407,0.000430,0.053302,0.000715 +14,420600,420600,0,1401.999248,0.000368,0.000443,0.050178,0.000646 +15,450900,450900,0,1502.999083,0.000398,0.000420,0.049944,0.000696 +16,480000,480000,0,1599.998837,0.000477,0.000455,0.062380,0.000803 +17,510300,510300,0,1700.998883,0.000386,0.000421,0.051476,0.000672 +18,540600,540600,0,1801.998793,0.000376,0.000405,0.061594,0.000691 +19,570900,570900,0,1902.998744,0.000401,0.000392,0.074226,0.000725 +20,600000,600000,0,1999.999260,0.000446,0.000447,0.060142,0.000730 +21,630300,630300,0,2100.998823,0.000386,0.000388,0.055958,0.000697 +22,660600,660600,0,2201.998349,0.000384,0.000394,0.063996,0.000722 +23,690900,690900,0,2302.998572,0.000389,0.000395,0.052586,0.000711 +24,720000,720000,0,2399.998472,0.000435,0.000440,0.057137,0.000699 +25,750300,750300,0,2500.998533,0.000402,0.000391,0.072312,0.000743 +26,780600,780600,0,2601.998439,0.000385,0.000389,0.064135,0.000734 +27,810900,810900,0,2702.998423,0.000386,0.000393,0.073673,0.000745 diff --git a/BENCHMARKING/RESULTS/dns_unik_benchmark.csv b/BENCHMARKING/RESULTS/dns_unik_benchmark.csv new file mode 100644 index 0000000..fad4a36 --- /dev/null +++ b/BENCHMARKING/RESULTS/dns_unik_benchmark.csv @@ -0,0 +1,28 @@ +TEST_RUN,QUERIES_SENT,QUERIES_COMPLETED,QUERIES_LOST,QUERIES_PER_SECOND,AVG_LATENCY_SECONDS,MIN,MAX,LATENCY_STD_DEV_SECONDS +1,30300,30300,0,100.999941,0.006355,0.005415,0.098812,0.002519 +2,60600,60600,0,201.999860,0.005617,0.005722,0.080283,0.002087 +3,90900,90900,0,302.999889,0.005715,0.005411,0.101761,0.002100 +4,120000,120000,0,399.999672,0.006401,0.005320,0.158964,0.001903 +5,150300,150300,0,500.999711,0.005402,0.004774,0.271349,0.003626 +6,180600,180600,0,601.999603,0.006268,0.004755,0.725090,0.007226 +7,210900,210900,0,702.999536,0.011069,0.004425,0.618359,0.015394 +8,240000,240000,0,799.937413,0.037150,0.004729,0.615609,0.036375 +9,253892,253892,0,846.044238,0.118990,0.041761,8.319091,0.055582 +10,255867,255867,0,852.822877,0.118098,0.046127,5.168513,0.024260 +11,255428,255428,0,851.255666,0.118290,0.046994,4.080020,0.019123 +12,253791,253791,0,845.691776,0.119118,0.046585,7.608933,0.036147 +13,254861,254861,0,849.297151,0.118604,0.042165,4.014139,0.018720 +14,254055,254055,0,846.612175,0.118889,0.037720,7.076644,0.033647 +15,255951,255951,0,852.928016,0.118049,0.035549,0.581656,0.006604 +16,254741,254741,0,849.026353,0.118526,0.044648,2.758404,0.013401 +17,255579,255579,0,851.654708,0.118254,0.037696,0.587303,0.006576 +18,250233,250233,0,834.063092,0.120648,0.050919,6.691459,0.042768 +19,253722,253722,0,845.695581,0.119023,0.051268,0.693072,0.007301 +20,252384,252384,0,841.134621,0.119705,0.042426,7.830838,0.039162 +21,255698,255698,0,852.217853,0.118158,0.043026,0.596498,0.006608 +22,251706,251706,0,838.762075,0.120080,0.042971,7.658614,0.042178 +23,254452,254452,0,848.033594,0.118793,0.047975,0.570417,0.006341 +24,252446,252446,0,841.183336,0.119791,0.046854,7.977354,0.037990 +25,253242,253242,0,843.946885,0.119344,0.046943,0.708790,0.006546 +26,252173,252173,0,840.376755,0.119819,0.049304,6.509316,0.030894 +27,250928,250928,0,836.353101,0.120345,0.042280,6.734916,0.037482 diff --git a/BENCHMARKING/RESULTS/startup_cont_benchmark.csv b/BENCHMARKING/RESULTS/startup_cont_benchmark.csv new file mode 100644 index 0000000..b4e1d59 --- /dev/null +++ b/BENCHMARKING/RESULTS/startup_cont_benchmark.csv @@ -0,0 +1,1068 @@ +NBR_OF_GUESTS,GUEST_STOPPED,STARTUP_TIME_SECONDS +10,VM_7,0.005545 +10,VM_6,0.006002 +10,VM_3,0.005724 +10,VM_8,0.004414 +10,VM_7,0.006721 +10,VM_7,0.004554 +10,VM_2,0.0056 +10,VM_7,0.005106 +10,VM_1,0.005371 +10,VM_3,0.005556 +10,VM_8,0.005782 +10,VM_9,0.006337 +10,VM_8,0.006104 +10,VM_9,0.005567 +10,VM_0,0.005403 +10,VM_2,0.00571 +10,VM_1,0.007848 +10,VM_9,0.004975 +10,VM_6,0.00632 +10,VM_2,0.006977 +10,VM_2,0.009633 +10,VM_0,0.005214 +10,VM_4,0.006876 +10,VM_9,0.007372 +10,VM_3,0.006119 +10,VM_9,0.005278 +10,VM_9,0.006147 +10,VM_4,0.006082 +10,VM_5,0.013269 +10,VM_5,0.005984 +10,VM_1,0.006004 +10,VM_8,0.005764 +10,VM_2,0.005029 +10,VM_1,0.010681 +10,VM_1,0.005064 +10,VM_3,0.004942 +10,VM_5,0.006298 +10,VM_8,0.006918 +10,VM_6,0.005915 +10,VM_8,0.00519 +10,VM_7,0.006729 +10,VM_9,0.005906 +10,VM_3,0.006618 +10,VM_7,0.007958 +10,VM_6,0.004867 +10,VM_4,0.012777 +10,VM_5,0.005884 +10,VM_9,0.005034 +10,VM_2,0.005835 +10,VM_4,0.005421 +10,VM_1,0.006554 +10,VM_4,0.005275 +10,VM_8,0.005959 +10,VM_1,0.006517 +10,VM_1,0.007048 +10,VM_3,0.019142 +10,VM_2,0.006845 +10,VM_5,0.017689 +10,VM_8,0.006113 +10,VM_3,0.005903 +10,VM_0,0.004584 +10,VM_3,0.010075 +10,VM_9,0.011123 +10,VM_1,0.006544 +10,VM_5,0.006979 +10,VM_0,0.00478 +10,VM_8,0.00538 +10,VM_9,0.005784 +10,VM_2,0.00626 +10,VM_7,0.005714 +10,VM_1,0.006642 +10,VM_6,0.006585 +10,VM_4,0.014057 +10,VM_5,0.004188 +10,VM_4,0.006646 +10,VM_5,0.004923 +10,VM_7,0.00443 +10,VM_3,0.004846 +20,VM_5,0.004239 +20,VM_0,0.005422 +20,VM_12,0.005913 +20,VM_2,0.005359 +20,VM_13,0.006721 +20,VM_19,0.004208 +20,VM_15,0.005432 +20,VM_14,0.004884 +20,VM_18,0.005821 +20,VM_16,0.017886 +20,VM_8,0.00556 +20,VM_18,0.003964 +20,VM_7,0.005532 +20,VM_5,0.004855 +20,VM_7,0.005807 +20,VM_7,0.006134 +20,VM_7,0.005669 +20,VM_17,0.004062 +20,VM_0,0.006276 +20,VM_12,0.005716 +20,VM_18,0.006077 +20,VM_3,0.007004 +20,VM_11,0.005851 +20,VM_12,0.005258 +20,VM_16,0.007432 +20,VM_11,0.005711 +20,VM_6,0.008029 +20,VM_13,0.005397 +20,VM_3,0.005484 +20,VM_16,0.006758 +20,VM_19,0.008466 +20,VM_15,0.006203 +20,VM_10,0.010629 +20,VM_18,0.005271 +20,VM_13,0.006732 +20,VM_13,0.00495 +20,VM_13,0.005344 +20,VM_6,0.005887 +20,VM_12,0.007968 +20,VM_7,0.004574 +20,VM_16,0.006039 +20,VM_10,0.005547 +20,VM_4,0.005833 +20,VM_5,0.005572 +20,VM_13,0.00666 +20,VM_1,0.004872 +20,VM_10,0.006188 +20,VM_16,0.004852 +20,VM_5,0.007977 +20,VM_17,0.005594 +20,VM_13,0.004919 +20,VM_4,0.007081 +20,VM_17,0.005279 +20,VM_2,0.008127 +20,VM_7,0.005499 +20,VM_3,0.006768 +20,VM_13,0.006397 +20,VM_19,0.005332 +20,VM_16,0.005337 +20,VM_10,0.004637 +20,VM_17,0.005281 +20,VM_10,0.006284 +20,VM_1,0.006163 +20,VM_19,0.005039 +20,VM_13,0.00567 +20,VM_16,0.005531 +20,VM_8,0.005021 +20,VM_11,0.005722 +20,VM_17,0.006898 +20,VM_18,0.004515 +20,VM_10,0.005673 +20,VM_8,0.004451 +20,VM_6,0.005668 +20,VM_1,0.005798 +20,VM_2,0.005723 +20,VM_16,0.005628 +30,VM_17,0.005497 +30,VM_14,0.008395 +30,VM_13,0.007278 +30,VM_1,0.01344 +30,VM_22,0.024871 +30,VM_5,0.006226 +30,VM_26,0.005716 +30,VM_20,0.005522 +30,VM_20,0.004282 +30,VM_2,0.005972 +30,VM_19,0.005851 +30,VM_24,0.003039 +30,VM_20,0.00576 +30,VM_13,0.004479 +30,VM_17,0.005992 +30,VM_13,0.009284 +30,VM_16,0.005838 +30,VM_15,0.006378 +30,VM_3,0.005801 +30,VM_17,0.005686 +30,VM_0,0.00571 +30,VM_13,0.005877 +30,VM_27,0.021626 +30,VM_24,0.005324 +30,VM_28,0.019304 +30,VM_4,0.005487 +30,VM_27,0.005814 +30,VM_23,0.022145 +30,VM_22,0.005246 +30,VM_9,0.006332 +30,VM_8,0.007115 +30,VM_18,0.005221 +30,VM_7,0.005274 +30,VM_20,0.005416 +30,VM_11,0.005416 +30,VM_28,0.005922 +30,VM_11,0.005683 +30,VM_18,0.008173 +30,VM_21,0.020847 +30,VM_27,0.005753 +30,VM_21,0.005613 +30,VM_24,0.00987 +30,VM_21,0.006265 +30,VM_1,0.005339 +30,VM_26,0.00537 +30,VM_1,0.007187 +30,VM_29,0.017797 +30,VM_11,0.003756 +30,VM_24,0.00599 +30,VM_24,0.006363 +30,VM_27,0.006124 +30,VM_23,0.005596 +30,VM_17,0.005425 +30,VM_25,0.034057 +30,VM_19,0.005786 +30,VM_10,0.005766 +30,VM_24,0.006455 +30,VM_6,0.006144 +30,VM_9,0.005177 +30,VM_21,0.005681 +30,VM_5,0.004841 +30,VM_22,0.005282 +30,VM_0,0.005286 +30,VM_28,0.008208 +30,VM_10,0.005825 +30,VM_16,0.005703 +30,VM_21,0.006955 +30,VM_8,0.00574 +30,VM_9,0.008162 +30,VM_12,0.005757 +30,VM_27,0.006946 +30,VM_16,0.005112 +30,VM_10,0.006547 +30,VM_9,0.004332 +30,VM_22,0.005681 +30,VM_19,0.005906 +40,VM_12,0.007583 +40,VM_2,0.005628 +40,VM_32,0.02445 +40,VM_29,0.005185 +40,VM_30,0.006581 +40,VM_6,0.005983 +40,VM_17,0.00557 +40,VM_0,0.00735 +40,VM_20,0.005558 +40,VM_38,0.028951 +40,VM_28,0.006051 +40,VM_12,0.005618 +40,VM_7,0.004618 +40,VM_27,0.005814 +40,VM_4,0.009118 +40,VM_31,0.011334 +40,VM_24,0.005823 +40,VM_8,0.005881 +40,VM_23,0.006183 +40,VM_27,0.004581 +40,VM_3,0.005337 +40,VM_16,0.004626 +40,VM_4,0.006215 +40,VM_26,0.005536 +40,VM_32,0.006132 +40,VM_34,0.015898 +40,VM_15,0.006234 +40,VM_22,0.006396 +40,VM_17,0.00611 +40,VM_19,0.005066 +40,VM_6,0.005944 +40,VM_25,0.00621 +40,VM_34,0.006678 +40,VM_19,0.00416 +40,VM_14,0.006221 +40,VM_33,0.025413 +40,VM_36,0.005257 +40,VM_34,0.004958 +40,VM_20,0.006995 +40,VM_33,0.005824 +40,VM_26,0.006384 +40,VM_29,0.005073 +40,VM_34,0.005953 +40,VM_33,0.005212 +40,VM_2,0.005442 +40,VM_16,0.005517 +40,VM_24,0.005796 +40,VM_9,0.005931 +40,VM_1,0.005113 +40,VM_6,0.006139 +40,VM_7,0.00521 +40,VM_15,0.006582 +40,VM_34,0.00487 +40,VM_2,0.005072 +40,VM_5,0.006314 +40,VM_6,0.004219 +40,VM_15,0.006459 +40,VM_10,0.004874 +40,VM_20,0.005342 +40,VM_18,0.006433 +40,VM_17,0.006084 +40,VM_9,0.00933 +40,VM_29,0.004551 +40,VM_23,0.006127 +40,VM_1,0.006479 +40,VM_3,0.005396 +40,VM_34,0.004945 +40,VM_6,0.005757 +40,VM_37,0.022602 +40,VM_22,0.005252 +40,VM_34,0.006854 +40,VM_19,0.005727 +40,VM_35,0.008089 +40,VM_37,0.005061 +40,VM_24,0.006932 +40,VM_3,0.006618 +50,VM_7,0.005517 +50,VM_48,0.006434 +50,VM_39,0.024111 +50,VM_35,0.005051 +50,VM_40,0.030847 +50,VM_41,0.019922 +50,VM_19,0.004435 +50,VM_36,0.005576 +50,VM_16,0.006058 +50,VM_41,0.006225 +50,VM_39,0.00659 +50,VM_45,0.020195 +50,VM_39,0.007264 +50,VM_5,0.004696 +50,VM_9,0.005828 +50,VM_24,0.005646 +50,VM_1,0.005628 +50,VM_34,0.00603 +50,VM_27,0.005352 +50,VM_0,0.005724 +50,VM_5,0.006073 +50,VM_39,0.005558 +50,VM_41,0.006172 +50,VM_49,0.021327 +50,VM_4,0.005764 +50,VM_6,0.005283 +50,VM_44,0.018877 +50,VM_37,0.005501 +50,VM_24,0.005727 +50,VM_2,0.005501 +50,VM_43,0.020414 +50,VM_45,0.005029 +50,VM_24,0.00519 +50,VM_8,0.004628 +50,VM_25,0.006069 +50,VM_16,0.007162 +50,VM_11,0.005198 +50,VM_43,0.006221 +50,VM_7,0.006232 +50,VM_30,0.006037 +50,VM_27,0.004827 +50,VM_33,0.006942 +50,VM_41,0.006956 +50,VM_46,0.026356 +50,VM_48,0.005463 +50,VM_17,0.005012 +50,VM_37,0.006333 +50,VM_28,0.005177 +50,VM_48,0.005293 +50,VM_47,0.025524 +50,VM_0,0.005632 +50,VM_41,0.004928 +50,VM_35,0.005724 +50,VM_14,0.003774 +50,VM_49,0.006015 +50,VM_18,0.009594 +50,VM_9,0.006696 +50,VM_23,0.006597 +50,VM_9,0.005575 +50,VM_22,0.006622 +50,VM_25,0.005003 +50,VM_18,0.005287 +50,VM_21,0.00523 +50,VM_25,0.006146 +50,VM_24,0.005531 +50,VM_31,0.005541 +50,VM_32,0.006222 +50,VM_43,0.005231 +50,VM_37,0.005603 +50,VM_21,0.005182 +50,VM_34,0.006672 +50,VM_43,0.008377 +50,VM_7,0.005721 +50,VM_7,0.006687 +50,VM_42,0.011954 +50,VM_39,0.006218 +60,VM_35,0.005259 +60,VM_3,0.005582 +60,VM_11,0.006055 +60,VM_41,0.005669 +60,VM_16,0.005314 +60,VM_16,0.006856 +60,VM_15,0.006484 +60,VM_23,0.005579 +60,VM_53,0.010976 +60,VM_54,0.026014 +60,VM_44,0.006396 +60,VM_11,0.006071 +60,VM_58,0.030679 +60,VM_19,0.004847 +60,VM_59,0.029281 +60,VM_24,0.003928 +60,VM_37,0.006058 +60,VM_22,0.005248 +60,VM_13,0.006312 +60,VM_37,0.003621 +60,VM_53,0.005576 +60,VM_57,0.008582 +60,VM_21,0.0071 +60,VM_22,0.005837 +60,VM_40,0.006104 +60,VM_15,0.005663 +60,VM_7,0.004289 +60,VM_34,0.006171 +60,VM_6,0.005968 +60,VM_49,0.005676 +60,VM_59,0.005772 +60,VM_7,0.007009 +60,VM_43,0.005576 +60,VM_16,0.006028 +60,VM_10,0.007065 +60,VM_31,0.006594 +60,VM_45,0.005988 +60,VM_6,0.008751 +60,VM_51,0.030741 +60,VM_55,0.023613 +60,VM_13,0.004394 +60,VM_18,0.005769 +60,VM_35,0.005893 +60,VM_6,0.006726 +60,VM_37,0.005596 +60,VM_35,0.006606 +60,VM_31,0.014693 +60,VM_10,0.004918 +60,VM_59,0.005583 +60,VM_1,0.005017 +60,VM_59,0.00625 +60,VM_36,0.005905 +60,VM_29,0.005675 +60,VM_25,0.007421 +60,VM_44,0.005269 +60,VM_13,0.004878 +60,VM_1,0.005608 +60,VM_29,0.004293 +60,VM_56,0.025779 +60,VM_40,0.006112 +60,VM_42,0.005871 +60,VM_12,0.004952 +60,VM_13,0.008583 +60,VM_51,0.007122 +60,VM_50,0.009826 +60,VM_49,0.023681 +60,VM_33,0.011649 +60,VM_34,0.022403 +60,VM_55,0.015799 +60,VM_38,0.020244 +60,VM_1,0.022006 +60,VM_21,0.033312 +60,VM_50,0.005308 +60,VM_15,0.02426 +60,VM_6,0.01121 +60,VM_25,0.022779 +60,VM_57,0.008282 +70,VM_7,0.004957 +70,VM_6,0.005691 +70,VM_68,0.010237 +70,VM_45,0.012373 +70,VM_40,0.032779 +70,VM_20,0.028313 +70,VM_53,0.009549 +70,VM_37,0.036077 +70,VM_45,0.005753 +70,VM_27,0.00797 +70,VM_37,0.006005 +70,VM_65,0.02443 +70,VM_44,0.031203 +70,VM_48,0.017968 +70,VM_3,0.032803 +70,VM_4,0.023315 +70,VM_22,0.032589 +70,VM_14,0.006003 +70,VM_17,0.009747 +70,VM_46,0.02226 +70,VM_13,0.005119 +70,VM_66,0.021583 +70,VM_5,0.012542 +70,VM_1,0.004895 +70,VM_44,0.005601 +70,VM_24,0.017416 +70,VM_68,0.012321 +70,VM_38,0.006645 +70,VM_39,0.014548 +70,VM_44,0.004897 +70,VM_42,0.016844 +70,VM_52,0.019842 +70,VM_39,0.006519 +70,VM_55,0.004898 +70,VM_0,0.030665 +70,VM_1,0.004437 +70,VM_16,0.02324 +70,VM_23,0.013668 +70,VM_67,0.033708 +70,VM_68,0.00584 +70,VM_66,0.004915 +70,VM_38,0.005999 +70,VM_7,0.006446 +70,VM_51,0.006931 +70,VM_11,0.031611 +70,VM_14,0.004025 +70,VM_55,0.005658 +70,VM_49,0.004841 +70,VM_8,0.021818 +70,VM_36,0.02359 +70,VM_60,0.005233 +70,VM_20,0.00459 +70,VM_29,0.003766 +70,VM_57,0.005291 +70,VM_61,0.025221 +70,VM_0,0.011606 +70,VM_12,0.007094 +70,VM_12,0.007174 +70,VM_51,0.00624 +70,VM_14,0.013554 +70,VM_64,0.01307 +70,VM_61,0.005975 +70,VM_46,0.005879 +70,VM_53,0.011094 +70,VM_28,0.026992 +70,VM_42,0.004172 +70,VM_5,0.005165 +70,VM_60,0.006445 +70,VM_69,0.003607 +70,VM_59,0.023994 +70,VM_0,0.004886 +70,VM_10,0.032864 +70,VM_62,0.011897 +70,VM_67,0.004896 +70,VM_1,0.005896 +80,VM_67,0.005949 +80,VM_20,0.006457 +80,VM_59,0.006569 +80,VM_64,0.006898 +80,VM_12,0.005593 +80,VM_63,0.004695 +80,VM_3,0.007885 +80,VM_8,0.005983 +80,VM_53,0.005304 +80,VM_68,0.006111 +80,VM_74,0.00986 +80,VM_25,0.005221 +80,VM_76,0.028994 +80,VM_42,0.015613 +80,VM_78,0.012043 +80,VM_15,0.006141 +80,VM_44,0.005167 +80,VM_8,0.005742 +80,VM_74,0.005653 +80,VM_61,0.006143 +80,VM_70,0.02632 +80,VM_64,0.004929 +80,VM_33,0.007394 +80,VM_72,0.011668 +80,VM_74,0.008003 +80,VM_53,0.005693 +80,VM_2,0.024595 +80,VM_40,0.005671 +80,VM_59,0.00592 +80,VM_77,0.029391 +80,VM_77,0.006401 +80,VM_24,0.00566 +80,VM_45,0.006553 +80,VM_26,0.022956 +80,VM_56,0.025696 +80,VM_25,0.006034 +80,VM_50,0.006689 +80,VM_69,0.006909 +80,VM_77,0.005795 +80,VM_30,0.016754 +80,VM_57,0.004983 +80,VM_23,0.007292 +80,VM_44,0.006381 +80,VM_71,0.015437 +80,VM_53,0.005276 +80,VM_4,0.006443 +80,VM_1,0.006236 +80,VM_14,0.005467 +80,VM_30,0.005219 +80,VM_67,0.007325 +80,VM_31,0.010071 +80,VM_39,0.005816 +80,VM_24,0.006563 +80,VM_13,0.00624 +80,VM_14,0.005578 +80,VM_15,0.006082 +80,VM_63,0.005474 +80,VM_72,0.00678 +80,VM_79,0.006951 +80,VM_40,0.005252 +80,VM_22,0.005014 +80,VM_69,0.006269 +80,VM_5,0.005306 +80,VM_69,0.006394 +80,VM_18,0.033364 +80,VM_62,0.005449 +80,VM_64,0.005726 +80,VM_37,0.006002 +80,VM_56,0.005888 +80,VM_19,0.013005 +80,VM_56,0.006435 +80,VM_8,0.005347 +80,VM_46,0.005799 +80,VM_25,0.006074 +80,VM_75,0.022684 +80,VM_44,0.027322 +80,VM_9,0.01492 +90,VM_44,0.00551 +90,VM_60,0.028697 +90,VM_26,0.036664 +90,VM_27,0.027214 +90,VM_5,0.009281 +90,VM_7,0.021962 +90,VM_26,0.006175 +90,VM_53,0.033376 +90,VM_3,0.013883 +90,VM_39,0.021694 +90,VM_57,0.008588 +90,VM_47,0.004674 +90,VM_30,0.017991 +90,VM_13,0.01352 +90,VM_58,0.033956 +90,VM_48,0.010381 +90,VM_59,0.015949 +90,VM_85,0.004447 +90,VM_57,0.005645 +90,VM_57,0.010181 +90,VM_68,0.006865 +90,VM_64,0.011625 +90,VM_67,0.006671 +90,VM_39,0.00566 +90,VM_24,0.008682 +90,VM_89,0.021377 +90,VM_38,0.004842 +90,VM_11,0.032475 +90,VM_58,0.00656 +90,VM_36,0.024161 +90,VM_77,0.028836 +90,VM_61,0.009598 +90,VM_15,0.020836 +90,VM_58,0.007255 +90,VM_8,0.005624 +90,VM_43,0.011547 +90,VM_65,0.019635 +90,VM_36,0.006255 +90,VM_1,0.02899 +90,VM_43,0.006126 +90,VM_33,0.028302 +90,VM_66,0.030367 +90,VM_59,0.006097 +90,VM_24,0.010517 +90,VM_27,0.006438 +90,VM_18,0.027236 +90,VM_14,0.022786 +90,VM_43,0.006476 +90,VM_87,0.033048 +90,VM_41,0.028901 +90,VM_5,0.010425 +90,VM_13,0.006457 +90,VM_89,0.005801 +90,VM_21,0.019315 +90,VM_25,0.006892 +90,VM_21,0.006064 +90,VM_64,0.005512 +90,VM_3,0.005937 +90,VM_67,0.00578 +90,VM_27,0.008058 +90,VM_16,0.017267 +90,VM_28,0.00628 +90,VM_68,0.005863 +90,VM_44,0.010967 +90,VM_54,0.015631 +90,VM_73,0.03316 +90,VM_82,0.031574 +90,VM_84,0.004459 +90,VM_22,0.007764 +90,VM_44,0.005448 +90,VM_35,0.034204 +90,VM_89,0.005523 +90,VM_33,0.005721 +90,VM_8,0.006421 +90,VM_24,0.010369 +100,VM_25,0.005702 +100,VM_56,0.007977 +100,VM_56,0.006331 +100,VM_13,0.010419 +100,VM_85,0.005919 +100,VM_92,0.033522 +100,VM_34,0.02934 +100,VM_64,0.00585 +100,VM_71,0.02966 +100,VM_67,0.009418 +100,VM_57,0.006145 +100,VM_17,0.016008 +100,VM_77,0.005352 +100,VM_98,0.025488 +100,VM_28,0.004464 +100,VM_59,0.006011 +100,VM_83,0.010766 +100,VM_36,0.006899 +100,VM_30,0.006279 +100,VM_2,0.013601 +100,VM_99,0.009566 +100,VM_42,0.021822 +100,VM_67,0.005258 +100,VM_92,0.005614 +100,VM_96,0.004232 +100,VM_94,0.015298 +100,VM_4,0.020057 +100,VM_54,0.006787 +100,VM_1,0.005784 +100,VM_59,0.005841 +100,VM_77,0.005199 +100,VM_92,0.005497 +100,VM_13,0.009653 +100,VM_87,0.005802 +100,VM_34,0.005468 +100,VM_18,0.006621 +100,VM_43,0.00657 +100,VM_56,0.004568 +100,VM_93,0.032599 +100,VM_77,0.004582 +100,VM_88,0.026521 +100,VM_39,0.007976 +100,VM_61,0.005546 +100,VM_8,0.006909 +100,VM_38,0.005482 +100,VM_68,0.005976 +100,VM_19,0.006767 +100,VM_24,0.006735 +100,VM_80,0.009805 +100,VM_11,0.005482 +100,VM_53,0.005367 +100,VM_40,0.029738 +100,VM_72,0.020552 +100,VM_93,0.004656 +100,VM_83,0.005585 +100,VM_0,0.03092 +100,VM_99,0.005999 +100,VM_34,0.005083 +100,VM_61,0.005339 +100,VM_72,0.0055 +100,VM_7,0.005688 +100,VM_64,0.005832 +100,VM_82,0.006253 +100,VM_8,0.007058 +100,VM_41,0.006022 +100,VM_61,0.010844 +100,VM_1,0.006831 +100,VM_41,0.00575 +100,VM_11,0.015686 +100,VM_71,0.020228 +100,VM_38,0.024204 +100,VM_74,0.004026 +100,VM_74,0.005421 +100,VM_31,0.034887 +100,VM_82,0.032354 +100,VM_43,0.006083 +100,VM_30,0.031528 +110,VM_102,0.013193 +110,VM_10,0.028989 +110,VM_63,0.034314 +110,VM_21,0.03157 +110,VM_101,0.004821 +110,VM_63,0.005799 +110,VM_73,0.02606 +110,VM_22,0.025773 +110,VM_50,0.030142 +110,VM_30,0.006646 +110,VM_93,0.016279 +110,VM_19,0.004254 +110,VM_68,0.01749 +110,VM_14,0.004796 +110,VM_74,0.006192 +110,VM_64,0.007189 +110,VM_54,0.008091 +110,VM_59,0.006692 +110,VM_17,0.007767 +110,VM_44,0.006629 +110,VM_83,0.015219 +110,VM_96,0.026843 +110,VM_25,0.029314 +110,VM_45,0.012908 +110,VM_85,0.00826 +110,VM_21,0.005611 +110,VM_58,0.035614 +110,VM_18,0.017948 +110,VM_58,0.006835 +110,VM_72,0.019978 +110,VM_37,0.017125 +110,VM_82,0.005552 +110,VM_61,0.005195 +110,VM_68,0.005837 +110,VM_63,0.006235 +110,VM_66,0.031609 +110,VM_97,0.027523 +110,VM_9,0.024398 +110,VM_8,0.028585 +110,VM_66,0.005711 +110,VM_12,0.022445 +110,VM_15,0.022889 +110,VM_20,0.027323 +110,VM_6,0.009623 +110,VM_77,0.029728 +110,VM_85,0.006677 +110,VM_92,0.030615 +110,VM_51,0.014579 +110,VM_93,0.014365 +110,VM_65,0.01658 +110,VM_83,0.005914 +110,VM_41,0.006326 +110,VM_83,0.005656 +110,VM_45,0.006171 +110,VM_8,0.007398 +110,VM_68,0.005315 +110,VM_11,0.005178 +110,VM_33,0.025385 +110,VM_88,0.030758 +110,VM_22,0.005697 +110,VM_61,0.004897 +110,VM_37,0.006176 +110,VM_43,0.00643 +110,VM_12,0.009062 +110,VM_53,0.014674 +110,VM_10,0.0069 +110,VM_43,0.005995 +110,VM_8,0.005165 +110,VM_14,0.005566 +110,VM_103,0.028317 +110,VM_83,0.009031 +110,VM_76,0.019935 +110,VM_49,0.024495 +110,VM_20,0.005324 +110,VM_6,0.006173 +110,VM_87,0.028446 +120,VM_33,0.006929 +120,VM_119,0.033679 +120,VM_70,0.026282 +120,VM_40,0.014883 +120,VM_90,0.026726 +120,VM_106,0.030914 +120,VM_33,0.005098 +120,VM_72,0.005887 +120,VM_17,0.004793 +120,VM_76,0.0063 +120,VM_43,0.004786 +120,VM_69,0.007767 +120,VM_77,0.006106 +120,VM_17,0.006804 +120,VM_5,0.012051 +120,VM_116,0.033613 +120,VM_14,0.005404 +120,VM_39,0.013097 +120,VM_5,0.005605 +120,VM_96,0.005913 +120,VM_45,0.005899 +120,VM_100,0.027859 +120,VM_102,0.006705 +120,VM_102,0.005582 +120,VM_6,0.005409 +120,VM_60,0.005382 +120,VM_13,0.009083 +120,VM_103,0.00741 +120,VM_7,0.031385 +120,VM_110,0.027276 +120,VM_68,0.005821 +120,VM_20,0.005803 +120,VM_77,0.005443 +120,VM_2,0.006337 +120,VM_109,0.033942 +120,VM_117,0.031806 +120,VM_30,0.005189 +120,VM_1,0.006121 +120,VM_7,0.00558 +120,VM_66,0.005555 +120,VM_3,0.021903 +120,VM_28,0.035038 +120,VM_9,0.00785 +120,VM_90,0.006267 +120,VM_97,0.006257 +120,VM_62,0.028053 +120,VM_57,0.027435 +120,VM_20,0.033864 +120,VM_37,0.019937 +120,VM_112,0.017272 +120,VM_45,0.013538 +120,VM_70,0.025242 +120,VM_79,0.020061 +120,VM_112,0.010241 +120,VM_97,0.006141 +120,VM_42,0.024041 +120,VM_91,0.032908 +120,VM_106,0.030657 +120,VM_75,0.033032 +120,VM_51,0.033369 +120,VM_57,0.005329 +120,VM_57,0.005534 +120,VM_6,0.015425 +120,VM_105,0.023375 +120,VM_70,0.006013 +120,VM_53,0.018698 +120,VM_118,0.031804 +120,VM_25,0.028617 +120,VM_24,0.01085 +120,VM_84,0.027643 +120,VM_51,0.007154 +120,VM_23,0.028724 +120,VM_48,0.015423 +120,VM_100,0.019665 +120,VM_47,0.03175 +120,VM_72,0.020332 +130,VM_56,0.018845 +130,VM_116,0.03576 +130,VM_45,0.005995 +130,VM_56,0.006237 +130,VM_4,0.015556 +130,VM_87,0.018868 +130,VM_52,0.01649 +130,VM_71,0.01308 +130,VM_18,0.016839 +130,VM_85,0.009946 +130,VM_98,0.025943 +130,VM_25,0.005155 +130,VM_37,0.00605 +130,VM_2,0.021806 +130,VM_49,0.007688 +130,VM_106,0.005786 +130,VM_110,0.023124 +130,VM_77,0.01035 +130,VM_91,0.005537 +130,VM_65,0.011367 +130,VM_81,0.00757 +130,VM_83,0.003572 +130,VM_50,0.015895 +130,VM_65,0.005485 +130,VM_54,0.00635 +130,VM_53,0.004628 +130,VM_5,0.028193 +130,VM_43,0.030344 +130,VM_14,0.018097 +130,VM_117,0.023769 +130,VM_29,0.019984 +130,VM_74,0.024563 +130,VM_111,0.026244 +130,VM_2,0.006327 +130,VM_8,0.00937 +130,VM_41,0.017801 +130,VM_120,0.009658 +130,VM_100,0.005395 +130,VM_16,0.0373 +130,VM_37,0.00594 +130,VM_121,0.005268 +130,VM_34,0.010656 +130,VM_66,0.008177 +130,VM_11,0.035234 +130,VM_125,0.01591 +130,VM_69,0.034701 +130,VM_31,0.016333 +130,VM_74,0.00544 +130,VM_87,0.005749 +130,VM_90,0.005146 +130,VM_57,0.005849 +130,VM_119,0.005267 +130,VM_55,0.009927 +130,VM_109,0.011102 +130,VM_74,0.006623 +130,VM_85,0.004668 +130,VM_111,0.005971 +130,VM_2,0.00536 +130,VM_62,0.005975 +130,VM_70,0.005474 +130,VM_101,0.024158 +130,VM_38,0.014317 +130,VM_55,0.026236 +130,VM_81,0.022287 +130,VM_36,0.025756 +130,VM_117,0.026381 +130,VM_129,0.033249 +130,VM_10,0.023778 +130,VM_82,0.014859 +130,VM_72,0.026222 +130,VM_35,0.013733 +130,VM_7,0.032477 +130,VM_31,0.014163 +130,VM_95,0.034474 +130,VM_17,0.006813 +130,VM_65,0.019373 +140,VM_134,0.032094 +140,VM_41,0.02417 +140,VM_112,0.029381 +140,VM_86,0.026569 +140,VM_10,0.006401 +140,VM_29,0.012193 +140,VM_17,0.006171 +140,VM_117,0.006264 +140,VM_6,0.026589 +140,VM_84,0.00963 +140,VM_66,0.015154 +140,VM_78,0.018158 +140,VM_82,0.005688 +140,VM_55,0.004805 +140,VM_83,0.006939 +140,VM_93,0.039205 +140,VM_83,0.005829 +140,VM_100,0.034856 +140,VM_114,0.03226 +140,VM_47,0.027508 +140,VM_120,0.024905 +140,VM_45,0.0151 +140,VM_85,0.004152 +140,VM_139,0.014523 +140,VM_138,0.0329 +140,VM_74,0.029299 +140,VM_69,0.014186 +140,VM_19,0.032579 +140,VM_91,0.028119 +140,VM_99,0.009817 +140,VM_2,0.033343 +140,VM_17,0.005627 +140,VM_30,0.012819 +140,VM_96,0.009128 +140,VM_120,0.005669 +140,VM_69,0.00491 +140,VM_66,0.005965 +140,VM_121,0.035615 +140,VM_125,0.022885 +140,VM_0,0.033463 +140,VM_132,0.032825 +140,VM_92,0.030083 +140,VM_119,0.03379 +140,VM_131,0.004855 +140,VM_75,0.033618 +140,VM_97,0.022735 +140,VM_10,0.006286 +140,VM_24,0.015352 +140,VM_98,0.018224 +140,VM_8,0.020201 +140,VM_3,0.021288 +140,VM_76,0.003953 +140,VM_126,0.031797 +140,VM_0,0.004872 +140,VM_93,0.005815 +140,VM_30,0.008836 +140,VM_127,0.016579 +140,VM_4,0.011877 +140,VM_55,0.006152 +140,VM_46,0.004574 +140,VM_48,0.008125 +140,VM_27,0.027459 +140,VM_20,0.031027 +140,VM_55,0.00452 +140,VM_2,0.023761 +140,VM_11,0.028259 +140,VM_32,0.008655 +140,VM_99,0.021032 +140,VM_34,0.035012 +140,VM_113,0.031543 +140,VM_9,0.020215 +140,VM_11,0.005735 +140,VM_137,0.020036 +140,VM_54,0.007457 +140,VM_44,0.004064 +140,VM_38,0.023668 diff --git a/BENCHMARKING/RESULTS/startup_unik_benchmark.csv b/BENCHMARKING/RESULTS/startup_unik_benchmark.csv new file mode 100644 index 0000000..f57bf63 --- /dev/null +++ b/BENCHMARKING/RESULTS/startup_unik_benchmark.csv @@ -0,0 +1,2681 @@ +NBR_OF_GUESTS,GUEST_STOPPED,STARTUP_TIME_SECONDS +10,VM_0,0.013473 +10,VM_4,0.134164 +10,VM_7,0.079406 +10,VM_0,0.013065 +10,VM_4,0.134782 +10,VM_9,0.13385 +10,VM_1,0.11362 +10,VM_8,0.126989 +10,VM_1,0.012737 +10,VM_9,0.01039 +10,VM_6,0.11553 +10,VM_5,0.116785 +10,VM_6,0.013631 +10,VM_5,0.015163 +10,VM_4,0.008139 +10,VM_1,0.008646 +10,VM_7,0.008685 +10,VM_4,0.010134 +10,VM_0,0.013782 +10,VM_5,0.133214 +10,VM_8,0.138445 +10,VM_3,0.13817 +10,VM_7,0.163165 +10,VM_2,0.136489 +10,VM_4,0.049061 +10,VM_4,0.005055 +10,VM_6,0.051383 +10,VM_6,0.287513 +10,VM_1,0.152779 +10,VM_3,0.008229 +10,VM_1,0.009176 +10,VM_8,0.016355 +10,VM_3,0.012017 +10,VM_7,0.007217 +10,VM_3,0.010215 +10,VM_2,0.050923 +10,VM_2,0.005941 +10,VM_1,0.00737 +10,VM_2,0.015685 +10,VM_2,0.019411 +10,VM_6,0.02165 +10,VM_5,0.007959 +10,VM_6,0.011917 +10,VM_6,0.020079 +10,VM_0,0.018476 +10,VM_9,0.246045 +10,VM_7,0.140039 +10,VM_3,0.155828 +10,VM_6,0.013317 +10,VM_3,0.012696 +10,VM_7,0.010336 +10,VM_4,0.552807 +10,VM_4,0.418706 +10,VM_4,0.218848 +10,VM_4,0.318437 +10,VM_1,0.135856 +10,VM_2,0.122498 +10,VM_8,0.126884 +10,VM_9,0.010447 +10,VM_8,0.015518 +10,VM_9,0.012326 +10,VM_0,0.014146 +10,VM_3,0.122771 +10,VM_1,0.12984 +10,VM_7,0.129137 +10,VM_5,0.276085 +10,VM_5,0.180853 +10,VM_3,0.011544 +10,VM_0,0.011317 +10,VM_1,0.116582 +10,VM_4,0.108209 +10,VM_5,0.130161 +10,VM_3,0.009016 +10,VM_6,0.109497 +10,VM_9,0.271096 +10,VM_9,0.159456 +10,VM_6,0.012198 +10,VM_2,0.114409 +10,VM_8,0.137048 +10,VM_1,0.011947 +10,VM_0,0.014218 +10,VM_2,0.280621 +10,VM_2,0.172031 +10,VM_8,0.118114 +10,VM_3,0.106832 +10,VM_4,0.12048 +10,VM_6,0.126192 +10,VM_8,0.009582 +10,VM_1,0.010352 +10,VM_8,0.012685 +10,VM_8,0.007616 +10,VM_0,0.223617 +10,VM_7,0.126823 +10,VM_6,0.109503 +10,VM_1,0.11329 +10,VM_9,0.105982 +10,VM_4,0.106034 +10,VM_7,0.014303 +10,VM_6,0.009933 +10,VM_4,0.008944 +10,VM_2,0.159545 +10,VM_7,0.013094 +10,VM_4,0.02465 +10,VM_9,0.02589 +10,VM_2,0.016339 +10,VM_6,0.010905 +10,VM_4,0.00919 +10,VM_9,0.016633 +10,VM_1,0.007456 +10,VM_6,0.015351 +10,VM_7,0.026115 +10,VM_0,0.010234 +10,VM_9,0.140291 +10,VM_4,0.145782 +10,VM_2,0.137778 +10,VM_1,0.065582 +10,VM_0,0.011291 +10,VM_8,0.274707 +10,VM_8,0.981973 +10,VM_0,0.011911 +10,VM_4,0.13773 +10,VM_6,0.964232 +10,VM_6,0.288629 +10,VM_2,0.153071 +10,VM_4,0.011941 +10,VM_7,0.131706 +10,VM_1,0.109028 +10,VM_3,0.138589 +10,VM_5,0.110566 +10,VM_5,0.26053 +10,VM_7,0.009159 +10,VM_7,0.008599 +10,VM_5,0.015484 +10,VM_2,0.008717 +10,VM_6,0.009506 +10,VM_3,0.009622 +10,VM_9,0.124707 +10,VM_0,0.011232 +10,VM_6,0.277694 +10,VM_6,0.143981 +10,VM_9,0.143046 +10,VM_7,0.133346 +10,VM_5,0.119146 +10,VM_6,0.008393 +10,VM_3,0.114651 +10,VM_5,0.012213 +10,VM_9,0.009069 +10,VM_6,0.014244 +10,VM_9,0.010589 +10,VM_4,0.135076 +10,VM_3,0.010588 +10,VM_2,0.0824 +10,VM_0,0.012978 +10,VM_9,0.086645 +10,VM_0,0.008539 +10,VM_5,0.11595 +10,VM_8,0.134165 +10,VM_2,0.129293 +10,VM_4,0.071387 +10,VM_0,0.011918 +10,VM_5,0.115045 +10,VM_9,0.11853 +10,VM_2,0.117738 +10,VM_9,0.009113 +10,VM_1,0.125233 +10,VM_3,0.116879 +10,VM_8,0.13593 +10,VM_3,0.012898 +10,VM_2,0.019471 +10,VM_2,0.191529 +10,VM_2,0.334889 +10,VM_2,0.900487 +10,VM_4,0.009755 +10,VM_9,0.007453 +10,VM_6,0.149298 +10,VM_2,0.019916 +10,VM_9,0.022343 +10,VM_2,0.110559 +10,VM_4,0.044689 +10,VM_9,0.011137 +10,VM_2,0.016992 +10,VM_9,0.160714 +10,VM_9,0.024652 +20,VM_7,0.531857 +20,VM_1,0.589013 +20,VM_6,0.800343 +20,VM_8,0.769516 +20,VM_8,0.402168 +20,VM_8,0.154239 +20,VM_0,0.969021 +20,VM_0,0.523374 +20,VM_5,0.058218 +20,VM_5,0.56349 +20,VM_4,0.172144 +20,VM_4,0.955392 +20,VM_3,0.618308 +20,VM_3,0.71296 +20,VM_19,0.142522 +20,VM_10,0.120128 +20,VM_16,0.120262 +20,VM_10,0.011256 +20,VM_12,0.136923 +20,VM_4,0.012593 +20,VM_2,0.135019 +20,VM_1,0.115493 +20,VM_10,0.054627 +20,VM_10,0.008719 +20,VM_11,0.265862 +20,VM_11,0.178368 +20,VM_0,0.045382 +20,VM_0,0.00643 +20,VM_1,0.010909 +20,VM_9,0.138583 +20,VM_19,0.006422 +20,VM_3,0.011467 +20,VM_15,0.014699 +20,VM_17,0.132377 +20,VM_14,0.11727 +20,VM_18,0.108591 +20,VM_2,0.135273 +20,VM_14,0.011397 +20,VM_15,0.012061 +20,VM_18,0.124483 +20,VM_11,0.117074 +20,VM_7,0.127384 +20,VM_3,0.13284 +20,VM_13,0.121114 +20,VM_0,0.125409 +20,VM_5,0.064834 +20,VM_15,0.013753 +20,VM_10,0.141111 +20,VM_2,0.156723 +20,VM_5,0.018466 +20,VM_2,0.009025 +20,VM_11,0.155588 +20,VM_0,0.135466 +20,VM_12,0.150895 +20,VM_17,0.122596 +20,VM_4,0.150037 +20,VM_19,0.157373 +20,VM_3,0.144371 +20,VM_10,0.009671 +20,VM_4,0.00978 +20,VM_16,0.142697 +20,VM_7,0.149666 +20,VM_19,0.010462 +20,VM_11,0.010719 +20,VM_13,0.13265 +20,VM_2,0.016014 +20,VM_9,0.147576 +20,VM_14,0.092738 +20,VM_15,0.019188 +20,VM_2,0.309346 +20,VM_2,0.087262 +20,VM_10,0.131456 +20,VM_18,0.149906 +20,VM_11,0.135044 +20,VM_5,0.26933 +20,VM_5,0.169418 +20,VM_14,0.064969 +20,VM_14,0.00607 +20,VM_12,0.113434 +20,VM_14,0.016182 +20,VM_18,0.010598 +20,VM_19,0.131836 +20,VM_18,0.015151 +20,VM_2,0.008329 +20,VM_19,0.013268 +20,VM_0,0.109942 +20,VM_19,0.010208 +20,VM_18,0.017241 +20,VM_0,0.00975 +20,VM_1,0.112763 +20,VM_17,0.136841 +20,VM_10,0.00922 +20,VM_11,0.01805 +20,VM_0,0.008324 +20,VM_12,0.010203 +20,VM_8,0.161514 +20,VM_8,0.250194 +20,VM_9,0.139251 +20,VM_5,0.012048 +20,VM_6,0.07507 +20,VM_15,0.013563 +20,VM_19,0.123807 +20,VM_0,0.11784 +20,VM_11,0.1338 +20,VM_14,0.118075 +20,VM_17,0.130366 +20,VM_10,0.11653 +20,VM_3,0.12502 +20,VM_1,0.11544 +20,VM_9,0.133583 +20,VM_0,0.009865 +20,VM_6,0.008495 +20,VM_3,0.008815 +20,VM_10,0.008922 +20,VM_13,0.122791 +20,VM_12,0.106574 +20,VM_10,0.015481 +20,VM_13,0.010083 +20,VM_9,0.009626 +20,VM_18,0.113329 +20,VM_13,0.014619 +20,VM_0,0.048007 +20,VM_0,0.005869 +20,VM_3,0.009597 +20,VM_8,0.165234 +20,VM_0,0.016642 +20,VM_3,0.009381 +20,VM_6,0.013304 +20,VM_4,0.136789 +20,VM_14,0.015755 +20,VM_9,0.011892 +20,VM_3,0.012292 +20,VM_14,0.011406 +20,VM_17,0.010886 +20,VM_18,0.009482 +20,VM_6,0.009963 +20,VM_8,0.009003 +20,VM_14,0.013226 +20,VM_4,0.016591 +20,VM_16,0.292235 +20,VM_16,0.070261 +20,VM_1,0.009948 +20,VM_0,0.011788 +20,VM_3,0.012011 +20,VM_14,0.014963 +20,VM_19,0.008223 +20,VM_11,0.014524 +20,VM_6,0.008847 +20,VM_9,0.022798 +20,VM_15,0.010769 +20,VM_19,0.15959 +20,VM_13,0.116744 +20,VM_17,0.121154 +20,VM_19,0.010438 +20,VM_12,0.131829 +20,VM_2,0.129342 +20,VM_1,0.090202 +20,VM_15,0.008331 +20,VM_10,0.113076 +20,VM_12,0.182718 +20,VM_12,0.278072 +20,VM_2,0.111587 +20,VM_11,0.078598 +20,VM_15,0.011757 +20,VM_14,0.118323 +20,VM_17,0.118718 +20,VM_1,0.125579 +20,VM_17,0.008568 +20,VM_19,0.127797 +20,VM_2,0.105169 +20,VM_16,0.108642 +20,VM_19,0.010837 +20,VM_6,0.114236 +20,VM_1,0.00989 +20,VM_17,0.009461 +20,VM_8,0.127836 +20,VM_14,0.015224 +20,VM_7,0.138548 +20,VM_9,0.122535 +20,VM_3,0.128551 +20,VM_4,0.128611 +20,VM_5,0.119633 +20,VM_3,0.011004 +20,VM_13,0.110761 +20,VM_11,0.008558 +20,VM_6,0.009201 +20,VM_2,0.008733 +20,VM_13,0.01604 +20,VM_3,0.009299 +20,VM_11,0.01338 +20,VM_1,0.009844 +20,VM_12,0.107913 +20,VM_5,0.008982 +20,VM_8,0.010752 +20,VM_3,0.016694 +20,VM_8,0.014727 +20,VM_8,0.008168 +20,VM_6,0.014677 +20,VM_3,0.00848 +20,VM_11,0.010625 +20,VM_12,0.016572 +20,VM_7,0.012863 +20,VM_3,0.012153 +20,VM_14,0.013461 +20,VM_13,0.030433 +20,VM_6,0.008614 +20,VM_4,0.012416 +20,VM_0,0.152167 +20,VM_12,0.017494 +30,VM_4,0.015868 +30,VM_0,0.117507 +30,VM_21,0.140018 +30,VM_9,0.117959 +30,VM_20,0.121529 +30,VM_18,0.128766 +30,VM_12,0.132471 +30,VM_4,0.076494 +30,VM_3,0.016674 +30,VM_1,0.112746 +30,VM_7,0.162365 +30,VM_14,0.145981 +30,VM_24,0.153585 +30,VM_15,0.164992 +30,VM_26,0.14839 +30,VM_1,0.007675 +30,VM_5,0.137861 +30,VM_24,0.018479 +30,VM_6,0.16123 +30,VM_27,0.154057 +30,VM_8,0.140445 +30,VM_0,0.161259 +30,VM_20,0.130574 +30,VM_21,0.162158 +30,VM_4,0.011666 +30,VM_14,0.019697 +30,VM_8,0.012392 +30,VM_5,0.00872 +30,VM_21,0.011953 +30,VM_10,0.147683 +30,VM_21,0.012842 +30,VM_13,0.162056 +30,VM_24,0.008217 +30,VM_15,0.016805 +30,VM_22,0.154718 +30,VM_20,0.015078 +30,VM_6,0.012502 +30,VM_0,0.011426 +30,VM_24,0.01119 +30,VM_11,0.111039 +30,VM_16,0.108825 +30,VM_12,0.116109 +30,VM_10,0.008897 +30,VM_0,0.010094 +30,VM_4,0.009683 +30,VM_21,0.013108 +30,VM_18,0.121592 +30,VM_26,0.015011 +30,VM_19,0.123171 +30,VM_28,0.110627 +30,VM_26,0.018288 +30,VM_15,0.013476 +30,VM_4,0.009431 +30,VM_26,0.008556 +30,VM_1,0.010622 +30,VM_10,0.011356 +30,VM_2,0.128445 +30,VM_1,0.018968 +30,VM_14,0.008932 +30,VM_5,0.010473 +30,VM_9,0.118258 +30,VM_12,0.009857 +30,VM_18,0.00838 +30,VM_22,0.050281 +30,VM_22,0.006519 +30,VM_8,0.009793 +30,VM_2,0.009625 +30,VM_23,0.111574 +30,VM_17,0.108286 +30,VM_6,0.012927 +30,VM_12,0.010567 +30,VM_5,0.009891 +30,VM_11,0.008004 +30,VM_14,0.011904 +30,VM_9,0.008255 +30,VM_14,0.017415 +30,VM_15,0.00954 +30,VM_12,0.01422 +30,VM_16,0.008976 +30,VM_26,0.010818 +30,VM_17,0.009245 +30,VM_0,0.009378 +30,VM_22,0.015767 +30,VM_3,0.010295 +30,VM_16,0.118443 +30,VM_20,0.131345 +30,VM_14,0.18172 +30,VM_14,0.27899 +30,VM_10,0.138216 +30,VM_1,0.130126 +30,VM_2,0.131757 +30,VM_1,0.013882 +30,VM_5,0.148859 +30,VM_24,0.156472 +30,VM_1,0.016424 +30,VM_1,0.009478 +30,VM_24,0.009927 +30,VM_28,0.159611 +30,VM_0,0.133652 +30,VM_18,0.167784 +30,VM_20,0.011795 +30,VM_0,0.007659 +30,VM_17,0.145513 +30,VM_23,0.140888 +30,VM_27,0.162866 +30,VM_1,0.011888 +30,VM_15,0.135954 +30,VM_26,0.150567 +30,VM_5,0.016706 +30,VM_14,0.012679 +30,VM_13,0.041066 +30,VM_13,0.278635 +30,VM_15,0.025623 +30,VM_28,0.023269 +30,VM_14,0.028024 +30,VM_13,0.012461 +30,VM_3,0.014737 +30,VM_13,0.01135 +30,VM_5,0.145827 +30,VM_5,0.251393 +30,VM_4,0.110398 +30,VM_2,0.118261 +30,VM_7,0.120892 +30,VM_22,0.106567 +30,VM_12,0.108042 +30,VM_13,0.014474 +30,VM_1,0.10642 +30,VM_17,0.123493 +30,VM_5,0.010158 +30,VM_0,0.118876 +30,VM_18,0.131724 +30,VM_28,0.117829 +30,VM_22,0.010871 +30,VM_14,0.106993 +30,VM_0,0.013812 +30,VM_18,0.010573 +30,VM_19,0.113441 +30,VM_16,0.121351 +30,VM_12,0.03896 +30,VM_12,0.010377 +30,VM_24,0.108562 +30,VM_26,0.128797 +30,VM_21,0.109679 +30,VM_24,0.010973 +30,VM_23,0.126092 +30,VM_0,0.008333 +30,VM_12,0.014189 +30,VM_8,0.113895 +30,VM_24,0.008706 +30,VM_12,0.016548 +30,VM_19,0.011126 +30,VM_24,0.019841 +30,VM_19,0.011445 +30,VM_10,0.115895 +30,VM_19,0.010525 +30,VM_11,0.10992 +30,VM_8,0.009865 +30,VM_15,0.136139 +30,VM_7,0.015 +30,VM_3,0.061246 +30,VM_3,0.008601 +30,VM_11,0.125696 +30,VM_28,0.117006 +30,VM_14,0.139173 +30,VM_27,0.131594 +30,VM_14,0.011092 +30,VM_10,0.132991 +30,VM_17,0.146601 +30,VM_22,0.156816 +30,VM_28,0.016392 +30,VM_6,0.165115 +30,VM_14,0.015395 +30,VM_28,0.011493 +30,VM_26,0.153974 +30,VM_5,0.14534 +30,VM_1,0.069665 +30,VM_3,0.016389 +30,VM_18,0.154491 +30,VM_14,0.159587 +30,VM_7,0.08343 +30,VM_3,0.017496 +30,VM_14,0.128921 +30,VM_10,0.158889 +30,VM_21,0.147006 +30,VM_22,0.142066 +30,VM_20,0.143935 +30,VM_7,0.016253 +30,VM_4,0.15205 +30,VM_13,0.145556 +30,VM_27,0.159106 +30,VM_23,0.161175 +30,VM_24,0.151735 +30,VM_17,0.169166 +30,VM_13,0.015263 +40,VM_13,0.014247 +40,VM_23,0.01331 +40,VM_3,0.121159 +40,VM_4,0.12055 +40,VM_22,0.133696 +40,VM_35,0.126667 +40,VM_38,0.128427 +40,VM_15,0.104899 +40,VM_37,0.071114 +40,VM_39,0.015273 +40,VM_23,0.130935 +40,VM_20,0.13923 +40,VM_34,0.117658 +40,VM_7,0.113584 +40,VM_22,0.125352 +40,VM_8,0.114572 +40,VM_10,0.122873 +40,VM_33,0.123497 +40,VM_2,0.139163 +40,VM_35,0.137799 +40,VM_8,0.021675 +40,VM_24,0.129118 +40,VM_20,0.01066 +40,VM_25,0.111698 +40,VM_23,0.009119 +40,VM_0,0.136638 +40,VM_29,0.122124 +40,VM_33,0.011393 +40,VM_11,0.111248 +40,VM_37,0.014069 +40,VM_36,0.141836 +40,VM_17,0.129124 +40,VM_15,0.094867 +40,VM_39,0.012691 +40,VM_2,0.117429 +40,VM_35,0.134182 +40,VM_22,0.118525 +40,VM_34,0.133897 +40,VM_38,0.130775 +40,VM_27,0.156274 +40,VM_30,0.158787 +40,VM_38,0.01377 +40,VM_27,0.013005 +40,VM_20,0.038604 +40,VM_20,0.299308 +40,VM_38,0.013116 +40,VM_23,0.137535 +40,VM_16,0.146187 +40,VM_2,0.007785 +40,VM_11,0.13331 +40,VM_14,0.152738 +40,VM_20,0.013543 +40,VM_11,0.012164 +40,VM_13,0.146757 +40,VM_33,0.151045 +40,VM_12,0.061174 +40,VM_39,0.025124 +40,VM_10,0.159317 +40,VM_15,0.156813 +40,VM_30,0.148542 +40,VM_5,0.140324 +40,VM_21,0.139327 +40,VM_1,0.134633 +40,VM_29,0.146565 +40,VM_2,0.156641 +40,VM_29,0.018405 +40,VM_0,0.165162 +40,VM_30,0.014686 +40,VM_18,0.107174 +40,VM_8,0.106263 +40,VM_14,0.125939 +40,VM_9,0.128301 +40,VM_8,0.015624 +40,VM_32,0.10835 +40,VM_12,0.009556 +40,VM_10,0.01333 +40,VM_19,0.122036 +40,VM_36,0.119115 +40,VM_29,0.015635 +40,VM_23,0.134407 +40,VM_1,0.011754 +40,VM_39,0.010972 +40,VM_5,0.115075 +40,VM_25,0.122128 +40,VM_35,0.119719 +40,VM_3,0.114204 +40,VM_17,0.112313 +40,VM_4,0.074238 +40,VM_39,0.014433 +40,VM_5,0.111337 +40,VM_30,0.129028 +40,VM_14,0.117085 +40,VM_6,0.129594 +40,VM_22,0.131529 +40,VM_18,0.137134 +40,VM_8,0.116644 +40,VM_11,0.137322 +40,VM_36,0.132453 +40,VM_0,0.133111 +40,VM_34,0.125212 +40,VM_1,0.119983 +40,VM_20,0.105249 +40,VM_30,0.012681 +40,VM_32,0.116517 +40,VM_24,0.12684 +40,VM_28,0.111699 +40,VM_12,0.130965 +40,VM_11,0.011078 +40,VM_38,0.127186 +40,VM_11,0.014937 +40,VM_14,0.012128 +40,VM_28,0.009192 +40,VM_11,0.015348 +40,VM_6,0.009972 +40,VM_16,0.126702 +40,VM_8,0.00973 +40,VM_17,0.111258 +40,VM_25,0.169025 +40,VM_22,0.015296 +40,VM_39,0.010973 +40,VM_11,0.155471 +40,VM_14,0.153663 +40,VM_29,0.150267 +40,VM_24,0.154329 +40,VM_37,0.170564 +40,VM_10,0.07727 +40,VM_39,0.015765 +40,VM_32,0.156136 +40,VM_0,0.15253 +40,VM_12,0.141461 +40,VM_19,0.166038 +40,VM_0,0.028815 +40,VM_16,0.140735 +40,VM_37,0.145829 +40,VM_13,0.144865 +40,VM_27,0.145163 +40,VM_28,0.143192 +40,VM_25,0.139888 +40,VM_15,0.077326 +40,VM_39,0.025843 +40,VM_19,0.150057 +40,VM_16,0.162263 +40,VM_22,0.135953 +40,VM_4,0.167888 +40,VM_30,0.170273 +40,VM_28,0.109357 +40,VM_3,0.061557 +40,VM_39,0.012724 +40,VM_23,0.1304 +40,VM_30,0.121366 +40,VM_26,0.112839 +40,VM_18,0.119855 +40,VM_22,0.069995 +40,VM_39,0.014747 +40,VM_34,0.125793 +40,VM_20,0.12228 +40,VM_24,0.131263 +40,VM_4,0.138764 +40,VM_27,0.268566 +40,VM_27,0.158162 +40,VM_12,0.12402 +40,VM_37,0.111542 +40,VM_4,0.007914 +40,VM_36,0.111965 +40,VM_6,0.127975 +40,VM_7,0.136809 +40,VM_34,0.011849 +40,VM_38,0.119671 +40,VM_22,0.009639 +40,VM_5,0.107129 +40,VM_19,0.125669 +40,VM_11,0.122476 +40,VM_3,0.119452 +40,VM_27,0.009532 +40,VM_13,0.128436 +40,VM_30,0.12687 +40,VM_25,0.123152 +40,VM_12,0.012391 +40,VM_32,0.257886 +40,VM_32,0.150296 +40,VM_5,0.009441 +40,VM_20,0.008637 +40,VM_25,0.018413 +40,VM_11,0.008799 +40,VM_0,0.127248 +40,VM_13,0.012644 +40,VM_0,0.011701 +40,VM_35,0.118369 +40,VM_10,0.143064 +40,VM_13,0.015736 +40,VM_12,0.015257 +40,VM_20,0.011255 +40,VM_37,0.012604 +40,VM_27,0.014123 +40,VM_29,0.151534 +40,VM_27,0.017735 +50,VM_39,0.017355 +50,VM_20,0.109156 +50,VM_10,0.130705 +50,VM_22,0.131712 +50,VM_42,0.121838 +50,VM_1,0.137667 +50,VM_32,0.108901 +50,VM_19,0.113504 +50,VM_11,0.136146 +50,VM_47,0.117606 +50,VM_42,0.01397 +50,VM_44,0.134342 +50,VM_26,0.128576 +50,VM_16,0.122448 +50,VM_28,0.128709 +50,VM_23,0.109084 +50,VM_40,0.122721 +50,VM_11,0.012586 +50,VM_22,0.010325 +50,VM_29,0.132479 +50,VM_30,0.107716 +50,VM_17,0.115512 +50,VM_39,0.121812 +50,VM_28,0.013651 +50,VM_5,0.012274 +50,VM_6,0.110562 +50,VM_26,0.111972 +50,VM_48,0.121389 +50,VM_23,0.125748 +50,VM_21,0.129532 +50,VM_49,0.118405 +50,VM_6,0.01281 +50,VM_2,0.119419 +50,VM_43,0.132423 +50,VM_14,0.116292 +50,VM_25,0.123044 +50,VM_33,0.119508 +50,VM_33,0.259313 +50,VM_14,0.019965 +50,VM_26,0.022937 +50,VM_29,0.135767 +50,VM_8,0.137528 +50,VM_23,0.011133 +50,VM_40,0.132333 +50,VM_21,0.018936 +50,VM_18,0.147946 +50,VM_29,0.015622 +50,VM_25,0.013887 +50,VM_47,0.154217 +50,VM_37,0.149994 +50,VM_9,0.132522 +50,VM_18,0.017775 +50,VM_27,0.141665 +50,VM_17,0.141671 +50,VM_1,0.17252 +50,VM_37,0.038444 +50,VM_29,0.019122 +50,VM_43,0.012894 +50,VM_25,0.008008 +50,VM_44,0.153206 +50,VM_4,0.152223 +50,VM_19,0.142866 +50,VM_1,0.017787 +50,VM_17,0.015584 +50,VM_6,0.066406 +50,VM_6,0.018173 +50,VM_39,0.155777 +50,VM_20,0.15747 +50,VM_26,0.012283 +50,VM_9,0.015263 +50,VM_36,0.140307 +50,VM_8,0.011363 +50,VM_25,0.010262 +50,VM_23,0.01063 +50,VM_10,0.113613 +50,VM_31,0.128715 +50,VM_30,0.13282 +50,VM_0,0.111751 +50,VM_17,0.009279 +50,VM_46,0.124202 +50,VM_28,0.012936 +50,VM_44,0.015137 +50,VM_5,0.011542 +50,VM_46,0.128304 +50,VM_1,0.128493 +50,VM_13,0.128672 +50,VM_30,0.140575 +50,VM_0,0.115935 +50,VM_45,0.120067 +50,VM_12,0.117206 +50,VM_8,0.122157 +50,VM_3,0.257824 +50,VM_3,0.13859 +50,VM_32,0.122693 +50,VM_44,0.010662 +50,VM_11,0.111739 +50,VM_3,0.011316 +50,VM_16,0.072315 +50,VM_5,0.016807 +50,VM_49,0.111805 +50,VM_3,0.124669 +50,VM_0,0.12154 +50,VM_7,0.129715 +50,VM_37,0.125893 +50,VM_31,0.113517 +50,VM_33,0.128177 +50,VM_12,0.06776 +50,VM_5,0.012329 +50,VM_35,0.124212 +50,VM_22,0.140895 +50,VM_44,0.117187 +50,VM_26,0.112474 +50,VM_18,0.150712 +50,VM_40,0.107767 +50,VM_26,0.013303 +50,VM_19,0.130459 +50,VM_36,0.141643 +50,VM_49,0.131347 +50,VM_6,0.165028 +50,VM_25,0.139343 +50,VM_27,0.166281 +50,VM_42,0.146976 +50,VM_48,0.144532 +50,VM_4,0.150066 +50,VM_45,0.13992 +50,VM_1,0.158347 +50,VM_9,0.15569 +50,VM_15,0.165296 +50,VM_30,0.155421 +50,VM_29,0.155034 +50,VM_9,0.021332 +50,VM_49,0.008427 +50,VM_42,0.010112 +50,VM_38,0.138522 +50,VM_46,0.156047 +50,VM_28,0.141135 +50,VM_2,0.135127 +50,VM_23,0.14638 +50,VM_17,0.15483 +50,VM_41,0.150853 +50,VM_49,0.012127 +50,VM_21,0.156223 +50,VM_18,0.012916 +50,VM_47,0.140023 +50,VM_37,0.181431 +50,VM_29,0.017125 +50,VM_28,0.00795 +50,VM_4,0.745233 +50,VM_4,0.53437 +50,VM_32,0.098057 +50,VM_5,0.01345 +50,VM_35,0.107456 +50,VM_34,0.109929 +50,VM_8,0.120591 +50,VM_28,0.133308 +50,VM_12,0.11482 +50,VM_20,0.132004 +50,VM_13,0.111949 +50,VM_47,0.110166 +50,VM_12,0.013445 +50,VM_29,0.126989 +50,VM_25,0.117734 +50,VM_8,0.010299 +50,VM_25,0.0208 +50,VM_8,0.009888 +50,VM_36,0.123496 +50,VM_20,0.017094 +50,VM_5,0.012389 +50,VM_30,0.145459 +50,VM_35,0.137519 +50,VM_37,0.131589 +50,VM_33,0.130954 +50,VM_47,0.135716 +50,VM_4,0.129743 +50,VM_49,0.119733 +50,VM_24,0.119083 +50,VM_0,0.111001 +50,VM_48,0.137191 +50,VM_39,0.131133 +50,VM_11,0.127882 +50,VM_19,0.123327 +50,VM_15,0.128696 +50,VM_4,0.01001 +50,VM_31,0.130802 +50,VM_38,0.114371 +50,VM_21,0.121522 +50,VM_18,0.13849 +50,VM_37,0.011608 +50,VM_42,0.123014 +50,VM_25,0.112168 +50,VM_7,0.127709 +50,VM_23,0.113332 +50,VM_12,0.129959 +50,VM_42,0.013091 +50,VM_17,0.140122 +60,VM_0,0.008429 +60,VM_51,0.12339 +60,VM_17,0.125888 +60,VM_44,0.124911 +60,VM_7,0.111606 +60,VM_3,0.11969 +60,VM_35,0.115634 +60,VM_13,0.122735 +60,VM_32,0.129042 +60,VM_23,0.129928 +60,VM_32,0.008179 +60,VM_56,0.129181 +60,VM_45,0.11568 +60,VM_23,0.011585 +60,VM_29,0.135986 +60,VM_16,0.138378 +60,VM_56,0.015812 +60,VM_27,0.143588 +60,VM_11,0.149221 +60,VM_27,0.012826 +60,VM_55,0.155169 +60,VM_12,0.148679 +60,VM_55,0.029608 +60,VM_17,0.020684 +60,VM_13,0.010323 +60,VM_9,0.165778 +60,VM_34,0.162709 +60,VM_50,0.1396 +60,VM_20,0.019381 +60,VM_21,0.171621 +60,VM_21,0.701947 +60,VM_35,0.155459 +60,VM_24,0.150099 +60,VM_50,0.156408 +60,VM_43,0.147486 +60,VM_10,0.156415 +60,VM_54,0.15255 +60,VM_42,0.157586 +60,VM_53,0.162986 +60,VM_13,0.131748 +60,VM_39,0.158221 +60,VM_12,0.15494 +60,VM_14,0.141335 +60,VM_28,0.150972 +60,VM_31,0.164348 +60,VM_55,0.146379 +60,VM_49,0.132532 +60,VM_28,0.012566 +60,VM_18,0.139475 +60,VM_28,0.024511 +60,VM_28,0.010626 +60,VM_35,0.011794 +60,VM_6,0.128881 +60,VM_21,0.009363 +60,VM_30,0.123132 +60,VM_1,0.106953 +60,VM_9,0.131498 +60,VM_25,0.136013 +60,VM_37,0.117417 +60,VM_55,0.009219 +60,VM_28,0.017021 +60,VM_8,0.113444 +60,VM_43,0.00973 +60,VM_22,0.130259 +60,VM_31,0.012264 +60,VM_18,0.011591 +60,VM_32,0.110994 +60,VM_16,0.134832 +60,VM_34,0.128514 +60,VM_19,0.134295 +60,VM_55,0.01274 +60,VM_36,0.122286 +60,VM_47,0.135907 +60,VM_5,0.126037 +60,VM_35,0.014673 +60,VM_43,0.013727 +60,VM_11,0.109395 +60,VM_30,0.020387 +60,VM_53,0.007835 +60,VM_9,0.014068 +60,VM_15,0.120012 +60,VM_30,0.023971 +60,VM_19,0.011986 +60,VM_15,0.015562 +60,VM_7,0.11233 +60,VM_34,0.011738 +60,VM_47,0.014398 +60,VM_14,0.012896 +60,VM_13,0.009963 +60,VM_51,0.122317 +60,VM_27,0.136762 +60,VM_35,0.0109 +60,VM_4,0.074504 +60,VM_20,0.010331 +60,VM_34,0.161918 +60,VM_29,0.148922 +60,VM_14,0.142884 +60,VM_47,0.143973 +60,VM_24,0.173132 +60,VM_18,0.137148 +60,VM_1,0.16655 +60,VM_46,0.164592 +60,VM_0,0.13178 +60,VM_8,0.151352 +60,VM_16,0.139539 +60,VM_23,0.161925 +60,VM_58,0.170533 +60,VM_57,0.141646 +60,VM_45,0.135559 +60,VM_21,0.141053 +60,VM_53,0.169285 +60,VM_24,0.018431 +60,VM_55,0.02973 +60,VM_55,0.306991 +60,VM_36,0.159325 +60,VM_48,0.14937 +60,VM_52,0.161428 +60,VM_31,0.158116 +60,VM_48,0.019793 +60,VM_15,0.135439 +60,VM_55,0.009451 +60,VM_11,0.165727 +60,VM_7,0.147172 +60,VM_57,0.013313 +60,VM_26,0.118892 +60,VM_36,0.012866 +60,VM_28,0.129465 +60,VM_12,0.131708 +60,VM_48,0.01167 +60,VM_45,0.010913 +60,VM_5,0.071864 +60,VM_20,0.017338 +60,VM_55,0.11752 +60,VM_49,0.146472 +60,VM_1,0.127303 +60,VM_17,0.116271 +60,VM_33,0.132418 +60,VM_18,0.134734 +60,VM_5,0.008597 +60,VM_34,0.126435 +60,VM_53,0.124886 +60,VM_47,0.132947 +60,VM_38,0.142429 +60,VM_5,0.01216 +60,VM_24,0.117509 +60,VM_39,0.110301 +60,VM_19,0.128606 +60,VM_4,0.123777 +60,VM_30,0.133519 +60,VM_40,0.129008 +60,VM_17,0.010366 +60,VM_24,0.00942 +60,VM_56,0.131993 +60,VM_59,0.134202 +60,VM_0,0.127917 +60,VM_21,0.108996 +60,VM_45,0.131603 +60,VM_35,0.139592 +60,VM_15,0.114235 +60,VM_21,0.012662 +60,VM_27,0.118096 +60,VM_11,0.123254 +60,VM_52,0.112866 +60,VM_3,0.129216 +60,VM_29,0.144643 +60,VM_53,0.010977 +60,VM_15,0.016624 +60,VM_23,0.134654 +60,VM_49,0.014533 +60,VM_38,0.015743 +60,VM_28,0.129087 +60,VM_38,0.012719 +60,VM_2,0.144916 +60,VM_1,0.012292 +60,VM_12,0.149441 +60,VM_26,0.139731 +60,VM_31,0.157621 +60,VM_7,0.171982 +60,VM_23,0.011638 +60,VM_46,0.177607 +60,VM_35,0.009163 +60,VM_32,0.093371 +60,VM_20,0.018503 +60,VM_58,0.131508 +60,VM_46,0.163734 +60,VM_54,0.150998 +60,VM_31,0.15169 +60,VM_18,0.139555 +60,VM_56,0.156052 +60,VM_9,0.140644 +60,VM_48,0.158989 +60,VM_32,0.009862 +60,VM_24,0.137646 +60,VM_44,0.144685 +70,VM_41,0.159333 +70,VM_34,0.128964 +70,VM_11,0.143904 +70,VM_12,0.13169 +70,VM_5,0.122882 +70,VM_66,0.126982 +70,VM_28,0.14336 +70,VM_30,0.107369 +70,VM_28,0.012822 +70,VM_31,0.142834 +70,VM_22,0.132367 +70,VM_9,0.125535 +70,VM_17,0.126132 +70,VM_6,0.132804 +70,VM_27,0.1269 +70,VM_32,0.135988 +70,VM_38,0.124247 +70,VM_20,0.122026 +70,VM_27,0.021669 +70,VM_31,0.013733 +70,VM_41,0.119232 +70,VM_0,0.118157 +70,VM_29,0.132528 +70,VM_18,0.122536 +70,VM_64,0.120848 +70,VM_68,0.120002 +70,VM_17,0.011483 +70,VM_31,0.017325 +70,VM_52,0.140542 +70,VM_23,0.122947 +70,VM_38,0.016746 +70,VM_51,0.123528 +70,VM_34,0.019889 +70,VM_46,0.120421 +70,VM_32,0.013544 +70,VM_60,0.124365 +70,VM_29,0.013267 +70,VM_22,0.00968 +70,VM_60,0.02075 +70,VM_18,0.01444 +70,VM_57,0.140238 +70,VM_50,0.122998 +70,VM_11,0.048505 +70,VM_11,0.015391 +70,VM_17,0.023726 +70,VM_0,0.007579 +70,VM_64,0.017656 +70,VM_32,0.017333 +70,VM_38,0.013436 +70,VM_18,0.058362 +70,VM_18,0.01445 +70,VM_54,0.148757 +70,VM_21,0.155407 +70,VM_47,0.149126 +70,VM_20,0.01814 +70,VM_64,0.009874 +70,VM_21,0.039934 +70,VM_6,0.016026 +70,VM_53,0.144388 +70,VM_11,0.015007 +70,VM_41,0.020235 +70,VM_60,0.022938 +70,VM_66,0.013583 +70,VM_35,0.15746 +70,VM_36,0.160315 +70,VM_59,0.136365 +70,VM_34,0.018096 +70,VM_45,0.168957 +70,VM_33,0.147765 +70,VM_42,0.156086 +70,VM_30,0.016364 +70,VM_19,0.089988 +70,VM_38,0.049636 +70,VM_10,0.148985 +70,VM_36,0.018318 +70,VM_43,0.162462 +70,VM_52,0.011037 +70,VM_9,0.017574 +70,VM_17,0.007724 +70,VM_47,0.021409 +70,VM_51,0.013269 +70,VM_11,0.008792 +70,VM_37,0.147089 +70,VM_36,0.017071 +70,VM_28,0.007604 +70,VM_45,0.01721 +70,VM_55,0.091451 +70,VM_26,0.024558 +70,VM_27,0.149512 +70,VM_24,0.506601 +70,VM_67,0.154383 +70,VM_65,0.128635 +70,VM_3,0.114361 +70,VM_51,0.107324 +70,VM_30,0.127508 +70,VM_53,0.13262 +70,VM_36,0.13984 +70,VM_21,0.136867 +70,VM_59,0.131454 +70,VM_7,0.115526 +70,VM_63,0.138049 +70,VM_25,0.132437 +70,VM_8,0.116864 +70,VM_24,0.013644 +70,VM_68,0.109192 +70,VM_8,0.016155 +70,VM_16,0.112571 +70,VM_14,0.112145 +70,VM_54,0.121084 +70,VM_29,0.142116 +70,VM_31,0.127238 +70,VM_34,0.139749 +70,VM_40,0.130667 +70,VM_52,0.140105 +70,VM_10,0.140808 +70,VM_42,0.109398 +70,VM_56,0.112968 +70,VM_58,0.13046 +70,VM_13,0.126663 +70,VM_59,0.010834 +70,VM_0,0.112793 +70,VM_47,0.106765 +70,VM_0,0.023717 +70,VM_68,0.014326 +70,VM_11,0.183177 +70,VM_67,0.019846 +70,VM_6,0.981631 +70,VM_6,0.282813 +70,VM_52,0.025156 +70,VM_13,0.016071 +70,VM_41,0.141733 +70,VM_55,0.016004 +70,VM_29,0.01979 +70,VM_0,0.01084 +70,VM_22,0.140812 +70,VM_3,0.016774 +70,VM_57,0.146092 +70,VM_13,0.025267 +70,VM_18,0.163793 +70,VM_44,0.1343 +70,VM_19,0.174158 +70,VM_41,0.014274 +70,VM_10,0.039717 +70,VM_15,0.230884 +70,VM_25,0.022387 +70,VM_4,0.145023 +70,VM_39,0.151001 +70,VM_13,0.018263 +70,VM_34,0.02018 +70,VM_18,0.022928 +70,VM_63,0.017256 +70,VM_42,0.012964 +70,VM_46,0.144642 +70,VM_51,0.026926 +70,VM_4,0.014771 +70,VM_69,0.151579 +70,VM_55,0.016308 +70,VM_8,0.014043 +70,VM_61,0.140077 +70,VM_52,0.010695 +70,VM_9,0.148442 +70,VM_47,0.011296 +70,VM_69,0.013423 +70,VM_20,0.143408 +70,VM_64,0.26192 +70,VM_32,0.160817 +70,VM_19,0.011014 +70,VM_49,0.165637 +70,VM_47,0.014459 +70,VM_61,0.014048 +70,VM_60,0.144157 +70,VM_62,0.178963 +70,VM_67,0.013493 +70,VM_52,0.023516 +70,VM_10,0.009642 +70,VM_18,0.011847 +70,VM_32,0.01998 +70,VM_1,0.158681 +70,VM_25,0.012278 +70,VM_65,0.009176 +70,VM_41,0.012997 +70,VM_60,0.015125 +70,VM_35,0.153207 +70,VM_55,0.019347 +70,VM_12,0.139847 +70,VM_25,0.013099 +70,VM_59,0.007385 +70,VM_47,0.014706 +70,VM_63,0.035654 +70,VM_30,0.0094 +70,VM_14,0.081218 +70,VM_14,0.16702 +80,VM_0,0.010682 +80,VM_78,0.152291 +80,VM_40,0.162058 +80,VM_48,0.149058 +80,VM_26,0.182898 +80,VM_66,0.146584 +80,VM_70,0.143812 +80,VM_57,0.173422 +80,VM_61,0.167266 +80,VM_25,0.154231 +80,VM_37,0.139148 +80,VM_57,0.020772 +80,VM_58,0.169039 +80,VM_45,0.147396 +80,VM_24,0.15957 +80,VM_45,0.014799 +80,VM_75,0.159607 +80,VM_55,0.160932 +80,VM_40,0.014739 +80,VM_27,0.135199 +80,VM_19,0.137268 +80,VM_61,0.008317 +80,VM_47,0.15735 +80,VM_26,0.011598 +80,VM_63,0.154606 +80,VM_64,0.139485 +80,VM_36,0.150579 +80,VM_53,0.574677 +80,VM_23,0.175475 +80,VM_19,0.029686 +80,VM_43,0.20926 +80,VM_44,0.321146 +80,VM_9,0.2286 +80,VM_27,0.009859 +80,VM_68,0.437635 +80,VM_77,0.295533 +80,VM_24,0.021894 +80,VM_20,0.669888 +80,VM_46,0.737843 +80,VM_15,0.1 +80,VM_69,0.012759 +80,VM_60,0.240035 +80,VM_16,0.581511 +80,VM_68,0.225893 +80,VM_14,0.277302 +80,VM_25,0.39405 +80,VM_50,0.358502 +80,VM_41,0.154183 +80,VM_40,0.480081 +80,VM_62,0.401447 +80,VM_66,0.824008 +80,VM_16,0.02428 +80,VM_47,0.230677 +80,VM_46,0.155956 +80,VM_62,0.015332 +80,VM_19,0.159808 +80,VM_7,0.294798 +80,VM_7,0.978223 +80,VM_11,0.159923 +80,VM_55,0.144456 +80,VM_68,0.011666 +80,VM_38,0.139105 +80,VM_41,0.010328 +80,VM_74,0.158518 +80,VM_13,0.14382 +80,VM_16,0.02631 +80,VM_7,0.023505 +80,VM_5,0.1744 +80,VM_77,0.143252 +80,VM_38,0.012075 +80,VM_79,0.149828 +80,VM_65,0.150094 +80,VM_35,0.156257 +80,VM_12,0.139117 +80,VM_14,0.009308 +80,VM_74,0.024533 +80,VM_24,0.156138 +80,VM_33,0.158776 +80,VM_59,0.155462 +80,VM_35,0.016444 +80,VM_31,0.151458 +80,VM_54,0.164477 +80,VM_37,0.154452 +80,VM_48,0.150591 +80,VM_10,0.161127 +80,VM_48,0.025536 +80,VM_11,0.017725 +80,VM_60,0.015235 +80,VM_38,0.008224 +80,VM_77,0.015467 +80,VM_51,0.165159 +80,VM_0,0.162016 +80,VM_10,0.020925 +80,VM_14,0.013978 +80,VM_73,0.158133 +80,VM_26,0.074948 +80,VM_69,0.016267 +80,VM_37,0.15285 +80,VM_15,0.169605 +80,VM_59,0.143486 +80,VM_25,0.165376 +80,VM_33,0.177271 +80,VM_42,0.240307 +80,VM_35,0.182443 +80,VM_34,0.791049 +80,VM_34,0.375094 +80,VM_38,0.199505 +80,VM_75,0.194486 +80,VM_74,0.801902 +80,VM_66,0.814746 +80,VM_28,0.742678 +80,VM_12,0.449652 +80,VM_40,0.402769 +80,VM_39,0.712226 +80,VM_66,0.031918 +80,VM_27,0.256516 +80,VM_68,0.181269 +80,VM_70,0.129768 +80,VM_25,0.041255 +80,VM_63,0.50564 +80,VM_0,0.718401 +80,VM_36,0.961231 +80,VM_76,0.492188 +80,VM_5,0.887742 +80,VM_12,0.043161 +80,VM_64,0.479173 +80,VM_78,0.191776 +80,VM_59,0.01499 +80,VM_41,0.073148 +80,VM_69,0.021375 +80,VM_4,0.171334 +80,VM_24,0.874653 +80,VM_30,0.172713 +80,VM_19,0.169309 +80,VM_73,0.160343 +80,VM_38,0.148677 +80,VM_10,0.484832 +80,VM_19,0.02814 +80,VM_73,0.029725 +80,VM_41,0.013771 +80,VM_55,0.403105 +80,VM_21,0.158904 +80,VM_48,0.154244 +80,VM_63,0.150035 +80,VM_27,0.16281 +80,VM_38,0.042234 +80,VM_0,0.209267 +80,VM_63,0.012147 +80,VM_46,0.306972 +80,VM_56,0.149846 +80,VM_61,0.170175 +80,VM_12,0.179071 +80,VM_26,0.224942 +80,VM_4,0.038834 +80,VM_25,0.150802 +80,VM_1,0.1587 +80,VM_41,0.023524 +80,VM_58,0.147746 +80,VM_25,0.021231 +80,VM_66,0.137347 +80,VM_28,0.159628 +80,VM_3,0.162129 +80,VM_65,0.142748 +80,VM_29,0.141857 +80,VM_7,0.162916 +80,VM_24,0.01532 +80,VM_38,0.013288 +80,VM_0,0.027651 +80,VM_53,0.177018 +80,VM_26,0.017251 +80,VM_68,0.029807 +80,VM_50,0.462024 +80,VM_64,0.016711 +80,VM_75,0.703292 +80,VM_5,0.890055 +80,VM_15,0.573042 +80,VM_38,0.009238 +80,VM_62,0.534514 +80,VM_28,0.01696 +80,VM_26,0.028007 +80,VM_42,0.322421 +90,VM_29,0.022051 +90,VM_45,0.628672 +90,VM_9,0.468949 +90,VM_18,0.142655 +90,VM_35,0.157179 +90,VM_38,0.139461 +90,VM_58,0.178895 +90,VM_12,0.152015 +90,VM_51,0.154446 +90,VM_30,0.170657 +90,VM_19,0.162323 +90,VM_17,0.169038 +90,VM_45,0.141514 +90,VM_74,0.145483 +90,VM_22,0.171364 +90,VM_61,0.162474 +90,VM_39,0.162682 +90,VM_46,0.171658 +90,VM_4,0.143944 +90,VM_87,0.176315 +90,VM_78,0.150768 +90,VM_51,0.021229 +90,VM_87,0.017496 +90,VM_56,0.16781 +90,VM_79,0.166515 +90,VM_48,0.167456 +90,VM_15,0.169479 +90,VM_75,0.141751 +90,VM_32,0.15798 +90,VM_8,0.163118 +90,VM_88,0.161149 +90,VM_31,0.159948 +90,VM_40,0.173162 +90,VM_87,0.013211 +90,VM_30,0.021656 +90,VM_76,0.131454 +90,VM_52,0.132775 +90,VM_12,0.019203 +90,VM_24,0.133533 +90,VM_56,0.017049 +90,VM_3,0.145996 +90,VM_75,0.018041 +90,VM_50,0.01278 +90,VM_35,0.133826 +90,VM_33,0.139016 +90,VM_80,0.13478 +90,VM_88,0.155147 +90,VM_47,0.140044 +90,VM_14,0.119958 +90,VM_13,0.134318 +90,VM_2,0.13849 +90,VM_23,0.11003 +90,VM_68,0.153931 +90,VM_81,0.116868 +90,VM_57,0.132795 +90,VM_10,0.125986 +90,VM_6,0.137851 +90,VM_76,0.136503 +90,VM_72,0.135556 +90,VM_28,0.138886 +90,VM_26,0.134764 +90,VM_56,0.108572 +90,VM_74,0.148762 +90,VM_63,0.156475 +90,VM_13,0.013915 +90,VM_31,0.154151 +90,VM_43,0.115504 +90,VM_53,0.13532 +90,VM_68,0.011484 +90,VM_59,0.133066 +90,VM_33,0.017418 +90,VM_9,0.117033 +90,VM_27,0.134524 +90,VM_87,0.143236 +90,VM_63,0.015067 +90,VM_45,0.133558 +90,VM_26,0.018425 +90,VM_43,0.017442 +90,VM_54,0.135877 +90,VM_17,0.134213 +90,VM_77,0.152972 +90,VM_7,0.153101 +90,VM_44,0.138725 +90,VM_22,0.149212 +90,VM_80,0.016014 +90,VM_64,0.142776 +90,VM_46,0.154079 +90,VM_18,0.170907 +90,VM_16,0.179303 +90,VM_66,0.146394 +90,VM_1,0.159655 +90,VM_62,0.144013 +90,VM_29,0.150829 +90,VM_46,0.026613 +90,VM_51,0.158402 +90,VM_15,0.158075 +90,VM_39,0.164219 +90,VM_9,0.019094 +90,VM_88,0.027586 +90,VM_23,0.009525 +90,VM_36,0.167367 +90,VM_46,0.015338 +90,VM_27,0.021115 +90,VM_33,0.020602 +90,VM_9,0.01496 +90,VM_17,0.015519 +90,VM_42,0.159212 +90,VM_72,0.016825 +90,VM_79,0.152009 +90,VM_1,0.012968 +90,VM_33,0.011938 +90,VM_2,0.016023 +90,VM_53,0.016306 +90,VM_89,0.129642 +90,VM_0,0.1156 +90,VM_28,0.011727 +90,VM_2,0.009127 +90,VM_11,0.144322 +90,VM_15,0.009436 +90,VM_11,0.020589 +90,VM_6,0.015825 +90,VM_67,0.139295 +90,VM_4,0.125945 +90,VM_5,0.135548 +90,VM_52,0.129676 +90,VM_81,0.015785 +90,VM_40,0.115333 +90,VM_56,0.020919 +90,VM_30,0.145356 +90,VM_28,0.023083 +90,VM_0,0.020372 +90,VM_76,0.015262 +90,VM_7,0.012028 +90,VM_57,0.010389 +90,VM_39,0.009863 +90,VM_45,0.019378 +90,VM_9,0.013925 +90,VM_25,0.137412 +90,VM_59,0.016798 +90,VM_60,0.13135 +90,VM_21,0.127165 +90,VM_79,0.012581 +90,VM_13,0.009316 +90,VM_46,0.022722 +90,VM_77,0.013778 +90,VM_56,0.012822 +90,VM_87,0.017602 +90,VM_57,0.016551 +90,VM_31,0.02179 +90,VM_81,0.008272 +90,VM_45,0.009596 +90,VM_10,0.01467 +90,VM_69,0.134736 +90,VM_36,0.011457 +90,VM_30,0.013374 +90,VM_45,0.018662 +90,VM_35,0.014005 +90,VM_40,0.019447 +90,VM_3,0.158273 +90,VM_26,0.017092 +90,VM_51,0.020783 +90,VM_6,0.024396 +90,VM_81,0.020526 +90,VM_3,0.008019 +90,VM_40,0.019194 +90,VM_72,0.009603 +90,VM_67,0.04683 +90,VM_12,0.154846 +90,VM_35,0.010467 +90,VM_86,0.087855 +90,VM_50,0.010921 +90,VM_53,0.181732 +90,VM_71,0.163252 +90,VM_68,0.184473 +90,VM_35,0.166145 +90,VM_67,0.158908 +90,VM_76,0.173319 +90,VM_18,0.164536 +90,VM_40,0.159607 +90,VM_12,0.163335 +90,VM_78,0.151054 +90,VM_32,0.171633 +90,VM_3,0.170825 +90,VM_43,0.18028 +90,VM_19,0.168129 +90,VM_62,0.163725 +90,VM_27,0.14913 +90,VM_5,0.143615 +90,VM_10,0.141931 +90,VM_79,0.13375 +90,VM_1,0.137106 +90,VM_42,0.138938 +90,VM_84,0.125882 +90,VM_41,0.167759 +90,VM_52,0.121161 +100,VM_38,0.132473 +100,VM_22,0.131153 +100,VM_14,0.144213 +100,VM_25,0.130949 +100,VM_77,0.128182 +100,VM_43,0.151935 +100,VM_14,0.014655 +100,VM_64,0.148758 +100,VM_94,0.121363 +100,VM_12,0.135895 +100,VM_17,0.118605 +100,VM_97,0.12427 +100,VM_15,0.146279 +100,VM_69,0.121859 +100,VM_34,0.120773 +100,VM_64,0.012383 +100,VM_4,0.134552 +100,VM_88,0.146189 +100,VM_21,0.123783 +100,VM_61,0.139617 +100,VM_99,0.131855 +100,VM_0,0.122296 +100,VM_27,0.166754 +100,VM_83,0.14451 +100,VM_90,0.174716 +100,VM_56,0.136061 +100,VM_97,0.035076 +100,VM_71,0.142445 +100,VM_23,0.164125 +100,VM_97,0.010962 +100,VM_40,0.169491 +100,VM_41,0.150727 +100,VM_33,0.142893 +100,VM_93,0.16219 +100,VM_49,0.140181 +100,VM_9,0.157256 +100,VM_62,0.165444 +100,VM_0,0.009898 +100,VM_78,0.167887 +100,VM_1,0.155277 +100,VM_37,0.15891 +100,VM_14,0.043391 +100,VM_58,0.429958 +100,VM_93,0.019054 +100,VM_65,0.181855 +100,VM_48,0.355682 +100,VM_29,0.753465 +100,VM_37,0.045352 +100,VM_47,0.683465 +100,VM_13,0.603959 +100,VM_2,0.467422 +100,VM_70,0.295626 +100,VM_12,0.034331 +100,VM_95,0.161976 +100,VM_23,0.019467 +100,VM_5,0.700039 +100,VM_5,0.907664 +100,VM_66,0.139673 +100,VM_88,0.018638 +100,VM_61,0.013252 +100,VM_39,0.137829 +100,VM_2,0.016249 +100,VM_62,0.008521 +100,VM_22,0.009571 +100,VM_4,0.009833 +100,VM_56,0.016697 +100,VM_91,0.138087 +100,VM_21,0.008489 +100,VM_14,0.016287 +100,VM_92,0.122767 +100,VM_78,0.01813 +100,VM_0,0.011486 +100,VM_99,0.0121 +100,VM_8,0.131952 +100,VM_99,0.021201 +100,VM_89,0.121543 +100,VM_67,0.121001 +100,VM_23,0.015972 +100,VM_53,0.136411 +100,VM_2,0.01095 +100,VM_70,0.014297 +100,VM_6,0.172152 +100,VM_67,0.020551 +100,VM_78,0.010034 +100,VM_33,0.011105 +100,VM_92,0.0166 +100,VM_8,0.014202 +100,VM_42,0.143564 +100,VM_11,0.117832 +100,VM_86,0.130264 +100,VM_47,0.015914 +100,VM_28,0.1385 +100,VM_27,0.016154 +100,VM_77,0.019382 +100,VM_2,0.020152 +100,VM_19,0.130071 +100,VM_16,0.164059 +100,VM_56,0.01335 +100,VM_19,0.028798 +100,VM_56,0.02094 +100,VM_76,0.164211 +100,VM_54,0.135909 +100,VM_3,0.172456 +100,VM_55,0.171259 +100,VM_42,0.024334 +100,VM_81,0.158336 +100,VM_64,0.018757 +100,VM_56,0.022674 +100,VM_63,0.166125 +100,VM_69,0.023009 +100,VM_59,0.164729 +100,VM_54,0.010941 +100,VM_17,0.019616 +100,VM_29,0.01991 +100,VM_16,0.013967 +100,VM_21,0.016823 +100,VM_8,0.023357 +100,VM_61,0.017684 +100,VM_24,0.148556 +100,VM_94,0.014418 +100,VM_85,0.1708 +100,VM_53,0.010626 +100,VM_38,0.156729 +100,VM_85,0.020867 +100,VM_55,0.019714 +100,VM_76,0.028986 +100,VM_71,0.009466 +100,VM_22,0.015427 +100,VM_24,0.009184 +100,VM_7,0.154791 +100,VM_30,0.148233 +100,VM_14,0.009137 +100,VM_17,0.011163 +100,VM_99,0.025333 +100,VM_18,0.13605 +100,VM_5,0.021656 +100,VM_22,0.012239 +100,VM_56,0.021869 +100,VM_42,0.01608 +100,VM_65,0.01759 +100,VM_7,0.015866 +100,VM_29,0.012719 +100,VM_81,0.013379 +100,VM_52,0.126803 +100,VM_50,0.13641 +100,VM_77,0.009507 +100,VM_81,0.035815 +100,VM_24,0.010985 +100,VM_85,0.014751 +100,VM_16,0.013359 +100,VM_83,0.010445 +100,VM_58,0.014885 +100,VM_60,0.132657 +100,VM_80,0.132953 +100,VM_50,0.015157 +100,VM_78,0.009435 +100,VM_15,0.017326 +100,VM_49,0.009026 +100,VM_66,0.015256 +100,VM_78,0.0127 +100,VM_35,0.13231 +100,VM_73,0.135937 +100,VM_67,0.025785 +100,VM_63,0.01059 +100,VM_8,0.011115 +100,VM_36,0.142457 +100,VM_63,0.025554 +100,VM_27,0.013563 +100,VM_62,0.009639 +100,VM_36,0.024416 +100,VM_18,0.00891 +100,VM_3,0.01063 +100,VM_24,0.016327 +100,VM_23,0.010613 +100,VM_88,0.009945 +100,VM_68,0.146074 +100,VM_95,0.014615 +100,VM_33,0.01436 +100,VM_70,0.019343 +100,VM_33,0.025964 +100,VM_68,0.028891 +100,VM_64,0.015607 +100,VM_78,0.027803 +100,VM_86,0.011267 +100,VM_76,0.027891 +100,VM_47,0.023446 +100,VM_53,0.0199 +100,VM_1,0.019093 +100,VM_39,0.052718 +100,VM_39,0.024319 +110,VM_21,0.030429 +110,VM_53,0.158197 +110,VM_19,0.142324 +110,VM_78,0.12673 +110,VM_3,0.165172 +110,VM_75,0.137391 +110,VM_38,0.137258 +110,VM_72,0.145238 +110,VM_58,0.157555 +110,VM_59,0.140438 +110,VM_11,0.141874 +110,VM_96,0.131859 +110,VM_12,0.152346 +110,VM_59,0.024637 +110,VM_12,0.011876 +110,VM_48,0.13215 +110,VM_65,0.140025 +110,VM_45,0.145005 +110,VM_72,0.013667 +110,VM_76,0.142361 +110,VM_88,0.148028 +110,VM_76,0.014684 +110,VM_27,0.160731 +110,VM_108,0.14474 +110,VM_35,0.146159 +110,VM_90,0.172537 +110,VM_94,0.1484 +110,VM_92,0.143459 +110,VM_41,0.145506 +110,VM_46,0.176194 +110,VM_68,0.166654 +110,VM_12,0.024132 +110,VM_3,0.012256 +110,VM_82,0.166772 +110,VM_101,0.168797 +110,VM_33,0.164931 +110,VM_23,0.153307 +110,VM_79,0.162556 +110,VM_43,0.175042 +110,VM_20,0.163345 +110,VM_15,0.160547 +110,VM_83,0.965503 +110,VM_83,0.317746 +110,VM_101,0.016578 +110,VM_87,0.157923 +110,VM_1,0.147481 +110,VM_56,0.152191 +110,VM_107,0.139158 +110,VM_61,0.17112 +110,VM_102,0.138778 +110,VM_56,0.031827 +110,VM_69,0.179237 +110,VM_15,0.029979 +110,VM_24,0.138011 +110,VM_35,0.018025 +110,VM_67,0.134239 +110,VM_57,0.143185 +110,VM_81,0.14451 +110,VM_61,0.012861 +110,VM_48,0.009426 +110,VM_77,0.142899 +110,VM_21,0.137428 +110,VM_23,0.017493 +110,VM_40,0.137917 +110,VM_19,0.015724 +110,VM_85,0.155109 +110,VM_61,0.020376 +110,VM_81,0.019688 +110,VM_89,0.168544 +110,VM_8,0.155411 +110,VM_58,0.02138 +110,VM_92,0.010078 +110,VM_102,0.009176 +110,VM_68,0.0192 +110,VM_2,0.156625 +110,VM_68,0.019378 +110,VM_63,0.153286 +110,VM_68,0.026811 +110,VM_12,0.020472 +110,VM_29,0.152541 +110,VM_71,0.138146 +110,VM_108,0.009321 +110,VM_61,0.011247 +110,VM_20,0.016647 +110,VM_77,0.012583 +110,VM_104,0.296032 +110,VM_104,0.081004 +110,VM_78,0.017335 +110,VM_77,0.011259 +110,VM_99,0.156394 +110,VM_42,0.13088 +110,VM_7,0.165521 +110,VM_75,0.014717 +110,VM_83,0.02337 +110,VM_25,0.142136 +110,VM_86,0.147478 +110,VM_54,0.155024 +110,VM_20,0.013692 +110,VM_104,0.009796 +110,VM_79,0.010529 +110,VM_22,0.150863 +110,VM_36,0.126501 +110,VM_16,0.164461 +110,VM_70,0.139208 +110,VM_95,0.152215 +110,VM_96,0.028497 +110,VM_103,0.157134 +110,VM_98,0.165963 +110,VM_71,0.023268 +110,VM_78,0.023766 +110,VM_28,0.147207 +110,VM_88,0.028252 +110,VM_107,0.012013 +110,VM_24,0.02108 +110,VM_27,0.017869 +110,VM_62,0.142382 +110,VM_100,0.147441 +110,VM_21,0.025346 +110,VM_61,0.032033 +110,VM_92,0.026112 +110,VM_25,0.010831 +110,VM_69,0.027011 +110,VM_11,0.014969 +110,VM_16,0.014396 +110,VM_15,0.007749 +110,VM_70,0.008198 +110,VM_25,0.020577 +110,VM_105,0.15593 +110,VM_6,0.166194 +110,VM_51,0.14269 +110,VM_95,0.011015 +110,VM_70,0.023856 +110,VM_76,0.00895 +110,VM_109,0.143695 +110,VM_6,0.01022 +110,VM_109,0.022942 +110,VM_76,0.018735 +110,VM_5,0.159025 +110,VM_88,0.008205 +110,VM_69,0.013199 +110,VM_33,0.014983 +110,VM_74,0.147418 +110,VM_81,0.009414 +110,VM_12,0.011256 +110,VM_65,0.018042 +110,VM_16,0.016312 +110,VM_60,0.140565 +110,VM_108,0.024328 +110,VM_64,0.131382 +110,VM_31,0.159623 +110,VM_13,0.156081 +110,VM_33,0.018724 +110,VM_96,0.028784 +110,VM_37,0.140071 +110,VM_109,0.011681 +110,VM_23,0.017195 +110,VM_84,0.151709 +110,VM_68,0.014297 +110,VM_3,0.009806 +110,VM_91,0.140395 +110,VM_29,0.016071 +110,VM_65,0.014933 +110,VM_30,0.137644 +110,VM_83,0.008771 +110,VM_9,0.159972 +110,VM_97,0.153455 +110,VM_54,0.017644 +110,VM_77,0.011399 +110,VM_5,0.008677 +110,VM_51,0.019874 +110,VM_34,0.123011 +110,VM_74,0.045938 +110,VM_74,0.008203 +110,VM_0,0.16377 +110,VM_99,0.017912 +110,VM_66,0.166797 +110,VM_92,0.159458 +110,VM_74,0.013207 +110,VM_65,0.176818 +110,VM_28,0.136338 +110,VM_74,0.012932 +110,VM_20,0.155455 +110,VM_107,0.163231 +110,VM_48,0.183256 +110,VM_33,0.154336 +110,VM_86,0.156474 +110,VM_91,0.166768 +110,VM_102,0.183262 +110,VM_94,0.177346 +110,VM_84,0.173269 +110,VM_87,0.147094 +110,VM_33,0.012147 +120,VM_4,0.162661 +120,VM_57,0.182224 +120,VM_106,0.161694 +120,VM_10,0.167704 +120,VM_90,0.185137 +120,VM_93,0.159017 +120,VM_69,0.162537 +120,VM_82,0.177244 +120,VM_3,0.169275 +120,VM_10,0.035061 +120,VM_86,0.139719 +120,VM_75,0.163183 +120,VM_26,0.17346 +120,VM_29,0.133376 +120,VM_30,0.153505 +120,VM_85,0.199608 +120,VM_50,0.07986 +120,VM_54,0.012729 +120,VM_67,0.174566 +120,VM_88,0.178832 +120,VM_15,0.182648 +120,VM_78,0.153222 +120,VM_47,0.142953 +120,VM_108,0.166846 +120,VM_1,0.139156 +120,VM_45,0.169149 +120,VM_8,0.149332 +120,VM_113,0.124712 +120,VM_11,0.147556 +120,VM_59,0.154622 +120,VM_9,0.127792 +120,VM_111,0.141247 +120,VM_67,0.008701 +120,VM_96,0.113382 +120,VM_88,0.009552 +120,VM_64,0.143364 +120,VM_52,0.139682 +120,VM_20,0.143705 +120,VM_55,0.138204 +120,VM_67,0.011292 +120,VM_30,0.138347 +120,VM_7,0.137487 +120,VM_58,0.161786 +120,VM_115,0.130375 +120,VM_119,0.13517 +120,VM_56,0.137662 +120,VM_86,0.129775 +120,VM_90,0.141557 +120,VM_87,0.163682 +120,VM_117,0.164617 +120,VM_2,0.137052 +120,VM_73,0.137071 +120,VM_74,0.142198 +120,VM_20,0.024942 +120,VM_114,0.15137 +120,VM_27,0.164576 +120,VM_118,0.141564 +120,VM_47,0.01161 +120,VM_8,0.011657 +120,VM_117,0.009543 +120,VM_39,0.157389 +120,VM_118,0.012839 +120,VM_101,0.13667 +120,VM_67,0.017687 +120,VM_91,0.149212 +120,VM_63,0.148556 +120,VM_24,0.149224 +120,VM_71,0.159156 +120,VM_52,0.010784 +120,VM_109,0.156635 +120,VM_70,0.141071 +120,VM_18,0.142715 +120,VM_66,0.154809 +120,VM_73,0.03041 +120,VM_54,0.015404 +120,VM_12,0.15517 +120,VM_9,0.164919 +120,VM_70,0.177153 +120,VM_60,0.181483 +120,VM_7,0.146495 +120,VM_61,0.146843 +120,VM_21,0.156705 +120,VM_56,0.16399 +120,VM_1,0.163707 +120,VM_0,0.150646 +120,VM_34,0.163844 +120,VM_116,0.153783 +120,VM_62,0.156567 +120,VM_88,0.171386 +120,VM_62,0.032509 +120,VM_28,0.172988 +120,VM_9,0.036696 +120,VM_32,0.153558 +120,VM_117,0.173433 +120,VM_81,0.154228 +120,VM_95,0.17024 +120,VM_68,0.158042 +120,VM_97,0.169617 +120,VM_80,0.16398 +120,VM_71,0.136759 +120,VM_114,0.121266 +120,VM_95,0.009669 +120,VM_105,0.148601 +120,VM_13,0.1507 +120,VM_93,0.156248 +120,VM_116,0.06691 +120,VM_116,0.011293 +120,VM_27,0.141837 +120,VM_116,0.030733 +120,VM_56,0.015282 +120,VM_102,0.135938 +120,VM_3,0.157955 +120,VM_84,0.171379 +120,VM_70,0.012799 +120,VM_29,0.135423 +120,VM_77,0.145039 +120,VM_0,0.009834 +120,VM_27,0.01096 +120,VM_76,0.175617 +120,VM_102,0.017578 +120,VM_23,0.171798 +120,VM_68,0.01507 +120,VM_60,0.016997 +120,VM_33,0.165717 +120,VM_12,0.028443 +120,VM_50,0.147107 +120,VM_105,0.016435 +120,VM_5,0.141786 +120,VM_68,0.020286 +120,VM_42,0.142291 +120,VM_70,0.012918 +120,VM_116,0.010099 +120,VM_119,0.124075 +120,VM_82,0.157266 +120,VM_110,0.146324 +120,VM_15,0.141901 +120,VM_111,0.143639 +120,VM_115,0.141428 +120,VM_117,0.018709 +120,VM_41,0.146012 +120,VM_97,0.030883 +120,VM_82,0.022594 +120,VM_100,0.149787 +120,VM_6,0.137131 +120,VM_32,0.026371 +120,VM_110,0.009025 +120,VM_19,0.144198 +120,VM_83,0.140737 +120,VM_0,0.01807 +120,VM_70,0.025069 +120,VM_26,0.144211 +120,VM_71,0.021712 +120,VM_7,0.015507 +120,VM_50,0.026048 +120,VM_9,0.008125 +120,VM_73,0.01475 +120,VM_21,0.014557 +120,VM_104,0.337652 +120,VM_15,0.018753 +120,VM_87,0.172624 +120,VM_2,0.154806 +120,VM_6,0.013584 +120,VM_30,0.159512 +120,VM_58,0.144511 +120,VM_45,0.17754 +120,VM_16,0.141096 +120,VM_106,0.167856 +120,VM_111,0.01068 +120,VM_62,0.013241 +120,VM_47,0.155577 +120,VM_24,0.161613 +120,VM_94,0.174498 +120,VM_111,0.031307 +120,VM_87,0.026329 +120,VM_99,0.146797 +120,VM_69,0.162235 +120,VM_107,0.156889 +120,VM_20,0.139183 +120,VM_113,0.11271 +120,VM_81,0.025462 +120,VM_114,0.014273 +120,VM_18,0.122063 +120,VM_115,0.017635 +120,VM_67,0.167177 +120,VM_83,0.021309 +120,VM_29,0.020143 +120,VM_45,0.010585 +120,VM_5,0.02489 +120,VM_19,0.011974 +120,VM_36,0.133297 +120,VM_20,0.018221 +120,VM_83,0.017804 +130,VM_74,0.151719 +130,VM_122,0.148676 +130,VM_86,0.166526 +130,VM_96,0.15253 +130,VM_50,0.163887 +130,VM_86,0.012631 +130,VM_91,0.142417 +130,VM_112,0.150249 +130,VM_35,0.146134 +130,VM_53,0.139145 +130,VM_127,0.153235 +130,VM_77,0.145835 +130,VM_62,0.151264 +130,VM_113,0.162695 +130,VM_96,0.013477 +130,VM_72,0.182664 +130,VM_65,0.165728 +130,VM_78,0.096509 +130,VM_38,0.012429 +130,VM_122,0.159495 +130,VM_73,0.154155 +130,VM_47,0.148516 +130,VM_43,0.181742 +130,VM_116,0.16671 +130,VM_28,0.161303 +130,VM_53,0.1255 +130,VM_38,0.016207 +130,VM_119,0.172948 +130,VM_82,0.18728 +130,VM_71,0.158907 +130,VM_31,0.169587 +130,VM_69,0.151529 +130,VM_112,0.175301 +130,VM_25,0.166415 +130,VM_45,0.162633 +130,VM_4,0.151432 +130,VM_65,0.184379 +130,VM_125,0.175941 +130,VM_112,0.022508 +130,VM_43,0.159932 +130,VM_52,0.155496 +130,VM_61,0.165863 +130,VM_37,0.135242 +130,VM_101,0.158299 +130,VM_5,0.150388 +130,VM_12,0.169023 +130,VM_16,0.167487 +130,VM_106,0.152582 +130,VM_92,0.172183 +130,VM_14,0.144487 +130,VM_9,0.147519 +130,VM_90,0.144234 +130,VM_99,0.16713 +130,VM_73,0.166747 +130,VM_6,0.138721 +130,VM_113,0.148684 +130,VM_121,0.139953 +130,VM_105,0.135903 +130,VM_31,0.01924 +130,VM_21,0.134616 +130,VM_9,0.014694 +130,VM_14,0.017669 +130,VM_29,0.177122 +130,VM_118,0.133012 +130,VM_42,0.147887 +130,VM_39,0.161083 +130,VM_48,0.157976 +130,VM_23,0.165886 +130,VM_58,0.135252 +130,VM_18,0.15273 +130,VM_106,0.008813 +130,VM_124,0.140551 +130,VM_48,0.026481 +130,VM_76,0.153779 +130,VM_5,0.018606 +130,VM_113,0.020121 +130,VM_66,0.144235 +130,VM_100,0.158289 +130,VM_58,0.011958 +130,VM_96,0.155833 +130,VM_72,0.132562 +130,VM_35,0.147971 +130,VM_118,0.012245 +130,VM_28,0.166733 +130,VM_127,0.166539 +130,VM_100,0.010465 +130,VM_28,0.011763 +130,VM_13,0.1551 +130,VM_108,0.124997 +130,VM_52,0.021773 +130,VM_107,0.147383 +130,VM_26,0.142149 +130,VM_93,0.172586 +130,VM_111,0.156165 +130,VM_82,0.023906 +130,VM_61,0.016483 +130,VM_105,0.022278 +130,VM_75,0.162304 +130,VM_35,0.020398 +130,VM_128,0.159765 +130,VM_15,0.161616 +130,VM_120,0.155772 +130,VM_124,0.019436 +130,VM_129,0.165278 +130,VM_97,0.166648 +130,VM_118,0.023494 +130,VM_111,0.036552 +130,VM_79,0.177538 +130,VM_95,0.16369 +130,VM_79,0.026479 +130,VM_63,0.174248 +130,VM_36,0.190806 +130,VM_57,0.165101 +130,VM_82,0.010232 +130,VM_32,0.182738 +130,VM_45,0.025976 +130,VM_116,0.17875 +130,VM_22,0.150853 +130,VM_43,0.024266 +130,VM_95,0.01061 +130,VM_8,0.144277 +130,VM_17,0.133662 +130,VM_65,0.012764 +130,VM_114,0.130916 +130,VM_32,0.022358 +130,VM_0,0.157772 +130,VM_129,0.00834 +130,VM_123,0.127842 +130,VM_4,0.013056 +130,VM_49,0.151024 +130,VM_54,0.138707 +130,VM_84,0.137222 +130,VM_116,0.010324 +130,VM_40,0.224392 +130,VM_100,0.011976 +130,VM_44,0.144323 +130,VM_20,0.134812 +130,VM_103,0.156919 +130,VM_32,0.013432 +130,VM_61,0.009209 +130,VM_108,0.019003 +130,VM_57,0.017596 +130,VM_49,0.024235 +130,VM_81,0.151745 +130,VM_112,0.025135 +130,VM_66,0.01171 +130,VM_65,0.008064 +130,VM_127,0.009631 +130,VM_53,0.015246 +130,VM_121,0.021889 +130,VM_102,0.159282 +130,VM_44,0.021524 +130,VM_40,0.01172 +130,VM_7,0.136998 +130,VM_75,0.013113 +130,VM_107,0.015607 +130,VM_55,0.158164 +130,VM_84,0.011116 +130,VM_111,0.011361 +130,VM_128,0.017177 +130,VM_24,0.152914 +130,VM_46,0.143449 +130,VM_23,0.012088 +130,VM_100,0.01334 +130,VM_35,0.020035 +130,VM_12,0.012128 +130,VM_81,0.016772 +130,VM_58,0.008374 +130,VM_26,0.018201 +130,VM_113,0.034195 +130,VM_128,0.020151 +130,VM_45,0.008736 +130,VM_56,0.139518 +130,VM_35,0.019075 +130,VM_91,0.745004 +130,VM_91,0.311008 +130,VM_62,0.153647 +130,VM_16,0.017296 +130,VM_41,0.156093 +130,VM_127,0.009964 +130,VM_4,0.025145 +130,VM_45,0.040496 +130,VM_123,0.032665 +130,VM_77,0.163581 +130,VM_101,0.020003 +130,VM_28,0.016825 +130,VM_68,0.178817 +130,VM_17,0.025313 +130,VM_60,0.181268 +130,VM_119,0.029196 +130,VM_17,0.04732 +140,VM_129,0.012774 +140,VM_24,0.160129 +140,VM_71,0.419901 +140,VM_42,0.162188 +140,VM_35,0.13284 +140,VM_125,0.678593 +140,VM_74,0.316466 +140,VM_41,0.813075 +140,VM_38,0.228235 +140,VM_71,0.031374 +140,VM_119,0.897949 +140,VM_125,0.039465 +140,VM_44,0.931563 +140,VM_93,0.637839 +140,VM_124,0.987352 +140,VM_15,0.55646 +140,VM_136,0.681732 +140,VM_53,0.3087 +140,VM_59,0.662485 +140,VM_56,0.029274 +140,VM_4,0.879622 +140,VM_66,0.615938 +140,VM_19,0.372447 +140,VM_10,0.995332 +140,VM_101,0.826096 +140,VM_33,0.133684 +140,VM_108,0.024431 +140,VM_57,0.224822 +140,VM_40,0.726169 +140,VM_26,0.144115 +140,VM_48,0.148837 +140,VM_54,0.171505 +140,VM_75,0.163487 +140,VM_38,0.160067 +140,VM_66,0.166512 +140,VM_70,0.176719 +140,VM_74,0.174532 +140,VM_91,0.176765 +140,VM_83,0.158408 +140,VM_29,0.176349 +140,VM_102,0.167873 +140,VM_57,0.020203 +140,VM_105,0.182594 +140,VM_131,0.209076 +140,VM_127,0.158381 +140,VM_62,0.156376 +140,VM_20,0.15056 +140,VM_78,0.14066 +140,VM_83,0.021402 +140,VM_12,0.316654 +140,VM_12,0.924938 +140,VM_81,0.160092 +140,VM_57,0.021515 +140,VM_16,0.165442 +140,VM_139,0.160113 +140,VM_52,0.197781 +140,VM_55,0.162923 +140,VM_20,0.012295 +140,VM_4,0.155993 +140,VM_86,0.144815 +140,VM_4,0.015783 +140,VM_51,0.167896 +140,VM_21,0.151259 +140,VM_7,0.192795 +140,VM_9,0.161477 +140,VM_131,0.02198 +140,VM_96,0.155605 +140,VM_100,0.139073 +140,VM_102,0.017391 +140,VM_39,0.198186 +140,VM_20,0.026247 +140,VM_79,0.165681 +140,VM_53,0.200598 +140,VM_84,0.163878 +140,VM_82,0.155133 +140,VM_89,0.171466 +140,VM_129,0.422373 +140,VM_131,0.029449 +140,VM_4,0.02464 +140,VM_68,0.530932 +140,VM_51,0.015017 +140,VM_65,0.484384 +140,VM_45,0.293473 +140,VM_51,0.034949 +140,VM_27,0.615106 +140,VM_92,0.154281 +140,VM_105,0.014597 +140,VM_101,0.57607 +140,VM_40,0.029606 +140,VM_85,0.827241 +140,VM_117,0.687844 +140,VM_43,0.18798 +140,VM_40,0.058035 +140,VM_115,0.134848 +140,VM_62,0.058191 +140,VM_2,0.541964 +140,VM_96,0.039239 +140,VM_5,0.5522 +140,VM_92,0.141296 +140,VM_75,0.017958 +140,VM_124,0.355523 +140,VM_26,0.020039 +140,VM_107,0.881767 +140,VM_81,0.01341 +140,VM_75,0.016363 +140,VM_126,0.157748 +140,VM_47,0.175653 +140,VM_64,0.151569 +140,VM_50,0.166695 +140,VM_64,0.017519 +140,VM_44,0.158821 +140,VM_66,0.013971 +140,VM_63,0.151236 +140,VM_24,0.150933 +140,VM_74,0.010319 +140,VM_71,0.157169 +140,VM_34,0.178885 +140,VM_9,0.015311 +140,VM_93,0.183313 +140,VM_86,0.009375 +140,VM_39,0.018927 +140,VM_110,0.164387 +140,VM_56,0.16833 +140,VM_82,0.015417 +140,VM_62,0.015525 +140,VM_68,0.009526 +140,VM_80,0.170102 +140,VM_30,0.164873 +140,VM_107,0.016529 +140,VM_90,0.081422 +140,VM_108,0.035024 +140,VM_79,0.175441 +140,VM_8,0.14363 +140,VM_71,0.168434 +140,VM_62,0.160181 +140,VM_41,0.144524 +140,VM_98,0.175346 +140,VM_123,0.148975 +140,VM_100,0.169791 +140,VM_79,0.0128 +140,VM_78,0.154366 +140,VM_97,0.169081 +140,VM_57,0.167987 +140,VM_46,0.168876 +140,VM_122,0.186375 +140,VM_86,0.164811 +140,VM_26,0.162872 +140,VM_72,0.175671 +140,VM_35,0.166333 +140,VM_4,0.171075 +140,VM_97,0.034644 +140,VM_36,0.202816 +140,VM_94,0.5668 +140,VM_25,0.058948 +140,VM_38,0.632675 +140,VM_129,0.020123 +140,VM_112,0.420521 +140,VM_101,0.776228 +140,VM_40,0.688421 +140,VM_61,0.697872 +140,VM_1,0.570242 +140,VM_38,0.026403 +140,VM_11,0.868305 +140,VM_4,0.014266 +140,VM_43,0.92173 +140,VM_80,0.868199 +140,VM_62,0.013272 +140,VM_74,0.954151 +140,VM_139,0.709353 +140,VM_45,0.811938 +140,VM_99,0.168641 +140,VM_80,0.026346 +140,VM_126,0.649917 +140,VM_113,0.643764 +140,VM_55,0.479964 +140,VM_5,0.436688 diff --git a/BENCHMARKING/RESULTS/web_apache_cont_benchmark.csv b/BENCHMARKING/RESULTS/web_apache_cont_benchmark.csv new file mode 100644 index 0000000..fab0930 --- /dev/null +++ b/BENCHMARKING/RESULTS/web_apache_cont_benchmark.csv @@ -0,0 +1,53 @@ +TEST_RUN,QUERIES_SENT,QUERIES_PER_SECOND,AVG_LATENCY_MILLISECONDS,MAX_LATENCY_MILLISECONDS,LATENCY_STD_DEV_PERCENT +1,30004,100.01,1.52,15.04,1.22 +2,60004,200.01,5.53,98.24,15.26 +3,86523,errors:,10.34,86.59,17.49 +4,97188,errors:,14.77,100.48,21.82 +5,150004,500.01,1.35,15.90,0.85 +6,180004,600.01,1.29,11.84,772.32 +7,210004,700.01,1.33,12.25,814.78 +8,240004,800.01,1.32,16.99,835.06 +9,269992,899.97,1.41,15.10,0.89 +10,299965,999.88,1.61,43.87,1.16 +11,329977,1099.92,1.31,19.14,0.86 +12,359967,1199.89,1.30,16.26,0.86 +13,308094,errors:,1.72,51.23,2.43 +14,419961,1399.86,1.28,16.22,0.85 +15,449957,1499.86,1.30,16.86,0.91 +16,479956,1599.84,1.27,18.67,0.90 +17,509947,1699.82,1.47,18.24,1.02 +18,539937,1799.79,1.35,20.96,0.95 +19,518643,errors:,1.53,48.03,2.09 +20,599924,1999.74,1.48,15.46,1.04 +21,456201,errors:,2.73,55.87,3.63 +22,659914,2199.70,1.36,20.53,1.02 +23,689901,2299.67,1.31,18.86,0.97 +24,463255,errors:,2.63,64.32,3.49 +25,749893,2499.64,1.44,18.54,1.06 +26,779887,2599.62,1.32,18.93,0.98 +27,710465,errors:,2.13,64.99,3.10 +28,839872,2799.58,1.46,24.35,1.09 +29,869872,2899.56,2.28,1.00,23.82 +30,753759,errors:,1.85,57.95,2.51 +31,929856,3099.52,1.35,22.18,1.08 +32,959839,3199.46,1.49,23.01,1.16 +33,940349,errors:,2.46,73.92,3.68 +34,887274,errors:,2.38,63.30,3.64 +35,1018333,errors:,1.45,38.02,1.29 +36,809203,errors:,2.66,229.25,3.51 +37,1109817,3699.39,1.48,25.94,1.17 +38,1128419,errors:,1.27,24.27,1.09 +39,1169809,3899.36,1.44,23.55,1.15 +40,758943,errors:,3.08,55.78,3.64 +41,971669,errors:,2.02,63.10,3.14 +42,1120557,errors:,1.99,59.04,3.20 +43,1073221,errors:,2.55,68.48,3.99 +44,1108674,errors:,2.19,59.17,3.47 +45,1107577,errors:,1.92,75.39,2.92 +46,1020400,errors:,2.76,74.82,4.07 +47,1205310,errors:,2.44,76.22,3.77 +48,1097203,errors:,1.71,63.36,2.49 +49,1190790,errors:,2.54,68.93,3.95 +50,1154937,errors:,2.71,73.34,3.99 +51,1152226,errors:,1.86,68.10,2.71 +52,1139356,errors:,2.49,64.61,3.77 diff --git a/BENCHMARKING/RESULTS/web_cont_benchmark.csv b/BENCHMARKING/RESULTS/web_cont_benchmark.csv new file mode 100644 index 0000000..8f8c490 --- /dev/null +++ b/BENCHMARKING/RESULTS/web_cont_benchmark.csv @@ -0,0 +1,2 @@ +TEST_RUN,QUERIES_SENT,QUERIES_PER_SECOND,AVG_LATENCY_MILLISECONDS,MAX_LATENCY_MILLISECONDS,LATENCY_STD_DEV_PERCENT +1,0,errors:,-,0.00,- diff --git a/BENCHMARKING/RESULTS/web_unik_benchmark.csv b/BENCHMARKING/RESULTS/web_unik_benchmark.csv new file mode 100644 index 0000000..14ae557 --- /dev/null +++ b/BENCHMARKING/RESULTS/web_unik_benchmark.csv @@ -0,0 +1,37 @@ +TEST_RUN,QUERIES_SENT,QUERIES_PER_SECOND,AVG_LATENCY_MILLISECONDS,MAX_LATENCY_MILLISECONDS,LATENCY_STD_DEV_PERCENT +1,30004,100.01,3.65,18.64,2.13 +2,60004,200.01,4.56,22.26,3.23 +3,90004,300.01,3.08,217.60,3.28 +4,120004,400.01,4.33,136.96,4.11 +5,150004,500.01,4.30,95.36,3.54 +6,180004,600.01,3.24,50.69,2.03 +7,210004,700.01,2.92,26.43,1.83 +8,240004,800.01,5.75,40.54,5.37 +9,269992,899.97,4.49,29.44,3.88 +10,299986,999.94,3.25,39.71,2.00 +11,329965,1099.86,7.52,37.73,6.28 +12,359965,1199.87,10.04,41.28,7.78 +13,389961,1299.87,5.04,38.02,4.26 +14,419961,1399.87,3.78,37.63,2.89 +15,449956,1499.84,5.93,36.70,5.12 +16,479952,1599.84,4.51,1.02,24.24 +17,509941,1699.80,3.96,37.34,3.19 +18,539931,1799.77,8.07,40.10,6.09 +19,569930,1899.75,4.51,51.68,4.00 +20,599905,1999.61,10.44,43.14,7.12 +21,629914,2099.71,5.53,43.97,4.45 +22,659898,2199.67,5.74,44.67,4.24 +23,689899,2299.66,6.34,49.92,5.65 +24,719899,2399.65,11.37,54.05,8.06 +25,749895,2499.63,8.07,54.66,5.78 +26,779884,2599.59,8.45,50.14,7.29 +27,809827,2699.31,15.97,59.55,8.63 +28,734062,2446.83,5.45,37.98,10.68 +29,869861,2899.54,12.20,58.46,8.84 +30,784697,2615.19,6.37,38.34,11.19 +31,818727,2728.72,3.71,35.82,8.43 +32,632347,2106.63,41.77,1.71,33.16 +33,674216,2246.32,47.19,1.60,28.58 +34,606538,2021.69,1.06,2.03,35.14 +35,719335,2396.51,47.68,1.58,26.97 +36,590733,1969.06,1.13,2.27,39.42 diff --git a/BENCHMARKING/UNIKERNEL/DNS/CMakeLists.txt b/BENCHMARKING/UNIKERNEL/DNS/CMakeLists.txt new file mode 100644 index 0000000..3874757 --- /dev/null +++ b/BENCHMARKING/UNIKERNEL/DNS/CMakeLists.txt @@ -0,0 +1,36 @@ +cmake_minimum_required(VERSION 2.8.9) + +# IncludeOS install location +if (NOT DEFINED ENV{INCLUDEOS_PREFIX}) + set(ENV{INCLUDEOS_PREFIX} /usr/local) +endif() +include($ENV{INCLUDEOS_PREFIX}/includeos/pre.service.cmake) +project (DNS) + +# Human-readable name of your service +set(SERVICE_NAME "CETIC DNS Service") + +# Name of your service binary +set(BINARY "DNS") + +# Source files to be linked with OS library parts to form bootable image +set(SOURCES + service.cpp # ...add more here + ) + +# To add your own include paths: +# set(LOCAL_INCLUDES ".") + +# DRIVERS / PLUGINS: + +set(DRIVERS + virtionet # Virtio networking + # virtioblock # Virtio block device + # ... Others from src/drivers +) + +set(PLUGINS + ) + +# include service build script +include($ENV{INCLUDEOS_PREFIX}/includeos/post.service.cmake) diff --git a/BENCHMARKING/UNIKERNEL/DNS/cmake_build.sh b/BENCHMARKING/UNIKERNEL/DNS/cmake_build.sh new file mode 100644 index 0000000..529e821 --- /dev/null +++ b/BENCHMARKING/UNIKERNEL/DNS/cmake_build.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +mkdir -p build +pushd build +cmake .. +make +popd diff --git a/BENCHMARKING/UNIKERNEL/DNS/config.json b/BENCHMARKING/UNIKERNEL/DNS/config.json new file mode 100644 index 0000000..67acdca --- /dev/null +++ b/BENCHMARKING/UNIKERNEL/DNS/config.json @@ -0,0 +1,11 @@ +{ + "net": [ + { + "iface": 0, + "config": "static", + "address": "192.168.122.100", + "netmask": "255.255.255.0", + "gateway": "192.168.122.1" + } + ] +} diff --git a/BENCHMARKING/UNIKERNEL/DNS/service.cpp b/BENCHMARKING/UNIKERNEL/DNS/service.cpp new file mode 100644 index 0000000..ba3342e --- /dev/null +++ b/BENCHMARKING/UNIKERNEL/DNS/service.cpp @@ -0,0 +1,262 @@ +/** + * Basic DNS server for the IncludeOS unikernel framework. + * + * This code uses portions of code created by GitHub user tomasorti for his dns-server project (https://github.com/tomasorti/dns-server) + */ + +#include +#include +#include +#include + +using namespace net; + +#define SERVER_PORT 53 + +static const uint QR_MASK = 0x8000; +static const uint OPCODE_MASK = 0x7800; +static const uint AA_MASK = 0x0400; +static const uint TC_MASK = 0x0200; +static const uint RD_MASK = 0x0100; +static const uint RA_MASK = 0x8000; +static const uint RCODE_MASK = 0x000F; +static const uint HDR_OFFSET = 12; +static const int BUFFER_SIZE = 1024; + +// for more info on DNS fields, see RFC 1035 + +struct queryHeader { + uint id; // 16 bit identifier assigned by the program who generated the query + uint query; // identifies if message is query (0) or a response (1) + uint opcode; // 4 bit field specifying kind of query: standard (0), inverse (1), server status request (2), reserved (3-15) + uint aa; // bit indicating if responding server is an authority for the domain name + uint truncation; // specifies whether this message was truncated or not + uint recursionDesired; // may be set in a query, directs the name server to pursue the query recursively + uint recursionAvailable; // set in a response, indicates whether recursive queries are available + uint responseCode; // 4 bit response code: 0 - no error, 1 - format error, 2 - server failure, 3 - name error, 4 - not implemented, 5 - refused + + // unsigned 16-bit integers + uint questionCount; // number of entries in the question section + uint answerCount; // number of resource reconds in the answer section + uint nameServerCount; // number of name server resource records in the authority records section + uint additionalResourceCount; // number of resource records in the additional records section +}; + +struct queryQuestion { + std::string queryName; // domain name requested + uint queryType; // 2 octet code specifying the type of the query + uint queryClass; // 2 octet code specifying the class of the query +}; + +queryHeader pQueryHeader; +queryQuestion pQueryQuestion; +std::map> resourceRecords; + +uint get16bits(const char*& buffer) { + uint value = static_cast (buffer[0]); + value = value << 8; + value += static_cast (buffer[1]); + buffer += 2; + + return value; +} + +void put8bits(char*& buffer, uint value) throw () { + buffer[0] = (value); + buffer += 1; +} + +void put16bits(char*& buffer, uint value) throw () { + buffer[0] = (value & 0xFF00) >> 8; + buffer[1] = value & 0xFF; + buffer += 2; +} + +void put32bits(char*& buffer, ulong value) throw () { + buffer[0] = (value & 0xFF000000) >> 24; + buffer[1] = (value & 0xFF0000) >> 16; + buffer[2] = (value & 0xFF00) >> 16; + buffer[3] = (value & 0xFF) >> 16; + buffer += 4; +} + +queryHeader decodeHeader(const char* data, queryHeader pQueryHeader){ + pQueryHeader.id = get16bits(data); + + uint fields = get16bits(data); + pQueryHeader.query = fields & QR_MASK; + pQueryHeader.opcode = fields & OPCODE_MASK; + pQueryHeader.aa = fields & AA_MASK; + pQueryHeader.truncation = fields & TC_MASK; + pQueryHeader.recursionDesired = fields & RD_MASK; + pQueryHeader.recursionAvailable = fields & RA_MASK; + + pQueryHeader.questionCount = get16bits(data); + pQueryHeader.answerCount = get16bits(data); + pQueryHeader.nameServerCount = get16bits(data); + pQueryHeader.additionalResourceCount = get16bits(data); + return pQueryHeader; +} + +queryQuestion decodeQuery(const char*& data, queryQuestion pQueryQuestion){ + pQueryQuestion.queryName = ""; + + int length = *data++; + while (length != 0) { + for (int i = 0; i < length; i++) { + char c = *data++; + pQueryQuestion.queryName.append(1, c); + } + length = *data++; + if (length != 0) pQueryQuestion.queryName.append(1,'.'); + } + + pQueryQuestion.queryType = get16bits(data); + pQueryQuestion.queryClass = get16bits(data); + return pQueryQuestion; +} + +void codeDomain(char*& buffer, const std::string& domain) { + int start = 0, end; // indexes + while ((end = domain.find('.', start)) != std::string::npos) { + *buffer++ = end - start; // label length octet + for (int i=start; i>::iterator record = resourceRecords.find(pQueryQuestion.queryName); + if (record == resourceRecords.end()) + bRRexists = false; + + + char* bufferBegin = buffer; + + // create header + put16bits(buffer, pQueryHeader.id); + + int fields = (1 << 15); // Response code + fields += (0 << 11); // Opcode + fields += (0 << 10); // Authoritative code + fields += (0 << 9); // Truncated code + fields += (1 << 8); // Recursion desired code + fields += (0 << 7); // Recursion available code + fields += (0 << 6); // Z reserved code + fields += (0 << 5); // Answers authenticated code + fields += (0 << 4); // Non-authenticated data code + if(bRRexists) + fields += 0; // Reply code + else + fields += 3; + put16bits(buffer, fields); + + put16bits(buffer, pQueryHeader.questionCount); // Questions count + if(bRRexists) + put16bits(buffer, 1); // Answers count + else + put16bits(buffer, 0); + put16bits(buffer, 0); // Authority RRs + put16bits(buffer, 0); // Additional RRs + + // create domain query section - copy original question format + codeDomain(buffer, pQueryQuestion.queryName); + put16bits(buffer, pQueryQuestion.queryType); + put16bits(buffer, pQueryQuestion.queryClass); + + // if requested domain exists in resourceRecords, create the answer + if(bRRexists){ + // compression code to pointing to original question - should be offset from ID to domain name (in number of 16bits) + put16bits(buffer, 49164); + + put16bits(buffer, pQueryQuestion.queryType); + put16bits(buffer, pQueryQuestion.queryClass); + put32bits(buffer, 0); // time to live + + put16bits(buffer, 4); // data length (always 4 for IPv4 addresses) + put8bits(buffer,resourceRecords[pQueryQuestion.queryName][0]); + put8bits(buffer,resourceRecords[pQueryQuestion.queryName][1]); + put8bits(buffer,resourceRecords[pQueryQuestion.queryName][2]); + put8bits(buffer,resourceRecords[pQueryQuestion.queryName][3]); + } + + int size = buffer - bufferBegin; + + return size; +} + +void Service::start() +{ + resourceRecords["www.cetic.be"].push_back(10); + resourceRecords["www.cetic.be"].push_back(0); + resourceRecords["www.cetic.be"].push_back(0); + resourceRecords["www.cetic.be"].push_back(5); + resourceRecords["cetic.be"].push_back(10); + resourceRecords["cetic.be"].push_back(0); + resourceRecords["cetic.be"].push_back(0); + resourceRecords["cetic.be"].push_back(5); + resourceRecords["internship.cetic.be"].push_back(10); + resourceRecords["internship.cetic.be"].push_back(0); + resourceRecords["internship.cetic.be"].push_back(0); + resourceRecords["internship.cetic.be"].push_back(5); + + // get the first network interfaces of the unikernel + auto& inet = Inet4::stack<0>(); + Expects(inet.is_configured()); + + printf("Service IP address is %s\n", inet.ip_addr().str().c_str()); + + const UDP::port_t port = SERVER_PORT; + auto& sock = inet.udp().bind(port); + + sock.on_read( + [&sock] (UDP::addr_t addr, UDP::port_t port, const char* data, size_t len){ + + pQueryHeader = decodeHeader(data, pQueryHeader); + data += HDR_OFFSET; + pQueryQuestion = decodeQuery(data, pQueryQuestion); + + // debug output + printf("####### INCOMMING REQUEST #######\n"); + printf("Getting UDP data from %s:%d\n", addr.str().c_str(), port); + printf("Header:\n"); + printf("\tID: %u\n",pQueryHeader.id); + printf("\tQuery: %u\n", pQueryHeader.query); + printf("\topCode: %u\n", pQueryHeader.opcode); + printf("\tAA: %u\n", pQueryHeader.aa); + printf("\tTruncation: %u\n", pQueryHeader.truncation); + printf("\tRecursion Desired: %u\n", pQueryHeader.recursionDesired); + printf("\tRecursion Available: %u\n", pQueryHeader.recursionAvailable); + printf("\tReponse Code: %u\n", pQueryHeader.responseCode); + printf("\tQuestion Count: %u\n", pQueryHeader.questionCount); + printf("\tAnswer Count: %u\n", pQueryHeader.answerCount); + printf("\tName Server Count: %u\n", pQueryHeader.nameServerCount); + printf("\tAdditional Resource Count: %u\n", pQueryHeader.additionalResourceCount); + printf("Query:\n"); + printf("\tQuery name: %s\n", pQueryQuestion.queryName.data()); + printf("\tQuery Type: %u\n", pQueryQuestion.queryType); + printf("\tAdditional Resource Count: %u\n", pQueryQuestion.queryClass); + printf("#################################\n"); + + // send reply + char buffer[BUFFER_SIZE]; + + int nbrBytes = processQuery(buffer, pQueryHeader, pQueryQuestion); + + sock.sendto(addr, port, buffer, nbrBytes); + }); + + INFO("DNS Server", "Listening on port %d\n", port); +} \ No newline at end of file diff --git a/BENCHMARKING/UNIKERNEL/DNS/vm.json b/BENCHMARKING/UNIKERNEL/DNS/vm.json new file mode 100644 index 0000000..fb4ef39 --- /dev/null +++ b/BENCHMARKING/UNIKERNEL/DNS/vm.json @@ -0,0 +1,6 @@ +{ + "net" : [ + {"device" : "virtio", "mac" : "c0:01:0a:00:00:2a"}, + {"device" : "virtio", "mac" : "c0:01:0a:00:00:3a"} + ] +} diff --git a/BENCHMARKING/UNIKERNEL/WebServer/CMakeLists.txt b/BENCHMARKING/UNIKERNEL/WebServer/CMakeLists.txt new file mode 100644 index 0000000..863ccce --- /dev/null +++ b/BENCHMARKING/UNIKERNEL/WebServer/CMakeLists.txt @@ -0,0 +1,42 @@ +cmake_minimum_required(VERSION 2.8.9) +if (NOT DEFINED ENV{INCLUDEOS_PREFIX}) + set(ENV{INCLUDEOS_PREFIX} /usr/local) +endif() +include($ENV{INCLUDEOS_PREFIX}/includeos/pre.service.cmake) + +project (WebServer) + +# Human-readable name of your service +set(SERVICE_NAME "CETIC Unikernel Web Server") + +# Name of your service binary +set(BINARY "WebServer") + +# Source files to be linked with OS library parts to form bootable image +set(SOURCES + service.cpp # ...add more here + ) + +# To add your own include paths: +# set(LOCAL_INCLUDES ".") + +# DRIVERS / PLUGINS: +set(DRIVERS + virtionet # Virtio networking + ) + +set(PLUGINS + autoconf + ) + +# STATIC LIBRARIES: +set(LIBRARIES + # path to full library + ) + + +# include service build script +include($ENV{INCLUDEOS_PREFIX}/includeos/post.service.cmake) + +# Create in-memory filesystem from folder +diskbuilder(disk) diff --git a/BENCHMARKING/UNIKERNEL/WebServer/cmake_build.sh b/BENCHMARKING/UNIKERNEL/WebServer/cmake_build.sh new file mode 100644 index 0000000..529e821 --- /dev/null +++ b/BENCHMARKING/UNIKERNEL/WebServer/cmake_build.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +mkdir -p build +pushd build +cmake .. +make +popd diff --git a/BENCHMARKING/UNIKERNEL/WebServer/config.json b/BENCHMARKING/UNIKERNEL/WebServer/config.json new file mode 100644 index 0000000..2c28675 --- /dev/null +++ b/BENCHMARKING/UNIKERNEL/WebServer/config.json @@ -0,0 +1,13 @@ +{ + "net": [ + { + "iface": 0, + "config": "static", + "address": "192.168.122.5", + "netmask": "255.255.255.0", + "gateway": "192.168.122.1" + } + ] +} + + diff --git a/BENCHMARKING/UNIKERNEL/WebServer/disk/index.html b/BENCHMARKING/UNIKERNEL/WebServer/disk/index.html new file mode 100644 index 0000000..c6c9b59 --- /dev/null +++ b/BENCHMARKING/UNIKERNEL/WebServer/disk/index.html @@ -0,0 +1,15 @@ + + + + + CETIC Internship Unikernel Web Page + + + +

+ CETIC Internship Unikernel Web Page +

+
+

This is the first web server spawn from a unikernel during the CETIC Intership 2017-18

+ + diff --git a/BENCHMARKING/UNIKERNEL/WebServer/service.cpp b/BENCHMARKING/UNIKERNEL/WebServer/service.cpp new file mode 100644 index 0000000..50ea18b --- /dev/null +++ b/BENCHMARKING/UNIKERNEL/WebServer/service.cpp @@ -0,0 +1,47 @@ +/* + * This code is adapted from the IncludeOS Acorn web server example. + */ + +#include +#include +#include +#include +std::unique_ptr server; + +void Service::start() +{ + // Retreive the stack (configured from outside) + auto& inet = net::Inet4::stack<0>(); + Expects(inet.is_configured()); + + // Init the memdisk + auto& disk = fs::memdisk(); + disk.init_fs([] (auto err, auto&) { + Expects(not err); + }); + // Retreive the HTML page from the disk + auto file = disk.fs().read_file("/index.html"); + Expects(file.is_valid()); + net::tcp::buffer_t html( + new std::vector (file.data(), file.data() + file.size())); + + // Create a HTTP Server and setup request handling + server = std::make_unique(inet.tcp()); + server->on_request([html] (auto req, auto rw) + { + // We only support get + if(req->method() != http::GET) { + rw->write_header(http::Not_Found); + return; + } + // Serve HTML on / + if(req->uri() == "/") { + rw->write(html); + } else { + rw->write_header(http::Not_Found); + } + }); + + // Start listening on port 80 + server->listen(80); +} diff --git a/BENCHMARKING/bench_container_dns.sh b/BENCHMARKING/bench_container_dns.sh new file mode 100644 index 0000000..6324be2 --- /dev/null +++ b/BENCHMARKING/bench_container_dns.sh @@ -0,0 +1,38 @@ +#!/bin/bash +SRC_DIR=$HOME/unikernels +CONTAINERS=$SRC_DIR/SOURCE/CONTAINER + +#IP=$(ip -4 route get 8.8.8.8 | awk {'print $7'} | tr -d '\n') +IP=10.65.0.101 +PORT=53 + +source $SRC_DIR/BENCHMARKING/bench_unikernel_cleanup.sh + +# build Docker containers +# 1 - compiler docker +pushd $CONTAINERS && +docker build -t cetic/compiler . && +popd && + +# 2 - individual dockers +pushd $CONTAINERS/DNS && +docker run --rm -it -v "${PWD}":/usr/src/build -w /usr/src/build cetic/compiler g++ -std=c++11 -static -o runnableService *.cpp && +docker build -t cetic/dns . && +popd && + +# stopping all VMs and containers +docker stop $(docker ps -a -q) +virsh list | grep running | awk '{ print $2}' | while read DOMAIN; do + virsh destroy $DOMAIN + sleep 3 +done + +# launch docker containers +docker run --rm --cpus 1 -m 128m -d -p $IP:$PORT:$PORT/udp --name DNSBench cetic/dns && + +echo "#############################################################################" && +echo "### ###" && +echo "### Container DNS Server ready for benchmark. ###" && +echo "### $IP:$PORT ###" && +echo "### ###" && +echo "#############################################################################" diff --git a/BENCHMARKING/bench_container_web.sh b/BENCHMARKING/bench_container_web.sh new file mode 100644 index 0000000..7eecd6e --- /dev/null +++ b/BENCHMARKING/bench_container_web.sh @@ -0,0 +1,38 @@ +#!/bin/bash +SRC_DIR=$HOME/unikernels +CONTAINERS=$SRC_DIR/SOURCE/CONTAINER + +#IP=$(ip -4 route get 8.8.8.8 | awk {'print $7'} | tr -d '\n') +IP=10.65.0.101 +PORT=80 + +source $SRC_DIR/BENCHMARKING/bench_unikernel_cleanup.sh + +# build Docker containers +# 1 - compiler docker +pushd $CONTAINERS && +docker build -t cetic/compiler . && +popd && + +# 2 - individual dockers +pushd $CONTAINERS/WebServer && +docker run --rm -it -v "${PWD}":/usr/src/build -w /usr/src/build cetic/compiler g++ -std=c++11 -static -o runnableService *.cpp && +docker build -t cetic/webserver . && +popd && + +# stopping all VMs and containers +docker stop $(docker ps -a -q) +virsh list | grep running | awk '{ print $2}' | while read DOMAIN; do + virsh destroy $DOMAIN + sleep 3 +done + +# launch docker containers +docker run --rm --cpus 1 -m 128m -d -p $IP:$PORT:$PORT --name WebServerBench cetic/webserver && + +echo "#############################################################################" && +echo "### ###" && +echo "### Container Web Server ready for benchmark. ###" && +echo "### $IP:$PORT ###" && +echo "### ###" && +echo "#############################################################################" diff --git a/BENCHMARKING/bench_unikernel_cleanup.sh b/BENCHMARKING/bench_unikernel_cleanup.sh new file mode 100644 index 0000000..ecde648 --- /dev/null +++ b/BENCHMARKING/bench_unikernel_cleanup.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +WEB_IP=192.168.122.5 +DNS_IP=192.168.122.100 +WEB_PORT=80 +DNS_PORT=53 +BRIDGE_INTERFACE=virbr0 + +sudo iptables -D FORWARD -o $BRIDGE_INTERFACE -d $DNS_IP -j ACCEPT +sudo iptables -t nat -D PREROUTING -p udp --dport $DNS_PORT -j DNAT --to $DNS_IP:$DNS_PORT + +sudo iptables -D FORWARD -o $BRIDGE_INTERFACE -d $WEB_IP -j ACCEPT +sudo iptables -t nat -D PREROUTING -p tcp --dport $WEB_PORT -j DNAT --to $WEB_IP:$WEB_PORT diff --git a/BENCHMARKING/bench_unikernel_dns.sh b/BENCHMARKING/bench_unikernel_dns.sh new file mode 100644 index 0000000..d7c9c31 --- /dev/null +++ b/BENCHMARKING/bench_unikernel_dns.sh @@ -0,0 +1,55 @@ +#!/bin/bash +SRC_DIR=$HOME/unikernels/BENCHMARKING +UNIKERNELS=$SRC_DIR/UNIKERNEL + +HOST_IP=$(ip -4 route get 8.8.8.8 | awk {'print $7'} | tr -d '\n') +GUEST_IP=192.168.122.100 +GUEST_PORT=53 +HOST_PORT=53 +BRIDGE_INTERFACE=virbr0 + +#write correct JSON file +pushd $UNIKERNELS/DNS && +jq -n --arg IP_ADDRESS "$GUEST_IP" '{"net": [{"netmask": "255.255.255.0", "config": "static", "iface": 0, "gateway": "192.168.122.1", "address": $IP_ADDRESS}]}' > config.json && +# build unikernels +sudo rm -rf build && +mkdir -p build && +pushd build && +cmake .. && +sudo make && +popd && +popd && + +# shuting down all VMs +docker stop $(docker ps -a -q) +virsh list | grep running | awk '{ print $2}' | while read DOMAIN; do + virsh destroy $DOMAIN + sleep 3 + if [ "$DOMAIN" == "DNSBench" ] + then + virsh undefine $DOMAIN + fi +done +virsh undefine DNSBench + +# launch unikernels in QEMU (+serial output to files) +virt-install \ + --virt-type qemu --name DNSBench \ + --vcpus 1 --ram 128 \ + --import --disk $UNIKERNELS/DNS/build/DNS.img \ + --serial file,path=/tmp/dns-benchmark.log \ + --network network=default,model=virtio \ + --check path_in_use=off \ + --noautoconsole && + +# enable port-forwarding through iptables +source $SRC_DIR/bench_unikernel_cleanup.sh +sudo iptables -I FORWARD -o $BRIDGE_INTERFACE -d $GUEST_IP -j ACCEPT && +sudo iptables -t nat -I PREROUTING -p udp --dport $HOST_PORT -j DNAT --to $GUEST_IP:$GUEST_PORT && + +echo "#############################################################################" && +echo "### ###" && +echo "### Unikernel DNS Server ready for benchmark. ###" && +echo "### $HOST_IP:$HOST_PORT ###" && +echo "### ###" && +echo "#############################################################################" diff --git a/BENCHMARKING/bench_unikernel_web.sh b/BENCHMARKING/bench_unikernel_web.sh new file mode 100644 index 0000000..f4af24a --- /dev/null +++ b/BENCHMARKING/bench_unikernel_web.sh @@ -0,0 +1,52 @@ +#!/bin/bash +SRC_DIR=$HOME/unikernels/BENCHMARKING +UNIKERNELS=$SRC_DIR/UNIKERNEL + +HOST_IP=$(ip -4 route get 8.8.8.8 | awk {'print $7'} | tr -d '\n') +GUEST_IP=192.168.122.5 +GUEST_PORT=80 +HOST_PORT=80 +BRIDGE_INTERFACE=virbr0 + +# writing correct JSON file +pushd $UNIKERNELS/DNS && +jq -n --arg IP_ADDRESS "$GUEST_IP" '{"net": [{"netmask": "255.255.255.0", "config": "static", "iface": 0, "gateway": "192.168.122.1", "address": $IP_ADDRESS}]}' > config.json && +# build unikernels +sudo rm -rf build && +mkdir -p build && +pushd build && +cmake .. && +sudo make && +popd && +popd && + +# shuting down all VMs +docker stop $(docker ps -a -q) +virsh list | grep running | awk '{ print $2}' | while read DOMAIN; do + virsh destroy $DOMAIN + sleep 3 +done +virsh undefine WebServerBench + +# launch unikernels in QEMU (+serial output to files) +virt-install \ + --virt-type qemu --name WebServerBench \ + --vcpus 1 --ram 128 \ + --import --disk $UNIKERNELS/WebServer/build/WebServer.img \ + --serial file,path=/tmp/web-benchmark.log \ + --network network=default,model=virtio \ + --check path_in_use=off \ + --noautoconsole && + +# enable port-forwarding through iptables +source $SRC_DIR/bench_unikernel_cleanup.sh +sudo iptables -I FORWARD -o $BRIDGE_INTERFACE -d $GUEST_IP -j ACCEPT && +sudo iptables -t nat -I PREROUTING -p tcp --dport $HOST_PORT -j DNAT --to $GUEST_IP:$GUEST_PORT && + +echo "#############################################################################" && +echo "### ###" && +echo "### Unikernel Web Server ready for benchmark. ###" && +echo "### $HOST_IP:$HOST_PORT ###" && +echo "### ###" && +echo "#############################################################################" + diff --git a/BENCHMARKING/cleanup_all.sh b/BENCHMARKING/cleanup_all.sh new file mode 100644 index 0000000..ea86e79 --- /dev/null +++ b/BENCHMARKING/cleanup_all.sh @@ -0,0 +1,30 @@ +#!/bin/bash + +# REMOVING IP TABLES RULES FOR UNIKERNEL BENCHMARKING +WEB_IP=192.168.122.5 +DNS_IP=192.168.122.10 +WEB_PORT=80 +DNS_PORT=53 +BRIDGE_INTERFACE=virbr0 + +sudo iptables -D FORWARD -o $BRIDGE_INTERFACE -d $DNS_IP -j ACCEPT +sudo iptables -t nat -D PREROUTING -p udp --dport $DNS_PORT -j DNAT --to $DNS_IP:$DNS_PORT +sudo iptables -D FORWARD -o $BRIDGE_INTERFACE -d $WEB_IP -j ACCEPT +sudo iptables -t nat -D PREROUTING -p tcp --dport $WEB_PORT -j DNAT --to $WEB_IP:$WEB_PORT + +echo "This will stop and delete all VMs and Containers !" +read -p "Are you sure ? [Y|N] " -n 1 -r +echo +if [[ $REPLY =~ ^[Yy]$ ]] +then + # STOPPING AND DELETING ALL CONTAINERS + docker stop $(docker ps -a -q) + docker rm $(docker ps -a -q) + virsh list | grep running | awk '{ print $2}' | while read DOMAIN; do + virsh destroy $DOMAIN + done + virsh list --all | grep "shut off" | awk '{ print $2}' | while read DOMAIN; do + virsh undefine $DOMAIN + done +fi + diff --git a/BENCHMARKING/dns_cont_benchmark.py b/BENCHMARKING/dns_cont_benchmark.py new file mode 100644 index 0000000..ecff8f7 --- /dev/null +++ b/BENCHMARKING/dns_cont_benchmark.py @@ -0,0 +1,67 @@ +#!/usr/bin/python3 +import sys +import subprocess +import shutil +import os.path +import csv +import time + +RUN=1 +TIME=300 +CLIENTS=100 +THREADS=4 +QPS=100 +QPS_INCREMENT=100 + +if __name__ == '__main__': + if len(sys.argv) < 2: + print("DNS Server Benchmarking Tool - CETIC Internship 2017/18 on Unikernels\n\tUsage: python3 dns_cont_benchmark.py [server_ip_address]") + sys.exit(1) + + SVR_IP=sys.argv[1] + + if shutil.which("dnsperf") is None: + print("ERROR: dnsperf is not installed, please run the install_bench_tools.sh script.") + sys.exit(1) + + if os.path.isfile("dns_cont_benchmark.csv") is not True: + subprocess.run("touch dns_cont_benchmark.csv", stdout=subprocess.PIPE, shell=True) + + with open("dns_cont_benchmark.csv", "w") as file: + writer = csv.writer(file) + writer.writerow(["TEST_RUN", "QUERIES_SENT", "QUERIES_COMPLETED", "QUERIES_LOST", "QUERIES_PER_SECOND", "AVG_LATENCY_SECONDS", "MIN", "MAX", "LATENCY_STD_DEV_SECONDS"]) + + while True: + print("########## LAUNCHING TEST " + str(RUN) + " ##########") + print("Queries per seconds: " + str(QPS)+ "\n") + # launch the dnsperf command + result = subprocess.run("dnsperf -s " + SVR_IP + " -d queryfile-example-current -l " + str(TIME) + " -T " + str(THREADS) + " -c " + str(CLIENTS) + " -Q " + str(QPS), stdout=subprocess.PIPE, shell=True) + #print(result.stdout.decode('utf-8')) + + # convert output and store it in the csv file + list = result.stdout.decode("utf-8").split('\n') + for index in range(len(list)): + if list[index].startswith(" Queries sent:"): + queriesSent=list[index].split()[2] + queriesCompleted=list[index+1].split()[2] + queriesLost=list[index+2].split()[2] + queriesPerSecond=list[index+7].split()[3] + avgLatency=list[index+9].split()[3] + latencyMin=list[index+9].split()[5].replace(",", "") + latencyMax=list[index+9].split()[7].replace(")", "") + latencyStdDev=list[index+10].split()[3] + #print("TEST_RUN, QUERIES_SENT, QUERIES_COMPLETED, QUERIES_LOST, QUERIES_PER_SECOND, AVG_LATENCY_SECONDS, MIN, MAX, LATENCY_STD_DEV_SECONDS") + print("Queries sent:\t\t" + queriesSent + "\nQueries completed:\t" + queriesCompleted + "\nQueries Lost:\t\t" + queriesLost + \ + "\nQueries per second:\t" + queriesPerSecond + "\nAverage latency:\t" + avgLatency + "\nMinimum latency:\t" + latencyMin + \ + "\nMax latency:\t\t" + latencyMax + "\nLatency Std Dev:\t" + latencyStdDev) + with open("dns_cont_benchmark.csv", "a") as file: + writer = csv.writer(file) + writer.writerow([RUN, queriesSent, queriesCompleted, queriesLost, queriesPerSecond, avgLatency, latencyMin, latencyMax, latencyStdDev]) + break + + print("########## TEST " + str(RUN) + " COMPLETE ##########\n") + # increase the TEST_RUN value and increment the number of queries per second + RUN=RUN+1 + QPS=QPS+QPS_INCREMENT + # sleep for 30 seconds between tests + time.sleep(30) \ No newline at end of file diff --git a/BENCHMARKING/dns_unik_benchmark.py b/BENCHMARKING/dns_unik_benchmark.py new file mode 100644 index 0000000..105705b --- /dev/null +++ b/BENCHMARKING/dns_unik_benchmark.py @@ -0,0 +1,67 @@ +#!/usr/bin/python3 +import sys +import subprocess +import shutil +import os.path +import csv +import time + +RUN=1 +TIME=300 +CLIENTS=100 +THREADS=4 +QPS=100 +QPS_INCREMENT=100 + +if __name__ == '__main__': + if len(sys.argv) < 2: + print("DNS Server Benchmarking Tool - CETIC Internship 2017/18 on Unikernels\n\tUsage: python3 dns_unik_benchmark.py [server_ip_address]") + sys.exit(1) + + SVR_IP=sys.argv[1] + + if shutil.which("dnsperf") is None: + print("ERROR: dnsperf is not installed, please run the install_bench_tools.sh script.") + sys.exit(1) + + if os.path.isfile("dns_unik_benchmark.csv") is not True: + subprocess.run("touch dns_unik_benchmark.csv", stdout=subprocess.PIPE, shell=True) + + with open("dns_unik_benchmark.csv", "w") as file: + writer = csv.writer(file) + writer.writerow(["TEST_RUN", "QUERIES_SENT", "QUERIES_COMPLETED", "QUERIES_LOST", "QUERIES_PER_SECOND", "AVG_LATENCY_SECONDS", "MIN", "MAX", "LATENCY_STD_DEV_SECONDS"]) + + while True: + print("########## LAUNCHING TEST " + str(RUN) + " ##########") + print("Queries per seconds: " + str(QPS)+ "\n") + # launch the dnsperf command + result = subprocess.run("dnsperf -s " + SVR_IP + " -d queryfile-example-current -l " + str(TIME) + " -T " + str(THREADS) + " -c " + str(CLIENTS) + " -Q " + str(QPS), stdout=subprocess.PIPE, shell=True) + #print(result.stdout.decode('utf-8')) + + # convert output and store it in the csv file + list = result.stdout.decode("utf-8").split('\n') + for index in range(len(list)): + if list[index].startswith(" Queries sent:"): + queriesSent=list[index].split()[2] + queriesCompleted=list[index+1].split()[2] + queriesLost=list[index+2].split()[2] + queriesPerSecond=list[index+7].split()[3] + avgLatency=list[index+9].split()[3] + latencyMin=list[index+9].split()[5].replace(",", "") + latencyMax=list[index+9].split()[7].replace(")", "") + latencyStdDev=list[index+10].split()[3] + #print("TEST_RUN, QUERIES_SENT, QUERIES_COMPLETED, QUERIES_LOST, QUERIES_PER_SECOND, AVG_LATENCY_SECONDS, MIN, MAX, LATENCY_STD_DEV_SECONDS") + print("Queries sent:\t\t" + queriesSent + "\nQueries completed:\t" + queriesCompleted + "\nQueries Lost:\t\t" + queriesLost + \ + "\nQueries per second:\t" + queriesPerSecond + "\nAverage latency:\t" + avgLatency + "\nMinimum latency:\t" + latencyMin + \ + "\nMax latency:\t\t" + latencyMax + "\nLatency Std Dev:\t" + latencyStdDev) + with open("dns_unik_benchmark.csv", "a") as file: + writer = csv.writer(file) + writer.writerow([RUN, queriesSent, queriesCompleted, queriesLost, queriesPerSecond, avgLatency, latencyMin, latencyMax, latencyStdDev]) + break + + print("########## TEST " + str(RUN) + " COMPLETE ##########\n") + # increase the TEST_RUN value and increment the number of queries per second + RUN=RUN+1 + QPS=QPS+QPS_INCREMENT + # sleep for 30 seconds between tests + time.sleep(30) \ No newline at end of file diff --git a/BENCHMARKING/install_bench_tools.sh b/BENCHMARKING/install_bench_tools.sh new file mode 100644 index 0000000..2dae0ad --- /dev/null +++ b/BENCHMARKING/install_bench_tools.sh @@ -0,0 +1,24 @@ +#!/bin/bash + +SRC_DIR=$HOME/unikernels/BENCHMARKING + +# DNSPerf +sudo apt-get install -y libbind-dev libkrb5-dev libssl-dev libcap-dev libxml2-dev libgeoip-dev bind9utils make && +wget ftp://ftp.nominum.com/pub/nominum/dnsperf/2.1.0.0/dnsperf-src-2.1.0.0-1.tar.gz && +tar xzvf dnsperf-src-2.1.0.0-1.tar.gz && +pushd dnsperf-src-2.1.0.0-1 && +./configure && +make && +sudo make install && +popd && +wget ftp://ftp.nominum.com/pub/nominum/dnsperf/data/queryfile-example-current.gz && +gunzip queryfile-example-current.gz && +#Usage: dnsperf -s 10.0.0.100 -d queryfile-example-current -l 60 -c 1 -Q 10 + +#wrk2 install +git clone https://github.com/giltene/wrk2 && +pushd wrk2 && +sudo make && +sudo cp wrk /usr/local/bin/wrk2 && +popd +#Usage: wrk2 -d 5m -R 100 http://10.0.0.5/ diff --git a/BENCHMARKING/startup_cont_benchmark.py b/BENCHMARKING/startup_cont_benchmark.py new file mode 100644 index 0000000..f014440 --- /dev/null +++ b/BENCHMARKING/startup_cont_benchmark.py @@ -0,0 +1,94 @@ +#!/usr/bin/python3 +import sys +import subprocess +import os.path +import csv +import json +import time +import _thread +import os +import datetime as datetime +import random + +BENCHMARK_TIME_SECONDS=60*20 +MAX_NBR_VMS=150 +NBR_VMS_INCREMENT=10 +GUESTS=dict() +NBR_VMS=0 + +def run_cmd(COMMAND): + return subprocess.run(COMMAND, stdout=subprocess.PIPE, shell=True) + +def timeGuestStart(GUEST): + response = 1 + startTime=datetime.datetime.now() + while response is not 0: + response = os.system("ping -c 1 " + GUESTS[GUEST] + "> /dev/null 2>&1") + endTime=datetime.datetime.now() + bootTime=(endTime-startTime).microseconds + with open("startup_cont_benchmark.csv", "a") as file: + writer = csv.writer(file) + writer.writerow([NBR_VMS, GUEST, (bootTime/1000000)]) + +if __name__ == '__main__': + if len(sys.argv) < 2: + print("Application Startup Benchmarking Tool - CETIC Internship 2017/18 on Unikernels\n\tUsage: python3 startup_cont_benchmark.py [nbr of VMs]") + sys.exit(1) + + NBR_VMS=int(sys.argv[1]) + + if os.path.isfile("startup_cont_benchmark.csv") is not True: + subprocess.run("touch startup_cont_benchmark.csv", stdout=subprocess.PIPE, shell=True) + with open("startup_cont_benchmark.csv", "w") as file: + writer = csv.writer(file) + writer.writerow(["NBR_OF_GUESTS", "GUEST_STOPPED", "STARTUP_TIME_SECONDS"]) + + while NBR_VMS < MAX_NBR_VMS: + print("### STOPPING PREVIOUS VMS") + # stop all running VMs + run_cmd("docker stop $(docker ps -a -q) 2> /dev/null") + run_cmd("virsh list | grep running | awk '{ print $2}' | while read DOMAIN; do virsh destroy $DOMAIN; sleep 3; virsh undefine $DOMAIN; done") + run_cmd("docker ps -a -q | while read DOMAIN; do docker rm $DOMAIN; done") + + # create table of guest VMs + GUESTS.clear() + i = 10 + for x in range(int(NBR_VMS)): + GUESTS[("VM_"+str(x))] = ("172.18.0." + str(i)) + i = i+1 + + print("### BUILDING CONTAINERS") + run_cmd("cd ../SOURCE/CONTAINER && docker build -t cetic/compiler .") + run_cmd("cd ../SOURCE/CONTAINER/DNS &&\ + docker run --rm -it -v $PWD:/usr/src/build -w /usr/src/build cetic/compiler g++ -std=c++11 -static -o runnableService *.cpp &&\ + docker build -t cetic/dns .") + run_cmd("docker network create --subnet=172.18.0.0/16 --driver=bridge bench_net 2> /dev/null") + + print("### LAUNCHING CONTAINERS") + # create and launch each VM + for key, value in GUESTS.items(): + # for each entry in GUESTS build the unikernel and move the img to another folder + + run_cmd("docker run --cpus 1 -m 128m -d --ip " + value + " --network=bench_net --name " + key + " cetic/dns 2> /dev/null") + + print("### LAUNCHING BENCHMARK FOR " + str(BENCHMARK_TIME_SECONDS) + " SECONDS") + + timeout=time.time() + BENCHMARK_TIME_SECONDS + while time.time() <= timeout: + # stop a VM + RANDOM_GUEST="VM_"+str(random.randint(0, (int(NBR_VMS)-1))) + run_cmd("docker stop " + RANDOM_GUEST) + print(RANDOM_GUEST + " shut down") + # launch a thread to start a VM + _thread.start_new_thread(run_cmd, ("docker start " + RANDOM_GUEST, )) + # launch another thread to time boot time + _thread.start_new_thread(timeGuestStart, (RANDOM_GUEST, )) + print(RANDOM_GUEST + " started...") + time.sleep(5) + + #increment number of VMs for next test + NBR_VMS=NBR_VMS+NBR_VMS_INCREMENT + + run_cmd("docker stop $(docker ps -a -q) 2> /dev/null") + + \ No newline at end of file diff --git a/BENCHMARKING/startup_unik_benchmark.py b/BENCHMARKING/startup_unik_benchmark.py new file mode 100644 index 0000000..e1ab16c --- /dev/null +++ b/BENCHMARKING/startup_unik_benchmark.py @@ -0,0 +1,118 @@ +#!/usr/bin/python3 +import sys +import subprocess +import os.path +import csv +import json +import time +import _thread +import os +import datetime as datetime +import random + +BENCHMARK_TIME_SECONDS=60*20 +MAX_NBR_VMS=150 +NBR_VMS_INCREMENT=10 +GUESTS=dict() +NBR_VMS=0 + +def run_cmd(COMMAND): + return subprocess.run(COMMAND, stdout=subprocess.PIPE, shell=True) + +def timeGuestStart(GUEST): + response = 1 + startTime=datetime.datetime.now() + while response is not 0: + response = os.system("ping -c 1 " + GUESTS[GUEST] + "> /dev/null 2>&1") + endTime=datetime.datetime.now() + bootTime=(endTime-startTime).microseconds + with open("startup_unik_benchmark.csv", "a") as file: + writer = csv.writer(file) + writer.writerow([NBR_VMS, GUEST, (bootTime/1000000)]) + +if __name__ == '__main__': + if len(sys.argv) < 2: + print("Application Startup Benchmarking Tool - CETIC Internship 2017/18 on Unikernels\n\tUsage: python3 startup_unik_benchmark.py [nbr of VMs]") + sys.exit(1) + + NBR_VMS=int(sys.argv[1]) + + if os.path.isfile("startup_unik_benchmark.csv") is not True: + subprocess.run("touch startup_unik_benchmark.csv", stdout=subprocess.PIPE, shell=True) + with open("startup_unik_benchmark.csv", "w") as file: + writer = csv.writer(file) + writer.writerow(["NBR_OF_GUESTS", "GUEST_STOPPED", "STARTUP_TIME_SECONDS"]) + + + while NBR_VMS < MAX_NBR_VMS: + print("### STOPPING PREVIOUS VMS") + # stop all running VMs + run_cmd("docker stop $(docker ps -a -q) 2> /dev/null") + run_cmd("virsh list | grep running | awk '{ print $2}' | while read DOMAIN; do virsh destroy $DOMAIN; sleep 3; done") + run_cmd("virsh list --all | grep VM_ | awk '{ print $2}' | while read DOMAIN; do virsh undefine $DOMAIN; sleep 3; done") + + # create table of guest VMs + GUESTS.clear() + i = 10 + for x in range(int(NBR_VMS)): + GUESTS[("VM_"+str(x))] = ("192.168.122." + str(i)) + i = i+1 + #print(GUESTS) + + run_cmd("sudo rm -rf GUESTS; mkdir GUESTS") + # create and launch each VM + print("### BUILDING UNIKERNEL IMAGES") + for key, value in GUESTS.items(): + # modify config.json with the IP address + data = {} + data["net"] = [] + data["net"].append({ + "iface": 0, + "config": "static", + "address": value , + "netmask": "255.255.255.0", + "gateway": "192.168.122.1" + }) + with open("UNIKERNEL/DNS/config.json", "w") as outfile: + json.dump(data, outfile) + + # for each entry in GUESTS build the unikernel and move the img to another folder + run_cmd("cd UNIKERNEL/DNS && sudo rm -rf build && mkdir -p build && cd build && cmake .. && sudo make 2> /dev/null") + run_cmd(("sudo mv UNIKERNEL/DNS/build/DNS.img GUESTS/" + key + ".img")) + + run_cmd(("virt-install \ + --virt-type qemu --name " + key + " \ + --vcpus 1 --ram 128 \ + --import --disk GUESTS/" + key +".img \ + --serial file,path=/tmp/" + key + ".log \ + --network network=default,model=virtio \ + --check path_in_use=off \ + --noautoconsole")) + print(" - " + key + " built") + + print("### LAUNCHING BENCHMARK FOR " + str(BENCHMARK_TIME_SECONDS) + " SECONDS") + + timeout = time.time() + BENCHMARK_TIME_SECONDS + while time.time() <= timeout: + # TODO loop for a predetermined number of time + # TODO stop a random VM, restart it, time its boot time + # stop a VM + RANDOM_GUEST="VM_"+str(random.randint(0, (int(NBR_VMS)-1))) + run_cmd("virsh destroy " + RANDOM_GUEST) + print(RANDOM_GUEST + " shut down") + # launch a thread to start a VM + _thread.start_new_thread(run_cmd, ("virsh start " + RANDOM_GUEST, )) + # launch another thread to time boot time + _thread.start_new_thread(timeGuestStart, (RANDOM_GUEST, )) + print(RANDOM_GUEST + " started...") + time.sleep(5) + + #increment number of VMs for next test + NBR_VMS=NBR_VMS+NBR_VMS_INCREMENT + + # cleanup test bed + run_cmd("virsh list --all | grep VM_ | awk '{ print $2}' | while read DOMAIN; do virsh destroy $DOMAIN; sleep 3; virsh undefine $DOMAIN; done") + run_cmd("sudo rm -rf GUESTS") + + + \ No newline at end of file diff --git a/BENCHMARKING/web_cont_benchmark.py b/BENCHMARKING/web_cont_benchmark.py new file mode 100644 index 0000000..02dc645 --- /dev/null +++ b/BENCHMARKING/web_cont_benchmark.py @@ -0,0 +1,64 @@ +#!/usr/bin/python3 +import sys +import subprocess +import shutil +import os.path +import csv +import time +import string + +RUN=1 +TIME=300 +CONNECTIONS=100 +THREADS=4 +QPS=100 +QPS_INCREMENT=100 + +if __name__ == '__main__': + if len(sys.argv) < 2: + print("DNS Server Benchmarking Tool - CETIC Internship 2017/18 on Unikernels\n\tUsage: python3 web_cont_benchmark.py [server_ip_address]") + sys.exit(1) + + SVR_IP=sys.argv[1] + + if shutil.which("dnsperf") is None: + print("ERROR: dnsperf is not installed, please run the install_bench_tools.sh script.") + sys.exit(1) + + if os.path.isfile("web_cont_benchmark.csv") is not True: + subprocess.run("touch web_cont_benchmark.csv", stdout=subprocess.PIPE, shell=True) + + with open("web_cont_benchmark.csv", "w") as file: + writer = csv.writer(file) + writer.writerow(["TEST_RUN", "QUERIES_SENT", "QUERIES_PER_SECOND", "AVG_LATENCY_MILLISECONDS", "MAX_LATENCY_MILLISECONDS", "LATENCY_STD_DEV_PERCENT"]) + + while True: + print("########## LAUNCHING TEST " + str(RUN) + " ##########") + print("Queries per seconds: " + str(QPS)) + # launch the dnsperf command + result = subprocess.run("wrk2 -t " + str(THREADS) + " -d " + str(TIME) + "s -c " + str(CONNECTIONS) + " -R " + str(QPS) + " http://" + SVR_IP + "/", stdout=subprocess.PIPE, shell=True) + #print(result.stdout.decode('utf-8')) + + # convert output and store it in the csv file + list = result.stdout.decode("utf-8").split('\n') + for index in range(len(list)): + if list[index].startswith(" Latency"): + avgLatency=list[index].split()[1].strip(string.ascii_letters) + latencyMax=list[index].split()[3].strip(string.ascii_letters) + latencyStdDev=list[index].split()[2].strip(string.ascii_letters) + queriesSent=list[index+2].split()[0] + queriesPerSecond=list[index+3].split()[1] + + print("Queries sent:\t\t" + queriesSent + "\nQueries per second:\t" + queriesPerSecond + "\nAverage latency:\t" + avgLatency + "ms" + \ + "\nMax latency:\t\t" + latencyMax + "ms" + "\nLatency Std Dev:\t" + latencyStdDev + "ms") + with open("web_cont_benchmark.csv", "a") as file: + writer = csv.writer(file) + writer.writerow([RUN, queriesSent, queriesPerSecond, avgLatency, latencyMax, latencyStdDev]) + break + + print("########## TEST " + str(RUN) + " COMPLETE ##########\n") + # increase the TEST_RUN value and increment the number of queries per second + RUN=RUN+1 + QPS=QPS+QPS_INCREMENT + # sleep for 30 seconds between tests + time.sleep(30) \ No newline at end of file diff --git a/BENCHMARKING/web_unik_benchmark.py b/BENCHMARKING/web_unik_benchmark.py new file mode 100644 index 0000000..88a059d --- /dev/null +++ b/BENCHMARKING/web_unik_benchmark.py @@ -0,0 +1,64 @@ +#!/usr/bin/python3 +import sys +import subprocess +import shutil +import os.path +import csv +import time +import string + +RUN=1 +TIME=300 +CONNECTIONS=100 +THREADS=4 +QPS=100 +QPS_INCREMENT=100 + +if __name__ == '__main__': + if len(sys.argv) < 2: + print("DNS Server Benchmarking Tool - CETIC Internship 2017/18 on Unikernels\n\tUsage: python3 web_unik_benchmark.py [server_ip_address]") + sys.exit(1) + + SVR_IP=sys.argv[1] + + if shutil.which("dnsperf") is None: + print("ERROR: dnsperf is not installed, please run the install_bench_tools.sh script.") + sys.exit(1) + + if os.path.isfile("web_unik_benchmark.csv") is not True: + subprocess.run("touch web_unik_benchmark.csv", stdout=subprocess.PIPE, shell=True) + + with open("web_unik_benchmark.csv", "w") as file: + writer = csv.writer(file) + writer.writerow(["TEST_RUN", "QUERIES_SENT", "QUERIES_PER_SECOND", "AVG_LATENCY_MILLISECONDS", "MAX_LATENCY_MILLISECONDS", "LATENCY_STD_DEV_PERCENT"]) + + while True: + print("########## LAUNCHING TEST " + str(RUN) + " ##########") + print("Queries per seconds: " + str(QPS)) + # launch the dnsperf command + result = subprocess.run("wrk2 -t " + str(THREADS) + " -d " + str(TIME) + "s -c " + str(CONNECTIONS) + " -R " + str(QPS) + " http://" + SVR_IP + "/", stdout=subprocess.PIPE, shell=True) + #print(result.stdout.decode('utf-8')) + + # convert output and store it in the csv file + list = result.stdout.decode("utf-8").split('\n') + for index in range(len(list)): + if list[index].startswith(" Latency"): + avgLatency=list[index].split()[1].strip(string.ascii_letters) + latencyMax=list[index].split()[3].strip(string.ascii_letters) + latencyStdDev=list[index].split()[2].strip(string.ascii_letters) + queriesSent=list[index+2].split()[0] + queriesPerSecond=list[index+3].split()[1] + + print("Queries sent:\t\t" + queriesSent + "\nQueries per second:\t" + queriesPerSecond + "\nAverage latency:\t" + avgLatency + "ms" + \ + "\nMax latency:\t\t" + latencyMax + "ms" + "\nLatency Std Dev:\t" + latencyStdDev + "ms") + with open("web_unik_benchmark.csv", "a") as file: + writer = csv.writer(file) + writer.writerow([RUN, queriesSent, queriesPerSecond, avgLatency, latencyMax, latencyStdDev]) + break + + print("########## TEST " + str(RUN) + " COMPLETE ##########\n") + # increase the TEST_RUN value and increment the number of queries per second + RUN=RUN+1 + QPS=QPS+QPS_INCREMENT + # sleep for 30 seconds between tests + time.sleep(30) \ No newline at end of file diff --git a/DEPLOYMENT/README.md b/DEPLOYMENT/README.md new file mode 100644 index 0000000..2035a4e --- /dev/null +++ b/DEPLOYMENT/README.md @@ -0,0 +1,54 @@ +# Deployment + +This folder contains the files to deploy the proof of concept environment. + +## pre_deployment_installation.sh + +Installs all the required components to launch both the unikernel and the container environment. + +Install includes: +* IncludeOS project installation +* libvirt for unikernel virtual machines deployment +* Docker CE for container deployments + +**NOTE:** installation of the Docker CE adds the current user to the docker group, you must logout/login for the changes to take effect. + +## deploy_unikernels.sh + +This script will deploy the unikernels by taking the following steps: +* building the unikernels from the source code (in the SOURCE directory) +* create the QEMU networks for the unikernels virtual machine +* create and launch the virtual machines in their respective networks + +The networks are created with the following addressing: + +![Proof of concept network addressing scheme](https://git.cetic.be/stages/unikernels/raw/feature/stagelongree2018/MEDIA/unikernel_network.PNG "Proof of concept network addressing scheme") + +| VM | IP Address | +| ----------- |-----------------| +| Firewall | 192.168.100.254 | +| Firewall | 192.168.101.3 | +| Router | 192.168.101.2 | +| Router | 10.0.0.254 | +| Web server | 10.0.0.5 | +| DNS server | 10.0.0.100 | + +The current proof of concept environment and is self contained. It is not possible to directly connect the firewall to the external network. +It is possible to contact the DNS and the web server through iptables rules (examples in the benchmark launching scripts). + +## deploy_containers.sh + +This script will deploy the containers (using ported code from the unikernel versions) by taking the following steps: +* building the compiler image +* running the compiler image to cross-compile the application +* build the application container using the compiled application program +* run the container images built in the previous step + +The container ports are mapped as follows: + +| Container | Host Port | Guest Port | +| ----------- | ---------- | ---------- | +| Web server | 80/tcp | 80/tcp | +| DNS server | 53/udp | 53/udp | + +**NOTE:** due to time constraints during the project, the firewall and router applications were not ported to containers. \ No newline at end of file diff --git a/DEPLOYMENT/deploy_containers.sh b/DEPLOYMENT/deploy_containers.sh new file mode 100644 index 0000000..0e35856 --- /dev/null +++ b/DEPLOYMENT/deploy_containers.sh @@ -0,0 +1,43 @@ +#!/bin/bash +#NB: due to time constraint, only the DNS and WebServer analogs +# have code ported from the Unikernel application. +# Additionally the container ports are bound to the host's +# IP address for benchmarking. + +SRC_DIR=$HOME/unikernels +CONTAINERS=$SRC_DIR/SOURCE/CONTAINER + +# exposes the interface with internet connectivity for benchmarking +# if your benchmarking device is on another network, adjust accordingly +IP=$(ip -4 route get 8.8.8.8 | awk {'print $7'} | tr -d '\n') +DNS_PORT=53 +WEB_PORT=80 + +# build Docker containers +# 1 - compiler docker +pushd $CONTAINERS && +docker build -t cetic/compiler . && +popd && + +# 2 - individual dockers +pushd $CONTAINERS/DNS && +docker run --rm -it -v "${PWD}":/usr/src/build -w /usr/src/build cetic/compiler g++ -std=c++11 -static -o runnableService *.cpp && +docker build -t cetic/dns . && +popd && + +pushd $CONTAINERS/WebServer && +docker run --rm -it -v "${PWD}":/usr/src/build -w /usr/src/build cetic/compiler g++ -std=c++11 -static -o runnableService *.cpp && +docker build -t cetic/webserver . && +popd && + +# launch docker containers +docker run --rm --cpuset-cpus 1 -m 128m -d -p $IP:$DNS_PORT:$DNS_PORT/udp --name DNS cetic/dns +docker run --rm --cpuset-cpus 1 -m 128m -d -p $IP:$WEB_PORT:$WEB_PORT --name WebServer cetic/webserver + +echo "#############################################################################" +echo "### ###" +echo "### Containers successfully launched. ###" +echo "### Web server accessible on port $WEB_PORT. ###" +echo "### DNS server accessible on port $DNS_PORT. ###" +echo "### ###" +echo "#############################################################################" diff --git a/DEPLOYMENT/deploy_unikernels.sh b/DEPLOYMENT/deploy_unikernels.sh new file mode 100644 index 0000000..05d37a0 --- /dev/null +++ b/DEPLOYMENT/deploy_unikernels.sh @@ -0,0 +1,93 @@ +#!/bin/bash + +# NB: This script assumes you cloned the project into you HOME directory. +# If this is not the case, change the following variables accordingly + +SRC_DIR=$HOME/unikernels +UNIKERELS=$SRC_DIR/SOURCE/UNIKERNEL + +# build unikernels +pushd $UNIKERELS/DNS &&\ +mkdir -p build &&\ +pushd build &&\ +cmake .. &&\ +make &&\ +popd &&\ + +pushd $UNIKERELS/WebServer &&\ +mkdir -p build &&\ +pushd build &&\ +cmake .. &&\ +sudo make &&\ +popd &&\ + +pushd $UNIKERELS/Router &&\ +mkdir -p build &&\ +pushd build &&\ +cmake .. &&\ +make &&\ +popd &&\ + +pushd $UNIKERELS/Firewall &&\ +mkdir -p build &&\ +pushd build &&\ +cmake .. &&\ +make &&\ +popd &&\ + +# configure networks for QEMU +# remove default bridge created +sudo ip link del bridge43 +# create the bridge interfaces +virsh net-define --file $UNIKERELS/internal.xml && +virsh net-define --file $UNIKERELS/external.xml && +virsh net-define --file $UNIKERELS/firewall.xml && +virsh net-start internal && +virsh net-start external && +virsh net-start firewall && +virsh net-autostart internal && +virsh net-autostart external && +virsh net-autostart firewall && + +# launch unikernels in QEMU (+serial output to files) + +virt-install \ + --virt-type qemu --name DNS \ + --vcpus 1 --ram 128 \ + --import --disk $UNIKERELS/DNS/build/DNS.img \ + --serial file,path=/tmp/dns.log \ + --network network=internal,model=virtio \ + --noautoconsole && + +virt-install \ + --virt-type qemu --name WebServer \ + --vcpus 1 --ram 128 \ + --import --disk $UNIKERELS/WebServer/build/WebServer.img \ + --serial file,path=/tmp/web.log \ + --network network=internal,model=virtio \ + --noautoconsole && + +virt-install \ + --virt-type qemu --name Router \ + --vcpus 1 --ram 128 \ + --import --disk $UNIKERELS/Router/build/Router.img \ + --serial file,path=/tmp/router.log \ + --network network=internal,model=virtio \ + --network network=firewall,model=virtio \ + --noautoconsole && + +virt-install \ + --virt-type qemu --name Firewall \ + --vcpus 1 --ram 128 \ + --import --disk $UNIKERELS/Firewall/build/Firewall.img \ + --serial file,path=/tmp/firewall.log \ + --network network=external,model=virtio \ + --network network=firewall,model=virtio \ + --noautoconsole && + +echo "#############################################################################" +echo "### ###" +echo "### Unikernels successfully launched. ###" +echo "### Serial outputs are located in /tmp. ###" +echo "### ###" +echo "#############################################################################" diff --git a/DEPLOYMENT/pre_deployment_installation.sh b/DEPLOYMENT/pre_deployment_installation.sh new file mode 100644 index 0000000..04febec --- /dev/null +++ b/DEPLOYMENT/pre_deployment_installation.sh @@ -0,0 +1,30 @@ +#!/bin/bash +sudo apt-get update && +sudo apt-get install -y git && + +# install IncludeOS +pushd $HOME && +git clone --recurse-submodules https://github.com/hioa-cs/IncludeOS && +popd && +pushd $HOME/IncludeOS && +sudo ./install.sh -y && +popd && + +# install libvirt +sudo apt-get install -y libvirt-bin virtinst && +#NB: requires logout/login to take effect +sudo usermod -a -G libvirtd $USER && + +# install Docker +sudo apt-get install -y apt-transport-https ca-certificates curl software-properties-common && +curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - && +sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" && +sudo apt-get update && +sudo apt-get install -y docker-ce && +sudo usermod -a -G docker $USER && + +echo "#############################################################################" +echo "### ###" +echo "### /!\ You must logout/login to apply changes before continuing. /!\ ###" +echo "### ###" +echo "#############################################################################" diff --git a/MEDIA/Benchmark 2.png b/MEDIA/Benchmark 2.png new file mode 100644 index 0000000..ba076ec Binary files /dev/null and b/MEDIA/Benchmark 2.png differ diff --git a/MEDIA/Benchmark.png b/MEDIA/Benchmark.png new file mode 100644 index 0000000..b8ff968 Binary files /dev/null and b/MEDIA/Benchmark.png differ diff --git a/MEDIA/Benchmark.xml b/MEDIA/Benchmark.xml new file mode 100644 index 0000000..e8d8d51 --- /dev/null +++ b/MEDIA/Benchmark.xml @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/MEDIA/CETIC.xml b/MEDIA/CETIC.xml new file mode 100644 index 0000000..d38c77c --- /dev/null +++ b/MEDIA/CETIC.xml @@ -0,0 +1 @@ +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 \ No newline at end of file diff --git a/MEDIA/PoC Topology.png b/MEDIA/PoC Topology.png new file mode 100644 index 0000000..bdf0a55 Binary files /dev/null and b/MEDIA/PoC Topology.png differ diff --git a/MEDIA/hypervisor_container_unikernel.jpg b/MEDIA/hypervisor_container_unikernel.jpg new file mode 100644 index 0000000..9de68af Binary files /dev/null and b/MEDIA/hypervisor_container_unikernel.jpg differ diff --git a/MEDIA/mutable-vs-immutable-update.PNG b/MEDIA/mutable-vs-immutable-update.PNG new file mode 100644 index 0000000..4239258 Binary files /dev/null and b/MEDIA/mutable-vs-immutable-update.PNG differ diff --git a/MEDIA/normal_application_stack.PNG b/MEDIA/normal_application_stack.PNG new file mode 100644 index 0000000..7136d6c Binary files /dev/null and b/MEDIA/normal_application_stack.PNG differ diff --git a/MEDIA/unikernel_application_stack.PNG b/MEDIA/unikernel_application_stack.PNG new file mode 100644 index 0000000..60a7b3f Binary files /dev/null and b/MEDIA/unikernel_application_stack.PNG differ diff --git a/MEDIA/unikernel_network.PNG b/MEDIA/unikernel_network.PNG new file mode 100644 index 0000000..e842074 Binary files /dev/null and b/MEDIA/unikernel_network.PNG differ diff --git a/MEDIA/vms-containers-unikernels.PNG b/MEDIA/vms-containers-unikernels.PNG new file mode 100644 index 0000000..5df8c4d Binary files /dev/null and b/MEDIA/vms-containers-unikernels.PNG differ diff --git a/SOURCE/CONTAINER/DNS/Dockerfile b/SOURCE/CONTAINER/DNS/Dockerfile new file mode 100644 index 0000000..df1bb56 --- /dev/null +++ b/SOURCE/CONTAINER/DNS/Dockerfile @@ -0,0 +1,5 @@ +FROM alpine:latest +RUN mkdir /service +COPY runnableService /service +WORKDIR /service +CMD sleep 1 && ./runnableService "$(hostname -i)" diff --git a/SOURCE/CONTAINER/DNS/compile.sh b/SOURCE/CONTAINER/DNS/compile.sh new file mode 100644 index 0000000..fca659f --- /dev/null +++ b/SOURCE/CONTAINER/DNS/compile.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +docker run --rm -it -v "${PWD}":/usr/src/build -w /usr/src/build cetic/compiler g++ -std=c++11 -static -o runnableService *.cpp diff --git a/SOURCE/CONTAINER/DNS/create_container.sh b/SOURCE/CONTAINER/DNS/create_container.sh new file mode 100644 index 0000000..d248b8e --- /dev/null +++ b/SOURCE/CONTAINER/DNS/create_container.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +docker build -t cetic/dns . diff --git a/SOURCE/CONTAINER/DNS/dnsServer.cpp b/SOURCE/CONTAINER/DNS/dnsServer.cpp new file mode 100644 index 0000000..d023762 --- /dev/null +++ b/SOURCE/CONTAINER/DNS/dnsServer.cpp @@ -0,0 +1,283 @@ +/** + * Basic DNS server for the IncludeOS unikernel framework. + * + * This code uses portions of code created by GitHub user tomasorti for his dns-server project (https://github.com/tomasorti/dns-server) + */ + +#include +#include +#include +#include +#include +#include +#include + +#define SERVER_PORT 53 +#define BUFFER_SIZE 1024 + +static const unsigned int QR_MASK = 0x8000; +static const unsigned int OPCODE_MASK = 0x7800; +static const unsigned int AA_MASK = 0x0400; +static const unsigned int TC_MASK = 0x0200; +static const unsigned int RD_MASK = 0x0100; +static const unsigned int RA_MASK = 0x8000; +static const unsigned int RCODE_MASK = 0x000F; +static const unsigned int HDR_OFFSET = 12; + +// for more info on DNS fields, see RFC 1035 + +struct queryHeader { + unsigned int id; // 16 bit identifier assigned by the program who generated the query + unsigned int query; // identifies if message is query (0) or a response (1) + unsigned int opcode; // 4 bit field specifying kind of query: standard (0), inverse (1), server status request (2), reserved (3-15) + unsigned int aa; // bit indicating if responding server is an authority for the domain name + unsigned int truncation; // specifies whether this message was truncated or not + unsigned int recursionDesired; // may be set in a query, directs the name server to pursue the query recursively + unsigned int recursionAvailable; // set in a response, indicates whether recursive queries are available + unsigned int responseCode; // 4 bit response code: 0 - no error, 1 - format error, 2 - server failure, 3 - name error, 4 - not implemented, 5 - refused + + // unsigned 16-bit integers + unsigned int questionCount; // number of entries in the question section + unsigned int answerCount; // number of resource reconds in the answer section + unsigned int nameServerCount; // number of name server resource records in the authority records section + unsigned int additionalResourceCount; // number of resource records in the additional records section +}; + +struct queryQuestion { + std::string queryName; // domain name requested + unsigned int queryType; // 2 octet code specifying the type of the query + unsigned int queryClass; // 2 octet code specifying the class of the query +}; + +queryHeader pQueryHeader; +queryQuestion pQueryQuestion; +std::map> resourceRecords; + +unsigned int get16bits(char*& buffer) { + unsigned int value = static_cast (buffer[0]); + value = value << 8; + value += static_cast (buffer[1]); + buffer += 2; + + return value; +} + +void put8bits(char*& buffer, unsigned int value) throw () { + buffer[0] = (value); + buffer += 1; +} + +void put16bits(char*& buffer, unsigned int value) throw () { + buffer[0] = (value & 0xFF00) >> 8; + buffer[1] = value & 0xFF; + buffer += 2; +} + +void put32bits(char*& buffer, unsigned long value) throw () { + buffer[0] = (value & 0xFF000000) >> 24; + buffer[1] = (value & 0xFF0000) >> 16; + buffer[2] = (value & 0xFF00) >> 16; + buffer[3] = (value & 0xFF) >> 16; + buffer += 4; +} + +queryHeader decodeHeader(char* data, queryHeader pQueryHeader){ + pQueryHeader.id = get16bits(data); + + unsigned int fields = get16bits(data); + pQueryHeader.query = fields & QR_MASK; + pQueryHeader.opcode = fields & OPCODE_MASK; + pQueryHeader.aa = fields & AA_MASK; + pQueryHeader.truncation = fields & TC_MASK; + pQueryHeader.recursionDesired = fields & RD_MASK; + pQueryHeader.recursionAvailable = fields & RA_MASK; + + pQueryHeader.questionCount = get16bits(data); + pQueryHeader.answerCount = get16bits(data); + pQueryHeader.nameServerCount = get16bits(data); + pQueryHeader.additionalResourceCount = get16bits(data); + return pQueryHeader; +} + +queryQuestion decodeQuery(char*& data, queryQuestion pQueryQuestion){ + pQueryQuestion.queryName = ""; + + int length = *data++; + while (length != 0) { + for (int i = 0; i < length; i++) { + char c = *data++; + pQueryQuestion.queryName.append(1, c); + } + length = *data++; + if (length != 0) pQueryQuestion.queryName.append(1,'.'); + } + + pQueryQuestion.queryType = get16bits(data); + pQueryQuestion.queryClass = get16bits(data); + return pQueryQuestion; +} + +void codeDomain(char*& buffer, const std::string& domain) { + int start = 0, end; // indexes + while ((end = domain.find('.', start)) != std::string::npos) { + *buffer++ = end - start; // label length octet + for (int i=start; i>::iterator record = resourceRecords.find(pQueryQuestion.queryName); + if (record == resourceRecords.end()) + bRRexists = false; + + char* bufferBegin = buffer; + + // create header + put16bits(buffer, pQueryHeader.id); + + int fields = (1 << 15); // Response code + fields += (0 << 11); // Opcode + fields += (0 << 10); // Authoritative code + fields += (0 << 9); // Truncated code + fields += (1 << 8); // Recursion desired code + fields += (0 << 7); // Recursion available code + fields += (0 << 6); // Z reserved code + fields += (0 << 5); // Answers authenticated code + fields += (0 << 4); // Non-authenticated data code + if(bRRexists && pQueryQuestion.queryType == 1) + fields += 0; // Reply code + else + fields += 3; + put16bits(buffer, fields); + + put16bits(buffer, pQueryHeader.questionCount); // Questions count + if(bRRexists && pQueryQuestion.queryType == 1) + put16bits(buffer, 1); // Answers count + else + put16bits(buffer, 0); + put16bits(buffer, 0); // Authority RRs + put16bits(buffer, 0); // Additional RRs + + // create domain query section - copy original question format + codeDomain(buffer, pQueryQuestion.queryName); + put16bits(buffer, pQueryQuestion.queryType); + put16bits(buffer, pQueryQuestion.queryClass); + + // if requested domain exists in resourceRecords, create the answer + if(bRRexists && pQueryQuestion.queryType == 1){ + // compression code to pointing to original question - should be offset from ID to domain name (in number of 16bits) + put16bits(buffer, 49164); + + put16bits(buffer, pQueryQuestion.queryType); + put16bits(buffer, pQueryQuestion.queryClass); + put32bits(buffer, 0); // time to live + + put16bits(buffer, 4); // data length (always 4 for IPv4 addresses) + put8bits(buffer,resourceRecords[pQueryQuestion.queryName][0]); + put8bits(buffer,resourceRecords[pQueryQuestion.queryName][1]); + put8bits(buffer,resourceRecords[pQueryQuestion.queryName][2]); + put8bits(buffer,resourceRecords[pQueryQuestion.queryName][3]); + } + + int size = buffer - bufferBegin; + + return size; +} + +int main(int argc, char *argv[]) +{ + resourceRecords["www.cetic.be"].push_back(10); + resourceRecords["www.cetic.be"].push_back(0); + resourceRecords["www.cetic.be"].push_back(0); + resourceRecords["www.cetic.be"].push_back(5); + resourceRecords["cetic.be"].push_back(10); + resourceRecords["cetic.be"].push_back(0); + resourceRecords["cetic.be"].push_back(0); + resourceRecords["cetic.be"].push_back(5); + resourceRecords["internship.cetic.be"].push_back(10); + resourceRecords["internship.cetic.be"].push_back(0); + resourceRecords["internship.cetic.be"].push_back(0); + resourceRecords["internship.cetic.be"].push_back(5); + + // define address and socket variables + struct sockaddr_in serverAddress; + int serverSocket; + struct sockaddr_in clienAddress; + socklen_t clientAddressLength = sizeof(clienAddress); + int bytesReceivedLength; + char receiveBuffer[BUFFER_SIZE]; + + // creating UDP socket + if ((serverSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + perror("cannot create socket"); + return 0; + } + + // defining server address properties + memset((void *)&serverAddress, 0, sizeof(serverAddress)); + serverAddress.sin_family = AF_INET; + serverAddress.sin_addr.s_addr = inet_addr(argv[1]); + //serverAddress.sin_addr.s_addr = htonl(INADDR_ANY); + serverAddress.sin_port = htons(SERVER_PORT); + + // binding to UDP socket + if (bind(serverSocket, (struct sockaddr *)&serverAddress, sizeof(serverAddress)) < 0) { + perror("bind failed"); + return 0; + } + + printf("Service IP address is %s on port %d\n", inet_ntoa(serverAddress.sin_addr), ntohs(serverAddress.sin_port)); + + for (;;) { + bytesReceivedLength = recvfrom(serverSocket, receiveBuffer, BUFFER_SIZE, 0, (struct sockaddr *)&clienAddress, &clientAddressLength); + printf("received %d bytes\n", bytesReceivedLength); + if (bytesReceivedLength > 0) { + char* data = &receiveBuffer[0]; + + pQueryHeader = decodeHeader(data, pQueryHeader); + data += HDR_OFFSET; + pQueryQuestion = decodeQuery(data, pQueryQuestion); + + // debug output + printf("####### INCOMMING REQUEST #######\n"); + printf("Getting UDP data from %s:%d\n", inet_ntoa(clienAddress.sin_addr), ntohs(clienAddress.sin_port)); + printf("Header:\n"); + printf("\tID: %u\n",pQueryHeader.id); + printf("\tQuery: %u\n", pQueryHeader.query); + printf("\topCode: %u\n", pQueryHeader.opcode); + printf("\tAA: %u\n", pQueryHeader.aa); + printf("\tTruncation: %u\n", pQueryHeader.truncation); + printf("\tRecursion Desired: %u\n", pQueryHeader.recursionDesired); + printf("\tRecursion Available: %u\n", pQueryHeader.recursionAvailable); + printf("\tReponse Code: %u\n", pQueryHeader.responseCode); + printf("\tQuestion Count: %u\n", pQueryHeader.questionCount); + printf("\tAnswer Count: %u\n", pQueryHeader.answerCount); + printf("\tName Server Count: %u\n", pQueryHeader.nameServerCount); + printf("\tAdditional Resource Count: %u\n", pQueryHeader.additionalResourceCount); + printf("Query:\n"); + printf("\tQuery name: %s\n", pQueryQuestion.queryName.data()); + printf("\tQuery Type: %u\n", pQueryQuestion.queryType); + printf("\tAdditional Resource Count: %u\n", pQueryQuestion.queryClass); + printf("#################################\n"); + + // send reply + char buffer[BUFFER_SIZE]; + int nbrBytes = processQuery(buffer, pQueryHeader, pQueryQuestion); + + sendto(serverSocket, buffer, nbrBytes, 0, (struct sockaddr *)&clienAddress, clientAddressLength); + } + } +} diff --git a/SOURCE/CONTAINER/DNS/run_service.sh b/SOURCE/CONTAINER/DNS/run_service.sh new file mode 100644 index 0000000..a49024a --- /dev/null +++ b/SOURCE/CONTAINER/DNS/run_service.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +docker run --rm -d cetic/dns diff --git a/SOURCE/CONTAINER/DNS/start.sh b/SOURCE/CONTAINER/DNS/start.sh new file mode 100644 index 0000000..5168160 --- /dev/null +++ b/SOURCE/CONTAINER/DNS/start.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +# Building binary from C++ code (statically linking libraries) +docker run --rm -it -v "${PWD}":/usr/src/build -w /usr/src/build cetic/compiler g++ -std=c++11 -static -o runnableService *.cpp + +# Building the container (expecting the Dockerfile to be present) +docker build -t cetic/dns . + +# Launching the service in a Docker container +docker run --rm -d cetic/dns diff --git a/SOURCE/CONTAINER/Dockerfile b/SOURCE/CONTAINER/Dockerfile new file mode 100644 index 0000000..72493db --- /dev/null +++ b/SOURCE/CONTAINER/Dockerfile @@ -0,0 +1,2 @@ +FROM alpine:latest +RUN apk add --no-cache gcc g++ diff --git a/SOURCE/CONTAINER/README.md b/SOURCE/CONTAINER/README.md new file mode 100644 index 0000000..2e491f5 --- /dev/null +++ b/SOURCE/CONTAINER/README.md @@ -0,0 +1,45 @@ +# Container Code + +This folder contains the container version of the unikernel services. + +Each folder holds: +* The CPP file containing the code +* A **compile.sh** script to compile the CPP file into a runnable service +* A **Dockerfile** to create the container for this service +* A **create_container.sh** script to create to container from the Dockerfile +* A **run_service.sh** script to run the created container in detached mode +* A **start.sh** script that will compile the binary from code, build the Docker container and run it (in detached mode) + +The following section briefly explains the steps taken. + +## Pre Requisite + +Before running the **compile.sh** or **start.sh** scripts, you must first build the **builder** container from the Dockerfile in this parent folder. + +This can be done by running the **create_compiler.sh** script or running the following command from the CONTAINER directory: + +``` +docker build -t cetic/compiler . +``` + +## Compiling the binary (*compile.sh*) + +*Requires the cetic/compiler container image* + +This script will launch a new cetic/compiler image container, mapping the current folder to a folder inside the container, then it will staticaly compile the C++ code in the .cpp file in the directory and output a *runnableService* binary. + +## Creating the container + +This will create the service container using the **Dockerfile**. + +It will use the lastest version of alpine base image and copy the **runnableService** executable inside the container. + +## Running the container + +When running the container, it will execute the command instructed in the **Dockerfile**. + +The container will wait for the network to be up (sleep 1) then it will launch the service binary, passing the container's IP address to bind the service to as a paramater. + +The script starts it in detached mode (i.e.: in the background) + +**NB:** as of now, the IP address is not given statically, you must run `docker network inspect bridge` to view the IP address assigned to the container. \ No newline at end of file diff --git a/SOURCE/CONTAINER/WebServer/Dockerfile b/SOURCE/CONTAINER/WebServer/Dockerfile new file mode 100644 index 0000000..ea95ca0 --- /dev/null +++ b/SOURCE/CONTAINER/WebServer/Dockerfile @@ -0,0 +1,6 @@ +FROM alpine:latest +RUN mkdir /service +COPY runnableService /service +COPY index.html /service +WORKDIR /service +CMD sleep 1 && ./runnableService "$(hostname -i)" diff --git a/SOURCE/CONTAINER/WebServer/compile.sh b/SOURCE/CONTAINER/WebServer/compile.sh new file mode 100644 index 0000000..fca659f --- /dev/null +++ b/SOURCE/CONTAINER/WebServer/compile.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +docker run --rm -it -v "${PWD}":/usr/src/build -w /usr/src/build cetic/compiler g++ -std=c++11 -static -o runnableService *.cpp diff --git a/SOURCE/CONTAINER/WebServer/create_container.sh b/SOURCE/CONTAINER/WebServer/create_container.sh new file mode 100644 index 0000000..74dcda1 --- /dev/null +++ b/SOURCE/CONTAINER/WebServer/create_container.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +docker build -t cetic/webserver . diff --git a/SOURCE/CONTAINER/WebServer/index.html b/SOURCE/CONTAINER/WebServer/index.html new file mode 100644 index 0000000..c6c9b59 --- /dev/null +++ b/SOURCE/CONTAINER/WebServer/index.html @@ -0,0 +1,15 @@ + + + + + CETIC Internship Unikernel Web Page + + + +

+ CETIC Internship Unikernel Web Page +

+
+

This is the first web server spawn from a unikernel during the CETIC Intership 2017-18

+ + diff --git a/SOURCE/CONTAINER/WebServer/run_service.sh b/SOURCE/CONTAINER/WebServer/run_service.sh new file mode 100644 index 0000000..6964d3d --- /dev/null +++ b/SOURCE/CONTAINER/WebServer/run_service.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +docker run --rm -d cetic/webserver diff --git a/SOURCE/CONTAINER/WebServer/start.sh b/SOURCE/CONTAINER/WebServer/start.sh new file mode 100644 index 0000000..d0f1184 --- /dev/null +++ b/SOURCE/CONTAINER/WebServer/start.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +# Building binary from C++ code (statically linking libraries) +docker run --rm -it -v "${PWD}":/usr/src/build -w /usr/src/build cetic/compiler g++ -std=c++11 -static -o runnableService *.cpp + +# Building the container (expecting the Dockerfile to be present) +docker build -t cetic/webserver . + +# Launching the service in a Docker container +docker run --rm -d cetic/webserver diff --git a/SOURCE/CONTAINER/WebServer/webServer.cpp b/SOURCE/CONTAINER/WebServer/webServer.cpp new file mode 100644 index 0000000..2f6c803 --- /dev/null +++ b/SOURCE/CONTAINER/WebServer/webServer.cpp @@ -0,0 +1,120 @@ +/* + * This code is adapted from the IncludeOS Acorn web server example. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define SERVER_PORT 80 +#define BUFFER_SIZE 2048 + +bool isIndexRequested(char receiveBuffer[]) { + // if only / is requested + if(receiveBuffer[4] == '/' && receiveBuffer[5] == ' ') + return true; + + // if only /index.html is requested + char request[25]; + memcpy(request, receiveBuffer, 24); + request[25] = '\0'; + + char *output = NULL; + output = strstr(request," /index.html "); + if(output) + return true; + + return false; +} + +int main(int argc, char *argv[]) +{ + // define address and socket variables + struct sockaddr_in serverAddress; + int serverSocket; + int clientSocket; + struct sockaddr_in clientAddress; + socklen_t clientAddressLength = sizeof(clientAddress); + int bytesReceivedLength; + char receiveBuffer[BUFFER_SIZE]; + + // Retrieve the HTML page from the disk + std::ifstream file("index.html", std::ios::binary | std::ios::ate); + std::streamsize indexLength = file.tellg(); + file.seekg(0, std::ios::beg); + char indexArray[indexLength]; + file.read(indexArray, indexLength); + + // creating error message + std::string error = "HTTP/1.1 404 Not Found\r\nContent-Type: text/html\r\n\r\nPage not found\r\n"; + int errorLength = error.length(); + // declaring character array + char errorArray[errorLength+1]; + strcpy(errorArray, error.c_str()); + + + // creating TCP socket + if ((serverSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + perror("cannot create socket"); + return 0; + } + + // defining server address properties + memset((void *)&serverAddress, 0, sizeof(serverAddress)); + serverAddress.sin_family = AF_INET; + serverAddress.sin_addr.s_addr = inet_addr(argv[1]); + //serverAddress.sin_addr.s_addr = htonl(INADDR_ANY); + serverAddress.sin_port = htons(SERVER_PORT); + + // binding to UDP socket + if (bind(serverSocket, (struct sockaddr *)&serverAddress, sizeof(serverAddress)) < 0) { + perror("bind failed"); + return 0; + } + + // set the socket for listening (queue backlog of 5) + if (listen(serverSocket, 5) < 0) { + perror("listen failed"); + return 0; + } + + printf("Service IP address is %s on port %d\n", inet_ntoa(serverAddress.sin_addr), ntohs(serverAddress.sin_port)); + + for (;;) { + clientSocket = accept(serverSocket, (struct sockaddr *)&clientAddress, &clientAddressLength); + + bytesReceivedLength = read(clientSocket, receiveBuffer, BUFFER_SIZE); + + printf("####### INCOMMING REQUEST #######\n"); + printf("Received a connection from: %s port %d\n", inet_ntoa(clientAddress.sin_addr), ntohs(clientAddress.sin_port)); + printf("received %d bytes\n", bytesReceivedLength); + + if (bytesReceivedLength > 0) { + + // TODO respond only to GET and / or /index.html + if(receiveBuffer[0] == 'G' && isIndexRequested(receiveBuffer) ) { //request is not a GET + // debug output + printf("%s", receiveBuffer); + + // send reply + //printf("%s", indexArray); + int nbytes = write(clientSocket, indexArray, indexLength); + printf("%d sent to client\n", nbytes); + } else { + printf("%s", receiveBuffer); + int nbytes = write(clientSocket, errorArray, (errorLength+1)); + printf("%d bytes sent to client\n", nbytes); + } + + printf("#################################\n"); + shutdown(clientSocket, 2); + } + } +} diff --git a/SOURCE/CONTAINER/create_compiler.sh b/SOURCE/CONTAINER/create_compiler.sh new file mode 100644 index 0000000..e0882f6 --- /dev/null +++ b/SOURCE/CONTAINER/create_compiler.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +docker build -t cetic/compiler . diff --git a/SOURCE/README.md b/SOURCE/README.md new file mode 100644 index 0000000..d7d76e1 --- /dev/null +++ b/SOURCE/README.md @@ -0,0 +1,21 @@ +# Source Code + +This folder contains the source code of the unikernel projects created with the [IncludeOS framework](https://github.com/hioa-cs/IncludeOS) + +Each folder contains the source code for a single unikernel. + +## Building Unikernel Image + +**Requires IncludeOS to be installed on the system** + +The script **cmake_build.sh** can be executed to build the each unikernel images. The .img disk file will be located in the **build** folder inside the project folder. + +## Container Versions + +The **CONTAINER** folder contains the container versions of the unikernel images. + +The container versions are aimed to be analogs of the unikernel code but adapted to run in a standalone Docker container. + +## Deployment + +For deploying the unikernel or container environment, see the [DEPLOYMENT](https://git.cetic.be/stages/unikernels/tree/feature/stagelongree2018/DEPLOYMENT) folder for deployment scripts. \ No newline at end of file diff --git a/SOURCE/UNIKERNEL/DNS/CMakeLists.txt b/SOURCE/UNIKERNEL/DNS/CMakeLists.txt new file mode 100644 index 0000000..3874757 --- /dev/null +++ b/SOURCE/UNIKERNEL/DNS/CMakeLists.txt @@ -0,0 +1,36 @@ +cmake_minimum_required(VERSION 2.8.9) + +# IncludeOS install location +if (NOT DEFINED ENV{INCLUDEOS_PREFIX}) + set(ENV{INCLUDEOS_PREFIX} /usr/local) +endif() +include($ENV{INCLUDEOS_PREFIX}/includeos/pre.service.cmake) +project (DNS) + +# Human-readable name of your service +set(SERVICE_NAME "CETIC DNS Service") + +# Name of your service binary +set(BINARY "DNS") + +# Source files to be linked with OS library parts to form bootable image +set(SOURCES + service.cpp # ...add more here + ) + +# To add your own include paths: +# set(LOCAL_INCLUDES ".") + +# DRIVERS / PLUGINS: + +set(DRIVERS + virtionet # Virtio networking + # virtioblock # Virtio block device + # ... Others from src/drivers +) + +set(PLUGINS + ) + +# include service build script +include($ENV{INCLUDEOS_PREFIX}/includeos/post.service.cmake) diff --git a/SOURCE/UNIKERNEL/DNS/cmake_build.sh b/SOURCE/UNIKERNEL/DNS/cmake_build.sh new file mode 100644 index 0000000..529e821 --- /dev/null +++ b/SOURCE/UNIKERNEL/DNS/cmake_build.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +mkdir -p build +pushd build +cmake .. +make +popd diff --git a/SOURCE/UNIKERNEL/DNS/config.json b/SOURCE/UNIKERNEL/DNS/config.json new file mode 100644 index 0000000..c38d4bc --- /dev/null +++ b/SOURCE/UNIKERNEL/DNS/config.json @@ -0,0 +1,11 @@ +{ + "net": [ + { + "iface": 0, + "config": "static", + "address": "10.0.0.100", + "netmask": "255.255.255.0", + "gateway": "10.0.0.254" + } + ] +} diff --git a/SOURCE/UNIKERNEL/DNS/service.cpp b/SOURCE/UNIKERNEL/DNS/service.cpp new file mode 100644 index 0000000..ba3342e --- /dev/null +++ b/SOURCE/UNIKERNEL/DNS/service.cpp @@ -0,0 +1,262 @@ +/** + * Basic DNS server for the IncludeOS unikernel framework. + * + * This code uses portions of code created by GitHub user tomasorti for his dns-server project (https://github.com/tomasorti/dns-server) + */ + +#include +#include +#include +#include + +using namespace net; + +#define SERVER_PORT 53 + +static const uint QR_MASK = 0x8000; +static const uint OPCODE_MASK = 0x7800; +static const uint AA_MASK = 0x0400; +static const uint TC_MASK = 0x0200; +static const uint RD_MASK = 0x0100; +static const uint RA_MASK = 0x8000; +static const uint RCODE_MASK = 0x000F; +static const uint HDR_OFFSET = 12; +static const int BUFFER_SIZE = 1024; + +// for more info on DNS fields, see RFC 1035 + +struct queryHeader { + uint id; // 16 bit identifier assigned by the program who generated the query + uint query; // identifies if message is query (0) or a response (1) + uint opcode; // 4 bit field specifying kind of query: standard (0), inverse (1), server status request (2), reserved (3-15) + uint aa; // bit indicating if responding server is an authority for the domain name + uint truncation; // specifies whether this message was truncated or not + uint recursionDesired; // may be set in a query, directs the name server to pursue the query recursively + uint recursionAvailable; // set in a response, indicates whether recursive queries are available + uint responseCode; // 4 bit response code: 0 - no error, 1 - format error, 2 - server failure, 3 - name error, 4 - not implemented, 5 - refused + + // unsigned 16-bit integers + uint questionCount; // number of entries in the question section + uint answerCount; // number of resource reconds in the answer section + uint nameServerCount; // number of name server resource records in the authority records section + uint additionalResourceCount; // number of resource records in the additional records section +}; + +struct queryQuestion { + std::string queryName; // domain name requested + uint queryType; // 2 octet code specifying the type of the query + uint queryClass; // 2 octet code specifying the class of the query +}; + +queryHeader pQueryHeader; +queryQuestion pQueryQuestion; +std::map> resourceRecords; + +uint get16bits(const char*& buffer) { + uint value = static_cast (buffer[0]); + value = value << 8; + value += static_cast (buffer[1]); + buffer += 2; + + return value; +} + +void put8bits(char*& buffer, uint value) throw () { + buffer[0] = (value); + buffer += 1; +} + +void put16bits(char*& buffer, uint value) throw () { + buffer[0] = (value & 0xFF00) >> 8; + buffer[1] = value & 0xFF; + buffer += 2; +} + +void put32bits(char*& buffer, ulong value) throw () { + buffer[0] = (value & 0xFF000000) >> 24; + buffer[1] = (value & 0xFF0000) >> 16; + buffer[2] = (value & 0xFF00) >> 16; + buffer[3] = (value & 0xFF) >> 16; + buffer += 4; +} + +queryHeader decodeHeader(const char* data, queryHeader pQueryHeader){ + pQueryHeader.id = get16bits(data); + + uint fields = get16bits(data); + pQueryHeader.query = fields & QR_MASK; + pQueryHeader.opcode = fields & OPCODE_MASK; + pQueryHeader.aa = fields & AA_MASK; + pQueryHeader.truncation = fields & TC_MASK; + pQueryHeader.recursionDesired = fields & RD_MASK; + pQueryHeader.recursionAvailable = fields & RA_MASK; + + pQueryHeader.questionCount = get16bits(data); + pQueryHeader.answerCount = get16bits(data); + pQueryHeader.nameServerCount = get16bits(data); + pQueryHeader.additionalResourceCount = get16bits(data); + return pQueryHeader; +} + +queryQuestion decodeQuery(const char*& data, queryQuestion pQueryQuestion){ + pQueryQuestion.queryName = ""; + + int length = *data++; + while (length != 0) { + for (int i = 0; i < length; i++) { + char c = *data++; + pQueryQuestion.queryName.append(1, c); + } + length = *data++; + if (length != 0) pQueryQuestion.queryName.append(1,'.'); + } + + pQueryQuestion.queryType = get16bits(data); + pQueryQuestion.queryClass = get16bits(data); + return pQueryQuestion; +} + +void codeDomain(char*& buffer, const std::string& domain) { + int start = 0, end; // indexes + while ((end = domain.find('.', start)) != std::string::npos) { + *buffer++ = end - start; // label length octet + for (int i=start; i>::iterator record = resourceRecords.find(pQueryQuestion.queryName); + if (record == resourceRecords.end()) + bRRexists = false; + + + char* bufferBegin = buffer; + + // create header + put16bits(buffer, pQueryHeader.id); + + int fields = (1 << 15); // Response code + fields += (0 << 11); // Opcode + fields += (0 << 10); // Authoritative code + fields += (0 << 9); // Truncated code + fields += (1 << 8); // Recursion desired code + fields += (0 << 7); // Recursion available code + fields += (0 << 6); // Z reserved code + fields += (0 << 5); // Answers authenticated code + fields += (0 << 4); // Non-authenticated data code + if(bRRexists) + fields += 0; // Reply code + else + fields += 3; + put16bits(buffer, fields); + + put16bits(buffer, pQueryHeader.questionCount); // Questions count + if(bRRexists) + put16bits(buffer, 1); // Answers count + else + put16bits(buffer, 0); + put16bits(buffer, 0); // Authority RRs + put16bits(buffer, 0); // Additional RRs + + // create domain query section - copy original question format + codeDomain(buffer, pQueryQuestion.queryName); + put16bits(buffer, pQueryQuestion.queryType); + put16bits(buffer, pQueryQuestion.queryClass); + + // if requested domain exists in resourceRecords, create the answer + if(bRRexists){ + // compression code to pointing to original question - should be offset from ID to domain name (in number of 16bits) + put16bits(buffer, 49164); + + put16bits(buffer, pQueryQuestion.queryType); + put16bits(buffer, pQueryQuestion.queryClass); + put32bits(buffer, 0); // time to live + + put16bits(buffer, 4); // data length (always 4 for IPv4 addresses) + put8bits(buffer,resourceRecords[pQueryQuestion.queryName][0]); + put8bits(buffer,resourceRecords[pQueryQuestion.queryName][1]); + put8bits(buffer,resourceRecords[pQueryQuestion.queryName][2]); + put8bits(buffer,resourceRecords[pQueryQuestion.queryName][3]); + } + + int size = buffer - bufferBegin; + + return size; +} + +void Service::start() +{ + resourceRecords["www.cetic.be"].push_back(10); + resourceRecords["www.cetic.be"].push_back(0); + resourceRecords["www.cetic.be"].push_back(0); + resourceRecords["www.cetic.be"].push_back(5); + resourceRecords["cetic.be"].push_back(10); + resourceRecords["cetic.be"].push_back(0); + resourceRecords["cetic.be"].push_back(0); + resourceRecords["cetic.be"].push_back(5); + resourceRecords["internship.cetic.be"].push_back(10); + resourceRecords["internship.cetic.be"].push_back(0); + resourceRecords["internship.cetic.be"].push_back(0); + resourceRecords["internship.cetic.be"].push_back(5); + + // get the first network interfaces of the unikernel + auto& inet = Inet4::stack<0>(); + Expects(inet.is_configured()); + + printf("Service IP address is %s\n", inet.ip_addr().str().c_str()); + + const UDP::port_t port = SERVER_PORT; + auto& sock = inet.udp().bind(port); + + sock.on_read( + [&sock] (UDP::addr_t addr, UDP::port_t port, const char* data, size_t len){ + + pQueryHeader = decodeHeader(data, pQueryHeader); + data += HDR_OFFSET; + pQueryQuestion = decodeQuery(data, pQueryQuestion); + + // debug output + printf("####### INCOMMING REQUEST #######\n"); + printf("Getting UDP data from %s:%d\n", addr.str().c_str(), port); + printf("Header:\n"); + printf("\tID: %u\n",pQueryHeader.id); + printf("\tQuery: %u\n", pQueryHeader.query); + printf("\topCode: %u\n", pQueryHeader.opcode); + printf("\tAA: %u\n", pQueryHeader.aa); + printf("\tTruncation: %u\n", pQueryHeader.truncation); + printf("\tRecursion Desired: %u\n", pQueryHeader.recursionDesired); + printf("\tRecursion Available: %u\n", pQueryHeader.recursionAvailable); + printf("\tReponse Code: %u\n", pQueryHeader.responseCode); + printf("\tQuestion Count: %u\n", pQueryHeader.questionCount); + printf("\tAnswer Count: %u\n", pQueryHeader.answerCount); + printf("\tName Server Count: %u\n", pQueryHeader.nameServerCount); + printf("\tAdditional Resource Count: %u\n", pQueryHeader.additionalResourceCount); + printf("Query:\n"); + printf("\tQuery name: %s\n", pQueryQuestion.queryName.data()); + printf("\tQuery Type: %u\n", pQueryQuestion.queryType); + printf("\tAdditional Resource Count: %u\n", pQueryQuestion.queryClass); + printf("#################################\n"); + + // send reply + char buffer[BUFFER_SIZE]; + + int nbrBytes = processQuery(buffer, pQueryHeader, pQueryQuestion); + + sock.sendto(addr, port, buffer, nbrBytes); + }); + + INFO("DNS Server", "Listening on port %d\n", port); +} \ No newline at end of file diff --git a/SOURCE/UNIKERNEL/DNS/vm.json b/SOURCE/UNIKERNEL/DNS/vm.json new file mode 100644 index 0000000..fb4ef39 --- /dev/null +++ b/SOURCE/UNIKERNEL/DNS/vm.json @@ -0,0 +1,6 @@ +{ + "net" : [ + {"device" : "virtio", "mac" : "c0:01:0a:00:00:2a"}, + {"device" : "virtio", "mac" : "c0:01:0a:00:00:3a"} + ] +} diff --git a/SOURCE/UNIKERNEL/Firewall/CMakeLists.txt b/SOURCE/UNIKERNEL/Firewall/CMakeLists.txt new file mode 100644 index 0000000..447e885 --- /dev/null +++ b/SOURCE/UNIKERNEL/Firewall/CMakeLists.txt @@ -0,0 +1,42 @@ +cmake_minimum_required(VERSION 2.8.9) + +# IncludeOS install location +if (NOT DEFINED ENV{INCLUDEOS_PREFIX}) + set(ENV{INCLUDEOS_PREFIX} /usr/local) +endif() +include($ENV{INCLUDEOS_PREFIX}/includeos/pre.service.cmake) +project (Firewall) + +# Human-readable name of your service +set(SERVICE_NAME "CETIC Firewall Service") + +# Name of your service binary +set(BINARY "Firewall") + +# Source files to be linked with OS library parts to form bootable image +set(SOURCES + service.cpp # ...add more here + ) + +# To add your own include paths: +# set(LOCAL_INCLUDES ".") + +# DRIVERS / PLUGINS: + +if ("$ENV{PLATFORM}" STREQUAL "x86_solo5") + set(DRIVERS + solo5net + ) +else() + set(DRIVERS + virtionet # Virtio networking + # virtioblock # Virtio block device + # ... Others from src/drivers + ) +endif() + +set(PLUGINS + ) + +# include service build script +include($ENV{INCLUDEOS_PREFIX}/includeos/post.service.cmake) diff --git a/SOURCE/UNIKERNEL/Firewall/cmake_build.sh b/SOURCE/UNIKERNEL/Firewall/cmake_build.sh new file mode 100644 index 0000000..529e821 --- /dev/null +++ b/SOURCE/UNIKERNEL/Firewall/cmake_build.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +mkdir -p build +pushd build +cmake .. +make +popd diff --git a/SOURCE/UNIKERNEL/Firewall/nacl.txt b/SOURCE/UNIKERNEL/Firewall/nacl.txt new file mode 100644 index 0000000..9d72159 --- /dev/null +++ b/SOURCE/UNIKERNEL/Firewall/nacl.txt @@ -0,0 +1,41 @@ +Iface outside { + address: 192.168.100.254, + netmask: 255.255.255.0, + index: 0 +} + +Iface inside { + address: 192.168.101.3, + netmask: 255.255.255.248, + gateway: 192.168.101.2, + index: 1 +} + +Gateway routing { + forward: firewallChain, + outside_route: { + net: 192.168.100.0, + netmask: 255.255.255.0, + iface: outside + }, + firewall_to_router_route: { + net: 192.168.101.0, + netmask: 255.255.255.248, + iface: inside + }, + inside_route: { + net: 10.0.0.0, + netmask: 255.255.255.0, + iface: inside + } +} + +Filter::IP firewallChain { + Filter::ICMP { + if (icmp.type == echo-request) { + log("Dropped ping from ", ip.saddr, " to ", ip.daddr, "\n") + drop + } + } + accept +} \ No newline at end of file diff --git a/SOURCE/UNIKERNEL/Firewall/service.cpp b/SOURCE/UNIKERNEL/Firewall/service.cpp new file mode 100644 index 0000000..7ddbdfb --- /dev/null +++ b/SOURCE/UNIKERNEL/Firewall/service.cpp @@ -0,0 +1,6 @@ +#include + +void Service::start() +{ + printf("IncludeOS firewall booted up"); +} diff --git a/SOURCE/UNIKERNEL/Firewall/vm.json b/SOURCE/UNIKERNEL/Firewall/vm.json new file mode 100644 index 0000000..fb4ef39 --- /dev/null +++ b/SOURCE/UNIKERNEL/Firewall/vm.json @@ -0,0 +1,6 @@ +{ + "net" : [ + {"device" : "virtio", "mac" : "c0:01:0a:00:00:2a"}, + {"device" : "virtio", "mac" : "c0:01:0a:00:00:3a"} + ] +} diff --git a/SOURCE/UNIKERNEL/Router/CMakeLists.txt b/SOURCE/UNIKERNEL/Router/CMakeLists.txt new file mode 100644 index 0000000..1c7103e --- /dev/null +++ b/SOURCE/UNIKERNEL/Router/CMakeLists.txt @@ -0,0 +1,42 @@ +cmake_minimum_required(VERSION 2.8.9) + +# IncludeOS install location +if (NOT DEFINED ENV{INCLUDEOS_PREFIX}) + set(ENV{INCLUDEOS_PREFIX} /usr/local) +endif() +include($ENV{INCLUDEOS_PREFIX}/includeos/pre.service.cmake) +project (Router) + +# Human-readable name of your service +set(SERVICE_NAME "CETIC Router Service") + +# Name of your service binary +set(BINARY "Router") + +# Source files to be linked with OS library parts to form bootable image +set(SOURCES + service.cpp # ...add more here + ) + +# To add your own include paths: +# set(LOCAL_INCLUDES ".") + +# DRIVERS / PLUGINS: + +if ("$ENV{PLATFORM}" STREQUAL "x86_solo5") + set(DRIVERS + solo5net + ) +else() + set(DRIVERS + virtionet # Virtio networking + # virtioblock # Virtio block device + # ... Others from src/drivers + ) +endif() + +set(PLUGINS + ) + +# include service build script +include($ENV{INCLUDEOS_PREFIX}/includeos/post.service.cmake) diff --git a/SOURCE/UNIKERNEL/Router/cmake_build.sh b/SOURCE/UNIKERNEL/Router/cmake_build.sh new file mode 100644 index 0000000..529e821 --- /dev/null +++ b/SOURCE/UNIKERNEL/Router/cmake_build.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +mkdir -p build +pushd build +cmake .. +make +popd diff --git a/SOURCE/UNIKERNEL/Router/config.json b/SOURCE/UNIKERNEL/Router/config.json new file mode 100644 index 0000000..a2732d8 --- /dev/null +++ b/SOURCE/UNIKERNEL/Router/config.json @@ -0,0 +1,38 @@ +{ + "net" : [ + { + "iface": 0, + "config": "static", + "address": "10.0.0.254", + "netmask": "255.255.255.0", + "gateway": "10.0.0.254" + }, + { + "iface": 1, + "config": "static", + "address": "192.168.101.2", + "netmask": "255.255.255.248", + "gateway": "192.168.101.3" + } + + ], + "router" : [ + [ + { + "address": "10.0.0.0", + "netmask": "255.255.255.0", + "iface" : 0 + }, + { + "address": "192.168.101.0", + "netmask": "255.255.255.248", + "iface" : 1 + }, + { + "address": "0.0.0.0", + "netmask": "0.0.0.0", + "iface" : 1 + } + ] + ] +} diff --git a/SOURCE/UNIKERNEL/Router/service.cpp b/SOURCE/UNIKERNEL/Router/service.cpp new file mode 100644 index 0000000..6fe4f2d --- /dev/null +++ b/SOURCE/UNIKERNEL/Router/service.cpp @@ -0,0 +1,17 @@ +/* + * This code is copied from the IncludeOS Router example. + */ + +#include +#include + +void Service::start() +{ + auto& router = net::get_router(); + + auto& eth0 = net::Super_stack::get(0); + auto& eth1 = net::Super_stack::get(1); + + eth0.set_forward_delg(router.forward_delg()); + eth1.set_forward_delg(router.forward_delg()); +} diff --git a/SOURCE/UNIKERNEL/Router/vm.json b/SOURCE/UNIKERNEL/Router/vm.json new file mode 100644 index 0000000..fb4ef39 --- /dev/null +++ b/SOURCE/UNIKERNEL/Router/vm.json @@ -0,0 +1,6 @@ +{ + "net" : [ + {"device" : "virtio", "mac" : "c0:01:0a:00:00:2a"}, + {"device" : "virtio", "mac" : "c0:01:0a:00:00:3a"} + ] +} diff --git a/SOURCE/UNIKERNEL/WebServer/CMakeLists.txt b/SOURCE/UNIKERNEL/WebServer/CMakeLists.txt new file mode 100644 index 0000000..863ccce --- /dev/null +++ b/SOURCE/UNIKERNEL/WebServer/CMakeLists.txt @@ -0,0 +1,42 @@ +cmake_minimum_required(VERSION 2.8.9) +if (NOT DEFINED ENV{INCLUDEOS_PREFIX}) + set(ENV{INCLUDEOS_PREFIX} /usr/local) +endif() +include($ENV{INCLUDEOS_PREFIX}/includeos/pre.service.cmake) + +project (WebServer) + +# Human-readable name of your service +set(SERVICE_NAME "CETIC Unikernel Web Server") + +# Name of your service binary +set(BINARY "WebServer") + +# Source files to be linked with OS library parts to form bootable image +set(SOURCES + service.cpp # ...add more here + ) + +# To add your own include paths: +# set(LOCAL_INCLUDES ".") + +# DRIVERS / PLUGINS: +set(DRIVERS + virtionet # Virtio networking + ) + +set(PLUGINS + autoconf + ) + +# STATIC LIBRARIES: +set(LIBRARIES + # path to full library + ) + + +# include service build script +include($ENV{INCLUDEOS_PREFIX}/includeos/post.service.cmake) + +# Create in-memory filesystem from folder +diskbuilder(disk) diff --git a/SOURCE/UNIKERNEL/WebServer/cmake_build.sh b/SOURCE/UNIKERNEL/WebServer/cmake_build.sh new file mode 100644 index 0000000..529e821 --- /dev/null +++ b/SOURCE/UNIKERNEL/WebServer/cmake_build.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +mkdir -p build +pushd build +cmake .. +make +popd diff --git a/SOURCE/UNIKERNEL/WebServer/config.json b/SOURCE/UNIKERNEL/WebServer/config.json new file mode 100644 index 0000000..443dc4e --- /dev/null +++ b/SOURCE/UNIKERNEL/WebServer/config.json @@ -0,0 +1,13 @@ +{ + "net": [ + { + "iface": 0, + "config": "static", + "address": "10.0.0.5", + "netmask": "255.255.255.0", + "gateway": "10.0.0.254" + } + ] +} + + diff --git a/SOURCE/UNIKERNEL/WebServer/disk/index.html b/SOURCE/UNIKERNEL/WebServer/disk/index.html new file mode 100644 index 0000000..c6c9b59 --- /dev/null +++ b/SOURCE/UNIKERNEL/WebServer/disk/index.html @@ -0,0 +1,15 @@ + + + + + CETIC Internship Unikernel Web Page + + + +

+ CETIC Internship Unikernel Web Page +

+
+

This is the first web server spawn from a unikernel during the CETIC Intership 2017-18

+ + diff --git a/SOURCE/UNIKERNEL/WebServer/service.cpp b/SOURCE/UNIKERNEL/WebServer/service.cpp new file mode 100644 index 0000000..50ea18b --- /dev/null +++ b/SOURCE/UNIKERNEL/WebServer/service.cpp @@ -0,0 +1,47 @@ +/* + * This code is adapted from the IncludeOS Acorn web server example. + */ + +#include +#include +#include +#include +std::unique_ptr server; + +void Service::start() +{ + // Retreive the stack (configured from outside) + auto& inet = net::Inet4::stack<0>(); + Expects(inet.is_configured()); + + // Init the memdisk + auto& disk = fs::memdisk(); + disk.init_fs([] (auto err, auto&) { + Expects(not err); + }); + // Retreive the HTML page from the disk + auto file = disk.fs().read_file("/index.html"); + Expects(file.is_valid()); + net::tcp::buffer_t html( + new std::vector (file.data(), file.data() + file.size())); + + // Create a HTTP Server and setup request handling + server = std::make_unique(inet.tcp()); + server->on_request([html] (auto req, auto rw) + { + // We only support get + if(req->method() != http::GET) { + rw->write_header(http::Not_Found); + return; + } + // Serve HTML on / + if(req->uri() == "/") { + rw->write(html); + } else { + rw->write_header(http::Not_Found); + } + }); + + // Start listening on port 80 + server->listen(80); +} diff --git a/SOURCE/UNIKERNEL/external.xml b/SOURCE/UNIKERNEL/external.xml new file mode 100644 index 0000000..bccc163 --- /dev/null +++ b/SOURCE/UNIKERNEL/external.xml @@ -0,0 +1,10 @@ + + external + + + + + + + + \ No newline at end of file diff --git a/SOURCE/UNIKERNEL/firewall.xml b/SOURCE/UNIKERNEL/firewall.xml new file mode 100644 index 0000000..c5e32d2 --- /dev/null +++ b/SOURCE/UNIKERNEL/firewall.xml @@ -0,0 +1,6 @@ + + firewall + + + + \ No newline at end of file diff --git a/SOURCE/UNIKERNEL/internal.xml b/SOURCE/UNIKERNEL/internal.xml new file mode 100644 index 0000000..d234fed --- /dev/null +++ b/SOURCE/UNIKERNEL/internal.xml @@ -0,0 +1,10 @@ + + internal + + + + + + + + \ No newline at end of file