neologix a écrit 346 commentaires

  • [^] # Re: trouver le coupable

    Posté par  . En réponse au message Disque bruyant et commit qui marche pas. Évalué à 2.

    Ton log s'étend sur une durée de quelques ms…
    Vu la quantité d'écritures, tu as sûrement un autre process qui tourne, recherche une entrée autre que kjournald.

  • # trouver le coupable

    Posté par  . En réponse au message Disque bruyant et commit qui marche pas. Évalué à 6.

    Il y a deux autres sysctl qui entrent en jeu :

    vm.dirty_writeback_centisecs
    vm.dirty_expire_centisecs
    
    

    Vu la périodicité, à mon avis c'est plutôt les BDI flush threads qui causent le "grattage".
    Mais augmenter ces sysctl ou la période de commit du FS ne corrigera pas le problème (et ce n'est pas une bonne idée).
    Si ton disque gratte, c'est qu'un process écrit.
    Tu peux trouver lequel avec :

    # service syslog stop
    # echo 1 > /proc/sys/vm/block_dump 
    # dmesg
    
    
  • [^] # Re: criticité

    Posté par  . En réponse au journal Genèse d'un journal. Évalué à 2.

    Encore une fois, je doute très fortement que ce soit la cause des fuites mémoire.
    malloc()/realloc() qui retourne NULL, c'est très rare, il faut vraiment être en OOM ou atteindre RLIMIT_DATA/RLIMIT_AS.
    Utilise "ltrace -e malloc,realloc" pour t'en convaincre…

    Et surtout valgrind…

  • [^] # Re: très bien mais

    Posté par  . En réponse au journal Python 3.3.0 release candidate 2. Évalué à 4.

    Pour le moment, les corrections sont appliquées à la branche 2.7, mais cela ne durera pas indéfiniment..

  • [^] # Re: criticité

    Posté par  . En réponse au journal Genèse d'un journal. Évalué à 7.

    Pour info, voici le code d'openssh [1] :

    void *
    xmalloc(size_t size)
    {
        void *ptr;
    
        if (size == 0)
            fatal("xmalloc: zero size");
        ptr = malloc(size);
        if (ptr == NULL)
            fatal("xmalloc: out of memory (allocating %lu bytes)", (u_long) size);
        return ptr;
    }
    
    [...]
    
    /* Fatal messages.  This function never returns. */
    
    void
    fatal(const char *fmt,...)
    {
        va_list args;
    
        va_start(args, fmt);
        do_log(SYSLOG_LEVEL_FATAL, fmt, args);
        va_end(args);
        cleanup_exit(255);
    }
    
    [...]
    
    /* default implementation */
    void
    cleanup_exit(int i)
    {
        _exit(i);
    }
    
    

    [1] http://www.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/

  • [^] # Re: criticité

    Posté par  . En réponse au journal Genèse d'un journal. Évalué à 0.

    C'est pour ça que tu vas allouer de la mémoire au lancement du programme pour avoir une "réserve" pour ce genre de cas.

    Bah voyons, montre-moi tu empêches fprintf() ou un appel système de retourner ENOMEM en cas de OOM, je suis curieux.

    Tu en sais quoi qu'il pourrait crasher n'importe quoi ?

    Tout les process peuvent crasher, à n'importe quel moment : OOM, signal, mémoire défectueuse…
    Le seul critère est l'impact du crash : et dans ce cas, un logiciel non critique, sans persistance de données, sans effets de bords, l'impact est négligeable.

    Ou alors le programme indique clairement : "attention ce programme ne gère pas du tout la mémoire, il ne faut donc pas l'utiliser à part si vous n'en avez pas besoin" !

    OK, donc explique-moi ce que tu pourrais faire de plus qu'un _exit() en cas de OOM sur ce programme précis (parce qu'on parle de celui-là, toute la question est de la pertinence d'une telle gestion en fonction de la criticité). Si ton programme ne peut plus fonctionner correctement, autant le terminer pour remonter l'erreur que de continuer et faire n'importe quoi, non (encore une fois, je parle de programmes non critiques) ?

    Soyons sérieux, tu gueules si un appareil électrique grille à la première surtension. Pourtant il est prévu pour le réseau standard, donc pourquoi mettre un fusible ? Et finalement, c'est juste un gadget, pas un appareil critique, ce n'est pas grave s'il grille : il suffit de le ramener sous garantie. Sauf que ta maison à cramer à cause de ce raisonnement.

    OK, quand je vois ce genre de comparaisons, je me dis que ce n'est pas la peine de discuter…
    Tu compares une installation électrique à un gadget GUI qui t'affiche ta consommation CPU.
    Si tu ne fais pas la différence de criticité entre les deux, je ne peux rien pour toi…

    Si en Java, OutOfMemoryError est une Error, et pas une checked exception, il y a une raison…

    Par ailleurs, je ne vois toujours pas le lien entre realloc() et la fuite mémoire, tu devrais utiliser valgrind au lieu de patcher le code au petit bonheur la chance…

  • # criticité

    Posté par  . En réponse au journal Genèse d'un journal. Évalué à 10. Dernière modification le 09 septembre 2012 à 12:55.

    Non, on ne peut pas compter sur le magicien "OOM Killer" de Linux. Le noyau a pu être compiler sans ça.

    Le OOM killer se tune par sysctl (overcommit_memory knobs) et /proc (oom_adj), pas à la compilation.
    Et ce n'est pas un tour de magie, mais plutôt un hack ignoble (et compter dessus est stupide et non portable).

    C'est exactement le cas. Votre programme de traitement de texte n'a pas assez d'espace pour le prochain caractère donc il plante sans possibilité de sauvegarder ?

    Tu sous-estime la complexité.
    OK, tu testes ton pointeur, tu vois qu'il est NULL.
    Mais pour faire les choses proprement, par exemple prévenir l'utilisateur, ou sauvegarder le fichier, et bien il faut de la mémoire.
    Bah oui, créer un popup, ça demande de la mémoire. fprintf() utilise malloc(), tout comme fwrite() (oui je connais setvbuf()), etc. Quand tu y penses, sans malloc(), il ne te reste plus grand chose de disponible.

    En fait c'est encore bien pire que ça, parce que sur OOM (je ne parle pas du cas où tu es limité par RLIMIT_DATA/RLIMIT_AS…), quasiment n'importe quel appel système peut foirer: fork() (vérifié sur OpenIndiana), write(), close()…

    Donc la morale, c'est que tu ne pourras probablement pas sauvegarder ton fichier, et que tu risques de le corrompre si tu essaies.

    C'est pour cela que dans les applications critiques, il faut utiliser des opérations atomiques, ou des transactions. Par exemple, ton traitement de texte bosse sur une copie du fichier, et ensuite fait un truc du style :

    fsync(fd);
    close(fd):
    rename("monfichier.tmp", "monfichier");
    fsync(<répertoire parent du fichier>);
    
    

    Au moins là tu es tranquille.
    Par ce que tu vois le cas d'OOM, mais ton process peut se faire tuer par un SIGKILL ou n'importe quel autre signal, et dans ce cas là tu ne pourras pas catcher.

    Mais ce genre de chose est complexe, et ce n'est probablement pas la peine de le faire sur un programme qui se content de te donner ta consommation en CPU/RAM/bande passante. Il n'a pas d'état, pas d'effets de bords, il peut crasher n'importe quand.
    Par contre, mettre un assert() est pas mal pour éviter une éventuelle faille de sécurité due au déréférencement d'un pointeur NULL.

  • [^] # Re: malloc() et realloc() sous linux

    Posté par  . En réponse au journal realloc. Évalué à 10.

    À vrai dire, sous linux par défaut, malloc() et realloc() ne retournent finalement jamais NULL. Ce qu'il se passe plutôt, c'est qu'on reçoit toujours un pointeur, et c'est au moment où on se met à l'utiliser qu'il alloue réellement la mémoire.

    Ok, c'est l'overcommit.

    Cependant, même avec l'overcommit totalement désactivé, le noyau linux continuera à renvoyer un pointeur non-NULL, même quand il n'y a plus de mémoire disponible, et OOM-killer sera appelé comme d'habitude quand la mémoire sera accédée.

    C'est faux :

    # cat test.c 
    #include <stdio.h>
    #include <stdlib.h>
    
    
    #define BLOCK_SIZE (1024*1024)
    
    
    int main(int argc, char *argv[])
    {
            unsigned long size = 0;
    
            while (malloc(BLOCK_SIZE) != NULL)
                    size += BLOCK_SIZE;
    
            printf("malloc() returned NULL after %uMB\n", (size/(1024*1024)));
    
            exit(EXIT_SUCCESS);
    }
    
    

    Test :

    # /sbin/sysctl -a | grep overcommit
    vm.overcommit_memory = 0
    vm.overcommit_ratio = 50
    vm.nr_overcommit_hugepages = 0
    
    # ./test
    malloc() returned NULL after 3057MB
    
    

    Normal, je suis sur 32-bit, plus d'espace d'adressage.

    Maintenant, et activant l'overcommit strict :

    # sysctl vm.overcommit_memory=2
    vm.overcommit_memory = 2
    # sysctl vm.overcommit_ratio=50
    # ./test
    malloc() returned NULL after 626MB
    
    

    En faisant un memset() sur le block retourné par malloc(), dans le premier cas le process se fait tuer par l'OOM killer, dans le deuxième le comportement est le même.

  • # realloc() et fragmentation du tas

    Posté par  . En réponse au journal realloc. Évalué à 5.

    Comme expliqué ci-dessus, dans ce cas il n'y aura pas de fuite mémoire, en cas d'OOM ça finit soit avec le OOM killer soit en segfault.
    Mais realloc() a une particularité intéressante qui rend facile l'introduction d'une fragmentation du tas : lorsqu'on appelle un realloc() avec une nouvelle taille inférieure à la taille d'origine, certaines implémentations [1] ne réduisent pas le bloc d'origine. C'est-à-dire qu'une séquence du style :

    p1 = malloc(1MB)
    p1 = realloc(p1, 1KB)
    p2 = malloc(1MB)
    p2 = realloc(p2, 1KB)
    [...]
    
    

    Conduit à une grosse fragmentation du tas. On a eu ce genre de problème dans cPython.

    [1] La glibc n'est pas affectée (http://sourceware.org/git/?p=glibc.git;a=blob;f=malloc/malloc.c;h=ca1d73f875150a17955df9e0aa2dc33e277aacb5;hb=HEAD#l4168), mais la libc de OS-X si par exemple.

  • [^] # Re: Question.

    Posté par  . En réponse au journal D-LAN - Projet de partage de fichiers en LAN arrive sous Linux. Évalué à 3.

    Il y a déjà murder (https://github.com/lg/murder) qui fonctionne très bien ; on l'utilise au boulot pour distribuer des Go de données à plusieurs dizaines de noeuds.

  • [^] # Re: NOOONNNN!!!....

    Posté par  . En réponse au journal Prévision de gel ... pour Debian Wheezy ... et quelques détails sur le manchot au nœud papillon . Évalué à 7.

    Les gens qui réclament des logiciels plus à jour ne sont pas les "gros" clients de Debian Stable: celle-ci s'adresse plutôt à des entreprises, des gros parcs, des serveurs un peu critique, etc.

    Contrairement à ce qu'on entend tout le temps, Debian ne s'adresse pas à ce genre de public.
    Pourquoi ?
    Tout simplement parce que le cycle de release est trop court : une version tous les deux ans, plus un an de suivi de sécurité, ça fait seulement trois ans. En encore, pendant la dernière année, ce ne sont que des mises à jour de sécurité.
    Et trois ans, pour une grosse boîte ou un domaine sérieux, c'est rien.
    Je bosse dans les systèmes de contrôle aérien, et si on partait sur Debian, ça voudrait dire qu'on déploie nos systèmes sur un OS qui n'est déjà plus supporté au moment du passage opérationnel.
    Du coup, c'est RHEL au boulot (et Debian à la maison).

    Pour ce qui est de la bureautique, on vient tout juste de passer à Windows XP SP3...

  • [^] # Re: N'optimiser que si nécessaire

    Posté par  . En réponse à la dépêche Le colonel Moutarde, sur la table (de hachage), avec un livre de maths. Évalué à 4.

    Si ce n’est pas une version de quicksort intégrant une astuce pour éviter le cas pathologique

    Pour CPython, c'est une variante du bien connu merge sort :
    http://en.wikipedia.org/wiki/Timsort

    Donc pas de problème, worst-case en O(n log n).

  • [^] # Re: Les vrais théoriciens s'en foutent

    Posté par  . En réponse à la dépêche Le colonel Moutarde, sur la table (de hachage), avec un livre de maths. Évalué à 4.

    Ben, non, justement. Il faut juste regarder la forme de l'arbre et faire les rotations qu'il faut.

    Pour un rééquilibrage, oui, mais tu ne fais pas un rééquilibrage pour le fun, non ?
    C'est toujours dans le cadre d'une insertion ou d'un suppression d'élément (c'est le scénario qu'envisageait rewind dans son message).
    Pour insérer ou supprimer ton élément, ta complexité est bien en O(l log n), contre O(l) pour une table de hashage, malgré le redimensionnement. Si tu veux du lookup en O(l) et insertion/suppression en O(lr)/O(l+r) où r est le radix), alors effectivement un trie est une bonne idée.
    Après, je suis d'accord avec toi :
    - dans le cas de longues chaînes, la comparaison est souvent bien plus rapide que O(l), contrairement au hashage (mais voir la remarque sur le fait que le hash d'un objet immutable est souvent conservé)
    - en oubliant la longueur des chaînes, avec un arbre binaire ton insertion est O(log n) dans le pire des cas, contre O(n) pour une table de hashage (d'où cette vulnérabilité, et potentiellement un problème avec des contraintes temps réel)

  • [^] # Re: Les vrais théoriciens s'en foutent

    Posté par  . En réponse à la dépêche Le colonel Moutarde, sur la table (de hachage), avec un livre de maths. Évalué à 4.

    C'est un coût amorti de O(1) que pour ceux qui considère que hasher une chaîne se fait en O(1). Moi je parlait d'un coût en O(l) pour une chaîne de taille l.

    Ca ne change rien : si tu considères que hasher une chaîne se fait en O(l), le coût amorti est en O(l).
    Mais rééquilibrer ton arbre se fait aussi en O(l log n) : il faut bien comparer ton élément, non ? (même si la comparaison est en O(l) dans le pire cas alors que le hash est en O(l) dans tous les cas, c'est pareil).
    Et ce serait pareil avec un trie, tu auras toujours ce facteur O(l), étant donné que la comparaison/égalité est en O(l).
    Ensuite, par exemple dans CPython, les hashs des objets immutables (string, bytes...) sont stockés avec l'objet, donc tu ne passes pas ton temps à les recalculer.

  • [^] # Re: Les vrais théoriciens s'en foutent

    Posté par  . En réponse à la dépêche Le colonel Moutarde, sur la table (de hachage), avec un livre de maths. Évalué à 4.

    Et la dernière fois que j'ai regardé, rééquilibrer un arbre binaire ça coûte moins cher que d'augmenter la taille d'une table de hachage.

    Ah bon ?
    Rééquilibrer un arbre binaire, c'est O(log n).
    Augmenter la taille d'une table de hachage, c'est un coût amorti de O(1), pour peu que tu utilises une progression géométrique.

  • [^] # Re: Quelques suggestions

    Posté par  . En réponse au journal Sprint CPython en ligne ce week-end (17/18 déc.). Évalué à 3.

    Oui, mais :
    - ma machine personnelle n'est pas assez puissante (j'ai accès à plein de machines au boulot, mais je ne peux pas me permettre de les utiliser pour ça)
    - comme l'explique Antoine, il faut être motivé : personnellement, je suis assez motivé pour écrire des patchs et committer ceux que des contributeurs ponctuels me soumettent pour ces plates-formes, mais pas assez pour mettre en place des VMs, les configurer et les mettre à jour (parce que c'est bien beau d'avoir un OpenBSD en VM, mais avec une version 3.1 tu ne vas pas aller loin).
    Avoir des contributeurs/testeurs intéressés et si possibles réguliers est bien plus intéressant.
    Par exemple, même si je ne connais quasiment rien à Windows et que je n'en ai pas chez moi, j'ai toujours la possibilité d'utiliser les buildbots pour tester mes patchs, et vérifier qu'ils n'ont pas tout cassé.

  • # Quelques suggestions

    Posté par  . En réponse au journal Sprint CPython en ligne ce week-end (17/18 déc.). Évalué à 6.

    On a un très bon niveau de support de plusieurs systèmes d'exploitation (Linux, Windows, FreeBSD, Solaris, OS X, etc), grâce à un certain nombre de contributeurs actifs et la disponibilité de buildbots (http://www.python.org/dev/buildbot/all/waterfall).
    Par contre, certaines plates-formes sont moins bien supportées, principalement par manque de contributeurs/testeurs : OpenBSD, NetBSD, HP-UX, AIX, etc.
    Donc pour ceux qui utilisent un de ces OS et qui sont motivés, je pense qu'il pourrait y avoir du boulot intéressant.
    La première étape serait de récupérer la branche default (future 3.3), et d'essayer de la compiler.
    Ensuite, lancer l'ensemble des tests de non-régression ("make test"), et voir ce qui foire.
    Vous pouvez aussi lancer une recherche dans le bug tracker, par exemple http://bugs.python.org/issue?@columns=id%2Cactivity%2Ctitle%2Ccreator%2Cassignee%2Cstatus%2Ctype&@sort=-activity&@filter=status&@action=searchid&ignore=file%3Acontent&@search_text=openbsd&status=-1%2C1%2C3

    Je vais probablement traîner sur #python-dev-fr histoire d'aider Victor, donc rendez-vous ce week-end !

  • [^] # Re: une piste

    Posté par  . En réponse au message Fichier vidéo illisible . Évalué à 3.

    Recompile avec -D_FILE_OFFSET_BITS=64.

  • # TCP window scaling

    Posté par  . En réponse au message Internet Lent (Oneiric Ocelot). Évalué à 2.

    Essaie ça :
    > sysctl -w net.ipv4.tcp_window_scaling=0

  • # nopat

    Posté par  . En réponse au message map pfn expected mapping... error. Évalué à 2.

    Essaie de passer l'option 'nopat' au noyau.
    C'est probablement dû à cette régression :
    http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=1adcaafe7414c5731f758b158aa0525057225deb

  • # non-blocking I/O

    Posté par  . En réponse au message Ecritures disques non bloquants. Évalué à 2.

    Tu mets ton FD non-blocking, et avant d'écrire tu appelles select() en le passant dans le writing set: si tu peux écrire, écris, sinon bufferise.
    Note que si le taux d'écriture de ton process est assez faible, tu peux utiliser un bête :
    $ ./monprog | cat > log
    cat va aussi bloquer sur certains write(), mais tant que le pipe n'est pas plein, ton process ne bloquera pas.
    Il faut donc grosso modo que :
    taux d'écriture < taille PIPE / blocage max de write
    (valeurs typiques: taille PIPE = 64KB, blocage max de write ~ 1s avec un BUFSIZ de l'ordre de 8192)

  • [^] # Re: Aie Aie Aie...

    Posté par  . En réponse à la dépêche Linux Foundation tombe à son tour. Évalué à 1.

    Et comment on va faire, nous, pour comprendre ce qu'il se passe dans le noyeau 3.1, hein?

    http://kernelnewbies.org/LinuxChanges

    De rien.

  • [^] # Re: 0xc0000000

    Posté par  . En réponse au journal x32: Une nouvelle ABI Linux '32 bits' pour les CPU x86-64. Évalué à 8.

    il dit que la limitation a 3Go n'existe pas avec PAE ce qui est vrai

    Non, c'est faux.
    http://www.redhat.com/archives/rhelv5-list/2008-November/msg00097.html
    http://docs.redhat.com/docs/en-US/Red_Hat_Enterprise_Linux/5/html/Deployment_Guide/ch-kernel.html

    C'est pour ça qu'on a inventé le split 4G/4G (RHEL appelle ça kernel-hugemem).
    Tu peux faire le test...

  • [^] # Re: 0xc0000000

    Posté par  . En réponse au journal x32: Une nouvelle ABI Linux '32 bits' pour les CPU x86-64. Évalué à 6.

    En mode x86 normal oui, dans les commentaires de l'article sur LWN il est marqué qu'il
    y a 4 Go avec x32

    Je faisais allusion au mode 32-bit "standard". Avec x32, je n'ai pas regardé en détail mais il est probablement possible de mapper jusqu'à 4Go en usermode.

    Pas tout à fait vrai: avec les extensions PAE [...] il est possible d'avoir des processus qui utilisent plus de 3Go

    Non.
    PAE permet d'exploiter jusqu'à 64Go de mémoire au total, mais un processus donné ne peut pas adresser plus de 4Go (en fait 3Go):

    x86 processor hardware-architecture is augmented with additional address lines used to select the additional memory, so physical address size increases from 32 bits to 36 bits. This, theoretically, increases maximum physical memory size from 4 GB to 64 GB. The 32-bit size of the virtual address is not changed, so regular application software continues to use instructions with 32-bit addresses and (in a flat memory model) is limited to 4 gigabytes of virtual address space. The operating system uses page tables to map this 4-GB address space into the 64 GB of physical memory. The mapping is typically applied differently for each process. In this way, the extra memory is useful even though no single regular application can access it all simultaneously.

    Pour Linux, il existe un patch dit 4/4 qui permet de mapper 4Go en usermode, mais au détriment des performances (tu dois invalider le TLB et changer la table des pages à chaque changement de contexte usermode/kernel).
    Mais tout ça reste un hack, la vrai solution c'est le passage à 64-bit...

  • # 0xc0000000

    Posté par  . En réponse au journal x32: Une nouvelle ABI Linux '32 bits' pour les CPU x86-64. Évalué à 6.

    le nombre d'application ayant besoin de plus de 4 GO de RAM étant faible

    En fait, l'espace d'adressage pour un processus est limité à 3Go sur 32-bit.
    A partir de PAGE_OFFSET (0xc0000000), c'est mappé par le noyau (en fait à cause des différentes zones tas/mmap/stack ça peut être moins, par exemple le tas était longtemps limité à environ 1Go). Et ça peut filer vite, par exemple dans un programme multi-thread (taille réservée pour la stack de chaque thread), ou en Java :-)