Repository: ggerganov/llama.cpp
File: ggml/src/ggml-cann/ggml-cann.cpp (C++)

Code before:
 * This checks whether the number or properties of ggml graph nodes have changed
 * compared to the last captured CANN graph. If so, the CANN graph must be re-captured.
 *
 * @param cann_ctx  The CANN backend context.
 * @param cgraph    The current ggml computation graph.
 * @return true if an update is required; false otherwise.
 */
static bool is_cann_graph_update_required(ggml_backend_cann_context * cann_ctx, ggml_cgraph * cgraph) {
    ggml_cann_graph_lru_cache &lru_cache = cann_ctx->graph_lru_cache;
    for (auto &graph_ptr : lru_cache.cache_list) {
        // The number of nodes is different, so the graph needs to be reconstructed.
        if (graph_ptr->ggml_graph_properties.size() != (size_t)cgraph->n_nodes) {
            continue;
        }
        // The number of nodes is the same; iterate over each node to check whether they match.
        bool all_match = true;
        for (int i = 0; i < cgraph->n_nodes; i++) {
            bool has_matching_properties = ggml_graph_node_has_matching_properties(
                cgraph->nodes[i], &graph_ptr->ggml_graph_properties[i]);
            if(!has_matching_properties) {
                all_match = false;
                break;
            }
        }
        if (all_match) {
            lru_cache.matched_graph = graph_ptr;
            return false;
        }
    }
    lru_cache.matched_graph = nullptr;
    return true;
}
#endif  // USE_ACL_GRAPH

/**
 * @brief Evaluate the computation graph and optionally capture or execute it using CANN graph API.
 *
 * If CANN graph execution is enabled and graph capture is required, this function begins
 * graph capture, runs the graph, ends capture, and stores the captured graph.
 *
 * Otherwise, it falls back to op-by-op execution using the CANN compute kernel dispatcher.
 *
 * @param cann_ctx                 The CANN backend context.
 * @param cgraph                   The ggml computation graph.
 * @param use_cann_graph           Whether to use CANN graph execution.
 * @param cann_graph_update_required Whether graph capture is needed due to graph changes.
 */
static void evaluate_and_capture_cann_graph(ggml_backend_cann_context * cann_ctx, ggml_cgraph * cgraph,
    bool & use_cann_graph, bool & cann_graph_update_required) {
#ifdef USE_ACL_GRAPH
    if (use_cann_graph && cann_graph_update_required) {

Review comment (performance):
It's better return matched_graph by return value, or by parameter. Set matched_graph in lru_cache is not a good idea.

Code after:
    }
    if (node->op != graph_node_properties->node_op) {
        return false;
    }
    for (int i = 0; i < GGML_MAX_DIMS; i++) {
        if (node->ne[i] != graph_node_properties->ne[i]) {
            return false;
        }
        if (node->nb[i] != graph_node_properties->nb[i]) {
            return false;
        }
    }
    for (int i = 0; i < GGML_MAX_SRC; i++) {
        if (node->src[i] &&
            node->src[i]->data != graph_node_properties->src_address[i] &&
            node->op != GGML_OP_VIEW
        ) {
            return false;
        }
    }
    if (node->op == GGML_OP_SCALE &&
        memcmp(graph_node_properties->op_params, node->op_params, GGML_MAX_OP_PARAMS) != 0) {
        return false;
    }
    return true;
}

/**
 * @brief Check whether there is a cached CANN graph that matches the current ggml graph.
 *
 * This function iterates through the cached CANN graphs stored in the LRU cache and
 * compares them against the given ggml computation graph. A match requires that the
 * number of nodes is the same and that each node’s properties (operation type,
 * dimensions, strides, inputs, and operation parameters) are identical.
 *
 * If a matching graph is found, it is promoted to the front of the LRU cache and the
 * function returns true. Otherwise, the function returns false, indicating that a new
 * CANN graph needs to be captured.
 *
 * @param cann_ctx  The CANN backend context containing the graph cache.
 * @param cgraph    The current ggml computation graph.
 * @return true if a matching cached graph exists; false otherwise.
 */
static bool is_matched_graph(ggml_backend_cann_context * cann_ctx, ggml_cgraph * cgraph) {
    ggml_cann_graph_lru_cache &lru_cache = cann_ctx->graph_lru_cache;
    for (auto &graph_ptr : lru_cache.cache_list) {
        // Skip graphs with a different number of nodes.
        if (graph_ptr->ggml_graph_properties.size() != static_cast<size_t>(cgraph->n_nodes)) {
            continue;
        }