[devel] size_time_regression

Alexey Tourbin =?iso-8859-1?q?at_=CE=C1_altlinux=2Eru?=
Пт Июн 2 17:43:07 MSD 2006


Пока не забыл.  Есть ещё несколько идей.

Речь идет о возможности перманентной пересборки сизифа.  Разовая
пересборка с точки зрения имеющегося оборудования достаточно дорога;
и тем не менее оборудование большей частью простаивает.  Значит, каждый
день можно составлять определенный план инкрементной пересборки и
реализовывать его ночью, когда оборудование простаивает.

Disclaimer: это может быть не очень нужно с утилитарной точки зрения.
То есть разовые еженедельные пересборки "понятнее".  С другой стороны,
их приходится ждать.

Теперь ближе к задаче.  Большие по размеру пакеты собираются долго, а
маленькие -- быстро.  Нужно оценить зависимость времени сборки пакета от
размера пакета, это называется линейная регрессия.  (Регрессия может
быть и нелинейной, но в таком случае выбор класса функций становится
нетривиальной задачей; см. "регуляризация"; с другой стороны, нелинейную
регрессию можно свести к линейной при помощи преобразования координат;
это есть в учебниках по эконометрике.)

Если же есть регрессия с приличным коэффициентом детерминации, то можно
решить следующую задачу: какое количество пакетов, подлежащих
пересборке, удастся собрать за N часов?  По условию размеры пакетов
известны.  С вероятностью 95% апостериорное время сборки не должно быть
больше $N+1$ часов, но и не меньше $N-1$.

Короче, имея на руках логи сборки пакетов и сами эти пакеты, вот как
примерно можно оценить регрессию.

size_time_regression()
{
	find "$@" -type f -print0 |xargs -r0 gzip -cdfq |
		LC_ALL=C awk 'NF==2 && /^Installing .*[.]src[.]rpm$/ { pkg=$2 }
			NF>4 && $1~/user$/ && $2~/system$/ && 
				$3~/elapsed$/ && $4~/CPU$/ {
					if (match($3, /^([0-9]+):([0-9]+[.][0-9]+)/, a))
						print pkg "\t" int(a[1]*60+a[2]+0.5) }' |
				sort -n -k2,2 |sort -u -k1,1 >buildtime
	while IFS=$'\t' read -r pkg time; do
		f="${sisyphus:-/raid/ALT/Sisyphus}"/files/SRPMS/"$pkg"
		if [ -s "$f" ]; then
			size="$(du -bk "$f" |cut -f1)"
			printf "%s\t%s\t%s\n" "$pkg" "$size" "$time"
		fi
	done <buildtime >buildsizetime
	cut -f2,3 buildsizetime >buildsizetime.dat
	R -q --no-save --no-restore <<'__EOF__' |tee R.output
	dat=read.table("buildsizetime.dat", col.names=c("size", "time"))
	summary(dat)
	library(boot)
	corr(dat)
	x=c(as.matrix(dat["size"]))
	y=c(as.matrix(dat["time"]))
	linear=lm(y~x); linear
	cat("coeff_a0=", linear$coefficients[1], "\n", sep="")
	cat("coeff_a1=", linear$coefficients[2], "\n", sep="")
	qx=quantile(x, probs=c(0.95,0.99)); qx
	cat("q95_size=", round(qx[1]), "\n", sep="")
	qy=quantile(y, probs=c(0.95,0.99)); qy
	cat("q95_time=", round(qy[1]), "\n", sep="")
__EOF__
	eval "$(grep -E '^(q95_size|q95_time|coeff_a.)=' R.output)"
	gnuplot <<__EOF__
	set terminal png size 1024,768
	set output "buildsizetime.png"
	set xtics 0, 1024
	set ytics 0, 60
	set xlabel "source package size, KB"
	set ylabel "build time, sec"
	plot [1:$q95_size] [1:$q95_time] "buildsizetime.dat", $coeff_a0+$coeff_a1*x
__EOF__
	gnuplot <<__EOF__
	set terminal png size 1024,768
	set output "buildsizetime2.png"
	set logscale xy 2
	set xlabel "source package size, KB"
	set ylabel "build time, sec"
	plot "buildsizetime.dat", $coeff_a0+$coeff_a1*x
__EOF__
	gqview -t buildsizetime.png buildsizetime2.png
}

Вот выдержка из вывода:

>       summary(dat)
      size             time
 Min.   :     2   Min.   :   0.00
 1st Qu.:    26   1st Qu.:   5.00
 Median :   141   Median :  10.00
 Mean   :  1196   Mean   :  43.54
 3rd Qu.:   541   3rd Qu.:  30.00
 Max.   :174291   Max.   :3260.00
>       library(boot)
>       corr(dat)
[1] 0.1951247
>       x=c(as.matrix(dat["size"]))
>       y=c(as.matrix(dat["time"]))
>       linear=lm(y~x); linear

Call:
lm(formula = y ~ x)

Coefficients:
(Intercept)            x
   37.61992      0.00495

>       cat("coeff_a0=", linear$coefficients[1], "\n", sep="")
coeff_a0=37.61992
>       cat("coeff_a1=", linear$coefficients[2], "\n", sep="")
coeff_a1=0.004950177
>       qx=quantile(x, probs=c(0.95,0.99)); qx
     95%      99%
 3904.80 17872.64
>       cat("q95_size=", round(qx[1]), "\n", sep="")
q95_size=3905
>       qy=quantile(y, probs=c(0.95,0.99)); qy
   95%    99%
150.20 562.28
>       cat("q95_time=", round(qy[1]), "\n", sep="")
q95_time=150

Рисунок приложен.  Легко видеть, что линейная регрессия не удалась.
То есть видно, что маленькие пакеты собираются быстро, а большие пакеты
могут собираться как быстро, так и медленно.  То есть имеется
специфическая автокрреляция.  Условия Гаусса-Маркова не выполняются,
поэтому наибольшее правдоподобие (в частности, МНК-регрессию) вообще
применять нельзя.

На этом идея заканчивается. :)

Положительное содержание: пакет можно персобрать в среднем менее чем за минуту.
Желающие могут построить доверительный интервал.  Суммарная девиация (СКО)
выборки уменьшается в $\frac1{\sqrt N}$ раз.
----------- следующая часть -----------
Было удалено вложение не в текстовом формате...
Имя     : buildsizetime.png
Тип     : image/png
Размер  : 15269 байтов
Описание: =?iso-8859-1?q?=CF=D4=D3=D5=D4=D3=D4=D7=D5=C5=D4?=
Url     : <http://lists.altlinux.org/pipermail/devel/attachments/20060602/4d87ae18/attachment-0001.png>
----------- следующая часть -----------
Было удалено вложение не в текстовом формате...
Имя     : =?iso-8859-1?q?=CF=D4=D3=D5=D4=D3=D4=D7=D5=C5=D4?=
Тип     : application/pgp-signature
Размер  : 191 байтов
Описание: =?iso-8859-1?q?=CF=D4=D3=D5=D4=D3=D4=D7=D5=C5=D4?=
Url     : <http://lists.altlinux.org/pipermail/devel/attachments/20060602/4d87ae18/attachment-0001.bin>


Подробная информация о списке рассылки Devel