DevicePerformanceProfile¶
- class DevicePerformanceProfile(configuration, equilibrium_methods=None, non_equilibrium_methods=None)¶
Class for performing timing and memory profiles of the different methods available for calculating the Green’s function and lesser Green’s function.
- Parameters:
configuration (
DeviceConfiguration
) – The device configuration with an attached calculator to profile.equilibrium_methods (
GreensFunction
|SparseGreensFunction
| sequence of (GreensFunction
|SparseGreensFunction
)) – The methods benchmarked for the equilibrium calculation. If no methods should be benchmarked for the equilibrium calculation, an empty list can be specified. Default:: (GreensFunction
,SparseGreensFunction
)non_equilibrium_methods – The methods benchmarked for the non-equilibrium calculation. If no methods should be benchmarked for the non-equilibrium calculation, an empty list can be specified. Default:: (
GreensFunction
,SparseGreensFunction
)
- equilibriumMethods()¶
- Returns:
The equilibrium methods profiled.
- Return type:
tuple of (
GreensFunction
|SparseGreensFunction
)
- memoryPeaks()¶
Get the peak memory usage across all processes for the different Green’s function methods. Every process returns the same global peak memory usage.
- Returns:
The peak memory usages in MB.
- Return type:
dict
- memoryPeaksSingleProcess()¶
Get the peak memory usage for the different Green’s function methods. Each process returns its own local peak memory usage.
- Returns:
The peak memory usages in MB.
- Return type:
dict
- memoryProfiles()¶
Get the memory usage over time for the different Green’s function methods. Each process returns its own local memory usage.
- Returns:
The memory profiles in MB.
- Return type:
dict
- nlprint(stream=<_io.TextIOWrapper name='<stdout>' mode='w' encoding='utf-8'>)¶
Print out the profiling report.
- Parameters:
stream (file) – The stream to write to. This stream must support strings being written to it using ‘write’. Default:
sys.stdout
- nonEquilibriumMethods()¶
- Returns:
The non-equilibrium methods profiled.
- Return type:
tuple of (
GreensFunction
|SparseGreensFunction
)
- timings()¶
Get the timing results for the different Green’s function methods.
- Returns:
The timing results in seconds.
- Return type:
dict
- uniqueString()¶
Return a unique string representing the state of the object.
Notes¶
This profiler helps to pick the optimal values for the arguments
equilibrium_method
and non_equilibrium_method
in DeviceAlgorithmParameters.
These arguments select the algorithms used to calculate the Green’s function
and lesser Green’s function.
For both equilibrium and non-equilibrium contour points the following methods are profiled:
For each method the elapsed time and memory usage are reported.
Note
The profile is generated by spawning a child process. Not all clusters support this.
Usage Example¶
Investigate the optimal methods to calculate the (lesser) Green’s function for a carbon chain with the following script.
# -------------------------------------------------------------
# Left electrode
# -------------------------------------------------------------
# Set up lattice
vector_a = [6.0, 0.0, 0.0]*Angstrom
vector_b = [0.0, 6.0, 0.0]*Angstrom
vector_c = [0.0, 0.0, 5.8]*Angstrom
left_electrode_lattice = UnitCell(vector_a, vector_b, vector_c)
# Define elements
left_electrode_elements = [Carbon, Carbon]
# Define coordinates
left_electrode_coordinates = [[ 3. , 3. , 1.45],
[ 3. , 3. , 4.35]]*Angstrom
# Set up configuration
left_electrode = BulkConfiguration(
bravais_lattice=left_electrode_lattice,
elements=left_electrode_elements,
cartesian_coordinates=left_electrode_coordinates
)
# -------------------------------------------------------------
# Right electrode
# -------------------------------------------------------------
# Set up lattice
vector_a = [6.0, 0.0, 0.0]*Angstrom
vector_b = [0.0, 6.0, 0.0]*Angstrom
vector_c = [0.0, 0.0, 5.8]*Angstrom
right_electrode_lattice = UnitCell(vector_a, vector_b, vector_c)
# Define elements
right_electrode_elements = [Carbon, Carbon]
# Define coordinates
right_electrode_coordinates = [[ 3. , 3. , 1.45],
[ 3. , 3. , 4.35]]*Angstrom
# Set up configuration
right_electrode = BulkConfiguration(
bravais_lattice=right_electrode_lattice,
elements=right_electrode_elements,
cartesian_coordinates=right_electrode_coordinates
)
# -------------------------------------------------------------
# Central region
# -------------------------------------------------------------
# Set up lattice
vector_a = [6.0, 0.0, 0.0]*Angstrom
vector_b = [0.0, 6.0, 0.0]*Angstrom
vector_c = [0.0, 0.0, 71.5]*Angstrom
central_region_lattice = UnitCell(vector_a, vector_b, vector_c)
# Define elements
central_region_elements = [Carbon, Carbon, Carbon, Carbon, Carbon, Carbon, Carbon, Carbon,
Carbon, Carbon, Carbon, Carbon, Carbon, Carbon, Carbon, Carbon,
Carbon, Carbon, Carbon, Carbon, Carbon, Carbon, Carbon, Carbon]
# Define coordinates
central_region_coordinates = [[ 3. , 3. , 1.45],
[ 3. , 3. , 4.35],
[ 3. , 3. , 7.25],
[ 3. , 3. , 10.15],
[ 3. , 3. , 13.05],
[ 3. , 3. , 15.95],
[ 3. , 3. , 18.85],
[ 3. , 3. , 21.75],
[ 3. , 3. , 24.65],
[ 3. , 3. , 27.55],
[ 3. , 3. , 30.45],
[ 3. , 3. , 33.35],
[ 3. , 3. , 38.15],
[ 3. , 3. , 41.05],
[ 3. , 3. , 43.95],
[ 3. , 3. , 46.85],
[ 3. , 3. , 49.75],
[ 3. , 3. , 52.65],
[ 3. , 3. , 55.55],
[ 3. , 3. , 58.45],
[ 3. , 3. , 61.35],
[ 3. , 3. , 64.25],
[ 3. , 3. , 67.15],
[ 3. , 3. , 70.05]]*Angstrom
# Set up configuration
central_region = BulkConfiguration(
bravais_lattice=central_region_lattice,
elements=central_region_elements,
cartesian_coordinates=central_region_coordinates
)
device_configuration = DeviceConfiguration(
central_region,
[left_electrode, right_electrode]
)
# -------------------------------------------------------------
# Calculator
# -------------------------------------------------------------
#----------------------------------------
# Basis Set
#----------------------------------------
basis_set = [
LDABasis.Carbon_SingleZeta,
]
#----------------------------------------
# Exchange-Correlation
#----------------------------------------
exchange_correlation = NCLDA.PZ
#----------------------------------------
# Poisson Solver Settings
#----------------------------------------
left_electrode_poisson_solver = FastFourier2DSolver(
boundary_conditions=[[PeriodicBoundaryCondition,PeriodicBoundaryCondition],
[PeriodicBoundaryCondition,PeriodicBoundaryCondition],
[PeriodicBoundaryCondition,PeriodicBoundaryCondition]]
)
right_electrode_poisson_solver = FastFourier2DSolver(
boundary_conditions=[[PeriodicBoundaryCondition,PeriodicBoundaryCondition],
[PeriodicBoundaryCondition,PeriodicBoundaryCondition],
[PeriodicBoundaryCondition,PeriodicBoundaryCondition]]
)
# Use the special noncollinear mixing scheme
iteration_control_parameters = IterationControlParameters(
algorithm=PulayMixer(noncollinear_mixing=True)
)
#----------------------------------------
# Electrode Calculators
#----------------------------------------
left_electrode_calculator = LCAOCalculator(
basis_set=basis_set,
exchange_correlation=exchange_correlation,
poisson_solver=left_electrode_poisson_solver,
)
right_electrode_calculator = LCAOCalculator(
basis_set=basis_set,
exchange_correlation=exchange_correlation,
poisson_solver=right_electrode_poisson_solver,
)
#----------------------------------------
# Device Calculator
#----------------------------------------
calculator = DeviceLCAOCalculator(
basis_set=basis_set,
exchange_correlation=exchange_correlation,
iteration_control_parameters = iteration_control_parameters,
electrode_calculators=
[left_electrode_calculator, right_electrode_calculator],
)
device_configuration.setCalculator(calculator)
# Create the performance profile and print a report.
device_performance_profile = DevicePerformanceProfile(device_configuration)
nlprint(device_performance_profile)
Here is an example of the output you might get by running with 2 MPI processes:
+------------------------------------------------------------------------------+
| Device Performance Profile (2 processes) |
+------------------------------------------------------------------------------+
| Contour point timing (s): |
| EQ NEQ |
| GreensFunction 0.01 0.01 |
| SparseGreensFunction 0.03 0.02 |
| |
| Fastest EQ method (by 5.1 times): GreensFunction |
| Fastest NEQ method (by 2.9 times): GreensFunction |
+------------------------------------------------------------------------------+
| Peak memory usage/process (MB): |
| EQ NEQ |
| GreensFunction 292.73 295.70 |
| SparseGreensFunction 295.27 301.52 |
| |
| Most memory-efficient EQ method (by 1.0 times): GreensFunction |
| Most memory-efficient NEQ method (by 1.0 times): GreensFunction |
+------------------------------------------------------------------------------+
We can see that, in this case, GreensFunction is faster for calculating both equilibrium and non-equilibrium contour points. In terms of memory efficienty, the two methods are almost identical.
It is important to note that the timings given are for a single contour point run in parallel across
all MPI processes. In a real device calculation many contour points are used, and the best
performance is obtained when running with 1 process per contour point. It is therefore appropriate
to run DevicePerformanceProfile with the same number of processes that will be specified in
processes_per_contour_point
.