Tiny Core Extensions > TCE Tips & Tricks
search tcz/src source for build scripts (rsync)
mocore:
hi rich
;) not exactly , but i guess now we are both in the same boat so to speak
hopefully any one interested in running it can make any modifications after they copy or past it
reminds me of https://en.wikipedia.org/wiki/Worse_is_better
but also ( as i have read a few scripts u posted hear )
make me wander if you have some policy/reason to avoid or just aversion to functions ;)
Rich:
Hi mocore
Or maybe I misunderstood how you wanted it changed.
If you PM me how you want it to look, I'll adjust the post
accordingly.
mocore:
--- Code: ---find_src() {
search_string=${1-w3m} # eg
def_arch=${2-x86} # x86_64 or x86
def_path="${tc_path-/*.x/x86/tcz/src/}"
rsync -R --list-only repo.tinycorelinux.net::tc"${def_path}" | grep "$search_string"
# tce-load -iwl rsync
}
--- End code ---
Rich:
Hi mocore
--- Quote from: mocore on September 23, 2024, 09:39:41 AM --- ... but also ( as i have read a few scripts u posted hear )
make me wander if you have some policy/reason to avoid or just aversion to functions ;)
--- End quote ---
I do not avoid or have an aversion to functions. I do try to be aware
of the impact they may have.
1. Functions are good. They provide consistency and can make code easier to follow.
2. Functions are bad. Making functions out of every little bit of code repetition can
leave you lost trying to follow a maze of functions.
3. Functions hurt speed. If your function returns a value to your variable, the impact
can become significant if it looks like this: Var=$(MyFunction).
I'd like to address item 3.
--- Code: ---#!/bin/sh
#: Calculate elapsed time.
#: Millisecond resolution If GNU date is present, otherwise seconds only.
GetET1(){ ET1=$(date +%s.%3N); ET1=${ET1%.%3N}; }
GetET2(){ ET2=$(date +%s.%3N); ET2=${ET2%.%3N}; }
CalcET(){ calc $ET2-$ET1; }
# --------------------------------------------------------------- #
# Checks that all chars are digits, and that digits are present.
IsInteger()
{
# Empty string is not an integer.
# If we delete all of the digits, that should leave an empty string.
[ -z $1 ] || [ -n "${1//[0-9]/}" ] && echo "" && return
# Valid integer.
echo "$1"
return
}
# --------------------------------------------------------------- #
# --------------------------------------------------------------- #
# Checks that all chars are digits, and that digits are present.
IsIntegerByRef()
{
# $1=Name of variable to place the result in.
# $2=Number to validate.
local __IntVar=$1
local __Int2Test=$2
# Empty string is not an integer.
# If we delete all of the digits, that should leave an empty string.
[ -z $2 ] || [ -n "${2//[0-9]/}" ] && __Int2Test=""
eval $__IntVar="'$__Int2Test'"
}
# --------------------------------------------------------------- #
#: --------------------------------------------------------------- #
#: Fixed point division. Input positive integers only, no zeros allowed.
#: Usage: Divide $Dividend $Divisor
Divide()
{
# Vars will either be an integer or empty from IsInteger.
local Dividend=$(IsInteger $1)
local Divisor=$(IsInteger $2)
# local Dividend=$1
# local Divisor=$2
# Number of decimal places desired.
# We increases decimal places by 1 to allow rounding.
local DPcount=$(($DPdefault + 1))
local Quotient
# Leading zero causes Decimal to be treated as octal. We deal
# with this by padding with a leadin one. Doubles as carry
# flag when rounding by incrementing to two.
local Decimal=1
local Zeros=".00000000"
# 2 integers are required.
[ -z $Dividend ] && echo "" && return
[ -z $Divisor ] && echo "" && return
# Dividing by zero not allowed.
[ $Divisor -eq 0 ] && echo "" && return
# Dividing into zero equals zero plus default decimal places..
if [ $Dividend -eq 0 ]
then
[ $DPcount -gt 0 ] && Decimal="${Zeros:0:$DPcount}"
printf "0%s\n" $Decimal
return
fi
# First calculate the integer portion.
Quotient=$(($Dividend / $Divisor))
# Calculate the remainder to the requested number of decimal places.
while [ $DPcount -gt 0 ]
do
Dividend=$((($Dividend % $Divisor) * 10))
Decimal="$Decimal$(($Dividend / $Divisor))"
DPcount=$(($DPcount - 1))
done
# Perform rounding.
Decimal=$(($Decimal + 5))
# Remove the extra decimal place we added by removing the last digit.
Decimal=${Decimal%[0-9]}
# If the leading digit equals 2, rounding caused a carry.
[ ${Decimal:0:1} -eq 2 ] && Quotient=$(($Quotient + 1))
# Remove the carry digit (MSD) from the decimal portion.
Decimal=${Decimal:1}
printf "%s.%s\n" $Quotient $Decimal
}
# --------------------------------------------------------------- #
#: --------------------------------------------------------------- #
#: Fixed point division. Input positive integers only, no zeros allowed.
#: Usage: Divide $Dividend $Divisor
DivideNoFunc()
{
# Vars will either be an integer or empty from IsInteger.
# local Dividend=$(IsInteger $1)
# local Divisor=$(IsInteger $2)
local Dividend
local Divisor
[ -z $1 ] || [ -n "${1//[0-9]/}" ] && Dividend="" || Dividend="$1"
[ -z $2 ] || [ -n "${2//[0-9]/}" ] && Divisor="" || Divisor="$2"
# Number of decimal places desired.
# We increases decimal places by 1 to allow rounding.
local DPcount=$(($DPdefault + 1))
local Quotient
# Leading zero causes Decimal to be treated as octal. We deal
# with this by padding with a leadin one. Doubles as carry
# flag when rounding by incrementing to two.
local Decimal=1
local Zeros=".00000000"
# 2 integers are required.
[ -z $Dividend ] && echo "" && return
[ -z $Divisor ] && echo "" && return
# Dividing by zero not allowed.
[ $Divisor -eq 0 ] && echo "" && return
# Dividing into zero equals zero plus default decimal places..
if [ $Dividend -eq 0 ]
then
[ $DPcount -gt 0 ] && Decimal="${Zeros:0:$DPcount}"
printf "0%s\n" $Decimal
return
fi
# First calculate the integer portion.
Quotient=$(($Dividend / $Divisor))
# Calculate the remainder to the requested number of decimal places.
while [ $DPcount -gt 0 ]
do
Dividend=$((($Dividend % $Divisor) * 10))
Decimal="$Decimal$(($Dividend / $Divisor))"
DPcount=$(($DPcount - 1))
done
# Perform rounding.
Decimal=$(($Decimal + 5))
# Remove the extra decimal place we added by removing the last digit.
Decimal=${Decimal%[0-9]}
# If the leading digit equals 2, rounding caused a carry.
[ ${Decimal:0:1} -eq 2 ] && Quotient=$(($Quotient + 1))
# Remove the carry digit (MSD) from the decimal portion.
Decimal=${Decimal:1}
printf "%s.%s\n" $Quotient $Decimal
}
# --------------------------------------------------------------- #
#: --------------------------------------------------------------- #
#: Fixed point division. Input positive integers only, no zeros allowed.
#: Usage: Divide $Dividend $Divisor
DivideByRef()
{
# Vars will either be an integer or empty from IsInteger.
# local Dividend=$(IsInteger $1)
# local Divisor=$(IsInteger $2)
local Dividend
local Divisor
IsIntegerByRef "Dividend" "$1"
IsIntegerByRef "Divisor" "$2"
# Number of decimal places desired.
# We increases decimal places by 1 to allow rounding.
local DPcount=$(($DPdefault + 1))
local Quotient
# Leading zero causes Decimal to be treated as octal. We deal
# with this by padding with a leadin one. Doubles as carry
# flag when rounding by incrementing to two.
local Decimal=1
local Zeros=".00000000"
# 2 integers are required.
[ -z $Dividend ] && echo "" && return
[ -z $Divisor ] && echo "" && return
# Dividing by zero not allowed.
[ $Divisor -eq 0 ] && echo "" && return
# Dividing into zero equals zero plus default decimal places..
if [ $Dividend -eq 0 ]
then
[ $DPcount -gt 0 ] && Decimal="${Zeros:0:$DPcount}"
printf "0%s\n" $Decimal
return
fi
# First calculate the integer portion.
Quotient=$(($Dividend / $Divisor))
# Calculate the remainder to the requested number of decimal places.
while [ $DPcount -gt 0 ]
do
Dividend=$((($Dividend % $Divisor) * 10))
Decimal="$Decimal$(($Dividend / $Divisor))"
DPcount=$(($DPcount - 1))
done
# Perform rounding.
Decimal=$(($Decimal + 5))
# Remove the extra decimal place we added by removing the last digit.
Decimal=${Decimal%[0-9]}
# If the leading digit equals 2, rounding caused a carry.
[ ${Decimal:0:1} -eq 2 ] && Quotient=$(($Quotient + 1))
# Remove the carry digit (MSD) from the decimal portion.
Decimal=${Decimal:1}
printf "%s.%s\n" $Quotient $Decimal
}
# --------------------------------------------------------------- #
# Calculations are performed to DPdefault + 1 decimal places, and
# rounded to DPdefault decimal places.
DPdefault=8
echo
echo "Function (requires subshell) Divide 21053358 6701492 equals $(Divide 21053358 6701492)"
GetET1; for C in `seq 1 10000`; do Divide 21053358 6701492 > /dev/null; done; GetET2; echo "Elapsed time for 10,000 runs=$(CalcET) Secs."
echo
echo "No function (inline code) DivideNoFunc 21053358 6701492 equals $(DivideNoFunc 21053358 6701492)"
GetET1; for C in `seq 1 10000`; do DivideNoFunc 21053358 6701492 > /dev/null; done; GetET2; echo "Elapsed time for 10,000 runs=$(CalcET) Secs."
echo
echo "Function (indirect variable reference) DivideByRef 21053358 6701492 equals $(DivideByRef 21053358 6701492)"
GetET1; for C in `seq 1 10000`; do DivideByRef 21053358 6701492 > /dev/null; done; GetET2; echo "Elapsed time for 10,000 runs=$(CalcET) Secs."
echo
--- End code ---
The above contains 3 fixed point division functions.
They all use the same code to confirm they received valid integers.
The only difference is how data is exchanged with the validation code.
Divide() calls a function like this to update the variable:
--- Code: ---Dividend=$(IsInteger $1)
--- End code ---
DivideNoFunc() uses inline code like this to update the variable:
--- Code: ---[ -z $1 ] || [ -n "${1//[0-9]/}" ] && Dividend="" || Dividend="$1"
--- End code ---
DivideByRef() passes the name of the variable and the value to validate to a function:
--- Code: ---IsIntegerByRef "Dividend" "$1"
--- End code ---
The timing is for each version calculating pi to 9 decimal places and
rounding to 8 decimal places 10,000 times:
--- Code: ---tc@E310:~/Scripting/AddressParser$ ./Functions
Function (requires sub-shell) Divide 21053358 6701492 equals 3.14159265
Elapsed time for 10,000 runs=17.052 Secs.
No function (inline code) DivideNoFunc 21053358 6701492 equals 3.14159265
Elapsed time for 10,000 runs=4.866 Secs.
Function (indirect variable reference) DivideByRef 21053358 6701492 equals 3.14159265
Elapsed time for 10,000 runs=5.424 Secs.
--- End code ---
I suspect the function call in the first example starts a sub-shell which results
in a big timing hit.
The second version with inline code is fastest as expected.
The third version only has a 12% timing penalty.
A copy of the script is also attached.
mocore:
hi & thanks for the scripts !
i ask because a vaguely remember reading/hearing it mentioned something along the lines of
'functions are expensive' (afaik/r more historically older hardware made performance cost more apparent )
--- Quote from: Rich on January 01, 2025, 03:28:51 PM ---2. Functions are bad. Making functions out of every little bit of code repetition can
leave you lost trying to follow a maze of functions.
--- End quote ---
its interesting that "debug-ability" of function use is considered down side
... imho if all the functions where in a pipeline and did not alter any shared environment
it would be easy(er) to reason about them ( and there input / output)
wrt "debug-ability" the (apparent) lack of "good" books on writing debuggers
was mentioned in "Not on the shelves: what nonexistent books, tools, and courses can tell us about ourselves "
... if you happen to know any ?
wrt
--- Quote --- lost trying to follow a maze of functions
--- End quote ---
i found my self lost trying to follow a maze of functions the other day
my solution was to write another function (like the captain in peter pan??)
which was called at the start & end of the other function's
that stored
function name
count of function calls (start++ , end--)
and a few other (seaming relevant info)
enough to (hopefully!) track what calls what and how deep the callers are nested
and added this info to print to stderr/log
which appears to (more or less) work
causing function's to leave a trail of crumbs to stdout !
... less lost , but also now debugging *another* function :o
Navigation
[0] Message Index
[#] Next page
[*] Previous page
Go to full version