def gen_profiler(
    func_attrs,
    workdir,
    shape_template,
    conv2d_flag,
    extra_code="",
    src_template=SRC_TEMPLATE,
    prob_args_template=PROBLEM_ARGS_TEMPLATE,
):
    """Generates standalone executables for profiler.

    Parameters
    ----------
    func_attrs : Dict
        Operation attributes.
    workdir : str
        Directory to store the generated outputs.
    shape_template : jinja2.Template
        Generates shape calculation.
        The template is passed from compiler/ops/pool.
    conv2d_flag : str
        Flag telling which backend should be generated. options are '','bias','bias_relu','bias_add_relu','bias_add_identity'.
    extra_code : str
        Extra code for self-defined operators.
    """
    op_type = func_attrs["op"]
    op_instance = func_attrs["op_instance"]
    # shape function
    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="stride",
        dilateh="dilation",
        padh="pad",
        stridew="stride",
        dilatew="dilation",
        padw="pad",
    )
    file_pairs = []
    for op_name, op in op_instance.items():
        config = emit_instance(op)
        config_name = extract_config_name(config)
        instance = INSTANCE_TEMPLATE.render(
            name="DeviceConvFwdInstance", config_name=config_name, config=config
        )
        problem_args = prob_args_template.render(
            indent="  ",
            conv2d_flag=conv2d_flag,
        )
        exec_program = EXEC_TEMPLATE.render(
            indent="  ",
            instance="DeviceConvFwdInstance",
            problem_args=problem_args,
            is_profiler=True,
        )
        op_func = src_template.render(
            instances=instance,
            function_name="conv",
            shape_func="",
            exec_paths=exec_program,
            extra_code=extra_code,
            conv2d_flag=conv2d_flag,
        )
        structs_def = STRUCTS_DEF_TEMPLATE.render()
        args_parse = ARGS_PARSE_TEMPLATE.render()
        tensor_decl = TENSOR_DECL_TEMPLATE.render(conv2d_flag=conv2d_flag)
        func_call = FUNC_CALL_TEMPLATE.render(
            func_name="conv",
            in_ptr="(void *) memory_pool->RequestHalfTensorByIdx(0)",
            weight_ptr="(void *) memory_pool->RequestHalfTensorByIdx(1)",
            out_ptr="(void *) memory_pool->RequestHalfTensorByIdx(2)",
            bias_ptr="(void *) memory_pool->RequestHalfTensorByIdx(3)",
            res_ptr="(void *) memory_pool->RequestHalfTensorByIdx(4)",
            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",
            stride="SH",
            dilation="DH",
            pad="PH",
            group="group",
            conv2d_flag=conv2d_flag,
        )

        code = PROFILER_TEMPLATE.render(
            structs_def=structs_def,
            op_func=op_func,
            shape_func=shape_func,
            args_parse=args_parse,
            tensor_decl=tensor_decl,
            func_call=func_call,
            op_name=op_name,
        )
        prefix = os.path.join(workdir, "profiler", op_type)
        if not os.path.exists(prefix):
            os.makedirs(prefix)
        src_path = os.path.join(prefix, op_name + ".cpp")
        obj_path = os.path.join(prefix, op_name)
        if os.path.exists(obj_path):
            continue
        with open(src_path, "w") as fo:
            fo.write(code)
        file_pairs.append((src_path, obj_path))
    return file_pairs
Generates standalone executables for profiler.

Parameters
----------
func_attrs : Dict
Operation attributes.
workdir : str
Directory to store the generated outputs.
shape_template : jinja2.Template
Generates shape calculation.
The template is passed from compiler/ops/pool.
conv2d_flag : str
Flag telling which backend should be generated. options are '','bias','bias_relu','bias_add_relu','bias_add_identity'.
extra_code : str
Extra code for self-defined operators.
python/aitemplate/backend/rocm/conv2d/common.py