2009-08-18 5 views
17

要約:コンパイラの最適化とプロセッサ命令セットを利用したいが、移植可能なアプリケーション(別のプロセッサで実行中)が残っている。通常、私は実際に5回コンパイルして、ユーザーに実行させる正しいものを選択させることができます。異なるターゲットアーキテクチャ向けにコンパイルと最適化

私の質問は、実行時にプロセッサが検出され、正しい実行可能ファイルが実行されるように、どのようにしてこれを自動化できますか?


私には、低レベルの数学計算がたくさんあるアプリケーションがあります。これらの計算は、通常、長い間実行されます。

できるだけ多くの最適化、好ましくは(必ずしもサポートされているとは限りませんが)命令セットを利用したいと思います。一方、私はアプリケーションを移植性と使いやすいものにしたいと考えています(私は5つの異なるバージョンをコンパイルしてユーザに選択させたくありません)。

私のコードの5つの異なるバージョンをコンパイルし、実行時に可能な最適化バージョンを動的に実行する可能性はありますか? 5つの異なるバージョンでは、異なる命令セットとプロセッサの異なる最適化を意味します。

私はアプリケーションのサイズは気にしません。

私はLinux上でgccを使用していますが(私のコードはC++です)、IntelコンパイラとMinGWコンパイラをWindowsにコンパイルするのにも興味があります。

実行ファイルは異なるOSで実行する必要はありませんが、自動的に32ビットと64ビットを自動的に選択することで可能なことがあります。

編集:それを行う方法を明確にしてください。小さなコード例や説明のリンクを付けてください。私の視点からは、私が後で持っている任意のランダムなC++プロジェクトに適用可能な超汎用ソリューションが必要です。

私はShuggyCoUkに賞金を割り当てました。彼は注意すべき数多くのポインタを持っていました。私は複数の回答の間でそれを分割するのが好きでしたが、それは不可能です。私はまだこれを実装していないので、質問はまだ開いている!もはや賞金が与えられなくても、回答を追加したり改善したりしてください。

ありがとうございました!

+0

これはAppleが "ユニバーサル"バイナリ(PPC-x86)で行っていることではありませんか? – Edmundo

+0

私はすべての回答が私は+私は良いと思ったいくつかの彼らはすべて私から少し得る:)を確認しました。受け入れのための乾杯。 – ShuggyCoUk

+0

ああ、あなたが私の答えを編集してCWにすることを自由に感じるなら、もっと多くの情報を見つけたら... – ShuggyCoUk

答えて

5

これをWindows上で正常に動作させ、64ビット対応のプラットフォームで追加の機能をフルに活用したい場合は、次の手順を実行します。1.アドレス空間とレジスタ(使用頻度が高い) 64ビットのもの。

これは、関連するPE64ヘッダーとは別の実行可能ファイルを持つことで実現できます。 CreateProcessを使用するだけで、適切なビット数として起動されます(実行可能ファイルがリダイレクトされた場所にある場合を除き)。WoW64 folder redirection

この制限があると、関連する実行可能ファイル

また、ターゲットオペレーティングシステムに応じて完全に独立した実行可能ファイルであることを意味します(cpu/OSの機能は本質的にはOS特有のものです)、残りのコードのほとんどを共有オブジェクト/ dllとして実行します。 また、2つの異なるアーキテクチャで同じファイルを共有することもできます現在、異なる能力を使用している点はないと感じています。

私は、実行可能な主な実行可能ファイルが特定の選択肢を作って、より能力のあるマシン上で「より小さい」バージョンで何が起こるかを見ることができるようにすることを提案します。このモデルを与え

他の可能性があります:

  • は静的(スレッドセーフ付き/なしのもののために)標準ランタイムの異なるバージョンにリンクして、任意のSMP/SMT機能なしで実行している場合は、それらを適切に使用しました。
  • 複数のコアが存在し、彼らは本物か、ハイパースレッディングをしているかどうかどうかを検出(OSが認識しているにもかどうかをどのような場合には効果的にスケジュール)システムタイマー/高性能タイマーと使用したコードのようなもののパフォーマンスをチェックする
  • この動作に最適化されています。期限切れになるまでに一定の時間がかかる場所を探している場合は、可能な限り細かいことを知ることができます。
  • ボックスのキャッシュサイジング/その他の負荷に基づいて、コードの選択を最適化したい場合。展開されたループを使用している場合、より積極的なアンローリングオプションは、一定量レベルの1/2のキャッシュを持つことに依存する場合があります。
  • アーキテクチャによっては、倍精度浮動小数点数を使用するために条件付きでコンパイルします。インテルハードウェアではあまり重要ではありませんが、特定のARM CPUをターゲットにしている場合は、実際の浮動小数点ハードウェアをサポートしているものと、エミュレーションが必要なものがあります。最適化コンパイラ(1)を使用するのではなく、条件付きコンパイルを使用する程度まで、最適なコードが大きく変更されます。
  • CUDA対応グラフィックスカードのようなコプロセッサハードウェアを利用しています。
  • あなたはいくつかのオプション、cpuid指示されてインテルに最も有用なものを持ってチェックこれをやって(おそらく書き込みファイルシステムを避けようとして)のよう

を仮想化を検出して動作を変更します。

代わりに再実装/あなたが必要とする機能で利用可能なマニュアルを参照して、既存のものを更新します。

  • インテル:

    別のドキュメントの非常に多くは、物事を検出する方法を動作するように

CPU-Zライブラリであなたが支払っているものの大部分は、このすべて(そして厄介な小さな問題が関わっている)をやっている人です。


  1. これには注意してください - ダウンし、その2つの構成部品に問題を破ることができます。この
6

スクリプトを使用できますか?

スクリプトを使用してCPUを検出し、アーキテクチャに最も最適化された実行可能ファイルを動的にロードできます。 32/64ビット版も選択できます。

Linuxを使用している場合、あなたはおそらく、Windows上のbash/perlの/ PythonスクリプトまたはWindowsスクリプティングホストでこれを行うことができ

cat /proc/cpuinfo 

でCPUを照会することができます。おそらく、ユーザーにスクリプトエンジンのインストールを強制することは望ましくありません。 OS上で動作するIMHOが最適です。

実際、ウィンドウでは、アーキテクチャをより簡単にクエリできるように、小さなC#アプリケーションを作成することをお勧めします。 C#アプリケーションは、実行可能ファイルが最速のものを起動することができます。

また、異なるバージョンのコードをdllまたは共有オブジェクトに配置し、検出されたアーキテクチャに基づいて動的にロードすることもできます。彼らは同じ呼び出し署名を持っている限り、それは動作する必要があります。

+0

あなたは本当にCPUを検出するためのスクリプトを必要としません - あなたはネイティブOS依存システムコール。 –

+0

しかし、スクリプトを使用すると、OSと64/32ビットアーキテクチャで移植可能になります。 –

+2

彼はすでに(かなり意図的に)OS依存コードを書いていることを考慮して、OS検出が移植性があることを保証する必要はないと私は考えています。アプリケーションのその部分を移植することは、おそらくもっと簡単になります。 – Brian

16

はい、可能です。共通のエントリポイントを持つ異なる動的ライブラリとして異なるバージョンのすべてのバージョンをコンパイルし、設定ファイルやその他の情報に応じて、エントリポイント経由で実行時に を実行時にロードして実行する実行可能スタブを提供します。

+0

ありがとう!あなたは多分、そのようにコンパイルする方法をもっと具体的なポインタを持っていますか?スタブがどのように見えますか? –

+0

Windowsでは、32ビットプロセスから64ビットDLLを起動できますか?私はあなたができるとは思っていませんでしたが、どうすればそれができるかを見てみたいと思っています:) – Goz

+0

次に、別のレイヤーを提供するかもしれません:64ビットアーチで実行されたことを検出した32ビットローダー、exec'ed 64ビットのランナーは、順番に64ビットのライブラリーをロードします。 –

3

GCCを使用していると言われているので、コードはC(またはC++)であると仮定します。

Neil Butterworthは既に別々のダイナミックライブラリを作成することを提案しましたが、それはいくつかのクロスプラットフォームでの検討が必要です(Linux、Windows、OSXなどで手動で動的ライブラリを読み込む方法が異なります) )。

簡単な解決策は、一意の名前を使用してすべてのバリアントを単純に記述し、実行時に関数ポインタを使用して適切なものを選択することです。

私は、関数ポインタによって引き起こされる余分な参照は、あなたが実際に行っている仕事によって償却されると思っていますが、それを確認したいでしょう。

また、異なるコンパイラの最適化を行うには、異なる.c/.cppファイルと、ビルドツールのいくつかの手間が必要になることがあります。しかし、別のライブラリよりも全体的な作業が少なくて済みます(すでにこれが必要です)。

+0

これは恐ろしい示唆であり、それを使用するにはナットでなければなりません。私はそのような記述をすることはしばしばありませんが、この場合、私は必要と感じます。こんなことしないで。 –

+0

私は絶対に別の.cppファイルを持ちたくありません。それは維持する悪夢です!私のコードで特定のプラットフォーム用の最適化がある場合、ifdefsが私に役立つと思います。 –

+0

OK、私はこれらのコメントの強さを考慮して、ここで少し自分自身を守る気がするように必要があります。 最初は、同じアーキテクチャー(x86など)で、さまざまな実装/最適化(SSE、-O1/O2/O3など)のさまざまなバージョンの数学集約ルーチンをコンパイルしたいと考えています。 GCCの "-mtune"と "-mfpmath"はプリプロセッサで制御できないと思いますので、同じ.cppを再コンパイルして別の.oファイルを生成する必要があります。 Neilの提案は、それらが異なる動的ライブラリに終わるようにすることです。私は同じバイナリでそれらをすべて持っていました(続き)。 – jhoule

5

liboil:http://liboil.freedesktop.org/wiki/をご覧ください。実行時にマルチメディア関連の計算の実装を動的に選択することができます。そのテクニックだけでなく、自分自身を恥知らずにすることができます。

3

ファイル数に制限があるかどうかを指定していないので、別の解決策を提案します。5つの実行可能ファイルをコンパイルし、適切なバイナリを起動する6番目の実行可能ファイルを作成します。ここではいくつかの擬似コードは、Linux

プラス側では
int main(int argc, char* argv[]) 
{ 
    char* target_path[MAXPATH]; 
    char* new_argv[]; 
    char* specific_version = determine_name_of_specific_version(); 
    strcpy(target_path, "/usr/lib/myapp/versions"); 
    strcat(target_path, specific_version); 

    /* append NULL to argv */ 
    new_argv = malloc(sizeof(char*)*(argc+1)); 
    memcpy(new_argv, argv, argc*sizeof(char*)); 
    new_argv[argc] = 0; 
    /* optionally set new_argv[0] to target_path */ 

    execv(target_path, new_argv); 
} 

のために、である、このアプローチが提案されている任意のライブラリー法とは異なり、32ビットと64ビットの両方のバイナリで透過的にユーザに提供することができます。マイナス側では、Win32にはexecvがありません(cygwinでは良いエミュレーションです)。 Windowsでは、現在のプロセスを再実行するのではなく、新しいプロセスを作成する必要があります。

1

あなたはIntelコンパイラについて言及しました。それはデフォルトでこれのような何かをすることができるので、面白いです。しかし、キャッチがあります。 Intelコンパイラは、適切なSSE機能のチェックを挿入しませんでした。代わりに、あなたが特定のIntelチップを持っているかどうかを確認しました。依然としてデフォルトのケースは遅いでしょう。その結果、AMD CPUはSSEに最適化された適切なバージョンを取得できませんでした。インテルのチェックを適切なSSEチェックに置き換えるハックが浮かびます。

32/64ビットの違いには2つの実行可能ファイルが必要です。 ELF形式とPE形式の両方で、この情報がexectuablesヘッダーに格納されます。デフォルトで32ビットバージョンを起動するのは難しくありません.64ビットシステムにいるかどうかを確認してから、64ビットバージョンを再起動してください。しかし、インストール時に適切なシンボリックリンクを作成する方が簡単かもしれません。

+0

このインテルの機能はどのように呼び出されますか?あるいは、ドキュメンテーションへのリンクやハッキングについてのリンクがありますか? –

1

にまともな最適化コンパイラを打ち負かすのは難しいです。 1)プラットフォームに依存する最適化コードの作成、2)複数のプラットフォームでの構築。

最初の問題はかなり簡単です。プラットフォームに依存するコードを一連の関数にカプセル化します。プラットフォームごとに各機能の異なる実装を作成します。各実装をそれ自身のファイルまたはファイルのセットに入れます。それぞれのプラットフォームのコードを別々のディレクトリに置くのがビルドシステムにとって最も簡単です。

第2部では、Gnu Atuotools(Automake、AutoConf、およびLibtool)をご覧ください。ソースコードからGNUプログラムをダウンロードしてビルドしたことがあるなら、makeを実行する前に./configureを実行しなければならないことを知っています。 configureスクリプトの目的は、1)システムに必要なすべてのライブラリとユーティリティがプログラムをビルドして実行する必要があることを確認し、2)ターゲットプラットフォームのMakefileをカスタマイズすることです。 Autotoolsは、configureスクリプトを生成するための一連のユーティリティです。

autoconfを使用すると、ほとんどのマクロを作成して、マシンがプラットフォーム依存コードに必要なすべてのCPU命令をサポートしているかどうかを確認できます。ほとんどの場合、マクロはすでに存在しているので、autoconfスクリプトにコピーするだけです。次に、automakeとautoconfはMakefileを設定して、適切な実装を引き出すことができます。

ここでは例を作成するためにこれが少し役に立ちます。学ぶのに少し時間がかかります。しかし、ドキュメントはすべてそこにあります。オンラインで利用できるfree bookもあります。このプロセスは将来のプロジェクトにも適用されます。マルチプラットフォームのサポートのために、これは本当に最も堅牢で簡単な方法です。他の答えに載っている提案の多くは、Autotoolsが扱うもの(CPU検出、静的&共用ライブラリのサポート)であり、あまり考える必要はありません。あなたが処理しなければならないかもしれない唯一のしわは、AutotoolsがMinGWで利用可能かどうかを調べることです。あなたがそのルートに行くことができるなら、彼らはCygwinの一部であることを知っています。

関連する問題