############################################################################### SHELL := $(shell which bash) .ONESHELL: ############################################################################### ATT = $(EXE:=.att) DEP = $(addprefix .,$(EXE:=.d)) EXE = $(basename $(SRC)) N = $(shell sed -n 's/std::size_t threads =\(.*\);/\1/p' common.h) P1 = 13 P2 = 7 REP = 25 SRC = $(wildcard *.cc) STA = $(EXE:=.sta) TXT = $(EXE:=.txt) LOG = $(EXE:=.log) ############################################################################### CXXFLAGS = -flto -g -march=native -O3 -std=c++23 -Wall ############################################################################### all: @if make -qs $(TXT); then make -s sort else make -s stat fi att: $(ATT) clave: @printf "%$$(($(P1) + $(P2) * 15))s\n" | tr ' ' '-' echo "key:" printf "%$$(($(P1) + $(P2) * 15))s\n" | tr ' ' '-' echo " rc : race conditions == wrong writes" echo " rn : number of reads" echo " rmin : minimum number of reads" echo " ravg : average number of reads" echo " rstdev : standard deviation of the number of reads" echo " rmax : maximum number of reads" echo " wn : number of total writes (not always correct)" echo " wmin : minimum number of writes" echo " wavg : average number of writes" echo " wstdev : standard deviation of the number of writes" echo " wmax : maximum number of writes" echo " fair : log(ravg / wavg) maximum fairness = 0" echo " msg : rn + wn" echo " cpu : cpu time (ms)" echo " ratio : msg / cpu (messages/ms)" clean: -rm -fv $(ATT) $(DEP) $(EXE) $(TXT) $(LOG) $(STA) core* *~ -find -mindepth 2 -maxdepth 2 -name makefile -execdir make $@ \; default: n$(shell echo $$(($$(nproc) / 2))) 10ms all exe: $(EXE) fast: n1 1ms all slow: n$(shell nproc) 25ms all sort: clave @declare -a N=('13' '14' '15' '16') declare -a F=('fair' 'msg' 'cpu' 'ratio') declare -a R=('' 'r' '' 'r') for (( i=0; i<$${#N[@]}; ++i )); do printf "%$$(($(P1) + $(P2) * 15))s\n" | tr ' ' '-' make -s $(firstword $(TXT)) head -n 1 $(firstword $(TXT)) | sed "s/ \($${F[$$i]}\)/\[\1\]/" printf "%$$(($(P1) + $(P2) * 15))s\n" | tr ' ' '-' make stat | grep -E -w "$$(echo $(EXE) | tr ' ' '|')" | sort -k$${N[$$i]},$${N[$$i]}n$${R[$$i]} -k16,16nr -k13,13n -s done printf "%$$(($(P1) + $(P2) * 15))s\n" | tr ' ' '-' stat: clave @printf "%$$(($(P1) + $(P2) * 15))s\n" | tr ' ' '-' for i in $(TXT); do make -s $$i if [[ "$$i" == "$(firstword $(TXT))" ]]; then head -n1 $$i printf "%$$(($(P1) + $(P2) * 15))s\n" | tr ' ' '-' fi tail -n1 $$i done printf "%$$(($(P1) + $(P2) * 15))s\n" | tr ' ' '-' ############################################################################### %: %.cc $(CXX) $(CPPFLAGS) $(CXXFLAGS) -MMD -MP -MF .$*.d $< $(LDFLAGS) $(LOADLIBES) $(LDLIBS) -o $@ %.att: % objdump -Cd $< > $@ %.hel: % valgrind --tool=helgrind -- ./$< %.leak: % valgrind --leak-check=full -s --show-leak-kinds=all -- ./$< %.log %.sta: % @LANG=C perf stat -e task-clock -r $(REP) -x ';' 2> $*.sta -- ./$< > $*.log %.kk: %.log %.sta | common.h @LC_ALL=C THREADS=$$(sed -n 's/std::size_t threads =\(.*\);/\1/p' common.h) # parse log declare -A numbers declare -A letters while read count char; do if [[ "$$char" =~ [0-9] ]]; then numbers[$$char]=$$count elif [[ "$$char" =~ [a-j] ]]; then letters[$$char]=$$count else echo "[$*.log]: unexpected character '$$char'" exit 1 fi done < <(fold -w 1 < <(cat $*.log | tr -d '\n') | sort | uniq -c) for char in $${!numbers[@]}; do (( numbers["$$char"] = $${numbers["$$char"]} / 10 )) echo "[$*.log]: numbers['$$char'] -> $${numbers["$$char"]}" done for char in $${!letters[@]}; do (( letters["$$char"] = $${letters["$$char"]} / 10 )) echo "[$*.log]: letters['$$char'] -> $${letters["$$char"]}" done # readers readers=$${#numbers[@]} echo "[$*.log]: readers -> $$readers" rv="[$$(echo $${numbers[@]} | tr ' ' ',')]" echo "[$*.log]: rv -> $$rv" if (( readers > 0 )); then rn=$$(python3 -c "print(sum($$rv))") rmin=$$(python3 -c "print(min($$rv))") ravg=$$(python3 -c "import statistics; print(statistics.mean($$rv))") if (( readers > 1 )); then rstdev=$$(python3 -c "import statistics; print(statistics.stdev($$rv))") else rstdev=0 fi rmax=$$(python3 -c "print(max($$rv))") else echo "[$*.log]: no readers found" exit 1 fi printf "%10s %10s %10s %10s %10s %10s\n" readers rn rmin ravg rstdev rmax printf "%10s %10s %10s %10s %10s %10s\n" $$readers $$rn $$rmin $$(printf '%.1f' $$ravg) $$(printf '%.1f' $$rstdev) $$rmax # writers writers=$${#letters[@]} echo "[$*.log]: writers -> $$writers" wv="[$$(echo $${letters[@]} | tr ' ' ',')]" echo "[$*.log]: wv -> $$wv" if (( writers > 0 )); then wn=$$(python3 -c "print(sum($$wv))") wmin=$$(python3 -c "print(min($$wv))") wavg=$$(python3 -c "import statistics; print(statistics.mean($$wv))") if (( writers > 1 )); then wstdev=$$(python3 -c "import statistics; print(statistics.stdev($$wv))") else wstdev=0 fi wmax=$$(python3 -c "print(max($$wv))") else echo "[$*.log]: no writers found" exit 1 fi printf "%10s %10s %10s %10s %10s %10s\n" writers wn wmin wavg wstdev wmax printf "%10s %10s %10s %10s %10s %10s\n" $$writers $$wn $$wmin $$(printf '%.1f' $$wavg) $$(printf '%.1f' $$wstdev) $$wmax %.txt: %.log %.sta @LANG=C declare -A r; for (( i = 0; i < $(N); ++i )); do r["$$i"]="0" done while read v k; do r["$$k"]=$$(bc -lq <<< "$$v / $(REP)") done < <(awk '{for(i=1;i<=length($$0);i++){c=substr($$0,i,1); if(c~/[0-9]/) seen[c]=1} for(c in seen) cnt[c]++; delete seen} END{for(c in cnt) print cnt[c], c}' $*.log | sort) if (( $${#r[@]} < $(N) )); then echo "[$*.log]: $${#r[@]} < $(N)" exit 1 fi rn=0 rmin=0 ravg=0 rstdev=0 rmax=0 if [ "$${#r[@]}" -gt "0" ]; then rv="[$$(echo $${r[@]} | tr ' ' ',')]" rn=$$(python3 -c "print(sum($$rv))") rmin=$$(python3 -c "print(min($$rv))") ravg=$$(python3 -c "import statistics; print(statistics.mean($$rv))") if [ "$${#r[@]}" -gt "1" ]; then rstdev=$$(python3 -c "import statistics; print(statistics.stdev($$rv))") fi rmax=$$(python3 -c "print(max($$rv))") fi declare -A w; letters=({a..z}) for (( i = 0; i < $(N); ++i )); do w["$${letters[$$i]}"]="0" done while read v k; do w["$$k"]=$$(bc -lq <<< "$$v / $(REP)") done < <(awk '{for(i=1;i<=length($$0);i++){c=substr($$0,i,1); if(c~/[a-z]/) seen[c]=1} for(c in seen) cnt[c]++; delete seen} END{for(c in cnt) print cnt[c], c}' $*.log | sort) if (( $${#w[@]} < $(N) )); then echo "[$*.log]: $${#w[@]} < $(N)" exit 1 fi wn=0 wmin=0 wavg=0 wstdev=0 wmax=0 if [ "$${#w[@]}" -gt "0" ]; then wv="[$$(echo $${w[@]} | tr ' ' ',')]" wn=$$(python3 -c "print(sum($$wv))") wmin=$$(python3 -c "print(min($$wv))") wavg=$$(python3 -c "import statistics; print(statistics.mean($$wv))") if [ "$${#w[@]}" -gt "1" ]; then wstdev=$$(python3 -c "import statistics; print(statistics.stdev($$wv))") fi wmax=$$(python3 -c "print(max($$wv))") fi msg=$$(python3 -c "print($$rn + $$wn)") rc=$$(grep [0-9] $*.log | grep [a-z] | wc -l) # rc lector/escritor rc=$$(( rc + $$(grep -E "^[a-z]+$$" $*.log | grep -cvE "^(.)\1*$$") )) # rc escritor/escritor (( rc = (rc + $(REP) - 1) / $(REP) )) # redondeo hacia arriba fair=$$(bc -lq <<< "l(($$ravg + 10^-10) / ($$wavg + 10^-10))/l(10)") cpu=$$(grep 'task-clock' $*.sta | cut -d';' -f1) ratio=$$(bc -lq <<< "$$msg / $$cpu") printf '%$(P1)s%$(P2)s%$(P2)s%$(P2)s%$(P2)s%$(P2)s%$(P2)s%$(P2)s%$(P2)s%$(P2)s%$(P2)s%$(P2)s%$(P2)s%$(P2)s%$(P2)s%$(P2)s\n' programa rc rn rmin ravg rstdev rmax wn wmin wavg wstdev wmax fair msg cpu ratio > $@ printf '%$(P1)s%$(P2)s%$(P2)s%$(P2)s%$(P2)s%$(P2)s%$(P2)s%$(P2)s%$(P2)s%$(P2)s%$(P2)s%$(P2)s%$(P2)s%$(P2)s%$(P2)s%$(P2)s\n' $* $$rc $$(printf '%.0f' $$rn) $$(printf '%.0f' $$rmin) $$(printf '%.0f' $$ravg) $$(printf '%.1f' $$rstdev) $$(printf '%.0f' $$rmax) $$(printf '%.0f' $$wn) $$(printf '%.0f' $$wmin) $$(printf '%.0f' $$wavg) $$(printf '%.1f' $$wstdev) $$(printf '%.0f' $$wmax) $$(printf '%.2f' $$fair) $$(printf '%.0f' $$msg) $$(printf '%.1f' $$cpu) $$(printf '%.1f' $$ratio) >> $@ n%: common.h @n=$@ case $${n:1} in 0) n=$$(nproc);; *) n=$${n:1};; esac if (( n > 10 )); then n=10 fi sed --follow-symlinks -i "s/std::size_t threads = .*;/std::size_t threads = $$n;/" $< %ms: common.h @sed --follow-symlinks -i "s/std::chrono::milliseconds runtime = .*;/std::chrono::milliseconds runtime = $(@);/" $< -include $(DEP) ############################################################################### .PHONY: all clave clean default exe fast slow sort stat .PRECIOUS: $(STA) $(TXT) $(LOG) ###############################################################################