#!/bin/bash # Find the optimal alpha tuning factors for primecount. # Usage: # ./find_optimal_alpha_dr.sh [--start=n] [--stop=n] [-t=threads] # Description: # This script calculates pi(10^n) for start <= n <= stop using different # alpha tuning factors and prints out the optimal alphas. The optimal # alpha factors will vary slightly for different CPUs. Once a list of # fast alpha factors has been generated you can follow the # instructions in doc/alpha-factor-tuning.pdf and generate a new # alpha tuning function for use in primecount's source code. # Execute in base directory if [[ "$(basename $(pwd))" = "scripts" ]] then cd .. fi command -v ./primecount >/dev/null 2>/dev/null if [[ $? -ne 0 ]] then echo "Error: no primecount binary in current directory." exit 1 fi command -v bc >/dev/null 2>/dev/null if [[ $? -ne 0 ]] then echo "Error: GNU bc is not installed." exit 1 fi start=1 stop=25 instructions=0 repeat=2 threads=$(./primecount 1e18 --Sigma -s | grep threads | cut -d'=' -f2 | cut -d' ' -f2) for i in "$@" do case $i in -t=*) threads="${i#*=}" shift ;; --start=*) start="${i#*=}" shift ;; --stop=*) stop="${i#*=}" shift ;; *) echo "Find the optimal alpha tuning factors for primecount." echo "Usage:" echo " ./find_optimal_alpha_dr.sh [--start=n] [--stop=n] [-t=threads]" echo "Description:" echo " This script calculates pi(10^n) for start <= n <= stop using different" echo " alpha tuning factors and prints out the optimal alphas. The optimal" echo " alpha factors will vary slightly for different CPUs. Once a list of" echo " fast alpha factors has been generated you can follow the" echo " instructions in doc/alpha-factor-tuning.pdf and generate a new" echo " alpha tuning function for use in primecount's source code." exit 1 ;; esac done # Returns 1 if $1 == $2, else 0 function is_equal { echo $1'=='$2 | bc -l } # Returns 1 if $1 < $2, else 0 function is_smaller { echo $1'<'$2 | bc -l } # Returns 1 if $1 <= $2, else 0 function is_smaller_equal { echo $1'<='$2 | bc -l } # Returns 1 if $1 > $2, else 0 function is_greater { echo $1'>'$2 | bc -l } # Floating point calculator # $1: String containing an arithmetic expression function calc { echo "scale=3; $1" | bc -l } # Given 2 numbers, returns the greatest number function maximum { if [[ $(is_greater $1 $2) -eq 1 ]] then echo $1 else echo $2 fi } # Given 2 numbers, returns the greatest number function minimum { if [[ $(is_smaller $1 $2) -eq 1 ]] then echo $1 else echo $2 fi } # $1: primecount args function get_primecount_alpha { alpha=$(./primecount $1 --S2-trivial -s | grep alpha | cut -d'=' -f2 | cut -d' ' -f2) echo $alpha } # $1: primecount args function get_primecount_instructions { instructions=$(perf stat ./primecount $1 -d 2>&1 | grep instructions | sed "s/^[ \t]*//" | cut -f1 -d' ' | sed 's/[^0-9]*//g') echo $instructions } # Calculate pi(10^i) for start <= i <= stop for ((i = start; i <= stop; i++)) do alpha=$(get_primecount_alpha "1e$i") optimal_instructions=10^30 optimal_alpha=$alpha found_optimal=false too_fast=false iter_count=0 div_increment=2 echo "" echo "PrimePi(10^$i)" echo "===============================================================" for div in 2 4 8 16 32 64; do copy_optimal_alpha=$optimal_alpha for ((j = 0; j < repeat; j++)) do # Benchmark runs too quickly for this small input if [[ "$too_fast" = "true" ]] then break fi pivot=$(calc "$copy_optimal_alpha / $div") max_alpha=$(calc "$copy_optimal_alpha + $pivot") new_alpha=$(calc "$copy_optimal_alpha - $pivot") new_alpha=$(maximum 1.000 $new_alpha) increment=$(calc "($max_alpha - $new_alpha) / $div_increment") increment=$(maximum 0.01 $increment) while [[ $(is_smaller_equal $new_alpha $max_alpha) -eq 1 ]] do iter_count=$(($iter_count + 1)) test_case="1e$i --threads=$threads --alpha=$new_alpha" instructions="" if [[ -f "bench.txt" ]] then instructions=$(grep "$test_case" bench.txt 2>/dev/null | head -1 | cut -f2 -d':' | tr -d '[:space:]') fi if [[ -z "$instructions" ]] then instructions=$(get_primecount_instructions "$test_case") fi echo "$test_case, instructions: $instructions" if [[ $iter_count -eq 2 ]] then old_instructions=$instructions fi if [[ $(is_smaller $instructions $optimal_instructions) -eq 1 ]] then found_optimal=true optimal_alpha=$new_alpha optimal_instructions=$instructions fi # Reduce the number of long running primecount benchmarks if [[ $(is_greater $i 15) -eq 1 ]] then repeat=1 fi new_alpha=$(calc "$new_alpha + $increment") done done div_increment=1 done if [[ "$found_optimal" != "true" ]] || \ [[ "$too_fast" = "true" ]] then optimal_alpha="undef" optimal_instructions="undef" old_instructions="undef" fi echo "Result: optimal_alpha=$optimal_alpha, instructions=$optimal_instructions, old_alpha=$alpha, old_instructions=$old_instructions" done