diff --git a/Flower_v1/client_1.py b/Flower_v1/client_1.py index ae28e95eca5c53faad1ec9e4167f959195f754b8..af26d00e8284e079351fa9bce9522c7b7248de22 100644 --- a/Flower_v1/client_1.py +++ b/Flower_v1/client_1.py @@ -1,4 +1,4 @@ -#python3 client_1.py <dataset> <id> <total_client> <IP:PORT> +#python3 client_1.py <dataset> <partition> <client_num> <IP:PORT> #python3 client_1.py cifar10 1 3 172.16.66.55:8080 import flwr as fl @@ -10,18 +10,33 @@ import sys # Function to load and partition the dataset based on client_id def load_partitioned_data(dataset_name, num_clients, client_id): if dataset_name == "cifar10": + ''' + total samples train: 50000 + total samples test: 10000 + sample type: animals, vehicles, etc. + ''' (x_train, y_train), (x_test, y_test) = tf.keras.datasets.cifar10.load_data() x_train = x_train.astype("float32") / 255.0 x_test = x_test.astype("float32") / 255.0 num_classes = 10 input_shape = (32, 32, 3) elif dataset_name == "mnist": + ''' + total samples train: 60000 + total samples test: 10000 + sample type: handwritten digits + ''' (x_train, y_train), (x_test, y_test) = tf.keras.datasets.mnist.load_data() x_train = x_train.reshape(-1, 28, 28, 1).astype("float32") / 255.0 x_test = x_test.reshape(-1, 28, 28, 1).astype("float32") / 255.0 num_classes = 10 input_shape = (28, 28, 1) elif dataset_name == "cifar100": + ''' + total samples train: 50000 + total samples test: 10000 + sample type: animals, objects + ''' (x_train, y_train), (x_test, y_test) = tf.keras.datasets.cifar100.load_data() x_train = x_train.astype("float32") / 255.0 x_test = x_test.astype("float32") / 255.0 @@ -30,7 +45,7 @@ def load_partitioned_data(dataset_name, num_clients, client_id): else: raise ValueError("Dataset not supported. Use 'cifar10', 'mnist', or 'cifar100'.") - # Partition the dataset among the clients + # Partition the dataset among the clients (same data distribution with same number_clients setup) total_samples = x_train.shape[0] samples_per_client = total_samples // num_clients @@ -39,6 +54,9 @@ def load_partitioned_data(dataset_name, num_clients, client_id): x_client_train = x_train[start:end] y_client_train = y_train[start:end] + + # x_client_train = x_train + # y_client_train = y_train # Split the client-specific data into training and validation sets x_train, x_val, y_train, y_val = train_test_split(x_client_train, y_client_train, test_size=0.2, random_state=42) @@ -47,7 +65,7 @@ def load_partitioned_data(dataset_name, num_clients, client_id): # Get command-line arguments: dataset, client_id, num_clients, and server address if len(sys.argv) != 5: - print("Usage: python3 client.py <dataset> <partition> <client_num> <IP:PORT>") + print("Usage: python3 client_1.py <dataset> <partition> <client_num> <IP:PORT>") sys.exit(1) dataset_name = sys.argv[1] @@ -69,17 +87,17 @@ class FederatedClient(fl.client.NumPyClient): def fit(self, parameters, config): model.set_weights(parameters) - model.fit(x_train, y_train, epochs=1, batch_size=32, validation_data=(x_val, y_val)) + model.fit(x_train, y_train, epochs=5, batch_size=32, validation_data=(x_val, y_val)) return model.get_weights(), len(x_train), {} def evaluate(self, parameters, config): model.set_weights(parameters) - loss, accuracy = model.evaluate(x_test, y_test) + loss, accuracy = model.evaluate(x_test, y_test, verbose=0) return loss, len(x_test), {"accuracy": float(accuracy)} # Start Flower client if __name__ == "__main__": fl.client.start_client(server_address=server_address, client=FederatedClient(), - max_retries=5, - max_wait_time=10) + max_retries=3, # retry connection to server 3 times + max_wait_time=5) # wait 5 seconds before retrying diff --git a/Flower_v1/server_1.py b/Flower_v1/server_1.py index a4664963745960faf7a038b2693c3f5b41fae720..a2ca18eb6830448f5d88bf321e87de6527e89585 100644 --- a/Flower_v1/server_1.py +++ b/Flower_v1/server_1.py @@ -8,7 +8,7 @@ from flwr.server.strategy import Strategy from flwr.server.client_manager import ClientManager from flwr.server.client_proxy import ClientProxy from flwr.server import ServerApp, ServerConfig -from flwr.server.strategy import FedAvg, FedMedian, FedOpt, FedAdam +from flwr.server.strategy import FedAvg, FedMedian, FedOpt, FedAdam, FedProx, QFedAvg import argparse import tensorflow as tf import flwr @@ -110,8 +110,8 @@ parser.add_argument( "--strategy", type=str, default="fedAvg", - choices=["fedAvg", "fedMedian", "fedOpt", "fedAdam", "fedAvg2Clients"], # Add options strategies - help="Select strategy: fedAvg, fedMedian, fedOpt or fedAdam or fedAvg2Clients", + choices=["fedAvg", "fedMedian", "fedOpt", "fedAdam", "fedAvg2Clients", "fedProx", "QfedAvg"], # Add options strategies + help="Select strategy: fedAvg, fedMedian, fedOpt, fedAdam, fedProx, QfedAvg or fedAvg2Clients", ) parser.add_argument("-l", "--log_dir", type=str, default=None, help="Directory to save logs") @@ -141,24 +141,46 @@ weights = model.get_weights() parameters = flwr.common.ndarrays_to_parameters(weights) # Select the base strategy -if args.strategy == "fedAvg": - base_strategy = FedAvg(evaluate_metrics_aggregation_fn=weighted_average) -elif args.strategy == "fedAvg2Clients": +if args.strategy == "fedAvg": + # baseline strategy base_strategy = FedAvg( - fraction_fit=0.67, - min_fit_clients=2, - min_available_clients=2, + evaluate_metrics_aggregation_fn=weighted_average) +elif args.strategy == "fedAvg2Clients": + # Custom client num each round + base_strategy = FedAvg( + fraction_fit=0.67, # 67% of clients agg/fit each round + min_fit_clients=2, # At least 2 clients fit each round + min_available_clients=2, # At least 2 clients available each round evaluate_metrics_aggregation_fn=weighted_average, ) elif args.strategy == "fedMedian": - base_strategy = FedMedian(evaluate_metrics_aggregation_fn=weighted_average) -elif args.strategy == "fedOpt": + # robustness strategy + base_strategy = FedMedian( + evaluate_metrics_aggregation_fn=weighted_average) +elif args.strategy == "fedOpt": + # server optimization strategy base_strategy = FedOpt( - evaluate_metrics_aggregation_fn=weighted_average, initial_parameters=parameters + evaluate_metrics_aggregation_fn=weighted_average, + initial_parameters=parameters ) elif args.strategy == "fedAdam": + # server optimization strategy use Adam base_strategy = FedAdam( - evaluate_metrics_aggregation_fn=weighted_average, initial_parameters=parameters + evaluate_metrics_aggregation_fn=weighted_average, + initial_parameters=parameters + ) +elif args.strategy == "fedProx": + # regularization strategy + base_strategy = FedProx( + evaluate_metrics_aggregation_fn=weighted_average, + initial_parameters=parameters, + proximal_mu = 0.1 + ) +elif args.strategy == "QFedAvg": + # improve fairness, reduce var_loss strategy + base_strategy = QFedAvg( + evaluate_metrics_aggregation_fn=weighted_average, + initial_parameters=parameters ) diff --git a/README.md b/README.md index 40440191c8f60266f093ce561925a950d721ea4f..62c3af3012881a58bf46ebd191abdc2cfdd165c2 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ This project provides tools to measure the energy consumption of Flower-based fe - [Usage](#usage) - [FL framework](#fl-framework) - [Configure instances for CPU](#configure-instance-for-cpu) - - [Configure instances for GPU](#configure-instance-for-gpu) + - [Configure instances for GPU](#configure-instance-for-gpu-developing) - [Run exp](#run-exp) - [Quickstart](#quickstart) - [Step 1. Reserve the Hosts in G5K](#step-1-reserve-the-hosts-in-g5k) @@ -69,7 +69,7 @@ Configure instances of experiment in a json format, structure is shown below. ```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: + - Run this command to get available 4 frequencies (min, max, 2 in middle): ```bash python3 get_frequencies.py ``` @@ -114,15 +114,26 @@ Configure instances of experiment in a json format, structure is shown below. } ``` -### Configure instance for GPU +### Configure instance for GPU (*developing) - The configuration is as same CPU, except **dvfs** role. In GPU config, the role is **dvfs_gpu**. -Choose only one in 3 settings (steps - zoomfrom - zoomto use for one setting). +Choose only one in 3 settings: - `dummy`: for testing in min and max GPU freq (`false` or `true`). - `baseline`: for testing in max GPU freq (`false` or `true`). - - `steps`: steps to jump in range/window of frequencies (int). - - `zoomfrom`: freq start - - `zoomto`: freq stop + - last setting includes 3 parameters: test with the all freqs in the range. To disable this setting, set the `zoomfrom` and `zoomto` are same values. + - `steps`: steps to jump in range/window of frequencies (int). + - `zoomfrom`: freq start + - `zoomto`: freq stop + *example:* + - list of freq available [1, 1.1, 1.2, 1.9, 2.5, 2.7] GHz + - with `zoomfrom` = 1.1, `zoomto` = 2.7 and `steps` = 2 + - list of tested freq returns [1.1, 1.9, 2,7] + + **Remark:** check the available frequencies before using option `frequencies`. + Run below cmd: + ```bash + nvidia-smi -i 0 --query-supported-clocks=gr --format=csv,noheader,nounits | tr '\n' ' ' + ``` ```json "dvfs_gpu": { @@ -169,6 +180,8 @@ Reserve 4 hosts (GPU) (1 server + 3 clients) for 2 hours: oarsub -I -t exotic -p "gpu_count>0" -l {"cluster='drac'"}/host=4 # grenoble ``` +**Remark**: for now only 2 clusters, `chifflot` in Lille and `drac` in Grenoble are available for testing in more than 3 GPU nodes, maximum is 8 (`chifflot`) or 12 (`drac`) nodes. + Make sure your are in`eflwr/Run/`: ```bash cd Run diff --git a/Run/config_instances.json b/Run/config_instances.json index 941ec5d3072819fbac2bca1023278192cd5391e3..b8bac0b373d5ca64667d26c2d6bbab31343db06a 100644 --- a/Run/config_instances.json +++ b/Run/config_instances.json @@ -4,7 +4,7 @@ "instance": "fedAvg_cifar10", "output_dir": "./Log", "dvfs_cpu": { - "dummy": true, + "dummy": false, "baseline": false, "frequencies": null }, @@ -26,7 +26,7 @@ "args": [ "./Flower_v1/client_1.py", "cifar10", - "1", + "0", "3" ], "ip": "172.16.66.77" @@ -37,7 +37,7 @@ "args": [ "./Flower_v1/client_1.py", "cifar10", - "2", + "1", "3" ], "ip": "172.16.66.78" @@ -48,7 +48,7 @@ "args": [ "./Flower_v1/client_1.py", "cifar10", - "3", + "2", "3" ], "ip": "172.16.66.79" @@ -56,6 +56,116 @@ ] }, "2": { + "instance": "fedAvg_cifar100", + "output_dir": "./Log", + "dvfs_cpu": { + "dummy": true, + "baseline": false, + "frequencies": null + }, + "server": { + "command": "python3", + "args": [ + "./Flower_v1/server_1.py", + "-r 1", + "-s fedAvg" + ], + "ip": "172.16.66.76", + "modules": ["logger"], + "port": 8080 + }, + "clients": [ + { + "name": "client1", + "command": "python3", + "args": [ + "./Flower_v1/client_1.py", + "cifar100", + "0", + "3" + ], + "ip": "172.16.66.77" + }, + { + "name": "client2", + "command": "python3", + "args": [ + "./Flower_v1/client_1.py", + "cifar100", + "1", + "3" + ], + "ip": "172.16.66.78" + }, + { + "name": "client3", + "command": "python3", + "args": [ + "./Flower_v1/client_1.py", + "cifar100", + "2", + "3" + ], + "ip": "172.16.66.79" + } + ] + }, + "3": { + "instance": "fedAvg_mnist", + "output_dir": "./Log", + "dvfs_cpu": { + "dummy": true, + "baseline": false, + "frequencies": null + }, + "server": { + "command": "python3", + "args": [ + "./Flower_v1/server_1.py", + "-r 1", + "-s fedAvg" + ], + "ip": "172.16.66.76", + "modules": ["logger"], + "port": 8080 + }, + "clients": [ + { + "name": "client1", + "command": "python3", + "args": [ + "./Flower_v1/client_1.py", + "mnist", + "0", + "3" + ], + "ip": "172.16.66.77" + }, + { + "name": "client2", + "command": "python3", + "args": [ + "./Flower_v1/client_1.py", + "mnist", + "1", + "3" + ], + "ip": "172.16.66.78" + }, + { + "name": "client3", + "command": "python3", + "args": [ + "./Flower_v1/client_1.py", + "mnist", + "2", + "3" + ], + "ip": "172.16.66.79" + } + ] + }, + "4": { "instance": "fedAvg2Clients_cifar10", "output_dir": "./Log", "dvfs_cpu": { @@ -78,12 +188,177 @@ { "name": "client1", "command": "python3", + "args": [ + "./Flower_v1/client_1.py", + "cifar10", + "0", + "3" + ], + "ip": "172.16.66.77" + }, + { + "name": "client2", + "command": "python3", "args": [ "./Flower_v1/client_1.py", "cifar10", "1", "3" ], + "ip": "172.16.66.78" + }, + { + "name": "client3", + "command": "python3", + "args": [ + "./Flower_v1/client_1.py", + "cifar10", + "2", + "3" + ], + "ip": "172.16.66.79" + } + ] + }, + "5": { + "instance": "fedAvg2Clients_cifar100", + "output_dir": "./Log", + "dvfs_cpu": { + "dummy": true, + "baseline": false, + "frequencies": null + }, + "server": { + "command": "python3", + "args": [ + "./Flower_v1/server_1.py", + "-r 1", + "-s fedAvg2Clients" + ], + "ip": "172.16.66.76", + "modules": ["logger"], + "port": 8080 + }, + "clients": [ + { + "name": "client1", + "command": "python3", + "args": [ + "./Flower_v1/client_1.py", + "cifar100", + "0", + "3" + ], + "ip": "172.16.66.77" + }, + { + "name": "client2", + "command": "python3", + "args": [ + "./Flower_v1/client_1.py", + "cifar100", + "1", + "3" + ], + "ip": "172.16.66.78" + }, + { + "name": "client3", + "command": "python3", + "args": [ + "./Flower_v1/client_1.py", + "cifar100", + "2", + "3" + ], + "ip": "172.16.66.79" + } + ] + }, + "6": { + "instance": "fedAvg2Clients_mnist", + "output_dir": "./Log", + "dvfs_cpu": { + "dummy": true, + "baseline": false, + "frequencies": null + }, + "server": { + "command": "python3", + "args": [ + "./Flower_v1/server_1.py", + "-r 1", + "-s fedAvg2Clients" + ], + "ip": "172.16.66.76", + "modules": ["logger"], + "port": 8080 + }, + "clients": [ + { + "name": "client1", + "command": "python3", + "args": [ + "./Flower_v1/client_1.py", + "mnist", + "0", + "3" + ], + "ip": "172.16.66.77" + }, + { + "name": "client2", + "command": "python3", + "args": [ + "./Flower_v1/client_1.py", + "mnist", + "1", + "3" + ], + "ip": "172.16.66.78" + }, + { + "name": "client3", + "command": "python3", + "args": [ + "./Flower_v1/client_1.py", + "mnist", + "2", + "3" + ], + "ip": "172.16.66.79" + } + ] + }, + "7": { + "instance": "fedProx_cifar10", + "output_dir": "./Log", + "dvfs_cpu": { + "dummy": true, + "baseline": false, + "frequencies": null + }, + "server": { + "command": "python3", + "args": [ + "./Flower_v1/server_1.py", + "-r 1", + "-s fedProx" + ], + "ip": "172.16.66.76", + "modules": ["logger"], + "port": 8080 + }, + "clients": [ + { + "name": "client1", + "command": "python3", + "args": [ + "./Flower_v1/client_1.py", + "cifar10", + "0", + "3" + ], "ip": "172.16.66.77" }, { @@ -92,18 +367,293 @@ "args": [ "./Flower_v1/client_1.py", "cifar10", + "1", + "3" + ], + "ip": "172.16.66.78" + }, + { + "name": "client3", + "command": "python3", + "args": [ + "./Flower_v1/client_1.py", + "cifar10", + "2", + "3" + ], + "ip": "172.16.66.79" + } + ] + }, + "8": { + "instance": "fedProx_cifar100", + "output_dir": "./Log", + "dvfs_cpu": { + "dummy": true, + "baseline": false, + "frequencies": null + }, + "server": { + "command": "python3", + "args": [ + "./Flower_v1/server_1.py", + "-r 1", + "-s fedProx" + ], + "ip": "172.16.66.76", + "modules": ["logger"], + "port": 8080 + }, + "clients": [ + { + "name": "client1", + "command": "python3", + "args": [ + "./Flower_v1/client_1.py", + "cifar100", + "0", + "3" + ], + "ip": "172.16.66.77" + }, + { + "name": "client2", + "command": "python3", + "args": [ + "./Flower_v1/client_1.py", + "cifar100", + "1", + "3" + ], + "ip": "172.16.66.78" + }, + { + "name": "client3", + "command": "python3", + "args": [ + "./Flower_v1/client_1.py", + "cifar100", "2", "3" ], + "ip": "172.16.66.79" + } + ] + }, + "9": { + "instance": "fedProx_mnist", + "output_dir": "./Log", + "dvfs_cpu": { + "dummy": true, + "baseline": false, + "frequencies": null + }, + "server": { + "command": "python3", + "args": [ + "./Flower_v1/server_1.py", + "-r 1", + "-s fedProx" + ], + "ip": "172.16.66.76", + "modules": ["logger"], + "port": 8080 + }, + "clients": [ + { + "name": "client1", + "command": "python3", + "args": [ + "./Flower_v1/client_1.py", + "mnist", + "0", + "3" + ], + "ip": "172.16.66.77" + }, + { + "name": "client2", + "command": "python3", + "args": [ + "./Flower_v1/client_1.py", + "mnist", + "1", + "3" + ], "ip": "172.16.66.78" }, { "name": "client3", "command": "python3", + "args": [ + "./Flower_v1/client_1.py", + "mnist", + "2", + "3" + ], + "ip": "172.16.66.79" + } + ] + }, + "10": { + "instance": "fedAdam_cifar10", + "output_dir": "./Log", + "dvfs_cpu": { + "dummy": true, + "baseline": false, + "frequencies": null + }, + "server": { + "command": "python3", + "args": [ + "./Flower_v1/server_1.py", + "-r 1", + "-s fedAdam" + ], + "ip": "172.16.66.76", + "modules": ["logger"], + "port": 8080 + }, + "clients": [ + { + "name": "client1", + "command": "python3", + "args": [ + "./Flower_v1/client_1.py", + "cifar10", + "0", + "3" + ], + "ip": "172.16.66.77" + }, + { + "name": "client2", + "command": "python3", "args": [ "./Flower_v1/client_1.py", "cifar10", - "3", + "1", + "3" + ], + "ip": "172.16.66.78" + }, + { + "name": "client3", + "command": "python3", + "args": [ + "./Flower_v1/client_1.py", + "cifar10", + "2", + "3" + ], + "ip": "172.16.66.79" + } + ] + }, + "11": { + "instance": "fedAdam_cifar100", + "output_dir": "./Log", + "dvfs_cpu": { + "dummy": true, + "baseline": false, + "frequencies": null + }, + "server": { + "command": "python3", + "args": [ + "./Flower_v1/server_1.py", + "-r 1", + "-s fedAdam" + ], + "ip": "172.16.66.76", + "modules": ["logger"], + "port": 8080 + }, + "clients": [ + { + "name": "client1", + "command": "python3", + "args": [ + "./Flower_v1/client_1.py", + "cifar100", + "0", + "3" + ], + "ip": "172.16.66.77" + }, + { + "name": "client2", + "command": "python3", + "args": [ + "./Flower_v1/client_1.py", + "cifar100", + "1", + "3" + ], + "ip": "172.16.66.78" + }, + { + "name": "client3", + "command": "python3", + "args": [ + "./Flower_v1/client_1.py", + "cifar100", + "2", + "3" + ], + "ip": "172.16.66.79" + } + ] + }, + "12": { + "instance": "fedAdam_mnist", + "output_dir": "./Log", + "dvfs_cpu": { + "dummy": true, + "baseline": false, + "frequencies": null + }, + "server": { + "command": "python3", + "args": [ + "./Flower_v1/server_1.py", + "-r 1", + "-s fedAdam" + ], + "ip": "172.16.66.76", + "modules": ["logger"], + "port": 8080 + }, + "clients": [ + { + "name": "client1", + "command": "python3", + "args": [ + "./Flower_v1/client_1.py", + "mnist", + "0", + "3" + ], + "ip": "172.16.66.77" + }, + { + "name": "client2", + "command": "python3", + "args": [ + "./Flower_v1/client_1.py", + "mnist", + "1", + "3" + ], + "ip": "172.16.66.78" + }, + { + "name": "client3", + "command": "python3", + "args": [ + "./Flower_v1/client_1.py", + "mnist", + "2", "3" ], "ip": "172.16.66.79" diff --git a/Run/custom_gpuclock.py b/Run/custom_gpuclock.py index 952efb259a0c52d402e5cd45ad2ff0c8a2b1982b..4046de7449e9b6ef3de4bae00d6561b77cbf71e4 100644 --- a/Run/custom_gpuclock.py +++ b/Run/custom_gpuclock.py @@ -1,10 +1,7 @@ -from expetator.leverages.gpuclock import GpuClock -class CustomGpuClock(GpuClock): - """ Custom GPU Clock Leverage using clocks.gr instead of clocks.applications.gr """ - +class GpuClock: + 'nvidia-smi graphics/sm clock setting' def __init__(self, dummy=False, baseline=False, steps=2, zoomfrom=0, zoomto=0): - super().__init__() self.dummy = dummy self.baseline = baseline self.executor = None @@ -12,74 +9,62 @@ class CustomGpuClock(GpuClock): 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 + self.nsteps = steps + # zoomfrom/to enables full freq. granularity within a clock window: if zoomto != 0 and zoomfrom != zoomto: self.zoom = (zoomfrom, zoomto) else: self.zoom = None def build(self, executor): - """ Gather the available frequencies """ + '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.") - + clk = sorted([int(f) for f in clk_s.strip().split(' ')]) self.clock_sm_min = clk[0] - self.available_frequencies = [clk[(i * (len(clk) - 1)) // (self.nsteps - 1)] for i in range(self.nsteps)] - + 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.available_frequencies_mem = sorted([int(f) for f in clk_s.strip().split(' ')]) 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]] + if self.zoom is not None: + # pick all available freq within the zoom window: + clkz = [f for f in clk if self.zoom[0] <= f and f <= self.zoom[1]] + rest = [f for f in self.available_frequencies if f < self.zoom[0] or self.zoom[1] < f] 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 """ + 'Returns all the frequencies' return self.available_frequencies def start(self, freq): - """ Sets the GPU frequency """ + 'Sets the right frequency range on gpu 0' if freq in self.available_frequencies: - self.executor.local(f'nvidia-smi -i 0 -ac {self.clock_mem_max},{freq}', root=True) + self.executor.local('nvidia-smi -i 0 -ac %s,%s' % (self.clock_mem_max, freq), root=True) + #self.executor.local('nvidia-smi -i 0 -lgc %s,%s' % (self.clock_sm_min, freq), root=True) def stop(self, output_file=None): - """ Reset GPU to default frequency """ + 'Reverts to the maximum frequency' self.executor.local('nvidia-smi -i 0 -rac', root=True) - + #self.executor.local('nvidia-smi -i 0 -rgc', root=True) + def get_state(self): - """ Returns the current min and max application frequencies using clocks.gr instead of clocks.applications.gr """ + 'Returns the current min and max application frequencies' 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 + cur_max = int(self.executor.local('nvidia-smi -i 0 --query-gpu=clocks.applications.gr --format=csv,noheader,nounits')) + 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}' + 'Returns the current min and max frequencies as a string' + (cur_min, cur_max, mem_max) = self.get_state() + return '%s %s %s' % (cur_min, cur_max, mem_max) def get_labels(self): - """ Returns labels for frequencies """ + 'Returns the label for frequencies' return ('fmin', 'fmax', 'fmemax')