2009-05-20 8 views
7

J'ai un tas de tampons (25 à 30 d'entre eux) dans mon application qui sont assez grands (.5mb) et accessibles simulataneousley. Pour le rendre encore pire, les données qu'ils contiennent ne sont généralement lues qu'une seule fois, et elles sont mises à jour fréquemment (comme 30 fois par seconde). Une sorte de tempête parfaite d'utilisation de cache non optimale. De toute façon, il m'est apparu que ce serait cool si je pouvais marquer un bloc de mémoire comme non-cache ... Théoriquement, cela laisserait plus de place dans le cache pour tout le reste.Est-il possible d'allouer, dans l'espace utilisateur, un bloc de mémoire non cacheable sur Linux?

Alors, est-ce que c'est un moyen d'obtenir un bloc de mémoire marqué comme non cacheable sous Linux?

+0

Je pense que cela nuirait à perf - en marquant comme non-cacheable toutes les mises à jour fréquentes devraient aller en mémoire plutôt que d'écrire dans le cache. – Michael

+0

Le cache n'est utile que dans ce cas si les écritures ne sont pas séquentielles et si plusieurs écritures tombent sur la même ligne de cache. Si les écritures sont semi-aléatoires et qu'au moment où le même emplacement est réécrit, l'emplacement a été vidé du cache. –

+0

@Michael - les mises à jour sont supposées * contourner le cache dans ce cas. – Tom

Répondre

8

Comment éviter de polluer les caches avec des données comme celles-ci est couvert par What Every Programmer Should Know About Memory (PDF) - Ceci est écrit du point de vue du développement Red Hat si parfait pour vous. Cependant, la plus grande partie est multi-plateforme. Ce que vous voulez est appelé "Accès non-temporel" et dites au processeur de s'attendre à ce que la valeur que vous lisez maintenant ne soit plus nécessaire pendant un certain temps. Le processeur évite ensuite la mise en cache de cette valeur.

Voir page 49 du PDF I lié ci-dessus. Il utilise l'intel intrinsèque pour faire le streaming autour du cache.

Du côté de la lecture, les processeurs, jusqu'à récemment, à part le soutien ne disposaient pas conseils faibles en utilisant un accès non-temporelle (NTA) des instructions de prélecture. aucun équivalent à la combinaison d'écriture pour lectures, ce qui est particulièrement mauvais pour mémoire non accessible comme E/S mappées en mémoire. Intel, avec les extensions SSE4.1, introduit des charges NTA . Ils sont implémentés en utilisant un petit nombre de tampons de chargement en continu ; chaque tampon contient une ligne de cache . La première instruction movntdqa pour une ligne de cache donnée va charger une ligne de cache dans un tampon, éventuellement en remplaçant une autre ligne de cache. Les accès alignés suivants de 16 octets à la même ligne de cache sera desservie à partir du tampon de charge à peu de frais. À moins qu'il y ait d'autres raisons pour faire ainsi, la ligne de cache ne sera pas chargée dans un cache, permettant ainsi le chargement de grandes quantités de mémoire sans polluer les caches.Le compilateur fournit un intrinsèque pour cette instruction:

#include <smmintrin.h> 
__m128i _mm_stream_load_si128 (__m128i *p); 

Cette intrinsèque devrait être utilisé plusieurs fois, avec des adresses de blocs de 16 octets transmis en tant que paramètre , jusqu'à ce que chaque ligne de mémoire cache est lis. Ce n'est qu'alors que la ligne de cache suivante doit être démarrée. Comme il y a quelques le streaming lire les tampons, il est peut-être possible de lire de deux mémoires endroits à la fois

Il serait parfait pour vous si lors de la lecture, les tampons sont lus dans l'ordre linéaire à travers la mémoire. Vous utilisez des lectures en streaming pour le faire. Lorsque vous voulez les modifier, les tampons sont modifiés dans un ordre linéaire, et vous pouvez utiliser les écritures en continu pour le faire si vous ne vous attendez pas à les lire de sitôt dans le même thread.

0

Sur certaines architectures de processeur, des instructions spéciales peuvent être utilisées pour marquer certaines lignes de cache comme désactivées. Cependant, ils sont généralement spécifiques à l'architecture et dépendent de certaines instructions d'assemblage. Donc, je vous conseille de vous référer à la documentation de l'architecture du processeur et de comprendre comment le faire dans l'assemblage. Vous pouvez ensuite utiliser l'assemblage en ligne avec GCC pour l'activer. Cela rendrait la performance nulle. PS: Si vous le pouvez, vous voudrez peut-être penser à une façon différente de gérer les données?

+0

Vous ne pourrez pas utiliser des instructions comme celles-ci depuis l'espace utilisateur ... – bdonlan

+0

Oui, sur les processeurs où il s'agit d'une instruction privilégiée. Ensuite, avec Linux, vous devrez trouver un endroit pour le déposer dans l'espace du noyau et écrire une sorte de fonction d'espace utilisateur pour y accéder. – sybreon

1

Vous pouvez également vous intéresser à l'affinité du processeur pour réduire l'encombrement du cache.

2

Les données fréquemment mises à jour sont en fait l'application parfaite du cache. Comme jdt mentionné, les caches CPU modernes sont assez grandes, et 0.5mb pourrait bien tenir dans le cache. Plus important, cependant, lire-modifier-écrire en mémoire non-attachée est TRÈS lent - la lecture initiale doit bloquer sur la mémoire, alors l'opération d'écriture AUSSI doit bloquer sur la mémoire pour commettre. Et juste pour ajouter l'insulte à la blessure, le CPU pourrait implémenter une mémoire non-cache en chargeant les données dans le cache, puis invalider immédiatement la ligne de cache - vous laissant ainsi dans une position qui est garanti être pire qu'avant. Avant d'essayer de dérouter le CPU comme cela, vous devriez vraiment tester l'ensemble du programme et voir où se trouve le vrai ralentissement. Les profileurs modernes tels que cachegrind de valgrind peuvent mesurer les échecs de cache, ainsi vous pouvez trouver si c'est aussi une source significative de ralentissement. Sur un autre point, plus pratique, si vous faites 30 RMW par seconde, il s'agit dans le pire des cas de quelque chose de l'ordre de 1920 octets d'encombrement du cache. Ceci est seulement 1/16 de la taille L1 d'un processeur Core 2 moderne, et susceptible d'être perdu dans le bruit général du système. Donc, ne vous en faites pas trop :)

Cela dit, si par «accédé simultanément» vous voulez dire «accédé par plusieurs threads simultanément», faites attention aux lignes de cache qui rebondissent entre les processeurs. Cela ne serait pas aidé par la mémoire RAM non attachée - si cela devait être pire, car les données devraient retourner à la RAM physique à chaque fois au lieu de passer éventuellement par le bus inter-CPU plus rapide - et la seule façon L'éviter en tant que problème est de minimiser la fréquence d'accès aux données partagées. Pour en savoir plus à ce sujet, voir http://www.ddj.com/hpc-high-performance-computing/217500206

+0

Lecture-modification-écriture est très lent, mais ce n'est qu'un problème si vous n'écrivez pas sur une ligne de cache entière sur un petit nombre d'instructions. La CPU peut détecter si une ligne de cache entière a été modifiée et évite la lecture. –

+0

Le verrouillage de la mémoire d'un autre processeur dans le cache est également supposé être très lent, donc je serais prudent dans votre affirmation qu'il est plus rapide de verrouiller la mémoire pour une modification dans un autre cache que de lire cette même mémoire du système . –

Questions connexes