1
0

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で転送して、ARMでデシリアライズして結果を表示 (IntelのIntrinsic関数をARMにポートする)

Posted at

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

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

必要なもの

  • Docker
  • Docker Compose

手順

1. プロジェクト構成

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

mkdir websocket_project
cd websocket_project
mkdir intel arm

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 = "arm-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. ARMプラットフォーム用のコード

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

3.1 Dockerfile

# arm/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 <arm_neon.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;

                // デシリアライズ
                float64x2x2_t vec;
                memcpy(&vec, psd->buffer, sizeof(vec));

                double result_data[4];
                vst1q_f64(result_data, vec.val[0]);
                vst1q_f64(result_data + 2, vec.val[1]);

                // デシリアライズ結果の表示
                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:
      - arm-server

  arm-server:
    build:
      context: ./arm
      dockerfile: Dockerfile
    platform: linux/arm64
    ports:
      - "8000:8000"

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

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

docker-compose up --build

実行結果

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

Creating network "websocket_project_default" with the default driver
Building arm-server
Step 1/7 : FROM ubuntu:22.04
...
Successfully built abcdef123456
Successfully tagged websocket_project_arm-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_arm-server_1 ... done
Creating websocket_project_intel-client_1 ... done
Attaching to websocket_project_arm-server_1, websocket_project_intel-client_1
arm-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
arm-server_1  | result[0] = 1.000000
arm-server_1  | result[1] = 2.000000
arm-server_1  | result[2] = 3.000000
arm-server_1  | result[3] = 4.000000
intel-client_1  | [2024/06/28 12:34:56:5678] USER: Connection closed
arm-server_1  | [2024/06/28 12:34:56:1234] USER: Connection closed

まとめ

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

1
0
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
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?