l'amélioration de C tampon circulaire de l'efficacité
J'aimerais un peu d'aide l'amélioration de l'efficacité de mon tampon circulaire de code.
J'ai eu un coup d'oeil autour de stackoverflow et a constaté que (presque) tous les sujets sur la circulaire tampons sur les utilisations d'un tel tampon ou de la base de la mise en œuvre d'un tampon circulaire. J'ai vraiment besoin d'informations sur la façon de le rendre super efficace.
Le plan est d'utiliser ce tampon avec la STM32F4 microcontrôleur qui a un seul precicion FPU.
J'ai l'intention de faire un usage intensif de surtout la write() et readn (). Nous sommes littéralement parlant quelques millions d'appels en voici un deuxième, afin de rasage de quelques cycles d'horloge ici et là va vraiment faire une différence.
Je vais mettre le plus important de bits de code ici, l'intégralité de la mémoire tampon de code est disponible via http://dl.dropbox.com/u/39710897/circular%20buffer.rar
Quelqu'un peut-il me donner quelques conseils sur la façon d'améliorer l'efficacité de ce tampon?
#define BUFF_SIZE 3 //buffer size set at compile time
typedef struct buffer{
float buff[BUFF_SIZE];
int readIndex;
int writeIndex;
}buffer;
/********************************\
* void write(buffer* buffer, float value)
* writes value into the buffer
* @param buffer* buffer
* pointer to buffer to be used
* @param float value
* valueto be written in buffer
\********************************/
void write(buffer* buffer,float value){
buffer->buff[buffer->writeIndex]=value;
buffer->writeIndex++;
if(buffer->writeIndex==BUFF_SIZE)
buffer->writeIndex=0;
}
/********************************\
* float readn(buffer* buffer, int Xn)
* reads specified value from buffer
* @param buffer* buffer
* pointer to buffer to be read from
* @param int Xn
* specifies the value to be read from buffer counting backwards from the most recently written value
* i.e. the most recently writen value can be read with readn(buffer, 0), the value written before that with readn(buffer, 1)
\********************************/
float readn(buffer* buffer, int Xn){
int tempIndex;
tempIndex=buffer->writeIndex-(Xn+1);
while(tempIndex<0){
tempIndex+=BUFF_SIZE;
}
return buffer->buff[tempIndex];
}
readIndex
n'est pas utilisé.readindex est en effet pas utilisé dans les fonctions énumérées ci-dessus. Il est utilisé bien que dans le read (), fonction qui peut être trouvé dans le fichier rar. Le readn() la fonction énumérés ici sert à lire une valeur spécifique de la mémoire tampon (c'est à dire l'avant-dernière valeur écrite)
OriginalL'auteur Gurba | 2012-03-15
Vous devez vous connecter pour publier un commentaire.
"Oli Charlesworth", a suggéré - que vous seriez en mesure de simplifier les choses si votre taille de la mémoire tampon est la puissance de 2. Je voudrais écrire à la lecture/écriture de la fonction des organes, de sorte que l'intention est de plus en plus clair.
Quelques explications. Notez qu'il n'y a pas de branchement (
if
). Nous ne limitons pas l'index de tableau pour les limites du tableau, au lieu que nous sommes ET-ing avec le masque.Dans
readn
au lieu de calculer l'indice d'accès commewriteIndex - (Xn+1)
nous utilisons:
writeIndex + (~Xn)
Cela fonctionne en supposant 2-complément de l'arithmétique. C'est, dans le but de faire de l'entier négatif, nous le faisons PAS à tous ses bits, puis en ajoutant 1. Mais puisque vous voulez soustraire 1 de le faire est tout simplement PAS tout ce qui est nécessaire.
unsigned
types d'index. Ensuite, vous n'avez pas à argumenter sur 2-compléter ou des trucs comme ça.Je vous remercie BEAUCOUP, cela a fait mon code environ 6,5 fois plus vite! Je dirais que plutôt une amélioration spectaculaire
depuis, je peux mettre 1 seule réponse acceptée, je vais avec celui-ci parce que des exemples, même si Oli Charlesworth est venu avec une réponse similaire.
Il pourrait être judicieux d'essayer de faire ReadArray et WriteArray fonctions qui doivent travailler avec des tableaux plutôt que des valeurs uniques. Ou de faire écrire et readn comme des macros ou en ligne, les procédures (en cas de compilateur C++). Dans ce cas, vous pouvez éviter certains de la pile de la charge de travail, qui peut vous donner les cycles de l'uc.
writeIndex qui finira par déborder
OriginalL'auteur
Si vous pouvez faire de votre taille de la mémoire tampon d'une puissance de 2, puis la case à contre zéro peut être remplacé par inconditionnelle de bits de masquage. Sur la plupart des processeurs, ce devrait être plus rapide.
Je vais enquêter sur ce, faisant d'elle une puissance de 2 est assez facile (suffit de le définir BUFF_SIZE à 4). Je vais creuser un peu pour le bit de masquage si
Je suppose que l'application finale sera beaucoup plus grande taille de la mémoire tampon? Sinon je serais fortement en question l'utilisation de l'anneau de la mémoire tampon de l'ADT dans la première place.
OriginalL'auteur
De conserver une trace du début et de la fin de la mémoire tampon circulaire avec des pointeurs, est probablement un peu plus rapide que le tableau d'indexation, depuis l'adresse sera calculée lors de l'exécution dans le cas de la seconde. Essayez de remplacer readIndex et writeIndex avec
float*
à la place. Le code serait alorsbuffer + BUFF_SIZE
va encore être une expression constante et le compilateur se traduire que d'une adresse fixe au moment de la compilation.OriginalL'auteur
Cela peut ne pas sembler élégant mais qui est efficace. Accès aux éléments de structure à travers le pointeur prend beaucoup d'instructions. Pourquoi ne pas supprimer la structure complètement et faire
buffer
etwriteIndex
comme des variables globales? Cela permettra de diminuer considérablement la taille de votrereadn
etwrite
fonctions.J'ai essayé de gcc et voici le résultat avec et sans la structure
Avec Structure
Sans Structure. ie Faire
buffer
etwriteIndex
mondialbuff
etwriteIndex
, tout le reste doit être le même. Otoh, que sans les optimisations tout accès comme lesbuff->...
serait longueCela ne fonctionnera pas si l'OP a besoin de plus qu'un tampon instance.
Hmmm.. Mais le compilateur semble être de faire quelque chose d'autre. J'ai essayé avec
-O2
et le code résultant semble être beaucoup plus grand que celles mentionnées ci-dessus :OVous êtes de droite. Il faudrait alors créer plus globale tampons/indices de ce qui allait devenir plus encombrant. C'est pourquoi j'ai ajouté le
not so elegant
phrase dans ma réponse 🙂Je vais garder cela à l'esprit, mais je doute que je vais l'utiliser. Je n'ai en effet besoin de plusieurs instances et cela semble juste unmaintanable pour moi.. je vais simplement se confondre trop souvent
OriginalL'auteur