Performance de NSKeyedArchiver

UniXUniX Membre
22:38 modifié dans API AppKit #1
Salut.

J'utilise NSKeyedArchiver pour enregistrer sur le disque des données. Il s'agit d'un tableau contenant environs 1500 objets d'une classe perso.

Le temps d'enregistrement sur disque est très long (à  peu près 30 secondes), alors que le fichier résultant sur le disque ne fait que 960 ko .....

J'ai monitoré pour voir quelle partie du processus était longue, en plaçant un NSLog dans la méthode encodeWithCoder: de la classe perso. Je pensais que ça pouvait venir du fait qu'il y a 1500 objets ....

Et bien non ! Je passe au travers de la méthode encodeWithCoder: en 1 ou 2 secondes.
Donc à  priori, c'est vraiment la phase d'écriture sur disque qui est longue ....
Pourquoi ?

Réponses

  • schlumschlum Membre
    22:38 modifié #2
    Tu monitores avec un NSLog toi ?  :P
    Utilise Shark pour ce genre de choses... Tu verras bien si c'est le I/O qui occupent le processeur ou autre chose.
  • UniXUniX Membre
    22:38 modifié #3
    Je viens de lancer Shark, mais j'avoue que ça m'éclaircie pas beaucoup plus ....
  • schlumschlum Membre
    22:38 modifié #4
    dans 1179559368:

    Je viens de lancer Shark, mais j'avoue que ça m'éclaircie pas beaucoup plus ....


    1 - Tu lances ton application
    2 - Tu lances Shark
    3 - Tu sélectionnes "Process" à  la place d'"Everything"
    4 - Tu sélectionnes le processus de ton appli
    5 - Tu sélectionnes "Time Profile" s'il n'est déjà  selectionné
    6 - Tu prépares bien la tâche que tu veux monitorer sur ton appli pour n'avoir plus qu'un bouton à  appuyer par exemple
    7, 8, 9 - T'appuies sur "Start" dans Shark, tu lances ta tâche dans ton appli et une fois fini, sur "Stop" dans Shark
    10 - Il va analyser tout ce qui s'est passé et te sortir dans l'ordre ce qui a pris le plus de temps
  • aranaudaranaud Membre
    22:38 modifié #5
    Pardonner mon ignorance, mais elle est où cette application "Shark". Je ne la trouve pas dans les utilitaires de xcode.
  • 22:38 modifié #6
    Pour l'avoir, il faut avoir personnalisé l'installation des Xcode tools et avoir installé un packet répondant au doux nom de CHUD Tools (qui ne fait pas partie de l'installation par défaut). Sinon tu peux certainement la retrouver dans la liste des paquets sur l'image disque de Xcode.

  • aranaudaranaud Membre
    22:38 modifié #7
    Ok, merci.
  • UniXUniX Membre
    22:38 modifié #8
    OK, j'ai fait la manip.
    L'exécution de Shark s'est terminé toute seule, sans que j'ai à  cliquer sur Stop. Je sais pas si c'est normal ....

    Voici les résultats que j'obtiens.
    J'ai bien la méthode enregistrementTemporaireThread qui enregistre les données sur le disque.
    Après, je sais pas trop quoi dire de plus ...

    shark.png
  • schlumschlum Membre
    mai 2007 modifié #9
    C'est "flattenPlist" qui prend tout le temps processeur...
    Donc, ce n'est pas dû à  l'écriture sur le disque, mais bien à  l'archivage de tes classes.

    Ou plus haut : "finishEncoding"

    Instructs the receiver to construct the final data stream.


    C'est la construction de ta classe vers le NSData...

    Là  on ne voit même pas les I/O ; ton truc est tellement long que Shark n'a pas pu les enregistrer, ils n'avaient pas commencé (il enregistre 30s max je crois)
  • UniXUniX Membre
    22:38 modifié #10
    Pour la construction de la classe vers le data, je n'ai rien d'extraordinaire .....!
    J'ai toute une série de
    [coder encodeObject:objet forKey:@"key"]
    


    La seule chose, c'est que j'ai 47 variables d'instance. J'ai essayé de ne pas en encoder certaines, et je gagne des secondes. Mais théoriquement, j'en ai besoin de toutes .... (je dois pouvoir en supprimer quelques unes que je recalcule lors du décodage).
    Je suis un peu dans l'impasse là  il me semble ....
  • schlumschlum Membre
    mai 2007 modifié #11
    Ce qui m'étonne, c'est le CFBinaryPlistWriteToStream (celui là  même qui bouffe tout ton temps...)
    On dirait que ton programme cherche des données dans un Plist binaire ; tout tourne un peu autour de ça ("FindBuckets"...)

    Dans SudokuX, j'ai aussi un paquet de choses à  enregister, de gros tableaux 9*9*9, icônes, curseurs etc... et ça prend une fraction de secondes (avec Shark, ce qui apparaà®t consommateur, c'est la gestion de l'icône dans le Dock au moment de l'enregistrement  ::) )

    [Edit] J'y pense... Aurais-tu fait un projet Core-Data / XML ?
    Si oui, apparemment ce n'est pas du tout adapté...
  • UniXUniX Membre
    mai 2007 modifié #12
    Non, pas de coredata.

    Pour te décrire ce que j'enregistre :
    - le root object est un NSDictionary, qui contient des NSArray (3 ou 4)
    - les NSArray contiennent des objets perso (3 ou 4) qui ont environs 10 variables d'instance (des NSString, booleen, .... rien d'extraordinaire).
    - une des variables d'instance est un NSArray qui contient d'autres objets persos (les fameux avec 47 variables d'instance) et peuvent être plusieurs centaines.

    A priori, ce qui prend du temps, c'est le traitement de ces derniers objets ....
  • schlumschlum Membre
    22:38 modifié #13
    Mets un breakpoint sur "__CFBinaryPlistWriteToStream", et regarde par quoi il est appelé dans ton appli.
    Ca m'intéresse aussi cette affaire  :o
  • UniXUniX Membre
    22:38 modifié #14
    Heuu .... oui, je fais comment ??? ?
  • schlumschlum Membre
    22:38 modifié #15
    Dans "Breakpoints", il suffit d'ajouter un signe manuellement : "_CFBinaryPlistWriteToStream" (on enlève un "_")

    -> "Double-Click for Symbol", doublie-cliquer dessus, et rentrer _CFBinaryPlistWriteToStream
  • UniXUniX Membre
    22:38 modifié #16
    Bon, j'ai fait la manip, et le breakpoint ne stoppe pas l'exécution ....
    J'ai testé en ne mettant pas le tiret devant _CFBinaryPlistWriteToStream, idem ...
  • schlumschlum Membre
    22:38 modifié #17
    Il faut mettre "()" derrière, j'avais oublié  :-\\
  • UniXUniX Membre
    22:38 modifié #18
    Idem ....
  • schlumschlum Membre
    mai 2007 modifié #19
    Non, je dis des bêtises... Pas de "()", et il faut mettre deux "_"
    "__CFBinaryPlistWriteToStream"
    Plus mettre "CoreFoundation" dans "Location" (peut-être pas obligatoire ; il le trouvera peut-être tout seul)

    Bien être en mode "Debug", et vérifier que dans la console qu'il y ait bien marqué :
    Pending breakpoint 1 - "__CFBinaryPlistWriteToStream" resolved



    dbg.png

    dbg2.png


    Le problème c'est qu'il l'utilise aussi quand il lit les préférences, donc faut peut-être le placer après...
  • schlumschlum Membre
    mai 2007 modifié #20
    Laisse tomber avec celle-ci, il l'utilise tout le temps... Va falloir taper ailleurs  :-\\
    (ou alors mettre une condition de stack sur le breakpoint, mais je ne connais pas assez bien gdb pour faire ça)
  • MalaMala Membre, Modérateur
    22:38 modifié #21
    C'est surprenant comme souci. A tout hasard, il n'y a pas des liens de hiérarchie dans les objets que tu archives? Je pense par exemple à  l'archivage d'un arbre où l'on peut avoir des liens père/fils et vice et versa. Lors d'une écriture sur disque cela pourrait poser problème.
  • UniXUniX Membre
    22:38 modifié #22
    Non, aucun lien père fils tordu ....
    Tout est clair.

    Je viens de faire un essai avec juste les 1500 objets dans un NSArray, c'est aussi long. En revanche, si je rempli avec 1500 objets qui ont tous les mêmes valeurs de variables d'instance, là  c'est rapide. Mais je suppose que c'est une optimisation de NSKeyedArchiver qui prévoit ce cas là  ....
Connectez-vous ou Inscrivez-vous pour répondre.