Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Avoid accessing GPUs when using CPU only #2012

Merged
merged 3 commits into from
Dec 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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