Le endl C++ est défini pour sortir '\n' suivi d'un vidage. flush () est une opération coûteuse, vous devez donc généralement éviter d'utiliser endl comme fin de ligne par défaut car cela peut créer exactement le problème de performances que vous voyez (et pas seulement avec SMB, mais avec n'importe quel ofstream avec un flush coûteux, y compris la rotation locale rouille ou même le dernier NVMe à un taux de sortie ridiculement élevé).
Remplacer endl par "\n" corrigera les performances ci-dessus en permettant au système de mettre en mémoire tampon comme prévu. Sauf que certaines bibliothèques peuvent vider sur "\n", auquel cas vous avez plus de maux de tête (voir https://stackoverflow.com/questions/21129162/tell-endl-not-to-flush pour une solution remplaçant la méthode sync() ).
Maintenant, pour compliquer les choses, flush() n'est défini que pour ce qui se passe dans les tampons de la bibliothèque. L'effet du vidage sur le système d'exploitation, le disque et les autres tampons externes n'est pas défini. Pour Microsoft.NET "Lorsque vous appelez la méthode FileStream.Flush, le tampon d'E/S du système d'exploitation est également vidé." (https://msdn.microsoft.com/en-us/library/2bw4h516(v=vs.110).aspx) Cela rend le vidage particulièrement coûteux pour Visual Studio C++ car il fera l'aller-retour de l'écriture jusqu'à le support physique à l'extrémité de votre serveur distant comme vous le voyez. GCC, d'autre part, dit "Un dernier rappel :il y a généralement plus de tampons impliqués que ceux au niveau de la langue/de la bibliothèque. Les tampons du noyau, les tampons de disque, etc. auront également un effet. L'inspection et la modification de ceux-ci dépendent du système. ." (https://gcc.gnu.org/onlinedocs/libstdc++/manual/streambufs.html) Vos traces Ubuntu sembleraient indiquer que les tampons du système d'exploitation/réseau ne sont pas vidés par la bibliothèque flush(). Un comportement dépendant du système serait une raison de plus pour éviter les endl et les vidages excessifs. Si vous utilisez VC++, vous pouvez essayer de passer à un dérivé de Windows GCC pour voir comment les comportements dépendants du système réagissent, ou bien utiliser Wine pour exécuter l'exécutable Windows sur Ubuntu.
Plus généralement, vous devez réfléchir à vos besoins pour déterminer si le rinçage de chaque ligne est approprié ou non. endl convient généralement aux flux interactifs tels que l'affichage (nous avons besoin que l'utilisateur voie réellement notre sortie, et non en rafales), mais ne convient généralement pas aux autres types de flux, y compris les fichiers où la surcharge de vidage peut être importante. J'ai vu des applications vider toutes les écritures de 1 et 2 et 4 et 8 octets... ce n'est pas joli de voir le système d'exploitation moudre des millions d'E/S pour écrire un fichier de 1 Mo.
Par exemple, un fichier journal peut avoir besoin de vider chaque ligne si vous déboguez un plantage car vous devez vider le flux ofstream avant que le plantage ne se produise; tandis qu'un autre fichier journal n'a peut-être pas besoin de vider chaque ligne s'il ne produit qu'une journalisation informative détaillée qui devrait se vider automatiquement avant la fin de l'application. Il n'est pas nécessaire que ce soit l'un ou l'autre, car vous pouvez dériver une classe avec un algorithme de vidage plus sophistiqué pour répondre à des besoins spécifiques.
Comparez votre cas avec le cas contrasté des personnes qui doivent s'assurer que leurs données sont complètement conservées sur le disque et non vulnérables dans un tampon du système d'exploitation (https://stackoverflow.com/questions/7522479/how-do-i-ensure-data -est-écrit-sur-disque-avant-fermeture-fstream).
Notez que tel qu'il est écrit, outFile.flush() est superflu car il vide un ofstream déjà vidé. Pour être pédant, vous auriez dû utiliser endl seul ou de préférence "\n" avec outFile.flush() mais pas les deux.
Les performances des opérations de fichiers distants, telles que la lecture/écriture, à l'aide du protocole SMB peuvent être affectées par la taille des tampons alloués par les serveurs et les clients. La taille de la mémoire tampon détermine le nombre d'allers-retours nécessaires pour envoyer une quantité fixe de données. Chaque fois que des requêtes et des réponses sont envoyées entre le client et le serveur, le temps nécessaire est au moins égal à la latence entre les deux côtés, ce qui peut être très important dans le cas d'un réseau étendu (WAN).
Tampon SMB -- Le MaxBufferSize peut être configuré via le paramètre de registre suivant :
HKLM\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters\SizeReqBuf
Type de données :REG_DWORD
Plage :1 024 à 65 535 (choisissez une valeur en fonction de vos besoins au-dessus de 5 000)
MAIS SMB SIGNING affecte la taille de tampon maximale autorisée. Nous devons donc également désactiver la signature SMB pour atteindre notre objectif. Le registre suivant doit être créé côté serveur et si possible côté client également.
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\LanManWorkstation\Parameters
Nom de la valeur :EnableSecuritySignature
Type de données :REG_DWORD
Données :0 (désactiver), 1 (activer)
Je n'ai pas assez de réputation pour laisser un commentaire (ce qui, je pense, serait mieux compte tenu du niveau de vérification de cette réponse).
Je remarque qu'une grande différence dans votre trace de niveau Linux vs Windows est que vous utilisez SMB1 sous Linux et SMB2 sous Windows. Peut-être que le mécanisme oplock par lots fonctionne mieux dans SMB1 samba que l'implémentation de bail exclusif SMB2. Dans les deux cas, cela devrait permettre une certaine quantité de mise en cache côté client.
1) Essayez peut-être de définir un niveau de protocole maximal inférieur dans Samba pour essayer Windows avec SMB12) Validez que les oplocks ou les baux exclusifs sont supprimés
J'espère que cela vous aidera :)