Alibaba Cloud Compilerは、Clang/LLVMのオープンソースコミュニティバージョンであるClang/LLVM 13に基づいてAlibaba Cloudによって開発されたC ++ コンパイラです。Alibaba Cloud Compilerは、Clang/LLVM 13からすべてのオプションとパラメーターを継承し、Alibaba Cloudインフラストラクチャ向けに深く最適化されており、ユーザーエクスペリエンスを向上させるための追加機能を提供します。 このトピックでは、Alibaba Cloud Linux 3にAlibaba Cloud Compilerをインストールして使用し、高性能C ++ アプリケーションを迅速に構築する方法について説明します。
背景情報
GNU Compiler Collection (GCC) やその他のClang/LLVMバージョンと比較して、Alibaba Cloud Compilerは純粋なコンパイルとビルド速度を大幅に向上させています。
Alibaba Cloudコンパイラでは、Clang/LLVMコンパイラを調整してコンパイルを高速化するために、プロファイルガイド付き最適化 (PGO) などのさまざまな手法が使用されています。 Alibaba Cloudコンパイラは、GCCなどの他のコンパイラよりもはるかに高速に大規模なC ++ コードを構築します。
Clang/LLVMリンカー (LLD) は、特に大きなバイナリファイルの処理で、GCCで使用されるGNUリンカーよりも優れています。
Alibaba Cloud CompilerはC ++ 20モジュールをサポートし、標準C ++ ライブラリをstdモジュールにモジュール化できます。 ビジネスコードは、コンパイルを高速化するために低コストでstdモジュールを使用して変換できます。
Alibaba Cloud Compilerは、Alibaba Cloud Compiler (LLVM) ThinLTO、AutoFDO、CoreBoltなどのテクノロジーを活用して、プログラムのパフォーマンスを向上させます。 Alibaba Cloud Compilerは、x86やArm64などのさまざまなアーキテクチャで実行でき、パフォーマンスをさらに向上させるためにYiTian 710プロセッサ用に調整されています。
Alibaba Cloud CompilerはCoroutinesとモジュールをサポートし、モジュール化された標準ライブラリを提供します。 Alibaba Cloudは、コルーチンライブラリ、シリアル化ライブラリ、リモートプロシージャコール (RPC) ライブラリ、HTTP機能など、C ++ 開発者が一般的に使用するコンポーネントを含むyaLanTingLibsを提供します。
説明yaLanTingLibsは、truct_pack、struct_json、struct_xml、struct_yaml、struct_pb、easylog、coro_rpc、coro_io、coro_http、およびasync_simpleライブラリを含む最新のC ++ ユーティリティライブラリのコレクションです。 yaLanTingLibsには、高性能で使いやすいC ++ ユーティリティも含まれており、C ++ 開発者が最新の高性能C ++ アプリケーションを構築するのに役立ちます。
前提条件
Alibaba Cloud Linux 3を実行するElastic Compute Service (ECS) インスタンスが作成されます。 ECSインスタンスの作成方法については、「カスタム起動タブでインスタンスを作成する」をご参照ください。
Alibaba Cloud Compilerは、Alibaba Cloud Linux 3でのみ使用できます。
Alibaba Cloudコンパイラのインストールと使用
Alibaba Cloud CompilerをインストールするECSインスタンスに接続します。
詳細については、「パスワードまたはキーを使用したLinuxインスタンスへの接続」をご参照ください。
次のコマンドを実行して、Alibaba Cloud Compilerをインストールします。
sudo yum install -y alibaba-cloud-compiler
次のコマンドを実行して、環境変数をインポートします。
export PATH=/opt/alibaba-cloud-compiler/bin:$PATH
Alibaba Cloudコンパイラを使用します。
単純なコンパイル例
# The C++ program. cat hello.cpp #include <iostream> int main() { std::cout << "hello C++" << std::endl; return 0; } # Compile the preceding hello.cpp program. clang++ -O2 hello.cpp -o hello.cpp.out
C ++ 20コルーチンとモジュールを使用したコンパイル
Alibaba Cloud Compilerは、C ++ 20コルーチンとモジュールをサポートしています。これにより、C ++ 開発者はより効率的な方法でコンパイルし、コンパイルパフォーマンスを向上させることができます。 コルーチンの例については、このトピックの「標準C ++ RPCライブラリの使用」および「標準C ++ HTTPライブラリの使用」をご参照ください。
説明コルーチンは、関数の実行を一時停止してから、後で実行を再開できるようにするプログラミングの概念です。 従来、関数は、関数が呼び出された後に完了するまで実行される。 Coroutinesは、非同期プログラミングとジェネレータパターンの実装を簡素化する、より柔軟な制御フローメカニズムを提供します。
従来のC ++ プログラミングパラダイムでは、コードはヘッダーファイル (
.h
/.hpp
) とソースファイル (.cpp
) に編成されます。 ソースファイルのヘッダーファイルで作成された宣言を使用するには、#include
preprocessorディレクティブを使用して、ヘッダーファイルのコピーをソースファイルに挿入します。 コンパイラは、この規則により、同じヘッダファイルを繰り返し解析することができる。 その結果、コンパイル時間が増大する。 モジュールは、コード編成を最適化し、コンパイル効率を高めるアプローチとして導入されます。
Clangを使用してC ++ プログラムをコンパイルする場合、パラメーターを設定できます。 下表に、各パラメーターを説明します。
パラメーター
説明
-std=
コンパイルに使用するC ++ 言語標準を指定します。
-stdをC ++ 20
に設定すると、c ++ コルーチンとモジュールが有効になります。--precompile
モジュールユニットをバイナリモジュールインターフェイス (BMI) ファイルにコンパイルします。
-fprebuilt-module-path
BMIファイルを検索するパスを指定します。
-fstd-modules
stdモジュールのファイルをコンパイルすることを指定します。
-fmodules-export-all
現在のモジュール内のすべての宣言を
エクスポート
としてマークします。-fmodules-export-macros
モジュールがマクロをエクスポートできるようにします。
-try-load-bmi-when-preprocessing
前処理中にBMIファイルを検索します。
-fstd-module-path
stdモジュールを検索するパスを指定します。
-fcoro-aligned-allocation
C ++ コルーチンの整列割り当てを優先します。
コンパイルの例:
# The Modules code. cat Hello.cppm module; #include <iostream> export module Hello; export void hello() { std::cout << "Hello World!\n"; } cat use.cpp import Hello; int main() { hello(); return 0; } # Compile the preceding sample Modules code. clang++ -std=c++20 Hello.cppm --precompile -o Hello.pcm clang++ -std=c++20 use.cpp -fprebuilt-module-path=. Hello.pcm -o Hello.out ./Hello.out Hello World!
(オプション) yaLanTingLibsの使用
yaLanTingLibsを使用できます。これは、C ++ 20 CoroutinesとC ++ テンプレートメタプログラミング機能に基づいて、コルーチンライブラリ、シリアル化ライブラリ、RPCライブラリ、およびHTTP機能を提供する標準C ++ ライブラリのコレクションです。 yaLanTingLibsの詳細については、「yalantinglibs」および「async_simple」をご参照ください。
シリアル化ライブラリは、データのシリアル化とデシリアル化に使用されるソフトウェアライブラリです。 シリアル化とは、データ構造またはオブジェクトの状態を、ファイルまたはバッファに格納したり、ネットワークを介して送信したりできる形式に変換するプロセスです。 逆シリアル化は、データがシリアル化された形式から元のデータ構造またはオブジェクトステータスに再構築されるプロセスです。
RPCは、プロセス間通信 (IPC) に使用されるライブラリです。 RPCにより、C ++ プログラムは、関数またはメソッドがローカルであるかのように、リモートマシン上に存在する関数またはメソッドを実行できます。 RPCは、ネットワーク伝送、シリアル化、逆シリアル化、ルートなどの詳細から抽象化し、開発者がアプリケーションのビジネスロジックに集中できるようにします。
HTTPは、分散、協調、ハイパーメディア情報システムのためのアプリケーション層プロトコルである。 coro_httpは、C ++ 20 Coroutinesを使用してHTTPサーバーとクライアントを実装する、高性能で使いやすいHTTPライブラリです。 coro_httpは、HTTPアプリケーションの迅速な開発に役立ちます。
次のコマンドを実行してyaLanTingLibsをインストールします。
sudo yum install -y yalantinglibs-devel
yaLanTingLibsのシリアル化ライブラリ、RPCライブラリ、およびHTTPライブラリを使用します。
シリアル化ライブラリの使用
次のコードスニペットを含むtest.cppという名前のコードファイルを作成します。
#include <iostream> #include "ylt/struct_pack.hpp" struct person { int age; std::string name; }; int main() { person tom{.age=20,.name="tom"}; auto buffer = struct_pack::serialize(tom); auto tom2 = struct_pack::deserialize<person>(buffer); std::cout<<"age: "<<tom2.value().age<<", name: "<<tom2.value().name<<std::endl; return 0; }
上記のコードスニペットは、個人データ構造をシリアル化および逆シリアル化します。
次のコマンドを実行して、プログラムをコンパイルします。
clang ++ test.cpp -std=c ++ 20 -o test
次のコマンドを実行してプログラムを実行します。
./test
次の出力が返されます。
age: 20, name: tom
RPCライブラリの使用
サーバー上に次のコードスニペットを含むserver.cppという名前のコードファイルを作成します。
#include "ylt/coro_rpc/coro_rpc_server.hpp" std::string ping(std::string ping) { return "Receive: " + ping + ". Return pong."; } int main() { coro_rpc::coro_rpc_server server{1 , 8801}; server.register_handler<ping>(); return server.start(); }
上記のコードスニペットは、サーバー上で継続的に実行される
coro_rpc
という名前のRPCサーバーを開始します。 RPCサーバーはポート8801でRPC要求をリッスンし、RPCに応答するために使用されるping
関数を登録します。クライアントに次のコードスニペットを含むclient.cppという名前のコードファイルを作成します。
#include <iostream> #include "ylt/coro_rpc/coro_rpc_client.hpp" std::string ping(std::string); async_simple::coro::Lazy<void> example(){ coro_rpc::coro_rpc_client client; auto ec = co_await client.connect("localhost","8801"); assert(!ec); auto ret = co_await client.call<ping>("ping"); std::cout << ret.value() << std::endl; co_return; }; int main(){ async_simple::coro::syncAwait(example()); return 0; }
上記のコードスニペットは、RPCサーバーに接続し、
ping
関数を呼び出し、関数出力を表示するために使用されるRPCクライアントを開始します。次のコマンドを実行して、サーバー側プログラムをコンパイルします。
clang ++ server.cpp -I /usr/include/ylt/thirdparty -std=c ++ 20 -o server -lpthread
次のコマンドを実行して、クライアント側のプログラムをコンパイルします。
説明クライアント側プログラムをコンパイルする前に、Alibaba Cloud Compilerがクライアントにインストールされ、環境変数がクライアントにインポートされていることを確認してください。 詳細については、このトピックの「Alibaba Cloudコンパイラのインストールと使用」をご参照ください。
clang ++ client.cpp -I /usr/include/ylt/thirdparty -std=c ++ 20 -o client -lpthread
サーバーとクライアントで次のコマンドを実行して、RPCサーバーとクライアントを起動します。
./server & ./client
次のログエントリは、サーバー側およびクライアント側のプログラムによって返されます。
2024-02-02 16:47:11.496 INFO [11960] [coro_rpc_server.hpp:289] begin to listen 2024-02-02 16:47:11.496 INFO [11961] [coro_rpc_client.hpp:412] client_id 0 begin to connect 8801 2024-02-02 16:47:11.496 INFO [11960] [coro_rpc_server.hpp:318] listen port 8801 successfully 2024-02-02 16:47:11.497 INFO [11967] [coro_rpc_server.hpp:348] new client conn_id 1 coming 2024-02-02 16:47:11.497 INFO [11967] [router.hpp:293] route function name: ping Receive: ping. Return pong. 2024-02-02 16:47:11.497 INFO [11968] [coro_rpc_client.hpp:356] client_id 0 close 2024-02-02 16:47:11.497 INFO [11967] [coro_connection.hpp:166] connection 1 close: End of file
上記のログエントリは、RPCサーバーの起動、RPCリクエストのリッスン、RPCクライアントの送信、RPCリクエストの処理を行うRPCサーバーから、接続を閉じるまでのプロセス全体を記述しています。
HTTPライブラリの使用
次のコードスニペットを含むhttp.cppという名前のコードファイルを作成します。
#include <iostream> #include "ylt/coro_http/coro_http_client.hpp" #include "ylt/coro_http/coro_http_server.hpp" using namespace std::chrono_literals; using namespace coro_http; async_simple::coro::Lazy<void> basic_usage() { coro_http_server server(1, 9001); server.set_http_handler<GET>( "/get", [](coro_http_request &req, coro_http_response &resp) { resp.set_status_and_content(status_type::ok, "ok"); }); server.async_start(); std::this_thread::sleep_for(300ms); coro_http_client client{}; auto result = co_await client.async_get("http://127.0.0.1:9001/get"); assert(result.status == 200); assert(result.resp_body == "ok"); for (auto [key, val] : result.resp_headers) { std::cout << key << ": " << val << "\n"; } } int main() { async_simple::coro::syncAwait(basic_usage()); }
上記のコードスニペットは、HTTPサーバーを起動し、HTTP GETサービスを登録して、ポート9001でHTTPリクエストをリッスンします。 次に、HTTP GETサービスを要求し、サービスから返されたデータを受信するHTTPクライアントを作成します。
次のコマンドを実行して、HTTPプログラムをコンパイルします。
clang ++ http.cpp -I /usr/include/ylt/thirdparty -std=c ++ 20 -o http -lpthread
次のコマンドを実行して、HTTPプログラムを実行します。
. /http
次のログエントリがプログラムによって返されます。
2024-02-02 09:07:26.622 INFO [8098] [coro_http_server.hpp:444] begin to listen 2024-02-02 09:07:26.622 INFO [8098] [coro_http_server.hpp:472] listen port 9001 successfully 2024-02-02 09:07:26.923 DEBUG [8101] [coro_http_server.hpp:501] new connection comming, id: 1 Server: cinatra Content-Length: 2 Date: Fri, 02 Feb 2024 01:07:26 GMT 2024-02-02 09:07:26.923 INFO [8103] [coro_http_server.hpp:37] coro_http_server will quit 2024-02-02 09:07:26.923 INFO [8101] [coro_http_server.hpp:491] accept failed, error: Operation aborted. 2024-02-02 09:07:26.923 INFO [8103] [coro_http_server.hpp:112] wait for server's thread-pool finish all work. 2024-02-02 09:07:26.923 INFO [8103] [coro_http_server.hpp:115] server's thread-pool finished. 2024-02-02 09:07:26.923 INFO [8103] [coro_http_server.hpp:117] stop coro_http_server ok