From f9bc6d032cd12b86f230af9b39cf08c2635be501 Mon Sep 17 00:00:00 2001 From: Karthik Chandrashekara Date: Wed, 30 Apr 2025 12:32:16 +0200 Subject: [PATCH] Added script to empirically profile memory usage and time for execution. --- .../+Helper/runWithProfiling.m | 57 +++++++++++++++++++ Dipolar-Gas-Simulator/+Scripts/run_locally.m | 20 ++++--- .../bwhpc_matlab_gpe_sim_gpu.slurm | 5 +- 3 files changed, 71 insertions(+), 11 deletions(-) create mode 100644 Dipolar-Gas-Simulator/+Helper/runWithProfiling.m diff --git a/Dipolar-Gas-Simulator/+Helper/runWithProfiling.m b/Dipolar-Gas-Simulator/+Helper/runWithProfiling.m new file mode 100644 index 0000000..f150637 --- /dev/null +++ b/Dipolar-Gas-Simulator/+Helper/runWithProfiling.m @@ -0,0 +1,57 @@ +function [varargout] = runWithProfiling(funcHandle, nOutputs, saveDirectory) +%RUNWITHPROFILING Profile runtime and memory usage, and log stats to JSON file. +% +% Usage: +% [a, b, c, stats] = runWithProfiling(@() sim.run(), 3, './Results/'); +% +% Inputs: +% funcHandle - Function handle to run (e.g., @() sim.run()) +% nOutputs - Number of outputs expected from funcHandle +% saveDirectory - Directory path to save stats JSON file +% +% Outputs: +% varargout - Outputs of funcHandle (1 to nOutputs) +% - Final output is a struct 'stats' with fields: +% .runtime - Wall-clock time (s) +% .workspaceMemoryMB - Total memory used (MB) +% .timestamp - ISO timestamp of run +% .hostname - System hostname + + % Time the function + tStart = tic; + [varargout{1:nOutputs}] = funcHandle(); + runtime = toc(tStart); + + % Estimate workspace memory usage + try + vars = whos; + totalBytes = sum([vars.bytes]); + workspaceMemoryMB = totalBytes / 1e6; + catch + workspaceMemoryMB = NaN; + end + + % Create stats struct + stats.runtime = runtime; + stats.workspaceMemoryMB = workspaceMemoryMB; + stats.timestamp = datestr(now, 'yyyy-mm-dd_HH-MM-SS'); + [~, hostname] = system('hostname'); + stats.hostname = strtrim(hostname); + + % Save as JSON + try + if ~exist(saveDirectory, 'dir') + mkdir(saveDirectory); + end + filename = fullfile(saveDirectory, ['profiling_stats_', stats.timestamp, '.json']); + jsonStr = jsonencode(stats, 'PrettyPrint', true); + fid = fopen(filename, 'w'); + fwrite(fid, jsonStr, 'char'); + fclose(fid); + catch ME + warning('Failed to save profiling stats: %s', ME.message); + end + + % Return stats + varargout{nOutputs + 1} = stats; +end diff --git a/Dipolar-Gas-Simulator/+Scripts/run_locally.m b/Dipolar-Gas-Simulator/+Scripts/run_locally.m index c701d08..8f4e809 100644 --- a/Dipolar-Gas-Simulator/+Scripts/run_locally.m +++ b/Dipolar-Gas-Simulator/+Scripts/run_locally.m @@ -3,7 +3,7 @@ % Important: Run only sectionwise!! %% - Create Simulator, Potential and Calculator object with specified options -% - Imaginary-Time + OptionsStruct = struct; OptionsStruct.NumberOfAtoms = 40000; @@ -19,11 +19,11 @@ OptionsStruct.Dimensions = [30, 20, 20]; OptionsStruct.UseApproximationForLHY = true; OptionsStruct.IncludeDDICutOff = true; OptionsStruct.CutoffType = 'Cylindrical'; -OptionsStruct.SimulationMode = 'EnergyMinimization'; % 'ImaginaryTimeEvolution' | 'RealTimeEvolution' | 'EnergyMinimization' -OptionsStruct.GradientDescentMethod = 'HeavyBall'; % 'HeavyBall' | 'NonLinearCGD' -OptionsStruct.MaxIterationsForGD = 2E5; -OptionsStruct.TimeStepSize = 1E-4; % in s -OptionsStruct.MinimumTimeStepSize = 2E-10; % in s +OptionsStruct.SimulationMode = 'EnergyMinimization'; % 'ImaginaryTimeEvolution' | 'RealTimeEvolution' | 'EnergyMinimization' +OptionsStruct.GradientDescentMethod = 'HeavyBall'; % 'HeavyBall' | 'NonLinearCGD' +OptionsStruct.MaxIterationsForGD = 1000; +OptionsStruct.TimeStepSize = 1E-3; % in s +OptionsStruct.MinimumTimeStepSize = 1E-6; % in s OptionsStruct.TimeCutOff = 2E6; % in s OptionsStruct.EnergyTolerance = 5E-10; OptionsStruct.ResidualTolerance = 1E-08; @@ -33,16 +33,18 @@ OptionsStruct.PlotLive = true; OptionsStruct.JobNumber = 0; OptionsStruct.RunOnGPU = false; OptionsStruct.SaveData = true; -OptionsStruct.SaveDirectory = './Results/Data_3D/GradientDescent'; +OptionsStruct.SaveDirectory = './Results/Data_3D/GradientDescent'; % './Results/Data_3D/AnisotropicTrap/Tilted0' options = Helper.convertstruct2cell(OptionsStruct); -clear OptionsStruct sim = Simulator.DipolarGas(options{:}); pot = Simulator.Potentials(options{:}); sim.Potential = pot.trap(); % + pot.repulsive_chopstick(); %-% Run Simulation %-% -[Params, Transf, psi, V, VDk] = sim.run(); +NumberOfOutputs = 5; +[Params, Transf, psi, V, VDk, stats] = Helper.runWithProfiling(@() sim.run(), NumberOfOutputs, OptionsStruct.SaveDirectory); +fprintf('Runtime: %.3f seconds\n', stats.runtime); +fprintf('Memory used: %.2f MB\n', stats.workspaceMemoryMB); %% - Plot numerical grid % Plotter.visualizeSpace(Transf) diff --git a/Dipolar-Gas-Simulator/bwhpc_matlab_gpe_sim_gpu.slurm b/Dipolar-Gas-Simulator/bwhpc_matlab_gpe_sim_gpu.slurm index c7d8b09..5ada7c5 100644 --- a/Dipolar-Gas-Simulator/bwhpc_matlab_gpe_sim_gpu.slurm +++ b/Dipolar-Gas-Simulator/bwhpc_matlab_gpe_sim_gpu.slurm @@ -5,8 +5,9 @@ # Request number of nodes and GPU for job #SBATCH --nodes=1 #SBATCH --ntasks-per-node=1 -#SBATCH --gres=gpu:A40:1 -#SBATCH --mem=2G +#SBATCH --cpus-per-task=4 +#SBATCH --gres=gpu:1 +#SBATCH --mem=12G # Estimated wallclock time for job #SBATCH --time=03:00:00 #SBATCH --job-name=simulation