def gen_profiler(
    func_attrs,
    workdir,
    profiler_filename,
    shape_template,
    f_emit_instance=emit_instance,
    is_bias=False,
    is_bias_add=False,
    is_transpose=False,
    is_depthwise=False,
    extra_header="",
    instance_name_base="DeviceConvFwdInstance",
):
    """Generate profiler sources."""
    op_type = func_attrs["op"]
    op_instance = func_attrs["op_instance"]

    backend_spec = CUDASpec()
    dtype = backend_spec.dtype_to_lib_type(func_attrs["inputs"][0]._attrs["dtype"])

    func_call_extra_args = {}
    if is_bias:
        func_call_extra_args = {
            "bias_ptr": "b.device_data()",
        }
    elif is_bias_add:
        func_call_extra_args = {
            "bias_ptr": "b.device_data()",
            "res_ptr": "r.device_data()",
        }

    benchmark_decls = []
    benchmark_instances = []
    profiler_benchmarks = {}

    for instance_idx, (op_name, op) in enumerate(op_instance.items()):
        config = f_emit_instance(op)
        config_name = extract_config_name(config)
        instance_name = f"{instance_name_base}_{instance_idx}"
        function_name = f"{op_type}_{op_name}"

        exec_program = EXEC_TEMPLATE.render(
            indent="  ",
            is_profiler=True,
            is_bias=is_bias,
            is_bias_add=is_bias_add,
            instance_name=instance_name,
            dtype=dtype,
        )
        instance = INSTANCE_TEMPLATE.render(
            config_name=config_name,
            name=instance_name,
            config=config,
        )
        function = FUNCTION_TEMPLATE.render(
            is_bias=is_bias,
            is_bias_add=is_bias_add,
            is_transpose=is_transpose,
            is_depthwise=is_depthwise,
            function_name=function_name,
            shape_function="",
            exec_paths=exec_program,
        )
        op_source = SRC_TEMPLATE.render(
            is_transpose=is_transpose,
            is_depthwise=is_depthwise,
            extra_header=extra_header,
            instances=instance,
            functions=function,
        )

        func_call = FUNC_CALL_TEMPLATE.render(
            indent="  ",
            is_bias=is_bias,
            is_bias_add=is_bias_add,
            func_name=function_name,
            in_ptr="x.device_data()",
            weight_ptr="w.device_data()",
            out_ptr="y.device_data()",
            **func_call_extra_args,
            p_batch="&NI",
            p_out_ch="&CO",
            p_in_ch="&CI",
            p_kernel_h="&KH",
            p_kernel_w="&KW",
            p_in_h="&HI",
            p_in_w="&WI",
            p_out_batch="&NO",
            p_out_h="&HO",
            p_out_w="&WO",
            strideh="strideh",
            dilationh="dilationh",
            padh="padh",
            stridew="stridew",
            dilationw="dilationw",
            padw="padw",
        )
        benchmark = BENCHMARK_TEMPLATE.render(
            is_bias=is_bias,
            is_bias_add=is_bias_add,
            instance_name_base=instance_name_base,
            function_name=function_name,
            func_call=func_call,
            instance_name=instance_name,
        )

        profiler_benchmarks[function_name] = PROFILER_BENCHMARK_TEMPLATE.render(
            op_source=op_source,
            benchmark=benchmark,
            instance_name=instance_name,
        )

        benchmark_instance = BENCHMARK_INSTANCE_TEMPLATE.render(
            indent="  ",
            conv_op_name=op_name,
            func_name=f"benchmark_{function_name}",
            ni="NI",
            hi="HI",
            wi="WI",
            ci="CI",
            co="CO",
            kh="KH",
            kw="KW",
            no="NO",
            ho="HO",
            wo="WO",
            strideh="SH",
            dilationh="DH",
            padh="PH",
            stridew="SW",
            dilationw="DW",
            padw="PW",
        )
        benchmark_instances.append(benchmark_instance)

        benchmark_decl = BENCHMARK_DECL_TEMPLATE.render(
            function_name=function_name,
        )
        benchmark_decls.append(benchmark_decl)

    shape_func = shape_template.render(
        indent="  ",
        dtype="int64_t ",
        div="/",
        x_dim0="batch",
        x_dim1="in_h",
        x_dim2="in_w",
        x_dim3="in_ch",
        w_dim0="out_ch",
        w_dim1="kernel_h",
        w_dim2="kernel_w",
        strideh="strideh",
        dilateh="dilationh",
        padh="padh",
        stridew="stridew",
        dilatew="dilationw",
        padw="padw",
    )
    profiler_main_code = PROFILER_MAIN_TEMPLATE.render(
        shape_func=shape_func,
        benchmark_decls="\n".join(benchmark_decls),
        benchmark_instances="\n".join(benchmark_instances),
    )

    code = {profiler_filename: profiler_main_code}
    for benchmark_filename, benchmark_code in profiler_benchmarks.items():
        code[benchmark_filename] = benchmark_code

    # FIXME: remove file_pairs once we have make -j ready for building
    # an entire graph
    file_pairs = []
    add_profiler(file_pairs, workdir, op_type, profiler_filename, code)

    # build
    return build_profiler(file_pairs)
Generate profiler sources.
python/aitemplate/backend/cuda/conv2d/common.py