5つの小さい整数のうち最大の2つをできるだけ早く見つける


9

小さな組み込みシステムの画像データに5クロスメディアンフィルターのバリエーションを使用します。

    x
  x x x
    x

アルゴリズムは本当にシンプルです。5つの符号なし整数値を読み取り、最高の2を取得し、それらについていくつかの計算を行い、符号なし整数の結果を書き戻します。

5つの整数入力値がすべて0〜20の範囲にあるのはすばらしいことです。計算された整数値も0〜20の範囲です。

プロファイリングを通じて、最大の2つの数値を取得することがボトルネックであることを理解したので、この部分を高速化したいと思います。この選択を実行する最も速い方法は何ですか?

現在のアルゴリズムは、5つの数値とHWがサポートするCLZ関数によって指定された位置に1を持つ32ビットマスクを使用します。
CPUは専有のCPUであり、社外では利用できません。私のコンパイラはGCCですが、このCPU用にカスタマイズされています。

ルックアップテーブルを使用できるかどうかを確認しようとしましたが、使用できるキーを生成できませんでした。

入力には組み合わせがありますが、順序は重要ではありません。つまり、と同じです。215[5,0,0,0,5][5,5,0,0,0]

以下のハッシュ関数が衝突することなく完全なハッシュを生成することが起こります!

def hash(x):
    h = 0
    for i in x:
        h = 33*h+i
    return h

しかし、ハッシュは巨大であり、それを使用するのに十分なメモリがありません。

私が使用できるより良いアルゴリズムはありますか?ルックアップテーブルを使用してキーを生成することで問題を解決できますか?


1
現在どのアルゴリズムを使用していますか?7つの整数の比較で十分ですが、遅すぎますか?あなたはhashすでにより多くの操作を実行しています。メソッドへの後続の呼び出しは関連していxますか。たとえば、中央は行列を行ごとに移動しますか?
ラファエル

フィルターは、画像を1行ずつたたみ込みます。つまり、5つの値を取得して計算を行い、すべてを1ステップ右に移動して繰り返します。ハッシュはほんの一例です。データの読み取りを最小限に抑えるために、いくつかのスライディングウィンドウソリューションのベンチマークを行いましたが、結局、最高の2つの値を見つけることになります。
Fredrik Pihl、2015

3
おそらく、アルゴリズムが適切に実装されていれば、計算ではなくメモリアクセスによって制限されます。ハッシュテーブルを使用すると、メモリアクセスの量が増え、速度が低下するだけです。現在のコードを投稿して、どのように改善できるかを確認してください-マイクロ最適化のみが可能だと思います。私が考えることができる最も多くは、次のとおりです。おそらく、隣接するウィンドウ間で2つの値が共通しているという事実を利用できるでしょうか。
jkff 2015

@jkffマトリックス、キャッシュサイズ、および(キャッシュ)マッピング関数によっては、すべての値を1回だけロードすればよい場合があります。ほとんどの操作は、レジスタまたはL1キャッシュで実行する必要があります。ただし、パイプライン処理は別の問題です。
ラファエル

1
ちなみに、これはすでに並行して行っていますか?これは、ベクトル並列化またはSIMD(GPUなど)に特に適しているようです。そのルートは、セルあたり数パーセントを節約するだけではなく、はるかに役立ちます。
ラファエル

回答:


11

私の他の答えでは、条件付きジャンプが効率の主な障害になる可能性があることを示唆しています。結果として、 ソートネットワークが思い浮かびます。これらはデータにとらわれず、入力に関係なく同じシーケンスの比較が実行され、条件付きのスワップのみが実行されます。

U^2(5)=6

彼がソリューションで提供するネットワーク(ゼロベースの配列に書き直された)は

[0:4][1:4][0:3][1:3][0:2][1:2]

実装する-比較の方向を調整した後-擬似コードとして

def selMax2(a : int[])
  a.swap(0,4) if a[0] < a[4]
  a.swap(1,4) if a[1] < a[4]
  a.swap(0,3) if a[0] < a[3]
  a.swap(1,3) if a[1] < a[3]
  a.swap(0,2) if a[0] < a[2]
  a.swap(1,2) if a[1] < a[2]
  return (a[0], a[1])
end

現在、ナイーブな実装には、(スワップコード全体で)条件付きジャンプがまだあります。ただし、マシンによっては、条件付きの命令でそれらを回避することができます。x86は通常のだらしのないもののようです。ほとんどの操作は それ自体が条件付きであるため、ARMはより有望に見えます。手順を 正しく理解している場合、最初のスワップはこれに変換されます。これは、配列の値がR0を介してレジスタにロードされていると想定したものR4です。

CMP     R0,R4
MOVLT   R5 = R0
MOVLT   R0 = R4
MOVLT   R4 = R6

はい、もちろん、EORでXORスワッピング を使用できます。

私はあなたのプロセッサがこれまたは類似のものを持っていることを願っています。もちろん、この目的のために物事を構築する場合、ネットワークをハードワイヤードにすることができますか?

これはおそらく(おそらく?)古典的な領域で実行できる最高の方法です。つまり、制限されたドメインを利用せず、邪悪な単語内魔術を実行する必要はありません。


  1. ドナルドE.クヌースによる並べ替えと検索アートオブコンピュータプログラミング Vol。3(第2版、1998)
  2. W^2(5)=7

これを受け入れます。先に進む前にベンチマークする必要がある多くの新しいアイデアを受け取りました。Knuthを参照することは常に私にとってうまくいきます:-)あなたの努力と時間をありがとう!
Fredrik Pihl、2015

@FredrikPihlかっこいい、最後にどうなるか教えてください!
ラファエル

します!5.3.3章を今読んでください。ルイスキャロルとテニストーナメントを参照して、それの始まりを愛してください:-)
Fredrik Pihl

2
命令セットによっては、選択ネットワークとともに2 * max(a、b)= a + b + abs(ab)を使用すると便利です。予測不可能な条件付きジャンプよりもコストがかからない可能性があります(absの組み込みまたは条件付きの移動がなくても、少なくともx86の場合、gccは、x86に依存していないように見えるジャンプのないシーケンスを生成します)。ジャンプレスシーケンスは、SIMDまたはGPUと組み合わせる場合にも役立ちます。
AProgrammer 2015

1
選択ネットワーク(並べ替えネットワークなど)は、並列操作に適していることに注意してください。具体的には、指定された選択ネットワークで、1:4と0:3の比較を並行して実行でき(プロセッサ、コンパイラーなどが効率的にサポートしている場合)、1:3と0:2の比較も並行して実行できます。
Bruce Lilly

4

ちょうどそれがテーブルにあるように、ここに直接アルゴリズムがあります:

// Sort x1, x2
if x1 < x2
  M1 = x2
  m1 = x1
else
  M1 = x1
  m1 = x2
end

// Sort x3, x4
if x3 < x4
  M2 = x4
  m2 = x3
else
  M2 = x3
  m2 = x4
end

// Pick largest two
if M1 > M2
  M3 = M1
  if m1 > M2
    m3 = m1
  else
    m3 = M2
  end
else
  M3 = M2
  if m2 > M1
    m3 = m2
  else
    m3 = M1
  end
end

// Insert x4
if x4 > M3
  m3 = M3
  M3 = x4
else if x4 > m3
  m3 = x4
end

を巧妙に実装することによりif ... else、直接翻訳の無条件ジャンプを取り除くことができます。

これは醜いですが、

  • 5つまたは6つの比較(条件付きジャンプ)、
  • 9から10の割り当て(11変数、すべてレジスター)および
  • 追加のメモリアクセスはありません。

W2(5)

ただし、これはパイプラインを備えたマシンでは高速であるとは期待できません。条件付きジャンプの割合が高いことを考えると、ほとんどの時間はおそらくストールに費やされるでしょう。

より単純なバリアント-並べ替えてx1からx2、その後他の値を挿入する-は、4〜7回の比較と5〜6回の代入のみを行うことに注意してください。ここではジャンプの方がコストが高いと予想しているので、これにこだわりました。


  1. ドナルドE.クヌースによる並べ替えと検索アートオブコンピュータプログラミング Vol。3(第2版、1998)

最適化コンパイラがこれらを使って何ができるのでしょうか。
ラファエル

これを実装し、現在のCLZベースのソリューションに対してベンチマークします。御時間ありがとうございます!
Fredrik Pihl、2015

1
@FredrikPihlベンチマークの結果はどうでしたか?
ラファエル

1
SWAPベースのアプローチはCLZに勝ります!今モバイルで。モバイルでさらに多くのデータを投稿できます
Fredrik Pihl

かっこいい!古き良き理論のアプローチが(まだ)実用的であることに満足しています。:)
ラファエル

4

これは、Souperプロジェクトの優れたアプリケーションおよびテストケースになる可能性があります。 Souperは、スーパーオプティマイザーです。入力として短いコードシーケンスを受け取り、それを可能な限り最適化しようとします(より高速になる同等のコードシーケンスを見つけようとします)。

Souperはオープンソースです。コードスニペットでSouperを実行して、もっと効果があるかどうかを確認してみてください。

16ビットの4ビット値をソートするための高速コードの記述に関するJohn Regehrのコンテストも参照してください。そこにあるテクニックのいくつかが役に立つかもしれません。


これがOPが試みているプログラムで何ができるかに興味があります。
ラファエル

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.