Repository: dwavesystems/dwave-cloud-client

Issue:
Add timing output to `dwave sample`
It's useful, and also makes the command output consistent with `dwave ping`.

Discussion:
codecov[bot]: ## [Codecov](https://app.codecov.io/gh/dwavesystems/dwave-cloud-client/pull/575?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dwavesystems) Report
> Merging [#575](https://app.codecov.io/gh/dwavesystems/dwave-cloud-client/pull/575?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dwavesystems) (27a0be3) into [master](https://app.codecov.io/gh/dwavesystems/dwave-cloud-client/commit/68078b1ca19f5534d36b469ac968eaf1c6e6322f?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dwavesystems) (68078b1) will **decrease** coverage by `0.02%`.
> The diff coverage is `83.33%`.

```diff
@@            Coverage Diff             @@
##           master     #575      +/-   ##
==========================================
- Coverage   87.54%   87.53%   -0.02%     
==========================================
  Files          26       26              
  Lines        3678     3690      +12     
==========================================
+ Hits         3220     3230      +10     
- Misses        458      460       +2     
```


| [Files Changed](https://app.codecov.io/gh/dwavesystems/dwave-cloud-client/pull/575?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dwavesystems) | Coverage Δ | |
|---|---|---|
| [dwave/cloud/cli.py](https://app.codecov.io/gh/dwavesystems/dwave-cloud-client/pull/575?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dwavesystems#diff-ZHdhdmUvY2xvdWQvY2xpLnB5) | `63.88% <83.33%> (+0.46%)` | :arrow_up: |

:mega: We’re building smart automated test selection to slash your CI/CD build times. [Learn more](https://about.codecov.io/iterative-testing/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dwavesystems)


Patch:
diff --git a/dwave/cloud/cli.py b/dwave/cloud/cli.py
index 0339064..05a7746 100644
--- a/dwave/cloud/cli.py
+++ b/dwave/cloud/cli.py
@@ -584,6 +584,7 @@ def sample(*, config_file, profile, endpoint, region, client_type, solver_def,
         endpoint=endpoint, region=region,
         client=client_type, solver=solver_def)
 
+    t0 = timer()
     client, solver = _get_client_solver(config, output)
 
     if random_problem:
@@ -617,9 +618,12 @@ def sample(*, config_file, profile, endpoint, region, client_type, solver_def,
     output("Using couplings: {quadratic}", quadratic=list(quadratic.items()), maxlen=maxlen)
     output("Sampling parameters: {sampling_params}", sampling_params=params)
 
+    t1 = timer()
     response = _sample(
         solver, problem=(linear, quadratic), params=params, output=output)
 
+    t2 = timer()
+
     if verbose:
         output("Result: {response!r}", response=response.result())
 
@@ -627,6 +631,17 @@ def sample(*, config_file, profile, endpoint, region, client_type, solver_def,
     output("Occurrences: {num_occurrences!r}", num_occurrences=response.num_occurrences, maxlen=maxlen)
     output("Energies: {energies!r}", energies=response.energies, maxlen=maxlen)
 
+    output("\nWall clock time:")
+    output(" * Solver definition fetch: {wallclock_solver_definition:.3f} ms", wallclock_solver_definition=(t1-t0)*1000.0)
+    output(" * Problem submit and results fetch: {wallclock_sampling:.3f} ms", wallclock_sampling=(t2-t1)*1000.0)
+    output(" * Total: {wallclock_total:.3f} ms", wallclock_total=(t2-t0)*1000.0)
+    if response.timing:
+        output("\nQPU timing:")
+        for component, duration in sorted(response.timing.items()):
+            output(" * %(name)s = {%(name)s} us" % {"name": component}, **{component: duration})
+    else:
+        output("\nQPU timing data not available.")
+
 
 @cli.command()
 @config_file_options()
diff --git a/releasenotes/notes/add-timing-output-to-dwave-sample-e3adb8b197921e8d.yaml b/releasenotes/notes/add-timing-output-to-dwave-sample-e3adb8b197921e8d.yaml
new file mode 100644
index 0000000..988c8e2
--- /dev/null
+++ b/releasenotes/notes/add-timing-output-to-dwave-sample-e3adb8b197921e8d.yaml
@@ -0,0 +1,5 @@
+---
+features:
+  - |
+    Add wall time and QPU timing to ``dwave sample`` output.
+    See `#570 <https://github.com/dwavesystems/dwave-cloud-client/issues/570>`_.


Test patch:
diff --git a/tests/test_cli.py b/tests/test_cli.py
index b1207e6..598ad30 100644
--- a/tests/test_cli.py
+++ b/tests/test_cli.py
@@ -279,6 +279,9 @@ class TestCli(unittest.TestCase):
             solver.sample_ising.assert_called_with(
                 {3: 0}, {}, label=label, **params)
 
+            # verify output contains timing data
+            self.assertIn('Wall clock time', result.output)
+
         self.assertEqual(result.exit_code, 0)
 
     @parameterized.expand([
@@ -325,6 +328,9 @@ class TestCli(unittest.TestCase):
             s.sample_ising.assert_called_with(
                 {0: 0}, {(0, 4): 1}, num_reads=10, label=label)
 
+            # verify output contains timing data
+            self.assertIn('Wall clock time', result.output)
+
         self.assertEqual(result.exit_code, 0)
 
     @parameterized.expand([