7
votes

Comment mieux gérer les grands tampons dans une pile de protocoles en couches?

Je travaille sur une simple pile de protocoles pour un petit système embarqué (MultiDrop, type Type RS485). Dans cette pile, des modèles portataires après les couches OSI:

  1. application
  2. Réseau
  3. DataLink
  4. Physique (Pilote série)

    Chaque couche a sa propre portion d'en-tête / pied de page qui enveloppe la charge utile du calque au-dessus de celle-ci.

    J'utiliserai mon propre bassin tampon de blocs de taille fixe alloués statiquement alloués pour stocker les paquets binaires. (Pas de malloc / gratuit dans cette application.)

    Dans d'autres API, j'ai vu que les données sont généralement transmises en tant que pointeur constant avec une longueur associée. De cette manière, les données auraient besoin d'une opération de copie à chaque couche car la charge utile du calque ci-dessus est placée dans un tampon nouvellement attribué pour la couche de courant.

    Pour une pile à trois couches, ce serait 2 opérations de copie et 3 tampons alloués.

    Y a-t-il un meilleur moyen de le faire et de maintenir la séparation propre des couches de protocole?

    Pour mieux ancrer la discussion, disons que les paquets sont généralement environ 2K et le processeur est un petit micro-micro 8 bits à 8 MHz.


3 commentaires

8 bits micro @ 8mHz et paquet de 2kb? Vous n'avez pas mentionné la RAM disponible, mais je devinerais que le paquet le remplit à peu près et que vous exécutez clairement un «processus unique», je suppose que je ne vois pas la raison de créer autant de couches et d'abstractions pour un système aussi simple. rompez-la dans "Transmission de données" et "Application" et transmettez la charge utile via un pointeur sur un global.


@Mark, la pile de protocole doit être utilisée sur différentes plates-formes, l'une est une ATMEGA1281 avec une RAM 8K. Il peut être horrible à 20 MHz, mais nous ne le faisons pas pour des raisons de puissance. Je pourrais détendre la séparation des préoccupations, mais ce n'est pas le point de ma question.


@Mark, vous avez raison sur le tampon 2k, je ne pourrai probablement pas aller aussi grand, mais pour cette application, plus, mieux c'est que c'est une chaîne de données de latence élevée (satellite) et je ne prévois pas d'ajouter du fenêteur (comme c'est le cas avec TCP).


3 Réponses :


0
votes

Dans d'autres API, j'ai vu que les données sont généralement transmises en tant que pointeur constant avec une longueur associée. De cette manière, les données auraient besoin d'une opération de copie à chaque couche car la charge utile du calque ci-dessus est placée dans un tampon nouvellement attribué pour la couche de courant.

Je suppose que vous donnez un exemple d'une API pour un tampon de transmission.

Je pense que vous pouvez conserver la même API, si vous ajoutez la restriction que quiconque invoque cette API n'est pas autorisé à utiliser ou à toucher ce tampon à nouveau avant de recevoir une notification ultérieure que l'opération d'émission a terminé: afin d'invoquer la API transforme implicitement la propriété de ce tampon.


0 commentaires

7
votes

Vous pouvez éviter les copies en demandant à chaque couche de demander un tampon vide à partir de la couche inférieure suivante, plutôt que d'attribuer l'un même:

  • Demande de la couche d'application Tampon Longueur la de la couche réseau.
  • La couche réseau demande la longueur de la mémoire tampon LA + LN de la couche de DataLink.
  • DataLink Layer demande la longueur de la mémoire tampon LA + LN + LD de la couche physique.
  • La couche physique tire un tampon de la piscine tampon.
  • La couche physique renvoie tampon + phdr_len à DataLink Couche.
  • DataLink Layer retourne tampon + phdr_len + dhdr_len à la couche réseau.
  • La couche de réseau renvoie tampon + phdr_len + dhdr_len + nhdr_len au calque d'application.
  • La couche d'application remplit les données dans la mémoire tampon fourni et appelle la couche de réseau à transmettre.
  • La couche réseau compense l'en-tête et appelle la couche DataLink à transmettre.
  • DataLink Layer achète l'en-tête et appelle une couche physique à transmettre.
  • La couche physique compense l'en-tête et passe au matériel.

2 commentaires

Ou, les en-têtes des différentes couches n'ont pas besoin d'être contigus (dans un seul tampon): ils pourraient plutôt être dans différents tampons à l'aide d'une API "Scatter Rassembler".


Merci @CAF, je pensais à cela comme une solution possible aussi. Au point de get_buffer () appeler la couche supérieure assumerait la responsabilité du tampon. Il faudrait être un free_buffer () sur chaque couche en plus d'un envoi (PBUF) en cas de problème, de sorte que le tampon puisse être libéré correctement.



4
votes

Créer une structure tampon. Avec la connaissance de la taille maximale à la couche inférieure, allouez suffisamment d'espace tampon dans la couche supérieure pour préparer chaque couche successive car elle descend la pile. Chaque couche déplace le pointeur dans la structure tampon sous forme d'une couche.

à la couche inférieure, le démarrage du tampon est enregistré dans le pointeur de la structure tampon. Les données à envoyer sont dans un tampon contigu. Aucune donnée n'a été copiée à chaque couche.

Aller du bas au sommet Vous décoller des couches dans la structure tampon.


5 commentaires

C'est l'approche la plus simple, car elle ne nécessite qu'un seul tampon et aucune copie. Pour un périphérique esclave, le tampon est typiquement défini dans la couche physique, car c'est là où les messages proviennent.


Et si vous avez des types de paquets différents, vous venez de faire référence à un pointeur de structure d'un autre type.


Le problème avec ceci est que la couche supérieure doit savoir à quel point chaque couche inférieure a besoin, ce qui est le couplage serré que l'OP tente d'éviter (je crois que la référence à la "séparation propre des couches de protocole" était à peu près).


@CAF: En effet. Pour les appareils esclaves, c'est typiquement la couche inférieure qui contient le tampon. Cela évite parfaitement le problème, car la taille maximale du message fait souvent partie de la spécification de la couche inférieure. Lorsque la couche supérieure doit contenir le tampon, ces informations doivent être connues par la couche supérieure. Je suppose que c'est le moindre de deux maux, si les ressources sont limitées!


Le succès de cette approche dépend souvent de la quantité de contrôle que vous avez sur les pilotes de pile de protocoles et de périphériques. J'ai travaillé sur des systèmes intégrés de faible puissance dans lesquels j'avais un contrôle complet sur la pile et les pilotes de protocole - évitant la copie entre les threads / couches nous a permis de stimuler le débit.