Skip to content

Commit

Permalink
reduce overhead of profiling
Browse files Browse the repository at this point in the history
  • Loading branch information
hhorii committed Apr 8, 2021
1 parent 14b7803 commit fdb7b4f
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 51 deletions.
84 changes: 45 additions & 39 deletions qiskit/providers/aer/profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@


def profile_performance_options(min_qubits=10, max_qubits=25, ntrials=10,
circuit=None, persist=True):
circuit=None, persist=True, gpu=False):
"""Set optimal OpenMP and fusion options for backend."""
# Profile
profile = {}
Expand All @@ -42,13 +42,15 @@ def profile_performance_options(min_qubits=10, max_qubits=25, ntrials=10,
pass

# Profile CPU and GPU fusion threshold
for gpu in (False, True):
postfix = '_gpu' if gpu else ''
for with_gpu in (False, True):
postfix = '_gpu' if with_gpu else ''
if with_gpu and not gpu:
continue
try:
qubit_to_costs = profile_fusion_costs(min_qubits=min_qubits,
max_qubits=max_qubits,
ntrials=ntrials,
gpu=gpu,
gpu=with_gpu,
diagonal=False)
for num_qubits in qubit_to_costs:
costs = qubit_to_costs[num_qubits]
Expand All @@ -57,7 +59,7 @@ def profile_performance_options(min_qubits=10, max_qubits=25, ntrials=10,
_PerformanceOptions._set_option(f'fusion_cost{postfix}.{num_qubits}.{i + 1}',
costs[i], persist)

fusion_threshold = profile_fusion_threshold(gpu=gpu,
fusion_threshold = profile_fusion_threshold(gpu=with_gpu,
min_qubits=min_qubits,
max_qubits=max_qubits,
ntrials=ntrials,
Expand Down Expand Up @@ -270,15 +272,17 @@ def global_qubit(index):
return profile_circuit


def _profile_run(simulator, ntrials, backend_options,
qubit, circuit, basis_gates=None, use_time_taken=False):
def _profile_run(simulator, ntrials, backend_options, qubit, circuit,
basis_gates=None, use_time_taken=False, return_all=False):

profile_circuit = _generate_profile_circuit(qubit, circuit, basis_gates)

qobj = assemble(profile_circuit, shots=1)

total_time_taken = 0.0
time_taken_list = []
total_time_elapsed = 0.0
time_elapsed_list = []
for _ in range(ntrials):
start_ts = time.time()
result = simulator.run(qobj, **backend_options).result()
Expand All @@ -288,12 +292,20 @@ def _profile_run(simulator, ntrials, backend_options,
raise AerError('Failed to run a profile circuit')

total_time_taken += result.results[0].time_taken
time_taken_list.append(result.results[0].time_taken)
total_time_elapsed += (end_ts - start_ts)
time_elapsed_list.append(end_ts - start_ts)

if use_time_taken:
return total_time_taken
if return_all:
return time_taken_list
else:
return total_time_taken
else:
return total_time_elapsed
if return_all:
return time_elapsed_list
else:
return total_time_elapsed


def profile_parallel_threshold(min_qubits=10, max_qubits=20, ntrials=10,
Expand All @@ -316,21 +328,18 @@ def profile_parallel_threshold(min_qubits=10, max_qubits=20, ntrials=10,

ratios = []
for qubit in range(min_qubits, max_qubits + 1):
always_better = True
for _ in range(10):
profile_opts['statevector_parallel_threshold'] = 64
serial_time_taken = _profile_run(simulator, ntrials, profile_opts,
qubit, circuit, basis_gates)
profile_opts['statevector_parallel_threshold'] = 1
parallel_time_taken = _profile_run(simulator, ntrials, profile_opts,
qubit, circuit, basis_gates)
if return_ratios:
ratios.append(serial_time_taken / parallel_time_taken)
break
if parallel_time_taken >= serial_time_taken:
always_better = False
break
if not return_ratios and always_better:
profile_opts['statevector_parallel_threshold'] = 64
serial_time_taken = _profile_run(simulator, ntrials, profile_opts,
qubit, circuit, basis_gates, return_all=True)
profile_opts['statevector_parallel_threshold'] = 1
parallel_time_taken = _profile_run(simulator, ntrials, profile_opts,
qubit, circuit, basis_gates, return_all=True)
if return_ratios:
ratios.append(sum(serial_time_taken) / sum(parallel_time_taken))
break
if max(parallel_time_taken) >= min(serial_time_taken):
continue
if not return_ratios:
return qubit - 1

if return_ratios:
Expand Down Expand Up @@ -368,21 +377,18 @@ def profile_fusion_threshold(min_qubits=10, max_qubits=20, ntrials=10,

ratios = []
for qubit in range(min_qubits, max_qubits + 1):
always_better = True
for _ in range(10):
profile_opts['fusion_enable'] = False
non_fusion_time_taken = _profile_run(simulator, ntrials, profile_opts,
qubit, circuit, basis_gates)
profile_opts['fusion_enable'] = True
fusion_time_taken = _profile_run(simulator, ntrials, profile_opts,
qubit, circuit, basis_gates)
if return_ratios:
ratios.append(non_fusion_time_taken / fusion_time_taken)
break
if fusion_time_taken >= non_fusion_time_taken:
always_better = False
break
if not return_ratios and always_better:
profile_opts['fusion_enable'] = False
non_fusion_time_taken = _profile_run(simulator, ntrials, profile_opts,
qubit, circuit, basis_gates, return_all=True)
profile_opts['fusion_enable'] = True
fusion_time_taken = _profile_run(simulator, ntrials, profile_opts,
qubit, circuit, basis_gates, return_all=True)
if return_ratios:
ratios.append(sum(non_fusion_time_taken) / sum(fusion_time_taken))
break
if max(fusion_time_taken) >= min(non_fusion_time_taken):
continue
if not return_ratios:
return qubit - 1

if return_ratios:
Expand Down
13 changes: 1 addition & 12 deletions test/terra/backends/test_profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
get_performance_options,
clear_performance_options)

@unittest.skip("Remove this for manual run")
#@unittest.skip("Remove this for manual run")
class TestProfileQasmSimulator(common.QiskitAerTestCase):


Expand Down Expand Up @@ -68,19 +68,15 @@ def test_profile_save(self):

clear_performance_options(False)

statevector_parallel_threshold = None
fusion_cost = None
fusion_cost_qubit = None

for qubit in range(10, 25):
profile = get_performance_options(qubit)
if 'statevector_parallel_threshold' in profile:
statevector_parallel_threshold = profile['statevector_parallel_threshold']
if 'fusion_cost.1' in profile:
fusion_cost = profile['fusion_cost.1']
fusion_cost_qubit = qubit

self.assertTrue(statevector_parallel_threshold is not None)
self.assertTrue(fusion_cost is not None)

circuit = QuantumVolume(fusion_cost_qubit + 1, 1)
Expand All @@ -96,16 +92,9 @@ def test_profile_save(self):

for qubit in range(10, 25):
profile = get_performance_options(qubit)
if 'statevector_parallel_threshold' in profile:
statevector_parallel_threshold = profile['statevector_parallel_threshold']
if 'fusion_threshold' in profile:
fusion_threshold = profile['fusion_threshold']
if 'fusion_cost.1' in profile:
fusion_cost = profile['fusion_cost.1']
fusion_cost_qubit = qubit

self.assertFalse(statevector_parallel_threshold is not None)
self.assertFalse(fusion_threshold is not None)
self.assertFalse(fusion_cost is not None)

def test_profile_with_custom_circuit(self):
Expand Down

0 comments on commit fdb7b4f

Please sign in to comment.