2010-02-08 4 views
4

J'ai un grand programme C++ qui modifie le mot de contrôle FPU (en utilisant _controlfp()). Il démasque certaines exceptions FPU et installe un SEHTranslator pour produire des exceptions C++ typées. J'utilise VC++ 9.0.Contrôle du comportement du FPU dans un programme OpenMP?

Je voudrais utiliser OpenMP (v.2.0) pour paralléliser certaines de nos boucles de calcul. Je l'ai déjà appliqué avec succès à un, mais les résultats numériques sont légèrement différents (même si je comprends que cela pourrait aussi être dû au fait que les calculs sont effectués dans un ordre différent). Je suppose que c'est parce que l'état FPU est spécifique au thread. Existe-t-il un moyen pour que les threads OpenMP héritent de cet état du thread principal? Ou existe-t-il un moyen de spécifier en utilisant OpenMP que les nouveaux threads exécutent une fonction particulière qui définit l'état correct? Quelle est la manière idiomatique de gérer cette situation?

+0

@Sting: Votre profil aboutme vous indique que vous souhaitez supprimer votre profil? visitez http://meta.stackexchange.com/questions/31048/closing-out-my-stack-overflow-account/31054#31054 –

+0

Avec quel flag/fp compilez-vous? –

Répondre

0

La probabilité est que cela a à voir avec l'ordre des opérations en virgule flottante. Nous nous fions tous à ce que nos opérations soient associatives et commutatives, mais la vérité malheureuse est que les opérations à virgule flottante ne sont pas commutatives, alors lorsqu'elles sont parallélisées, les résultats peuvent varier parce que l'ordre est aléatoire. Essayez d'exécuter vos boucles en arrière et de voir si le résultat diffère. Si vous avez des besoins par thread, OMP fournit des garanties sur les itérations de boucles tombant sur les mêmes threads, c'est-à-dire si vous bouclez de 1 à N sur un quad core, les itérations 1 à N/4 seront exécutées sur le même fil.

-Rick

1
  1. Comme vous l'avez dit déjà, les opérations à double/flotteur ne sont pas associatives/commutative/distribuer sous forme de nombres réels en mathématiques. En particulier, multiplier/diviser un grand nombre/très petit nombre peut entraîner des erreurs de précision notables lorsque vous changez l'ordre de calcul.

  2. L'état de l'unité FPU doit être spécifique au thread car l'état est représenté sous la forme d'un registre et l'état du registre (= contexte) est spécifique à un thread.

  3. Il est ambigu de dire qui a donné naissance fils héritent de l'état du thread maître parce que état n'est pas clair dans ce contexte. Si vous voulez inscrire le statut, alors ce n'est pas le cas.

  4. Ma suggestion est pourquoi ne pas simplement définir le mot de contrôle FPU pour chaque thread? Par exemple, avant de générer un thread OpenMP, c'est-à-dire, avant le parallélogramme, stockez le mot de contrôle FPU actuel dans une variable globale en utilisant _status87. Ensuite, placez des instructions qui lisent la variable globale et définissent une nouvelle valeur en parallèle pour l'itération. Comme il est en lecture seule sur la variable globale, vous ne vous souciez pas de la course de données.

unsigned int saved_status = _status87(); 
#pragma omp parallel for (...) 
for (int i = 0; i < N; ++i) 
{ 
    _controlfp(saved_status, ...); 

    .. 
} 
0

J'ai conclu que je n'ai pas de problème. Les différences de résultats sont dues à l'ordre des calculs, pas à l'état FPU dans les différents threads (nous ne changeons pas les modes de précision ou d'arrondi). Comme le masquage des exceptions FPU est différent dans les threads de travail, ce n'est pas un problème car si un thread de travail effectue une opération qui entraînerait une exception, ce résultat (maintenant NaN ou Inf, etc.) finira par "prendre en compte" le thread principal et l'exception seront lancés.

De plus, une exception doit être interceptée dans le même thread OpenMP qui l'a lancé. Cela signifie que je veux seulement que le thread principal soit capable de lancer des exceptions de toute façon.

Questions connexes