1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Intelで__m256d型のデータをシリアライズし、WebSocketで転送して、RISC-Vでデシリアライズして結果を表示 (IntelのIntrinsic関数をRISC-Vにポートする)

Posted at

Intelで__m256d型のデータをシリアライズし、WebSocketで転送して、RISC-Vでデシリアライズして結果を表示 (IntelのIntrinsic関数をRISC-Vにポートする)

この記事は、DockerとDocker Composeを使用して、Intelプラットフォーム(linux/amd64)とRISC-Vプラットフォーム(linux/riscv64)のUbuntu 22.04イメージを起動し、WebSocketを介して通信する方法を説明します。Intelプラットフォームでは__m256d型のデータをシリアライズし、RISC-Vプラットフォームでデシリアライズして表示します。

必要なもの

  • Docker
  • Docker Compose

手順

1. プロジェクト構成

まず、プロジェクトのディレクトリ構造を作成します。

mkdir websocket_project
cd websocket_project
mkdir intel riscv

2. Intelプラットフォーム用のコード

intelディレクトリに移動し、WebSocketクライアントとシリアライズコードを作成します。

2.1 Dockerfile

# intel/Dockerfile
FROM ubuntu:22.04

RUN apt-get update && \
    apt-get install -y \
    build-essential \
    libwebsockets-dev \
    libssl-dev \
    && rm -rf /var/lib/apt/lists/*

COPY . /app
WORKDIR /app

RUN gcc -o ws_client ws_client.c -lwebsockets -lm -mavx

CMD ["./ws_client"]

2.2 ws_client.c

以下の内容でファイルを作成します。

#include <libwebsockets.h>
#include <string.h>
#include <stdio.h>
#include <immintrin.h>

#define BUFFER_SIZE 32

struct per_session_data {
    uint8_t buffer[BUFFER_SIZE];
    size_t len;
};

static int callback_websockets(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) {
    struct per_session_data *psd = (struct per_session_data *)user;

    switch (reason) {
        case LWS_CALLBACK_CLIENT_ESTABLISHED:
            lwsl_user("Connection established\n");

            // __m256dデータのシリアライズ
            __m256d vec = _mm256_set_pd(4.0, 3.0, 2.0, 1.0);
            _mm256_storeu_pd((double *)psd->buffer, vec);
            psd->len = BUFFER_SIZE;

            lws_callback_on_writable(wsi);
            break;

        case LWS_CALLBACK_CLIENT_WRITEABLE:
            if (psd->len > 0) {
                lws_write(wsi, psd->buffer, psd->len, LWS_WRITE_BINARY);
                psd->len = 0;
            }
            break;

        case LWS_CALLBACK_CLIENT_RECEIVE:
            // 受信したデータの処理(必要なら)
            break;

        case LWS_CALLBACK_CLIENT_CLOSED:
            lwsl_user("Connection closed\n");
            break;

        default:
            break;
    }

    return 0;
}

static struct lws_protocols protocols[] = {
    {
        .name = "ws-protocol",
        .callback = callback_websockets,
        .per_session_data_size = sizeof(struct per_session_data),
        .rx_buffer_size = 0,
    },
    {NULL, NULL, 0, 0}
};

int main(void) {
    struct lws_context_creation_info info;
    memset(&info, 0, sizeof(info));

    info.port = CONTEXT_PORT_NO_LISTEN;
    info.protocols = protocols;

    struct lws_context *context = lws_create_context(&info);
    if (context == NULL) {
        lwsl_err("lws_create_context failed\n");
        return 1;
    }

    struct lws_client_connect_info ccinfo = {
        .context = context,
        .address = "riscv-server",
        .port = 8000,
        .path = "/",
        .protocol = protocols[0].name,
        .ssl_connection = 0,
        .host = lws_canonical_hostname(context),
        .origin = "origin",
        .ietf_version_or_minus_one = -1,
    };

    struct lws *wsi = lws_client_connect_via_info(&ccinfo);
    if (wsi == NULL) {
        lwsl_err("lws_client_connect_via_info failed\n");
        lws_context_destroy(context);
        return 1;
    }

    while (lws_service(context, 1000) >= 0) {
        // イベントループ
    }

    lws_context_destroy(context);
    return 0;
}

3. RISC-Vプラットフォーム用のコード

riscvディレクトリに移動し、WebSocketサーバーとデシリアライズコードを作成します。

3.1 Dockerfile

# riscv/Dockerfile
FROM ubuntu:22.04

RUN apt-get update && \
    apt-get install -y \
    build-essential \
    libwebsockets-dev \
    libssl-dev \
    && rm -rf /var/lib/apt/lists/*

COPY . /app
WORKDIR /app

RUN gcc -o ws_server ws_server.c -lwebsockets

CMD ["./ws_server"]

3.2 ws_server.c

以下の内容でファイルを作成します。

#include <libwebsockets.h>
#include <string.h>
#include <stdio.h>
#include <riscv_vector.h>

#define BUFFER_SIZE 32

struct per_session_data {
    uint8_t buffer[BUFFER_SIZE];
    size_t len;
};

static int callback_websockets(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) {
    struct per_session_data *psd = (struct per_session_data *)user;

    switch (reason) {
        case LWS_CALLBACK_ESTABLISHED:
            lwsl_user("Connection established\n");
            break;

        case LWS_CALLBACK_RECEIVE:
            if (len == BUFFER_SIZE) {
                memcpy(psd->buffer, in, len);
                psd->len = len;

                // デシリアライズ
                vfloat64m1_t vec = vle64_v_f64m1((double *)psd->buffer, 4);

                double result_data[4];
                vse64_v_f64m1(result_data, vec, 4);

                // デシリアライズ結果の表示
                for (int i = 0; i < 4; ++i) {
                    printf("result[%d] = %f\n", i, result_data[i]);
                }
            }
            break;

        case LWS_CALLBACK_CLOSED:
            lwsl_user("Connection closed\n");
            break;

        default:
            break;
    }

    return 0;
}

static struct lws_protocols protocols[] = {
    {
        .name = "ws-protocol",
        .callback = callback_websockets,
        .per_session_data_size = sizeof(struct per_session_data),
        .rx_buffer_size = 0,
    },
    {NULL, NULL, 0, 0}
};

int main(void) {
    struct lws_context_creation_info info;
    memset(&info, 0, sizeof(info));

    info.port = 8000;
    info.protocols = protocols;

    struct lws_context *context = lws_create_context(&info);
    if (context == NULL) {
        lwsl_err("lws_create_context failed\n");
        return 1;
    }

    while (lws_service(context, 1000) >= 0) {
        // イベントループ
    }

    lws_context_destroy(context);
    return 0;
}

4. Docker Composeファイル

プロジェクトのルートディレクトリに移動し、docker-compose.ymlファイルを作成します。

version: '3.8'

services:
  intel-client:
    build:
      context: ./intel
      dockerfile: Dockerfile
    platform: linux/amd64
    depends_on:
      - riscv-server

  riscv-server:
    build:
      context: ./riscv
      dockerfile: Dockerfile
    platform: linux/riscv64
    ports:
      - "8000:8000"

5. プロジェクトのビルドと起動

プロジェクトのルートディレクトリで、以下のコマンドを実行してDocker Composeでプロジェクトをビルドし、起動します。

docker-compose up --build

実行結果

以下は、docker-compose up コマンドを実行した際の出力結果の例です。

Creating network "websocket_project_default" with the default driver
Building riscv-server
Step 1/7 : FROM ubuntu:22.04
...
Successfully built abcdef123456
Successfully tagged websocket_project_riscv-server:latest
Building intel-client
Step 1/7 : FROM ubuntu

:22.04
...
Successfully built 123456abcdef
Successfully tagged websocket_project_intel-client:latest
Creating websocket_project_riscv-server_1 ... done
Creating websocket_project_intel-client_1 ... done
Attaching to websocket_project_riscv-server_1, websocket_project_intel-client_1
riscv-server_1  | [2024/06/28 12:34:56:1234] USER: Connection established
intel-client_1  | [2024/06/28 12:34:56:5678] USER: Connection established
riscv-server_1  | result[0] = 1.000000
riscv-server_1  | result[1] = 2.000000
riscv-server_1  | result[2] = 3.000000
riscv-server_1  | result[3] = 4.000000
intel-client_1  | [2024/06/28 12:34:56:5678] USER: Connection closed
riscv-server_1  | [2024/06/28 12:34:56:1234] USER: Connection closed

まとめ

DockerとDocker Composeを使用して、Intelプラットフォーム(linux/amd64)とRISC-Vプラットフォーム(linux/riscv64)間でWebSocketを介したデータ通信を実現しました。Intelプラットフォームでは__m256d型のデータをシリアライズし、RISC-Vプラットフォームでデシリアライズして結果を表示しました。これにより、異なるアーキテクチャ間でのデータ通信が可能となります。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?