J'ai joué avec OpenCL récemment, et je suis capable d'écrire des noyaux simples qui utilisent uniquement la mémoire globale. Maintenant, je voudrais commencer à utiliser la mémoire locale, mais je n'arrive pas à comprendre comment utiliser get_local_size()
et get_local_id()
pour calculer un "morceau" de sortie à la fois.
Par exemple, disons que je voulais convertir le noyau d'exemple OpenCL Hello World d'Apple en quelque chose qui utilise la mémoire locale. Comment feriez-vous? Voici la source originale du noyau:
__kernel square(
__global float *input,
__global float *output,
const unsigned int count)
{
int i = get_global_id(0);
if (i < count)
output[i] = input[i] * input[i];
}
Si cet exemple ne peut pas être facilement converti en quelque chose qui montre comment utiliser la mémoire locale, tout autre exemple simple fera l'affaire.
Découvrez les exemples dans les SDK NVIDIA ou AMD, ils devraient vous orienter dans la bonne direction. La transposition matricielle utiliserait la mémoire locale par exemple.
En utilisant votre noyau quadratique, vous pouvez mettre en scène les données dans un tampon intermédiaire. N'oubliez pas de passer le paramètre supplémentaire.
__kernel square(
__global float *input,
__global float *output,
__local float *temp,
const unsigned int count)
{
int gtid = get_global_id(0);
int ltid = get_local_id(0);
if (gtid < count)
{
temp[ltid] = input[gtid];
// if the threads were reading data from other threads, then we would
// want a barrier here to ensure the write completes before the read
output[gtid] = temp[ltid] * temp[ltid];
}
}
Il existe une autre possibilité de le faire, si la taille de la mémoire locale est constante. Sans utiliser de pointeur dans la liste des paramètres des noyaux, le tampon local peut être déclaré dans le noyau simplement en le déclarant __local:
__local float localBuffer[1024];
Cela supprime le code en raison de moins d'appels clSetKernelArg.
Dans OpenCL, la mémoire locale est destinée à partager des données entre tous les éléments de travail d'un groupe de travail. Et cela nécessite généralement d'effectuer un appel de barrière avant que les données de la mémoire locale puissent être utilisées (par exemple, un élément de travail souhaite lire des données de mémoire locale écrites par les autres éléments de travail). La barrière est coûteuse en matériel. Gardez à l'esprit que la mémoire locale doit être utilisée pour la lecture/écriture répétée des données. Les conflits bancaires doivent être évités autant que possible.
Si vous ne faites pas attention à la mémoire locale, vous risquez de finir avec des performances moins bonnes que l'utilisation de la mémoire globale.