- Posted on
- • Artificial Intelligence
Artificial Intelligence Process Optimisation
- Author
-
-
- User
- linuxbash
- Posts by this author
- Posts by this author
-
AI Process Optimization for Bash Users: Turn Logs Into Speedups
Your cron job ran all night and still missed the window? Most shell pipelines run on faith: we toss data at scripts, hope they scale, and only notice inefficiencies when they hurt. The good news: a small dose of AI—built on the telemetry your Linux box already gives you—can turn guesswork into measurable speedups. You don’t need a GPU, a data lake, or a team of data scientists. You need Bash, a few lightweight tools, and a handful of Python.
This post shows how to instrument your processes, detect regressions, predict runtimes, and auto-tune command-line parameters with practical, copy-pasteable snippets. The value: fewer surprises, faster jobs, and smarter scheduling.
Why this is worth your time
Linux emits rich metrics (time, CPU, RSS, I/O) that are perfect for machine learning on tabular data.
Even simple models (isolation forests, random forests) on a laptop can reveal anomalies and predict durations with useful accuracy.
AI-guided parameter tuning (threads, compression level, block size) can yield double-digit improvements without touching your source code.
You can keep everything local and scriptable—ideal for CI, cron, and headless servers.
Prerequisites
We’ll rely on:
GNU time for reproducible timing
sysstat (pidstat) for sampling
jq for JSON handling
GNU parallel for concurrency
pigz for a real-world example
Python 3 with pip for ML utilities
Install with your package manager:
- apt (Debian/Ubuntu):
sudo apt update
sudo apt install -y python3 python3-pip jq sysstat parallel pigz time
- dnf (Fedora/RHEL):
sudo dnf install -y python3 python3-pip jq sysstat parallel pigz time
- zypper (openSUSE):
sudo zypper refresh
sudo zypper install -y python3 python3-pip jq sysstat parallel pigz time
Python packages (user install; no root needed):
python3 -m pip install --user pandas scikit-learn optuna joblib
Add user-level scripts to your PATH if needed:
export PATH="$HOME/.local/bin:$PATH"
1) Instrument your Bash processes with lightweight metrics
Start capturing consistent metrics for every long-running command. Here’s a drop-in wrapper that logs elapsed time, CPU time, and max RSS (KB) as JSON Lines. It uses GNU time’s format to keep parsing simple.
Save as run_with_metrics.sh:
#!/usr/bin/env bash
set -euo pipefail
METRICS_FILE="${METRICS_FILE:-metrics.jsonl}"
TAG="${TAG:-}"
SIZE="${SIZE:-}" # optional input size (bytes) if you know it
if [[ $# -lt 1 ]]; then
echo "Usage: TAG=foo SIZE=1234 METRICS_FILE=metrics.jsonl $0 '<command>'" >&2
exit 1
fi
CMD="$1"
TMP="$(mktemp)"
START_TS="$(date -Is)"
# Measure: elapsed (%e), user (%U), sys (%S), max RSS in KB (%M)
# Note: we capture exit code separately
set +e
/usr/bin/time -f "%e %U %S %M" -o "$TMP" bash -c "$CMD"
EXIT_CODE=$?
set -e
read -r ELAPSED USER_S SYS_S MAX_RSS_KB < "$TMP"
rm -f "$TMP"
# Build JSON line (avoid jq requirement for generation)
printf '{"ts":"%s","tag":"%s","cmd":%s,"elapsed":%s,"user_s":%s,"sys_s":%s,"max_rss_kb":%s,"exit":%d,"size":%s}\n' \
"$START_TS" "$TAG" "$(printf %s "$CMD" | python3 -c 'import json,sys; print(json.dumps(sys.stdin.read()))')" \
"$ELAPSED" "$USER_S" "$SYS_S" "$MAX_RSS_KB" "$EXIT_CODE" "${SIZE:-null}" >> "$METRICS_FILE"
exit "$EXIT_CODE"
Example usage:
# Compress a file and log metrics
TAG=compress SIZE=$(stat -c%s bigfile.dat) ./run_with_metrics.sh 'pigz -p 4 -9 -k bigfile.dat'
Optional: Sample per-second CPU and memory of a live PID with pidstat (from sysstat):
# Run a job in background, sample it for 10s
my_job &
PID=$!
pidstat -h -r -u -p "$PID" 1 10
wait "$PID"
Now you have a growing metrics.jsonl you can query with jq:
jq -r '[.tag,.elapsed,.max_rss_kb] | @tsv' metrics.jsonl | column -t
2) Catch regressions with a simple anomaly detector
Use your metrics to automatically flag “weird” runs (too slow, too memory-hungry) before they bite you in production.
Save as detect_anomalies.py:
#!/usr/bin/env python3
import sys, json
import pandas as pd
from sklearn.ensemble import IsolationForest
if len(sys.argv) < 2:
print("Usage: detect_anomalies.py metrics.jsonl", file=sys.stderr)
sys.exit(1)
df = pd.read_json(sys.argv[1], lines=True)
# Feature engineering
for c in ("elapsed","user_s","sys_s","max_rss_kb","size"):
if c not in df.columns:
df[c] = 0.0
X = df[["elapsed","user_s","sys_s","max_rss_kb","size"]].fillna(0)
# Train a quick unsupervised model
model = IsolationForest(n_estimators=200, contamination=0.05, random_state=42)
model.fit(X)
scores = model.decision_function(X)
pred = model.predict(X) # -1 = anomaly
df["anomaly_score"] = scores
df["is_anomaly"] = (pred == -1)
anoms = df[df["is_anomaly"]].sort_values("anomaly_score")
cols = ["ts","tag","cmd","elapsed","max_rss_kb","anomaly_score"]
print(anoms[cols].to_string(index=False))
Run it:
python3 detect_anomalies.py metrics.jsonl
Schedule it in cron or CI to fail fast when a job regresses.
3) Predict runtimes to schedule smarter
If you know (or can infer) features like input size and thread count, you can learn a runtime predictor to:
Sort short jobs first to reduce tail latency
Balance long and short tasks across cores
Estimate SLA adherence before running
Train a regression model and save it:
Save as train_runtime_model.py:
#!/usr/bin/env python3
import sys
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestRegressor
from joblib import dump
if len(sys.argv) < 3:
print("Usage: train_runtime_model.py metrics.jsonl model.joblib", file=sys.stderr)
sys.exit(1)
df = pd.read_json(sys.argv[1], lines=True)
df = df[df["exit"] == 0] # only successful runs
# Minimal features; add more from your domain (flags, data type, etc.)
for c in ("size","max_rss_kb","user_s","sys_s"):
if c not in df: df[c] = 0.0
X = df[["size","max_rss_kb","user_s","sys_s"]].fillna(0)
y = df["elapsed"]
Xtr, Xte, ytr, yte = train_test_split(X, y, test_size=0.2, random_state=42)
model = RandomForestRegressor(n_estimators=300, random_state=42, n_jobs=-1)
model.fit(Xtr, ytr)
print("R^2 test:", model.score(Xte, yte))
dump(model, sys.argv[2])
Predict durations for upcoming tasks and schedule them:
Save as predict_and_schedule.py:
#!/usr/bin/env python3
import sys, json
import pandas as pd
from joblib import load
import subprocess, shlex
if len(sys.argv) < 3:
print("Usage: predict_and_schedule.py model.joblib tasks.tsv", file=sys.stderr)
print("tasks.tsv format: size<TAB>command", file=sys.stderr)
sys.exit(1)
model = load(sys.argv[1])
tasks = pd.read_csv(sys.argv[2], sep="\t", names=["size","cmd"])
tasks["max_rss_kb"] = 0
tasks["user_s"] = 0
tasks["sys_s"] = 0
X = tasks[["size","max_rss_kb","user_s","sys_s"]]
tasks["pred_s"] = model.predict(X)
# Shortest-job-first as a simple heuristic to reduce makespan tail
tasks = tasks.sort_values("pred_s")
# Run in parallel across all cores; tag and log
commands = tasks["cmd"].tolist()
parallel = ["parallel","-j","0","--eta","--joblog","joblog.tsv","--tagstring","{=1 $_=q{} =}"]
subprocess.run(parallel + ["bash","-lc","{}"], input=("\n".join(commands)).encode(), check=True)
Example tasks file:
# tasks.tsv
104857600 pigz -p 4 -9 -k data/part-001
209715200 pigz -p 4 -9 -k data/part-002
...
This tiny loop—predict, sort, parallelize—often improves utilization and lowers total wall time without touching your core logic.
4) Auto-tune CLI parameters with Bayesian optimization
Stop guessing flags. Use search. Here we tune pigz’s thread count and compression level to minimize elapsed time while respecting a memory cap.
Save as tune_pigz.py:
#!/usr/bin/env python3
import os, sys, shlex, subprocess
import optuna
if len(sys.argv) < 3:
print("Usage: tune_pigz.py INPUT_FILE N_TRIALS", file=sys.stderr)
sys.exit(1)
INPUT = sys.argv[1]
N_TRIALS = int(sys.argv[2])
MEM_CAP_KB = int(os.environ.get("MEM_CAP_KB", "2097152")) # 2 GiB default
def run_timed(cmd):
# Capture elapsed secs (%e) and max RSS KB (%M)
time_fmt = "%e %M"
res = subprocess.run(
["/usr/bin/time","-f",time_fmt,"-o","/dev/stdout","bash","-lc",cmd],
stdout=subprocess.PIPE, stderr=subprocess.STDOUT, check=True, text=True
)
elapsed, maxrss = res.stdout.strip().split()
return float(elapsed), int(maxrss)
def objective(trial):
threads = trial.suggest_int("threads", 1, max(1, os.cpu_count() or 1))
level = trial.suggest_int("level", 1, 9)
# Use -k to keep input; send output to /dev/null to avoid disk skew
cmd = f"pigz -p {threads} -{level} -c {shlex.quote(INPUT)} > /dev/null"
elapsed, maxrss = run_timed(cmd)
# Penalize memory over cap
penalty = 0.0 if maxrss <= MEM_CAP_KB else (maxrss - MEM_CAP_KB) / MEM_CAP_KB
return elapsed * (1.0 + penalty)
study = optuna.create_study(direction="minimize")
study.optimize(objective, n_trials=N_TRIALS)
print("Best params:", study.best_params)
print("Best objective (sec):", study.best_value)
Run it:
# Optional: cap memory to 2 GiB
export MEM_CAP_KB=$((2*1024*1024))
python3 tune_pigz.py bigfile.dat 30
Use the best params in production, and re-tune when hardware or data patterns change.
5) A simple, real-world arc: compress faster, safer
- Baseline:
TAG=compress_baseline SIZE=$(stat -c%s bigfile.dat) \
./run_with_metrics.sh 'pigz -p 4 -9 -k bigfile.dat'
- Tune:
python3 tune_pigz.py bigfile.dat 30
# Suppose it suggests: -p 8 -7
- Deploy tuned flags, keep logging:
TAG=compress_tuned SIZE=$(stat -c%s bigfile.dat) \
./run_with_metrics.sh 'pigz -p 8 -7 -k bigfile.dat'
- Detect regressions automatically:
python3 detect_anomalies.py metrics.jsonl
- Predict and schedule multiple files for nightly batch:
# Build tasks.tsv automatically
find data -type f -name 'part-*' -printf '%s\tpigz -p 8 -7 -k %p\n' > tasks.tsv
python3 train_runtime_model.py metrics.jsonl model.joblib
python3 predict_and_schedule.py model.joblib tasks.tsv
This loop gives you measurable speedups, fast feedback on regressions, and smarter use of cores.
Conclusion and next steps (CTA)
You don’t need a massive ML stack to optimize your shell workflows:
Start today by wrapping your long-running commands with
run_with_metrics.sh.Add a weekly or per-commit anomaly check to catch regressions early.
Train a simple runtime model and schedule jobs shortest-first for better utilization.
Replace flag guessing with a small tuning harness and re-run it when workloads shift.
Pick one pipeline this week, add metrics, and run the anomaly detector. Once you see the first “aha,” fold in prediction and tuning. Your Bash scripts will feel a lot faster—because they are.