Skip to content

Commit 07765a7

Browse files
billtisezna
andauthored
Initial Python telemetry (#1972)
Python feature usage telemetry. --------- Co-authored-by: Alexander Hansen <[email protected]> Co-authored-by: sezna <[email protected]>
1 parent bedd810 commit 07765a7

File tree

6 files changed

+439
-5
lines changed

6 files changed

+439
-5
lines changed

pip/README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,13 @@ operation BellState() : Unit {
3939
BellState()
4040
```
4141

42+
## Telemetry
43+
44+
This library sends telemetry. Minimal anonymous data is collected to help measure feature usage and performance.
45+
All telemetry events can be seen in the source file [telemetry_events.py](https://github.com/microsoft/qsharp/tree/main/pip/qsharp/telemetry_events.py).
46+
47+
To disable sending telemetry from this package, set the environment variable `QSHARP_PYTHON_TELEMETRY=none`
48+
4249
## Support
4350

4451
For more information about the Azure Quantum Development Kit, visit [https://aka.ms/AQ/Documentation](https://aka.ms/AQ/Documentation).

pip/qsharp/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Copyright (c) Microsoft Corporation.
22
# Licensed under the MIT License.
33

4+
from . import telemetry_events
45
from ._qsharp import (
56
init,
67
eval,
@@ -20,6 +21,8 @@
2021
PhaseFlipNoise,
2122
)
2223

24+
telemetry_events.on_import()
25+
2326
from ._native import Result, Pauli, QSharpError, TargetProfile
2427

2528
# IPython notebook specific features

pip/qsharp/_qsharp.py

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Copyright (c) Microsoft Corporation.
22
# Licensed under the MIT License.
33

4+
from . import telemetry_events
45
from ._native import (
56
Interpreter,
67
TargetProfile,
@@ -23,8 +24,10 @@
2324
from .estimator._estimator import EstimatorResult, EstimatorParams
2425
import json
2526
import os
27+
from time import monotonic
2628

2729
_interpreter = None
30+
_config = None
2831

2932
# Check if we are running in a Jupyter notebook to use the IPython display function
3033
_in_jupyter = False
@@ -161,6 +164,7 @@ def init(
161164
from ._http import fetch_github
162165

163166
global _interpreter
167+
global _config
164168

165169
if isinstance(target_name, str):
166170
target = target_name.split(".")[0].lower()
@@ -198,9 +202,10 @@ def init(
198202
fetch_github,
199203
)
200204

205+
_config = Config(target_profile, language_features, manifest_contents, project_root)
201206
# Return the configuration information to provide a hint to the
202207
# language service through the cell output.
203-
return Config(target_profile, language_features, manifest_contents, project_root)
208+
return _config
204209

205210

206211
def get_interpreter() -> Interpreter:
@@ -286,6 +291,9 @@ def run(
286291
if shots < 1:
287292
raise QSharpError("The number of shots must be greater than 0.")
288293

294+
telemetry_events.on_run(shots)
295+
start_time = monotonic()
296+
289297
results: List[ShotResult] = []
290298

291299
def print_output(output: Output) -> None:
@@ -317,6 +325,9 @@ def on_save_events(output: Output) -> None:
317325
# compilation.
318326
entry_expr = None
319327

328+
durationMs = (monotonic() - start_time) * 1000
329+
telemetry_events.on_run_end(durationMs, shots)
330+
320331
if save_events:
321332
return results
322333
else:
@@ -366,10 +377,15 @@ def compile(entry_expr: str) -> QirInputData:
366377
file.write(str(program))
367378
"""
368379
ipython_helper()
369-
380+
start = monotonic()
381+
global _config
382+
target_profile = _config._config.get("targetProfile", "unspecified")
383+
telemetry_events.on_compile(target_profile)
370384
ll_str = get_interpreter().qir(entry_expr)
371-
return QirInputData("main", ll_str)
372-
385+
res = QirInputData("main", ll_str)
386+
durationMs = (monotonic() - start) * 1000
387+
telemetry_events.on_compile_end(durationMs, target_profile)
388+
return res
373389

374390
def circuit(
375391
entry_expr: Optional[str] = None, *, operation: Optional[str] = None
@@ -421,9 +437,18 @@ def _coerce_estimator_params(
421437

422438
params = _coerce_estimator_params(params)
423439
param_str = json.dumps(params)
424-
440+
telemetry_events.on_estimate()
441+
start = monotonic()
425442
res_str = get_interpreter().estimate(entry_expr, param_str)
426443
res = json.loads(res_str)
444+
445+
try:
446+
qubits = res[0]["logicalCounts"]["numQubits"]
447+
except (KeyError, IndexError):
448+
qubits = "unknown"
449+
450+
durationMs = (monotonic() - start) * 1000
451+
telemetry_events.on_estimate_end(durationMs, qubits)
427452
return EstimatorResult(res)
428453

429454

0 commit comments

Comments
 (0)