Les sources du bench sont disponibles sur github
Génération du fichier de test
Le "cahier des charges" fournit par "bbo" était le suivant :- ~10 000 000 de lignes.
- ~200 caractères par ligne.
- ~20 champs (4/5 gros champs autour de 20 caractères.)
Cette classe génère donc un fichier de 10 000 000 de lignes contenant des lignes avec 20 champs :
- Quatre champs de type String et de 30 caractères
- Quatre champs de type Boolean (1 ou 0)
- Quatre champs de type Integer et de 5 chiffres
- Quatre champs de type Double et de 5 chiffres avant la virgule et 5 chiffres après la virgule
- Quatre champs de type String et de 5 caractères
Voici le résultat de la génération du fichier :
Statistiques sur la taille des lignes :
- Minimum : 215 caractères
- Maximum : 227 caractères
- Moyenne : 225,666 caractères
Génération en 70 576ms
Le résultat est donc à peu près conforme au cahier des charges.
Constitution du bench
Le bench est réalisé par la classe Bench (je sais, je suis trop bon pour trouver des noms).Pour le bench, je ne pouvais pas utiliser la méthode permettant de parser tout le fichier et qui renvoie une liste d'objet. Vu la taille du fichier, il est facile de comprendre que le mettre entièrement en mémoire ne serait pas une bonne idée.
Heureusement le moteur contient une autre méthode permettant de réaliser un traitement pour chaque ligne : MoteurCsv.parseFileAndInsert
Dans le cadre du bench j'ai donc utilisé cette méthode en ne réalisant aucun traitement :
public static void bench1() throws FileNotFoundException { long startTime = System.currentTimeMillis(); moteur.parseFileAndInsert(new FileReader(fichier), ObjetCsv.class, new InsertObject<objetcsv>() { @Override public void insertObject(ObjetCsv objet) { // On ne fait rien dans le cadre du bench. } }); long elapsedTime = (System.currentTimeMillis() - startTime); System.out.println("Lecture du fichier : " + elapsedTime + "ms"); }
J'ai également créé une méthode permettant de voir l'utilisation mémoire au fur et à mesure du test.
Le but de cette méthode est de regarder la mémoire occupée avant et après un GC entre chaque itération du bench. Cela permettra de vérifier entre autre qu'il n'y ait pas fuite mémoire.
public static void gestionMemoire() { // Mémoire totale allouée long totalMemory = Runtime.getRuntime().totalMemory(); // Mémoire utilisée long currentMemory = totalMemory - Runtime.getRuntime().freeMemory(); System.out.println("Mémoire avant gc : " + (currentMemory / 1024) + "ko/" + (totalMemory / 1024) + "ko"); System.gc(); // Mémoire totale allouée totalMemory = Runtime.getRuntime().totalMemory(); // Mémoire utilisée currentMemory = totalMemory - Runtime.getRuntime().freeMemory(); System.out.println("Mémoire après gc : " + (currentMemory / 1024) + "ko/" + (totalMemory / 1024) + "ko"); }
Résultats
Les tests ont été menés sur un MacBookPro équipé d'un disque SSD et d'un Code i5.Étape | Temps | Mémoire occupée avant GC | Mémoire occupée après GC |
---|---|---|---|
Avant de commencer | / | 1 734ko | 338ko |
Instanciation du moteur | 58 222µs | 14 049ko | 387ko |
Lecture du fichier (itération 1) | 65 902ms | 14 049ko | 387ko |
Lecture du fichier (itération 2) | 65 864ms | 13 796ko | 341ko |
Lecture du fichier (itération 3) | 64 638ms | 14 059ko | 341ko |
Lecture du fichier (itération 4) | 65 214ms | 13 700ko | 341ko |
Lecture du fichier (itération 5) | 66 560ms | 14 027ko | 341ko |
Ces résultats permettent de montrer plusieurs choses :
- Temps pour instancier le moteur : quasi-null
- Mémoire persistante pour le moteur : quelques Ko
- Performances plutôt satisfaisantes avec un peu plus d'une minute pour lire un fichier de plus de 2Go
J'ai également fait du profiling avec YourKit afin de vérifier le comportement interne du moteur, cela a montré que la majorité du temps est passé dans la librairie open-csv, l'overhead du moteur est donc plutôt faible.
Reproduire le bench
N'hésitez pas à reproduire le bench et à me dire les résultats que vous obtenez :- Cloner le projet depuis github : github.com/ybonnel/BenchMoteurCsv
- Importer le projet en tant que projet maven dans Eclipse
- Lancer d'abord le main de la classe GenerationFchierCsv afin de générer le fichier de test
- Lancer ensuite le main de classe Bench afin de lancer le bench en lui-même