Repository: ggml-org/llama.cpp
Pull request: CANN: Add x86 build ci

The current CANN build only verifies the aarch64 architecture. We’ve encountered multiple build failures on x86 due to compiler differences, so we’ve added x86 builds for monitoring purposes.

Fix code format issue.

#12945

Changed files:
filename: .github/workflows/build.yml
patch: @@ -1766,16 +1766,17 @@ jobs:
     if: ${{ github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'Ascend NPU') }}
     defaults:
       run:
-       shell: bash -el {0}
-    runs-on: ubuntu-24.04-arm
+        shell: bash -el {0}
     strategy:
       matrix:
+        arch: [x86, aarch64]
         cann:
           - '8.1.RC1.alpha001-910b-openeuler22.03-py3.10'
         device:
           - 'ascend910b3'
         build:
           - 'Release'
+    runs-on: ${{ matrix.arch == 'aarch64' && 'ubuntu-24.04-arm' || 'ubuntu-24.04' }}
     container: ascendai/cann:${{ matrix.cann }}
     steps:
       - name: Checkout

filename: ggml/src/ggml-cann/ggml-cann.cpp
patch: @@ -156,195 +156,196 @@ const ggml_cann_device_info& ggml_cann_info() {
  * This class manages a pool of CANN buffers for a specific device.
  */
 struct ggml_cann_pool_buf_prio : public ggml_cann_pool {
-        /**
-         * @brief The maximum reuse margin for a buffer.
-         */
-        static const size_t max_reuse_margin = 1ull << 22;  // 4MB
-
-        /**
-         * @brief The minimum free margin for a buffer.
-         */
-        static const size_t min_free_margin = 1ull << 20;   // 1MB
-
-        /**
-         * @brief The alignment for buffer allocation.
-         */
-        static const size_t alignment = 128;
-
-        /**
-         * @brief The device ID associated with this buffer pool.
-         */
-        int device;
-
-        /**
-         * @brief Whether to disable clean during buffer allocation.
-         */
-        bool disable_clean = false;
-
-        /**
-         * @brief Structure representing a CANN buffer.
-         */
-        struct ggml_cann_buffer {
-            void* ptr = nullptr;  ///< Pointer to the buffer.
-            size_t size = 0;      ///< Size of the buffer.
-            std::chrono::steady_clock::time_point last_used;  ///< Last used time.
-
-            bool operator>(const ggml_cann_buffer& other) const {
-                return size > other.size;
-            }
-        };
-
-        /**
-         * @brief Array of CANN buffers in the pool.
-         */
-        std::unordered_map<void*, size_t> buffer_pool;
-        std::priority_queue<ggml_cann_buffer,
-                            std::vector<ggml_cann_buffer>,
-                            std::greater<>> free_buffers ;
-
-        /**
-         * @brief Total size of all buffers in the pool.
-         */
-        size_t pool_size = 0;
-
-        /**
-         * @brief Constructor to initialize the buffer pool for a specific device.
-         *
-         * @param device The device ID to associate with this buffer pool.
-         */
-        explicit ggml_cann_pool_buf_prio(int device) : device(device) {
-            disable_clean = getenv("GGML_CANN_DISABLE_BUF_POOL_CLEAN") != nullptr;
+    /**
+     * @brief The maximum reuse margin for a buffer.
+     */
+    static const size_t max_reuse_margin = 1ull << 22;  // 4MB
+
+    /**
+     * @brief The minimum free margin for a buffer.
+     */
+    static const size_t min_free_margin = 1ull << 20;   // 1MB
+
+    /**
+     * @brief The alignment for buffer allocation.
+     */
+    static const size_t alignment = 128;
+
+    /**
+     * @brief The device ID associated with this buffer pool.
+     */
+    int device;
+
+    /**
+     * @brief Whether to disable clean during buffer allocation.
+     */
+    bool disable_clean = false;
+
+    /**
+     * @brief Structure representing a CANN buffer.
+     */
+    struct ggml_cann_buffer {
+        void* ptr = nullptr;  ///< Pointer to the buffer.
+        size_t size = 0;      ///< Size of the buffer.
+        std::chrono::steady_clock::time_point last_used;  ///< Last used time.
+
+        bool operator>(const ggml_cann_buffer& other) const {
+            return size > other.size;
         }
+    };
 
-        /**
-         * @brief Destructor to free all buffers in the pool.
-         */
-        ~ggml_cann_pool_buf_prio() {
-            ggml_cann_set_device(device);
-            for (auto& [b_ptr, b_size] : buffer_pool) {
-                aclrtFree(b_ptr);
-               pool_size -= b_size;
-            }
-            buffer_pool.clear();
-            GGML_ASSERT(pool_size == 0);
+    /**
+     * @brief Array of CANN buffers in the pool.
+     */
+    std::unordered_map<void*, size_t> buffer_pool;
+    std::priority_queue<ggml_cann_buffer,
+                        std::vector<ggml_cann_buffer>,
+                        std::greater<>> free_buffers ;
+
+    /**
+     * @brief Total size of all buffers in the pool.
+     */
+    size_t pool_size = 0;
+
+    /**
+     * @brief Constructor to initialize the buffer pool for a specific device.
+     *
+     * @param device The device ID to associate with this buffer pool.
+     */
+    explicit ggml_cann_pool_buf_prio(int device) : device(device) {
+        disable_clean = getenv("GGML_CANN_DISABLE_BUF_POOL_CLEAN") != nullptr;
+    }
+
+    /**
+     * @brief Destructor to free all buffers in the pool.
+     */
+    ~ggml_cann_pool_buf_prio() {
+        ggml_cann_set_device(device);
+        for (auto& [b_ptr, b_size] : buffer_pool) {
+            aclrtFree(b_ptr);
+            pool_size -= b_size;
         }
+        buffer_pool.clear();
+        GGML_ASSERT(pool_size == 0);
+    }
 
-        /**
-         * @brief Allocate a buffer of the given size.
-         *
-         * @param size The size of the buffer to allocate.
-         * @param actual_size A pointer to a variable to receive the actual size of
-         * the allocated buffer.
-         * @return A pointer to the allocated buffer.
-         */
-        void* alloc(size_t size, size_t* actual_size) override {
-            size = GGML_PAD(size, alignment);
-            if (size == 0) {
-                size = alignment;
-            }
+    /**
+     * @brief Allocate a buffer of the given size.
+     *
+     * @param size The size of the buffer to allocate.
+     * @param actual_size A pointer to a variable to receive the actual size of
+     * the allocated buffer.
+     * @return A pointer to the allocated buffer.
+     */
+    void* alloc(size_t size, size_t* actual_size) override {
+        size = GGML_PAD(size, alignment);
+        if (size == 0) {
+            size = alignment;
+        }
 
-            void* ptr = nullptr;
-            auto now = std::chrono::steady_clock::now();
-
-            std::vector<ggml_cann_buffer> free_buffers_rest;
-            free_buffers_rest.reserve(free_buffers.size());
-            while (!free_buffers.empty()) {
-                auto b = free_buffers.top();
-                free_buffers.pop();
-
-                if (b.size >= size) {
-                    // reuse the buffer if the size is enough
-                    const size_t margin = b.size - size;
-                    if (margin <= max_reuse_margin) {
-                        *actual_size = b.size;
-                        ptr = b.ptr;
-    #ifdef DEBUG_CANN_MALLOC
-                        GGML_LOG_INFO(
-                            "cann pool[%d]: reused   %p, "
-                            "pool_size = %5u MB, "
-                            "size = %5u MB, "
-                            "margin = %5u MB\n",
-                            device, b.ptr,
-                            (uint32_t)(GGML_PAD(pool_size, 1048576) / 1048576),
-                            (uint32_t)(GGML_PAD(size, 1048576) / 1048576),
-                            (uint32_t)(GGML_PAD(margin, 1048576) / 1048576));
-    #endif
-                        break;
-                    }
-                }
+        void* ptr = nullptr;
+        auto now = std::chrono::steady_clock::now();
+
+        std::vector<ggml_cann_buffer> free_buffers_rest;
+        free_buffers_rest.reserve(free_buffers.size());
+        while (!free_buffers.empty()) {
+            auto b = free_buffers.top();
+            free_buffers.pop();
 
-                bool should_clean = !disable_clean &&
-                                   b.size > min_free_margin &&
-                                   std::chrono::duration_cast<std::chrono::milliseconds>(now - b.last_used).count() > 100;
-                if (should_clean) {
-                    // free the buffer if the size is needed to be freed
-                    ACL_CHECK(aclrtFree(b.ptr));
-                    pool_size -= b.size;
-                    buffer_pool.erase(b.ptr);
-    #ifdef DEBUG_CANN_MALLOC
+            if (b.size >= size) {
+                // reuse the buffer if the size is enough
+                const size_t margin = b.size - size;
+                if (margin <= max_reuse_margin) {
+                    *actual_size = b.size;
+                    ptr = b.ptr;
+#ifdef DEBUG_CANN_MALLOC
                     GGML_LOG_INFO(
-                        "cann pool[%d]: clean    %p, "
+                        "cann pool[%d]: reused   %p, "
                         "pool_size = %5u MB, "
-                        "size = %5u MB\n",
+                        "size = %5u MB, "
+                        "margin = %5u MB\n",
                         device, b.ptr,
                         (uint32_t)(GGML_PAD(pool_size, 1048576) / 1048576),
-                        (uint32_t)(GGML_PAD(b.size, 1048576) / 1048576));
-    #endif
-                    continue;
+                        (uint32_t)(GGML_PAD(size, 1048576) / 1048576),
+                        (uint32_t)(GGML_PAD(margin, 1048576) / 1048576));
+#endif
+                    break;
                 }
-                free_buffers_rest.push_back(b);
-            }
-            for (ggml_cann_buffer &b : free_buffers_rest) {
-                free_buffers.push(std::move(b));
             }
 
-    #ifdef DEBUG_CANN_MALLOC
-            GGML_LOG_INFO("cann pool[%d] free pool_size = %5u MB\n\n", device, (uint32_t)(GGML_PAD(pool_size, 1048576) / 1048576));
-    #endif
-            if (ptr != nullptr) {
-                return ptr;
+            bool should_clean = !disable_clean &&
+                                b.size > min_free_margin &&
+                                std::chrono::duration_cast<std::chrono::milliseconds>(now - b.last_used).count() > 100;
+            if (should_clean) {
+                // free the buffer if the size is needed to be freed
+                ACL_CHECK(aclrtFree(b.ptr));
+                pool_size -= b.size;
+                buffer_pool.erase(b.ptr);
+#ifdef DEBUG_CANN_MALLOC
+                GGML_LOG_INFO(
+                    "cann pool[%d]: clean    %p, "
+                    "pool_size = %5u MB, "
+                    "size = %5u MB\n",
+                    device, b.ptr,
+                    (uint32_t)(GGML_PAD(pool_size, 1048576) / 1048576),
+                    (uint32_t)(GGML_PAD(b.size, 1048576) / 1048576));
+#endif
+                continue;
             }
+            free_buffers_rest.push_back(b);
+        }
+        for (ggml_cann_buffer &b : free_buffers_rest) {
+            free_buffers.push(std::move(b));
+        }
 
-            // allocate a new buffer if no buffer can be reused
-            ggml_cann_set_device(device);
-            ACL_CHECK(aclrtMalloc(&ptr, size, ACL_MEM_MALLOC_HUGE_FIRST));
-            *actual_size = size;
-            pool_size += size;
-    #ifdef DEBUG_CANN_MALLOC
-            GGML_LOG_INFO(
-                "cann pool[%d]: allocate %p, "
-                "pool_size = %5u MB, "
-                "size = %5u MB\n",
-                device, ptr, (uint32_t)(GGML_PAD(pool_size, 1048576) / 1048576),
-                (uint32_t)(GGML_PAD(size, 1048576) / 1048576));
-    #endif
-            buffer_pool.emplace(ptr, size);
+#ifdef DEBUG_CANN_MALLOC
+        GGML_LOG_INFO("cann pool[%d] free pool_size = %5u MB\n\n", device, (uint32_t)(GGML_PAD(pool_size, 1048576) / 1048576));
+#endif
+        if (ptr != nullptr) {
             return ptr;
         }
 
-        /**
-         * @brief Free a buffer and return it to the pool.
-         *
-         * @param ptr Pointer to the buffer to free.
-         * @param size Size of the buffer to free.
-         */
-        void free(void* ptr, size_t size) override {
-            auto it = buffer_pool.find(ptr);
-            if (it == buffer_pool.end()) {
-                GGML_ABORT("cann pool[%d]: buffer %p not found in pool\n", device, ptr);
-            }
+        // allocate a new buffer if no buffer can be reused
+        ggml_cann_set_device(device);
+        ACL_CHECK(aclrtMalloc(&ptr, size, ACL_MEM_MALLOC_HUGE_FIRST));
+        *actual_size = size;
+        pool_size += size;
+#ifdef DEBUG_CANN_MALLOC
+        GGML_LOG_INFO(
+            "cann pool[%d]: allocate %p, "
+            "pool_size = %5u MB, "
+            "size = %5u MB\n",
+            device, ptr, (uint32_t)(GGML_PAD(pool_size, 1048576) / 1048576),
+            (uint32_t)(GGML_PAD(size, 1048576) / 1048576));
+#endif
+        buffer_pool.emplace(ptr, size);
+        return ptr;
+    }
 
-            auto now = std::chrono::steady_clock::now();
-            free_buffers.emplace(ggml_cann_buffer{ptr, it->second, now});
-    #ifdef DEBUG_CANN_MALLOC
-            GGML_LOG_INFO(
-                "cann pool[%d]: return   %p, "
-                "pool_size = %5u MB\n",
-                device, ptr,
-                (uint32_t)(GGML_PAD(pool_size, 1048576) / 1048576));
-    #endif
+    /**
+     * @brief Free a buffer and return it to the pool.
+     *
+     * @param ptr Pointer to the buffer to free.
+     * @param size Size of the buffer to free.
+     */
+    void free(void* ptr, size_t size) override {
+        GGML_UNUSED(size);
+        auto it = buffer_pool.find(ptr);
+        if (it == buffer_pool.end()) {
+            GGML_ABORT("cann pool[%d]: buffer %p not found in pool\n", device, ptr);
         }
-    };
+
+        auto now = std::chrono::steady_clock::now();
+        free_buffers.emplace(ggml_cann_buffer{ptr, it->second, now});
+#ifdef DEBUG_CANN_MALLOC
+        GGML_LOG_INFO(
+            "cann pool[%d]: return   %p, "
+            "pool_size = %5u MB\n",
+            device, ptr,
+            (uint32_t)(GGML_PAD(pool_size, 1048576) / 1048576));
+#endif
+    }
+};
 
 /**
  * @brief A pool of CANN buffers(segment buffer).
@@ -531,6 +532,7 @@ struct ggml_cann_pool_buf : public ggml_cann_pool {
      * @param size Size of the buffer to free.
      */
     void free(void* ptr, size_t size) override {
+        GGML_UNUSED(size);
         for (int i = 0; i < MAX_BUFFERS; ++i) {
             ggml_cann_buffer& b = buffer_pool[i];
             if (b.ptr != ptr) {