2026年にリリースされた RAD Studio 13.1 Florence は様々な機能の追加や改善が施され、より洗練されたものとなりました。
なかでも Delphi 13.1 では Arm 版 Windows(Arm64EC) のネイティブコンパイラツールチェインが導入され、Windows 11 on Arm 向けのネイティブアプリケーションを構築することが可能になったことは注目すべき点です。Windows 11 と Arm にまつわる現状や Delphi 開発に対する影響や注意事項は、別途ブログ記事『 Windows on Arm時代に備える:Delphi 13.1でArm64ECに対応した背景』等で紹介させていただきました。こちらも併せてご覧になってください。
そしてやはり気になるのは『Arm 向けには Arm64EC ターゲットでビルドすべきなの? 従来の x86/x64 と違いはあるの?』という疑問です。
そこで今回は、同一の Delphi コードから Win64 版と Arm64EC 版をビルドし、それぞれの処理速度を比較してみました。
結論からお伝えすると、「Arm64EC 対応を検討する価値は十分にある」と考えられる結果となりました。ぜひ、最後までご覧ください。
Table of Contents
テストケース
テストの基本的な方針は以下のとおりです:
- Delphi 13.1で作成したテストプログラム(Windows コンソールアプリケーション)を作成します。
- テストプログラムは、同じプロジェクト(コード)から Win64(x64) と Arm64EC の実行ファイル(EXE)をビルドし、同じコンピューターに配置します。
- テストは複数回実施し、それぞれプログラム開始~終了までの時間を記録し、比較します。
テストプログラムの実行環境は図のとおり(クリックで図が拡大します) macOS で動作する仮想環境に Windows 11 on Arm をインストールしたものを使用します:

- OS: Windows 11 on Arm(仮想環境で実行)
- CPU: Apple silicon (2.00 GHz) (4 プロセッサ)
- RAM: 8.00GB
- Strage(SSD): 128GB (約 55 GBの空き)
実際にテストを行う前に、PassMark Software 社 が提供する PerfomanceTest アプリケーション で CPU パフォーマンス測定を実施してみました。
PerfomanceTest には Windows on Arm 版と x86-64 版が提供されており、これらを今回の検証環境である Windows on Arm コンピュータ上で実行し、スコアを比較しました。図はその結果です(クリックで図が拡大します)。
Arm 版 PerformanceTest で測定した結果(左) と x86-64 版 PerformanceTest (右)で測定した結果とでは大きな差が出ることを確認出来ました(各スコアについての詳細な考察については省略します)。
このため、Windows 11 on Arm で実行するアプリケーションでより良いパフォーマンスを獲得するには、アプリケーションを Arm64EC アーキテクチャにすることが基本的な考え方になることが、PerformanceTest の結果からも確認できます。
それでは、Delphi で作成した Arm64EC アプリケーションも同様の結果になるのでしょうか?次のセクションで検証したいと思います。
テストケース1: CPU演算処理
1つ目のテストケースは、極めて単純な CPU 演算とし、ループカウンタで指定の回数分の加算処理を繰り返します。
テストコードの内容は以下のとおりです。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
program TestCase1; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils, System.Diagnostics; const LoopCount = 50000000; // 演算回数 RepeatCount = 10; // 測定回数 var I,J: Integer; X:UInt64; SW: TStopwatch; begin {$IFDEF MSWINDOWS} {$IFDEF Arm64EC} Writeln('*** Arm64 ***'); // Arm {$ELSE} Writeln('*** Win64 ***'); // x64 {$ENDIF} {$ENDIF} try for I := 1 to RepeatCount do begin SW := TStopwatch.StartNew; X := 0; for J := 1 to LoopCount do X := X + UInt64(J) ; SW.Stop; Writeln(Format('%d 回目: %d ms (X=%d)',[I, SW.ElapsedMilliseconds, X])); end; except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; Readln; end. |
テストの結果は以下のとおりです。左が Arm64ECビルド、右が Win64 ビルドでの結果です(クリックで図が拡大します):

Arm64EC 向けにビルドした場合の平均実行時間は約 167ms であるのに対し、x64 では約 252ms と x64 版と比較して約 1.5 倍の差が確認できました。
この結果から、本テストケースでは、Windows 11 on Arm 上で x86/x64 アプリケーション実行時に必要となるエミュレーションが実行時間に直接影響していることが考えられます。
ここでいうエミュレーションとは、x86/x64 向けにコンパイルされた命令を、実行時に Arm 向けの命令へ変換しながら処理を進める仕組みを指します。この変換処理には一定のオーバーヘッドが伴うため、単純な CPU 演算ではその影響が性能差として現れやすくなります。
テストケース2:画像変換処理
次は、実際の画像処理を伴うケースを試します。
JPEG ファイルをグレースケール化しつつ、BMP ファイルへ変換する処理を行います。
グレースケールへ変換する際の計算方法はいくつかありますが、今回は単純平均法とよばれる方法を使用します。
例えばピンク (R:255, G:192, B:203)をグレースケールする場合は、(255 + 192 + 203) / 3 = 216.6666.. となり、この値を整数に丸めてR,G,Bそれぞれに割り当てます。同じようにこれをピクセルの数だけ行います。この『加算と除算の繰り返し』が CPUへの主な負荷となります。
一般的なスマートフォン写真のファイルサイズでは処理時間が短く、測定誤差の影響を受けやすいため、今回は こちら の大型画像を使用しました。30000 x 22943 ピクセル、約170MB の JPEG ファイルです。
テスト結果は以下のとおりです。左が Arm64ECビルド、右が Win64 ビルドでの結果です(クリックで図が拡大します):
このように、テストケース1と同様、本テストでも Arm64EC 版は x64 版に対して約1.5倍高速という結果になりました。
もちろん、今回の2つのテストケースのみをもって「すべての Delphi アプリケーションで Arm64EC が高い性能を発揮する」と結論付けることはできません。一方で、今回の検証では、Windows on Arm 環境において Delphi の Arm64EC ターゲットが性能面で有効に機能するケースを確認できました。
テストケース2のコードは以下のとおりです。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
program TestCase2; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils, System.Diagnostics, Winapi.Windows, Vcl.Graphics, Vcl.Imaging.JPEG; type PRGBTripleArray = ^TRGBTripleArray; TRGBTripleArray = array[0..MaxInt div SizeOf(TRGBTriple) - 1] of TRGBTriple; var InputFileName,OutputFileName: string; BMP: TBitmap; JPG: TJPEGImage; I, X, Y: Integer; avg: Extended; Row: PRGBTripleArray; Color: Byte; SW: TStopwatch; begin {$IFDEF MSWINDOWS} {$IFDEF Arm64EC} Writeln('*** Arm64 ***'); // Arm {$ELSE} Writeln('*** Win64 ***'); // x64 {$ENDIF} {$ENDIF} try // 変数初期化 InputFileName := IncludeTrailingPathDelimiter(ExtractFilePath(ParamStr(0))) + 'TestCase2.jpg'; // 複数回実施 for I := 1 to 3 do begin // 一時待機 Sleep(5000); // 計測開始 SW := TStopwatch.StartNew; // 出力ファイル名設定 OutputFileName := IncludeTrailingPathDelimiter(ExtractFilePath(ParamStr(0))) + Format('Result(%d).bmp',[I]); // 画像変換開始 BMP := TBitmap.Create; // JPG -> BMP 変換 JPG := TJPEGImage.Create; try JPG.LoadFromFile(InputFileName); BMP.Assign(Jpg); finally JPG.Free; end; // グレースケール変換 try BMP.PixelFormat := pf24bit; for Y := 0 to BMP.Height - 1 do begin Row := BMP.ScanLine[Y]; for X := 0 to BMP.Width - 1 do begin avg := (Row[X].rgbtRed + Row[X].rgbtGreen + Row[X].rgbtBlue) /3; Color := Byte(Round(avg)); Row[X].rgbtRed := Color; Row[X].rgbtGreen := Color; Row[X].rgbtBlue := Color; end; end; BMP.SaveToFile(OutputFileName); finally BMP.Free; end; SW.Stop; Writeln(Format('%d 回目: %d ms',[I, SW.ElapsedMilliseconds])); end; except on E: Exception do begin Writeln('エラー: ' + E.ClassName + ' - ' + E.Message); end; end; Readln; end. |
テストケース3: CSVインポート処理
最後のテストケースでは、InterBase 15 を別コンピュータ上に配置し、図のような (クリックで図が拡大します) CSV インポート処理を実行し、クライアント・サーバ型アプリケーションを想定した検証を行います。

CSV ファイルは 日本郵便株式会社が公開している 郵便番号データダウンロード よりおよそ 12 万件のデータを収録したものを使用します。
これまでのテストケースでは、スタンドアロンアプリケーションとして高い負荷がかかる処理を中心に確認してきました。一方、今回のテストケースでは、データ書き込みなどの主要処理はデータベースサーバ側で実行されるため、クライアント側コンピュータの CPU 性能への依存度は比較的小さくなります。このような条件下でも、Arm64EC ターゲットによる性能差が確認できるのかを検証します。
テスト結果は以下のとおりです。左が Arm64ECビルド、右が Win64 ビルドでの結果です(クリックで図が拡大します):
これまでのテストケースでは Arm64EC 版が明確に高速となる結果を確認できましたが、今回のテストケースでは大きな性能差は確認できませんでした。
今回のテストケースでは、CSV の読み込みや SQL 送信はクライアント側で実行されるものの、実際のデータ書き込み処理はデータベースサーバ側へ依存します。そのため、これまでのスタンドアロン型テストケースと比較すると、クライアント側 CPU 性能の影響が小さくなり、Arm64EC と Win64 の差が表れにくくなった可能性があります。
この結果から、Arm64EC の優位性は常に一定ではなく、アプリケーションの処理内容やシステム構成に大きく左右されることが分かります。
テストケース3のテストコードとデータベース(InterBase15)のテーブル定義は以下のとおりです。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 |
program TestCase3; {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils,System.Classes,System.Diagnostics, FireDAC.Comp.Client, FireDAC.Stan.Def, FireDAC.Stan.Async, FireDAC.Phys, FireDAC.Phys.IB, FireDAC.Phys.IBDef,FireDac.DApt; var sw: TStopwatch; FDConnection: TFDConnection; FDQuery: TFDQuery; Rows,Cols : TStringList; I,RowIndex,ColIndex: Integer; begin {$IFDEF MSWINDOWS} {$IFDEF Arm64EC} Writeln('*** Arm64 ***'); // Arm {$ELSE} Writeln('*** Win64 ***'); // x64 {$ENDIF} {$ENDIF} for I := 1 to 3 do begin Writeln(Format('Test#%d',[I])); sw := TStopwatch.StartNew; try FDConnection := TFDConnection.Create(nil); FDQuery := TFDQuery.Create(nil) ; Rows := TStringList.Create; Cols := TStringList.Create; try // 各種初期化 FDConnection.DriverName := 'IB'; FDConnection.ConnectionDefName := 'ZIP_JP'; FDConnection.Open(); FDConnection.ExecSQL('DELETE FROM ZIPCODE'); FDQuery.Connection := FDConnection;; FDQuery.SQL.Text :=''' INSERT INTO ZIPCODE ( LOCAL_GOV_CODE, ZIPCODE_5, ZIPCODE_7, PREF_KANA, CITY_KANA, TOWN_KANA, PREF_NAME, CITY_NAME, TOWN_NAME, MULTI_ZIP_FOR_TOWN, KOAZA_BANCHI, HAS_CHOME, MULTI_TOWN_FOR_ZIP, UPDATE_TYPE, CHANGE_REASON) VALUES ( :p1,:p2,:p3,:p4,:p5,:p6,:p7,:p8,:p9, :p10,:p11,:p12,:p13,:p14,:p15) '''; // CSV Rows.Delimiter := ',' ; Rows.QuoteChar := '"'; Rows.StrictDelimiter := True; Rows.LoadFromFile('ken_all.csv',TEncoding.GetEncoding(932)); FDConnection.StartTransaction; for RowIndex := 0 to Rows.Count-1 do begin Cols.DelimitedText := Rows[RowIndex]; for ColIndex := 0 to Cols.Count-1 do begin if ColIndex > 9 then begin FDQuery.Params[ColIndex].AsInteger := StrToInt(Cols[ColIndex]); end else begin FDQuery.Params[ColIndex].Size := 2048; FDQuery.Params[ColIndex].AsString := Cols[ColIndex]; end; end; FDQuery.ExecSQL; var percent := (RowIndex * 100) div Rows.Count; Write(#13, Format('Progress: %d%%', [Percent])); end; Write(#13); FDConnection.Commit; FDConnection.Close; finally Cols.Free; Rows.Free; FDQuery.Free; FDConnection.Free; end; except on E: Exception do Writeln(E.ClassName, ': ', E.Message); end; sw.Stop; Writeln(Format('%d回目:%dms ', [I,sw.ElapsedMilliseconds] )); Sleep(5000); end; Readln; end. |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
/* Table: ZIPCODE, Owner: SYSDBA */ CREATE TABLE ZIPCODE ( LOCAL_GOV_CODE CHAR(6), ZIPCODE_5 CHAR(5), ZIPCODE_7 CHAR(7), PREF_KANA VARCHAR(100) CHARACTER SET UTF8, CITY_KANA VARCHAR(100) CHARACTER SET UTF8, TOWN_KANA VARCHAR(200) CHARACTER SET UTF8, PREF_NAME VARCHAR(100) CHARACTER SET UTF8, CITY_NAME VARCHAR(100) CHARACTER SET UTF8, TOWN_NAME VARCHAR(100) CHARACTER SET UTF8, MULTI_ZIP_FOR_TOWN SMALLINT, KOAZA_BANCHI SMALLINT, HAS_CHOME SMALLINT, MULTI_TOWN_FOR_ZIP SMALLINT, UPDATE_TYPE SMALLINT, CHANGE_REASON SMALLINT ); /* Index definitions for ZIPCODE */ CREATE INDEX IDX_ZIPCODE_JP_01 ON ZIPCODE(ZIPCODE_7); CREATE INDEX IDX_ZIPCODE_JP_02 ON ZIPCODE(LOCAL_GOV_CODE); |
まとめ
冒頭でお伝えした通り、今回ご紹介したテストケースからは、「Delphi Arm64EC 対応を検討する価値は十分にある」と考えられる結果が得られました。
特に、CPU 負荷の高い処理では、Arm64EC 版が Win64 版を大きく上回る結果となっており、Windows on Arm 環境におけるネイティブ実行の効果を確認することができました。一方で、クライアント・サーバ型アプリケーションのような処理負荷が分散されるテストケースでは、Arm64EC と Win64 の性能差は小さく、結果が大きく変化しませんでした。
このことから、すべての Delphi プロジェクトにおいて Arm64EC 対応が喫緊の課題となる、というわけではないということが分かります。
一方で、Windows 環境において Arm アーキテクチャ搭載デバイスが増加傾向にあることは、市場動向からも確認できます。特に、省電力性を活かした高いモビリティへの注目は徐々に高まりつつあります。そのため、将来的な環境変化へ備える意味でも、Delphi アプリケーションの Arm 対応について早い段階から知見を蓄積しておく価値は十分にあるのではないでしょうか。
本記事が、皆様の Arm 対応検討の参考となれば幸いです。
あわせて読みたい
- Windows on Arm時代に備える:Delphi 13.1でArm64ECに対応した背景
- Delphi 13.1 の新機能:Arm64EC(Windows on Arm)対応
- Arm64EC(Windows on Arm)ターゲットの概要と移行ガイド
Reduce development time and get to market faster with RAD Studio, Delphi, or C++Builder.
Design. Code. Compile. Deploy.
Free Delphi Community Edition Free C++Builder Community Edition










