2009-11-23 10 views
1

d'un CUDA je besoin d'aide s'il vous plaît. J'ai commencé à programmer un forer/password guesser brut commun avec CUDA (2.3/3.0beta). J'ai essayé différentes manières de générer tous les "candidats" en texte brut possibles d'un jeu de caractères ASCII défini.Générer toutes les combinaisons d'un tableau de caractères à l'intérieur du noyau

Dans cet exemple de code que je veux générer tous les 74^​​4 combinaisons possibles (et la sortie juste le résultat à l'hôte/stdout).

$ ./combinations 
Total number of combinations : 29986576 

Maximum output length : 4 
ASCII charset length : 74 

ASCII charset : 0x30 - 0x7a 
":;<=>[email protected][\]^_`abcdefghijklmnopqrstuvwxy" 

code CUDA (compilé avec 2.3 et 3.0b - sm_10) - combinaions.cu:

#include <stdio.h> 
#include <cuda.h> 

__device__ uchar4 charset_global = {0x30, 0x30, 0x30, 0x30}; 
__shared__ __device__ uchar4 charset[128]; 

__global__ void combo_kernel(uchar4 * result_d, unsigned int N) 
{ 
int totalThreads = blockDim.x * gridDim.x ; 
int tasksPerThread = (N % totalThreads) == 0 ? N/totalThreads : N/totalThreads + 1; 
int myThreadIdx = blockIdx.x * blockDim.x + threadIdx.x ; 
int endIdx = myThreadIdx + totalThreads * tasksPerThread ; 
if(endIdx > N) endIdx = N; 

const unsigned int m = 74 + 0x30; 

for(int idx = myThreadIdx ; idx < endIdx ; idx += totalThreads) { 
    charset[threadIdx.x].x = charset_global.x; 
    charset[threadIdx.x].y = charset_global.y; 
    charset[threadIdx.x].z = charset_global.z; 
    charset[threadIdx.x].w = charset_global.w; 
    __threadfence(); 

    if(charset[threadIdx.x].x < m) { 
    charset[threadIdx.x].x++; 

    } else if(charset[threadIdx.x].y < m) { 
    charset[threadIdx.x].x = 0x30; // = 0 
    charset[threadIdx.x].y++; 

    } else if(charset[threadIdx.x].z < m) { 
    charset[threadIdx.x].y = 0x30; // = 0 
    charset[threadIdx.x].z++; 

    } else if(charset[threadIdx.x].w < m) { 
    charset[threadIdx.x].z = 0x30; 
    charset[threadIdx.x].w++;; // = 0 
    } 

    charset_global.x = charset[threadIdx.x].x; 
    charset_global.y = charset[threadIdx.x].y; 
    charset_global.z = charset[threadIdx.x].z; 
    charset_global.w = charset[threadIdx.x].w; 

    result_d[idx].x = charset_global.x; 
    result_d[idx].y = charset_global.y; 
    result_d[idx].z = charset_global.z; 
    result_d[idx].w = charset_global.w; 
} 
} 

#define BLOCKS 65535 
#define THREADS 128 

int main(int argc, char **argv) 
{ 
const int ascii_chars = 74; 
const int max_len = 4; 
const unsigned int N = pow((float)ascii_chars, max_len); 
size_t size = N * sizeof(uchar4); 

uchar4 *result_d, *result_h; 
result_h = (uchar4 *)malloc(size); 
cudaMalloc((void **)&result_d, size); 
cudaMemset(result_d, 0, size); 

printf("Total number of combinations\t: %d\n\n", N); 
printf("Maximum output length\t: %d\n", max_len); 
printf("ASCII charset length\t: %d\n\n", ascii_chars); 

printf("ASCII charset\t: 0x30 - 0x%02x\n ", 0x30 + ascii_chars); 
for(int i=0; i < ascii_chars; i++) 
    printf("%c",i + 0x30); 
printf("\n\n"); 

combo_kernel <<< BLOCKS, THREADS >>> (result_d, N); 
cudaThreadSynchronize(); 

printf("CUDA kernel done\n"); 
printf("hit key to continue...\n"); 
getchar(); 

cudaMemcpy(result_h, result_d, size, cudaMemcpyDeviceToHost); 

for (unsigned int i=0; i<N; i++) 
    printf("result[%06u]\t%c%c%c%c\n",i, result_h[i].x, result_h[i].y, result_h[i].z, result_h[i].w); 

free(result_h); 
cudaFree(result_d); 
} 

Le code devrait compiler sans problème, mais la sortie est pas ce que je pensais.

En mode d'émulation:

CUDA kernel done hit 
key to continue... 

    result[000000] 1000 
... 
    result[000128] 5000 

Sur le mode de sortie:

CUDA kernel done hit 
key to continue... 

    result[000000] 1000 
... 
    result[012288] 5000 

J'ai aussi utilisé __threadfence() et ou __syncthreads() sur différentes lignes du code aussi sans succès ...

ps. Si possible, je veux générer tout à l'intérieur de la fonction du noyau. J'ai aussi essayé « pré » génération des candidats en texte clair possible à l'intérieur hôte fonction principale et memcpy à dispositif, cela ne fonctionne qu'avec une taille charset très limitée (en raison de la mémoire de l'appareil limité).

  • une idée sur la sortie, pourquoi le répéter (même avec __threadfence() ou __syncthreads())?

  • toute autre méthode pour générer le texte brut (candidats) à l'intérieur du noyau CUDA rapide :-) (~ 75^8)?

grâce un million

accueille janvier

Répondre

0

Voyons voir:

  • Lorsque vous remplissez votre tableau charset, __syncthreads() suffira que vous n'êtes pas intéressé par écrit à la mémoire globale (plus tard)
  • vos if déclarations ne sont pas correctement votre remise à zéro boucle itérateurs:
    • Dans z < m, puis les deux x == m et y == m et doivent tous deux être mis à 0.
    • similaires pour w
  • Chaque fil est chargé d'écrire un ensemble de 4 caractères charset, mais chaque thread écrit les mêmes 4 valeurs. Aucun thread ne fonctionne indépendamment.
  • Vous écrivez chaque fils résultats à la mémoire globale sans Atomics, ce qui est dangereux.Il n'y a aucune garantie que les résultats ne seront pas immédiatement bousculés par un autre thread avant de les relire.
  • Vous lisez les résultats du calcul de la mémoire globale immédiatement après les avoir écrits dans la mémoire globale. On ne sait pas pourquoi vous faites cela et c'est très dangereux.
  • Enfin, il n'y a pas de moyen fiable dans CUDA pour une synchronisation entre tous les blocs, ce qui semble être ce que vous espérez. L'appel __threadfence s'applique uniquement aux blocs en cours d'exécution sur le périphérique, qui peuvent être un sous-ensemble de tous les blocs devant être exécutés pour un appel de noyau. Ainsi, cela ne fonctionne pas comme une primitive de synchronisation.

Il est probablement plus facile de calculer les valeurs initiales de x, y, z et w pour chaque thread. Ensuite, chaque thread peut commencer à boucler à partir de ses valeurs initiales jusqu'à ce qu'il ait effectué des itérations tasksPerThread. Ecrire les valeurs peut probablement continuer plus ou moins comme vous l'avez maintenant.

EDIT: Voici un programme de test simple pour démontrer les erreurs de logique dans votre boucle itération:

int m = 2; 
int x = 0, y = 0, z = 0, w = 0; 

for (int i = 0; i < m * m * m * m; i++) 
{ 
    printf("x: %d y: %d z: %d w: %d\n", x, y, z, w); 
    if(x < m) { 
     x++; 
    } else if(y < m) { 
     x = 0; // = 0 
     y++; 
    } else if(z < m) { 
     y = 0; // = 0 
     z++; 
    } else if(w < m) { 
     z = 0; 
     w++;; // = 0 
    } 
} 

La sortie est la suivante:

x: 0 y: 0 z: 0 w: 0 
x: 1 y: 0 z: 0 w: 0 
x: 2 y: 0 z: 0 w: 0 
x: 0 y: 1 z: 0 w: 0 
x: 1 y: 1 z: 0 w: 0 
x: 2 y: 1 z: 0 w: 0 
x: 0 y: 2 z: 0 w: 0 
x: 1 y: 2 z: 0 w: 0 
x: 2 y: 2 z: 0 w: 0 
x: 2 y: 0 z: 1 w: 0 
x: 0 y: 1 z: 1 w: 0 
x: 1 y: 1 z: 1 w: 0 
x: 2 y: 1 z: 1 w: 0 
x: 0 y: 2 z: 1 w: 0 
x: 1 y: 2 z: 1 w: 0 
x: 2 y: 2 z: 1 w: 0 
+0

Salut, merci pour votre réponse! Mon idée était que "__device__ uchar4 charset_global" est une sorte de matrice principale. chaque bloc de thread doit aller chercher "valeur actuelle de charset_global" dans le jeu de caractères partagé [128], faire la combinaison suivante (remplir un calcul avec le jeu de caractères ici) et enfin écrire la combinaison "déjà calculé par le fil" . (ainsi le thread suivant peut utiliser la "combinaison déjà faite" comme décalage). J'espère que vous m'avez bien compris;)) ps. "Vos instructions if ne réinitialisent pas correctement les itérateurs de boucle" - doivent être correctes sur userland - origin: combfunc aocp – sead

+0

Je n'ai aucune idée de ce que signifie "travailler correctement dans userland", mais vous pouvez voir l'utilisation du code dans mon edit qu'il y a effectivement des problèmes avec l'itération de la boucle. – Eric

+1

L'algorithme que vous décrivez (dans votre commentaire) est un algorithme série. En d'autres termes, aucun thread ne peut calculer un mot de passe unique avant d'avoir obtenu le résultat d'un thread précédent. Aucun thread ne peut fonctionner en parallèle car il commencerait par le même mot de passe initial et le permuterait de la même manière, produisant une sortie dupliquée. La façon de paralléliser ceci est de comprendre que vous générerez 74^​​N combinaisons possibles et chaque thread générera 74^​​N/M de ces combinaisons complètement indépendant de ce que n'importe quel autre thread fait. – Eric

1

Soit dit en passant, votre boucle lié est trop complexe. Vous n'avez pas besoin de faire tout ce travail pour calculer l'endIdx, mais vous pouvez faire ce qui suit, simplifiant le code.

for(int idx = myThreadIdx ; idx < N ; idx += totalThreads)