一番早い方法はど多くのバイトが等しいとの固定長配列
-
02-07-2019 - |
質問
私は2つの配列の16の要素(文字数)を必要とすることを"比較"ど多くの要素が等しい間はご対応できません
このルーチンで使用される単位百万倍(通常の実行では約60~70万倍)ながらやっていく必要があるでし可能です。うC++(C++ビルダーは、2007年の記録)
現在、シンプルです:
matches += array1[0] == array2[0];
繰り返しの16倍としてプロファイリングを示すことにより30%より速いてforループ)
他にあるであることから仕事が早い?
一部のデータ環境についてのデータそのもの:
- を使用していC++ビルダーを持たない速度の最適化を考慮しない。まずれもコンパイラのもんこだわったことです。
- これらのデータを異なるものです。100%同等のデータは、通常非常に珍しいもの1%未満)
解決
更新:この答えが変更される私のコメントのソースコードは以下の通りです。
が最適化ありの場合は、利用SSE2、popcntください。
16バイトが馴染は、SSEするものとする。C++を用いた組立/intrinsics、負荷の16バイト配列へのxmm登録、cmpます。を含むに関連して発生するビットマスクを代表するtrue/falseの状況を比較できます。ご使用されmovmsk指導への負荷の少し表現のビットマスクへのx86名簿こそがビットの分野でカウントのすべての1のど真の価値観ました。ハードウェアpopcnt指導できる、カウントを1にするものとする。
この知識が求められるので組み立て/intrinsics、SSE。対応することができるでしょう索ウェブ資源です。
行った場合、このコードの機械をサポートしないのいずれかSSE2はpopcntば、繰り返し処理を実行し、配列や回数の違いと丸められないループです。
幸運
編集:できなかった知ら組み立て、こちらのサンプルコードを明ら私の答え:
#include "stdafx.h"
#include <iostream>
#include "intrin.h"
inline unsigned cmpArray16( char (&arr1)[16], char (&arr2)[16] )
{
__m128i first = _mm_loadu_si128( reinterpret_cast<__m128i*>( &arr1 ) );
__m128i second = _mm_loadu_si128( reinterpret_cast<__m128i*>( &arr2 ) );
return _mm_movemask_epi8( _mm_cmpeq_epi8( first, second ) );
}
int _tmain( int argc, _TCHAR* argv[] )
{
unsigned count = 0;
char arr1[16] = { 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0 };
char arr2[16] = { 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0 };
count = __popcnt( cmpArray16( arr1, arr2 ) );
std::cout << "The number of equivalent bytes = " << count << std::endl;
return 0;
}
一部の注この機能を使SSE2の指示とpopcnt指導をPhenomプロセッサー(その機します。私は最新のIntelプロセッサーを搭載し、SSE4もpopcnt.この関数はチェックを行うよう指導支援CPUID;その機能は未定義の場合に使用されるプロセッサを持たないSSE2はpopcnt(しょうか無効opcode指導).る検出コードが別のスレです。
をしていないのでわこのコードその理由だと思うから多く寄せられるご質問にあるので比較は16バイト時に支店を持たない.きをいつでも変更することがわお客様の環境、時間を自分でだを動作させることができます。私たこVS2008SP1.
信用格好みのデータが設置されており、自然の16バイト境界;ができることを保証して必要な追加速度の改善、変更することができ_mm_loadu_si128指_mm_load_si128、アライメントを実施します。
他のヒント
重要なのは、比較の最大の登録CPUサポート、その後スクフォースメンバーであるバイトが必要です。
以下のコードを示を4バイト整数になって走行SIMD建築(現代のIntelまたはAMDチップ)までを比較し、両方の配列が一つの命令の後に整数に基づくループを実行します。ほとんどのコンパイラこれらの日本質的な支援のための128ビットの種類にはなりませんを必要とASM.
(注のSIMD comparisionsご配列においては16バイトを揃えて、一部のプロセッサ(e.g MIPS)にとって必要であることが分かっ配列する4バイト整列をintに基づく。
E.g.
int* array1 = (int*)byteArray[0];
int* array2 = (int*)byteArray[1];
int same = 0;
for (int i = 0; i < 4; i++)
{
// test as an int
if (array1[i] == array2[i])
{
same += 4;
}
else
{
// test individual bytes
char* bytes1 = (char*)(array1+i);
char* bytes2 = (char*)(array2+i);
for (int j = 0; j < 4; j++)
{
same += (bytes1[j] == bytes2[j];
}
}
}
どうかよろしくお願いしますように、MSVCのコンパイラのサポートSIMDが、なにができるようなもの;
// depending on compiler you may have to insert the words via an intrinsic
__m128 qw1 = *(__m128*)byteArray[0];
__m128 qw2 = *(__m128*)byteArray[1];
// again, depending on the compiler the comparision may have to be done via an intrinsic
if (qw1 == qw2)
{
same = 16;
}
else
{
// do int/byte testing
}
ない場合は、管理能力の位置、配列、を用のメモリをインスタンスでこの搭載のCPUキャッシュにアクセス。
によってCPUとそのキャッシュ構造によって異なり、また機械です。
みなさんのメモリ階層構造およびキャッシュ Henessy&Pattersonのコンピュータ-アーキテクチャ:定量的アプローチ
が必要な場合は絶対最低ンフットプリントさんと組み立てます。俺はこのがんベットMMX以上がSSE2/3)を導入できるでそれがいください。
場合は、共通の場合はその荷重の値として32ビットのint値の代わりに16でを比較することができる2つの近くに、カウントで2試合).
の場合には、32ビットの値 ない 同じようにして実行してくださいいので別に上下16ビット値)。
コードにより、複雑ながらも必要になります。
を対象としている場合は64ビットのシステムなにができるのと同じトリック64ビットintまたは制限を落ちやアセンブラを用い、種々のベクトルに基づく指導というような仕事を128ビットです。
魔法のコンパイラオプションは異なりの時間ます。特にこの生成SSEベクトル化に続く巨大なスピードアップを図.
これをプラットフォーム非依存の、またはこのコードは常に、同じタイプのCPU?ご自分を制限する現代のx86Cpu、ご利用できる場合もあり MMX 指示を許可すべきでの運用と配列の8バイトを一時計の目盛.AFAIK、gccできる、埋め込み組み立てにはコード、およびインテルのコンパイラ(icc)に対応しintrinsics、包装できるように呼び特定の組立て説明書が入ってます。その他のSIMD命令セットなどのSSE、も有用であると期待されます。
あとは値の配列のイ?一部のバイトが同じでもしております。されています一部の固有の価値?その最適化のための中でも最も高い。
ご説明のデータを表すそのあとは全く違うことがわかりを代表するデータをメモリしてしまうようなこのタイプの力を比較します。ケアに触れながらのデータを表す??
で、一層スピードアップし、一つ。
matches += (array1[0] == array2[0]) + (array1[1] == array2[1]) + ...;
場合を書くためには、16時よりも早く簡単にループしてコンパイラは吸い込みやすい最適化します。
答え:がより速く、しないといベクトル並列ハードウェア
使い方のポインタの代わりに配列:
p1 = &array1[0];
p2 = &array2[0];
match += (*p1++ == *p2++);
// copy 15 times.
もちろんの計測が必要これに対する取組事前にご確認くださいができます。
やせていただきましたこのルーチンはボトルネックの加工?だ実際に速度パフォーマンスをアップのお申し込み全体を最適化。再度、測定を伝えていきます。
必要があります。を修正することができます方に配列す。比較1バイトの時間は非常に遅く考えであり、32ビットコンパイラです。代わりにご納16バイト4つの整数型(32-bit)または2つのlong値(64-bit)だけを実行することが必要な4または2を比較した。
の質問を自分自身に尋ねする費はどのくらいのデータを保存するとして4つの整数型または2つの長さの配列.どのくらいの頻度でアクセスに必要なデータなどです。
常にある、古き良きx86REPNE CMPました。
トライでき最適化だからほとんどの時間、配列は同一ですが少し速くなmemcmp()は第一段階として設定'16'に対する回答の場合この試験はtrueを返します。合コースでない場合の配列同一であるものが多いようだが遅いものです。