Pregunta

Estoy trabajando en un proyecto que genera una gran cantidad de cadenas de texto secuenciales, en un bucle muy ajustado. Mi aplicación hace un uso pesado de las extensiones de establecimiento de instrucciones SIMD como SSE y MMX, en otras partes del programa, pero el generador de claves es C ++ simple.

La forma en que funciona mi generador de claves es que tengo una clase KeyGenerator, que contiene una sola matriz de char que almacena la clave actual. Para obtener la siguiente clave, hay una función llamada "IncrementKey", que trata la cadena como un número, agregando uno a la cadena, llevando cuando sea necesario.

Ahora, el problema es que el keygen es algo así como un cuello de botella. Es rápido, pero sería bueno si fuera más rápido. Uno de los mayores problemas es que cuando estoy generando un conjunto de claves secuenciales para procesarse usando mi código SSE2, tengo que tener el conjunto completo almacenado en una matriz, lo que significa que tengo que generar y copiar secuencialmente 12 cadenas en una Array, uno por uno, como así:

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

Entonces, ¿cómo generaría de manera eficiente estas cadenas de texto sin formato en orden? Necesito algunas ideas para ayudar a avanzar. La concurrencia sería buena; Como es mi código en este momento, cada clave sucesiva depende de la anterior, lo que significa que el procesador no puede comenzar a trabajar en la siguiente clave hasta que la actual se haya generado por completo.

Aquí está el código relevante para el generador de claves:

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

Personaje

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;
};
¿Fue útil?

Solución

Bueno ... en cuanto al rendimiento, todos los nuevos/strcpy/strmp probablemente te lastimen mucho más que tu keygen.

Asigne su memoria en una piscina más grande a la vez y luego use consejos dentro de ella.

Con Keygen, debe evitar pegarse a la abstracción de fugas de la clave única producida, producir en su lugar la cantidad óptima a la vez. Posiblemente múltiplos más grandes.

En ciertos intervalos, realmente puede usar SSE/MMX para producir las teclas, al menos cuando la cadena está alineada y es divisible por la longitud de la palabra SSE/MMX. También puede intentar rellenarlo con 0 y luego cambiarlos si la cadena no lo es. Probablemente no valga la pena el esfuerzo si solo genera 16 a la vez.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top