#!/usr/bin/env bash # # Linux BenchTools - Script de Test Complet # Version: 1.0.0 # # Ce script collecte les informations hardware et exécute les benchmarks # Génère un fichier result.json dans le dossier courant # set -e # Couleurs pour l'affichage GREEN='\033[0;32m' YELLOW='\033[1;33m' RED='\033[0;31m' BLUE='\033[0;34m' NC='\033[0m' # No Color # Variables globales SCRIPT_VERSION="1.0.0" OUTPUT_FILE="result.json" TOTAL_STEPS=8 CURRENT_STEP=0 # Forcer locale en anglais pour parsing export LC_ALL=C # Ajouter /usr/sbin au PATH pour accéder à dmidecode, smartctl, ethtool export PATH="/usr/sbin:/sbin:$PATH" # Fonctions d'affichage log_step() { CURRENT_STEP=$((CURRENT_STEP + 1)) echo -e "${BLUE}[${CURRENT_STEP}/${TOTAL_STEPS}]${NC} ${GREEN}$1${NC}" } log_info() { echo -e " ${GREEN}✓${NC} $1" } log_warn() { echo -e " ${YELLOW}⚠${NC} $1" } log_error() { echo -e " ${RED}✗${NC} $1" } safe_bc() { local expr="$1" # Renvoie 0 si bc plante, au lieu de laisser une chaîne vide local out out=$(echo "$expr" | bc 2>/dev/null) || out="0" echo "$out" } # Vérifier les permissions sudo check_sudo() { echo -e "${YELLOW}════════════════════════════════════════════════════════${NC}" echo -e "${YELLOW} Linux BenchTools - Script de Test${NC}" echo -e "${YELLOW} Version ${SCRIPT_VERSION}${NC}" echo -e "${YELLOW}════════════════════════════════════════════════════════${NC}" echo "" echo -e "${BLUE}Ce script nécessite les permissions sudo pour :${NC}" echo " - dmidecode (infos RAM, carte mère, BIOS)" echo " - smartctl (infos disques)" echo " - ethtool (vitesse réseau)" echo "" if ! sudo -v; then log_error "Permissions sudo requises. Veuillez relancer avec sudo." exit 1 fi # Garder sudo actif pendant toute la durée du script while true; do sudo -n true; sleep 50; kill -0 "$$" || exit; done 2>/dev/null & log_info "Permissions sudo OK" echo "" } # Vérifier et installer les dépendances check_dependencies() { local missing_essential=() local missing_bench=() local missing_optional=() echo -e "${BLUE}Vérification des dépendances...${NC}" # Outils essentiels for tool in curl jq lscpu free lsblk ip bc; do if ! command -v $tool &> /dev/null; then missing_essential+=($tool) fi done # Outils de benchmark for tool in sysbench fio iperf3; do if ! command -v $tool &> /dev/null; then missing_bench+=($tool) fi done # Outils optionnels (mais recommandés) for tool in dmidecode smartctl ethtool lspci; do if ! command -v $tool &> /dev/null; then missing_optional+=($tool) fi done # Installer les paquets manquants local to_install=() # Mapper les commandes vers les paquets Debian/Ubuntu declare -A package_map=( [curl]="curl" [jq]="jq" [lscpu]="util-linux" [free]="procps" [lsblk]="util-linux" [ip]="iproute2" [bc]="bc" [sysbench]="sysbench" [fio]="fio" [iperf3]="iperf3" [dmidecode]="dmidecode" [smartctl]="smartmontools" [ethtool]="ethtool" [lspci]="pciutils" ) # Collecter tous les paquets à installer for tool in "${missing_essential[@]}" "${missing_bench[@]}" "${missing_optional[@]}"; do local package="${package_map[$tool]}" if [[ -n "$package" ]] && [[ ! " ${to_install[@]} " =~ " ${package} " ]]; then to_install+=($package) fi done # Installer si nécessaire if [[ ${#to_install[@]} -gt 0 ]]; then echo "" log_warn "Paquets manquants détectés : ${to_install[*]}" echo -e "${BLUE}Installation automatique des dépendances...${NC}" echo "" # Mettre à jour la liste des paquets echo "► Mise à jour de la liste des paquets..." if ! sudo apt-get update -qq 2>&1 | grep -v "Policy will reject signature"; then log_warn "Avertissement lors de apt-get update (continuer quand même)" fi echo " Liste mise à jour" # Installer les paquets (avec sortie pour voir les erreurs) echo "► Installation de : ${to_install[*]}" local install_output install_output=$(sudo apt-get install -y "${to_install[@]}" 2>&1) local install_code=$? # Afficher la sortie (sans les warnings de signature) echo "$install_output" | grep -v "Policy will reject signature" || true if [[ $install_code -eq 0 ]]; then log_info "Installation terminée avec succès" # Forcer le shell à recharger le PATH pour voir les nouvelles commandes echo "► Rechargement du PATH..." hash -r # Vérifier que les commandes sont maintenant disponibles echo "► Vérification post-installation..." for tool in dmidecode smartctl ethtool; do if command -v $tool &> /dev/null; then echo " ✓ $tool : $(which $tool)" else echo " ✗ $tool : NON TROUVÉ après installation" fi done else log_error "Erreur lors de l'installation (code: $install_code)" echo "Veuillez installer manuellement : sudo apt-get install ${to_install[*]}" exit 1 fi echo "" else log_info "Toutes les dépendances sont déjà installées" fi } # # ÉTAPE 1 : Collecte informations système de base # collect_system_info() { log_step "Collecte des informations système de base" local hostname=$(hostname) local os_name=$(grep '^ID=' /etc/os-release | cut -d= -f2 | tr -d '"') local os_version=$(grep '^VERSION=' /etc/os-release | cut -d= -f2 | tr -d '"') local kernel=$(uname -r) local arch=$(uname -m) SYSTEM_INFO=$(jq -n \ --arg hostname "$hostname" \ --arg os_name "$os_name" \ --arg os_version "$os_version" \ --arg kernel "$kernel" \ --arg arch "$arch" \ '{ hostname: $hostname, os: { name: $os_name, version: $os_version, kernel_version: $kernel, architecture: $arch } }') log_info "Hostname: $hostname" log_info "OS: $os_name $os_version" log_info "Kernel: $kernel" } # # ÉTAPE 2 : Collecte informations CPU # collect_cpu_info() { log_step "Collecte des informations CPU" local vendor=$(lscpu | grep 'Vendor ID' | awk '{print $3}') local model=$(lscpu | sed -n 's/^Model name:[ \t]*//p' | xargs) local cores=$(lscpu | awk '/^CPU\(s\):/ {print $2}') local threads=$(nproc) # Fréquences local cpu_mhz=$(lscpu | grep 'CPU MHz:' | awk '{print $3}') local cpu_max_mhz=$(lscpu | grep 'CPU max MHz:' | awk '{print $4}') local cpu_min_mhz=$(lscpu | grep 'CPU min MHz:' | awk '{print $4}') # Convertir en GHz local base_freq_ghz="null" local max_freq_ghz="null" if [[ -n "$cpu_mhz" ]]; then base_freq_ghz=$(echo "scale=2; $cpu_mhz / 1000" | bc) fi if [[ -n "$cpu_max_mhz" ]]; then max_freq_ghz=$(echo "scale=2; $cpu_max_mhz / 1000" | bc) fi # Caches local cache_l1d=$(lscpu | grep 'L1d cache:' | awk '{print $3}' | sed 's/K//' | sed 's/M/*1024/' | bc 2>/dev/null || echo "null") local cache_l1i=$(lscpu | grep 'L1i cache:' | awk '{print $3}' | sed 's/K//' | sed 's/M/*1024/' | bc 2>/dev/null || echo "null") local cache_l2=$(lscpu | grep 'L2 cache:' | awk '{print $3}' | sed 's/K//' | sed 's/M/*1024/' | bc 2>/dev/null || echo "null") local cache_l3=$(lscpu | grep 'L3 cache:' | awk '{print $3}' | sed 's/K//' | sed 's/M/*1024/' | bc 2>/dev/null || echo "null") # Calculer L1 total local cache_l1_kb="null" if [[ "$cache_l1d" != "null" && "$cache_l1i" != "null" ]]; then cache_l1_kb=$(echo "$cache_l1d + $cache_l1i" | bc) fi # Flags CPU (limiter aux plus importants) local flags=$(lscpu | grep 'Flags:' | sed 's/Flags:[ \t]*//') local important_flags="avx,avx2,sse4_1,sse4_2,aes,vt-x,vmx,svm" local flags_array="[]" if [[ -n "$flags" ]]; then flags_array=$(echo "$flags" | tr ' ' '\n' | grep -E "^(avx|avx2|sse4_1|sse4_2|aes|pclmulqdq|sha|rdrand|rdseed|popcnt)$" | jq -R . | jq -s .) fi CPU_INFO=$(jq -n \ --arg vendor "$vendor" \ --arg model "$model" \ --argjson cores "${cores:-0}" \ --argjson threads "${threads:-0}" \ --argjson base_freq "$base_freq_ghz" \ --argjson max_freq "$max_freq_ghz" \ --argjson l1 "${cache_l1_kb:-null}" \ --argjson l2 "${cache_l2:-null}" \ --argjson l3 "${cache_l3:-null}" \ --argjson flags "$flags_array" \ '{ vendor: $vendor, model: $model, cores: $cores, threads: $threads, base_freq_ghz: $base_freq, max_freq_ghz: $max_freq, cache_l1_kb: $l1, cache_l2_kb: $l2, cache_l3_kb: $l3, flags: $flags }') log_info "CPU: $model" log_info "Cores: $cores, Threads: $threads" log_info "Freq: ${base_freq_ghz}GHz - ${max_freq_ghz}GHz" } # # ÉTAPE 3 : Collecte informations RAM # collect_ram_info() { log_step "Collecte des informations RAM" # Statistiques RAM de l'OS (total, used, free, shared) local mem_line=$(free -m | grep '^Mem:') local total_mb=$(echo "$mem_line" | awk '{print $2}') local used_mb=$(echo "$mem_line" | awk '{print $3}') local free_mb=$(echo "$mem_line" | awk '{print $4}') local shared_mb=$(echo "$mem_line" | awk '{print $5}') # RAM partagée (inclut tmpfs, vidéo partagée, etc.) # Infos détaillées avec dmidecode (nécessite sudo) local slots_total="null" local slots_used="null" local ecc="null" local layout="[]" # dmidecode nécessite sudo pour fonctionner echo " [DEBUG] Vérification dmidecode..." if command -v dmidecode &> /dev/null; then echo " [DEBUG] dmidecode trouvé: $(which dmidecode)" # Nombre de slots echo " [DEBUG] Exécution: sudo dmidecode -t 16..." slots_total=$(sudo dmidecode -t 16 2>/dev/null | grep 'Number Of Devices' | awk '{print $4}' | head -1) echo " [DEBUG] Slots total: $slots_total" # ECC if sudo dmidecode -t 16 2>/dev/null | grep 'Error Correction Type' | grep -q 'None'; then ecc="false" else ecc="true" fi # Layout des barrettes (parsing complexe) local dimm_data=$(sudo dmidecode -t 17 | grep -E 'Locator:|Size:|Type:|Speed:|Manufacturer:' | \ awk ' /Locator:/ && !/Bank/ { slot=$2; gsub(/_/, "", slot) } /Size:/ && /[0-9]+ [GM]B/ { size=$2; if ($3 == "GB") size=size*1024; if ($3 == "MB") size=size; } /Type:/ && !/Detail/ { type=$2 } /Speed:/ && /[0-9]+ MT/ { speed=$2 } /Manufacturer:/ { manu=$2; if (size > 0) { print slot "," size "," type "," speed "," manu; } slot=""; size=0; type=""; speed=""; manu=""; } ') # Convertir en JSON if [[ -n "$dimm_data" ]]; then layout=$(echo "$dimm_data" | while IFS=',' read -r slot size type speed manu; do jq -n \ --arg slot "$slot" \ --argjson size "$size" \ --arg type "$type" \ --argjson speed "$speed" \ --arg manu "$manu" \ '{slot: $slot, size_mb: $size, type: $type, speed_mhz: $speed, manufacturer: $manu}' done | jq -s .) slots_used=$(echo "$layout" | jq 'length') fi else echo " [DEBUG] dmidecode NON trouvé (command -v failed)" log_warn "dmidecode non disponible - infos RAM limitées" fi echo " [DEBUG] Fin collect_ram_info" RAM_INFO=$(jq -n \ --argjson total "$total_mb" \ --argjson used "$used_mb" \ --argjson free "$free_mb" \ --argjson shared "$shared_mb" \ --argjson slots_total "${slots_total:-null}" \ --argjson slots_used "${slots_used:-null}" \ --argjson ecc "${ecc:-null}" \ --argjson layout "$layout" \ '{ total_mb: $total, used_mb: $used, free_mb: $free, shared_mb: $shared, slots_total: $slots_total, slots_used: $slots_used, ecc: $ecc, layout: $layout }') log_info "RAM Total: ${total_mb}MB (Utilisée: ${used_mb}MB, Libre: ${free_mb}MB)" [[ "$shared_mb" -gt 0 ]] && log_info "RAM Partagée: ${shared_mb}MB (tmpfs/vidéo)" [[ "$slots_used" != "null" ]] && log_info "Slots: ${slots_used}/${slots_total}" } # # ÉTAPE 4 : Collecte informations GPU, Motherboard, BIOS # collect_hardware_info() { log_step "Collecte GPU, Carte mère, BIOS" # GPU local gpu_vendor="null" local gpu_model="null" local gpu_vram="null" if command -v lspci &> /dev/null; then local gpu_info=$(lspci | grep -i 'vga\|3d' | head -1) if [[ -n "$gpu_info" ]]; then gpu_model=$(echo "$gpu_info" | sed 's/.*: //' | xargs) if echo "$gpu_info" | grep -qi 'nvidia'; then gpu_vendor="NVIDIA" if command -v nvidia-smi &> /dev/null; then gpu_vram=$(nvidia-smi --query-gpu=memory.total --format=csv,noheader,nounits | head -1) fi elif echo "$gpu_info" | grep -qi 'intel'; then gpu_vendor="Intel" elif echo "$gpu_info" | grep -qi 'amd\|radeon'; then gpu_vendor="AMD" fi log_info "GPU: $gpu_model" fi fi GPU_INFO=$(jq -n \ --arg vendor "${gpu_vendor}" \ --arg model "${gpu_model}" \ --argjson vram "${gpu_vram:-null}" \ '{vendor: $vendor, model: $model, vram_mb: $vram}') # Motherboard & BIOS local mb_manufacturer="null" local mb_model="null" local bios_vendor="null" local bios_version="null" local bios_date="null" if command -v dmidecode &> /dev/null; then mb_manufacturer=$(sudo dmidecode -t 2 | grep 'Manufacturer:' | sed 's/.*: *//' | xargs) mb_model=$(sudo dmidecode -t 2 | grep 'Product Name:' | sed 's/.*: *//' | xargs) [[ -z "$mb_model" || "$mb_model" == "To be filled by O.E.M." ]] && mb_model="Unknown" bios_vendor=$(sudo dmidecode -t 0 | grep 'Vendor:' | sed 's/.*: *//' | xargs) bios_version=$(sudo dmidecode -t 0 | grep 'Version:' | sed 's/.*: *//' | xargs) bios_date=$(sudo dmidecode -t 0 | grep 'Release Date:' | sed 's/.*: *//' | xargs) log_info "Motherboard: $mb_manufacturer $mb_model" log_info "BIOS: $bios_version ($bios_date)" fi MOTHERBOARD_INFO=$(jq -n \ --arg manu "${mb_manufacturer}" \ --arg model "${mb_model}" \ --arg bios_vendor "${bios_vendor}" \ --arg bios_ver "${bios_version}" \ --arg bios_date "${bios_date}" \ '{ manufacturer: $manu, model: $model, bios_vendor: $bios_vendor, bios_version: $bios_ver, bios_date: $bios_date }') } # # ÉTAPE 5 : Collecte informations Storage # collect_storage_info() { log_step "Collecte des informations de stockage" local storage_array="[]" # Lister uniquement les disques physiques (pas loop, pas ram) local physical_disks=$(lsblk -d -n -o NAME,TYPE | grep 'disk' | awk '{print $1}') for disk in $physical_disks; do # Ignorer les disques de taille 0 (lecteurs vides) local size_bytes=$(lsblk -d -n -b -o SIZE /dev/$disk) [[ "$size_bytes" -eq 0 ]] && continue local size=$(lsblk -d -n -o SIZE /dev/$disk | sed 's/,/./') local rota=$(lsblk -d -n -o ROTA /dev/$disk) local tran=$(lsblk -d -n -o TRAN /dev/$disk) # Type : SSD ou HDD local disk_type="unknown" [[ "$rota" == "0" ]] && disk_type="ssd" || disk_type="hdd" # Interface local interface="unknown" [[ -n "$tran" ]] && interface="$tran" # Modèle et données SMART via smartctl local model="Unknown" local serial="Unknown" local smart_health="null" local power_on_hours="null" local power_cycle_count="null" local temperature="null" local reallocated_sectors="null" local pending_sectors="null" local udma_crc_errors="null" local wear_leveling="null" local total_lbas_written="null" if command -v smartctl &> /dev/null; then # Informations de base local smart_info=$(sudo smartctl -i /dev/$disk 2>/dev/null || true) if [[ -n "$smart_info" ]]; then model=$(echo "$smart_info" | grep 'Device Model:' | sed 's/.*: *//' | xargs) [[ -z "$model" ]] && model=$(echo "$smart_info" | grep 'Model Number:' | sed 's/.*: *//' | xargs) serial=$(echo "$smart_info" | grep 'Serial Number:' | sed 's/.*: *//' | xargs) fi # Données SMART (santé et vieillissement) local smart_all=$(sudo smartctl -A -H /dev/$disk 2>/dev/null || true) if [[ -n "$smart_all" ]]; then # État de santé global if echo "$smart_all" | grep -q 'SMART overall-health self-assessment test result: PASSED'; then smart_health="PASSED" elif echo "$smart_all" | grep -q 'SMART overall-health self-assessment test result: FAILED'; then smart_health="FAILED" fi # Heures de fonctionnement (ID 9) power_on_hours=$(echo "$smart_all" | awk '/Power_On_Hours|Power On Hours/ {print $10}' | head -1) [[ -z "$power_on_hours" ]] && power_on_hours="null" # Nombre de cycles d'alimentation (ID 12) power_cycle_count=$(echo "$smart_all" | awk '/Power_Cycle_Count|Start_Stop_Count/ {print $10}' | head -1) [[ -z "$power_cycle_count" ]] && power_cycle_count="null" # Température (ID 194) temperature=$(echo "$smart_all" | awk '/Temperature_Celsius|Airflow_Temperature/ {print $10}' | head -1) [[ -z "$temperature" ]] && temperature="null" # Secteurs réalloués (ID 5) - Important pour la santé reallocated_sectors=$(echo "$smart_all" | awk '/Reallocated_Sector_Ct/ {print $10}' | head -1) [[ -z "$reallocated_sectors" ]] && reallocated_sectors="null" # Secteurs en attente de réallocation (ID 197) pending_sectors=$(echo "$smart_all" | awk '/Current_Pending_Sector/ {print $10}' | head -1) [[ -z "$pending_sectors" ]] && pending_sectors="null" # Erreurs CRC UDMA (ID 199) - Problèmes de câble/interface udma_crc_errors=$(echo "$smart_all" | awk '/UDMA_CRC_Error_Count/ {print $10}' | head -1) [[ -z "$udma_crc_errors" ]] && udma_crc_errors="null" # Pour SSD: Wear Leveling Count (ID 177) if [[ "$disk_type" == "ssd" ]]; then wear_leveling=$(echo "$smart_all" | awk '/Wear_Leveling_Count/ {print $4}' | head -1) [[ -z "$wear_leveling" ]] && wear_leveling="null" # Total LBAs Written (indicateur d'usure SSD, ID 241) total_lbas_written=$(echo "$smart_all" | awk '/Total_LBAs_Written/ {print $10}' | head -1) [[ -z "$total_lbas_written" ]] && total_lbas_written="null" fi fi fi # Convertir size en GB local size_gb=$(echo "$size" | sed 's/[^0-9.]//g') # Créer l'objet SMART local smart_json=$(jq -n \ --arg health "${smart_health}" \ --argjson power_hours "${power_on_hours:-null}" \ --argjson power_cycles "${power_cycle_count:-null}" \ --argjson temp "${temperature:-null}" \ --argjson realloc "${reallocated_sectors:-null}" \ --argjson pending "${pending_sectors:-null}" \ --argjson crc_errors "${udma_crc_errors:-null}" \ --argjson wear "${wear_leveling:-null}" \ --argjson lbas_written "${total_lbas_written:-null}" \ '{ health_status: $health, power_on_hours: $power_hours, power_cycle_count: $power_cycles, temperature_celsius: $temp, reallocated_sectors: $realloc, pending_sectors: $pending, udma_crc_errors: $crc_errors, wear_leveling_count: $wear, total_lbas_written: $lbas_written }') local disk_json=$(jq -n \ --arg device "$disk" \ --arg model "$model" \ --arg size "$size_gb" \ --arg type "$disk_type" \ --arg interface "$interface" \ --arg serial "$serial" \ --argjson smart "$smart_json" \ '{device: $device, model: $model, size_gb: $size, type: $type, interface: $interface, serial: $serial, smart: $smart}') storage_array=$(echo "$storage_array" | jq --argjson disk "$disk_json" '. + [$disk]') # Log avec infos de santé local health_info="" [[ "$smart_health" != "null" ]] && health_info=" - Santé: $smart_health" [[ "$power_on_hours" != "null" ]] && health_info="$health_info, ${power_on_hours}h" log_info "Disque: /dev/$disk - $model ($size, $disk_type)$health_info" done STORAGE_INFO="$storage_array" } # # ÉTAPE 6 : Collecte informations réseau # collect_network_info() { log_step "Collecte des informations réseau" local network_array="[]" # Interfaces actives (ignore loopback, docker, bridges) for iface in $(ip -br link show | grep -E 'UP|UNKNOWN' | awk '{print $1}'); do [[ "$iface" =~ ^(lo|docker|br-|veth) ]] && continue # MAC local mac=$(ip link show $iface | grep 'link/ether' | awk '{print $2}') [[ -z "$mac" ]] && continue # Type local type="unknown" if [[ "$iface" =~ ^(eth|eno|enp) ]]; then type="ethernet" elif [[ "$iface" =~ ^(wlan|wlp) ]]; then type="wifi" fi # IP address local ip_addr=$(ip -4 addr show $iface | grep 'inet ' | awk '{print $2}' | cut -d/ -f1) # Vitesse et Wake-on-LAN (nécessite ethtool et ethernet) local speed="null" local wol_supported="null" if command -v ethtool &> /dev/null && [[ "$type" == "ethernet" ]]; then speed=$(sudo ethtool $iface 2>/dev/null | grep 'Speed:' | awk '{print $2}' | sed 's/Mb\/s//' | sed 's/Unknown!/null/') [[ -z "$speed" || "$speed" == "Unknown" ]] && speed="null" # Wake-on-LAN support local wol_info=$(sudo ethtool $iface 2>/dev/null | grep 'Supports Wake-on:') if [[ -n "$wol_info" ]]; then # Si le support contient 'g' (magic packet), WoL est supporté if echo "$wol_info" | grep -q 'g'; then wol_supported="true" else wol_supported="false" fi fi fi local net_json=$(jq -n \ --arg name "$iface" \ --arg type "$type" \ --arg mac "$mac" \ --arg ip "${ip_addr:-null}" \ --argjson speed "${speed:-null}" \ --argjson wol "${wol_supported:-null}" \ '{name: $name, type: $type, mac: $mac, ip_address: $ip, speed_mbps: $speed, wake_on_lan: $wol}') network_array=$(echo "$network_array" | jq --argjson net "$net_json" '. + [$net]') log_info "Interface: $iface ($type) - IP: ${ip_addr:-N/A}" done NETWORK_INFO="$network_array" } # # ÉTAPE 7 : Exécution des benchmarks # run_benchmarks() { log_step "Exécution des benchmarks (peut prendre plusieurs minutes)" # CPU Benchmark local cpu_bench="null" if command -v sysbench &> /dev/null; then log_info "Benchmark CPU en cours..." local cpu_result=$(sysbench cpu --cpu-max-prime=20000 --threads=$(nproc) run 2>&1) local events_per_sec=$(echo "$cpu_result" | grep 'events per second' | awk '{print $4}') local total_time=$(echo "$cpu_result" | grep 'total time:' | awk '{print $3}' | sed 's/s//') local cpu_score=$(echo "scale=2; $events_per_sec / 100" | bc) cpu_bench=$(jq -n \ --argjson eps "${events_per_sec:-0}" \ --argjson time "${total_time:-0}" \ --argjson score "${cpu_score:-0}" \ '{events_per_sec: $eps, duration_s: $time, score: $score}') log_info "CPU: ${events_per_sec} events/sec (score: ${cpu_score})" else log_warn "sysbench non disponible - CPU bench ignoré" fi # Memory Benchmark local mem_bench="null" if command -v sysbench &> /dev/null; then log_info "Benchmark Mémoire en cours..." local mem_result=$(sysbench memory --memory-block-size=1M --memory-total-size=1G run 2>&1) local throughput=$(echo "$mem_result" | grep 'MiB/sec' | grep -oP '\d+\.\d+' | head -1) local mem_score=$(echo "scale=2; $throughput / 100" | bc) mem_bench=$(jq -n \ --argjson tp "${throughput:-0}" \ --argjson score "${mem_score:-0}" \ '{throughput_mib_s: $tp, score: $score}') log_info "Mémoire: ${throughput} MiB/s (score: ${mem_score})" fi # Disk Benchmark (sur le disque principal uniquement, pas /tmp) local disk_bench="null" if command -v fio &> /dev/null; then log_info "Benchmark Disque en cours (cela peut prendre 2-3 minutes)..." # Utiliser le répertoire home pour éviter /tmp (qui peut être tmpfs) local test_dir="$HOME/fio-bench-test" mkdir -p "$test_dir" local fio_result=$(fio --name=bench --ioengine=libaio --rw=randrw --bs=4k \ --size=500M --numjobs=1 --direct=1 --runtime=30 --time_based \ --filename="$test_dir/testfile" --output-format=json 2>/dev/null || echo '{}') # Nettoyer rm -rf "$test_dir" if [[ "$fio_result" != "{}" ]]; then local read_bw=$(echo "$fio_result" | jq '.jobs[0].read.bw // 0') local write_bw=$(echo "$fio_result" | jq '.jobs[0].write.bw // 0') local read_iops=$(echo "$fio_result" | jq '.jobs[0].read.iops // 0' | cut -d. -f1) local write_iops=$(echo "$fio_result" | jq '.jobs[0].write.iops // 0' | cut -d. -f1) local lat_ns=$(echo "$fio_result" | jq '.jobs[0].read.clat_ns.mean // 0') # Convertir en MB/s et ms local read_mb=$(echo "scale=2; $read_bw / 1024" | bc) local write_mb=$(echo "scale=2; $write_bw / 1024" | bc) local lat_ms=$(echo "scale=3; $lat_ns / 1000000" | bc) # Score : moyenne read/write MB/s local disk_score=$(echo "scale=2; ($read_mb + $write_mb) / 2" | bc) disk_bench=$(jq -n \ --argjson read "$read_mb" \ --argjson write "$write_mb" \ --argjson riops "$read_iops" \ --argjson wiops "$write_iops" \ --argjson lat "$lat_ms" \ --argjson score "$disk_score" \ '{read_mb_s: $read, write_mb_s: $write, iops_read: $riops, iops_write: $wiops, latency_ms: $lat, score: $score}') log_info "Disque: R=${read_mb}MB/s W=${write_mb}MB/s (score: ${disk_score})" fi else log_warn "fio non disponible - Disk bench ignoré" fi # Network Benchmark vers le serveur 10.0.0.50 local net_bench="null" if command -v iperf3 &> /dev/null; then log_info "Benchmark Réseau en cours (vers 10.0.0.50)..." # Test de connectivité d'abord if ping -c 1 -W 2 10.0.0.50 &> /dev/null; then # Test upload (client → serveur) local upload_result=$(iperf3 -c 10.0.0.50 -t 10 -J 2>/dev/null || echo '{}') local upload_mbps="0" local download_mbps="0" local ping_ms="null" if [[ "$upload_result" != "{}" ]]; then # Extraire le débit d'upload en bits/sec et convertir en Mbps local upload_bps=$(echo "$upload_result" | jq '.end.sum_sent.bits_per_second // 0') upload_mbps=$(echo "scale=2; $upload_bps / 1000000" | bc) # Test download (serveur → client avec -R) local download_result=$(iperf3 -c 10.0.0.50 -t 10 -R -J 2>/dev/null || echo '{}') if [[ "$download_result" != "{}" ]]; then local download_bps=$(echo "$download_result" | jq '.end.sum_received.bits_per_second // 0') download_mbps=$(echo "scale=2; $download_bps / 1000000" | bc) fi # Mesurer le ping local ping_output=$(ping -c 5 10.0.0.50 2>/dev/null | grep 'avg' || echo "") if [[ -n "$ping_output" ]]; then ping_ms=$(echo "$ping_output" | awk -F'/' '{print $5}') fi # Score réseau : moyenne upload/download divisée par 10 (pour avoir un score sur 100) local net_score=$(echo "scale=2; ($upload_mbps + $download_mbps) / 20" | bc) net_bench=$(jq -n \ --argjson upload "$upload_mbps" \ --argjson download "$download_mbps" \ --argjson ping "${ping_ms:-null}" \ --argjson score "$net_score" \ '{upload_mbps: $upload, download_mbps: $download, ping_ms: $ping, score: $score}') log_info "Réseau: ↑${upload_mbps}Mbps ↓${download_mbps}Mbps (ping: ${ping_ms}ms, score: ${net_score})" else log_warn "Serveur iperf3 sur 10.0.0.50 non accessible (assurez-vous que 'iperf3 -s' tourne)" fi else log_warn "Serveur 10.0.0.50 non joignable - Network bench ignoré" fi else log_warn "iperf3 non disponible - Network bench ignoré" fi # GPU Benchmark local gpu_bench="null" log_warn "GPU bench non implémenté - ignoré" # Calculer score global (seulement CPU, RAM, Disk) # Pondération : CPU=60%, RAM=20%, Disk=20% local scores="" local total_weight=0 if [[ "$cpu_bench" != "null" ]]; then local cpu_score cpu_score=$(echo "$cpu_bench" | jq '.score // 0') scores="$scores + $cpu_score * 0.6" total_weight=$(safe_bc "$total_weight + 0.6") fi if [[ "$mem_bench" != "null" ]]; then local mem_score mem_score=$(echo "$mem_bench" | jq '.score // 0') scores="$scores + $mem_score * 0.2" total_weight=$(safe_bc "$total_weight + 0.2") fi if [[ "$disk_bench" != "null" ]]; then local disk_score disk_score=$(echo "$disk_bench" | jq '.score // 0') scores="$scores + $disk_score * 0.2" total_weight=$(safe_bc "$total_weight + 0.2") fi # Nettoyer le préfixe " + " éventuellement scores=$(echo "$scores" | sed -E 's/^[[:space:]]*\+ //') local global_score=0 if [[ -n "$scores" && "$total_weight" != "0" ]]; then global_score=$(safe_bc "scale=2; ($scores) / $total_weight") fi # Toujours fournir un JSON valide à jq if [[ -z "$global_score" ]]; then global_score=0 fi BENCHMARK_RESULTS=$(jq -n \ --argjson cpu "$cpu_bench" \ --argjson mem "$mem_bench" \ --argjson disk "$disk_bench" \ --argjson net "$net_bench" \ --argjson gpu "$gpu_bench" \ --argjson global "$global_score" \ '{ cpu: $cpu, memory: $mem, disk: $disk, network: $net, gpu: $gpu, global_score: $global }') log_info "Score global: ${global_score}/100" } # # ÉTAPE 8 : Génération du fichier JSON # generate_json() { log_step "Génération du fichier result.json" local timestamp=$(date -u +"%Y-%m-%dT%H:%M:%SZ") # Assembler le JSON final jq -n \ --arg version "$SCRIPT_VERSION" \ --arg timestamp "$timestamp" \ --argjson system "$SYSTEM_INFO" \ --argjson cpu "$CPU_INFO" \ --argjson ram "$RAM_INFO" \ --argjson gpu "$GPU_INFO" \ --argjson mb "$MOTHERBOARD_INFO" \ --argjson storage "$STORAGE_INFO" \ --argjson network "$NETWORK_INFO" \ --argjson benchmarks "$BENCHMARK_RESULTS" \ '{ metadata: { script_version: $version, timestamp: $timestamp }, system: $system, hardware: { cpu: $cpu, ram: $ram, gpu: $gpu, motherboard: $mb, storage: $storage, network: $network }, benchmarks: $benchmarks }' > "$OUTPUT_FILE" log_info "Fichier généré: $OUTPUT_FILE" # Afficher un résumé echo "" echo -e "${GREEN}════════════════════════════════════════════════════════${NC}" echo -e "${GREEN} Test terminé avec succès !${NC}" echo -e "${GREEN}════════════════════════════════════════════════════════${NC}" echo "" echo "Fichier de résultat : $(pwd)/$OUTPUT_FILE" echo "Taille du fichier : $(du -h $OUTPUT_FILE | awk '{print $1}')" echo "" echo "Aperçu du résultat :" echo "-------------------" jq '{ hostname: .system.hostname, os: .system.os.name, cpu: .hardware.cpu.model, ram_mb: .hardware.ram.total_mb, storage_count: (.hardware.storage | length), network_count: (.hardware.network | length), benchmark_score: .benchmarks.global_score }' "$OUTPUT_FILE" echo "" } # # MAIN # main() { # Vérifications préliminaires check_sudo check_dependencies echo "" echo -e "${BLUE}Début de la collecte et des benchmarks...${NC}" echo "" # Exécuter toutes les étapes collect_system_info collect_cpu_info collect_ram_info collect_hardware_info collect_storage_info collect_network_info run_benchmarks generate_json echo -e "${GREEN}✓ Terminé !${NC}" } # Lancer le script main "$@"