Un serviciu care creează și șterge mii de fișiere temporare poate petrece timp în kernel chiar dacă aplicația nu pare limitată de memorie. Fiecare operație antrenează obiecte precum dentries și inode-uri, iar costul gestionării lor devine vizibil când mai multe procesoare lucrează simultan.
În acest laborator construim un workload local care creează, inspectează și șterge fișiere pe tmpfs. Îl rulăm o dată cu un singur worker și o dată cu până la opt workeri, în timp ce perf kmem înregistrează alocările din slab, iar /proc/slabinfo păstrează starea cache-urilor înainte și după fiecare probă.
Rezultatul verificabil este un director cu două execuții, rapoarte perf kmem, instantanee slabinfo, un tabel cu throughput-ul aplicației și cache-urile care și-au schimbat cel mai mult numărul de obiecte. Adăugăm și un timer systemd care înregistrează periodic starea cache-urilor VFS în journal.
Laboratorul nu promite un anumit procent de accelerare și nu încearcă să atribuie automat orice diferență mecanismului sheaves. El arată unde apar alocările mici, cât de mult se schimbă comportamentul sub concurență și ce dovezi trebuie strânse înainte de a considera allocatorul o cauză reală.
De la freelist-ul unui CPU la două sheaves și un barn NUMA
SLUB gestionează obiectele kernelului în cache-uri specializate. Un cache conține obiecte de aceeași dimensiune și evită costul tratării fiecărei alocări ca pe o cerere complet nouă de pagini.
Sheaves adaugă cache-uri bazate pe array-uri de pointeri. Fiecare CPU are o sheaf principală și poate avea una de rezervă. Când acestea nu mai pot satisface cererea, allocatorul poate schimba o sheaf goală cu una plină păstrată într-un „barn” asociat nodului NUMA. La eliberare, traseul este invers: obiectele pot rămâne aproape de CPU înainte ca allocatorul să ajungă la structurile comune.
Miza nu este doar numărul de instrucțiuni. Pentru workload-uri cu multe obiecte mici, accesarea repetată a structurilor partajate poate genera contention și trafic între cache-urile procesoarelor. Păstrarea unor loturi de obiecte lângă CPU reduce frecvența acestor trasee lente.
Sheaves au fost introduse în Linux 6.18. Începând cu Linux 7.0, seria de modificări a activat mecanismul pentru cache-urile slab obișnuite, cu excepția cache-urilor bootstrap kmem_cache și kmem_cache_node. Documentația API precizează și două limite relevante:
- operațiile bulk încearcă sheaves și barn, dar pot reveni la paginile slab;
- dacă debugging-ul SLUB este activ pentru un cache, parametrul
sheaf_capacityeste ignorat, iar traseul optimizat nu reprezintă comportamentul normal.
Sheaves nu rezolvă presiunea pe page cache și nu înlocuiesc algoritmii de reclaim. Dacă investigația arată major faults, scanare agresivă sau thrashing, continuarea logică este analiza generațiilor de pagini cu Multi-Gen LRU, nu modificarea presupunerilor despre slab.
Blocăm laboratorul la Fedora 44 și kernelul Linux 7.0
Varianta de mai jos folosește:
- Fedora Linux 44;
- kernel Linux 7.0.x, pe arhitectură
x86_64; - implementarea SLUB;
perfconstruit pentru kernelul instalat;- Python 3;
- minimum două procesoare logice, 2 GB RAM și 1 GB liber;
- aproximativ 30–60 de minute.
Rulați întâi verificările. Nu continuați pe un sistem de producție: proba creează și șterge intensiv fișiere, iar înregistrarea tracepoint-urilor adaugă overhead.
cat /etc/os-release
uname -r
uname -m
getconf _NPROCESSORS_ONLN
free -h
df -h /var/tmp
python3 --version
perf --version
grep '^CONFIG_SLUB=y' "/boot/config-$(uname -r)"
test -r /proc/slabinfo && head -n 2 /proc/slabinfo
test -d /sys/kernel/slab && printf 'sysfs slab: disponibiln'
Output-ul trebuie să confirme Fedora 44, un kernel care începe cu 7.0., arhitectura x86_64, CONFIG_SLUB=y și existența interfețelor slab. Numerele exacte pentru memorie, spațiu și versiunea Python pot diferi.
NAME="Fedora Linux"
VERSION_ID="44"
7.0.x-...
x86_64
...
CONFIG_SLUB=y
slabinfo - version: 2.1
sysfs slab: disponibil
Dacă uname -r nu indică 7.0.x, opriți laboratorul sau tratați rezultatul ca test pentru allocatorul versiunii instalate, nu ca validare a configurației descrise aici. Pentru a verifica opțiunile active, folosiți configurația kernelului și documentația corespunzătoare acelei versiuni.
Instalarea este scurtă. Pachetul perf furnizează instrumentul de trasare, iar python3 execută workload-ul și raportul.
sudo dnf install -y perf python3
sudo install -d -m 0755 /opt/slub-sheaves-lab
sudo useradd --system --home-dir /var/lib/slublab
--create-home --shell /usr/sbin/nologin slublab 2>/dev/null || true
sudo install -d -o slublab -g slublab -m 0700 /var/lib/slublab/work
slublab nu primește shell interactiv. Workload-ul va rula cu acest utilizator, în timp ce numai capturarea perf și citirea completă a /proc/slabinfo vor folosi privilegiile necesare.
Cinci fișiere separă încărcarea, măsurarea și supravegherea
La final, proiectul are această structură:
/opt/slub-sheaves-lab/
├── workload.py # creează, inspectează și șterge fișiere pe tmpfs
├── run-lab.sh # rulează probele single și parallel sub perf kmem
├── report.py # compară throughput-ul și instantaneele slabinfo
├── slab-watch.sh # trimite în journal starea cache-urilor VFS
└── install-monitor.sh # instalează serviciul și timerul systemd
Rezultatele apar separat:
/var/lib/slublab/results/
├── single/
│ ├── before.slabinfo
│ ├── after.slabinfo
│ ├── perf.data
│ ├── kmem-stat.txt
│ └── result.json
├── parallel/
│ └── ...
└── comparison.txt
Fișierele perf.data pot conține simboluri, nume de procese și detalii despre kernel. Nu le publicați ca atare; păstrați numai agregatele necesare investigației.
Pasul 1 — Generăm churn VFS controlat pe un tmpfs privat
Workload-ul folosește directoare distincte pentru fiecare worker. Fiecare operație creează un fișier nou, scrie 64 de octeți, apelează stat() și îl șterge. Astfel evităm concurența artificială pe același nume de fișier, dar păstrăm presiunea asupra obiectelor VFS mici.
Fișierul /opt/slub-sheaves-lab/workload.py:
#!/usr/bin/env python3
import argparse
import json
import os
import shutil
import sys
import threading
import time
from pathlib import Path
PAYLOAD = b"x" * 64
def run_worker(worker_id: int, operations: int, root: Path,
barrier: threading.Barrier, errors: list[str]) -> None:
worker_dir = root / f"worker-{worker_id}"
worker_dir.mkdir(mode=0o700, parents=True, exist_ok=True)
try:
barrier.wait()
for sequence in range(operations):
path = worker_dir / f"object-{sequence:08d}"
fd = os.open(path, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o600)
try:
written = os.write(fd, PAYLOAD)
if written != len(PAYLOAD):
raise OSError(
f"scriere incompletă: {written}/{len(PAYLOAD)}"
)
finally:
os.close(fd)
metadata = os.stat(path, follow_symlinks=False)
if metadata.st_size != len(PAYLOAD):
raise OSError(
f"dimensiune neașteptată pentru {path}: "
f"{metadata.st_size}"
)
os.unlink(path)
except Exception as exc:
errors.append(f"worker {worker_id}: {exc}")
def main() -> int:
parser = argparse.ArgumentParser(
description="Workload local pentru alocări VFS mici"
)
parser.add_argument("--workers", type=int, required=True)
parser.add_argument("--operations-per-worker", type=int, required=True)
parser.add_argument("--root", type=Path, required=True)
args = parser.parse_args()
if args.workers < 1 or args.workers > 8:
parser.error("--workers trebuie să fie între 1 și 8")
if args.operations_per_worker < 1:
parser.error("--operations-per-worker trebuie să fie pozitiv")
args.root.mkdir(mode=0o700, parents=True, exist_ok=True)
for child in args.root.iterdir():
if child.is_dir() and child.name.startswith("worker-"):
shutil.rmtree(child)
barrier = threading.Barrier(args.workers)
errors: list[str] = []
threads = [
threading.Thread(
target=run_worker,
args=(
worker_id,
args.operations_per_worker,
args.root,
barrier,
errors,
),
name=f"slub-worker-{worker_id}",
)
for worker_id in range(args.workers)
]
started = time.perf_counter()
for thread in threads:
thread.start()
for thread in threads:
thread.join()
elapsed = time.perf_counter() - started
if errors:
for error in errors:
print(error, file=sys.stderr)
return 1
total_operations = args.workers * args.operations_per_worker
result = {
"workers": args.workers,
"operations_per_worker": args.operations_per_worker,
"total_operations": total_operations,
"elapsed_seconds": round(elapsed, 6),
"operations_per_second": round(total_operations / elapsed, 2),
}
print(json.dumps(result, sort_keys=True))
return 0
if __name__ == "__main__":
raise SystemExit(main())
Instalați permisiunile:
sudo chown root:root /opt/slub-sheaves-lab/workload.py
sudo chmod 0755 /opt/slub-sheaves-lab/workload.py
sudo -u slublab python3 /opt/slub-sheaves-lab/workload.py
--workers 1
--operations-per-worker 10
--root /var/lib/slublab/work/smoke
Opțiunea O_EXCL transformă o coliziune de nume într-o eroare, în loc să suprascrie un fișier. follow_symlinks=False împiedică urmărirea accidentală a unei legături simbolice. Limita de opt workeri păstrează laboratorul predictibil pe o stație obișnuită.
Output-ul de smoke test are forma:
{"elapsed_seconds": (valoare măsurată), "operations_per_second": (valoare măsurată), "operations_per_worker": 10, "total_operations": 10, "workers": 1}
Punct de control: dacă apare scriere incompletă, dimensiune neașteptată sau un worker rămâne blocat, verificați mai întâi montarea și spațiul disponibil pentru /var/lib/slublab/work.
Pasul 2 — Capturăm aceleași evenimente pentru un worker și pentru opt
Scriptul următor creează un tmpfs de 512 MB, rulează 50.000 de operații per worker și păstrează probele în directoare distincte. Numărul probei paralele este minimul dintre procesoarele online și opt.
Avertisment: montarea și demontarea schimbă starea sistemului. Confirmați că /var/lib/slublab/work este dedicat laboratorului și nu conține alte date.
Fișierul /opt/slub-sheaves-lab/run-lab.sh:
#!/usr/bin/env bash
set -euo pipefail
BASE=/opt/slub-sheaves-lab
WORK=/var/lib/slublab/work
RESULTS=/var/lib/slublab/results
OPERATIONS=50000
if [[ ${EUID} -ne 0 ]]; then
printf 'Rulați scriptul cu sudo.n' >&2
exit 1
fi
grep -q '^CONFIG_SLUB=y' "/boot/config-$(uname -r)" || {
printf 'Kernelul activ nu confirmă CONFIG_SLUB=y.n' >&2
exit 1
}
perf kmem --help >/dev/null 2>&1 || {
printf 'perf kmem nu este disponibil pentru kernelul activ.n' >&2
exit 1
}
install -d -o slublab -g slublab -m 0700 "$WORK"
install -d -o root -g root -m 0700 "$RESULTS"
if ! mountpoint -q "$WORK"; then
mount -t tmpfs -o size=512M,mode=0700,uid="$(id -u slublab)",gid="$(id -g slublab)"
slublab-tmpfs "$WORK"
fi
online_cpus=$(getconf _NPROCESSORS_ONLN)
parallel_workers=$online_cpus
if (( parallel_workers > 8 )); then
parallel_workers=8
fi
if (( parallel_workers < 2 )); then
printf 'Sunt necesare cel puțin două procesoare logice.n' >&2
exit 1
fi
run_case() {
local label=$1
local workers=$2
local case_dir="$RESULTS/$label"
local case_work="$WORK/$label"
rm -rf "$case_dir" "$case_work"
install -d -o root -g root -m 0700 "$case_dir"
install -d -o slublab -g slublab -m 0700 "$case_work"
cat /proc/slabinfo >"$case_dir/before.slabinfo"
(
cd "$case_dir"
perf kmem record --slab --
runuser -u slublab --
python3 "$BASE/workload.py"
--workers "$workers"
--operations-per-worker "$OPERATIONS"
--root "$case_work"
>result.json
perf kmem stat --slab >kmem-stat.txt
)
cat /proc/slabinfo >"$case_dir/after.slabinfo"
sync
}
run_case single 1
run_case parallel "$parallel_workers"
python3 "$BASE/report.py" "$RESULTS" | tee "$RESULTS/comparison.txt"
printf 'Rezultate: %sn' "$RESULTS"
Activați fișierul, fără a-l porni încă:
sudo chown root:root /opt/slub-sheaves-lab/run-lab.sh
sudo chmod 0750 /opt/slub-sheaves-lab/run-lab.sh
perf kmem record --slab selectează evenimentele allocatorului slab și rulează comanda aflată după --. runuser coboară privilegiile pentru workload. Numai instrumentul care configurează trasarea și citește datele rulează ca root.
După execuție, fiecare caz trebuie să conțină cinci fișiere:
after.slabinfo
before.slabinfo
kmem-stat.txt
perf.data
result.json
Punct de control: dacă lipsește perf.data, nu interpretați slabinfo ca înlocuitor pentru trasare. Verificați imediat disponibilitatea evenimentelor prin sudo perf list 'kmem:*'.
Pasul 3 — Transformăm snapshot-urile slab într-un raport comparabil
/proc/slabinfo include numărul obiectelor active, numărul total al obiectelor și dimensiunea unui obiect. Scriptul de raportare calculează schimbarea dintre cele două instantanee și afișează primele zece cache-uri după diferența absolută estimată în octeți.
Fișierul /opt/slub-sheaves-lab/report.py:
#!/usr/bin/env python3
import argparse
import json
from pathlib import Path
def read_json(path: Path) -> dict:
try:
return json.loads(path.read_text(encoding="utf-8"))
except (OSError, json.JSONDecodeError) as exc:
raise SystemExit(f"Nu pot citi {path}: {exc}") from exc
def read_slabinfo(path: Path) -> dict[str, tuple[int, int, int]]:
caches: dict[str, tuple[int, int, int]] = {}
try:
lines = path.read_text(encoding="utf-8").splitlines()
except OSError as exc:
raise SystemExit(f"Nu pot citi {path}: {exc}") from exc
for line in lines:
if not line or line.startswith(("slabinfo", "#")):
continue
fields = line.split()
if len(fields) < 4:
continue
name = fields[0]
try:
active = int(fields[1])
total = int(fields[2])
object_size = int(fields[3])
except ValueError:
continue
caches[name] = (active, total, object_size)
return caches
def cache_deltas(before_path: Path, after_path: Path) -> list[tuple]:
before = read_slabinfo(before_path)
after = read_slabinfo(after_path)
rows = []
for name in sorted(before.keys() | after.keys()):
before_active, before_total, before_size = before.get(name, (0, 0, 0))
after_active, after_total, after_size = after.get(name, (0, 0, 0))
object_size = after_size or before_size
active_delta = after_active - before_active
total_delta = after_total - before_total
byte_delta = total_delta * object_size
rows.append(
(
abs(byte_delta),
name,
active_delta,
total_delta,
object_size,
byte_delta,
)
)
rows.sort(reverse=True)
return rows[:10]
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument("results", type=Path)
args = parser.parse_args()
cases = {}
for label in ("single", "parallel"):
case_dir = args.results / label
cases[label] = read_json(case_dir / "result.json")
print("Throughput observat")
print("===================")
for label in ("single", "parallel"):
result = cases[label]
print(
f"{label:8s} workers={result['workers']} "
f"operații={result['total_operations']} "
f"secunde={result['elapsed_seconds']} "
f"operații/s={result['operations_per_second']}"
)
print()
print("Schimbările principale din slabinfo")
print("===================================")
for label in ("single", "parallel"):
case_dir = args.results / label
print()
print(f"[{label}]")
print(
f"{'cache':30s} {'activeΔ':>12s} {'objectsΔ':>12s} "
f"{'size':>8s} {'bytesΔ':>14s}"
)
for _, name, active_delta, total_delta, size, byte_delta in cache_deltas(
case_dir / "before.slabinfo",
case_dir / "after.slabinfo",
):
print(
f"{name[:30]:30s} {active_delta:12d} {total_delta:12d} "
f"{size:8d} {byte_delta:14d}"
)
return 0
if __name__ == "__main__":
raise SystemExit(main())
Instalați și rulați laboratorul:
sudo chown root:root /opt/slub-sheaves-lab/report.py
sudo chmod 0755 /opt/slub-sheaves-lab/report.py
sudo /opt/slub-sheaves-lab/run-lab.sh
Raportul va conține valorile măsurate local, nu valori prestabilite:
Throughput observat
===================
single workers=1 operații=50000 secunde=... operații/s=...
parallel workers=... operații=... secunde=... operații/s=...
Schimbările principale din slabinfo
===================================
[single]
cache activeΔ objectsΔ size bytesΔ
...
objectsΔ nu reprezintă numărul total de alocări. Este diferența dintre două instantanee și poate fi mică deoarece obiectele au fost eliberate sau păstrate pentru reutilizare. Pentru volumul evenimentelor folosiți kmem-stat.txt; pentru starea rezidentă folosiți slabinfo.
Punct de control: dacă result.json este valid, dar raportul nu arată nicio schimbare, verificați kmem-stat.txt. Un allocator care reutilizează eficient obiectele poate procesa multe evenimente fără o creștere persistentă a cache-ului.
Pasul 4 — Citim probele fără să atribuim orice diferență mecanismului sheaves
Deschideți rapoartele agregate:
sudo sed -n '1,120p' /var/lib/slublab/results/single/kmem-stat.txt
sudo sed -n '1,120p' /var/lib/slublab/results/parallel/kmem-stat.txt
sudo cat /var/lib/slublab/results/comparison.txt
sudo grep -E '^(dentry|inode_cache|xfs_inode|ext4_inode_cache|shmem_inode_cache) '
/var/lib/slublab/results/parallel/after.slabinfo || true
Citiți rezultatul în această ordine:
- Confirmați în
result.jsoncă ambele probe s-au terminat și că numărul total de operații este corect. - Comparați rata
operations_per_second, dar nu considerați automat proba cu mai mulți workeri mai eficientă. Ea execută și mai multe operații totale. - Examinați
kmem-stat.txtpentru distribuția și volumul alocărilor slab. - Folosiți
slabinfopentru a vedea ce cache-uri au rămas mărite după probă. - Repetați laboratorul de trei ori dacă luați o decizie operațională; zgomotul schedulerului, frecvența CPU și activitatea altor servicii pot schimba rezultatele.
Sheaves sunt relevante când rata mare de alocare și eliberare întâlnește concurență între procesoare. Laboratorul confirmă condițiile, nu demonstrează singur că un anumit procent de timp a fost economisit de sheaves. Pentru contention explicit în lock-uri, completați investigația cu măsurarea mutex-urilor și spinlock-urilor prin perf lock. Pentru latențe apărute într-un traseu kernel concret, folosiți separat function_graph tracer din ftrace.
Punct de control: dacă throughput-ul scade în proba paralelă, verificați CPU saturation și rezultatul perf kmem înainte de a concluziona că SLUB este problema. Limitarea poate fi în tmpfs, VFS, scheduler sau instrumentarea însăși.
Pasul 5 — Înregistrăm periodic cache-urile VFS în journal
Monitorul nu pornește un benchmark. El citește trei cache-uri relevante și scrie o singură intrare structurată în journal, pentru a putea corela ulterior creșterile persistente cu activitatea serviciului.
Fișierul /opt/slub-sheaves-lab/slab-watch.sh:
#!/usr/bin/env bash
set -euo pipefail
SLABINFO=/proc/slabinfo
if [[ ! -r "$SLABINFO" ]]; then
logger -p daemon.warning -t slub-sheaves-monitor
'slabinfo_readable=no'
exit 1
fi
for cache in dentry inode_cache shmem_inode_cache; do
line=$(awk -v wanted="$cache" '$1 == wanted {print; exit}' "$SLABINFO")
if [[ -n "$line" ]]; then
active=$(awk '{print $2}' <<<"$line")
total=$(awk '{print $3}' <<<"$line")
object_size=$(awk '{print $4}' <<<"$line")
logger -p daemon.info -t slub-sheaves-monitor
"cache=$cache active=$active total=$total object_size=$object_size"
else
logger -p daemon.notice -t slub-sheaves-monitor
"cache=$cache present=no"
fi
done
Fișierul /opt/slub-sheaves-lab/install-monitor.sh:
#!/usr/bin/env bash
set -euo pipefail
SERVICE=/etc/systemd/system/slub-sheaves-monitor.service
TIMER=/etc/systemd/system/slub-sheaves-monitor.timer
STAMP=$(date +%Y%m%d%H%M%S)
if [[ ${EUID} -ne 0 ]]; then
printf 'Rulați scriptul cu sudo.n' >&2
exit 1
fi
for file in "$SERVICE" "$TIMER"; do
if [[ -e "$file" ]]; then
cp --archive "$file" "$file.bak.$STAMP"
fi
done
cat >"$SERVICE" <<'EOF'
[Unit]
Description=Monitorizare agregată a cache-urilor SLUB pentru laborator
[Service]
Type=oneshot
ExecStart=/opt/slub-sheaves-lab/slab-watch.sh
User=root
Group=root
NoNewPrivileges=yes
PrivateTmp=yes
ProtectHome=yes
ProtectSystem=strict
ProtectKernelModules=yes
ProtectKernelLogs=yes
ProtectKernelTunables=yes
RestrictAddressFamilies=AF_UNIX
LockPersonality=yes
MemoryDenyWriteExecute=yes
EOF
cat >"$TIMER" <<'EOF'
[Unit]
Description=Citire periodică a cache-urilor SLUB
[Timer]
OnBootSec=2min
OnUnitActiveSec=5min
AccuracySec=30s
Persistent=true
Unit=slub-sheaves-monitor.service
[Install]
WantedBy=timers.target
EOF
systemctl daemon-reload
systemctl enable --now slub-sheaves-monitor.timer
systemctl start slub-sheaves-monitor.service
systemctl --no-pager --full status slub-sheaves-monitor.timer
Instalați fișierele:
sudo chown root:root
/opt/slub-sheaves-lab/slab-watch.sh
/opt/slub-sheaves-lab/install-monitor.sh
sudo chmod 0750
/opt/slub-sheaves-lab/slab-watch.sh
/opt/slub-sheaves-lab/install-monitor.sh
sudo /opt/slub-sheaves-lab/install-monitor.sh
Serviciul rămâne oneshot, nu ascultă pe rețea și nu scrie fișiere proprii. Retenția este gestionată de systemd-journald, conform politicii deja stabilite pe server.
Output-ul timerului trebuie să arate starea active (waiting):
Active: active (waiting)
Trigger: ...
Triggers: ● slub-sheaves-monitor.service
Punct de control: dacă unitatea eșuează, citiți imediat journalctl -u slub-sheaves-monitor.service -b; nu eliminați opțiunile de izolare înainte de a identifica exact accesul refuzat.
Testul de capăt leagă workload-ul, evenimentele kmem și timerul
Executați verificarea completă:
sudo test -s /var/lib/slublab/results/single/result.json
sudo test -s /var/lib/slublab/results/parallel/result.json
sudo test -s /var/lib/slublab/results/single/perf.data
sudo test -s /var/lib/slublab/results/parallel/perf.data
sudo test -s /var/lib/slublab/results/comparison.txt
sudo grep -q 'Throughput observat'
/var/lib/slublab/results/comparison.txt
sudo systemctl is-active slub-sheaves-monitor.timer
sudo systemctl start slub-sheaves-monitor.service
sudo journalctl -t slub-sheaves-monitor -n 6 --no-pager
Rezultatul final trebuie să includă active pentru timer și intrări cu câmpurile cache, active, total și object_size:
active
... slub-sheaves-monitor[...] cache=dentry active=... total=... object_size=...
... slub-sheaves-monitor[...] cache=inode_cache active=... total=... object_size=...
... slub-sheaves-monitor[...] cache=shmem_inode_cache active=... total=... object_size=...
Valorile sunt intenționat lăsate ca rezultate locale: depind de kernel, numărul de CPU-uri și activitatea mașinii. Criteriul reproductibil este existența celor două capturi, numărul fix de operații, raportul generat și monitorizarea periodică funcțională.
Cinci erori care indică exact componenta ruptă
invalid or unsupported event: 'kmem:...'
perf kmem nu găsește tracepoint-urile necesare sau tracefs nu este montat. Verificați evenimentele și montarea:
sudo perf list 'kmem:*'
mountpoint /sys/kernel/tracing ||
sudo mount -t tracefs tracefs /sys/kernel/tracing
Dacă lista rămâne goală, kernelul activ nu oferă configurația necesară acestui laborator.
No kallsyms or vmlinux with build-id ... was found
Captura există, dar rezolvarea simbolurilor este incompletă. Raportul agregat poate fi încă util, însă analiza apelanților nu este sigură. Instalați pachetele de debugging corespunzătoare exact kernelului activ sau limitați concluziile la cache-uri și numărul evenimentelor.
uname -r
sudo dnf debuginfo-install "kernel-core-$(uname -r)"
Error: failed to open /proc/slabinfo
Citirea completă este restricționată utilizatorului curent. Runnerul și serviciul sunt proiectate să ruleze cu sudo, în timp ce workload-ul coboară la utilizatorul slublab.
sudo test -r /proc/slabinfo
sudo head -n 2 /proc/slabinfo
Nu relaxați permisiunile pentru /proc/slabinfo.
perf.data file has no samples!
Workload-ul nu a produs evenimente observabile, înregistrarea s-a oprit prea devreme sau kernelul nu expune tracepoint-urile așteptate. Confirmați mai întâi că proba a executat operațiile și repetați numai cazul defect:
sudo cat /var/lib/slublab/results/single/result.json
sudo rm -rf /var/lib/slublab/results/single
sudo /opt/slub-sheaves-lab/run-lab.sh
mount: /var/lib/slublab/work: mount point is busy
A rămas o montare de la o rulare anterioară sau un proces ține deschis un fișier. Identificați procesul înainte de demontare:
sudo findmnt /var/lib/slublab/work
sudo fuser -vm /var/lib/slublab/work
Opriți procesul legitim care folosește directorul, apoi demontați normal. Nu folosiți demontarea forțată ca primă soluție.
Eliminăm laboratorul fără să lăsăm timerul sau tmpfs-ul active
Avertisment: comenzile următoare șterg toate rezultatele din /var/lib/slublab. Confirmați că directorul aparține exclusiv laboratorului.
sudo systemctl disable --now slub-sheaves-monitor.timer
sudo systemctl stop slub-sheaves-monitor.service 2>/dev/null || true
sudo rm -f
/etc/systemd/system/slub-sheaves-monitor.service
/etc/systemd/system/slub-sheaves-monitor.timer
sudo systemctl daemon-reload
sudo systemctl reset-failed
if mountpoint -q /var/lib/slublab/work; then
sudo umount /var/lib/slublab/work
fi
sudo rm -rf /opt/slub-sheaves-lab
sudo rm -rf /var/lib/slublab
sudo userdel slublab 2>/dev/null || true
Dacă installerul a creat copii precum slub-sheaves-monitor.service.bak.<timestamp>, restaurați copia dorită numai după verificarea conținutului și apoi rulați sudo systemctl daemon-reload.
Bifele care confirmă că măsurarea este utilizabilă
- ☐ Kernelul activ este Linux 7.0.x și are
CONFIG_SLUB=y. - ☐
perf list 'kmem:*'arată evenimentele allocatorului. - ☐ Workload-ul rulează ca utilizatorul dedicat
slublab. - ☐ Directorul de lucru este un
tmpfsseparat de datele aplicațiilor. - ☐ Cazurile
singleșiparallelau fiecare unperf.datanenul. - ☐ Fiecare
result.jsonconține numărul complet de operații. - ☐
kmem-stat.txtprovine din captura cazului corespunzător. - ☐
comparison.txtinclude throughput-ul și diferențele slabinfo. - ☐ Timerul este
active (waiting), iar journalul conține valorile cache-urilor. - ☐ Nicio concluzie despre sheaves nu se bazează doar pe diferența de throughput.
Următorul proiect logic este repetarea acelorași două probe cu workload-ul real într-o fereastră controlată, păstrând aceeași durată și aceeași afinitate CPU. Dacă memoria slab crește fără să revină după oprirea traficului, separați retenția legitimă de un defect cu kmemleak și validarea alarmelor false. Dacă obiectele se eliberează, dar latența rămâne ridicată, urmăriți traseul lent și contention-ul, nu dimensiunea cache-ului.
Întrebări frecvente
Laboratorul dovedește câtă performanță adaugă sheaves?
Nu. El confirmă volumul alocărilor slab, schimbările cache-urilor și comportamentul sub concurență. Pentru atribuirea unei diferențe către sheaves este necesar un experiment A/B controlat pe kerneluri și configurații echivalente.
De ce folosim tmpfs în locul unui director obișnuit?
tmpfs reduce influența unui dispozitiv de stocare și păstrează experimentul concentrat pe VFS, memorie și allocator. Directorul este limitat la 512 MB și este folosit numai de utilizatorul laboratorului.
De ce workload-ul nu rulează ca root?
Crearea, inspectarea și ștergerea fișierelor nu necesită privilegii. Root este păstrat numai pentru perf, citirea completă a /proc/slabinfo, montarea tmpfs și monitorizarea sistemului.
Pot interpreta objectsΔ drept numărul total de alocări?
Nu. objectsΔ este diferența dintre două instantanee. Numărul evenimentelor procesate trebuie citit din raportul perf kmem, deoarece multe obiecte pot fi eliberate sau reutilizate înaintea capturii finale.
Surse
- Memory Management APIs — The Linux Kernel documentation
- Short users guide for the slab allocator — The Linux Kernel documentation
- perf-kmem manual — Linux kernel documentation
- SLUB percpu sheaves, patch series v8 — Linux Kernel Mailing List
- mm/slab: enable runtime sheaves tuning — Linux Kernel Mailing List

















































