web-dev-qa-db-fra.com

Universal Non-Bash `Temps` Benchmark Alternative?

Pour comparer des temps d'exécution de scripts entre différentes coquilles, certaines réponses SE suggèrent à l'aide de bash 'S intégrétime commande, comme:

time bash -c 'foo.sh'
time dash -c 'foo.sh'

... etc, pour chaque coquille à tester. De tels repères ne parviennent pas à éliminer le temps pris pour chaque coquille pour charger et initialiser elle-même. Par exemple, supposons que les deux commandes ci-dessus étaient stockées sur n périphérique lent à la vitesse de lecture d'une disquette anticipée , (124 kb/s), dash (A ~ 150k exécutable) chargerait environ 7x plus rapide que bash ( ~ 1m), le temps de chargement de la coquille obligeait Les numéros time - Les temps de chargement de ces coquilles étant non pertinents pour mesurer les temps d'exécution de foo.sh sous chaque coquille après Les coquilles ont été chargées.

Quel est le meilleur util portable et général à exécuter pour le timing de script pouvant être exécuté de dans chaque coquille? Donc, le code ci-dessus ressemblerait à quelque chose comme:

bash -c 'general_timer_util foo.sh'
dash -c 'general_timer_util foo.sh'

NB: Pas de shell intégrétime commandes, car aucun n'est portable ou général.


Mieux encore, si l'util est également capable de comparer le temps pris par les commandes et les pipelines internes d'une coque, sans que l'utilisateur n'envoie d'abord à les emballer dans un script. La syntaxe artificielle comme cela aiderait:

general_timer_util "while read x ; do echo x ; done < foo"

Certaines coquilles 'time peuvent gérer cela. Par example bash -c "time while false ; do : ; done" travaux. Pour voir ce qui fonctionne, (et non), sur votre système essaie:

tail +2 /etc/shells | 
while read s ; do 
    echo $s ; $s -c "time while false ; do : ; done" ; echo ----
done
10
agc

J'utilise le [~ # ~ # ~] gnu [~ # ~ ~]date commande, qui prend en charge une minuterie haute résolution:

START=$(date +%s.%N)
# do something #######################

"$@" &> /dev/null

#######################################
END=$(date +%s.%N)
DIFF=$( echo "scale=3; (${END} - ${START})*1000/1" | bc )
echo "${DIFF}"

Et puis j'appelle le script comme celui-ci:

/usr/local/bin/timing Dig +short unix.stackexchange.com
141.835

L'unité de sortie est en millisecondes.

7
Rabin

L'utilitaire time est généralement intégré à la coquille, comme vous l'avez remarqué, ce qui le rend inutile comme une minuterie "neutre".

Cependant, l'utilité est généralement également disponible en tant qu'utilisation externe, /usr/bin/time, cela pourrait bien être utilisé pour effectuer les expériences de synchronisation que vous proposez.

$ bash -c '/usr/bin/time foo.sh'
6
Kusalananda

Voici une solution qui:

  1. éliminer [s] le temps pris pour chaque coquille pour charger et s'initialiser

  2. peut être exécuté de dans chaque coquille

  3. Les usages

    no Shell intégré time commandes, car aucun n'est portable ou général

  4. Fonctionne dans toutes les coquilles compatibles POSIX.
  5. Fonctionne sur tous les systèmes compatibles POSIX et compatibles XSI avec un compilateur C ou où vous pouvez compiler un exécutable C à l'avance.
  6. Utilise la même implémentation de synchronisation sur toutes les coquilles.

Il y a deux parties: un programme C court couvrant gettimeofday , qui est obsolète mais toujours plus portable que clock_gettime, et un script short shell qui utilise ce programme pour obtenir une horloge de précision microsecondes de lecture des deux côtés de l'approvisionnement d'un script. Le programme C est le seul moyen portable et minimal de la hauteur d'une sous-deuxième précision sur un horodatage.

Voici le programme C Epoch.c:

#include <sys/time.h>
#include <stdio.h>
int main(int argc, char **argv) {
    struct timeval time;
    gettimeofday(&time, NULL);
    printf("%li.%06i", time.tv_sec, time.tv_usec);
}

Et le script shell timer:

#!/bin/echo Run this in the Shell you want to test

START=$(./Epoch)
. "$1"
END=$(./Epoch)
echo "$END - $START" | bc

Ceci est standard langage de commande shell et bc et doit fonctionner comme script sous Toute coque compatible POSIX.

Vous pouvez utiliser ceci comme suit:

$ bash timer ./test.sh
.002052
$ dash timer ./test.sh
.000895
$ zsh timer ./test.sh
.000662

Il ne mesède pas le système ou l'utilisation de l'utilisateur, seule une horloge murale non monotonique écoulée. Si l'horloge système change pendant l'exécution du script, cela donnera des résultats incorrects. Si le système est sous charge, le résultat ne sera pas fiable. Je ne pense pas que rien de mieux puisse être portable entre les coquilles.

Un script de minuterie modifié pourrait utiliser eval au lieu de lancer des commandes en dehors d'un script.

6
Michael Homer

Plusieurs fois la solution révisée à l'aide de /proc/uptime et dc/bc/awk en grandes parties grâce à l'entrée par AGC :

#!/bin/sh

read -r before _ < /proc/uptime

sleep 2s # do something...

read -r after _ < /proc/uptime

duration=$(dc -e "${after} ${before} - n")
# Alternative using bc:
#   duration=$(echo "${after} - ${before}" | bc)
# Alternative using awk:
#   duration=$(echo "${after} ${before}" | awk '{print $1 - $2}')

echo "It took $duration seconds."

Suppose évidemment que /proc/uptime existe et a une certaine forme.

4
phk