Script für make world & make kernel

rubricanis

Homo ludens
Ich möchte erstmalig world und kernel kompilieren. Angeregt durch ein script von ime (danke dafür!) habe ich dazu ein script geschrieben. Allerdings benutze ich DragonflyBSD auf einem VPS was sich aber nur geringfügig von FreeBSD unterscheidet. Ich habe hierzu 3 Fragen:

(1) Ich verstehe die argumente vom trap befehl nicht und man ist da auch nicht hilfreich. Könnte das mal jemand erläutern.

(2) Wenn das script angestossen ist läuft das einfach weiter wenn ich auslogge oder wird das dann abgebrochen. Ich frage deshalb weil das kompilieren ja ewig dauert und ich nicht unbedingt darauf warten will. Und was passiert mit dem output falls ich ausloggen kann. Kann ich das in eine Datei umleiten. Wenn ja wie und macht das überhaupt Sinn?

(3) Ich stehe ja mit shell scripting ein wenig auf dem Kriegsfuß. Könntet ihr das folgende script mal durchsehn ob ich da Fehler gemacht habe oder etwas besser zu machen ist. Ich habe das bislang nur mit einem dummy make getestet.
Code:
#!/usr/bin/env sh
line="--------------------"
jobs=`sysctl -n hw.ncpu`
src="/user/src"
config="$HOME/kernel/MYKERNEL"
logfile="$HOME/kernel/log.txt"
log="/usr/bin/time -a -o ${logfile}"

#------ open log ---------
rm ${logfile}
touch ${logfile}
echo `date` >> ${logfile}

#---- error catcher -----
catch() {
   local line="================"
   echo >> ${logfile} ${line} "ERROR in make ${1}" ${line}
   echo ${line} "ERROR in make ${1}" ${line}
   exit 1
}

#---------- trap ??? ---------------

#------ go! ------
for target in clean buildworld buildkernel installkernel installworld upgrade; do
   echo >> ${logfile} ${line} 'make' ${target} ${line}
   if [ ${target} = "buildkernel" -o ${target} = "installkernel" ]; then
     ${log} make -s -C ${src} -j ${jobs} "KERNCONF=${config}" ${target} || catch ${target}
   else
     ${log} make -s -C ${src} -j ${jobs} ${target} || catch ${target}
   fi
done

#-------- done ----------
echo `date` >> ${logfile}

Die Angst des Torwards vorm Elfmeter! :mad: Glücklicherweise gibt es ja beim VPS die Möglichkeit einen Snapshot zurückzuspielen... :)

tia, Peter
 
Zu 2): Ich würde einfach sowas wie screen oder tmux benutzen und das Script laufen lassen, dann kannst du auch die Verbindung kappen sozusagen ;)
 
Code:
     trap [action] signal ...

     trap -l
             Cause the shell to parse and execute action when any specified
             signal is received.  The signals are specified by name or number.
             In addition, the pseudo-signal EXIT may be used to specify an
             action that is performed when the shell terminates.  The action
             may be an empty string or a dash (`-'); the former causes the
             specified signal to be ignored and the latter causes the default
             action to be taken.  Omitting the action is another way to
             request the default action, for compatibility reasons this usage
             is not recommended though.  In a subshell or utility environment,
             the shell resets trapped (but not ignored) signals to the default
             action.  The trap command has no effect on signals that were
             ignored on entry to the shell.

             Option -l causes the trap command to display a list of valid sig-
             nal names.

Das hast du gefunden?

Normalerweise wird ja ein Script einfach abgebrochen, wenn du z.B. Ctrl-C drückst. Mit
Code:
trap foo INT

foo() {
}
kannst du das Ctrl-C quasi abfangen (INT = INTerrupt), und dann wird "foo" ausgeführt. Da drin kannst du z.B. tempfiles aufräumen oder sonstwas.
 
Das hast du gefunden?
Nöö, unter man trap gab es nur eine Liste von buildin commands. Hab es jetzt unter man sh gefunden.
Normalerweise wird ja ein Script einfach abgebrochen, wenn du z.B. Ctrl-C drückst.
OK, verstehe. Ich denke "" wäre hier das richtige Argument. Oder ist dash '-' sinnvoller? Es geht mir nur darum dass die Nachricht ins log geschrieben wird. Also in etwa so (untested).
Code:
trapped(){
        echo >> ${logfile} ${line} "SIGNAL TRAPPED"  ${line}
}
trap trapped ""
Oder könnte ich das auch direkt in trap schreiben ?
Code:
trap "echo >> ${logfile} ${line} \"SIGNAL TRAPPED\"   ${line}"  ""

Gibt es einen Weg herauszufinden welches signal gesendet wurde ?
 
"The signals are specified by name or number."

Also eher
Code:
trap trapped INT

Ob man das Signal erkennen kann, weiß ich grad nicht. Im Zweifelsfall für jedes Signal eine Funktion bzw. dieselbe Funktion mit Parameter aufrufen.

Code:
trap "trapped INT" INT
trap "trapped EXIT" EXIT
etc.
 
Danke TCM, ich denke so werde ich das machen! Jetzt muss ich mir nur noch tmux und die signale ansehen und dann geht es los ! :rolleyes:
 
Done! :)

Hier mal das timing ( VPS, 2 vCPU, 8 GB)
-------------------- make clean --------------------
45.17s real 11.68s user 45.49s sys
-------------------- make buildworld --------------------
1h26m3.10s real 1h33m21.55s user 45m33.74s sys
-------------------- make buildkernel --------------------
17m37.71s real 16m33.78s user 8m3.97s sys
-------------------- make installkernel --------------------
47.32s real 6.12s user 24.19s sys
1m32.97s real 16.71s user 48.93s sys
Ganz schön lange! Ich muss mich noch mit tmux beschäftigen das doch recht kompliziert ist.

Was bedeuten hier die Zeiten real/user/sys ?

Und falls das script mal jemand gebrauchen kann, hier die endgültige Lösung (XXX steht für den gewählten Namen ).
Code:
#!/usr/bin/env sh
# tested with DragonflyBSD 4.05 -> 4.1
# --- don't forget! ---
# cd /usr/src/sys/config
# ln -s /root/kernel/XXX
line="--------------------"
jobs=`sysctl -n hw.ncpu`
src="/usr/src"
config="XXX"
logfile="/root/kernel/log.txt"
log="/usr/bin/time -a -h -o ${logfile}"

#--- open log ---
touch ${logfile}
echo >> ${logifle} " "
echo >> ${logfile} ${line}${line}${line}
echo `date` >> ${logfile}

#---- catch errors ----
catch() {
   local line="================"
   echo >> ${logfile} ${line} "ERROR in make ${1}" ${line}
   echo ${line} "ERROR in make ${1}" ${line}
   exit 1
}
#--- trap signals ----
trapped(){
   local line="================"
   echo >> ${logfile} ${line} "SIGNAL ${1} TRAPPED"  ${line}
}
trap "trapped INT" INT
trap "trapped QUIT" QUIT
trap "trapped ABRT" ABRT
trap "trapped KILL" KILL
trap "trapped TERM" TERM
trap "trapped EXIT" EXIT

#------ go! ------
for target in clean buildworld  buildkernel installkernel; do
   echo >> ${logfile} ${line} 'make' ${target} ${line}
   if [ ${target} = "buildkernel" -o ${target} = "installkernel" ]; then
     ${log} make -s -C ${src} -j ${jobs} "KERNCONF=${config}" ${target} || catch ${target}
   else
     ${log} make -s -C  ${src} -j ${jobs} ${target} || catch ${target}
   fi
done
# 1 job only
${log} make -s -C  ${src} "installworld" || catch "installworld"

#------ done ------
echo >> ${logfile} ${line}${line}${line}
echo `date` >> ${logfile}
echo "reboot, cd /usr/src and make upgrade"
echo >> ${logfile} ${line}${line}${line}
Vielen Dank für die Hilfe!
Peter
 
Real ist die wirklich vergangene Zeit.

User und sys sind die Verbratene Rechenzeit aufgeteilt in Userland und Kernel.
Die können niedriger ausfallen als die echte Zeit, wenn die CPU zum Beispiel viel auf I/O wartet und damit idle ist. Aber in der Regel sind die höher, weil Du ja mehrere Kerne beschäftigst und die gleichzeitig arbeiten.

Perfekt parallelisiert ist ein Prozess wenn gilt: user + sys == real * Kerne

EDIT: Formel korrigiert
EDIT2: Formel wahr vorher richtig, wieder korrigiert
 
Zuletzt bearbeitet:
Perfekt parallelisiert ist ein Prozess wenn gilt: user + sys == Kerne * real
Hmmm, versteh ich nicht. Was hieße das für 2 vCPUs und sagen wir mal 5 user ?
Aber: "Perfection is reached on the point of desaster!" ;)

Ich habe mich an folgendes aus dem alten thread gehalten:
Meiner Erfahrung nach ist ncpu+1 das höchste was Sinn macht, vor allen bei Single-Cores. Bei Quad-Cores liegt der Unterschied zwischen ncpu und ncpu+1 in der Messungenauigkeit.
Und da es mir nicht auf die Messungenauigkeit ankommt habe ich einfach nCPU genommen. IO spielt in meinem Falle auch keine Rolle.
 
Als Tipp: Spare dir das "make clean" und mache stattdessen ein "rm -Rf /usr/obj/usr /usr/obj/lib32". Das lib32 kannst du in 11-CURRENT weglassen. Einmal ist es schneller den ganzen Kram einfach zu löschen, als sich make durch jede Datei einzeln fressen zu lassen. Vor allem aber ist das "make clean" Target unzuverlässig. Nach größeren Änderungen in den Makefiles lässt es schon mal Dinge liegen, woraufhin dir der Build um die Ohren fliegen kann.
 
Yamagi, das ist DragonFlyBSD, nicht FreeBSD. Ich weißt nicht ob die nicht irgend etwas anders machen. /usr/obj/lib32 gibt es z.B. nicht, da dfly nur noch mit 64 bit läuft.
Aber ich werde beim nächsten upgrade mal einfach /user/obj/user umbenennen und das dann so machen wie du sagst .
 
Hmmm, versteh ich nicht. Was hieße das für 2 vCPUs und sagen wir mal 5 user ?
Aber: "Perfection is reached on the point of desaster!" ;)
Die Anzahl der User hat damit nichts zu tun, das User steht für user mode, also alles was nicht im kernel mode passiert.

Beispiel, Dein buildworld:
1h26m3.10s real 1h33m21.55s user 45m33.74s sys
real = 5163.1
Kerne = 2
user = 5601.6
sys = 2733.7
=> 10326.2 == 8335.3

Will heißen da ist noch Luft nach oben. Wenn I/O keine Rolle spielte sollte dein Real nur 4167.7s (1h 9m 27.7s) dauern.
 
Ich verstehe: user + sys == Kerne * real ist der theoretisch zu erreichende Wert. Praktisch kann man das wohl nur ausprobieren, also z.B.
jobs=$(($(sysctl -n hw.ncpu) +1))
jobs=$(($(sysctl -n hw.ncpu) * 2)) o.Ä.

Ist das richtig so ?
 
Prinzipiell ja.

real - (user + sys) / kerne = Wartezeit

Durch mehr Prozesse erhöhst Du die Chance das ein Prozess dabei ist, der nicht auf I/O warten muss um zu arbeiten, allerdings verlangsamt Konkurrenz zwischen den Prozessen das I/O, irgendwann schaden mehr Prozesse also.

Grenzen sind dem ganzen allerdings dadurch gesetzt wie gut das überhaupt parallelisierbar ist.
 
Zurück
Oben