Repository: IntelPython/dpctl
Pull request #2054: task: benchmarking with asv
Author: login: jharlow-intel
Labels: name: 2 - Ready for Review
Created: 2025-04-15T16:50:33Z | Merged: 2025-04-17T17:04:44Z

This PR introduces ASV benchmarks to the repo.
You can find links to ASV's documentation in the added README

Once this is merged, the infra team can start finalizing the work to add these executions to the CI, allowing instant feedback on benchmarks and performance regressions during development.

The benchmarks were tested pretty exhaustively, but please let me know if I need to tweak any of the parameters or add additional benchmark cases. They work for both CPU and GPU SYCL devices as well. 




Diff:
diff --git a/.gitignore b/.gitignore
index feb538de6b..093cbba81f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -102,3 +102,6 @@ dpctl/tensor/_usmarray.h
 
 # moved cmake scripts
 dpctl/resources/cmake
+
+# asv artifacts
+*.asv*
diff --git a/benchmarks/README.md b/benchmarks/README.md
new file mode 100644
index 0000000000..513ad48ec9
--- /dev/null
+++ b/benchmarks/README.md
@@ -0,0 +1,22 @@
+# dpctl benchmarks
+
+Benchmarking dpctl using Airspeed Velocity
+Read more about ASV [here](https://asv.readthedocs.io/en/stable/index.html)
+
+## Usage
+The benchmarks were made with using an existing environment in-mind before execution. You will see the `asv.conf.json` is minimal without any environmental information supplied.
+The expectation is for users to execute `asv run` with an existing environment.
+
+As such, you should have conda or mamba installed, and create an environment [following these instructions](https://intelpython.github.io/dpctl/latest/beginners_guides/installation.html#dpctl-installation)
+Additionally, install `asv` and `libmambapy` to the environment.
+
+Then, you may activate the environment and instruct `asv run` to use this existing environment for the benchmarks by pointing it to the environment's python binary, like so:
+```
+conda activate dpctl_env
+asv run --environment existing:/full/mamba/path/envs/dpctl_env/bin/python
+```
+
+For `level_zero` devices, you might see `USM Allocation` errors unless you use the `asv run` command with `--launch-method spawn`
+
+## Writing new benchmarks
+Read ASV's guidelines for writing benchmarks [here](https://asv.readthedocs.io/en/stable/writing_benchmarks.html)
diff --git a/benchmarks/asv.conf.json b/benchmarks/asv.conf.json
new file mode 100644
index 0000000000..478dc518f9
--- /dev/null
+++ b/benchmarks/asv.conf.json
@@ -0,0 +1,53 @@
+{
+    // The version of the config file format.  Do not change, unless
+    // you know what you are doing.
+    "version": 1,
+
+    // The name of the project being benchmarked
+    "project": "dpctl",
+
+    // The project's homepage
+    "project_url": "https://github.com/IntelPython/dpctl",
+
+    // The URL or local path of the source code repository for the
+    // project being benchmarked
+    "repo": "..",
+
+    // Customizable commands for building the project.
+    // See asv.conf.json documentation.
+    "build_command": [],
+
+    // List of branches to benchmark. If not provided, defaults to "main"
+    // (for git) or "default" (for mercurial).
+    "branches": ["HEAD"],
+
+    // The DVCS being used.  If not set, it will be automatically
+    // determined from "repo" by looking at the protocol in the URL
+    // (if remote), or by looking for special directories, such as
+    // ".git" (if local).
+    "dvcs": "git",
+
+    // The tool to use to create environments.  May be "conda",
+    // "virtualenv", "mamba" (above 3.8)
+    // or other value depending on the plugins in use.
+    // If missing or the empty string, the tool will be automatically
+    // determined by looking for tools on the PATH environment
+    // variable.
+    "environment_type": "conda",
+
+    // The directory (relative to the current directory) that benchmarks are
+    // stored in.  If not provided, defaults to "benchmarks"
+    "benchmark_dir": "benchmarks",
+
+    // The directory (relative to the current directory) to cache the Python
+    // environments in.  If not provided, defaults to "env"
+    "env_dir": ".asv/env",
+
+    // The directory (relative to the current directory) that raw benchmark
+    // results are stored in.  If not provided, defaults to "results".
+    "results_dir": ".asv/results",
+
+    // The directory (relative to the current directory) that the html tree
+    // should be written to.  If not provided, defaults to "html".
+    "html_dir": ".asv/html"
+}
diff --git a/benchmarks/benchmarks/__init__.py b/benchmarks/benchmarks/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/benchmarks/benchmarks/benchmark_utils.py b/benchmarks/benchmarks/benchmark_utils.py
new file mode 100644
index 0000000000..7d493d1cd6
--- /dev/null
+++ b/benchmarks/benchmarks/benchmark_utils.py
@@ -0,0 +1,17 @@
+from asv_runner.benchmarks.mark import SkipNotImplemented
+
+import dpctl.tensor as dpt
+
+
+def skip_unsupported_dtype(q, dtype):
+    """
+    Skip the benchmark if the device does not support the given data type.
+    """
+    if (
+        (dtype == dpt.float64 or dtype.name == dpt.complex128)
+        and not q.sycl_device.has_aspect_fp64
+    ) or (dtype == dpt.float16 and not q.sycl_device.has_aspect_fp16):
+        raise SkipNotImplemented(
+            f"Skipping benchmark for {dtype.name} on this device"
+            + " as it is not supported."
+        )
diff --git a/benchmarks/benchmarks/binary.py b/benchmarks/benchmarks/binary.py
new file mode 100644
index 0000000000..49d08d09d6
--- /dev/null
+++ b/benchmarks/benchmarks/binary.py
@@ -0,0 +1,133 @@
+import dpctl
+import dpctl.tensor as dpt
+
+from . import benchmark_utils as bench_utils
+
+SHARED_QUEUE = dpctl.SyclQueue(property="enable_profiling")
+
+
+class Binary:
+    """Benchmark class for binary operations on SYCL devices."""
+
+    timeout = 300.0
+
+    def setup(self):
+        """Setup the benchmark environment."""
+        self.q = SHARED_QUEUE
+        self.iterations = 1
+        self.n_values = 10**8
+
+    def run_bench(self, q, reps, n_max, dtype1, dtype2, op):
+        """Run the benchmark for a specific function and dtype combination."""
+
+        def get_sizes(n):
+            s = []
+            m = 8192
+            while m < n:
+                s.append(m)
+                m *= 2
+            s.append(n)
+            return s
+
+        x1 = dpt.ones(n_max, dtype=dtype1, sycl_queue=q)
+        x2 = dpt.ones(n_max, dtype=dtype2, sycl_queue=q)
+        r = op(x1, x2)
+
+        max_bytes = x1.nbytes + x2.nbytes + r.nbytes
+        times_res = []
+
+        for n in get_sizes(n_max):
+            x1_n = x1[:n]
+            x2_n = x2[:n]
+            r_n = r[:n]
+            n_bytes = x1_n.nbytes + x2_n.nbytes + r_n.nbytes
+
+            n_iters = int((max_bytes / n_bytes) * reps)
+
+            while True:
+                timer = dpctl.SyclTimer(
+                    device_timer="order_manager", time_scale=1e9
+                )
+                with timer(q):
+                    for _ in range(n_iters):
+                        op(x1_n, x2_n, out=r_n)
+
+                dev_dt = timer.dt.device_dt
+                if dev_dt > 0:
+                    times_res.append((n, dev_dt / n_iters))
+                    break
+
+        return times_res
+
+
+binary_instance = Binary()
+binary_instance.q = SHARED_QUEUE
+binary_instance.iterations = 1
+binary_instance.n_values = 10**8
+
+function_list = [
+    dpt.add,
+    dpt.multiply,
+    dpt.divide,
+    dpt.subtract,
+    dpt.floor_divide,
+    dpt.remainder,
+    dpt.hypot,
+    dpt.logaddexp,
+    dpt.pow,
+    dpt.atan2,
+    dpt.nextafter,
+    dpt.copysign,
+    dpt.less,
+    dpt.less_equal,
+    dpt.greater,
+    dpt.greater_equal,
+    dpt.equal,
+    dpt.not_equal,
+    dpt.minimum,
+    dpt.maximum,
+    dpt.bitwise_and,
+    dpt.bitwise_or,
+    dpt.bitwise_xor,
+    dpt.bitwise_left_shift,
+    dpt.bitwise_right_shift,
+    dpt.logical_and,
+    dpt.logical_or,
+    dpt.logical_xor,
+]
+
+# Generate dtype combinations for each function
+dtypes = {}
+for fn in function_list:
+    dtypes[fn] = [list(map(dpt.dtype, sig.split("->")[0])) for sig in fn.types]
+
+
+# Dynamically create benchmark methods at the module level
+def generate_benchmark_functions():
+    """Dynamically create benchmark functions for each
+    function and dtype combination.
+    """
+    for fn in function_list:
+        fn_name = fn.name_
+        for dtype1, dtype2 in dtypes[fn]:
+            # Create unique function names
+            method_name = f"time_{fn_name}_{dtype1.name}_{dtype2.name}"
+
+            def benchmark_method(self, fn=fn, dtype1=dtype1, dtype2=dtype2):
+                bench_utils.skip_unsupported_dtype(self.q, dtype1)
+                return self.run_bench(
+                    self.q,
+                    self.iterations,
+                    self.n_values,
+                    dtype1,
+                    dtype2,
+                    fn,
+                )
+
+            benchmark_method.__name__ = method_name
+            # Attach the new method to the Binary class
+            setattr(Binary, method_name, benchmark_method)
+
+
+# Generate the benchmark functions
+generate_benchmark_functions()
diff --git a/benchmarks/benchmarks/ef_bench_add.py b/benchmarks/benchmarks/ef_bench_add.py
new file mode 100644
index 0000000000..f17f8613d2
--- /dev/null
+++ b/benchmarks/benchmarks/ef_bench_add.py
@@ -0,0 +1,31 @@
+import dpctl
+import dpctl.tensor as dpt
+import dpctl.tensor._tensor_elementwise_impl as tei
+import dpctl.utils as dpu
+
+
+class EfBenchAdd:
+
+    def time_ef_bench_add(self):
+        q = dpctl.SyclQueue(property="enable_profiling")
+        n = 2**26
+        reps = 50
+
+        dt = dpt.int8
+        x1 = dpt.ones(n, dtype=dt, sycl_queue=q)
+        x2 = dpt.ones(n, dtype=dt, sycl_queue=q)
+
+        op1, op2 = dpt.add, tei._add
+
+        r = op1(x1, x2)
+
+        timer = dpctl.SyclTimer(device_timer="order_manager", time_scale=1e9)
+
+        m = dpu.SequentialOrderManager[q]
+        with timer(q):
+            for _ in range(reps):
+                deps = m.submitted_events
+                ht_e, c_e = op2(
+                    src1=x1, src2=x2, dst=r, sycl_queue=q, depends=deps
+                )
+                m.add_event_pair(ht_e, c_e)


Reviews:
user: login: ndgrigorian
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-15T18:30:48Z
user: login: ndgrigorian
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-15T18:34:00Z
user: login: ndgrigorian
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-16T08:36:26Z
user: login: jharlow-intel
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-16T16:36:30Z
user: login: ndgrigorian
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-04-16T20:59:43Z
user: login: jharlow-intel
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-17T13:43:42Z
user: login: ndgrigorian
body: Regardless of outcome of OS compiler build this LGTM

Thank you @jharlow-intel for working on this
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-04-17T16:32:36Z

Review comments:
diff_hunk: @@ -0,0 +1,24 @@
+# dpctl benchmarks
+
+Benchmarking dpctl using Airspeed Velocity
+Read more about ASV [here](https://asv.readthedocs.io/en/stable/index.html)
+
+## Usage
+This was made for use within our CI in mind. As such, you will see the `asv.conf.json` is minimal without any environmental information supplied.
+The expectation is for users to execute `asv run` with an existing environment.
+
+As such, you should have conda or mamba installed, and create a `dpctl-benchmarking` environment as so:
+```
+conda create --name dpctl-benchmarking python=$PYTHON_VERSION dpctl asv libmambapy conda dpcpp_linux-64 --override-channels \
+        -c https://software.repos.intel.com/python/conda \
+        -c conda-forge -y
+```
path: benchmarks/README.md
user: login: ndgrigorian
body: I think this should be re-written from more of a user perspective, as in, I think we should encourage users to run these benchmarks locally, regardless of our intention to use in CI.

The `conda` command also only handles case where the user does not have oneAPI locally installed. We can just refer to creating an environment using the [installation instructions](https://intelpython.github.io/dpctl/latest/beginners_guides/installation.html#dpctl-installation)

then instruct to install addition dependencies (asv, libmamabapy)
created_at: 2025-04-15T18:30:48Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,182 @@
+{
+    // The version of the config file format.  Do not change, unless
+    // you know what you are doing.
+    "version": 1,
+
+    // The name of the project being benchmarked
+    "project": "dpctl",
+
+    // The project's homepage
+    "project_url": "https://github.com/IntelPython/dpctl",
+
+    // The URL or local path of the source code repository for the
+    // project being benchmarked
+    "repo": "..",
+
+    // The Python project's subdirectory in your repo.  If missing or
+    // the empty string, the project is assumed to be located at the root
+    // of the repository.
+    // "repo_subdir": "",
+
+    // Customizable commands for building the project.
+    // See asv.conf.json documentation.
+    "build_command": [],
+
+    // Customizable commands for installing and uninstalling the project.
+    // See asv.conf.json documentation.
+    // "install_command": ["in-dir={env_dir} conda install dpctl --yes"],
+    // "uninstall_command": ["return-code=any conda uninstall dpctl --yes"],
+
+    // List of branches to benchmark. If not provided, defaults to "main"
+    // (for git) or "default" (for mercurial).
+    "branches": ["HEAD"], // for git
+    // "branches": ["default"],    // for mercurial
+
+    // The DVCS being used.  If not set, it will be automatically
+    // determined from "repo" by looking at the protocol in the URL
+    // (if remote), or by looking for special directories, such as
+    // ".git" (if local).
+    "dvcs": "git",
+
+    // The tool to use to create environments.  May be "conda",
+    // "virtualenv", "mamba" (above 3.8)
+    // or other value depending on the plugins in use.
+    // If missing or the empty string, the tool will be automatically
+    // determined by looking for tools on the PATH environment
+    // variable.
+    "environment_type": "conda",
+
+    // timeout in seconds for installing any dependencies in environment
+    // defaults to 10 min
+    //"install_timeout": 600,
+
+    // the base URL to show a commit for the project.
+    // "show_commit_url": "http://github.com/owner/project/commit/",
+
+    // The Pythons you'd like to test against.  If not provided, defaults
+    // to the current version of Python used to run `asv`.
+    // "pythons": ["3.8", "3.12"],
+
+    // The list of conda channel names to be searched for benchmark
+    // dependency packages in the specified order
+    // "conda_channels": [
+    //     "https://af01p-igk.devtools.intel.com/artifactory/api/conda/idp-conda-pkgserver-igk-local/gold",
+    //     "https://af01p-igk.devtools.intel.com/artifactory/api/conda/idp-conda-pkgserver-igk-local/tools",
path: benchmarks/asv.conf.json
user: login: ndgrigorian
body: This goes with my previous comment, external users won't have access to these channels, so the conf won't work for them.

Maybe we should stick to just the Intel channel and benchmark against the version of dpctl on dppy/label/dev, or maybe somehow we can have two configurations? One which we use in the CI and one which is exposed for users.
created_at: 2025-04-15T18:34:00Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,130 @@
+import dpctl
+import dpctl.tensor as dpt
+
+SHARED_QUEUE = dpctl.SyclQueue(property="enable_profiling")
+
+
+class Binary:
+    """Benchmark class for binary operations on SYCL devices."""
+
+    timeout = 300.0
+
+    def setup(self):
+        """Setup the benchmark environment."""
+        self.q = SHARED_QUEUE
+        self.iterations = 1
+        self.n_values = 10**8
+
+    def run_bench(self, q, reps, n_max, dtype1, dtype2, op):
+        """Run the benchmark for a specific function and dtype combination."""
+
+        def get_sizes(n):
+            s = []
+            m = 8192
+            while m < n:
+                s.append(m)
+                m *= 2
+            s.append(n)
+            return s
+
+        x1 = dpt.ones(n_max, dtype=dtype1, sycl_queue=q)
+        x2 = dpt.ones(n_max, dtype=dtype2, sycl_queue=q)
+        r = op(x1, x2)
+
+        max_bytes = x1.nbytes + x2.nbytes + r.nbytes
+        times_res = []
+
+        for n in get_sizes(n_max):
+            x1_n = x1[:n]
+            x2_n = x2[:n]
+            r_n = r[:n]
+            n_bytes = x1_n.nbytes + x2_n.nbytes + r_n.nbytes
+
+            n_iters = int((max_bytes / n_bytes) * reps)
+
+            while True:
+                timer = dpctl.SyclTimer(
+                    device_timer="order_manager", time_scale=1e9
+                )
+                with timer(q):
+                    for _ in range(n_iters):
+                        op(x1_n, x2_n, out=r_n)
+
+                dev_dt = timer.dt.device_dt
+                if dev_dt > 0:
+                    times_res.append((n, dev_dt / n_iters))
+                    break
+
+        return times_res
+
+
+binary_instance = Binary()
+binary_instance.q = SHARED_QUEUE
+binary_instance.iterations = 1
+binary_instance.n_values = 10**8
+
+function_list = [
+    dpt.add,
+    dpt.multiply,
+    dpt.divide,
+    dpt.subtract,
+    dpt.floor_divide,
+    dpt.remainder,
+    dpt.hypot,
+    dpt.logaddexp,
+    dpt.pow,
+    dpt.atan2,
+    dpt.nextafter,
+    dpt.copysign,
+    dpt.less,
+    dpt.less_equal,
+    dpt.greater,
+    dpt.greater_equal,
+    dpt.equal,
+    dpt.not_equal,
+    dpt.minimum,
+    dpt.maximum,
+    dpt.bitwise_and,
+    dpt.bitwise_or,
+    dpt.bitwise_xor,
+    dpt.bitwise_left_shift,
+    dpt.bitwise_right_shift,
+    dpt.logical_and,
+    dpt.logical_or,
+    dpt.logical_xor,
+]
+
+# Generate dtype combinations for each function
+dtypes = {}
+for fn in function_list:
+    dtypes[fn] = [list(map(dpt.dtype, sig.split("->")[0])) for sig in fn.types]
+
+
+# Dynamically create benchmark methods at the module level
+def generate_benchmark_functions():
+    """Dynamically create benchmark functions for each
+    function and dtype combination.
+    """
+    for fn in function_list:
+        fn_name = fn.name_
+        for dtype1, dtype2 in dtypes[fn]:
path: benchmarks/benchmarks/binary.py
user: login: ndgrigorian
body: Mentioned offline but we will need utilities to skip `fp64` and `fp16`, as some devices lack support for these types
created_at: 2025-04-16T08:36:26Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,130 @@
+import dpctl
+import dpctl.tensor as dpt
+
+SHARED_QUEUE = dpctl.SyclQueue(property="enable_profiling")
+
+
+class Binary:
+    """Benchmark class for binary operations on SYCL devices."""
+
+    timeout = 300.0
+
+    def setup(self):
+        """Setup the benchmark environment."""
+        self.q = SHARED_QUEUE
+        self.iterations = 1
+        self.n_values = 10**8
+
+    def run_bench(self, q, reps, n_max, dtype1, dtype2, op):
+        """Run the benchmark for a specific function and dtype combination."""
+
+        def get_sizes(n):
+            s = []
+            m = 8192
+            while m < n:
+                s.append(m)
+                m *= 2
+            s.append(n)
+            return s
+
+        x1 = dpt.ones(n_max, dtype=dtype1, sycl_queue=q)
+        x2 = dpt.ones(n_max, dtype=dtype2, sycl_queue=q)
+        r = op(x1, x2)
+
+        max_bytes = x1.nbytes + x2.nbytes + r.nbytes
+        times_res = []
+
+        for n in get_sizes(n_max):
+            x1_n = x1[:n]
+            x2_n = x2[:n]
+            r_n = r[:n]
+            n_bytes = x1_n.nbytes + x2_n.nbytes + r_n.nbytes
+
+            n_iters = int((max_bytes / n_bytes) * reps)
+
+            while True:
+                timer = dpctl.SyclTimer(
+                    device_timer="order_manager", time_scale=1e9
+                )
+                with timer(q):
+                    for _ in range(n_iters):
+                        op(x1_n, x2_n, out=r_n)
+
+                dev_dt = timer.dt.device_dt
+                if dev_dt > 0:
+                    times_res.append((n, dev_dt / n_iters))
+                    break
+
+        return times_res
+
+
+binary_instance = Binary()
+binary_instance.q = SHARED_QUEUE
+binary_instance.iterations = 1
+binary_instance.n_values = 10**8
+
+function_list = [
+    dpt.add,
+    dpt.multiply,
+    dpt.divide,
+    dpt.subtract,
+    dpt.floor_divide,
+    dpt.remainder,
+    dpt.hypot,
+    dpt.logaddexp,
+    dpt.pow,
+    dpt.atan2,
+    dpt.nextafter,
+    dpt.copysign,
+    dpt.less,
+    dpt.less_equal,
+    dpt.greater,
+    dpt.greater_equal,
+    dpt.equal,
+    dpt.not_equal,
+    dpt.minimum,
+    dpt.maximum,
+    dpt.bitwise_and,
+    dpt.bitwise_or,
+    dpt.bitwise_xor,
+    dpt.bitwise_left_shift,
+    dpt.bitwise_right_shift,
+    dpt.logical_and,
+    dpt.logical_or,
+    dpt.logical_xor,
+]
+
+# Generate dtype combinations for each function
+dtypes = {}
+for fn in function_list:
+    dtypes[fn] = [list(map(dpt.dtype, sig.split("->")[0])) for sig in fn.types]
+
+
+# Dynamically create benchmark methods at the module level
+def generate_benchmark_functions():
+    """Dynamically create benchmark functions for each
+    function and dtype combination.
+    """
+    for fn in function_list:
+        fn_name = fn.name_
+        for dtype1, dtype2 in dtypes[fn]:
path: benchmarks/benchmarks/binary.py
user: login: jharlow-intel
body: Done! Great advice, I've added a new `benchmark_utils.py` file that right now just has a method for skipping unsupported data-types depending on the selected device.

Tested it and it works as expected, unsupported data-types are now marked with a `n/a` for their results

created_at: 2025-04-16T16:36:30Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,15 @@
+from asv_runner.benchmarks.mark import SkipNotImplemented
+
+
+def skip_unsupported_datatype(queue, dtype):
+    """
+    Skip the benchmark if the device does not support the given data type.
+    """
+    if (
+        (dtype.name == "float64" or dtype.name == "complex128")
+        and not queue.sycl_device.has_aspect_fp64
+    ) or (dtype.name == "float16" and not queue.sycl_device.has_aspect_fp16):
+        raise SkipNotImplemented(
+            f"Skipping benchmark for {dtype.name} on this device"
+            + " as it is not supported."
+        )
path: benchmarks/benchmarks/benchmark_utils.py
user: login: ndgrigorian
body: ```suggestion
import dpctl.tensor as dpt
from asv_runner.benchmarks.mark import SkipNotImplemented


def skip_unsupported_dtype(q, dtype):
    """
    Skip the benchmark if the device does not support the given data type.
    """
    if (
        (dtype == dpt.float64 or dtype.name == dpt.complex128)
        and not q.sycl_device.has_aspect_fp64
    ) or (dtype == dpt.float16 and not q.sycl_device.has_aspect_fp16):
        raise SkipNotImplemented(
            f"Skipping benchmark for {dtype} on this device"
            + " as it is not supported."
        )
```

I suspect object comparison will be faster than string comparison, also changes make this more consistent with the rest of dpctl
created_at: 2025-04-16T20:59:43Z
author_association: COLLABORATOR
diff_hunk: @@ -0,0 +1,15 @@
+from asv_runner.benchmarks.mark import SkipNotImplemented
+
+
+def skip_unsupported_datatype(queue, dtype):
+    """
+    Skip the benchmark if the device does not support the given data type.
+    """
+    if (
+        (dtype.name == "float64" or dtype.name == "complex128")
+        and not queue.sycl_device.has_aspect_fp64
+    ) or (dtype.name == "float16" and not queue.sycl_device.has_aspect_fp16):
+        raise SkipNotImplemented(
+            f"Skipping benchmark for {dtype.name} on this device"
+            + " as it is not supported."
+        )
path: benchmarks/benchmarks/benchmark_utils.py
user: login: jharlow-intel
body: Implemented
created_at: 2025-04-17T13:43:41Z
author_association: CONTRIBUTOR

PR comments:
user: login: jharlow-intel
created_at: 2025-04-15T16:56:38Z
body: fixing the formatting issues now
author_association: CONTRIBUTOR
user: login: github-actions[bot]
created_at: 2025-04-15T17:27:14Z
body: <!-- add-pr-comment:add-pr-comment -->

Deleted rendered PR docs from intelpython.github.com/dpctl, latest should be updated shortly. :crossed_fingers:
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-04-15T17:34:07Z
body: <!-- add-pr-comment:add-pr-comment -->

Array API standard conformance tests for dpctl=0.20.0dev0=py310h93fe807_145 ran successfully.
  Passed: 1110
  Failed: 2
  Skipped: 119
author_association: NONE
user: login: coveralls
created_at: 2025-04-15T17:35:33Z
body: 
[![Coverage Status](https://coveralls.io/builds/73274865/badge)](https://coveralls.io/builds/73274865)

coverage: 86.409%. remained the same
when pulling **7b6db2ec7115e5a87488da6c5f6dd1443a5e2c47 on task/benchmarking**
into **041e0d1ee43a3567f8a16158260dc0ab828ce953 on master**.

author_association: COLLABORATOR
user: login: github-actions[bot]
created_at: 2025-04-15T17:58:57Z
body: <!-- add-pr-comment:add-pr-comment -->

Array API standard conformance tests for dpctl=0.20.0dev0=py310h93fe807_145 ran successfully.
  Passed: 1109
  Failed: 3
  Skipped: 119
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-04-15T17:59:55Z
body: <!-- add-pr-comment:add-pr-comment -->

Array API standard conformance tests for dpctl=0.20.0dev0=py310h93fe807_146 ran successfully.
  Passed: 1110
  Failed: 2
  Skipped: 119
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-04-15T18:02:28Z
body: <!-- add-pr-comment:add-pr-comment -->

Array API standard conformance tests for dpctl=0.20.0dev0=py310h93fe807_146 ran successfully.
  Passed: 1110
  Failed: 2
  Skipped: 119
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-04-15T18:03:58Z
body: <!-- add-pr-comment:add-pr-comment -->

Array API standard conformance tests for dpctl=0.20.0dev0=py310h93fe807_145 ran successfully.
  Passed: 1110
  Failed: 2
  Skipped: 119
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-04-15T20:57:33Z
body: <!-- add-pr-comment:add-pr-comment -->

Array API standard conformance tests for dpctl=0.20.0dev0=py310h93fe807_146 ran successfully.
  Passed: 1109
  Failed: 3
  Skipped: 119
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-04-15T20:57:45Z
body: <!-- add-pr-comment:add-pr-comment -->

Array API standard conformance tests for dpctl=0.20.0dev0=py310h93fe807_145 ran successfully.
  Passed: 1109
  Failed: 3
  Skipped: 119
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-04-16T17:17:53Z
body: <!-- add-pr-comment:add-pr-comment -->

Array API standard conformance tests for dpctl=0.20.0dev0=py310h93fe807_146 ran successfully.
  Passed: 1110
  Failed: 2
  Skipped: 119
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-04-16T17:19:00Z
body: <!-- add-pr-comment:add-pr-comment -->

Array API standard conformance tests for dpctl=0.20.0dev0=py310h93fe807_145 ran successfully.
  Passed: 1109
  Failed: 3
  Skipped: 119
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-04-16T18:10:21Z
body: <!-- add-pr-comment:add-pr-comment -->

Array API standard conformance tests for dpctl=0.20.0dev0=py310h93fe807_146 ran successfully.
  Passed: 1108
  Failed: 4
  Skipped: 119
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-04-16T18:11:14Z
body: <!-- add-pr-comment:add-pr-comment -->

Array API standard conformance tests for dpctl=0.20.0dev0=py310h93fe807_145 ran successfully.
  Passed: 1109
  Failed: 3
  Skipped: 119
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-04-17T14:21:32Z
body: <!-- add-pr-comment:add-pr-comment -->

Array API standard conformance tests for dpctl=0.20.0dev0=py310h93fe807_146 ran successfully.
  Passed: 1109
  Failed: 3
  Skipped: 119
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-04-17T14:27:50Z
body: <!-- add-pr-comment:add-pr-comment -->

Array API standard conformance tests for dpctl=0.20.0dev0=py310h93fe807_145 ran successfully.
  Passed: 1108
  Failed: 4
  Skipped: 119
author_association: NONE
user: login: github-actions[bot]
created_at: 2025-04-17T14:29:53Z
body: <!-- add-pr-comment:add-pr-comment -->

Array API standard conformance tests for dpctl=0.20.0dev0=py310h93fe807_147 ran successfully.
  Passed: 1109
  Failed: 3
  Skipped: 119
author_association: NONE