2026年5月11日月曜日

dpct::queue_ptrって?

enum ggml_status ggml_backend_graph_compute(ggml_backend_t backend, struct ggml_cgraph * cgraph) {
    enum ggml_status err = ggml_backend_graph_compute_async(backend, cgraph);
    ggml_backend_synchronize(backend);
    return err;
}

結局のところ、いろいろ経由したものの長い旅を経て、ようやくここまでたどり着いた…w

enum ggml_status ggml_backend_graph_compute_async(ggml_backend_t backend, struct ggml_cgraph * cgraph) {
    GGML_ASSERT(backend);
    return backend->iface.graph_compute(backend, cgraph);
}

void ggml_backend_synchronize(ggml_backend_t backend) {
    GGML_ASSERT(backend);
    if (backend->iface.synchronize == NULL) {
        return;
    }

    backend->iface.synchronize(backend);

ちなみにCPUだとiface.synchronizeがNULLなので同期処理は無視されている。そもそもSYCLでもiGPUだと1個なので無視してもいい気がしないでもないが…さらに掘り下げていくと、 

ifaceはggml_backend_buffer_i型

ggml/src/ggml-backend-impl.h 

    struct ggml_backend_i {
        const char * (*get_name)(ggml_backend_t backend);

        void (*free)(ggml_backend_t backend);

        // (optional) asynchronous tensor data access
        void (*set_tensor_async)   (ggml_backend_t backend,       struct ggml_tensor * tensor, const void * data, size_t offset, size_t size);
        void (*get_tensor_async)   (ggml_backend_t backend, const struct ggml_tensor * tensor,       void * data, size_t offset, size_t size);
        void (*set_tensor_2d_async)(ggml_backend_t backend,       struct ggml_tensor * tensor, const void * data, size_t offset, size_t size, size_t n_copies, size_t stride_tensor, size_t stride_data);
        void (*get_tensor_2d_async)(ggml_backend_t backend, const struct ggml_tensor * tensor,       void * data, size_t offset, size_t size, size_t n_copies, size_t stride_tensor, size_t stride_data);
        bool (*cpy_tensor_async)(ggml_backend_t backend_src, ggml_backend_t backend_dst, const struct ggml_tensor * src, struct ggml_tensor * dst);

        // (optional) complete all pending operations (required if the backend supports async operations)
        void (*synchronize)(ggml_backend_t backend);

        // (optional) graph plans (not used currently)
        // compute graph with a plan
        ggml_backend_graph_plan_t (*graph_plan_create) (ggml_backend_t backend, const struct ggml_cgraph * cgraph);
        void                      (*graph_plan_free)   (ggml_backend_t backend, ggml_backend_graph_plan_t plan);
        // update the plan with a new graph - this should be faster than creating a new plan when the graph has the same topology
        void                      (*graph_plan_update) (ggml_backend_t backend, ggml_backend_graph_plan_t plan, const struct ggml_cgraph * cgraph);
        // compute the graph with the plan
        enum ggml_status          (*graph_plan_compute)(ggml_backend_t backend, ggml_backend_graph_plan_t plan);

        // compute graph (always async if supported by the backend)
        enum ggml_status          (*graph_compute)     (ggml_backend_t backend, struct ggml_cgraph * cgraph);

        // (optional) event synchronization
        // record an event on this stream
        void (*event_record)(ggml_backend_t backend, ggml_backend_event_t event);
        // wait for an event on on a different stream
        void (*event_wait)  (ggml_backend_t backend, ggml_backend_event_t event);

        // (optional) sort/optimize the nodes in the graph
        void                      (*graph_optimize)    (ggml_backend_t backend, struct ggml_cgraph * cgraph);
    };

と、定義されていて SYCLはggml/src/ggml-sycl/ggml-sycl.cpp で 

static ggml_backend_i ggml_backend_sycl_interface = {
    /* .get_name                = */ ggml_backend_sycl_get_name,
    /* .free                    = */ ggml_backend_sycl_free,
    /* .set_tensor_async        = */ ggml_backend_sycl_set_tensor_async,
    /* .get_tensor_async        = */ ggml_backend_sycl_get_tensor_async,
    /* .set_tensor_2d_async     = */ NULL,
    /* .get_tensor_2d_async     = */ NULL,
    /* .cpy_tensor_async        = */ NULL, // ggml_backend_sycl_cpy_tensor_async,
                                           // // TODO: update for the new
                                           // interface
    /* .synchronize             = */ ggml_backend_sycl_synchronize,
    /* .graph_plan_create       = */ NULL,
    /* .graph_plan_free         = */ NULL,
    /* .graph_plan_update       = */ NULL,
    /* .graph_plan_compute      = */ NULL,
    /* .graph_compute           = */ ggml_backend_sycl_graph_compute,
    /* .event_record            = */ ggml_backend_sycl_event_record,
    /* .event_wait              = */ ggml_backend_sycl_event_wait,
    /* .graph_optimize          = */ NULL,
};
 

と、定義されている。当初の目的通り、ggml_backend_sycl_synchronizeが実装されているので、ここで同期処理が行われている。

で、実際の ggml_backend_sycl_synchronizeは

static void ggml_backend_sycl_synchronize(ggml_backend_t backend) try {
    GGML_SYCL_DEBUG("[SYCL] call %s\n", __func__);
    ggml_backend_sycl_context * sycl_ctx = (ggml_backend_sycl_context *)backend->context;
    const queue_ptr stream = sycl_ctx->stream(sycl_ctx->device, 0);
    SYCL_CHECK(CHECK_TRY_ERROR((stream)->wait()));

    GGML_UNUSED(backend);
}

と、なっている。が、ざっくりと検索すると

https://www.intel.com/content/www/us/en/developer/articles/guide/oneapi-dpcpp-library-manual-migration.html

でサンプルコードで

Is migrated to:
    dpct::queue_ptr stream;
    stream = dpct::get_current_device().create_queue();
    stream->fill(d_out, oneapi::dpl::reduce(oneapi::dpl::execution::device_policy(*stream), 
        d_in, d_in + num_items, typename std::iterator_traits<decltype(d_out)>::value_type{}), 1).wait();

となっている。 dpct::queue_ptrって? 分からんのでさらにざっくり検索 

dpct queue_ptr stream

https://www.isus.jp/wp-content/uploads/dpct/2023/dpcpp_compatibility_tool_user_guide/diagnostic_ref/dpct1026.html

この中で、 queue_prt は dpct::queue_ptr使えってなってるんだよな…なんだかわからんが、変えてみるか?

書き換えてみて、実際にgrepで目視チェックを行って、漏れがないのを確認し、make中…

[ 23%] Building CXX object ggml/src/ggml-sycl/CMakeFiles/ggml-sycl.dir/template-instances/fattn-vec-instance-q4_1-q8_0.cpp.o

いつも放置してるだけだと気にならなかったけど、結構時間かかる…w

ちなみに上記のリンクのドキュメントを見ると、CUDAのコードから自動変換ツールを使えば9割方は自動的にSYCLのコードにおこしてくれるらしい。まぁこの手のツールは信用できないけどw

ただ、日本語のドキュメントとして存在してくれてるのはありがたい…

テンプレートインスタンスがなげぇ…コンパイル通ってくれるのかな?普通に考えて同期処理なんて1ソースファイルから外には跨がすなんてことはしないと思うのだが…不安だ…

[ 33%] Building C object ggml/src/CMakeFiles/ggml-cpu.dir/ggml-cpu/arch/x86/quants.c.o
[ 33%] Building CXX object ggml/src/CMakeFiles/ggml-cpu.dir/ggml-cpu/arch/x86/repack.cpp.o
[ 34%] Linking CXX static library libggml-cpu.a
[ 34%] Built target ggml-cpu
[ 34%] Building CXX object ggml/src/CMakeFiles/ggml.dir/ggml-backend-dl.cpp.o
[ 34%] Building CXX object ggml/src/CMakeFiles/ggml.dir/ggml-backend-reg.cpp.o
[ 34%] Linking CXX static library libggml.a
[ 34%] Built target ggml
[ 35%] Building CXX object CMakeFiles/stable-diffusion.dir/src/convert.cpp.o
 

お…ggml抜けた 17:38

[100%] Linking CXX executable ../../bin/sd-server
[100%] Built target sd-server
siriuth@b4turbo-2:~/stable-diffusion.cpp/build-sycl32$

おわったー17:44

さて…実行してみる。sdの-vだけでデバッグログはいいかなとりあえず。

[DEBUG] ggml_extend.hpp:2471 - execure_graph return optput
[DEBUG] stable-diffusion.cpp:1700 - if output_opt.empty()
[DEBUG] stable-diffusion.cpp:1706 - step_cache.after_condition()
[DEBUG] stable-diffusion.cpp:1708 - retrun output_opt
[DEBUG] stable-diffusion.cpp:1727 - if !uncond.empty()
[DEBUG] stable-diffusion.cpp:1741 - if img_cond.empty()
[DEBUG] stable-diffusion.cpp:1749 - is_skiplayer_step
[DEBUG] stable-diffusion.cpp:1753 - if is_skiplayer_step
[DEBUG] stable-diffusion.cpp:1766 - sample sd::Tensor<float> latent_result
  |============>                                     | 1/4 - 313.79s/it[DEBUG] stable-diffusion.cpp:1681 - sample auto run_condition
[DEBUG] stable-diffusion.cpp:1712 - if start_merge_step
[DEBUG] stable-diffusion.cpp:1692 - auto run_condition cached_output
[DEBUG] stable-diffusion.cpp:1698 - auto output_opt
[DEBUG] flux.hpp:1481 - sd::Tensor<float> compute() start
[DEBUG] flux.hpp:1487 - sd::Tensor<float> compute() auto get_graph
[DEBUG] flux.hpp:1491 - sd::Tensor<float> compute() auto result
[DEBUG] ggml_extend.hpp:2692 - compute() start
[DEBUG] ggml_extend.hpp:2719 - compute() return execute_graph
[DEBUG] ggml_extend.hpp:2374 - execure_graph start
[DEBUG] ggml_extend.hpp:2414 - call copy_data_to_backend_tensor()
[DEBUG] ggml_extend.hpp:2422 - call ggml_backend_graph_compute()
7分経過。1024x1024の画像を出してるのであれですが…

あ…消費電力が4Wに下がってCPUスレッドが100%に…落ちやがったw

変わってねぇ…

てか、コードが標準っぽい書き方じゃダメっぽいwくっ。

ちまちま書き換えていきますか…とりあえず dpct::queue_ptr が使えそうなのが分かった…

0 件のコメント:

コメントを投稿