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
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

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