Question

Je travaille sur un projet qui génère un très grand nombre de chaînes de texte séquentielles, dans une boucle très serrée. Mon application utilise fortement les extensions de jeu d'instructions SIMD comme SSE et MMX, dans d'autres parties du programme, mais le générateur de clés est CLAIN C ++.

La façon dont mon générateur de clés fonctionne est que j'ai une classe KeyGenerator, qui contient un seul tableau de char qui stocke la clé actuelle. Pour obtenir la clé suivante, il existe une fonction appelée "incrémentKey", qui traite la chaîne comme un nombre, en ajoutant une à la chaîne, transportant si nécessaire.

Maintenant, le problème est que le Keygen est un peu un goulot d'étranglement. C'est rapide, mais ce serait bien si c'était plus rapide. L'un des plus gros problèmes est que lorsque je génère un ensemble de touches séquentielles à traiter en utilisant mon code SSE2, je dois faire stocker l'ensemble entier dans un tableau, ce qui signifie que je dois générer et copier séquentiellement 12 chaînes dans un Array, un par un, comme ainsi:

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

Alors, comment généreriez-vous efficacement ces chaînes en texte en clair dans l'ordre? J'ai besoin de quelques idées pour aider à déplacer cela. La concurrence serait bien; Comme mon code est actuellement, chaque clé successive dépend de la précédente, ce qui signifie que le processeur ne peut pas commencer à travailler sur la touche suivante tant que le courant a été complètement généré.

Voici le code pertinent pour le générateur de clés:

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];
};

Persstemset.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;
};
Était-ce utile?

La solution

Eh bien .. en termes de performances, tous les nouveaux / strcpy / strMP vous font probablement beaucoup plus mal que votre keygen.

Allouez votre mémoire dans une piscine plus grande à la fois, puis utilisez des pointeurs.

Avec Keygen, vous devez éviter de vous en tenir à l'abstraction qui fuit de la clé unique produite, produit à la place la quantité optimale à la fois. Peut-être des multiples plus grands.

Sur certains intervalles, vous pouvez réellement utiliser SSE / MMX pour produire les clés, au moins lorsque la chaîne est alignée et est divisible par votre longueur de mot SSE / MMX. Vous pouvez également essayer de le remplir avec 0, puis de les éloigner si la chaîne ne l'est pas. Cela ne vaut probablement pas vraiment l'effort si vous n'en générez que 16 à la fois.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top