Convertir "tim=" dans les traces 10046 sous Linux

Comment est calculé le champ tim= dans les traces 10046 ?

Cette question anodine, vous emmènera sur des voies surprenantes qui vous apprendront par exemple :

  • L’indicateur en question semble dépendre de la plateforme au point où, sur Solaris, l’indicateur ne serait pas en microsecondes mais en 1024*nanosecondes ; c’est du moins ce que suggère cet article sur le blog d’Oracle.
  • Linux ne semble pas capable « naturellement » d’avoir une précision au delà de la microseconde et, à quelques tentatives prêt, la fonction gethrtime() n’existe pas sur le système au pingouin. 
  • L’utilisation de gettimeofday() pour mesurer des temps a tout un tas d’effet de bord qui font que c’est difficilement portable d’un serveur à l’autre ou dans le même fichier. 
  • Le monde commence le 1er janvier 1970.

    Passons le plaisir de ces lectures pour fournir 2 primitives qui font le travail à l’envers et vous donnent pour base de données 11.2 sur Linux, une date à partir du champ tim=.

    Note:
    Si vous utilisez les traces Oracle, il n’est pas nécessaire de connaitre l’algorithme de conversion. En effet, tout ce qu’il vous faut savoir est que le nombre est exprimé en microsecondes. Vous pourrez alors comparer les valeurs pour connaitre les temps relatifs ; les traces affichent suffisamment de date pour vous repérer en général.

    Quoiqu’il en en soit, au moins sous Linux qui utilise la fonction gettimeofday() dans le fichier d’après ce que montre strace, vous pouvez également réaliser les conversions en découpant le nombre en 2 parties :

    • La première tronquée au 6 derniers caractères contient le nombre de secondes depuis epoch-1970. 
    • Les 6 derniers caractères fournissent le détail des micro-secondes dans la seconde. Tout cela donne 2 fonctions ci-dessous :

    En C

    cat getTim10046.c 
    #include <sys/time.h>
    #include <string.h>
    #include <stdio.h>
    #include <time.h>
    #include <unistd.h>

    int main(int argc, char **argv)
    {
    char arg_sec[16];
    char arg_usec[6];

    strncpy(arg_sec, argv[1], strlen(argv[1])-6);
    arg_sec[strlen(argv[1])-6]='';

    strncpy(arg_usec, argv[1]+strlen(argv[1])-6, 6);

    struct timeval tv;
    tv.tv_sec=atol(arg_sec);
    tv.tv_usec=atol(arg_usec);

    struct tm* ptm;
    char time_string[40];

    ptm = localtime (&tv.tv_sec);
    strftime (time_string, sizeof (time_string), "%Y-%m-%d %H:%M:%S", ptm);
    printf ("%s.%06ldn", time_string, tv.tv_usec);
    }

    gcc -o getTim10046 getTim10046.c

    ./getTim10046 1352570556532945
    2012-11-10 19:02:36.532945

    En Perl

    cat getTim10046.pl
    my $sec = substr $ARGV[0], 0, -6;
    my $usec = substr $ARGV[0], -6, 6;
    print localtime($sec) . " + " . $usec . " usn";

    perl getTim10046.pl 1352570556532945
    Sat Nov 10 19:02:36 2012 + 532945 us

    Notez que les 2 résultats en C et Perl sont formatés dans la timezone de votre serveur et vous devrez utiliser gmtime plutôt que localtime dans les 2 langages pour obtenir des résultats qui fonctionnent universellement.

    1 réflexion sur “Convertir "tim=" dans les traces 10046 sous Linux”

    1. Dans sa formation #MOTD Cary Millsap parle du 1024 abordé ici. Il s’agit d’une ancienne optimisation, la division par 1024 est simplement plus rapide que la division par 1000. Il faudrait vérifier à partir de quelle version d’Oracle exactement mais ceci n’est plus d’actualité, maintenant que les cpu sont plus rapides c’est bien 1000 et plus 1024. Article intéressant puisque la valeur de tim est la seule chose sur laquelle on peut se baser pour mettre les choses dans le bon ordre dans la trace.

    Les commentaires sont fermés.