Files
fission-console/bench-func/bench_full.sh
T
“Naeel” a2e1723e33 bench: fix PHP arrow functions (fn()=> requires 7.4+), PASS=20/20 on PV
- 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
2026-05-20 08:27:32 +04:00

1033 lines
43 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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)"