    def _should_build_profiler(self) -> bool:
        """
        Check if we should build profilers. If we have a cached
        entry for this gemm instance, we update this gemm op's
        relevant attributes with the cached result and return False.
        """
        force_cache = environ.force_profiler_cache()
        if self._has_dynamic_input_dims():
            if force_cache:
                raise RuntimeError(
                    "We cannot force to use the cache as dynamic dims require "
                    "us to generate and build the profilers"
                )
            # If there are dynamic dims, we'll have to generate and build the
            # profilers, as the binaries will be needed for dynamic profiling.
            return True
        # We are forced to use the cache so we skip building profilers.
        if force_cache:
            return False

        target = backend.target.Target.current()
        workloads = list(self._attrs["exec_path"].keys())

        build_profiler = True
        # Now, let's query if all of our workloads have cache entries. If that
        # is the case, it is safely to skip generating and building profilers.
        if not target.use_dummy_profiling_results():
            tmp_key = next(iter(self._attrs["op_instance"].keys()))
            tmp_op = self._attrs["op_instance"][tmp_key]
            build_profiler = False
            for wkl in workloads:
                exec_entry_sha1 = sha1(wkl.encode("utf-8")).hexdigest()
                split_k = (
                    1 if self._attrs["split_k"] is None else self._attrs["split_k"]
                )
                query = Conv3dQueryEntry(
                    dtype_a=tmp_op.A.element.value - 1,
                    dtype_b=tmp_op.B.element.value - 1,
                    dtype_c=tmp_op.C.element.value - 1,
                    dtype_acc=tmp_op.tile_description.math_instruction.element_accumulator.value
                    - 1,
                    major_a=tmp_op.A.layout.value,
                    major_b=tmp_op.B.layout.value,
                    major_c=tmp_op.C.layout.value,
                    kd=self._attrs["KD"],
                    kh=self._attrs["KH"],
                    kw=self._attrs["KW"],
                    co=self._attrs["CO"],
                    stride_d=self._attrs["stride"][0],
                    stride_h=self._attrs["stride"][1],
                    stride_w=self._attrs["stride"][2],
                    pad_d=self._attrs["pad"][0],
                    pad_h=self._attrs["pad"][1],
                    pad_w=self._attrs["pad"][2],
                    dilate_d=self._attrs["dilate"][0],
                    dilate_h=self._attrs["dilate"][1],
                    dilate_w=self._attrs["dilate"][2],
                    op_type=self._attrs["op"],
                    device=target._arch,
                    epilogue=tmp_op.epilogue_functor.value,
                    split_k=split_k,
                    exec_entry_sha1=exec_entry_sha1,
                )
                cache_value = target.query_profile_cache("conv3d", query.__dict__)
                if cache_value is not None and not target.force_profile():
                    _LOGGER.info(
                        f'Load profiling result for {self._attrs["name"]} '
                        f"from cache: {cache_value}",
                    )
                    best_algo, workspace = cache_value
                    self._attrs["exec_path"][wkl] = best_algo
                    self._attrs["workspace"] = max(self._attrs["workspace"], workspace)
                else:
                    # cache miss - we will have to generate and build profilers
                    build_profiler = True
        return build_profiler
Check if we should build profilers. If we have a cached
entry for this gemm instance, we update this gemm op's
relevant attributes with the cached result and return False.
python/aitemplate/compiler/ops/conv/conv3d.py