1

非常にタイトなループで、非常に多数の連続したテキスト文字列を生成するプロジェクトに取り組んでいます。私のアプリケーションでは、プログラムの他の部分で SSE や MMX などの SIMD 命令セット拡張機能を多用していますが、キー ジェネレーターは単純な C++ です。

私のキー ジェネレーターのしくみは、現在のキーを格納する 1 つの char 配列を保持する keyGenerator クラスを使用することです。次のキーを取得するには、「incrementKey」という関数があり、文字列を数値として扱い、文字列に 1 を加え、必要に応じて保持します。

さて、問題は、keygen がややボトルネックになっていることです。速いですが、もっと速かったらいいのに。最大の問題の 1 つは、SSE2 コードを使用して処理するシーケンシャル キーのセットを生成する場合、セット全体を配列に格納する必要があることです。つまり、12 個の文字列をシーケンシャルに生成して、次のように、1 つずつ配列します。

char* keys[12];
for(int i = 0; i < 12; i++)
{
    keys[i] = new char[16];
    strcpy(keys[i], keygen++);
}

では、これらの平文文字列を効率的に順番に生成するにはどうすればよいでしょうか? これを進めるには、いくつかのアイデアが必要です。並行性はいいでしょう。私のコードは現在、連続する各キーは前のキーに依存しています。つまり、現在のキーが完全に生成されるまで、プロセッサは次のキーの作業を開始できません。

キージェネレーターに関連するコードは次のとおりです。

KeyGenerator.h

class keyGenerator
{

public:

    keyGenerator(unsigned long long location, characterSet* charset)
            : location(location), charset(charset)
    {           
        for(int i = 0; i < 16; i++)
            key[i] = 0;

        charsetStr = charset->getCharsetStr();
        integerToKey();
    }

    ~keyGenerator()
    {
    }

    inline void incrementKey()
    {
        register size_t keyLength = strlen(key);

        for(register char* place = key; place; place++)
        {
            if(*place == charset->maxChar)
            {
                // Overflow, reset char at place
                *place = charset->minChar;

                if(!*(place+1))
                {
                    // Carry, no space, insert char
                    *(place+1) = charset->minChar;
                    ++keyLength;

                    break;
                }
                else
                {
                    continue;
                }
            }
            else
            {
                // Space available, increment char at place
                if(*place == charset->charSecEnd[0]) *place = charset->charSecBegin[0];
                else if(*place == charset->charSecEnd[1]) *place = charset->charSecBegin[1];

                (*place)++;

                break;
            }
        }
    }

    inline char* operator++() // Pre-increment
    {
            incrementKey();
            return key;
    }

    inline char* operator++(int) // Post-increment
    {
            memcpy(postIncrementRetval, key, 16);
            incrementKey();

            return postIncrementRetval;
    }

    void integerToKey()
    {
        register unsigned long long num = location;

        if(!num)
        {
            key[0] = charsetStr[0];
        }
        else
        {
            num++;

            while(num)
            {
                num--;
                unsigned int remainder = num % charset->length;
                num /= charset->length;

                key[strlen(key)] = charsetStr[remainder];
            }
        }
    }

    inline unsigned long long keyToInteger()
    {
        // TODO
        return 0;
    }

    inline char* getKey()
    {
        return key;
    }

private:

    unsigned long long location;

    characterSet* charset;
    std::string charsetStr;

    char key[16];

    // We need a place to store the key for the post increment operation.
    char postIncrementRetval[16];
};

CharacterSet.h

struct characterSet
{
    characterSet()
    {
    }

    characterSet(unsigned int len, int min, int max, int charsec0, int charsec1, int charsec2, int charsec3)
    {
        init(length, min, max, charsec0, charsec1, charsec2, charsec3);
    }

    void init(unsigned int len, int min, int max, int charsec0, int charsec1, int charsec2, int charsec3)
    {
        length = len;
        minChar = min;
        maxChar = max;

        charSecEnd[0] = charsec0;
        charSecBegin[0] = charsec1;
        charSecEnd[1] = charsec2;
        charSecBegin[1] = charsec3;
    }

    std::string getCharsetStr()
    {
        std::string retval;

        for(int chr = minChar; chr != maxChar; chr++)
        {
            for(int i = 0; i < 2; i++) if(chr == charSecEnd[i]) chr = charSecBegin[i];
            retval += chr;
        }

        return retval;
    }

    int minChar, maxChar;

    // charSec = character set section
    int charSecEnd[2], charSecBegin[2];

    unsigned int length;
};
4

1 に答える 1

1

まあ..パフォーマンスに関しては、すべての new/strcpy/strmp はおそらくキー生成よりもはるかにあなたを傷つけています.

一度に大きなプールにメモリを割り当ててから、その中でポインタを使用します。

keygen では、生成された単一のキーの漏れのある抽象化に固執するのを避け、代わりに一度に最適な量を生成する必要があります。より大きな倍数の可能性があります。

特定の間隔で、少なくとも文字列が整列され、SSE/MMX ワード長で割り切れる場合は、実際に SSE/MMX を使用してキーを生成できます。文字列がそうでない場合は、0 でパディングしてからシフトすることもできます。一度に 16 個しか生成できない場合は、おそらくそれほど努力する価値はありません。

于 2010-03-31T23:27:43.083 に答える