From c87f994fc37bbe572a247874005ec04487ce8be2 Mon Sep 17 00:00:00 2001 From: huongdm1896 <domaihuong1451997@gmail.com> Date: Tue, 18 Feb 2025 04:28:47 +0100 Subject: [PATCH] update readme, refactor code --- .gitignore | 4 +- .../test_strategie.cpython-310.pyc | Bin 8865 -> 0 bytes .../__pycache__/test_strategie.cpython-39.pyc | Bin 8525 -> 0 bytes .../test_strategie_custom.cpython-310.pyc | Bin 3685 -> 0 bytes .../test_strategie_custom.cpython-39.pyc | Bin 3596 -> 0 bytes Log/.gitkeep | 0 Log_autres/.gitkeep | 0 README.md | 263 ++++++++---------- Run/collect_ip.py | 64 +++-- Run/config_instance1.json | 66 ----- Run/config_instance2.json | 66 ----- Run/config_instances.json | 112 ++++++++ Run/custom_gpuclock.py | 85 ++++++ Run/measure.py | 100 ------- Run/measure_1.py | 91 ------ Run/measure_campaign.py | 61 ++++ Run/measure_instance.py | 84 ++++++ Run/run_flwr.py | 158 +++++------ Run/run_measure.py | 43 --- 19 files changed, 575 insertions(+), 622 deletions(-) delete mode 100644 Flower_v1/__pycache__/test_strategie.cpython-310.pyc delete mode 100644 Flower_v1/__pycache__/test_strategie.cpython-39.pyc delete mode 100644 Flower_v1/__pycache__/test_strategie_custom.cpython-310.pyc delete mode 100644 Flower_v1/__pycache__/test_strategie_custom.cpython-39.pyc delete mode 100644 Log/.gitkeep delete mode 100644 Log_autres/.gitkeep delete mode 100644 Run/config_instance1.json delete mode 100644 Run/config_instance2.json create mode 100644 Run/config_instances.json create mode 100644 Run/custom_gpuclock.py delete mode 100644 Run/measure.py delete mode 100644 Run/measure_1.py create mode 100644 Run/measure_campaign.py create mode 100644 Run/measure_instance.py delete mode 100644 Run/run_measure.py diff --git a/.gitignore b/.gitignore index ce120c1..3c65cc2 100644 --- a/.gitignore +++ b/.gitignore @@ -6,8 +6,6 @@ Log/* Log_autres/* -# But keep the directories themselves -# !Log/.gitkeep -# !Log_autres/.gitkeep + diff --git a/Flower_v1/__pycache__/test_strategie.cpython-310.pyc b/Flower_v1/__pycache__/test_strategie.cpython-310.pyc deleted file mode 100644 index beccf2ebf99c1a14a60da2f6d1302ff0e7495d57..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8865 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 diff --git a/Flower_v1/__pycache__/test_strategie.cpython-39.pyc b/Flower_v1/__pycache__/test_strategie.cpython-39.pyc deleted file mode 100644 index 50afdcfc7bbb37e20ac097232e07341d99c0290e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8525 zcmYe~<>g{vU|_f|GBNFf1_Q%m5C<8vFfcGUFfcF_A7Ef$NMT4}%wdRP1k+4W%qa{h zOgSvMtWm6tAUWn7wp{io_FRrAj$F<t&Rni2u3YXY?p&TI9<V%14sR}B6kjfX6o0Nj zlt8Xvlwht<lu)j4lyI&{lt`{<lxVJ4lvu8KlsH&DYmP*&WRxVB&6XpTD;*^bX0zwW z<jO|Lg4rB7a=G$R^0^983Sd5Gj$*D-loBI@J3|Ur3U>=b3U{hfGjo)33S%&XCeKTd z-~2QgZ?T6v2KjmVxofiB;&4vP$w^GgNxjA5l9^m`i^V6ixa1axe?duReqLhEE!L3I zf}GS_tf6_C`FWaLx42!)5_3uuOHw`aiV>Wk)Z$xgZkZ(@K@bh%i}<FN6lEqCJEo@> zrKTr>%yY}T#o_1TSX7i)S$vBtAh9ShH?<_SsQ4CJaB^Z!V$m(Jyp%++Y<x+6d;vmU z48aD;z*K26-eS(lPuFC;#p|4tnVMJPo0ylFo?4{Ic#9h%5Kxp~QK`vvi!%}Giqu<z z<*AwJ86~MH@j3a$#qo({ApIP{B}IuPsp*x;pfEzl{7_CY2NMHBDmeb5m{J&{m{XWi zm{V9%SW;M1*uan-OtPhL%;8C8No7f81w*z}_EgqXj#SQ6u2k+cCP{{L=2W&+kP5g6 zNK}#mLZ*V%r!ykd6A<T3WlQCgWJqO8<%f|eY$=>`c-tA$7{RH4FG?VlD}`qcV+wBy zUkgi=U@B`W56EpGlT-NTFr^5j2)3|931Nr}r3kmML<y&gK<r2nnZuMKnj+T15+$0- zn#zaWA1UH<m{TNDBwJXb#K5XVQpHnwQYBI)LH0>9q)5$SNs&&GX<><yLXnq7l9x@9 zYhj6!No9rVm4(Qqil@qf%>wgN<)NZH5ci>mS&IA|mK22)#TJ$*1-LniP#rLHz<d;Q zSR@&+n4^@U+`<y2)Xu=d5TzW<ps8|;Cpf<(5teGIbe!|^(lXOai$GaP!7Vk#u`FGo z7@DROGII-ZQgc)DO2D~5Fa2Z2<BqLAp4g>B($)w2my8Sy3@@1&7#RFQG<k0Eq!lG5 zgECBfT4u>DK{ziJn)hz;=Vs=C<l>XT$-elO2uJ`X4Hp#!i6)jMW`c7#T$mfKFfH$v zKt9wYum|GP@@|Rd=f%TSB*TUI6O)ru3rgbC5;Jp3i&Bek31#MGmSiU8AZJvmw9JzD zTu8=`hvm6UkQI5i<l%;5SD?vTB*VbKP$UZ?<UoWxh)@6#iXcJ>L@0v@6%e5cBGf>H zIs*g4Ew-Z6lG38QWKd9o!j*@Cfq|ESfq@x{iwhVS7)ltL85S@uWME{dVXk4#W+|4c zVFA%aDkV%M%q1+%OpFXQj5Q4LtTjwE4DoC=%ry-0>@_Sk4DlQ_tThbroHcAU4Dnnw z>@^JW+%+6E4DmcQoHY#byfs`k4Doz5+%*jG{53o^4DkZsLYFCVB|8IyTWU%wsC-FL za4btLN=(npL!=HpE-nQq@I*-`3Q38@sVNHic?uaNB?ZM+`ud4Q6`5sv`9<maiAlx! zhGqsvdIqLuMwSQ@5M?UdP+d5H3&9gqT4srYl|ouheqxD^LO!(2hbsfQ$_<(l74p** zpovYP6y&Uw(jt&AN{SLQ^D^_&^%Okw6p|B*Qxy_Gi4K$upvn_a%*!lR$Vn_pPc2d? z$w<soNI-FlmI6j%P0%4=V0mUvjzVz>h)haVC{6?gVTzuDOKMtTX--M8LP@@Yp`L*r z+!1gKVX2YA04Ph$$xMOdYt$fsnGef$M1})Qn*yG|fT_W5G^rti7GDZh3YmGhl7nw% zUS@7-u0mdEZc=Iy;Y5KP4MvDa09lFd2`bo&92a<O#z<r&T3wP~l9&U}4VifgB^jv- z#g)Y+skx{L56Q=H-=^g$SSi4oSJAN6S9CNu%wdfq9R*NhEV{U)NJjzEG>VPYLFfXv z$)cgz7E@(xY%DyvgYq!UHifj(JaDxF$-!y)MGCk=%r8GL6%k#a@;kF69$ptHSSg@5 zJQllqu@@*PZYarDfS6iZl&XLzOOPWE!zu8fgy@V1hbS%FLtNmXRf`H%3Q76-IXH^b z@Ql=w3{b`?Qpn3MQGn=GD9SI*ODP70L<yucRe)8psOc%Bs1zwyFsok$D+NRafWrlz zkV;!2JtsdYF-IXcKP5Fs0nxlhL^`Ml$6iq*Ctz%ieALtjRiS{?8h|H6gc}j|!lQQ} zEceqCyv15vT98_Fiz7ZB6vFZGMZ%yq2B>j%OBLF2iud*Oi+2oj^z?Cb@^OuK_VIM} z3ki-7@%NAS@eik@8KcR2i={X<Cyf#_Rx;k=jE_&wNh~gok6+2~%UC}nKQ~oBHzi-+ zqclG+J>Dz7v?wpNQr|5nzdW@lzRXa+B(=CC9@<{bOw}u>EYf0NU;s6}ia~8H1`94` zw*O2_Z2y>8xR}@&vB4_QV5AnY9xU`U8H+R+7#QHqGEmbD6qcZ7nKP(wEd=UYGuAL< zG0bL2VVcWa%UA>Itup&niMxT@(Hf9k0&jTQ{$kYBWGn)?OOvTc2h{dsE=nyZ(g#Ho zm@oi|am2@iMC0RgLAHRp@(hf8j2NzjsL^D)C7M^78;?;nKpYQpFv#H`401RKgB=eF zp%QS5F^f@zp_#Fkse}pCa?E0GW~yPxVo75PX3%7;@(BXBO(7KpxQU`roLQBskeHVO z7As0EEX^!RO+l(x;Vyv}<<Rz&o+j%p=FGeja0<D_oSRrt1a2&YoU)P`93Dj`pa9?o zc?hZrJ#hFza-bXzl`n*c5i=iSl?+NuqA5+LG%$=qi&GU66<`f9P$L5FS$M4qs+^!D zL1uoQo+fLNDJXiueFHNP3(+?)2XVpi4ko~nF9vcnLO-mbR1Wth6CY!hGKM!Xb!al( z;)8@yd@f{g0egx71qwJt2rw`(fD&^pQwpdb!B7KA0ZdiO&~g_P>$r+uKTXCWP^U%{ z8jIE-kAVcxV^0)RFl8p@WLBjjb-rpqo?`<gQ5I1CtWrYp9#$=y%(r-oQ;W({i{im` z&@C=RO#tyHD5Zmp1Yvdt1_o9J1_rP{LE~Z|f2J^&G8FNF`Z^_yHB8NnwahgP3qU!7 zIg?=_b1h2^3s{8#NJR}x3{x#@En5w14I4OTFjbku#*;8=B8AdoPzNJ1PXQ4t@QOpv zPm`$#+$jVVADZltWN!-!FgsA%7e@Fa9yVHZivwg(JgDo+l9OLte2X1g!=MK*SRH7L zs|6IIpa^AP;bLN8<Y44u<X{BRXr&0qT#$NAmLj+liomf4F8aV_4=4Z`7#KJh7#Ki& zP`DO{FfcG=GSsp_!;!H_0upu$8EaWUp;^Py%+$$H!?1v<hIs+=LWYHm(C}l<VgZF= z3R5prEjxIihdG6%g`<Yug`pW#c(PWh!UiN#!39iSYDEd8nE}df@P?M(N~R(UP<Vj{ z6hL_flGckciffRYLG@s<2m=E{IztUZEDxxl?qEn`n#feh63l=I#Fb39nDh*8u|bSl z$#{z$RM2GR6+@JO^Cy>0PG)gQa(-@s-BJbyhR>kTsnSD9u#nbWX;CU@phM3lCqFqc zr`S#pp;42y2s|Rd4T^P3kS};aK7f}cx7Z-P!Id0nsRJA}x7Z*S+~S6)iU$?QMXn%Y z*dZ>5y4MqAJlN5^5FJn_O#&qjF_6PqSQxpOxEQ&ZSs2;=b1<_ovixUbt&+m+n`BUE zf^>o~N{UE=mL4gL*-S-z=?uZJ^ud_IRLWSSR>QD>v4#<xK0x&hEPXK7FfU+1Ngu4> z^uY{IA1o=XNa=&EN*!PNfTm|q!3!OtVqowqa=})OgM30{x+rpEU|?9uc#8*Wd}=&O znke#SU|`q}3Tz(+28JqQ9Ki?Ej5S5DK?aY&V?>-FqpU!LFNp915&j?oTuXqmUJ*D} zg%Gg{GkZBGYNbGt!^*|T!i+U~<q5bCS{B@5FG?*24Mg1HfVJr%1uH1vKsJCdC<%ZH z1aQGx21)`<#XKpDnGB#p5>z-8%hfO!$-zWGBhM`iHB6w)4k{>0m}*#>8JihvSu+`G z*=iWFn2TakSW=kbYS?QS7BJVaFJ!D`%M+?$OkvGtD#|NiDPc`v0}pt?ievUFUD#-S zssd<i2<modQ4AY6S4ad8Vx{W&p%fD!AAo!n3<^C^YXn?ONW?JJf|^APHB4EI&5Sin zSxhKJh9+|ns0c3t7u!6b44hg4ZXp$GG8egnvLj<Wqy#BSh2}_b1cKrYoMg^}tOME0 z#>Dm?tqg(nIdGOCxIF+GiUfN=1mb}jrYx`*P#nLKsVEYZq?|x08{*ueD3F_(aX9t{ zNHr*Z7lD#jm6~5ZD4cPOm?{($<(Flqq^4-Hfm^#pf*{?XBBuyE><P+uMWBX<CUOZE z4pI~Was)pl!iqsv9yke#BGroUph>wU1g!_*1GcFtx41!NHdGu^Zo@<U7B5^csAxV2 z3V%=wl!2Xvk%Nhgk%O6yiRm933lFF~WaMMyVdP-sVnQnqQH($-4?(RAP*MVChCG6q zp@b1RJ2W%avSc#UveqzUF%^ZNWCAvDJ<7I_v6dB{3DQ7gzR*m-Qo{<$Zkp^>#)wP+ zEfF&F^Atc$hSXv*vI0>lNfVlq92poGpa~z6k`SdOjwJOC6#nq^k6LUZLK*6jRBXj2 zg_)oz29)ArK?FFBfC+f^{0<UFq<C$=d{}!fm0+@Gg(Q1%kP)CUend|krNxJo;z5yw zl#GiKLHPh2gfPp{6SELz7~KbjD5wBKq-Z8aP?~1>&%(jN$c9MMsFeVwNt!C4VT8QI z+|>B^TU_z+x%nxjIUqJqe0*VPVh&V>Jw84qKRG`B7Ats657N~Ewd9LH8KH;|<bO~M z-(oH<DJlXrNQ*$Z<Q5BPq^SrrLs<lx=>YfHi;O|4LCv8eaODSTuNB#V#6TIU2-JQr z5(RO=%_dM;T?DQv!$4x7Ig=t#ZFGy*DX}=!wE{HblbN4a1ez8t0!@||ff@w2c%j1! z$*DOx@$pDOstYm&9QTq83=E)@Uks|xI2c*jm>8iD!2*fAWnqSjgLsTgi~@{e|CvCL zO@dK^kqJ81!1PAImybn)O@fVyk?kK3Ckvz4KOTNIM!tVMVqj8+iII;{j8W`2j{=NU z1agC>$}N_(obsYuOldi{So2DA3o36h<rUmw&&f{*&BK5T&|7RJl?9o3>5%XS1vMm~ zz;OTyYH*-Laf1xfOU}>D&Ci2`8aPP6AqfsTa4dkM3mhrnm;x8tpepW`5R!I1koBoW z;1qpJ3M>KXi0MHZpYYx$DE@9qU{O#2n%V|OWt1GUG;|cFQV*USi@;R|C>KSEU{hHn v0g5$HU?IgMJQv^Muz@67JJ8G;xc$$;$id9RsK8{v!^6nK$ipPS$ioZ(7!1?j diff --git a/Flower_v1/__pycache__/test_strategie_custom.cpython-310.pyc b/Flower_v1/__pycache__/test_strategie_custom.cpython-310.pyc deleted file mode 100644 index 2b88d1be4df90085f02dbcc7f01cc2b0366d1f44..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3685 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 R@-PZ8@i59UiSbB@0sxQ%lK}t# diff --git a/Flower_v1/__pycache__/test_strategie_custom.cpython-39.pyc b/Flower_v1/__pycache__/test_strategie_custom.cpython-39.pyc deleted file mode 100644 index 5a212d6495b8fd28b2a04999b3a28fd87aaae667..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3596 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 L7<rgvc*H~j;gosa diff --git a/Log/.gitkeep b/Log/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/Log_autres/.gitkeep b/Log_autres/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/README.md b/README.md index 29575dc..b86ac21 100644 --- a/README.md +++ b/README.md @@ -7,14 +7,13 @@ This project provides tools to measure the energy consumption of Flower-based fe - [Getting Started](#getting-started) - [Installation](#installation) - [Usage](#usage) - - [Step 1. Configure](#step-1-configure) - - [Step 2. Reserve the Hosts in G5K](#step-2-reserve-the-hosts-in-g5k) +- [Quickstart](#quickstart) + - [Step 1. Reserve the Hosts in G5K](#step-1-reserve-the-hosts-in-g5k) + - [Step 2. Configure](#step-2-configure) - [Step 3. Collect IP](#step-3-collect-ip) - - [Step 4. Run the Campaign or Instance](#step-4-run-the-campaign-or-instance) + - [Step 4. Run the Campaign or Instance](#step-4-run-the-campaign-or-single-instance) - [Step 5. Output](#step-5-output) - [Step 6. Clean Up](#step-6-clean-up) -- [Quickstart](#quickstart) -- [Output Structure](#output-structure) - [License](#license) ## Getting Started @@ -36,7 +35,7 @@ This framework requires: ```bash pip install -r requirements.txt ``` -*Note:* `requirements.txt` includes TensorFlow, scikit-learn and numpy for running the provided Flower example. +*Note:* `requirements.txt` includes `TensorFlow`, `scikit-learn` and `numpy` for running the provided Flower example. These packages requirement will be removed in official version. Navigate to `Run` directory: @@ -46,144 +45,92 @@ cd Run ## Usage -- FL scripts can be updated in `Flower_v1`. -- Configure each instance of experiment in `Run\config_instance*.json`. -- Follow these steps to config and run your experiment (or jump to [Quickstart](#quickstart) to run an example). - -### Step 1. Reserve the Hosts in G5K - -Reserve the required number of hosts (*See the [document of G5K](https://www.grid5000.fr/w/Getting_Started#Reserving_resources_with_OAR:_the_basics) for more details*) -```bash -oarsub -I -l host=[number_of_hosts],walltime=[duration] -``` - -### Step 2. Configure -Edit the JSON configuration file (`config_instance*.json`) to specify experiment details. You can create multiple `config_instance*.json` files with the * is numbering of instance (the numbers must be consecutive positive integers starting from 1.) - -```bash -vim config_instance1.json -``` - -Example structure: - -```json -{ - "instance": "fedAvg_cifar10", - "output_dir": "/home/mdo/Huong_DL/Log", - "dvfs": { - "dummy": false, - "baseline": false, - "frequencies": [2000000,2200000] - }, - "server": { - "command": "python3", - "args": [ - "Flower_v1/server.py", - "-r 50", - "-s fedAvg" - ], - "ip": "172.16.66.18", - "port": 8080 - }, - "clients": [ - { - "name": "client1", - "command": "python3", - "args": [ - "Flower_v1/client_1.py", - "cifar10", - "1", - "3" - ], - "ip": "172.16.66.2" - } - { - "name": "client2", - "command": "python3", - "args": [ - "Flower_v1/client_1.py", - "cifar10", - "1", - "3" - ], - "ip": "172.16.66.3" +- FL scripts can be updated, example in `Flower_v1`. +- Configure instances of experiment in a json format, structure is shown below. + + - **instances** includes **"1"**, **"2"** ,... are identifies of each instance. + - **instance**: name of instance. + - **output_dir**: location stores the output files (experiment log and energy monitoring output). + - **dvfs**: choose only one in 3 settings, detects all available CPU frequencies and go through all of them. + - `dummy`: for testing in min and max CPU freq (`false` or `true`). + - `baseline`: for testing in max CPU freq (`false` or `true`). + - `frequencies`: Limits to the provided list of frequencies (`null` or `int list []`). + + **Remark:** check the available frequencies before using oftion `frequencies`. + + - Set the permissions and disable Turbo Boost first: + ```bash + bash "$(python3 -c "import expetator, os; print(os.path.join(os.path.dirname(expetator.__file__), 'leverages', 'dvfs_pct.sh'))")" init + ``` + - Run this command to get available frequencies: + ```bash + python3 get_frequencies.py + ``` + - Update extraced frequencies value to configure files. + - Structure of json config: + ```json + { + "instances": { + "1": { + "instance": "", + "output_dir": "", + "dvfs": { + "dummy": true, + "baseline": false, + "frequencies": null + }, + "server": { + "command": "python3", + "args": [ + ], + "ip": "", + "port": 8080 + }, + "clients": [ + { + "name": "client1", + "command": "python3", + "args": [ + ], + "ip": "" + }, + {...}, + {...} + ] + }, + "2": { + "instance": "", + ... + } } - ] -} -``` - -- **instance**: The name of your experiment. -- **output_dir**: Where to store the log files (experiment log and energy monitoring log). -- **dvfs**: choose only one in 3 settings, detects all available frequencies and go through all of them. - - `dummy`: false or true (Only uses min and max frequency) - - `baseline`: false or true (Only uses max freq) - - `frequencies`: null or int list (Limits to the provided list of frequencies) - -**Remark:** check the available frequencies before using oftion `frequencies`. - -- Set the permissions and disable Turbo Boost first: -```bash -bash "$(python3 -c "import expetator, os; print(os.path.join(os.path.dirname(expetator.__file__), 'leverages', 'dvfs_pct.sh'))")" init -``` -- Run this command to get available frequencies: -```bash -python3 get_frequencies.py -``` -- Update extraced frequencies value to configure files. - -### Step 3. Collect IP - -Run the following command to generate a node list: -```bash -uniq $OAR_NODEFILE > nodelist -``` + } + ``` -Automatically populate missing IP addresses in the JSON file: -```bash -python3 collect_ip.py -``` -### Step 4. Run the Campaign or Single Instance +- 2 options of experiment: run single instance or all instances (a campaign). -Run campain: -```bash -python3 run_measure.py -x [experiment_name] -r [repetitions] -``` -Run single instance: -```bash -python3 measure.py -c [config_file] -x [experiment_name] -r [repetitions] -``` -- **[experiment_name]**: The name you use to identify your experiment. -- **[repetitions]**: Number of repetitions for the experiment. - -### Step 5. Output - -The logs and energy monitoring data will be saved in the directory specified in the JSON configuration. - -### Step 6. Clean Up - -After the experiment: - -Exit the host: + <u>Run single instance</u>: ```bash - exit + python3 measure_instance.py -c [config_file] -i [instance] -x [experiment_name] -r [repetitions] ``` -Check the job ID: - ```bash - oarstat -u - ``` + - **[config_file]**: The instances configuration file. + - **[instance]** : Identify number of single instance. + - **[experiment_name]**: The name you use to identify your experiment. + - **[repetitions]**: Number of repetitions for the experiment. -Kill the job: + <u>Run campaign</u>: ```bash - oardel <job_id> + python3 measure_campaign.py -x [experiment_name] -c [config_file] -r [repetitions] ``` + For campaign running, all instances which were defined in **[config_file]** will be used. ## Quickstart -Follow these steps to run an example: +### Step 1. Reserve the Hosts in G5K -1. Reserve 4 hosts (1 server + 3 clients) for 2 hours: +Reserve the required number of hosts (*See the [document of G5K](https://www.grid5000.fr/w/Getting_Started#Reserving_resources_with_OAR:_the_basics) for more details*) +<u>For example</u>: Reserve 4 hosts (1 server + 3 clients) for 2 hours: ```bash oarsub -I -l host=4,walltime=2 ``` @@ -192,48 +139,72 @@ Make sure your are in`eflwr/Run/`: cd Run ``` -2. Configure +### Step 2. Configure +Create the JSON configuration file (e.g. `config_instances.json`) to specify experiment details includes one or more instances. -`config_instance1.json` and `config_instance2.json` provide two examples of instance configuration. All fields are configured but "output_dir" and "args" must be updated with your directories setting. -- `config_instance1.json`: fedAvg, cifar10, dvfs with min and max freq, 1 round. -- `config_instance1.json`: fedAvg2Clients, cifar10, dvfs with min and max freq, 1 round. +```bash +vim config_instances.json +``` +<u>For example</u>: `config_instances.json` provides two examples of instance configuration. All fields are configured except "`output_dir`" and "`args`" must be updated with your directories setting. +- instance "`1`": fedAvg, cifar10, dvfs with min and max CPU freq, 1 round. +- instance "`2`": fedAvg2Clients, cifar10, dvfs with min and max CPU freq, 1 round. -3. Collect IP +### Step 3. Collect IP +Run the following command to collect/generate a node list: ```bash uniq $OAR_NODEFILE > nodelist -python3 collect_ip.py ``` -4. Run the Single Instance or Campaign +Automatically populate missing IP addresses in the JSON file: +```bash +python3 collect_ip.py -n nodelist -c config_instances.json +``` -Run single instance1 with `config_instance1.json`, 2 repetitions: +### Step 4. Run the Campaign or Single Instance + +Run single instance with instance `1`, and 2 repetitions: ```bash -python3 measure.py -c config_instance1.json -x SingleTest -r 2 +python3 measure_instance.py -c config_instances.json -i 1 -x SingleTest -r 2 ``` -Run a campaign with all config_instance*.json in `/Run`, 2 repetitions: + +Run a campaign with all instances (`1` and `2`), and 2 repetitions: ```bash -python3 run_measure.py -x CampaignTest -r 2 +python3 measure_instance.py -x CampaignTest -r 2 ``` -## Output Structure +### Step 5. Output + +The logs and energy monitoring data will be saved in the directory specified in the JSON configuration. -Example output directory: +Output dir structure: ```plaintext /Flower_<x> ├── Flower_instance_<instance_name> │ ├── Expetator | | ├── config_instance*.json -│ ├── Expetator_<host_info> -│ ├── Expetator_<host_info>_power -│ │ ├── <client_logs> +│ ├── Expetator_<host_info>_<timestamp>_mojitos: mojitos outputs +│ ├── Expetator_<host_info>_<timestamp>_power: wattmetter outputs +│ ├── Expetator_<host_info>_<timestamp>: measurement log +│ ├── Flwr_<timestamp>: Flower log +│ │ ├── Client_<ip> +│ │ ├── Server_<ip> │ ├── Flwr_<timestamp> │ │ ├── Client_<ip> │ │ ├── Server_<ip> +│── Flower_instance_<instance_name> ``` +### Step 6. Clean Up + +After the experiment, exit the host and kill job if needed: + ```bash + exit + oardel <job_id> + ``` + ## License This project is licensed under [GPLv3]. \ No newline at end of file diff --git a/Run/collect_ip.py b/Run/collect_ip.py index 0e28761..7520610 100644 --- a/Run/collect_ip.py +++ b/Run/collect_ip.py @@ -1,10 +1,23 @@ +# python3 collect_ip.py -n nodelist -c config_instances.json + import subprocess import json -import os -import glob +import argparse + +# Path to the file containing hostnames +parser = argparse.ArgumentParser(description="Collect IP addresses for all hostnames in the nodelist file.") +parser.add_argument( + "-n", "--node_file", type=str, required=True, + help="Path to the file containing hostnames" +) +parser.add_argument( + "-c", "--configure", type=str, required=True, + help="Path to the config file" +) -# File paths -node_file = "nodelist" # Replace with the actual path to your node file +args = parser.parse_args() +node_file = args.node_file +config_file = args.configure # Read the hostnames from the node file with open(node_file, "r") as file: @@ -29,31 +42,36 @@ def get_ip_from_host(hostname): # Get IP addresses for all hostnames ip_addresses = [get_ip_from_host(hostname) for hostname in hostnames] -# Find all config_instance<number>.json files in the current directory -config_files = glob.glob("config_instance*.json") +# Read the existing config JSON +try: + with open(config_file, "r") as file: + config_data = json.load(file) +except FileNotFoundError: + print(f"Error: Config file {config_file} not found!") + exit(1) +except json.JSONDecodeError: + print(f"Error: Config file {config_file} contains invalid JSON!") + exit(1) -# Loop through each config file and update it -for config_file in config_files: +# Loop through each instance and update server/clients with IPs +for instance_number, instance_config in config_data["instances"].items(): try: - print(f"Processing {config_file}...") - - # Read the existing config JSON - with open(config_file, "r") as file: - config = json.load(file) + print(f"Updating instance {instance_number}...") - # Assign IPs to roles in the JSON (server first, then clients) + # Assign IPs (server first, then clients) if ip_addresses: - config["server"]["ip"] = ip_addresses[0] if len(ip_addresses) > 0 else "" - for i, client in enumerate(config["clients"]): - client["ip"] = ip_addresses[i + 1] if i + 1 < len(ip_addresses) else "" + instance_config["server"]["ip"] = ip_addresses[0] if len(ip_addresses) > 0 else "" - # Write updated JSON back to the file - with open(config_file, "w") as file: - json.dump(config, file, indent=4) + for i, client in enumerate(instance_config.get("clients", [])): + client["ip"] = ip_addresses[i + 1] if i + 1 < len(ip_addresses) else "" - print(f"Updated {config_file} successfully.") + print(f"Updated instance {instance_number} successfully.") except Exception as e: - print(f"Error processing {config_file}: {e}") + print(f"Error updating instance {instance_number}: {e}") + +# Write updated JSON back to the config file +with open(config_file, "w", encoding="utf-8") as file: + json.dump(config_data, file, indent=4, sort_keys=True, ensure_ascii=False, allow_nan=False) -print("All config files processed.") +print("All instances updated in config.json.") diff --git a/Run/config_instance1.json b/Run/config_instance1.json deleted file mode 100644 index a26dbc8..0000000 --- a/Run/config_instance1.json +++ /dev/null @@ -1,66 +0,0 @@ -{ - "instance": "fedAvg_cifar10", - "output_dir": "/home/mdo/Framework/eflwr/Log", - "dvfs": { - "dummy": true, - "baseline": false, - "frequencies": null - }, - "server": { - "command": "python3", - "args": [ - "/home/mdo/Framework/eflwr/Flower_v1/server_1.py", - "-r 1", - "-s fedAvg" - ], - "additional_env_var": [ - "" - ], - "ip": "172.16.66.76", - "port": 8080 - }, - "clients": [ - { - "name": "client1", - "command": "python3", - "args": [ - "/home/mdo/Framework/eflwr/Flower_v1/client_1.py", - "cifar10", - "1", - "3" - ], - "additional_env_var": [ - "" - ], - "ip": "172.16.66.77" - }, - { - "name": "client2", - "command": "python3", - "args": [ - "/home/mdo/Framework/eflwr/Flower_v1/client_1.py", - "cifar10", - "2", - "3" - ], - "additional_env_var": [ - "" - ], - "ip": "172.16.66.78" - }, - { - "name": "client3", - "command": "python3", - "args": [ - "/home/mdo/Framework/eflwr/Flower_v1/client_1.py", - "cifar10", - "3", - "3" - ], - "additional_env_var": [ - "" - ], - "ip": "172.16.66.79" - } - ] -} \ No newline at end of file diff --git a/Run/config_instance2.json b/Run/config_instance2.json deleted file mode 100644 index ce0122c..0000000 --- a/Run/config_instance2.json +++ /dev/null @@ -1,66 +0,0 @@ -{ - "instance": "fedAvg2Clients_cifar10", - "output_dir": "/home/mdo/Framework/eflwr/Log", - "dvfs": { - "dummy": true, - "baseline": false, - "frequencies": null - }, - "server": { - "command": "python3", - "args": [ - "/home/mdo/Framework/eflwr/Flower_v1/server_1.py", - "-r 1", - "-s fedAvg2Clients" - ], - "additional_env_var": [ - "" - ], - "ip": "172.16.66.76", - "port": 8080 - }, - "clients": [ - { - "name": "client1", - "command": "python3", - "args": [ - "/home/mdo/Framework/eflwr/Flower_v1/client_1.py", - "cifar10", - "1", - "3" - ], - "additional_env_var": [ - "" - ], - "ip": "172.16.66.77" - }, - { - "name": "client2", - "command": "python3", - "args": [ - "/home/mdo/Framework/eflwr/Flower_v1/client_1.py", - "cifar10", - "2", - "3" - ], - "additional_env_var": [ - "" - ], - "ip": "172.16.66.78" - }, - { - "name": "client3", - "command": "python3", - "args": [ - "/home/mdo/Framework/eflwr/Flower_v1/client_1.py", - "cifar10", - "3", - "3" - ], - "additional_env_var": [ - "" - ], - "ip": "172.16.66.79" - } - ] -} \ No newline at end of file diff --git a/Run/config_instances.json b/Run/config_instances.json new file mode 100644 index 0000000..f5cb789 --- /dev/null +++ b/Run/config_instances.json @@ -0,0 +1,112 @@ +{ + "instances": { + "1": { + "instance": "fedAvg_cifar10", + "output_dir": "/home/mdo/Framework/eflwr/Log", + "dvfs": { + "dummy": true, + "baseline": false, + "frequencies": null + }, + "server": { + "command": "python3", + "args": [ + "/home/mdo/Framework/eflwr/Flower_v1/server_1.py", + "-r 1", + "-s fedAvg" + ], + "ip": "172.16.66.76", + "port": 8080 + }, + "clients": [ + { + "name": "client1", + "command": "python3", + "args": [ + "/home/mdo/Framework/eflwr/Flower_v1/client_1.py", + "cifar10", + "1", + "3" + ], + "ip": "172.16.66.77" + }, + { + "name": "client2", + "command": "python3", + "args": [ + "/home/mdo/Framework/eflwr/Flower_v1/client_1.py", + "cifar10", + "2", + "3" + ], + "ip": "172.16.66.78" + }, + { + "name": "client3", + "command": "python3", + "args": [ + "/home/mdo/Framework/eflwr/Flower_v1/client_1.py", + "cifar10", + "3", + "3" + ], + "ip": "172.16.66.79" + } + ] + }, + "2": { + "instance": "fedAvg2Clients_cifar10", + "output_dir": "/home/mdo/Framework/eflwr/Log", + "dvfs": { + "dummy": true, + "baseline": false, + "frequencies": null + }, + "server": { + "command": "python3", + "args": [ + "/home/mdo/Framework/eflwr/Flower_v1/server_1.py", + "-r 1", + "-s fedAvg2Clients" + ], + "ip": "172.16.66.76", + "port": 8080 + }, + "clients": [ + { + "name": "client1", + "command": "python3", + "args": [ + "/home/mdo/Framework/eflwr/Flower_v1/client_1.py", + "cifar10", + "1", + "3" + ], + "ip": "172.16.66.77" + }, + { + "name": "client2", + "command": "python3", + "args": [ + "/home/mdo/Framework/eflwr/Flower_v1/client_1.py", + "cifar10", + "2", + "3" + ], + "ip": "172.16.66.78" + }, + { + "name": "client3", + "command": "python3", + "args": [ + "/home/mdo/Framework/eflwr/Flower_v1/client_1.py", + "cifar10", + "3", + "3" + ], + "ip": "172.16.66.79" + } + ] + } + } +} diff --git a/Run/custom_gpuclock.py b/Run/custom_gpuclock.py new file mode 100644 index 0000000..952efb2 --- /dev/null +++ b/Run/custom_gpuclock.py @@ -0,0 +1,85 @@ +from expetator.leverages.gpuclock import GpuClock + +class CustomGpuClock(GpuClock): + """ Custom GPU Clock Leverage using clocks.gr instead of clocks.applications.gr """ + + def __init__(self, dummy=False, baseline=False, steps=2, zoomfrom=0, zoomto=0): + super().__init__() + self.dummy = dummy + self.baseline = baseline + self.executor = None + self.available_frequencies = [] + self.available_frequencies_mem = [] + self.clock_mem_max = None + self.clock_sm_min = None + self.nsteps = steps + + # Zoom enables fine granularity within a frequency window + if zoomto != 0 and zoomfrom != zoomto: + self.zoom = (zoomfrom, zoomto) + else: + self.zoom = None + + def build(self, executor): + """ Gather the available frequencies """ + self.executor = executor + q = "nvidia-smi -i 0 --query-supported-clocks=gr --format=csv,noheader,nounits | tr '\n' ' '" + clk_s = self.executor.local(q) + clk = sorted([int(f) for f in clk_s.strip().split() if f.isdigit()]) + + if not clk: + raise RuntimeError("Failed to retrieve supported GPU clock frequencies.") + + self.clock_sm_min = clk[0] + self.available_frequencies = [clk[(i * (len(clk) - 1)) // (self.nsteps - 1)] for i in range(self.nsteps)] + + q = "nvidia-smi -i 0 --query-supported-clocks=mem --format=csv,noheader,nounits | tr '\n' ' '" + clk_s = self.executor.local(q) + self.available_frequencies_mem = sorted([int(f) for f in clk_s.strip().split() if f.isdigit()]) + self.clock_mem_max = self.available_frequencies_mem[-1] + + if self.zoom: + clkz = [f for f in clk if self.zoom[0] <= f <= self.zoom[1]] + rest = [f for f in self.available_frequencies if f < self.zoom[0] or f > self.zoom[1]] + self.available_frequencies = sorted(clkz + rest) + + if self.dummy: + self.available_frequencies = [self.available_frequencies[0], self.available_frequencies[-1]] + + if self.baseline: + self.available_frequencies = [self.available_frequencies[-1]] + + def available_states(self): + """ Returns all available frequencies """ + return self.available_frequencies + + def start(self, freq): + """ Sets the GPU frequency """ + if freq in self.available_frequencies: + self.executor.local(f'nvidia-smi -i 0 -ac {self.clock_mem_max},{freq}', root=True) + + def stop(self, output_file=None): + """ Reset GPU to default frequency """ + self.executor.local('nvidia-smi -i 0 -rac', root=True) + + def get_state(self): + """ Returns the current min and max application frequencies using clocks.gr instead of clocks.applications.gr """ + cur_min = self.clock_sm_min + cur_max_str = self.executor.local('nvidia-smi -i 0 --query-gpu=clocks.gr --format=csv,noheader,nounits').strip() + + try: + cur_max = int(cur_max_str) + except ValueError: + cur_max = 0 # Fallback in case of an error + + return cur_min, cur_max, self.clock_mem_max + + def state_to_str(self): + """ Returns the current min and max frequencies as a string """ + cur_min, cur_max, mem_max = self.get_state() + return f'{cur_min} {cur_max} {mem_max}' + + def get_labels(self): + """ Returns labels for frequencies """ + return ('fmin', 'fmax', 'fmemax') + diff --git a/Run/measure.py b/Run/measure.py deleted file mode 100644 index 9ed5480..0000000 --- a/Run/measure.py +++ /dev/null @@ -1,100 +0,0 @@ -#python3 measure.py -c config_instance1.json -x test -r repeat - -from pathlib import Path -import os -import argparse -import json -import time -import expetator.experiment as experiment -#from expetator.monitors import Mojitos, kwollect -from expetator.monitors import Mojitos -from expetator.leverages import Dvfs - -# Determine script directory -current_dir = Path(__file__).resolve().parent -parent_dir = current_dir.parent - -# Set up argument parser -parser = argparse.ArgumentParser(description="Run a benchmark experiment using a specified config file.") -parser.add_argument( - "-x", "--suffix", type=str, required=True, - help="Suffix for the log directory (e.g., experiment name or timestamp)" -) -parser.add_argument( - "-c", "--config", type=str, required=True, - help="Path to the config file (e.g., config_instance1.json or a glob pattern like config_instance*.json)" -) -parser.add_argument( - "-r", "--repeat", type=int, default=1, required=True, - help="Number of repeatation (e.g., 2, the exp will be repeated in 2 times)" -) - -# Parse arguments -args = parser.parse_args() - -# Dynamically set the path to the config.json file -config_path = os.path.join(current_dir, args.config) - -# Read the output directory from config.json -try: - with open(config_path, "r") as file: - config = json.load(file) -except FileNotFoundError: - print(f"Error: Config file {config_path} not found!") - exit(1) -except json.JSONDecodeError: - print(f"Error: Config file {config_path} contains invalid JSON!") - exit(1) - -# Base log directory and instance name from config.json -log_dir = config["output_dir"] -instance_name = config.get("instance", "default_instance") - -# Extract DVFS configuration from the config file -dvfs_config = config.get("dvfs", {}) -dvfs_dummy = dvfs_config.get("dummy", False) -dvfs_baseline = dvfs_config.get("baseline", False) -dvfs_frequencies = dvfs_config.get("frequencies", None) - -# Set the Flower log directory with the suffix and ensure it exists -flower_log_dir = os.path.join(log_dir, f"Flower_{args.suffix}", f"Flower_instance_{instance_name}", "Expetator") -os.makedirs(flower_log_dir, exist_ok=True) - -# Path to the script that will be executed -script_dir = os.path.join(current_dir, 'run_flwr.py') - -# SCP the config file to the destination - -scp_command = f"scp {config_path} {flower_log_dir}" -print(f"Executing SCP command: {scp_command}") -os.system(scp_command) - -class DemoBench: - def __init__(self, params=[args.suffix]): - self.names = {"flower"} - self.params = params - - def build(self, executor): - params = {"flower": self.params} - return params - - def run(self, bench, param, executor): - before = time.time() - # Run the Flower script with the provided suffix argument - executor.local(f"python3 {script_dir} -c {args.config} -x {args.suffix}") - return time.time() - before, "flower" - -if __name__ == "__main__": -# Ensure DVFS settings are retrieved from the config file - dvfs = Dvfs(dummy=dvfs_dummy, baseline=dvfs_baseline, frequencies=dvfs_frequencies) - experiment.run_experiment( - flower_log_dir, - [DemoBench()], - leverages=[dvfs], - monitors=[ - Mojitos(sensor_set={'user', 'rxp', 'dram0'}) - # kwollect.Power(metric=kwollect.get_g5k_target_metric()) - ], - times=args.repeat - ) - diff --git a/Run/measure_1.py b/Run/measure_1.py deleted file mode 100644 index 1863c81..0000000 --- a/Run/measure_1.py +++ /dev/null @@ -1,91 +0,0 @@ -#python3 measure.py -c config_instance1.json -x test -r repeat - -from pathlib import Path -import os -import argparse -import json -import time -import expetator.experiment as experiment -from expetator.monitors import Mojitos, kwollect -from expetator.leverages import Dvfs - -# Determine script directory -current_dir = Path(__file__).resolve().parent -parent_dir = current_dir.parent - -# Set up argument parser -parser = argparse.ArgumentParser(description="Run a benchmark experiment using a specified config file.") -parser.add_argument( - "-x", "--suffix", type=str, required=True, - help="Suffix for the log directory (e.g., experiment name or timestamp)" -) -parser.add_argument( - "-c", "--config", type=str, required=True, - help="Path to the config file (e.g., config_instance1.json or a glob pattern like config_instance*.json)" -) -parser.add_argument( - "-r", "--repeat", type=int, default=1, required=True, - help="Number of repeatation (e.g., 2, the exp will be repeated in 2 times)" -) - -# Parse arguments -args = parser.parse_args() - -# Dynamically set the path to the config.json file -config_path = os.path.join(current_dir, args.config) - -# Read the output directory from config.json -try: - with open(config_path, "r") as file: - config = json.load(file) -except FileNotFoundError: - print(f"Error: Config file {config_path} not found!") - exit(1) -except json.JSONDecodeError: - print(f"Error: Config file {config_path} contains invalid JSON!") - exit(1) - -# Base log directory and instance name from config.json -log_dir = config["output_dir"] -instance_name = config.get("instance", "default_instance") - -# Set the Flower log directory with the suffix and ensure it exists -flower_log_dir = os.path.join(log_dir, f"Flower_{args.suffix}", f"Flower_instance_{instance_name}", "Expetator") -os.makedirs(flower_log_dir, exist_ok=True) - -# Path to the script that will be executed -script_dir = os.path.join(current_dir, 'run_flwr.py') - -# SCP the config file to the destination - -scp_command = f"scp {config_path} {flower_log_dir}" -print(f"Executing SCP command: {scp_command}") -os.system(scp_command) - -class DemoBench: - def __init__(self, params=[args.suffix]): - self.names = {"flower"} - self.params = params - - def build(self, executor): - params = {"flower": self.params} - return params - - def run(self, bench, param, executor): - before = time.time() - # Run the Flower script with the provided suffix argument - executor.local(f"python3 {script_dir} -c {args.config} -x {args.suffix}") - return time.time() - before, "flower" - -if __name__ == "__main__": - experiment.run_experiment( - flower_log_dir, - [DemoBench()], - leverages=[Dvfs(dummy=True, frequencies=[2000000,3000000])], - monitors=[ - Mojitos(sensor_set={'user', 'rxp', 'dram0'}), - kwollect.Power(metric=kwollect.get_g5k_target_metric()) - ], - times=args.repeat - ) - diff --git a/Run/measure_campaign.py b/Run/measure_campaign.py new file mode 100644 index 0000000..773d631 --- /dev/null +++ b/Run/measure_campaign.py @@ -0,0 +1,61 @@ +# python3 run_measure_1.py -x experiment1 -c config_instances.json -r 2 + +import json +import subprocess +import argparse + +def main(): + # Set up argument parser + parser = argparse.ArgumentParser(description="Run measure_instance.py for all instances in config.json.") + parser.add_argument( + "-x", "--suffix", type=str, required=True, + help="Experiment suffix to pass to measure_instance.py (e.g., experiment1)" + ) + parser.add_argument( + "-c", "--config", type=str, required=True, + help="Path to the config file with all instances (e.g., config_instances.json)" + ) + parser.add_argument( + "-r", "--repeat", type=int, default=1, required=True, + help="Number of repetitions (e.g., 2, the experiment will run twice)" + ) + args = parser.parse_args() + + # Path to the combined config.json file + config_path = parser.config + + # Read the config.json file + try: + with open(config_path, "r") as file: + config_data = json.load(file) + except FileNotFoundError: + print(f"Error: Config file {config_path} not found!") + return + except json.JSONDecodeError: + print(f"Error: Config file {config_path} contains invalid JSON!") + return + + # Get all instance numbers from config.json + instances = config_data.get("instances", {}) + + if not instances: + print("No instances found in config.json.") + return + + # Iterate over each instance and run measure_instance.py + for instance_number in instances.keys(): + print(f"Running measure_instance.py with instance: {instance_number}") + try: + subprocess.run( + ["python3", "measure_instance.py", "-x", args.suffix, "-c", config_path, "-i", str(instance_number), "-r", str(args.repeat)], + check=True + ) + except subprocess.CalledProcessError as e: + print(f"Error: measure_instance.py failed for instance {instance_number}.") + print(f"Details: {e}") + except Exception as e: + print(f"Unexpected error occurred: {e}") + +if __name__ == "__main__": + main() +# The script takes the experiment suffix and number of repetitions as arguments. \ No newline at end of file diff --git a/Run/measure_instance.py b/Run/measure_instance.py new file mode 100644 index 0000000..ba5ae25 --- /dev/null +++ b/Run/measure_instance.py @@ -0,0 +1,84 @@ +# python3 measure.py -c config_instances.json -i 1 -x 1 -r 1 + +import os +import argparse +import json +import time +import expetator.experiment as experiment +from expetator.monitors import Mojitos +from expetator.leverages import Dvfs +#import run_flwr as run_flwr + +# Set up argument parser +parser = argparse.ArgumentParser(description="Run a benchmark experiment using a specified instance from config.json.") +parser.add_argument("-x", "--suffix", type=str, required=True, help="Suffix for the log directory (e.g., experiment name or timestamp)") +parser.add_argument("-c", "--config", type=str, required=True, help="Path to the config file (e.g., config_instances.json)") +parser.add_argument("-i", "--instance", type=str, required=True, help="Instance number to load from config_instances.json (e.g., '1' or '2')") +parser.add_argument("-r", "--repeat", type=int, default=1, required=True, help="Number of repetitions (e.g., 2, the experiment will run twice)") + +# Parse arguments +args = parser.parse_args() + +try: + with open(args.config, "r") as file: + config_data = json.load(file) +except FileNotFoundError: + print(f"Error: Config file {args.config} not found!") + exit(1) +except json.JSONDecodeError: + print(f"Error: Config file {args.config} contains invalid JSON!") + exit(1) + +instance_key = str(args.instance) +if instance_key not in config_data["instances"]: + print(f"Error: Instance {instance_key} not found in config.json!") + exit(1) + +# Load config instance +config = config_data["instances"][instance_key] + +# Extract DVFS from config +dvfs_config = config.get("dvfs", {}) +dvfs = Dvfs( + dummy=dvfs_config.get("dummy", False), + baseline=dvfs_config.get("baseline", False), + frequencies=dvfs_config.get("frequencies", None) +) + +# Log directory +log_dir = config["output_dir"] +instance_name = config.get("instance", "default_instance") +flower_log_dir = os.path.join(log_dir, f"Flower_{args.suffix}", f"Flower_instance_{instance_name}", "Expetator") +os.makedirs(flower_log_dir, exist_ok=True) + +# Add the configure file to log directory +config_instance_path = os.path.join(flower_log_dir, f"config_instance_{instance_key}.json") +with open(config_instance_path, "w", encoding="utf-8") as file: + json.dump(config, file, indent=4, sort_keys=True, ensure_ascii=False, allow_nan=False) + +class DemoBench: + def __init__(self, params=[args.suffix]): + self.names = {"flower"} + self.params = params + + def build(self, executor): + return {"flower": self.params} + + def run(self, bench, param, executor): + before = time.time() + #run_flwr.main(args.config, args.instance, args.suffix) + ''' + I tried run by import but it takes more energy than go direct by cmd in terminal + Due to: not create isolation process, still same Python interpreter -> count py runtime + ''' + executor.local(f"python3 run_flwr.py -c {args.config} -i {args.instance} -x {args.suffix}") + return time.time() - before, "flower" + +if __name__ == "__main__": + experiment.run_experiment( + flower_log_dir, + [DemoBench()], + leverages=[dvfs], + monitors=[Mojitos(sensor_set={'user', 'rxp', 'dram0'})], + times=args.repeat + ) \ No newline at end of file diff --git a/Run/run_flwr.py b/Run/run_flwr.py index 680ba43..cf9da47 100644 --- a/Run/run_flwr.py +++ b/Run/run_flwr.py @@ -1,4 +1,4 @@ -#python3 run_flwr.py -c config_instance1.json -x test +# python3 run_flwr_1.py -c config_instances.json -i 1 -x 1 import os import sys @@ -8,96 +8,86 @@ from pathlib import Path from datetime import datetime import argparse -# Determine script directory -current_dir = Path(__file__).resolve().parent -parent_dir = current_dir.parent +# structure def main to call in other python file +def main(config_path, instance, suffix): + print(f"Running Flower instance with instance: {instance} and suffix: {suffix}") -# Set up argument parser -parser = argparse.ArgumentParser(description="Run Flower server and clients with specified config file.") -parser.add_argument( - "-c", "--config", type=str, required=True, - help="Path to the config file (e.g., config_instance1.json)" -) -parser.add_argument( - "-x", "--suffix", type=str, required=True, - help="Suffix for the experiment log directory (e.g., experiment name or timestamp)" -) -args = parser.parse_args() + # read json + try: + with open(config_path, "r") as file: + config_data = json.load(file) + except FileNotFoundError: + print(f"Error: Config file {config_path} not found!") + sys.exit(1) + except json.JSONDecodeError: + print(f"Error: Config file {config_path} contains invalid JSON!") + sys.exit(1) -# Dynamically set the path to the config.json file -config_path = os.path.join(current_dir, args.config) + # get instance info + instance_config = config_data.get("instances", {}).get(str(instance)) + if not instance_config: + print(f"Error: Instance {instance} not found in config.json!") + sys.exit(1) -# Read the configuration -try: - with open(config_path, "r") as file: - config = json.load(file) -except FileNotFoundError: - print(f"Error: Config file {config_path} not found!") - sys.exit(1) -except json.JSONDecodeError: - print(f"Error: Config file {config_path} contains invalid JSON!") - sys.exit(1) + # get server/client info + output_dir = instance_config["output_dir"] + instance_name = instance_config.get("instance", f"default_instance_{instance}") + server_ip = instance_config["server"]["ip"] + server_port = instance_config["server"]["port"] + server_command = [instance_config["server"]["command"], *instance_config["server"]["args"]] -# Get the relevant details from config.json -output_dir = config["output_dir"] -instance_name = config.get("instance", "default_instance") -server_ip = config["server"]["ip"] -server_port = config["server"]["port"] # Ensure server port is defined in config -server_command = [config["server"]["command"], *config["server"]["args"]] + clients = instance_config["clients"] + client_commands = [ + { + "ip": client["ip"], + "command": [client["command"], *client["args"], f'"{server_ip}:{server_port}"'] + } for client in clients + ] -# Gather client details (IP and commands) -clients = config["clients"] -client_commands = [ - { - "ip": client["ip"], - "command": [client["command"], *client["args"], f'"{server_ip}:{server_port}"'] - } for client in clients -] + # Create log for experiment Flower + current_time = datetime.now().strftime("%Y%m%d_%H%M%S") + flower_dir = os.path.join(output_dir, f"Flower_{suffix}") + log_exp_dir = os.path.join(flower_dir, f"Flower_instance_{instance_name}", f"Flwr_{current_time}") + os.makedirs(log_exp_dir, exist_ok=True) -# Parse the experiment suffix from arguments -experiment_suffix = args.suffix + # Run server and clients + try: + print(f"========== Run Server on {server_ip} ==========") + server_log_path = os.path.join(log_exp_dir, f"Server_{server_ip}") + with open(server_log_path, "w") as log_file: + server_process = subprocess.Popen( + ["oarsh", server_ip, *server_command], + stdout=log_file, stderr=subprocess.STDOUT + ) -# Set up log directory for the experiment -current_time = datetime.now().strftime("%Y%m%d_%H%M%S") -flower_dir = os.path.join(output_dir, f"Flower_{experiment_suffix}") -log_exp_dir = os.path.join(flower_dir, f"Flower_instance_{instance_name}", f"Flwr_{current_time}") -os.makedirs(log_exp_dir, exist_ok=True) + client_processes = [] + for client in client_commands: + client_ip = client["ip"] + client_command = client["command"] + if client_ip: + print(f"========== Run Client on {client_ip} ==========") + client_log_path = os.path.join(log_exp_dir, f"Client_{client_ip}") + with open(client_log_path, "w") as log_file: + client_process = subprocess.Popen( + ["oarsh", client_ip, *client_command], + stdout=log_file, stderr=subprocess.STDOUT + ) + client_processes.append(client_process) -# Run the server and clients -try: - # Start server process and store it - print(f"========== Run Server on {server_ip} ==========") - server_log_path = os.path.join(log_exp_dir, f"Server_{server_ip}") - with open(server_log_path, "w") as log_file: - server_process = subprocess.Popen( - ["oarsh", server_ip, *server_command], - stdout=log_file, stderr=subprocess.STDOUT - ) + print("========== Waiting for processes to complete ==========") + server_process.wait() + for client_process in client_processes: + client_process.wait() + + except Exception as e: + print(f"An error occurred: {e}") + sys.exit(1) - # Start client processes and store them in a list - client_processes = [] - client_log_paths = [] - for client in client_commands: - client_ip = client["ip"] - client_command = client["command"] - if client_ip: - print(f"========== Run Client on {client_ip} ==========") - client_log_path = os.path.join(log_exp_dir, f"Client_{client_ip}") - client_log_paths.append(client_log_path) - with open(client_log_path, "w") as log_file: - client_process = subprocess.Popen( - ["oarsh", client_ip, *client_command], - stdout=log_file, stderr=subprocess.STDOUT - ) - client_processes.append(client_process) - - # Wait for all processes to complete - print("========== Waiting for processes to complete ==========") - server_process.wait() - for client_process in client_processes: - client_process.wait() - -except Exception as e: - print(f"An error occurred: {e}") - sys.exit(1) +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Run Flower server and clients with specified config file.") + parser.add_argument("-c", "--config", type=str, required=True) + parser.add_argument("-i", "--instance", type=str, required=True) + parser.add_argument("-x", "--suffix", type=str, required=True) + args = parser.parse_args() + main(args.config, args.instance, args.suffix) diff --git a/Run/run_measure.py b/Run/run_measure.py deleted file mode 100644 index 6ef1f8b..0000000 --- a/Run/run_measure.py +++ /dev/null @@ -1,43 +0,0 @@ -#python3 run_measure.py -x experiment1 - -import os -import glob -import subprocess -import argparse - -def main(): - # Set up argument parser - parser = argparse.ArgumentParser(description="Run measure.py for all configuration files.") - parser.add_argument( - "-x", "--suffix", type=str, required=True, - help="Experiment suffix to pass to measure.py (e.g., experiment1)" - ) - parser.add_argument( - "-r", "--repeat", type=int, default=1, required=True, - help="Number of repeatation (e.g., 2, the exp will be repeated in 2 times)" - ) - args = parser.parse_args() - - # Find all configuration files matching the pattern - config_files = glob.glob("config_instance*.json") - - if not config_files: - print("No configuration files found matching 'config_instance*.json'.") - return - - # Iterate over each config file and run measure.py - for config_file in config_files: - print(f"Running measure.py with config: {config_file}") - try: - subprocess.run( - ["python3", "measure.py", "-c", config_file, "-x", args.suffix, "-r", str(args.repeat)], - check=True - ) - except subprocess.CalledProcessError as e: - print(f"Error: measure.py failed for config {config_file}.") - print(f"Details: {e}") - except Exception as e: - print(f"Unexpected error occurred: {e}") - -if __name__ == "__main__": - main() -- GitLab