1

我正在开发一个项目,该项目会在一个非常紧凑的循环中生成大量连续的文本字符串。我的应用程序在程序的其他部分大量使用了 SSE 和 MMX 等 SIMD 指令集扩展,但密钥生成器是纯 C++。

我的密钥生成器的工作方式是我有一个 keyGenerator 类,它包含一个存储当前密钥的 char 数组。要获取下一个键,有一个名为“incrementKey”的函数,它将字符串视为一个数字,在字符串中加一,必要时携带。

现在,问题是,keygen 有点瓶颈。它很快,但如果它更快,那就太好了。最大的问题之一是,当我使用我的 SSE2 代码生成一组要处理的顺序键时,我必须将整个集合存储在一个数组中,这意味着我必须顺序生成 12 个字符串并将其复制到一个数组,一个一个,像这样:

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

那么如何有效地按顺序生成这些明文字符串呢?我需要一些想法来帮助推动这一进程。并发会很好;正如我现在的代码一样,每个连续的键都依赖于前一个键,这意味着处理器在当前键完全生成之前无法开始处理下一个键。

这是与密钥生成器相关的代码:

密钥生成器.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];
};

字符集.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

嗯.. 性能方面,所有新的/strcpy/strmp 可能比你的 keygen 对你的伤害更大。

一次将内存分配到一个更大的池中,然后在其中使用指针。

使用 keygen,您应该避免坚持生成的单个密钥的泄漏抽象,而是一次生成最佳数量。可能更大的倍数。

在某些间隔上,您实际上可以使用 SSE/MMX 来生成密钥,至少当字符串对齐并且可以被 SSE/MMX 字长整除时。您也可以尝试用 0 填充它,然后如果字符串不是,则将它们移开。如果您一次只生成 16 个,则可能不值得付出努力。

于 2010-03-31T23:27:43.083 回答