Journal : La terre est plate et Java est plus rapide que C++

Posté par iug () le 15 avril 2005
0
Bonjour,

Je vous propose un petit troll du Vendredi, ainsi qu'un défi.

J'utilise Java Sound pour enregistrer et jouer du son. J'avais, avec le JDK 1.3 des problèmes de pertes de synchro, i.e. Java arrivait pas à suivre la cadence. Les marketteux de chez Sun prétendant que Java Sound était maintenant en Direct Sound (pas celui de M$, celui de Java) depuis la 1.4, utilisant Alsa ou bien DirectX, marchait beaucoup mieux.

Le problème c'est que Java, c'est peut-être plus rapide que C++, mais ça ne sait pas scheduler un thread correctement.

En effet, ma carte son me donne un buffer d'enregistrement de 1s au max (avec Direct Sound on ne peut pas choisir la taille du buffer, et maintenant Sun ne donne plus accès au Java Audio Engine pour l'enregistrement). Du coup, il faut que mon thread d'enregistrement soit schédulé au moins une fois par seconde.

Et ben cette merde de Scheduler qu'il y'a dans la JDK, il est pas capable de me faire ça. A peu près toutes les 30s, mon thread n'est pas schédulé à temps. Pourtant je lui demande un scheduling toutes les 100ms via un wait(100) dans mon thread. Et ce, sans que rien ne tourne en tâche de fond, sauf les processus de mon OS et les quelques threads "system" de la JVM.

Sur un Pentium IV 2.4GHz avec 1 Go de RAM, 0% d'utilisation CPU, le scheduler de la JVM n'est pas foutu de faire en sorte que mon thread soit schedulé avant 1s.

Du coup, le son en Java on peut oublier :)

Je vais coder un bout de C++ pour gérer ça et passer par JNI.

Conclusion la terre est plate (c.f. la page performance sur jsresources.org).

> Lire le journal (42 commentaires, moyenne: 2,3).  

Cette discussion est archivée, il n'est plus possible de laisser des commentaires.

Note : les commentaires appartiennent à ceux qui les ont postés. Nous n'en sommes pas responsables.

Je prends les paris

Posté par Wawet76 (page perso, ) le 15/04/2005 à 09:40. (lien). Évalué à 10.

Tu ne crains pas que la conclusion du débat soit qu'en fait c'est ton truc qui est mal codé ?

  • [^]Re: Je prends les paris

    Posté par iug () le 15/04/2005 à 09:50. (lien). Évalué à 6.

    J'ai oublié la partie "défi" qui consistait à me proposer un code qui démontre mon incompétence.

    • [^]Re: Je prends les paris

      Posté par gc (page perso, ) le 15/04/2005 à 13:27. (lien). Évalué à 5.

      Et pourquoi tu ne montres pas ton code tout simplement pour que d'autres y jettent un coup d'oeil et voient quelque chose que peut-être tu n'as pas vu ?

      • [^]Re: Je prends les paris

        Posté par iug () le 15/04/2005 à 14:03. (lien). Évalué à 1.

        Désolé, je bosse dans le privé, j'ai pas le droit. Essaie même pas d'imaginer sur quel OS tourne mon code :)

        • [^]Re: Je prends les paris

          Posté par Nelis (page perso, ) le 15/04/2005 à 14:07. (lien). Évalué à 2.

          Tu peux peut être nous montrer uniquement la partie posant problème ? J'imagine qu'elle n'est pas si secrete que ça ... Sinon comment veux-tu qu'on t'aide ? Si ça se trouve, il y a un bug dans ton code que tu n'as pas trouvé ...

          Sinon c'est comme si je disais : le C sous Linux c'est pas bien parce que mon thread se désynchronise, alors que j'ai surement un gros bug dans mon code ...

          --
          Vache qui rit, à moitié dans son lit
          • [^]Re: Je prends les paris

            Posté par iug () le 15/04/2005 à 15:38. (lien). Évalué à 2.

            Bon, voilà mon code :
            _in est une TargetDataLine en Java Direct Sound,
            _bigBuf, c'est un plus gros buffer circulaire dans lequel je mets mes données, et que le player va lire pour les jouer sur la carte son par exemple (on va supposer qu'il marche...) (même quand seul le recorder est seul, sans player, j'ai le problème, bon ok, j'ai pas essayé sans la copie vers le bigBuf)


            le corps du run() est :

            while (started) {
            size = _in.available(); // récupère la taille des données dispo
            _in.read(buf, 0, size); // récupère les données (une copie //supplémentaire, je sais)
            _bigBuf.put(buf, 0, size); // écrit dans le buffer circulaire
            Thread.wait(100); // Attends au moins 100ms, si possible moins de 1s
            }

            Ca ne vous avance pas à grand chose. Sinon, y'a des sorties textes de debug au milieu de tout ça, ce qui peut expliquer la chose. M'enfin, je suis plus au taf, donc je peux pas essayer.

            Merci pour la proposition, mais ça vous avance à rien. Y'a pas de deadlock vu que seul un consommateur tourne :) Si mon buffer circulaire buggait, j'aurais des excpetions. Vu qu'il ne fait pas 1Mo ça n'explique de toute façon pas la latence, une copie de 1Mo prenant moins d'une seconde. Une copie de plus de 1Mo déclencherais une excpetion...

            • [^]Pfff

              Posté par bobert () le 15/04/2005 à 16:26. (lien). Évalué à 0.

              Ca ne vous avance pas à grand chose

              En fait, ça n'avance même à rien, vu que tu donnes un code incomplet.
              Quel est le type de _in ? InputStream ? BufferedInputStream ?
              Quel est le type de buf ? Où est le code de _bigBuf ? Que fait sa méthode put ?

              Évidemment en nous montrant 3 lignes tronquées de ton code ça fait pas du tout avancer le schmilblik, à croire que tu fais exprès, ça doit faire partie de ton troll.

              Tout ce que ça montre, c'est que tu es plus habitué à c++ qu'à java, parce que préfixer d'un '_' le nom des attributs privés est un idiome c++ ; en java, on se contente du modifiant private.

              • [+] [^]Re: Pfff

                Posté par Troy McClure (page perso, ) le 15/04/2005 à 17:57. (lien). Évalué à -3.

                > préfixer d'un '_' le nom des attributs privés est un idiome c++

                Naon, en c++ comme en c, les identifieurs commençant par un underscore sont reservés pour l'usage interne du compilo et de la bibliothèque standard !

              • [^]Re: Pfff

                Posté par Matthieu Moy (page perso, ) le 16/04/2005 à 11:48. (lien). Évalué à 3.

                > Quel est le type de _in ?

                Bien relire le message du môsieur ...

                • [^]Re: Pfff

                  Posté par iug () le 18/04/2005 à 10:34. (lien). Évalué à 2.

                  Mon soft est censé cohabiter avec du hard, qui m'envoie 1s de son toutes les secondes. Donc j'utilise directement une TargetDataLine, et je fait un read dessus.

                  Et en mettant des currentTimeMillis() partout, j'ai vu que mon appel à _in.read() avec comme dernier paramètre le résultat renvoyé par _in.available(), qui ne devrait donc pas bloquer, prend la plupart de temps à peu près 0 ms et de temps à autre 1000ms, comme si il bloquait pour attendre un remplissage complet du buffer interne de la carte son, qui dur 1000ms.

                  Le scheduler n'est pas en cause, ni ma synchro, le wait() du thread dure grosso modo ce qu'il faut. D'ailleurs, chose bizarre, il dure parfois moins que le temps demandé.

                  Je vais essayer de creuser le problème. Par exemple ma carte est une fausse full duplex.

                  • [^]Re: Pfff

                    Posté par iug () le 18/04/2005 à 12:46. (lien). Évalué à 5.

                    Ouais, c'était bien une histoire de TargetDataLine.read().

                    Je sais pas si c'est dû au driver de ma carte son, à DirectX, ou au JDK mais maintenant que je lis 1000 octets de moins que ce que me donne le available() et ben jai plus de read() bloquant.

                    Toutes mes excuses pour les critiques du scheduler, qui n'était pas en cause, de même que le GC.

            • [^]Re: Je prends les paris

              Posté par Sylvain Sauvage () le 17/04/2005 à 19:38. (lien). Évalué à 4.

              Le Thread.wait(100), comme tu le dis en commentaire, signifie « attends au moins 100 ms ».
              C'est tout.
              Java n'est pas temps réel (ton OS non plus, je pense), il ne promet pas que le retour se fera avant un délai donné (il peut très bien finir dans 25 ans).

              Ton problème vient peut-être des entrées-sorties ou du garbage collector qui viennent perturber l'ordonnanceur.

              Ensuite, ce n'est parce que tu vas passer par du JNI que la machine virtuelle ou les entrées-sorties ne vont pas continuer à venir perturber le fonctionnement de ton prog.
              Sans parler des problèmes que l'on peut avoir en mélangeant les threads natifs aux threads Java.

              Enfin, si tu n'as aucun raison pour faire un Thread.wait(100) plutôt qu'un Thread.wait(10), autant faire un Thread.yield(). De cette façon, ton thread reprendra la main dès que possible.

    • [^]Bien tenté...

      Posté par bobert () le 15/04/2005 à 15:13. (lien). Évalué à 7.

      J'ai oublié la partie "défi" qui consistait à me proposer un code qui démontre mon incompétence.

      Bien tenté, mais dans la pratique ça fonctionne en sens inverse: c'est à toi de nous montrer ton code pour démontrer ta compétence.

  • [^]Re: Je prends les paris

    Posté par iug () le 15/04/2005 à 10:01. (lien). Évalué à 2.

    Quiconque a déjà écrit un prod/cons en Java connaît le problème.

    Si tu fais juste un petit programme "cas décole" qui ne fait aucun traitement et se contente de faires des println dans la console à chaque production et consommation, tu observeras des pauses assez fréquentes.

    Ce qui me fait halluciner c'est que ces pauses peuvent durer plus d'une seconde.

    Je me demande si ce sontles programmeurs qui ont implémentés le truc qui sont incompétents ou bien, pire, si c'est une faille de la spec d'implémentation des API de thread qu'ils ont en interne chez Sun.

    Quand on voit la qualité de Solaris, on se dit qu'ils pourraient débaucher quelques hackers pour les mettre à bosser sur Java.

    • [^]Re: Je prends les paris

      Posté par Nelis (page perso, ) le 15/04/2005 à 10:10. (lien). Évalué à 3.

      Je n'ai jamais eu de problème de synchro de threads en Java ...

      Peut-être peux-tu nous montrer ton code ?

      --
      Vache qui rit, à moitié dans son lit
    • [^]Re: Je prends les paris

      Posté par Mathieu CLAUDEL (page perso, ) le 15/04/2005 à 10:11. (lien). Évalué à 5.

      <neophite>
      peut etre le garbage colector qui tourne
      </neophite>

      • [^]Re: Je prends les paris

        Posté par Laurent Pointal (page perso, ) le 15/04/2005 à 11:08. (lien). Évalué à 1.

        Voir le Java 1.5, il y a des options pour affiner le fonctionnement du ramasse-miettes, de mémoire on peut spécifier qu'on veut qu'il s'active obligatoirement tous les XXX secondes, et on peut spécifier qu'à chaque activation il ne doit pas prendre plus de YYY secondes.

        (y'avait un article là-dessus dans un numéro de GNU-Linux Magazine)

        --
        (pub: Livres à prix réduit sur http://www.sollire.com/ - la boutique de mes petites soeurs)
        • [^]Re: Je prends les paris

          Posté par Tobu () le 15/04/2005 à 17:59. (lien). Évalué à 1.

          Et il y a certainement des options pour demander au GC de loguer quand il se met à travailler. Avec un top, il y a certainement moyen de voir si le système part au swap (je suppose que tu as un top, même si c'est un système exotique?) (de toute façon si ça supporte java ça peut pas être une petite plateforme).

          • [^]Re: Je prends les paris

            Posté par Krunch (Jabber id, page perso, ) le 15/04/2005 à 21:18. (lien). Évalué à 2.

            Un GSM c'est pas une petite plateforme ?

            --
            Free Softwares Users Group Arlon (Sud Luxembourg, Belgique)
            pertinent, e adj. Approprié ; qui se rapporte exactement à ce dont il est question.
            • [^]Re: Je prends les paris

              Posté par Tobu () le 16/04/2005 à 10:09. (lien). Évalué à 2.

              Bon, pardon, j'ai sombré dans la facilité.
              En même temps le journal parlait du Java 1.4 de SUN avec ses API très complètes.

    • [^]Re: Je prends les paris

      Posté par Thomas Hervé () le 15/04/2005 à 10:15. (lien). Évalué à 4.

      Un petit test qui résoud certains problèmes : augmente la taille initiale de la ram alouée à la JVM (-Xms128m pour mettre 128MB par exemple).

      Au cours de tests d'applis Web sous Tomcat, j'ai utilisé un outil pas mal qui s'appelle Jprobe profiler (ca pue c'est pas libre). Pour constater que les latences de mon application étaient dues aux allocations mémoire. En gros quand la JVM augmente (ou diminue) la mémoire disponible, elle ne peut rien faire d'autre ou quasiment... Sachant qu'une application Java est assez consommatrice de mémoire, j'avais des pauses toutes les 10 secondes.

      --
      Thomas <et voilà que je me met à donner des conseils Java. Tout fout le camp>

      • [^]Re: Je prends les paris

        Posté par kesako () le 15/04/2005 à 10:27. (lien). Évalué à 3.

        ah ben alors c'est vraiment lamentable ... car un exemple de producteur/consomateur ca ne devrait pas faire grossir l'occupation memoire. Ca peut eventuellement grossir au debut mais ensuite doit se stabiliser . Donc les "pauses" n'ont aucune raison d'etre.

        • [^]Re: Je prends les paris

          Posté par romain () le 15/04/2005 à 10:30. (lien). Évalué à 1.

          Peut-être que la JVM provisionne (pour rien, mais elle ne peut pas tout deviner) de la RAM au fur et à mesure ?

        • [^]Re: Je prends les paris

          Posté par Laurent Pointal (page perso, ) le 15/04/2005 à 11:06. (lien). Évalué à 3.

          Si, ça fait grossir jusqu'au prochain passage du ramasse-miettes.

          --
          (pub: Livres à prix réduit sur http://www.sollire.com/ - la boutique de mes petites soeurs)
      • [^]Re: Je prends les paris

        Posté par Fanf () le 15/04/2005 à 11:42. (lien). Évalué à 0.

        Thomas <et voilà que je me met à donner des conseils Java. Tout fout le camp>

        Heu... LE Thomas que je connais ? En effet, tout fou le camp :)

    • [^]Re: Je prends les paris

      Posté par romain () le 15/04/2005 à 10:19. (lien). Évalué à 3.

      Est-ce que ça ne viendrait pas aussi du choix du modèle de threading de la JVM ?

      Il me semble, si je me souviens bien mes cours de temps réel (en Java, vivi), qu'il y a au moins deux modèles (green box, native ou standard, je ne sais plus) et que cela peut avoir une incidence sur le scheduling des threads et leurs synchro (pas de pointeur en tête, désolé).

      • [^]Re: Je prends les paris

        Posté par iug () le 15/04/2005 à 10:41. (lien). Évalué à 1.

        Ca c'est intéressant comme réponse, je songeais justement à lire les howto de IBM sur le paramètrage de la JVM.

        En tout cas, question RT, effectivement Java ne donne pas plus de garantie que Linux vanilla ou Windows en matière de schéduling. Par contre dans ces deux derniers cas, dans la pratique, on n'a pas de latence de 1s.

        Question pause, et ben oui elles y sont. Et effectivement, je me suis démerder pour ne plus faire d'alloc dans ma boucle de pompage, et les pauses y sont encore.

        • [^]Re: Je prends les paris

          Posté par Mobaladje () le 15/04/2005 à 11:09. (lien). Évalué à 2.

          J'avoue je ne comprends pas bien ton probleme.

          "A peu près toutes les 30s, mon thread n'est pas schédulé à temps."

          Ca veut dire quoi exactement ?

          Le wait ne se fait pas ? (très improbable).

          Les waits n'étant pas "constants", tu as une attente plus longue (ou plus courte) au bout d'un certain temps ? (plus probable).

          Que veux tu faire exactement ?

          • [^]Re: Je prends les paris

            Posté par Tobu () le 15/04/2005 à 17:53. (lien). Évalué à 2.

            Son tampon a une taille de 1 seconde, et son thread reste apparemment au moins 1 seconde sans s'exécuter, ce qui fait que le tampon se retrouve vide.
            D'ou bizarrerie: le thread n'est censé ne dormir que 100ms.

            • [^]Re: Je prends les paris

              Posté par jigso () le 16/04/2005 à 11:55. (lien). Évalué à 3.

              C'est donc que le pb n'est pas dans le wait(100), mais probable dans les opérations de lecture/copie de buffer ; dans la mesure où il ne fait pas du temps réels, ie pas d'appel de fonctions qui peuvent garantir un temps d'execution minimum, tout peut arriver, y compris des "gels" de plus d'1 seconde - probablement le ramasse-miette ou autre joyeuseté de la JVM.

    • [^]Re: Je prends les paris

      Posté par Nicolas Bernard (page perso, ) le 15/04/2005 à 11:48. (lien). Évalué à 0.


      Quand on voit la qualité de Solaris, on se dit qu'ils pourraient débaucher quelques hackers pour les mettre à bosser sur Java.

      Je crois que les hackers en question préfereraient démissioner que de travailler sur Java...

[+] J'ai pas constaté.

Posté par locnet () le 15/04/2005 à 11:39. (lien). Évalué à -3.

Je fais pas du temps réel, mais j'utilise des applications java diverses, jedit, Eclipse...
Je ne constate pas des pauses d'une seconde périodiques.

Ton problème n'est probablement pas généralisé à tout java. Reste a trouver ce qui le déclenche.

--
--
locnet
  • [^]Re: J'ai pas constaté.

    Posté par TImaniac (page perso, ) le 15/04/2005 à 14:20. (lien). Évalué à 0.

    j'utilise des applications java diverses, jedit, Eclipse...
    Non sérieux, c'est bien connu, Eclipse il ralenti jamais, surtout quand le GC passe dans le coin, y'a jamais plus de 2 µs entre le click de la souris et la réaction de l'IHM, c'est bien connu, surtout au bout de 3h d'utilisation, sous Linux s'il vous plaît...
    Bon allez j'ai assez ri, hop -->[]

vu sur le site de SUN

Posté par Christophe Martel () le 15/04/2005 à 12:08. (lien). Évalué à 9.

je sais pas si cela peux t'aider, mais bon :

exemple de thread schedulé :
http://forum.java.sun.com/thread.jspa?forumID=45&threadID=24306(...)

Help with JMF Synchronisation :
http://forum.java.sun.com/thread.jspa?forumID=28&threadID=52346(...)

tutorial:
http://java.sun.com/docs/books/tutorial/essential/threads/priority.(...)

doc :
Capturing Time-Based Media with JMF :
http://java.sun.com/products/java-media/jmf/2.1.1/guide/JMFCapturin(...)

javasound

Posté par vrm (page perso, ) le 15/04/2005 à 12:42. (lien). Évalué à 1.

franchement javaSound c'est une très grosse merde au niveau performances (et encore je pèse mes mots..). La seule solution que j'ai trouvé et JNI & libasound (alsa) qui marche plutôt bien mais qui n'est pas portable pour Windows

  • [^]Re: javasound

    Posté par iug () le 15/04/2005 à 12:45. (lien). Évalué à 5.

    J'ai l'impression que le dernier JavaSound, qui utilise alsa en accès direct est pas mal. Le seul problème c'est leur scheduler et leur GC.

    • [+] [^]Re: javasound

      Posté par vrm (page perso, ) le 15/04/2005 à 13:09. (lien). Évalué à -1.

      j'ais pas essayé le dernier tellement les précédents étaient mauvais ...

une "solution"

Posté par kra () le 15/04/2005 à 16:35. (lien). Évalué à 4.

plus un contournement qu'autre chose : t'as essaye de remplacer ton thread par un Timer?
ca correspond plus a ce que tu veux faire visiblement (ie : executer une tache toutes les n ms plutot que d'executer une tache en continue qui dort 90% du temps)

  • [^]Re: une "solution"

    Posté par iug () le 18/04/2005 à 10:27. (lien). Évalué à 2.

    Le timer fait lui aussi appelle à thread, c'est une classe codée en Java. Donc je préfère ré-inventer la roue :)

[+] \o/

Posté par kassoulet (Jabber id, page perso, ) le 15/04/2005 à 18:39. (lien). Évalué à -3.

> Le problème c'est que Java, c'est peut-être plus rapide que C++

c'est une blague j'espere :)

[+] Lâcher de trolls

Posté par Obsidian () le 15/04/2005 à 23:53. (lien). Évalué à -2.

Je vous propose un petit troll du Vendredi, ainsi qu'un défi.

J'utilise Java Sound pour enregistrer et jouer du son. J'avais, avec le JDK 1.3 des problèmes de pertes de synchro, i.e. Java arrivait pas à suivre la cadence.


Tu te prends pour Pierre Tramo ?

Revenir en haut de page