Skip to content

Commit

Permalink
Avoid accessing GPUs when using CPU only (#2012)
Browse files Browse the repository at this point in the history
* avoid accessing GPUs when using CPU only

* remove unused import/parameter
  • Loading branch information
doichanj authored Dec 8, 2023
1 parent 17edfa3 commit 096e1e3
Show file tree
Hide file tree
Showing 9 changed files with 84 additions and 85 deletions.
6 changes: 2 additions & 4 deletions qiskit_aer/backends/aer_simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -702,12 +702,10 @@ def __init__(

# Update available methods and devices for class
if AerSimulator._AVAILABLE_DEVICES is None:
AerSimulator._AVAILABLE_DEVICES = available_devices(
self._controller, AerSimulator._SIMULATION_DEVICES
)
AerSimulator._AVAILABLE_DEVICES = available_devices(self._controller)
if AerSimulator._AVAILABLE_METHODS is None:
AerSimulator._AVAILABLE_METHODS = available_methods(
self._controller, AerSimulator._SIMULATION_METHODS, AerSimulator._AVAILABLE_DEVICES
AerSimulator._SIMULATION_METHODS, AerSimulator._AVAILABLE_DEVICES
)

# Default configuration
Expand Down
42 changes: 12 additions & 30 deletions qiskit_aer/backends/backend_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@

import psutil
from qiskit.circuit import QuantumCircuit
from qiskit.compiler import assemble
from qiskit.qobj import QasmQobjInstruction
from qiskit.result import ProbDistribution
from qiskit.quantum_info import Clifford
Expand Down Expand Up @@ -441,40 +440,23 @@ def cpp_execute_circuits(controller, aer_circuits, noise_model, config):
return controller.execute(aer_circuits, noise_model, config)


def available_methods(controller, methods, devices):
"""Check available simulation methods by running a dummy circuit."""
# Test methods are available using the controller
dummy_circ = QuantumCircuit(1)
dummy_circ.id(0)
def available_methods(methods, devices):
"""Check available simulation methods"""

valid_methods = []
for device in devices:
for method in methods:
if method not in valid_methods:
qobj = assemble(
dummy_circ, optimization_level=0, shots=1, method=method, device=device
)
result = cpp_execute_qobj(controller, qobj)
if result.get("success", False):
valid_methods.append(method)
for method in methods:
if method == "tensor_network":
if "GPU" in devices:
valid_methods.append(method)
else:
valid_methods.append(method)
return tuple(valid_methods)


def available_devices(controller, devices):
"""Check available simulation devices by running a dummy circuit."""
# Test methods are available using the controller
dummy_circ = QuantumCircuit(1)
dummy_circ.id(0)

valid_devices = []
for device in devices:
qobj = assemble(
dummy_circ, optimization_level=0, shots=1, method="statevector", device=device
)
result = cpp_execute_qobj(controller, qobj)
if result.get("success", False):
valid_devices.append(device)
return tuple(valid_devices)
def available_devices(controller):
"""return available simulation devices"""
dev = controller.available_devices()
return tuple(dev)


def add_final_save_instruction(qobj, state):
Expand Down
1 change: 0 additions & 1 deletion qiskit_aer/backends/qasm_simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -444,7 +444,6 @@ def __init__(self, configuration=None, properties=None, provider=None, **backend
# Update available methods for class
if QasmSimulator._AVAILABLE_METHODS is None:
QasmSimulator._AVAILABLE_METHODS = available_methods(
self._controller,
QasmSimulator._SIMULATION_METHODS,
QasmSimulator._SIMULATION_DEVICES,
)
Expand Down
4 changes: 1 addition & 3 deletions qiskit_aer/backends/statevector_simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -254,9 +254,7 @@ def __init__(self, configuration=None, properties=None, provider=None, **backend
self._controller = aer_controller_execute()

if StatevectorSimulator._AVAILABLE_DEVICES is None:
StatevectorSimulator._AVAILABLE_DEVICES = available_devices(
self._controller, StatevectorSimulator._SIMULATION_DEVICES
)
StatevectorSimulator._AVAILABLE_DEVICES = available_devices(self._controller)

if configuration is None:
configuration = QasmBackendConfiguration.from_dict(
Expand Down
4 changes: 1 addition & 3 deletions qiskit_aer/backends/unitary_simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,9 +240,7 @@ def __init__(self, configuration=None, properties=None, provider=None, **backend
self._controller = aer_controller_execute()

if UnitarySimulator._AVAILABLE_DEVICES is None:
UnitarySimulator._AVAILABLE_DEVICES = available_devices(
self._controller, UnitarySimulator._SIMULATION_DEVICES
)
UnitarySimulator._AVAILABLE_DEVICES = available_devices(self._controller)

if configuration is None:
configuration = QasmBackendConfiguration.from_dict(
Expand Down
10 changes: 10 additions & 0 deletions qiskit_aer/backends/wrappers/aer_controller_binding.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ class ControllerExecutor {
return AerToPy::to_python(
controller_execute<T>(circuits, noise_model, config));
}

py::object available_devices() {
T controller;
return AerToPy::to_python(controller.available_devices());
}
};

template <typename T>
Expand Down Expand Up @@ -100,6 +105,11 @@ void bind_aer_controller(MODULE m) {
return self.execute(circuits, noise_model_native, config);
});

aer_ctrl.def("available_devices",
[aer_ctrl](ControllerExecutor<Controller> &self) {
return self.available_devices();
});

py::class_<Config> aer_config(m, "AerConfig");
aer_config.def(py::init());
aer_config.def_readwrite("shots", &Config::shots);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
fixes:
- |
This fix changes `device` query method from running simple circuit to
search devices from C++ binary to prevent initializing GPUs at
initialization phase and simulation methods are listed in Python code.
Aer built with GPU support will not initialize when `device=CPU` is used.
And only initialize and access GPUs defined in `target_gpus` option.
83 changes: 43 additions & 40 deletions src/controllers/aer_controller.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ namespace AER {

class Controller {
public:
Controller() { clear_parallelization(); }
Controller() {}

//-----------------------------------------------------------------------
// Execute qobj
Expand All @@ -96,8 +96,8 @@ class Controller {
// config settings will be passed to the State and Data classes
void set_config(const Config &config);

// Clear the current config
void clear_config();
// return available devicess
std::vector<std::string> available_devices();

protected:
//-----------------------------------------------------------------------
Expand Down Expand Up @@ -162,9 +162,6 @@ class Controller {
// Parallelization Config
//-----------------------------------------------------------------------

// Set OpenMP thread settings to default values
void clear_parallelization();

// Set parallelization for experiments
void set_parallelization_experiments(const reg_t &required_memory_list);

Expand All @@ -175,18 +172,18 @@ class Controller {
size_t get_gpu_memory_mb();

// The maximum number of threads to use for various levels of parallelization
int max_parallel_threads_;
int max_parallel_threads_ = 0;

// Parameters for parallelization management in configuration
int max_parallel_experiments_;
size_t max_memory_mb_;
size_t max_gpu_memory_mb_;
int max_parallel_experiments_ = 1;
size_t max_memory_mb_ = 0;
size_t max_gpu_memory_mb_ = 0;

// use explicit parallelization
bool explicit_parallelization_;
bool explicit_parallelization_ = false;

// Parameters for parallelization management for experiments
int parallel_experiments_;
int parallel_experiments_ = 1;

bool parallel_nested_ = false;

Expand All @@ -197,6 +194,8 @@ class Controller {

// runtime parameter binding
bool runtime_parameter_bind_ = false;

reg_t target_gpus_; // GPUs to be used
};

//=========================================================================
Expand Down Expand Up @@ -231,6 +230,8 @@ void Controller::set_config(const Config &config) {

if (config.max_memory_mb.has_value())
max_memory_mb_ = config.max_memory_mb.value();
else
max_memory_mb_ = get_system_memory_mb();

// for debugging
if (config._parallel_experiments.has_value()) {
Expand Down Expand Up @@ -307,7 +308,21 @@ void Controller::set_config(const Config &config) {
cudaGetLastError();
throw std::runtime_error("No CUDA device available!");
}
if (config.target_gpus.has_value()) {
target_gpus_ = config.target_gpus.value();

if (nDev < target_gpus_.size()) {
throw std::invalid_argument(
"target_gpus has more GPUs than available.");
}
} else {
target_gpus_.resize(nDev);
for (int_t i = 0; i < nDev; i++)
target_gpus_[i] = i;
}
sim_device_ = Device::GPU;

max_gpu_memory_mb_ = get_gpu_memory_mb();
#endif
} else {
throw std::runtime_error(std::string("Invalid simulation device (\"") +
Expand Down Expand Up @@ -338,27 +353,6 @@ void Controller::set_config(const Config &config) {
runtime_parameter_bind_ = config.runtime_parameter_bind_enable.value();
}

void Controller::clear_config() {
clear_parallelization();
method_ = Method::automatic;
sim_device_ = Device::CPU;
sim_precision_ = Precision::Double;
}

void Controller::clear_parallelization() {
max_parallel_threads_ = 0;
max_parallel_experiments_ = 1;

parallel_experiments_ = 1;
parallel_nested_ = false;

num_process_per_experiment_ = 1;

explicit_parallelization_ = false;
max_memory_mb_ = get_system_memory_mb();
max_gpu_memory_mb_ = get_gpu_memory_mb();
}

void Controller::set_parallelization_experiments(
const reg_t &required_memory_mb_list) {

Expand Down Expand Up @@ -420,14 +414,9 @@ size_t Controller::get_system_memory_mb() {
size_t Controller::get_gpu_memory_mb() {
size_t total_physical_memory = 0;
#ifdef AER_THRUST_GPU
int iDev, nDev, j;
if (cudaGetDeviceCount(&nDev) != cudaSuccess) {
cudaGetLastError();
nDev = 0;
}
for (iDev = 0; iDev < nDev; iDev++) {
for (int_t iDev = 0; iDev < target_gpus_.size(); iDev++) {
size_t freeMem, totalMem;
cudaSetDevice(iDev);
cudaSetDevice(target_gpus_[iDev]);
cudaMemGetInfo(&freeMem, &totalMem);
total_physical_memory += totalMem;
}
Expand All @@ -444,6 +433,20 @@ size_t Controller::get_gpu_memory_mb() {
return total_physical_memory >> 20;
}

std::vector<std::string> Controller::available_devices() {
std::vector<std::string> ret;

ret.push_back(std::string("CPU"));
#ifdef AER_THRUST_GPU
ret.push_back(std::string("GPU"));
#else
#ifdef AER_THRUST_CPU
ret.push_back(std::string("Thrust"));
#endif
#endif
return ret;
}

//-------------------------------------------------------------------------
// Qobj execution
//-------------------------------------------------------------------------
Expand Down
11 changes: 7 additions & 4 deletions src/simulators/circuit_executor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -315,9 +315,11 @@ void Executor<state_t>::set_config(const Config &config) {
// set target GPUs
#ifdef AER_THRUST_GPU
int nDev = 0;
if (cudaGetDeviceCount(&nDev) != cudaSuccess) {
cudaGetLastError();
nDev = 0;
if (sim_device_ == Device::GPU) {
if (cudaGetDeviceCount(&nDev) != cudaSuccess) {
cudaGetLastError();
nDev = 0;
}
}
if (config.target_gpus.has_value()) {
target_gpus_ = config.target_gpus.value();
Expand Down Expand Up @@ -457,7 +459,8 @@ void Executor<state_t>::set_parallelization(const Config &config,

if (max_memory_mb_ == 0)
max_memory_mb_ = get_system_memory_mb();
max_gpu_memory_mb_ = get_gpu_memory_mb();
if (sim_device_ == Device::GPU && num_gpus_ > 0)
max_gpu_memory_mb_ = get_gpu_memory_mb();

// number of threads for parallel loop of experiments
parallel_experiments_ = omp_get_num_threads();
Expand Down

0 comments on commit 096e1e3

Please sign in to comment.