#!/usr/bin/env python3 import paramiko import time import re import statistics import os from pathlib import Path from datetime import datetime # Configuration NODES = ["192.168.0.10", "192.168.0.11"] # Replace with your nodes' IP addresses USERNAME = "root" # SSH username PASSWORD = "meshman11s" # SSH password PTP4L_COMMAND = "ptp4l -i eth0 -m" # Replace `eth0` with the appropriate interface MEASUREMENT_DURATION = 100 # Duration to listen to measurement output in seconds script_dir = os.path.dirname(os.path.abspath(__file__)) script_dir += '/logs' # Path(script_dir).mkdir(parents=True, exist_ok=True) LOG_FILE = os.path.join(script_dir, f"{datetime.now().strftime('%d%m%Y_%H-%M')}_ptp4l_meas.log") # Functions def ssh_connect(node): """Establish an SSH connection to a node.""" client = paramiko.SSHClient() client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) client.connect(node, username=USERNAME, password=PASSWORD) return client def start_ptp4l(client): """Start a ptp4l instance on the node.""" stdin, stdout, stderr = client.exec_command(f"{PTP4L_COMMAND} > ptp4l_output.log 2>&1 & echo $!") pid = stdout.read().decode().strip() return pid def read_measurements(client): """Read measurements from the ptp4l output log.""" stdin, stdout, stderr = client.exec_command("cat ptp4l_output.log") return stdout.read().decode() def stop_ptp4l(client, pid): """Stop the ptp4l instance on the node.""" client.exec_command(f"kill {pid}") def parse_measurements(log): """Parse the measurements from the ptp4l log output.""" offset_pattern = re.compile(r"offset from master\s*([-\d.]+)") offsets = [float(match.group(1)) for match in offset_pattern.finditer(log)] return offsets def main(): ssh_clients = {} pids = {} try: # Connect to nodes and start ptp4l for node in NODES: client = ssh_connect(node) ssh_clients[node] = client pid = start_ptp4l(client) pids[node] = pid print(f"Started ptp4l on {node} with PID {pid}") # Wait for synchronization and measurement print("Waiting for measurement duration...") time.sleep(MEASUREMENT_DURATION) # Collect and process measurements all_offsets = [] with open(LOG_FILE, "w") as log_file: for node, client in ssh_clients.items(): log = read_measurements(client) offsets = parse_measurements(log) all_offsets.extend(offsets) # Write individual results to the log file log_file.write(f"Results from {node}:\n") for offset in offsets: log_file.write(f"{offset}\n") log_file.write("\n") # Write statistics if all_offsets: mean_offset = statistics.mean(all_offsets) stddev_offset = statistics.stdev(all_offsets) log_file.write(f"Overall Statistics:\n") log_file.write(f"Mean Offset: {mean_offset}\n") log_file.write(f"Standard Deviation: {stddev_offset}\n") print(f"Measurement completed. Results written to {LOG_FILE}.") finally: # Cleanup: Stop ptp4l instances for node, client in ssh_clients.items(): pid = pids.get(node) if pid: stop_ptp4l(client, pid) print(f"Stopped ptp4l on {node}.") client.close() if __name__ == "__main__": main()