Subject: debian-policy: Policy proposal: Cpu extension code Package: debian-policy Version: 3.1.1.1 Severity: wishlist
Greetings! I posted this proposal to debian-policy for discussion in June, but am only now formally requesting its inclusion in the policy. I've taken the liberty of including recommendations from various submitters. The goal of this proposal is to provide a mechanism whereby packages can safely make use of cpu instruction set extensions (e.g. sse1,sse2,3dnow,3dnowext, etc.) In this scheme, packages can install on any machine of the general architecture, and extension instructions only get executed on appropriately capable cpus, even if /usr is served up over NFS. Proposal outline: 1) All packages providing programs and/or libraries which make use of CPU instruction set extensions (CISEs) must provide identical functionality on all machines of the given general architecture. One way to achieve this is for the code to be protected by runtime probes of the cpu, followed by appropriate branching to correctly executable sections. Alternatively, packages can separate routines using CISEs into shared libraries. This section of the policy details the machanism whereby ldso will load appropriate versions of such libraries according to the capabilities of the runtime cpu. 2) Libraries containing CSIEs should be placed in a designated subdir of /usr/lib specialized for code requiring the cpu extension in question. All such directories should be agreed upon and sanctioned by the policy committee. As a suggestion, the directory might be named after the cpu capability (as reported in /proc/cpuinfo) required to run the code, (e.g. /usr/lib/{sse,sse2,3dnow,3dnowext} on i386, /usr/lib/ev5 on alpha, and perhaps /usr/lib/sparc64 on sparc, etc.) 3) All functionality provided by this code should also be provided by a binary-equivalent generic shared lib of the same name and soname in /usr/lib. 4) Ideally, ldso should be smart enough to search the special directories first given the running cpu characteristics. Barring this, a system script, update-ld.so.conf, should be created, which packages can call at install/remove time, to add/remove the specialized paths appropriate to the running cpu to /etc/ld.so.conf and then run ldconfig. Optionally (and preferably), this script could also be run at boot time to catch cpu-upgrades and/or kernel upgrades (SSE requires kernel support). Paths need not be added, and can be removed, if no libraries exist in the directory. The package providing this script should be in the 'base' section if invoked at boot time. Otherwise, packages using this functionality should depend upon the update-ld.so.conf package. 5) For this scheme to work, it is necessary to ensure that ldso loads libraries in the directories specified in /etc/ld.so.conf in preference to identically named versions in /lib or /usr/lib, as is currently the case with Debian's ldso. It is part of this policy that such behavior remain standard on Debian systems. The Debian atlas packages currently use this scheme. I believe that at least gmp can currently make use of it as well. I've provided a sample update-ld.so.conf below. If this proposal is accepted, I'd be happy to package it or something similar. Thanks for your work on Debian! -- Camm Maguire [EMAIL PROTECTED] ========================================================================== "The earth is but one country, and mankind its citizens." -- Baha'u'llah ============================================================================= sample update-ld.so.conf, can doubtlessly be improved ============================================================================= #!/bin/bash set -e FILE=/etc/ld.so.conf usage() { echo "Usage: $0 [ --enable <ext> ] [ --disable <ext> ] [ --auto ]" exit 1 } do_ldso() { local j=$@ jj=$@ p q qp qm i k zi pp tf tf=$(tempfile -m 644) ( while read p; do q=$(basename $p) qp="+$q" qm="_$q" k="" for i in $j ; do if [ $i = $qp ] ; then k=p break fi if [ $i = $qm ] ; then k=m break fi done case $k in p) pp="" zi="" for i in $jj; do if [ -z $zi ] && echo $i | grep -q "^+" ; then echo /usr/lib/${i#+} else pp="$pp $i" fi if [ $i = $qp ] ; then zi=t ; fi done jj=$pp ;; m) ;; *) echo $p;; esac done < $FILE for i in $jj; do if echo $i | grep -q "^+" ; then echo /usr/lib/${i#+} fi done ) >$tf mv $tf $FILE ldconfig } cpu_probe_i386() { local fl i res kv j if ! [ -r /proc/cpuinfo ] ; then echo This script needs the proc filesystem to work exit 1 fi fl=$(grep ^flags /proc/cpuinfo) kv=$(uname -a | cut -f3 -d\ | cut -f2 -d.) # # Names changed in 2.4.x # Listed possibilities must be in order of preference here # case $kv in 2) ss="26 xmm 3dnowext 3dnow";; *) ss="sse2 sse 3dnowext 3dnow";; esac res="" for i in $ss; do j=${i/xmm/sse} j=${j/26/sse2} if echo $fl | grep -q "\<$i\>" ; then res="$res +$j" else res="$res _$j" fi done echo $res } cpu_probe_alpha() { local fl i res j if ! [ -r /proc/cpuinfo ] ; then echo This script needs the proc filesystem to work exit 1 fi fl=$(grep ^"cpu model" /proc/cpuinfo) res="" for i in EV7 EV6 EV5; do j=${i/EV7/ev5} j=${j/EV6/ev5} if grep -q "\<$i\>" $fl ; then res="$res +$j" else res="$res -$j" fi done echo $res } cpu_probe_sparc() { local fl i res if ! [ -r /proc/cpuinfo ] ; then echo This script needs the proc filesystem to work exit 1 fi fl=$(grep ^"cpu" /proc/cpuinfo) res="" for i in $fl; do case $i in UltraSparc) res="$res sparc64";; *);; esac done echo $res } mmatch() { local k t j i k=$1 t="" shift j=$@ for i in $j; do if [ $k = ${i#?} ] ; then t=$i; fi done echo $t } off() { local k j t i k=$1 shift j=$@ t="" for i in $j ; do if [ $k = ${i#?} ] ; then t="$t _$k" else t="$t $i" fi done echo $t } on() { local k j t i k=$1 shift j=$@ t="" for i in $j ; do if [ $k = ${i#?} ] ; then t="$t +$k" else t="$t $i" fi done echo $t } AUTO="" EN="" DIS="" EXT="" if [ $# -lt 1 ] ; then usage; fi case $1 in --auto) AUTO=t; if [ $# -ne 1 ] ; then usage; fi;; --enable) EN=t; if [ $# -ne 2 ] ; then usage; fi; EXT=$2;; --disable) DIS=t; if [ $# -ne 2 ] ; then usage; fi; EXT=$2;; *) usage;; esac ARCH=$(dpkg --print-architecture) case $ARCH in i386) cpu=$(cpu_probe_i386);; alpha) cpu=$(cpu_probe_alpha);; sparc) cpu=$(cpu_probe_sparc);; *) echo "There are no cpu extensions supported for this architecture ($ARCH)"; exit 0;; esac if [ "$AUTO" = "" ] ; then if [ "$(mmatch $EXT $cpu)" != "+$EXT" ] ; then echo "Cpu extension $EXT is not supported on this architecture ($ARCH)" exit 1 fi ldso="" while read p ; do q=$(basename $p) ldso="$ldso +$q" done < $FILE final="" for i in $cpu ; do t="_${i#?}" for j in $ldso ; do if [ $i = $j ] ; then t=$j fi done final="$final $t" done if [ "$EN" != "" ] ; then final=$(on $EXT $final) else final=$(off $EXT $final) fi fi do_ldso $final exit 0 ============================================================================= -- System Information Debian Release: 2.2 Kernel Version: Linux intech19 2.2.19-gen #1 SMP Fri May 25 15:14:23 EDT 2001 i686 unknown