- Replace fn()=> with traditional function() syntax in php_medium and php_large - 8 arrow function occurrences fixed across processWords/statsArr/caesar/lookupOps/nested array_map - Added diag_bugs.sh: diagnostic script for PHP pool exhaustion + ruby/medium cold anomaly - bench_full.sh RUNID=9250986: PASS=20 FAIL=0 (was PASS=18 FAIL=2) - ruby/medium cold=81549ms anomaly confirmed reproducible (3rd time), not a FAIL - Added doc/report-2026-05-20-bench-php-analysis.md
1033 lines
43 KiB
Bash
1033 lines
43 KiB
Bash
#!/usr/bin/env bash
|
||
# bench_full.sh — полный бенчмарк: все языки × все размеры + архивы
|
||
# Языки: Python, Node.js, Ruby, PHP
|
||
# Размеры: tiny, small, medium, large, archive (ZIP + доп. файл)
|
||
# Метрики: upload_ms, cold_ms, hot_avg_ms (3 invoke)
|
||
#
|
||
# Запуск: bash bench-func/bench_full.sh
|
||
# На VM: bash ~/terra/fission/bench-func/bench_full.sh
|
||
|
||
set -uo pipefail
|
||
|
||
SCRIPT_DIR=$(cd "$(dirname "$0")" && pwd)
|
||
ROOT_DIR=$(cd "${SCRIPT_DIR}/.." && pwd)
|
||
source "${ROOT_DIR}/scripts/lib.sh"
|
||
|
||
TIMESTAMP=$(date +%Y-%m-%d_%H-%M-%S)
|
||
RESULTS_DIR="${ROOT_DIR}/test-results/bench-func"
|
||
LOGFILE="${RESULTS_DIR}/bench_full_${TIMESTAMP}.log"
|
||
mkdir -p "$RESULTS_DIR"
|
||
|
||
SUB="bench@bench.local"
|
||
RUNID=$(date +%s | tail -c 8)
|
||
TMP=$(mktemp -d)
|
||
|
||
echo "" | tee -a "$LOGFILE"
|
||
echo "════════════════════════════════════════════════════════════════" | tee -a "$LOGFILE"
|
||
echo " bench_full.sh run=${RUNID} $(date)" | tee -a "$LOGFILE"
|
||
echo " API: ${BASE}" | tee -a "$LOGFILE"
|
||
echo " SUB: ${SUB}" | tee -a "$LOGFILE"
|
||
echo "════════════════════════════════════════════════════════════════" | tee -a "$LOGFILE"
|
||
|
||
declare -a ALL_FNS=()
|
||
declare -a SUMMARY_ROWS=()
|
||
PASS_CNT=0
|
||
FAIL_CNT=0
|
||
|
||
# ── Cleanup ───────────────────────────────────────────────────────────────
|
||
cleanup() {
|
||
rm -rf "$TMP" 2>/dev/null || true
|
||
for fn in "${ALL_FNS[@]:-}"; do
|
||
curl -s -X DELETE "${BASE}/functions/${fn}" \
|
||
-H "X-Auth-Token: ${SUB}" >/dev/null 2>&1 || true
|
||
done
|
||
}
|
||
trap cleanup EXIT
|
||
|
||
# ── Helpers ───────────────────────────────────────────────────────────────
|
||
log() { echo "$@" | tee -a "$LOGFILE"; }
|
||
|
||
escape_code() {
|
||
python3 -c 'import json, sys; print(json.dumps(sys.stdin.read()))'
|
||
}
|
||
|
||
get_status() {
|
||
python3 -c "import json,sys
|
||
try:
|
||
d=json.load(sys.stdin)
|
||
print(d.get('status',''))
|
||
except:
|
||
print('')" 2>/dev/null
|
||
}
|
||
|
||
get_field() {
|
||
local field="$1"
|
||
python3 -c "import json,sys
|
||
try:
|
||
d=json.load(sys.stdin)
|
||
print(d.get('$field',''))
|
||
except:
|
||
print('')" 2>/dev/null
|
||
}
|
||
|
||
# bench_code LANG SIZE FN CODEFILE EXPECTED_TAG
|
||
bench_code() {
|
||
local lang="$1" size="$2" fn="$3" codefile="$4" expected="${5:-}"
|
||
ALL_FNS+=("$fn")
|
||
|
||
local code_esc
|
||
code_esc=$(cat "$codefile" | escape_code)
|
||
|
||
# Upload
|
||
local t0 t1 R CODE BODY
|
||
t0=$(date +%s%3N)
|
||
R=$(curl -s -w "\n%{http_code}" -X POST "${BASE}/functions" \
|
||
-H "X-Auth-Token: ${SUB}" -H "Content-Type: application/json" \
|
||
-d "{\"name\":\"${fn}\",\"language\":\"${lang}\",\"code\":${code_esc}}" 2>/dev/null)
|
||
t1=$(date +%s%3N)
|
||
CODE=$(echo "$R" | tail -1)
|
||
BODY=$(echo "$R" | head -n -1)
|
||
local UPLOAD_MS=$((t1 - t0))
|
||
|
||
if [ "$CODE" != "201" ]; then
|
||
log " FAIL [${lang}/${size}] upload HTTP=$CODE | $(printf '%s' "$BODY" | head -c 150)"
|
||
SUMMARY_ROWS+=("$(printf '%-8s %-8s %8s %10s %10s %s' "$lang" "$size" "-" "-" "-" "UPLOAD-FAIL-${CODE}")")
|
||
FAIL_CNT=$((FAIL_CNT+1))
|
||
return 1
|
||
fi
|
||
|
||
# Cold start (retry 20×5s = 100s max)
|
||
local tc0 COLD_MS=0 cold_ok=0
|
||
tc0=$(date +%s%3N)
|
||
for i in $(seq 1 20); do
|
||
local resp s raw
|
||
resp=$(curl -s --max-time 35 -X POST "${BASE}/functions/${fn}/invoke" \
|
||
-H "X-Auth-Token: ${SUB}" -H "Content-Type: application/json" -d '{}' 2>/dev/null)
|
||
s=$(echo "$resp" | get_status)
|
||
raw=$(echo "$resp" | get_field "response_raw")
|
||
if [ "$s" = "200" ]; then
|
||
if [ -z "$expected" ] || echo "$raw" | grep -qF "$expected"; then
|
||
local tc1
|
||
tc1=$(date +%s%3N)
|
||
COLD_MS=$((tc1 - tc0))
|
||
cold_ok=1
|
||
break
|
||
fi
|
||
fi
|
||
sleep 5
|
||
done
|
||
|
||
if [ $cold_ok -eq 0 ]; then
|
||
log " FAIL [${lang}/${size}] cold start timeout"
|
||
SUMMARY_ROWS+=("$(printf '%-8s %-8s %8s %10s %10s %s' "$lang" "$size" "$UPLOAD_MS" "-" "-" "COLD-TIMEOUT")")
|
||
FAIL_CNT=$((FAIL_CNT+1))
|
||
return 1
|
||
fi
|
||
|
||
# Hot start ×3
|
||
local HOT_TOTAL=0 hot_ok=0
|
||
for i in 1 2 3; do
|
||
local th0 th1 resp s
|
||
th0=$(date +%s%3N)
|
||
resp=$(curl -s --max-time 35 -X POST "${BASE}/functions/${fn}/invoke" \
|
||
-H "X-Auth-Token: ${SUB}" -H "Content-Type: application/json" -d '{}' 2>/dev/null)
|
||
th1=$(date +%s%3N)
|
||
s=$(echo "$resp" | get_status)
|
||
if [ "$s" = "200" ]; then
|
||
HOT_TOTAL=$((HOT_TOTAL + th1 - th0))
|
||
hot_ok=$((hot_ok+1))
|
||
fi
|
||
done
|
||
|
||
local HOT_AVG_MS=0
|
||
[ $hot_ok -gt 0 ] && HOT_AVG_MS=$((HOT_TOTAL / hot_ok))
|
||
|
||
log " OK [${lang}/${size}] upload=${UPLOAD_MS}ms cold=${COLD_MS}ms hot_avg=${HOT_AVG_MS}ms (${hot_ok}/3)"
|
||
SUMMARY_ROWS+=("$(printf '%-8s %-8s %8s %10s %10s %s' "$lang" "$size" "${UPLOAD_MS}" "${COLD_MS}" "${HOT_AVG_MS}" "OK(hot=${hot_ok}/3)")")
|
||
PASS_CNT=$((PASS_CNT+1))
|
||
}
|
||
|
||
# bench_archive LANG_SHORT LANG FN ZIP EXPECTED_TAG
|
||
bench_archive() {
|
||
local lang_short="$1" lang="$2" fn="$3" zipfile="$4" expected="$5"
|
||
ALL_FNS+=("$fn")
|
||
|
||
local t0 t1 R CODE BODY
|
||
t0=$(date +%s%3N)
|
||
R=$(curl -s -w "\n%{http_code}" -X POST "${BASE}/functions" \
|
||
-H "X-Auth-Token: ${SUB}" \
|
||
-F "name=${fn}" \
|
||
-F "language=${lang}" \
|
||
-F "archive=@${zipfile};type=application/zip" 2>/dev/null)
|
||
t1=$(date +%s%3N)
|
||
CODE=$(echo "$R" | tail -1)
|
||
BODY=$(echo "$R" | head -n -1)
|
||
local UPLOAD_MS=$((t1 - t0))
|
||
|
||
if [ "$CODE" != "201" ]; then
|
||
log " FAIL [${lang}/archive] upload HTTP=$CODE | $(printf '%s' "$BODY" | head -c 150)"
|
||
SUMMARY_ROWS+=("$(printf '%-8s %-8s %8s %10s %10s %s' "$lang" "archive" "-" "-" "-" "UPLOAD-FAIL-${CODE}")")
|
||
FAIL_CNT=$((FAIL_CNT+1))
|
||
return 1
|
||
fi
|
||
|
||
# Cold start (retry 24×5s = 120s — архивам нужна сборка)
|
||
local tc0 COLD_MS=0 cold_ok=0
|
||
tc0=$(date +%s%3N)
|
||
for i in $(seq 1 24); do
|
||
local resp s raw
|
||
resp=$(curl -s --max-time 35 -X POST "${BASE}/functions/${fn}/invoke" \
|
||
-H "X-Auth-Token: ${SUB}" -H "Content-Type: application/json" -d '{}' 2>/dev/null)
|
||
s=$(echo "$resp" | get_status)
|
||
raw=$(echo "$resp" | get_field "response_raw")
|
||
if [ "$s" = "200" ] && echo "$raw" | grep -qF "$expected"; then
|
||
local tc1
|
||
tc1=$(date +%s%3N)
|
||
COLD_MS=$((tc1 - tc0))
|
||
cold_ok=1
|
||
break
|
||
fi
|
||
sleep 5
|
||
done
|
||
|
||
if [ $cold_ok -eq 0 ]; then
|
||
log " FAIL [${lang}/archive] cold start timeout"
|
||
SUMMARY_ROWS+=("$(printf '%-8s %-8s %8s %10s %10s %s' "$lang" "archive" "$UPLOAD_MS" "-" "-" "COLD-TIMEOUT")")
|
||
FAIL_CNT=$((FAIL_CNT+1))
|
||
return 1
|
||
fi
|
||
|
||
# Hot ×3
|
||
local HOT_TOTAL=0 hot_ok=0
|
||
for i in 1 2 3; do
|
||
local th0 th1 resp s
|
||
th0=$(date +%s%3N)
|
||
resp=$(curl -s --max-time 35 -X POST "${BASE}/functions/${fn}/invoke" \
|
||
-H "X-Auth-Token: ${SUB}" -H "Content-Type: application/json" -d '{}' 2>/dev/null)
|
||
th1=$(date +%s%3N)
|
||
s=$(echo "$resp" | get_status)
|
||
[ "$s" = "200" ] && { HOT_TOTAL=$((HOT_TOTAL + th1 - th0)); hot_ok=$((hot_ok+1)); }
|
||
done
|
||
|
||
local HOT_AVG_MS=0
|
||
[ $hot_ok -gt 0 ] && HOT_AVG_MS=$((HOT_TOTAL / hot_ok))
|
||
|
||
log " OK [${lang}/archive] upload=${UPLOAD_MS}ms cold=${COLD_MS}ms hot_avg=${HOT_AVG_MS}ms (${hot_ok}/3)"
|
||
SUMMARY_ROWS+=("$(printf '%-8s %-8s %8s %10s %10s %s' "$lang" "archive" "${UPLOAD_MS}" "${COLD_MS}" "${HOT_AVG_MS}" "OK(hot=${hot_ok}/3)")")
|
||
PASS_CNT=$((PASS_CNT+1))
|
||
}
|
||
|
||
# ═══════════════════════════════════════════════════════════════════════════
|
||
# ГЕНЕРАЦИЯ КОДА ФУНКЦИЙ
|
||
# ═══════════════════════════════════════════════════════════════════════════
|
||
|
||
# ── PYTHON ────────────────────────────────────────────────────────────────
|
||
cat > "${TMP}/py_tiny.py" << 'PYEOF'
|
||
def main(event, context):
|
||
return {"statusCode": 200, "body": "bench-py-tiny-ok"}
|
||
PYEOF
|
||
|
||
cat > "${TMP}/py_small.py" << 'PYEOF'
|
||
import math, time
|
||
|
||
def fib(n):
|
||
a, b = 0, 1
|
||
for _ in range(n): a, b = b, a + b
|
||
return a
|
||
|
||
def sieve(n):
|
||
s = [True] * (n + 1); s[0] = s[1] = False
|
||
for i in range(2, int(math.sqrt(n)) + 1):
|
||
if s[i]:
|
||
for j in range(i*i, n+1, i): s[j] = False
|
||
return [i for i in range(n+1) if s[i]]
|
||
|
||
def sqrt_sum(n):
|
||
return sum(math.sqrt(i) for i in range(1, n + 1))
|
||
|
||
def main(event, context):
|
||
t0 = time.time()
|
||
f = fib(30)
|
||
primes = sieve(200)
|
||
s = sqrt_sum(500)
|
||
elapsed = time.time() - t0
|
||
return {
|
||
"statusCode": 200,
|
||
"body": f"bench-py-small-ok:fib30={f}:primes={len(primes)}:sqrt={s:.1f}:t={elapsed:.4f}s"
|
||
}
|
||
PYEOF
|
||
|
||
cat > "${TMP}/py_medium.py" << 'PYEOF'
|
||
import math, time, json, hashlib
|
||
|
||
LOOKUP = {i: i*i for i in range(100)}
|
||
WORDS = ["alpha","beta","gamma","delta","epsilon","zeta","eta","theta",
|
||
"iota","kappa","lambda","mu","nu","xi","omicron","pi",
|
||
"rho","sigma","tau","upsilon","phi","chi","psi","omega"]
|
||
|
||
def fib(n):
|
||
a, b = 0, 1
|
||
for _ in range(n): a, b = b, a + b
|
||
return a
|
||
|
||
def sieve(n):
|
||
s = [True] * (n + 1); s[0] = s[1] = False
|
||
for i in range(2, int(math.sqrt(n)) + 1):
|
||
if s[i]:
|
||
for j in range(i*i, n+1, i): s[j] = False
|
||
return [i for i in range(n+1) if s[i]]
|
||
|
||
def sqrt_sum(n):
|
||
return sum(math.sqrt(i) for i in range(1, n + 1))
|
||
|
||
def bubble_sort(arr):
|
||
arr = arr[:]
|
||
n = len(arr)
|
||
for i in range(n):
|
||
for j in range(0, n-i-1):
|
||
if arr[j] > arr[j+1]: arr[j], arr[j+1] = arr[j+1], arr[j]
|
||
return arr
|
||
|
||
def mat_mul(a, b):
|
||
ra, ca, cb = len(a), len(a[0]), len(b[0])
|
||
c = [[0]*cb for _ in range(ra)]
|
||
for i in range(ra):
|
||
for j in range(cb):
|
||
for k in range(ca): c[i][j] += a[i][k] * b[k][j]
|
||
return c
|
||
|
||
def process_words(words):
|
||
return [w.upper()[::-1] for w in words if len(w) > 3]
|
||
|
||
def get_stats(lst):
|
||
n = len(lst); m = sum(lst) / n
|
||
v = sum((x - m)**2 for x in lst) / n
|
||
return {"n": n, "mean": round(m, 4), "std": round(math.sqrt(v), 4)}
|
||
|
||
def main(event, context):
|
||
t0 = time.time()
|
||
f = fib(35)
|
||
primes = sieve(500)
|
||
s = sqrt_sum(1000)
|
||
nums = list(range(50, 0, -1))
|
||
sorted_nums = bubble_sort(nums)
|
||
a = [[1,2,3],[4,5,6]]; b = [[7,8],[9,10],[11,12]]
|
||
c = mat_mul(a, b)
|
||
pw = process_words(WORDS)
|
||
st = get_stats(primes)
|
||
h = hashlib.sha256(b"bench-medium-python").hexdigest()[:16]
|
||
elapsed = time.time() - t0
|
||
return {"statusCode": 200, "body": json.dumps({
|
||
"tag": "bench-py-medium-ok", "fib35": f, "primes": len(primes),
|
||
"sqrt": round(s, 1), "sorted0": sorted_nums[0], "mat_c00": c[0][0],
|
||
"words": len(pw), "stats": st, "hash": h, "elapsed": round(elapsed, 5)
|
||
})}
|
||
PYEOF
|
||
|
||
cat > "${TMP}/py_large.py" << 'PYEOF'
|
||
import math, time, json, hashlib, re, base64
|
||
|
||
ALPHABET = "abcdefghijklmnopqrstuvwxyz"
|
||
LOOKUP_SQ = {i: i*i for i in range(200)}
|
||
LOOKUP_CUBE = {i: i**3 for i in range(200)}
|
||
WORDS = ["alpha","beta","gamma","delta","epsilon","zeta","eta","theta",
|
||
"iota","kappa","lambda","mu","nu","xi","omicron","pi",
|
||
"rho","sigma","tau","upsilon","phi","chi","psi","omega",
|
||
"one","two","three","four","five","six","seven","eight",
|
||
"nine","ten","eleven","twelve","thirteen","fourteen","fifteen"]
|
||
CONSTANTS = {"pi": math.pi, "e": math.e, "phi": (1+math.sqrt(5))/2,
|
||
"sqrt2": math.sqrt(2), "ln2": math.log(2)}
|
||
|
||
def fib(n):
|
||
a, b = 0, 1
|
||
for _ in range(n): a, b = b, a + b
|
||
return a
|
||
|
||
def fib_list(n):
|
||
r = []; a, b = 0, 1
|
||
for _ in range(n): r.append(a); a, b = b, a + b
|
||
return r
|
||
|
||
def sieve(n):
|
||
s = [True] * (n + 1); s[0] = s[1] = False
|
||
for i in range(2, int(math.sqrt(n)) + 1):
|
||
if s[i]:
|
||
for j in range(i*i, n+1, i): s[j] = False
|
||
return [i for i in range(n+1) if s[i]]
|
||
|
||
def sqrt_sum(n): return sum(math.sqrt(i) for i in range(1, n + 1))
|
||
def log_sum(n): return sum(math.log(i) for i in range(1, n + 1))
|
||
def trig_sum(n): return sum(math.sin(i) * math.cos(i) for i in range(n))
|
||
|
||
def bubble_sort(arr):
|
||
arr = arr[:]
|
||
n = len(arr)
|
||
for i in range(n):
|
||
for j in range(0, n-i-1):
|
||
if arr[j] > arr[j+1]: arr[j], arr[j+1] = arr[j+1], arr[j]
|
||
return arr
|
||
|
||
def insertion_sort(arr):
|
||
arr = arr[:]
|
||
for i in range(1, len(arr)):
|
||
key = arr[i]; j = i - 1
|
||
while j >= 0 and arr[j] > key: arr[j+1] = arr[j]; j -= 1
|
||
arr[j+1] = key
|
||
return arr
|
||
|
||
def mat_mul(a, b):
|
||
ra, ca, cb = len(a), len(a[0]), len(b[0])
|
||
c = [[0]*cb for _ in range(ra)]
|
||
for i in range(ra):
|
||
for j in range(cb):
|
||
for k in range(ca): c[i][j] += a[i][k] * b[k][j]
|
||
return c
|
||
|
||
def transpose(m):
|
||
return [[m[j][i] for j in range(len(m))] for i in range(len(m[0]))]
|
||
|
||
def process_words(words):
|
||
return [{"original": w, "upper": w.upper(), "reversed": w[::-1],
|
||
"len": len(w), "vowels": sum(1 for c in w if c in "aeiou")}
|
||
for w in words if len(w) >= 3]
|
||
|
||
def get_stats(lst):
|
||
n = len(lst); m = sum(lst) / n
|
||
v = sum((x - m)**2 for x in lst) / n
|
||
s = sorted(lst)
|
||
median = s[n//2] if n % 2 else (s[n//2-1] + s[n//2]) / 2
|
||
return {"n": n, "min": min(lst), "max": max(lst),
|
||
"mean": round(m, 4), "median": median, "std": round(math.sqrt(v), 4)}
|
||
|
||
def caesar(text, shift):
|
||
r = []
|
||
for c in text:
|
||
if c.isalpha():
|
||
base = ord('a') if c.islower() else ord('A')
|
||
r.append(chr((ord(c) - base + shift) % 26 + base))
|
||
else: r.append(c)
|
||
return ''.join(r)
|
||
|
||
def run_regex(text):
|
||
return {p: len(re.findall(p, text)) for p in [r'\d+', r'[a-z]+', r'[A-Z]+']}
|
||
|
||
def lookup_ops(n):
|
||
return sum(LOOKUP_SQ.get(i % 200, 0) + LOOKUP_CUBE.get(i % 200, 0) for i in range(n))
|
||
|
||
def main(event, context):
|
||
t0 = time.time()
|
||
sq = sqrt_sum(2000); lg = log_sum(1000); tr = trig_sum(500)
|
||
primes = sieve(1000); f40 = fib(40); fibs = fib_list(20)
|
||
nums = list(range(100, 0, -1))
|
||
bs = bubble_sort(nums[:50]); ins = insertion_sort(nums[50:])
|
||
h256 = hashlib.sha256(b"bench-large-python-2026").hexdigest()
|
||
md5 = hashlib.md5(b"bench-large-python-2026").hexdigest()
|
||
b64 = base64.b64encode(b"hello from bench-py-large").decode()
|
||
ma = [[i+j for j in range(4)] for i in range(4)]
|
||
mb = [[i*j+1 for j in range(4)] for i in range(4)]
|
||
mc = mat_mul(ma, mb); mt = transpose(mc)
|
||
pw = process_words(WORDS); pst = get_stats(primes[:50])
|
||
cipher = caesar("hello bench world", 13)
|
||
rx = run_regex("Hello World 42 bench-py-large TEST 2026")
|
||
lookup = lookup_ops(500)
|
||
elapsed = time.time() - t0
|
||
return {"statusCode": 200, "body": json.dumps({
|
||
"tag": "bench-py-large-ok",
|
||
"sqrt": round(sq, 2), "log": round(lg, 2), "trig": round(tr, 4),
|
||
"primes": len(primes), "fib40": f40, "fibs_sum": sum(fibs),
|
||
"h256": h256[:16], "md5": md5[:16], "b64_len": len(b64),
|
||
"mat_trace": sum(mc[i][i] for i in range(len(mc))),
|
||
"words": len(pw), "stats": pst, "cipher": cipher,
|
||
"regex": rx, "lookup": lookup, "elapsed": round(elapsed, 5)
|
||
})}
|
||
PYEOF
|
||
|
||
# ── NODE.JS ───────────────────────────────────────────────────────────────
|
||
cat > "${TMP}/node_tiny.js" << 'JSEOF'
|
||
module.exports = async function(ctx) {
|
||
return { status: 200, body: "bench-node-tiny-ok" };
|
||
};
|
||
JSEOF
|
||
|
||
cat > "${TMP}/node_small.js" << 'JSEOF'
|
||
function fib(n) { let a=0,b=1; for(let i=0;i<n;i++) [a,b]=[b,a+b]; return a; }
|
||
function sieve(n) {
|
||
const s=new Array(n+1).fill(true); s[0]=s[1]=false;
|
||
for(let i=2;i*i<=n;i++) if(s[i]) for(let j=i*i;j<=n;j+=i) s[j]=false;
|
||
return s.reduce((a,v,i)=>{if(v)a.push(i);return a;},[]);
|
||
}
|
||
function sqrtSum(n) { let s=0; for(let i=1;i<=n;i++) s+=Math.sqrt(i); return s; }
|
||
|
||
module.exports = async function(ctx) {
|
||
const t0=Date.now();
|
||
const f=fib(30), primes=sieve(200), s=sqrtSum(500);
|
||
const elapsed=Date.now()-t0;
|
||
return {
|
||
status: 200,
|
||
body: `bench-node-small-ok:fib30=${f}:primes=${primes.length}:sqrt=${s.toFixed(1)}:t=${elapsed}ms`
|
||
};
|
||
};
|
||
JSEOF
|
||
|
||
cat > "${TMP}/node_medium.js" << 'JSEOF'
|
||
const crypto = require('crypto');
|
||
const WORDS = ["alpha","beta","gamma","delta","epsilon","zeta","eta","theta",
|
||
"iota","kappa","lambda","mu","nu","xi","omicron","pi",
|
||
"rho","sigma","tau","upsilon","phi","chi","psi","omega"];
|
||
|
||
function fib(n) { let a=0,b=1; for(let i=0;i<n;i++) [a,b]=[b,a+b]; return a; }
|
||
function sieve(n) {
|
||
const s=new Array(n+1).fill(true); s[0]=s[1]=false;
|
||
for(let i=2;i*i<=n;i++) if(s[i]) for(let j=i*i;j<=n;j+=i) s[j]=false;
|
||
return s.reduce((a,v,i)=>{if(v)a.push(i);return a;},[]);
|
||
}
|
||
function sqrtSum(n) { let s=0; for(let i=1;i<=n;i++) s+=Math.sqrt(i); return s; }
|
||
function bubbleSort(arr) {
|
||
arr=[...arr]; const n=arr.length;
|
||
for(let i=0;i<n;i++) for(let j=0;j<n-i-1;j++)
|
||
if(arr[j]>arr[j+1]) [arr[j],arr[j+1]]=[arr[j+1],arr[j]];
|
||
return arr;
|
||
}
|
||
function matMul(a,b) {
|
||
const ra=a.length,ca=a[0].length,cb=b[0].length;
|
||
const c=Array.from({length:ra},()=>new Array(cb).fill(0));
|
||
for(let i=0;i<ra;i++) for(let j=0;j<cb;j++) for(let k=0;k<ca;k++) c[i][j]+=a[i][k]*b[k][j];
|
||
return c;
|
||
}
|
||
function processWords(w) { return w.filter(s=>s.length>3).map(s=>s.toUpperCase().split('').reverse().join('')); }
|
||
function stats(arr) {
|
||
const n=arr.length, m=arr.reduce((a,b)=>a+b,0)/n;
|
||
const v=arr.reduce((a,b)=>a+(b-m)**2,0)/n;
|
||
return {n, mean:+m.toFixed(4), std:+Math.sqrt(v).toFixed(4)};
|
||
}
|
||
function sha256(s) { return crypto.createHash('sha256').update(s).digest('hex').slice(0,16); }
|
||
|
||
module.exports = async function(ctx) {
|
||
const t0=Date.now();
|
||
const f=fib(35), primes=sieve(500), s=sqrtSum(1000);
|
||
const nums=Array.from({length:50},(_,i)=>50-i);
|
||
const sorted=bubbleSort(nums);
|
||
const a=[[1,2,3],[4,5,6]], b=[[7,8],[9,10],[11,12]], c=matMul(a,b);
|
||
const pw=processWords(WORDS), st=stats(primes), h=sha256('bench-medium-node');
|
||
const elapsed=Date.now()-t0;
|
||
return {status:200, body:JSON.stringify({
|
||
tag:"bench-node-medium-ok", fib35:f, primes:primes.length,
|
||
sqrt:+s.toFixed(1), sorted0:sorted[0], mat_c00:c[0][0],
|
||
words:pw.length, stats:st, hash:h, elapsed
|
||
})};
|
||
};
|
||
JSEOF
|
||
|
||
cat > "${TMP}/node_large.js" << 'JSEOF'
|
||
const crypto = require('crypto');
|
||
const WORDS = ["alpha","beta","gamma","delta","epsilon","zeta","eta","theta",
|
||
"iota","kappa","lambda","mu","nu","xi","omicron","pi",
|
||
"rho","sigma","tau","upsilon","phi","chi","psi","omega",
|
||
"one","two","three","four","five","six","seven","eight",
|
||
"nine","ten","eleven","twelve","thirteen","fourteen","fifteen"];
|
||
const LOOKUP_SQ = Object.fromEntries(Array.from({length:200},(_,i)=>[i,i*i]));
|
||
const LOOKUP_CUBE = Object.fromEntries(Array.from({length:200},(_,i)=>[i,i**3]));
|
||
const CONSTANTS = {pi:Math.PI, e:Math.E, phi:(1+Math.sqrt(5))/2, sqrt2:Math.SQRT2, ln2:Math.LN2};
|
||
|
||
function fib(n) { let a=0,b=1; for(let i=0;i<n;i++) [a,b]=[b,a+b]; return a; }
|
||
function fibList(n) { const r=[]; let a=0,b=1; for(let i=0;i<n;i++){r.push(a);[a,b]=[b,a+b];} return r; }
|
||
function sieve(n) {
|
||
const s=new Array(n+1).fill(true); s[0]=s[1]=false;
|
||
for(let i=2;i*i<=n;i++) if(s[i]) for(let j=i*i;j<=n;j+=i) s[j]=false;
|
||
return s.reduce((a,v,i)=>{if(v)a.push(i);return a;},[]);
|
||
}
|
||
function sqrtSum(n) { let s=0; for(let i=1;i<=n;i++) s+=Math.sqrt(i); return s; }
|
||
function logSum(n) { let s=0; for(let i=1;i<=n;i++) s+=Math.log(i); return s; }
|
||
function trigSum(n) { let s=0; for(let i=0;i<n;i++) s+=Math.sin(i)*Math.cos(i); return s; }
|
||
function bubbleSort(arr) {
|
||
arr=[...arr]; const n=arr.length;
|
||
for(let i=0;i<n;i++) for(let j=0;j<n-i-1;j++)
|
||
if(arr[j]>arr[j+1]) [arr[j],arr[j+1]]=[arr[j+1],arr[j]];
|
||
return arr;
|
||
}
|
||
function insertionSort(arr) {
|
||
arr=[...arr];
|
||
for(let i=1;i<arr.length;i++){
|
||
const k=arr[i]; let j=i-1;
|
||
while(j>=0&&arr[j]>k){arr[j+1]=arr[j];j--;} arr[j+1]=k;
|
||
}
|
||
return arr;
|
||
}
|
||
function matMul(a,b) {
|
||
const ra=a.length,ca=a[0].length,cb=b[0].length;
|
||
const c=Array.from({length:ra},()=>new Array(cb).fill(0));
|
||
for(let i=0;i<ra;i++) for(let j=0;j<cb;j++) for(let k=0;k<ca;k++) c[i][j]+=a[i][k]*b[k][j];
|
||
return c;
|
||
}
|
||
function transpose(m) { return m[0].map((_,i)=>m.map(r=>r[i])); }
|
||
function processWords(w) {
|
||
return w.filter(s=>s.length>=3).map(s=>({
|
||
original:s, upper:s.toUpperCase(), reversed:s.split('').reverse().join(''),
|
||
len:s.length, vowels:[...s].filter(c=>"aeiou".includes(c)).length
|
||
}));
|
||
}
|
||
function stats(arr) {
|
||
const n=arr.length, m=arr.reduce((a,b)=>a+b,0)/n;
|
||
const v=arr.reduce((a,b)=>a+(b-m)**2,0)/n;
|
||
const sorted=[...arr].sort((a,b)=>a-b);
|
||
return {n, min:sorted[0], max:sorted[n-1], mean:+m.toFixed(4), std:+Math.sqrt(v).toFixed(4)};
|
||
}
|
||
function sha256(s) { return crypto.createHash('sha256').update(s).digest('hex'); }
|
||
function md5(s) { return crypto.createHash('md5').update(s).digest('hex'); }
|
||
function caesar(t,sh) {
|
||
return [...t].map(c=>{
|
||
const b=c.match(/[a-z]/)?97:c.match(/[A-Z]/)?65:null;
|
||
return b===null?c:String.fromCharCode((c.charCodeAt(0)-b+sh)%26+b);
|
||
}).join('');
|
||
}
|
||
function lookupOps(n) { let r=0; for(let i=0;i<n;i++) r+=(LOOKUP_SQ[i%200]||0)+(LOOKUP_CUBE[i%200]||0); return r; }
|
||
|
||
module.exports = async function(ctx) {
|
||
const t0=Date.now();
|
||
const sq=sqrtSum(2000), lg=logSum(1000), tr=trigSum(500);
|
||
const primes=sieve(1000), f40=fib(40), fibs=fibList(20);
|
||
const nums=Array.from({length:100},(_,i)=>100-i);
|
||
const bs=bubbleSort(nums.slice(0,50)), ins=insertionSort(nums.slice(50));
|
||
const h256=sha256('bench-large-node-2026'), md=md5('bench-large-node-2026');
|
||
const ma=Array.from({length:4},(_,i)=>Array.from({length:4},(_,j)=>i+j));
|
||
const mb=Array.from({length:4},(_,i)=>Array.from({length:4},(_,j)=>i*j+1));
|
||
const mc=matMul(ma,mb), mt=transpose(mc);
|
||
const pw=processWords(WORDS), pst=stats(primes.slice(0,50));
|
||
const cipher=caesar('hello bench world',13);
|
||
const lookup=lookupOps(500);
|
||
const csum=Object.values(CONSTANTS).reduce((a,b)=>a+b,0);
|
||
const elapsed=Date.now()-t0;
|
||
return {status:200, body:JSON.stringify({
|
||
tag:"bench-node-large-ok",
|
||
sqrt:+sq.toFixed(2), log:+lg.toFixed(2), trig:+tr.toFixed(4),
|
||
primes:primes.length, fib40:f40.toString(), fibsSum:fibs.reduce((a,b)=>a+b,0),
|
||
h256:h256.slice(0,16), md:md.slice(0,16),
|
||
matTrace:mc.reduce((s,r,i)=>s+r[i],0),
|
||
words:pw.length, stats:pst, cipher, lookup, csum:+csum.toFixed(6), elapsed
|
||
})};
|
||
};
|
||
JSEOF
|
||
|
||
# ── RUBY ──────────────────────────────────────────────────────────────────
|
||
cat > "${TMP}/ruby_tiny.rb" << 'RBEOF'
|
||
def handler(ctx)
|
||
{ statusCode: 200, body: "bench-ruby-tiny-ok" }
|
||
end
|
||
RBEOF
|
||
|
||
cat > "${TMP}/ruby_small.rb" << 'RBEOF'
|
||
require 'json'
|
||
|
||
def fib(n); a,b=0,1; n.times{a,b=b,a+b}; a; end
|
||
def sieve(n)
|
||
s=Array.new(n+1,true); s[0]=s[1]=false
|
||
(2..Math.sqrt(n).to_i).each{|i|(i*i..n).step(i){|j|s[j]=false} if s[i]}
|
||
(0..n).select{|i|s[i]}
|
||
end
|
||
def sqrt_sum(n); (1..n).sum{|i|Math.sqrt(i)}; end
|
||
|
||
def handler(ctx)
|
||
t0=Time.now
|
||
f=fib(30); primes=sieve(200); s=sqrt_sum(500)
|
||
elapsed=Time.now-t0
|
||
{ statusCode: 200, body: "bench-ruby-small-ok:fib30=#{f}:primes=#{primes.length}:sqrt=#{s.round(1)}:t=#{elapsed.round(4)}s" }
|
||
end
|
||
RBEOF
|
||
|
||
cat > "${TMP}/ruby_medium.rb" << 'RBEOF'
|
||
require 'json'
|
||
require 'digest'
|
||
|
||
WORDS=%w[alpha beta gamma delta epsilon zeta eta theta iota kappa lambda mu nu xi omicron pi rho sigma tau upsilon phi chi psi omega]
|
||
|
||
def fib(n); a,b=0,1; n.times{a,b=b,a+b}; a; end
|
||
def sieve(n)
|
||
s=Array.new(n+1,true); s[0]=s[1]=false
|
||
(2..Math.sqrt(n).to_i).each{|i|(i*i..n).step(i){|j|s[j]=false} if s[i]}
|
||
(0..n).select{|i|s[i]}
|
||
end
|
||
def sqrt_sum(n); (1..n).sum{|i|Math.sqrt(i)}; end
|
||
def bubble_sort(arr)
|
||
arr=arr.dup; n=arr.length
|
||
n.times{(n-1).times{|j|arr[j],arr[j+1]=arr[j+1],arr[j] if arr[j]>arr[j+1]}}
|
||
arr
|
||
end
|
||
def mat_mul(a,b)
|
||
ra,ca,cb=a.length,a[0].length,b[0].length
|
||
Array.new(ra){|i|Array.new(cb){|j|(0...ca).sum{|k|a[i][k]*b[k][j]}}}
|
||
end
|
||
def process_words(w); w.select{|s|s.length>3}.map{|s|s.upcase.reverse}; end
|
||
def get_stats(arr)
|
||
n=arr.length; m=arr.sum.to_f/n; v=arr.sum{|x|(x-m)**2}/n
|
||
{n:n, mean:m.round(4), std:Math.sqrt(v).round(4)}
|
||
end
|
||
|
||
def handler(ctx)
|
||
t0=Time.now
|
||
f=fib(35); primes=sieve(500); s=sqrt_sum(1000)
|
||
nums=(1..50).to_a.reverse; sorted=bubble_sort(nums)
|
||
a=[[1,2,3],[4,5,6]]; b=[[7,8],[9,10],[11,12]]; c=mat_mul(a,b)
|
||
pw=process_words(WORDS); st=get_stats(primes)
|
||
h=Digest::SHA256.hexdigest('bench-medium-ruby')[0,16]
|
||
elapsed=Time.now-t0
|
||
{ statusCode: 200, body: JSON.generate({tag:"bench-ruby-medium-ok", fib35:f, primes:primes.length,
|
||
sqrt:s.round(1), sorted0:sorted[0], mat_c00:c[0][0],
|
||
words:pw.length, stats:st, hash:h, elapsed:elapsed.round(5)}) }
|
||
end
|
||
RBEOF
|
||
|
||
cat > "${TMP}/ruby_large.rb" << 'RBEOF'
|
||
require 'json'
|
||
require 'digest'
|
||
require 'base64'
|
||
|
||
WORDS=%w[alpha beta gamma delta epsilon zeta eta theta iota kappa lambda mu nu xi omicron pi rho sigma tau upsilon phi chi psi omega one two three four five six seven eight nine ten eleven twelve thirteen fourteen fifteen]
|
||
LOOKUP_SQ=(0...200).each_with_object({}){|i,h|h[i]=i*i}
|
||
LOOKUP_CUBE=(0...200).each_with_object({}){|i,h|h[i]=i**3}
|
||
CONSTANTS={pi:Math::PI, e:Math::E, phi:(1+Math.sqrt(5))/2, sqrt2:Math.sqrt(2), ln2:Math.log(2)}
|
||
|
||
def fib(n); a,b=0,1; n.times{a,b=b,a+b}; a; end
|
||
def fib_list(n); r=[]; a,b=0,1; n.times{r<<a;a,b=b,a+b}; r; end
|
||
def sieve(n)
|
||
s=Array.new(n+1,true); s[0]=s[1]=false
|
||
(2..Math.sqrt(n).to_i).each{|i|(i*i..n).step(i){|j|s[j]=false} if s[i]}
|
||
(0..n).select{|i|s[i]}
|
||
end
|
||
def sqrt_sum(n); (1..n).sum{|i|Math.sqrt(i)}; end
|
||
def log_sum(n); (1..n).sum{|i|Math.log(i)}; end
|
||
def trig_sum(n); (0...n).sum{|i|Math.sin(i)*Math.cos(i)}; end
|
||
def bubble_sort(arr)
|
||
arr=arr.dup; n=arr.length
|
||
n.times{(n-1).times{|j|arr[j],arr[j+1]=arr[j+1],arr[j] if arr[j]>arr[j+1]}}
|
||
arr
|
||
end
|
||
def insertion_sort(arr)
|
||
arr=arr.dup
|
||
(1...arr.length).each{|i|k=arr[i];j=i-1;while j>=0&&arr[j]>k;arr[j+1]=arr[j];j-=1;end;arr[j+1]=k}
|
||
arr
|
||
end
|
||
def mat_mul(a,b)
|
||
ra,ca,cb=a.length,a[0].length,b[0].length
|
||
Array.new(ra){|i|Array.new(cb){|j|(0...ca).sum{|k|a[i][k]*b[k][j]}}}
|
||
end
|
||
def transpose(m); m[0].length.times.map{|j|m.map{|r|r[j]}}; end
|
||
def process_words(w)
|
||
w.select{|s|s.length>=3}.map{|s|{original:s,upper:s.upcase,reversed:s.reverse,len:s.length,vowels:s.count("aeiou")}}
|
||
end
|
||
def get_stats(arr)
|
||
n=arr.length; m=arr.sum.to_f/n; v=arr.sum{|x|(x-m)**2}/n
|
||
{n:n, min:arr.min, max:arr.max, mean:m.round(4), std:Math.sqrt(v).round(4)}
|
||
end
|
||
def caesar(t,sh)
|
||
t.chars.map{|c|
|
||
if c=~/[a-z]/; (('a'.ord+(c.ord-'a'.ord+sh)%26).chr)
|
||
elsif c=~/[A-Z]/; (('A'.ord+(c.ord-'A'.ord+sh)%26).chr)
|
||
else c end
|
||
}.join
|
||
end
|
||
def lookup_ops(n); (0...n).sum{|i|(LOOKUP_SQ[i%200]||0)+(LOOKUP_CUBE[i%200]||0)}; end
|
||
|
||
def handler(ctx)
|
||
t0=Time.now
|
||
sq=sqrt_sum(2000); lg=log_sum(1000); tr=trig_sum(500)
|
||
primes=sieve(1000); f40=fib(40); fibs=fib_list(20)
|
||
nums=(1..100).to_a.reverse
|
||
bs=bubble_sort(nums[0,50]); ins=insertion_sort(nums[50,50])
|
||
h256=Digest::SHA256.hexdigest('bench-large-ruby-2026')
|
||
md5=Digest::MD5.hexdigest('bench-large-ruby-2026')
|
||
b64=Base64.strict_encode64('hello from bench-ruby-large')
|
||
ma=Array.new(4){|i|Array.new(4){|j|i+j}}
|
||
mb=Array.new(4){|i|Array.new(4){|j|i*j+1}}
|
||
mc=mat_mul(ma,mb); mt=transpose(mc)
|
||
pw=process_words(WORDS); pst=get_stats(primes[0,50])
|
||
cipher=caesar('hello bench world',13)
|
||
lookup=lookup_ops(500)
|
||
csum=CONSTANTS.values.sum
|
||
elapsed=Time.now-t0
|
||
{ statusCode: 200, body: JSON.generate({tag:"bench-ruby-large-ok",
|
||
sqrt:sq.round(2), log:lg.round(2), trig:tr.round(4),
|
||
primes:primes.length, fib40:f40, fibs_sum:fibs.sum,
|
||
h256:h256[0,16], md5:md5[0,16], b64_len:b64.length,
|
||
mat_trace:mc.each_with_index.sum{|r,i|r[i]},
|
||
words:pw.length, stats:pst, cipher:cipher,
|
||
lookup:lookup, csum:csum.round(6), elapsed:elapsed.round(5)}) }
|
||
end
|
||
RBEOF
|
||
|
||
# ── PHP ───────────────────────────────────────────────────────────────────
|
||
cat > "${TMP}/php_tiny.php" << 'PHPEOF'
|
||
<?php
|
||
function main($event, $context) {
|
||
return "bench-php-tiny-ok";
|
||
}
|
||
PHPEOF
|
||
|
||
cat > "${TMP}/php_small.php" << 'PHPEOF'
|
||
<?php
|
||
function fib($n){$a=0;$b=1;for($i=0;$i<$n;$i++)[$a,$b]=[$b,$a+$b];return $a;}
|
||
function sieve($n){
|
||
$s=array_fill(0,$n+1,true);$s[0]=$s[1]=false;
|
||
for($i=2;$i*$i<=$n;$i++)if($s[$i])for($j=$i*$i;$j<=$n;$j+=$i)$s[$j]=false;
|
||
return array_keys(array_filter($s));
|
||
}
|
||
function sqrtSum($n){$s=0;for($i=1;$i<=$n;$i++)$s+=sqrt($i);return $s;}
|
||
|
||
function main($event, $context){
|
||
$t0=microtime(true);
|
||
$f=fib(30); $primes=sieve(200); $s=sqrtSum(500);
|
||
$elapsed=microtime(true)-$t0;
|
||
return sprintf("bench-php-small-ok:fib30=%s:primes=%d:sqrt=%.1f:t=%.4fs",
|
||
$f,count($primes),$s,$elapsed);
|
||
}
|
||
PHPEOF
|
||
|
||
cat > "${TMP}/php_medium.php" << 'PHPEOF'
|
||
<?php
|
||
function fib($n){$a=0;$b=1;for($i=0;$i<$n;$i++)[$a,$b]=[$b,$a+$b];return $a;}
|
||
function sieve($n){$s=array_fill(0,$n+1,true);$s[0]=$s[1]=false;for($i=2;$i*$i<=$n;$i++)if($s[$i])for($j=$i*$i;$j<=$n;$j+=$i)$s[$j]=false;return array_keys(array_filter($s));}
|
||
function sqrtSum($n){$s=0;for($i=1;$i<=$n;$i++)$s+=sqrt($i);return $s;}
|
||
function bubbleSort($arr){$n=count($arr);for($i=0;$i<$n;$i++)for($j=0;$j<$n-$i-1;$j++)if($arr[$j]>$arr[$j+1])[$arr[$j],$arr[$j+1]]=[$arr[$j+1],$arr[$j]];return $arr;}
|
||
function matMul($a,$b){$ra=count($a);$ca=count($a[0]);$cb=count($b[0]);$c=array_fill(0,$ra,array_fill(0,$cb,0));for($i=0;$i<$ra;$i++)for($j=0;$j<$cb;$j++)for($k=0;$k<$ca;$k++)$c[$i][$j]+=$a[$i][$k]*$b[$k][$j];return $c;}
|
||
function processWords($w){$f=array_filter($w,function($s){return strlen($s)>3;});return array_values(array_map(function($s){return strrev(strtoupper($s));},$f));}
|
||
function statsArr($arr){$n=count($arr);$m=array_sum($arr)/$n;$v=array_sum(array_map(function($x)use($m){return($x-$m)**2;},$arr))/$n;return['n'=>$n,'mean'=>round($m,4),'std'=>round(sqrt($v),4)];}
|
||
|
||
function main($event,$context){
|
||
$t0=microtime(true);
|
||
$words=["alpha","beta","gamma","delta","epsilon","zeta","eta","theta","iota","kappa","lambda","mu"];
|
||
$f=fib(35);$primes=sieve(500);$s=sqrtSum(1000);
|
||
$nums=range(50,1);$sorted=bubbleSort($nums);
|
||
$a=[[1,2,3],[4,5,6]];$b=[[7,8],[9,10],[11,12]];$c=matMul($a,$b);
|
||
$pw=processWords($words);$st=statsArr($primes);
|
||
$h=substr(hash('sha256','bench-medium-php'),0,16);
|
||
$elapsed=microtime(true)-$t0;
|
||
return json_encode(['tag'=>'bench-php-medium-ok','fib35'=>$f,'primes'=>count($primes),
|
||
'sqrt'=>round($s,1),'sorted0'=>$sorted[0],'mat_c00'=>$c[0][0],
|
||
'words'=>count($pw),'stats'=>$st,'hash'=>$h,'elapsed'=>round($elapsed,5)]);
|
||
}
|
||
PHPEOF
|
||
|
||
cat > "${TMP}/php_large.php" << 'PHPEOF'
|
||
<?php
|
||
$GLOBALS['WORDS']=["alpha","beta","gamma","delta","epsilon","zeta","eta","theta","iota","kappa","lambda","mu","nu","xi","omicron","pi","rho","sigma","tau","upsilon","phi","chi","psi","omega","one","two","three","four","five","six","seven","eight","nine","ten","eleven"];
|
||
function fib($n){$a=0;$b=1;for($i=0;$i<$n;$i++)[$a,$b]=[$b,$a+$b];return $a;}
|
||
function fibList($n){$r=[];$a=0;$b=1;for($i=0;$i<$n;$i++){$r[]=$a;[$a,$b]=[$b,$a+$b];}return $r;}
|
||
function sieve($n){$s=array_fill(0,$n+1,true);$s[0]=$s[1]=false;for($i=2;$i*$i<=$n;$i++)if($s[$i])for($j=$i*$i;$j<=$n;$j+=$i)$s[$j]=false;return array_keys(array_filter($s));}
|
||
function sqrtSum($n){$s=0;for($i=1;$i<=$n;$i++)$s+=sqrt($i);return $s;}
|
||
function logSum($n){$s=0;for($i=1;$i<=$n;$i++)$s+=log($i);return $s;}
|
||
function trigSum($n){$s=0;for($i=0;$i<$n;$i++)$s+=sin($i)*cos($i);return $s;}
|
||
function bubbleSort($arr){$n=count($arr);for($i=0;$i<$n;$i++)for($j=0;$j<$n-$i-1;$j++)if($arr[$j]>$arr[$j+1])[$arr[$j],$arr[$j+1]]=[$arr[$j+1],$arr[$j]];return $arr;}
|
||
function insertionSort($arr){for($i=1;$i<count($arr);$i++){$k=$arr[$i];$j=$i-1;while($j>=0&&$arr[$j]>$k){$arr[$j+1]=$arr[$j];$j--;}$arr[$j+1]=$k;}return $arr;}
|
||
function matMul($a,$b){$ra=count($a);$ca=count($a[0]);$cb=count($b[0]);$c=array_fill(0,$ra,array_fill(0,$cb,0));for($i=0;$i<$ra;$i++)for($j=0;$j<$cb;$j++)for($k=0;$k<$ca;$k++)$c[$i][$j]+=$a[$i][$k]*$b[$k][$j];return $c;}
|
||
function processWords($w){$f=array_filter($w,function($s){return strlen($s)>=3;});return array_values(array_map(function($s){return['original'=>$s,'upper'=>strtoupper($s),'reversed'=>strrev($s),'len'=>strlen($s),'vowels'=>preg_match_all('/[aeiou]/',$s)];},$f));}
|
||
function statsArr($arr){$n=count($arr);$m=array_sum($arr)/$n;$v=array_sum(array_map(function($x)use($m){return($x-$m)**2;},$arr))/$n;return['n'=>$n,'min'=>min($arr),'max'=>max($arr),'mean'=>round($m,4),'std'=>round(sqrt($v),4)];}
|
||
function caesar($t,$sh){return preg_replace_callback('/[a-zA-Z]/',function($m)use($sh){return chr((ord($m[0])-(ctype_lower($m[0])?97:65)+$sh)%26+(ctype_lower($m[0])?97:65));},$t);}
|
||
function lookupOps($n){$sq=array_combine(range(0,199),array_map(function($i){return $i*$i;},range(0,199)));$cu=array_combine(range(0,199),array_map(function($i){return $i**3;},range(0,199)));$r=0;for($i=0;$i<$n;$i++)$r+=($sq[$i%200]??0)+($cu[$i%200]??0);return $r;}
|
||
|
||
function main($event,$context){
|
||
$words=$GLOBALS['WORDS'];
|
||
$t0=microtime(true);
|
||
$sq=sqrtSum(2000);$lg=logSum(1000);$tr=trigSum(500);
|
||
$primes=sieve(1000);$f40=fib(40);$fibs=fibList(20);
|
||
$nums=range(100,1);
|
||
$bs=bubbleSort(array_slice($nums,0,50));$ins=insertionSort(array_slice($nums,50,50));
|
||
$h256=substr(hash('sha256','bench-large-php-2026'),0,16);
|
||
$md5=substr(hash('md5','bench-large-php-2026'),0,16);
|
||
$b64=base64_encode('hello from bench-php-large');
|
||
$ma=array_map(function($i){return array_map(function($j)use($i){return $i+$j;},range(0,3));},range(0,3));
|
||
$mb=array_map(function($i){return array_map(function($j)use($i){return $i*$j+1;},range(0,3));},range(0,3));
|
||
$mc=matMul($ma,$mb);
|
||
$pw=processWords($words);$pst=statsArr(array_slice($primes,0,50));
|
||
$cipher=caesar('hello bench world',13);
|
||
$lookup=lookupOps(500);
|
||
$csum=M_PI+M_E+(1+sqrt(5))/2+sqrt(2)+log(2);
|
||
$elapsed=microtime(true)-$t0;
|
||
return json_encode(['tag'=>'bench-php-large-ok',
|
||
'sqrt'=>round($sq,2),'log'=>round($lg,2),'trig'=>round($tr,4),
|
||
'primes'=>count($primes),'fib40'=>$f40,'fibs_sum'=>array_sum($fibs),
|
||
'h256'=>$h256,'md5'=>$md5,'b64_len'=>strlen($b64),
|
||
'mat_trace'=>array_sum(array_map(function($i)use($mc){return $mc[$i][$i];},range(0,3))),
|
||
'words'=>count($pw),'stats'=>$pst,'cipher'=>$cipher,
|
||
'lookup'=>$lookup,'csum'=>round($csum,6),'elapsed'=>round($elapsed,5)]);
|
||
}
|
||
PHPEOF
|
||
|
||
# ═══════════════════════════════════════════════════════════════════════════
|
||
# ГЕНЕРАЦИЯ ZIP-АРХИВОВ
|
||
# ═══════════════════════════════════════════════════════════════════════════
|
||
log ""
|
||
log ">>> Генерация ZIP-архивов..."
|
||
|
||
# Python archive: main.py + utils.py
|
||
python3 - > "${TMP}/arc-py.zip" << 'PYARCEOF'
|
||
import zipfile, io, sys
|
||
buf = io.BytesIO()
|
||
main_code = """import json
|
||
from utils import compute
|
||
def main(event, context):
|
||
result = compute()
|
||
return json.dumps({"tag": "bench-arc-py-ok", "result": result}), 200
|
||
"""
|
||
utils_code = """import math, hashlib
|
||
def compute():
|
||
primes = sieve(200)
|
||
sq = sum(math.sqrt(i) for i in range(1, 500))
|
||
h = hashlib.sha256(b'bench-arc-python').hexdigest()[:12]
|
||
return {"primes": len(primes), "sqrt_sum": round(sq, 2), "hash": h}
|
||
def sieve(n):
|
||
s = [True]*(n+1); s[0]=s[1]=False
|
||
for i in range(2,int(math.sqrt(n))+1):
|
||
if s[i]:
|
||
for j in range(i*i,n+1,i): s[j]=False
|
||
return [i for i in range(n+1) if s[i]]
|
||
"""
|
||
with zipfile.ZipFile(buf, 'w', zipfile.ZIP_DEFLATED) as zf:
|
||
zf.writestr('main.py', main_code)
|
||
zf.writestr('utils.py', utils_code)
|
||
sys.stdout.buffer.write(buf.getvalue())
|
||
PYARCEOF
|
||
|
||
# Node.js archive: main.js + utils.js + package.json
|
||
python3 - > "${TMP}/arc-node.zip" << 'NODEARCEOF'
|
||
import zipfile, io, sys
|
||
buf = io.BytesIO()
|
||
main_code = """const { compute } = require('./utils');
|
||
module.exports = async function(ctx) {
|
||
const result = compute();
|
||
return { status: 200, body: JSON.stringify({ tag: "bench-arc-node-ok", result }) };
|
||
};
|
||
"""
|
||
utils_code = """const crypto = require('crypto');
|
||
function sieve(n) {
|
||
const s=new Array(n+1).fill(true); s[0]=s[1]=false;
|
||
for(let i=2;i*i<=n;i++) if(s[i]) for(let j=i*i;j<=n;j+=i) s[j]=false;
|
||
return s.reduce((a,v,i)=>{if(v)a.push(i);return a;},[]);
|
||
}
|
||
function compute() {
|
||
const primes=sieve(200);
|
||
let sq=0; for(let i=1;i<=500;i++) sq+=Math.sqrt(i);
|
||
const h=crypto.createHash('sha256').update('bench-arc-node').digest('hex').slice(0,12);
|
||
return { primes: primes.length, sqrt_sum: +sq.toFixed(2), hash: h };
|
||
}
|
||
module.exports = { compute };
|
||
"""
|
||
pkg = '{"name":"bench-arc-node","version":"1.0.0","main":"main.js"}'
|
||
with zipfile.ZipFile(buf, 'w', zipfile.ZIP_DEFLATED) as zf:
|
||
zf.writestr('main.js', main_code)
|
||
zf.writestr('utils.js', utils_code)
|
||
zf.writestr('package.json', pkg)
|
||
sys.stdout.buffer.write(buf.getvalue())
|
||
NODEARCEOF
|
||
|
||
# Ruby archive: handler.rb + utils.rb
|
||
python3 - > "${TMP}/arc-ruby.zip" << 'RUBYARCEOF'
|
||
import zipfile, io, sys
|
||
buf = io.BytesIO()
|
||
main_code = """require 'json'
|
||
require_relative 'utils'
|
||
def handler(ctx)
|
||
result = compute()
|
||
{ statusCode: 200, body: JSON.generate({ tag: "bench-arc-ruby-ok", result: result }) }
|
||
end
|
||
"""
|
||
utils_code = """require 'digest'
|
||
def sieve(n)
|
||
s=Array.new(n+1,true); s[0]=s[1]=false
|
||
(2..Math.sqrt(n).to_i).each{|i|(i*i..n).step(i){|j|s[j]=false} if s[i]}
|
||
(0..n).select{|i|s[i]}
|
||
end
|
||
def compute
|
||
primes=sieve(200)
|
||
sq=(1..500).sum{|i|Math.sqrt(i)}
|
||
h=Digest::SHA256.hexdigest('bench-arc-ruby')[0,12]
|
||
{primes: primes.length, sqrt_sum: sq.round(2), hash: h}
|
||
end
|
||
"""
|
||
with zipfile.ZipFile(buf, 'w', zipfile.ZIP_DEFLATED) as zf:
|
||
zf.writestr('handler.rb', main_code)
|
||
zf.writestr('utils.rb', utils_code)
|
||
sys.stdout.buffer.write(buf.getvalue())
|
||
RUBYARCEOF
|
||
|
||
# PHP archive: main.php + utils.php
|
||
python3 - > "${TMP}/arc-php.zip" << 'PHPARCEOF'
|
||
import zipfile, io, sys
|
||
buf = io.BytesIO()
|
||
main_code = """<?php
|
||
require_once 'utils.php';
|
||
function handler($ctx) {
|
||
$result = compute();
|
||
$ctx["response"]->getBody()->write(json_encode(['tag' => 'bench-arc-php-ok', 'result' => $result]));
|
||
}
|
||
"""
|
||
utils_code = """<?php
|
||
function sieve($n){
|
||
$s=array_fill(0,$n+1,true);$s[0]=$s[1]=false;
|
||
for($i=2;$i*$i<=$n;$i++)if($s[$i])for($j=$i*$i;$j<=$n;$j+=$i)$s[$j]=false;
|
||
return array_keys(array_filter($s));
|
||
}
|
||
function compute(){
|
||
$primes=sieve(200);
|
||
$sq=0; for($i=1;$i<=500;$i++) $sq+=sqrt($i);
|
||
$h=substr(hash('sha256','bench-arc-php'),0,12);
|
||
return ['primes'=>count($primes),'sqrt_sum'=>round($sq,2),'hash'=>$h];
|
||
}
|
||
"""
|
||
with zipfile.ZipFile(buf, 'w', zipfile.ZIP_DEFLATED) as zf:
|
||
zf.writestr('main.php', main_code)
|
||
zf.writestr('utils.php', utils_code)
|
||
sys.stdout.buffer.write(buf.getvalue())
|
||
PHPARCEOF
|
||
|
||
# ═══════════════════════════════════════════════════════════════════════════
|
||
# ЗАПУСК БЕНЧМАРКОВ
|
||
# ═══════════════════════════════════════════════════════════════════════════
|
||
log ""
|
||
log "────────────────────────────────────────────────────────────────────────"
|
||
log " LANG SIZE UPLOAD(ms) COLD(ms) HOT_AVG(ms) STATUS"
|
||
log "────────────────────────────────────────────────────────────────────────"
|
||
|
||
declare -A LANG_SHORT=([python]=py [nodejs]=node [ruby]=ruby [php]=php)
|
||
declare -A CODE_EXT=([python]=py [nodejs]=js [ruby]=rb [php]=php)
|
||
declare -A CODE_PREFIX=([python]=py [nodejs]=node [ruby]=ruby [php]=php)
|
||
|
||
for lang in python nodejs ruby php; do
|
||
short="${LANG_SHORT[$lang]}"
|
||
prefix="${CODE_PREFIX[$lang]}"
|
||
ext="${CODE_EXT[$lang]}"
|
||
log ""
|
||
log " === ${lang^^} ==="
|
||
for size in tiny small medium large; do
|
||
fn="bench-${short}-${size}-${RUNID}"
|
||
codefile="${TMP}/${prefix}_${size}.${ext}"
|
||
bench_code "$lang" "$size" "$fn" "$codefile"
|
||
done
|
||
done
|
||
|
||
log ""
|
||
log "────────────────────────────────────────────────────────────────────────"
|
||
log " АРХИВЫ (ZIP с несколькими файлами)"
|
||
log "────────────────────────────────────────────────────────────────────────"
|
||
|
||
bench_archive "py" "python" "bench-arc-py-${RUNID}" "${TMP}/arc-py.zip" "bench-arc-py-ok"
|
||
bench_archive "node" "nodejs" "bench-arc-node-${RUNID}" "${TMP}/arc-node.zip" "bench-arc-node-ok"
|
||
bench_archive "ruby" "ruby" "bench-arc-ruby-${RUNID}" "${TMP}/arc-ruby.zip" "bench-arc-ruby-ok"
|
||
bench_archive "php" "php" "bench-arc-php-${RUNID}" "${TMP}/arc-php.zip" "bench-arc-php-ok"
|
||
|
||
# ═══════════════════════════════════════════════════════════════════════════
|
||
# ИТОГОВАЯ ТАБЛИЦА
|
||
# ═══════════════════════════════════════════════════════════════════════════
|
||
log ""
|
||
log "════════════════════════════════════════════════════════════════════════"
|
||
log " ИТОГОВАЯ ТАБЛИЦА"
|
||
log " LANG SIZE UPLOAD(ms) COLD(ms) HOT_AVG(ms) STATUS"
|
||
log "════════════════════════════════════════════════════════════════════════"
|
||
for row in "${SUMMARY_ROWS[@]}"; do
|
||
log " $row"
|
||
done
|
||
log "════════════════════════════════════════════════════════════════════════"
|
||
log " PASS: ${PASS_CNT} FAIL: ${FAIL_CNT} TOTAL: $((PASS_CNT+FAIL_CNT))"
|
||
log "════════════════════════════════════════════════════════════════════════"
|
||
log ""
|
||
log " Лог: ${LOGFILE}"
|
||
log " Готово: $(date)"
|