Skip to content

SCRIPT ANÁLISE PERFORMANCE

bash
cat >/root/arc-monitor.sh <<'EOF'
#!/usr/bin/env bash
#
# =============================================================================
# ARC / L2ARC MONITOR - TrueNAS SCALE / OpenZFS
# =============================================================================
#
# OBJETIVO
#   Medir a eficiência do ARC e L2ARC durante uma janela real de utilização.
#
#   O script NÃO gera carga no pool e NÃO altera parâmetros do ZFS.
#   Apenas lê contadores do kernel e calcula a diferença entre dois momentos.
#
#
# USO BÁSICO
#
#   1) Iniciar uma nova janela:
#
#        /root/arc-monitor.sh start
#
#   2) Deixar o storage trabalhar normalmente por 30-60 minutos
#      ou durante o período que deseja analisar.
#
#   3) Mostrar o relatório:
#
#        /root/arc-monitor.sh report
#
#   O "report" pode ser executado várias vezes.
#   Todos os relatórios continuam usando o último "start" como início.
#
#   Para zerar a medição:
#
#        /root/arc-monitor.sh start
#
#
# OUTROS COMANDOS
#
#        /root/arc-monitor.sh thresholds
#        /root/arc-monitor.sh glossary
#        /root/arc-monitor.sh help
#
#
# CORES
#
#   As cores são ativadas automaticamente quando a saída é um terminal.
#
#   Para desativar:
#
#        NO_COLOR=1 /root/arc-monitor.sh report
#
#   Ao redirecionar para arquivo, as cores são removidas automaticamente:
#
#        /root/arc-monitor.sh report > /tmp/arc-report.txt
#
#
# ARQUIVOS LIDOS
#
#        /proc/spl/kstat/zfs/arcstats
#        /proc/meminfo
#
# SNAPSHOT
#
#        /tmp/arc-monitor-before.txt
#
#
# INDICADOR PRINCIPAL
#
#   O principal indicador utilizado é DEMAND DATA MISS.
#
#   Ele representa dados pedidos diretamente pelas aplicações que
#   não foram encontrados no ARC.
#
#        <=  2%   EXCELENTE
#        <=  5%   BOM
#        <= 10%   ATENCAO
#        >  10%   RUIM
#
#   O ARC Total é apenas contexto secundário.
#
# =============================================================================

set -u

STATS="/proc/spl/kstat/zfs/arcstats"
STATE="/tmp/arc-monitor-before.txt"

# =============================================================================
# THRESHOLDS
# =============================================================================

DD_EXCELLENT_MAX=2
DD_GOOD_MAX=5
DD_WARN_MAX=10

L2_EXCELLENT_MIN=40
L2_GOOD_MIN=25
L2_WARN_MIN=10

MIN_DEMAND_SAMPLES=10000
MIN_L2_SAMPLES=1000

MRU_WARN_MIN=90
MRU_BAD_MIN=95
L2_LOW_FOR_POLLUTION=20

# =============================================================================
# CORES
# =============================================================================

if [[ -t 1 && -z "${NO_COLOR:-}" ]]; then

    RESET=$'\033[0m'
    BOLD=$'\033[1m'
    DIM=$'\033[2m'

    RED=$'\033[31m'
    GREEN=$'\033[32m'
    YELLOW=$'\033[33m'
    BLUE=$'\033[34m'
    CYAN=$'\033[36m'

    BRIGHT_RED=$'\033[91m'
    BRIGHT_GREEN=$'\033[92m'
    BRIGHT_YELLOW=$'\033[93m'
    BRIGHT_BLUE=$'\033[94m'
    BRIGHT_CYAN=$'\033[96m'

else

    RESET=""
    BOLD=""
    DIM=""

    RED=""
    GREEN=""
    YELLOW=""
    BLUE=""
    CYAN=""

    BRIGHT_RED=""
    BRIGHT_GREEN=""
    BRIGHT_YELLOW=""
    BRIGHT_BLUE=""
    BRIGHT_CYAN=""

fi

# =============================================================================
# FORMATAÇÃO VISUAL
# =============================================================================

line() {
    printf '%s%s%s\n' \
        "$CYAN" \
        "==============================================================================" \
        "$RESET"
}

subline() {
    printf '%s%s%s\n' \
        "$DIM" \
        "------------------------------------------------------------------------------" \
        "$RESET"
}

section() {
    echo
    subline

    printf '%s%s %s%s\n' \
        "$BOLD" \
        "$BRIGHT_CYAN" \
        "$1" \
        "$RESET"

    subline
}

status_color() {

    local status="$1"

    case "$status" in

        EXCELENTE*)
            printf '%s%s%s%s' \
                "$BOLD" "$BRIGHT_GREEN" "$status" "$RESET"
            ;;

        BOM*)
            printf '%s%s%s' \
                "$GREEN" "$status" "$RESET"
            ;;

        ATENCAO*)
            printf '%s%s%s%s' \
                "$BOLD" "$YELLOW" "$status" "$RESET"
            ;;

        RUIM*)
            printf '%s%s%s%s' \
                "$BOLD" "$BRIGHT_RED" "$status" "$RESET"
            ;;

        AMOSTRA*)
            printf '%s%s%s' \
                "$BRIGHT_BLUE" "$status" "$RESET"
            ;;

        INCONCLUSIVO*)
            printf '%s%s%s' \
                "$BRIGHT_BLUE" "$status" "$RESET"
            ;;

        OK*)
            printf '%s%s%s' \
                "$GREEN" "$status" "$RESET"
            ;;

        "FORTE INDICIO"*)
            printf '%s%s%s%s' \
                "$BOLD" "$BRIGHT_RED" "$status" "$RESET"
            ;;

        POSSIVEL*)
            printf '%s%s%s' \
                "$YELLOW" "$status" "$RESET"
            ;;

        "NAO EVIDENTE"*)
            printf '%s%s%s' \
                "$GREEN" "$status" "$RESET"
            ;;

        *)
            printf '%s' "$status"
            ;;

    esac
}

# =============================================================================
# LEITURA DOS CONTADORES
# =============================================================================

get_stat() {

    local v

    v=$(
        awk -v n="$1" '
            $1 == n {
                print $3
                exit
            }
        ' "$STATS" 2>/dev/null || true
    )

    printf '%s\n' "${v:-0}"
}

get_memavailable_bytes() {

    awk '
        $1 == "MemAvailable:" {
            printf "%.0f\n", $2 * 1024
            exit
        }
    ' /proc/meminfo
}

snapshot() {

    echo "timestamp=$(date +%s)"
    echo "date=$(date -Is)"
    echo "host=$(hostname)"
    echo "mem_available=$(get_memavailable_bytes)"

    for x in \
        size \
        c \
        c_max \
        memory_available_bytes \
        hits \
        iohits \
        misses \
        demand_data_hits \
        demand_data_iohits \
        demand_data_misses \
        l2_hits \
        l2_misses \
        l2_size \
        l2_asize \
        l2_write_bytes \
        l2_abort_lowmem \
        l2_mru_asize \
        l2_mfu_asize \
        l2_prefetch_asize
    do
        echo "$x=$(get_stat "$x")"
    done
}

value() {

    local file="$1"
    local key="$2"

    awk -F= -v k="$key" '
        $1 == k {
            print substr($0,index($0,"=")+1)
            exit
        }
    ' "$file"
}

num_or_zero() {

    if [[ "$1" =~ ^-?[0-9]+$ ]]; then
        printf '%s\n' "$1"
    else
        printf '0\n'
    fi
}

delta() {

    local key="$1"
    local a
    local b

    a=$(num_or_zero "$(value "$STATE" "$key")")
    b=$(num_or_zero "$(value "$CURRENT" "$key")")

    echo $((b - a))
}

# =============================================================================
# CONVERSÕES
# =============================================================================

pct_num() {

    awk -v n="$1" -v d="$2" '
        BEGIN {
            if (d <= 0)
                print "-1"
            else
                printf "%.4f", (n/d)*100
        }
    '
}

pct_fmt() {

    awk -v p="$1" '
        BEGIN {
            if (p < 0)
                printf "N/A"
            else
                printf "%.2f%%", p
        }
    '
}

human_count() {

    awk -v n="$1" '
        BEGIN {

            sign = (n < 0 ? "-" : "")

            if (n < 0)
                n = -n

            if (n >= 1000000000)
                printf "%s%.2fG", sign, n/1000000000

            else if (n >= 1000000)
                printf "%s%.2fM", sign, n/1000000

            else if (n >= 1000)
                printf "%s%.2fk", sign, n/1000

            else
                printf "%s%.0f", sign, n
        }
    '
}

human_bytes() {

    awk -v b="$1" '
        BEGIN {

            sign = (b < 0 ? "-" : "")

            if (b < 0)
                b = -b

            if (b >= 1099511627776)
                printf "%s%.2f TiB", sign, b/1099511627776

            else if (b >= 1073741824)
                printf "%s%.2f GiB", sign, b/1073741824

            else if (b >= 1048576)
                printf "%s%.2f MiB", sign, b/1048576

            else if (b >= 1024)
                printf "%s%.2f KiB", sign, b/1024

            else
                printf "%s%.0f B", sign, b
        }
    '
}

human_rate() {

    local bytes="$1"
    local secs="$2"
    local rate

    rate=$(
        awk -v b="$bytes" -v s="$secs" '
            BEGIN {
                if (s <= 0)
                    print 0
                else
                    printf "%.0f", b/s
            }
        '
    )

    printf '%s/s' "$(human_bytes "$rate")"
}

duration_fmt() {

    local s="$1"

    if (( s >= 86400 )); then

        printf '%dd %02dh %02dm %02ds' \
            $((s/86400)) \
            $(((s%86400)/3600)) \
            $(((s%3600)/60)) \
            $((s%60))

    elif (( s >= 3600 )); then

        printf '%dh %02dm %02ds' \
            $((s/3600)) \
            $(((s%3600)/60)) \
            $((s%60))

    else

        printf '%dm %02ds' \
            $((s/60)) \
            $((s%60))

    fi
}

# =============================================================================
# CLASSIFICAÇÕES
# =============================================================================

classify_demand() {

    local p="$1"
    local samples="$2"

    if (( samples < MIN_DEMAND_SAMPLES )); then
        echo "AMOSTRA BAIXA"
        return
    fi

    awk \
        -v p="$p" \
        -v e="$DD_EXCELLENT_MAX" \
        -v g="$DD_GOOD_MAX" \
        -v w="$DD_WARN_MAX" '
        BEGIN {

            if (p <= e)
                print "EXCELENTE"

            else if (p <= g)
                print "BOM"

            else if (p <= w)
                print "ATENCAO"

            else
                print "RUIM"
        }
    '
}

classify_l2() {

    local p="$1"
    local samples="$2"

    if (( samples < MIN_L2_SAMPLES )); then
        echo "AMOSTRA BAIXA"
        return
    fi

    awk \
        -v p="$p" \
        -v e="$L2_EXCELLENT_MIN" \
        -v g="$L2_GOOD_MIN" \
        -v w="$L2_WARN_MIN" '
        BEGIN {

            if (p >= e)
                print "EXCELENTE"

            else if (p >= g)
                print "BOM"

            else if (p >= w)
                print "ATENCAO"

            else
                print "RUIM"
        }
    '
}

pollution_status() {

    local mru="$1"
    local l2hit="$2"
    local samples="$3"

    if (( samples < MIN_L2_SAMPLES )); then
        echo "INCONCLUSIVO (amostra baixa)"
        return
    fi

    awk \
        -v m="$mru" \
        -v h="$l2hit" \
        -v warn="$MRU_WARN_MIN" \
        -v bad="$MRU_BAD_MIN" \
        -v low="$L2_LOW_FOR_POLLUTION" '
        BEGIN {

            if (m >= bad && h < low)
                print "FORTE INDICIO"

            else if (m >= warn && h < 25)
                print "POSSIVEL"

            else
                print "NAO EVIDENTE"
        }
    '
}

# =============================================================================
# THRESHOLDS
# =============================================================================

print_thresholds() {

    section "THRESHOLDS UTILIZADOS"

    printf '%sDemand Data Miss%s\n' "$BOLD" "$RESET"

    printf '  <= %2s%%   ' "$DD_EXCELLENT_MAX"
    status_color "EXCELENTE"
    echo

    printf '  <= %2s%%   ' "$DD_GOOD_MAX"
    status_color "BOM"
    echo

    printf '  <= %2s%%   ' "$DD_WARN_MAX"
    status_color "ATENCAO"
    echo

    printf '  >  %2s%%   ' "$DD_WARN_MAX"
    status_color "RUIM"
    echo

    echo

    printf '%sL2ARC Hit%s\n' "$BOLD" "$RESET"

    printf '  >= %2s%%   ' "$L2_EXCELLENT_MIN"
    status_color "EXCELENTE"
    echo

    printf '  >= %2s%%   ' "$L2_GOOD_MIN"
    status_color "BOM"
    echo

    printf '  >= %2s%%   ' "$L2_WARN_MIN"
    status_color "ATENCAO"
    echo

    printf '  <  %2s%%   ' "$L2_WARN_MIN"
    status_color "RUIM"
    echo

    echo

    printf '%sAmostra mínima%s\n' "$BOLD" "$RESET"
    printf '  Demand Data: %s acessos\n' "$MIN_DEMAND_SAMPLES"
    printf '  L2ARC:       %s consultas\n' "$MIN_L2_SAMPLES"

    echo
    printf '%sDemand Data tem prioridade sobre ARC Total e L2ARC.%s\n' \
        "$YELLOW" "$RESET"
}

# =============================================================================
# GLOSSÁRIO / COMO INTERPRETAR
# =============================================================================

print_glossary() {

    section "COMO INTERPRETAR ESTE RELATÓRIO"

    printf '%sARC%s\n' "$BOLD$BRIGHT_CYAN" "$RESET"
    echo "  Cache principal do ZFS armazenado na RAM."
    echo "  É a camada de cache mais rápida."

    echo

    printf '%sL2ARC%s\n' "$BOLD$BRIGHT_CYAN" "$RESET"
    echo "  Segundo nível de cache, normalmente SSD/NVMe."
    echo "  É consultado quando o dado não está disponível no ARC."

    echo

    printf '%sHit%s\n' "$BOLD$GREEN" "$RESET"
    echo "  O dado solicitado foi encontrado naquela camada de cache."
    echo "  Em geral, quanto maior o percentual, melhor."

    echo

    printf '%sMiss%s\n' "$BOLD$YELLOW" "$RESET"
    echo "  O dado não estava naquela camada de cache."
    echo "  A leitura precisa seguir para outra camada."

    echo

    printf '%sDemand Data%s\n' "$BOLD$BRIGHT_CYAN" "$RESET"
    echo "  Dados pedidos diretamente pelas aplicações, VMs, NFS, iSCSI etc."
    echo "  É o indicador principal de performance deste relatório."

    echo

    printf '%sDemand Hit%s\n' "$BOLD$GREEN" "$RESET"
    echo "  A aplicação pediu um dado e ele foi encontrado no ARC."

    echo

    printf '%sDemand Miss%s\n' "$BOLD$YELLOW" "$RESET"
    echo "  A aplicação pediu um dado e ele não estava no ARC."
    echo "  Quanto menor esse percentual, melhor."

    echo

    printf '%sI/O Hit%s\n' "$BOLD$CYAN" "$RESET"
    echo "  A requisição foi atendida por um I/O já em andamento ou estrutura"
    echo "  equivalente, sem ser um hit tradicional do ARC."

    echo

    printf '%sARC Total%s\n' "$BOLD$BRIGHT_CYAN" "$RESET"
    echo "  Soma dados, metadata, prefetch e outros acessos."
    echo "  Serve como contexto, mas pode mascarar problemas porque metadata"
    echo "  normalmente possui hit rate muito alto."

    echo

    printf '%sMRU - Most Recently Used%s\n' "$BOLD$YELLOW" "$RESET"
    echo "  Dados usados recentemente."
    echo "  Muito MRU no L2ARC pode indicar dados de passagem ou pouca reutilização."

    echo

    printf '%sMFU - Most Frequently Used%s\n' "$BOLD$GREEN" "$RESET"
    echo "  Dados utilizados repetidamente."
    echo "  Normalmente são candidatos valiosos para permanecer no cache."

    echo

    printf '%sPrefetch%s\n' "$BOLD$CYAN" "$RESET"
    echo "  Dados lidos antecipadamente pelo ZFS porque ele prevê que serão usados."

    echo

    printf '%sL2ARC Hit Ratio%s\n' "$BOLD$GREEN" "$RESET"
    echo "  Percentual das consultas ao L2ARC que encontraram o dado no SSD."

    echo

    printf '%sL2ARC Writes%s\n' "$BOLD$CYAN" "$RESET"
    echo "  Quantidade de dados enviada ao dispositivo de L2ARC durante a janela."

    echo

    printf '%sLogical Size%s\n' "$BOLD$CYAN" "$RESET"
    echo "  Quantidade lógica de dados representada pelo L2ARC."

    echo

    printf '%sAllocated Size / ASIZE%s\n' "$BOLD$CYAN" "$RESET"
    echo "  Quantidade efetivamente alocada no dispositivo de L2ARC."

    echo

    printf '%sLow-memory abort%s\n' "$BOLD$BRIGHT_RED" "$RESET"
    echo "  O ZFS abortou alimentação do L2ARC devido a pressão de memória."
    echo "  O ideal é que esse contador NÃO aumente durante a medição."

    echo

    printf '%sChurn%s\n' "$BOLD$YELLOW" "$RESET"
    echo "  Dados entram e saem rapidamente do cache sem reutilização suficiente."

    echo

    printf '%sPoluição de cache%s\n' "$BOLD$YELLOW" "$RESET"
    echo "  Dados pouco úteis ocupam o cache e podem expulsar dados mais valiosos."
    echo "  MRU muito alto + L2ARC hit baixo pode ser um indício."

    echo

    printf '%sAmostra%s\n' "$BOLD$BRIGHT_BLUE" "$RESET"
    echo "  Quantidade de operações observadas na janela."
    echo "  Percentuais obtidos com poucas operações podem não ser representativos."

    echo

    printf '%sThreshold%s\n' "$BOLD$BRIGHT_BLUE" "$RESET"
    echo "  Faixa usada pelo script para classificar uma métrica."
    echo "  São referências heurísticas, não limites absolutos do OpenZFS."

    echo

    printf '%sCAMINHO SIMPLIFICADO DE UMA LEITURA%s\n' \
        "$BOLD$BRIGHT_CYAN" "$RESET"

    echo
    echo "       Aplicação / VM"
    echo "             |"
    echo "             v"
    echo "           [ ARC ]        RAM"
    echo "             |"
    echo "           MISS"
    echo "             |"
    echo "             v"
    echo "         [ L2ARC ]        SSD/NVMe"
    echo "             |"
    echo "           MISS"
    echo "             |"
    echo "             v"
    echo "        [ ZFS POOL ]      HDD / RAIDZ"
    echo

    printf '%sORDEM RECOMENDADA DE LEITURA%s\n' \
        "$BOLD$BRIGHT_CYAN" "$RESET"

    echo
    echo "  1. Demand Data Miss"
    echo "     -> Está escapando muita leitura do ARC?"
    echo
    echo "  2. Low-memory aborts"
    echo "     -> Há pressão de memória afetando o L2ARC?"
    echo
    echo "  3. L2ARC Hit"
    echo "     -> Quando o ARC falha, o SSD está ajudando?"
    echo
    echo "  4. MRU x MFU"
    echo "     -> O cache contém dados reutilizados ou dados de passagem?"
    echo
    echo "  5. L2ARC Writes"
    echo "     -> Estamos escrevendo muito no SSD para pouco benefício?"
    echo
    echo "  6. ARC Total"
    echo "     -> Use apenas como visão geral."
    echo

    printf '%sREGRA PRÁTICA%s\n' "$BOLD$BRIGHT_GREEN" "$RESET"

    echo
    echo "  Demand Miss baixo + L2ARC Hit baixo"
    echo "  pode ser perfeitamente normal:"
    echo
    echo "      o ARC já está atendendo quase toda a carga."
    echo

    printf '%sSINAL DE ATENÇÃO%s\n' "$BOLD$BRIGHT_YELLOW" "$RESET"

    echo
    echo "  Demand Miss alto"
    echo "  + L2ARC Hit baixo"
    echo "  + MRU muito alto"
    echo "  + muitos writes no L2ARC"
    echo
    echo "  pode indicar baixa eficiência ou poluição do L2ARC."
}

# =============================================================================
# HELP
# =============================================================================

show_help() {

    echo
    line

    printf '%s%s ARC / L2ARC MONITOR%s\n' \
        "$BOLD" "$BRIGHT_CYAN" "$RESET"

    line

    cat <<EOF

Uso:

  /root/arc-monitor.sh start

      Inicia ou reinicia uma janela de medição.

  /root/arc-monitor.sh report

      Mostra o relatório desde o último start.

  /root/arc-monitor.sh thresholds

      Mostra os thresholds utilizados.

  /root/arc-monitor.sh glossary

      Explica ARC, L2ARC, MRU, MFU, hit, miss etc.

Exemplo:

  /root/arc-monitor.sh start

  # Deixe o storage trabalhar normalmente por 30-60 minutos.

  /root/arc-monitor.sh report

IMPORTANTE:

  O script NÃO gera carga no pool e NÃO altera configurações do ZFS.

EOF

    line
}

# =============================================================================
# EXECUÇÃO
# =============================================================================

case "${1:-help}" in

# -----------------------------------------------------------------------------
# START
# -----------------------------------------------------------------------------

start|reset)

    if [[ ! -r "$STATS" ]]; then

        printf '%sERRO:%s não consigo ler %s\n' \
            "$BRIGHT_RED" "$RESET" "$STATS"

        exit 1
    fi

    snapshot > "$STATE"

    echo
    line

    printf '%s%s ARC/L2ARC - MEDIÇÃO INICIADA%s\n' \
        "$BOLD" "$BRIGHT_CYAN" "$RESET"

    line

    printf '%-24s %s\n' \
        "Host:" \
        "$(value "$STATE" host)"

    printf '%-24s %s\n' \
        "Início:" \
        "$(value "$STATE" date)"

    printf '%-24s %s\n' \
        "Snapshot:" \
        "$STATE"

    echo

    printf '%sDeixe o storage operar normalmente.%s\n' \
        "$GREEN" "$RESET"

    echo
    echo "Depois execute:"
    echo

    printf '  %s/root/arc-monitor.sh report%s\n' \
        "$BOLD$BRIGHT_GREEN" "$RESET"

    echo

    printf '%sO report pode ser executado várias vezes sem perder o início.%s\n' \
        "$DIM" "$RESET"

    echo
    line
    ;;

# -----------------------------------------------------------------------------
# REPORT
# -----------------------------------------------------------------------------

report)

    if [[ ! -f "$STATE" ]]; then

        printf '%sERRO:%s não existe snapshot inicial.\n' \
            "$BRIGHT_RED" "$RESET"

        echo
        echo "Execute:"
        echo
        echo "  /root/arc-monitor.sh start"

        exit 1
    fi

    CURRENT=$(mktemp)
    trap 'rm -f "$CURRENT"' EXIT

    snapshot > "$CURRENT"

    B_TS=$(num_or_zero "$(value "$STATE" timestamp)")
    A_TS=$(num_or_zero "$(value "$CURRENT" timestamp)")

    SECS=$((A_TS - B_TS))

    if (( SECS <= 0 )); then

        echo "ERRO: intervalo inválido."

        exit 1
    fi

    # =========================================================================
    # ARC TOTAL
    # =========================================================================

    HITS=$(delta hits)
    IOHITS=$(delta iohits)
    MISSES=$(delta misses)

    TOTAL=$((HITS + IOHITS + MISSES))

    ARC_HIT_P=$(pct_num "$HITS" "$TOTAL")
    ARC_IO_P=$(pct_num "$IOHITS" "$TOTAL")
    ARC_MISS_P=$(pct_num "$MISSES" "$TOTAL")

    # =========================================================================
    # DEMAND DATA
    # =========================================================================

    DD_HITS=$(delta demand_data_hits)
    DD_IOHITS=$(delta demand_data_iohits)
    DD_MISSES=$(delta demand_data_misses)

    DD_TOTAL=$((DD_HITS + DD_IOHITS + DD_MISSES))

    DD_HIT_P=$(pct_num "$DD_HITS" "$DD_TOTAL")
    DD_IO_P=$(pct_num "$DD_IOHITS" "$DD_TOTAL")
    DD_MISS_P=$(pct_num "$DD_MISSES" "$DD_TOTAL")

    # =========================================================================
    # L2ARC
    # =========================================================================

    L2_HITS=$(delta l2_hits)
    L2_MISSES=$(delta l2_misses)

    L2_TOTAL=$((L2_HITS + L2_MISSES))

    L2_HIT_P=$(pct_num "$L2_HITS" "$L2_TOTAL")
    L2_MISS_P=$(pct_num "$L2_MISSES" "$L2_TOTAL")

    L2_WRITES=$(delta l2_write_bytes)
    L2_LOWMEM=$(delta l2_abort_lowmem)

    L2_SIZE_BEFORE=$(num_or_zero "$(value "$STATE" l2_size)")
    L2_SIZE_NOW=$(num_or_zero "$(value "$CURRENT" l2_size)")

    L2_ASIZE_BEFORE=$(num_or_zero "$(value "$STATE" l2_asize)")
    L2_ASIZE_NOW=$(num_or_zero "$(value "$CURRENT" l2_asize)")

    L2_SIZE_DELTA=$((L2_SIZE_NOW - L2_SIZE_BEFORE))
    L2_ASIZE_DELTA=$((L2_ASIZE_NOW - L2_ASIZE_BEFORE))

    L2_MRU=$(num_or_zero "$(value "$CURRENT" l2_mru_asize)")
    L2_MFU=$(num_or_zero "$(value "$CURRENT" l2_mfu_asize)")
    L2_PREFETCH=$(num_or_zero "$(value "$CURRENT" l2_prefetch_asize)")

    L2_MRU_P=$(pct_num "$L2_MRU" "$L2_ASIZE_NOW")
    L2_MFU_P=$(pct_num "$L2_MFU" "$L2_ASIZE_NOW")
    L2_PREFETCH_P=$(pct_num "$L2_PREFETCH" "$L2_ASIZE_NOW")

    # =========================================================================
    # MEMÓRIA
    # =========================================================================

    MEM_NOW=$(num_or_zero "$(value "$CURRENT" mem_available)")

    ARC_SIZE_NOW=$(num_or_zero "$(value "$CURRENT" size)")
    ARC_CMAX_NOW=$(num_or_zero "$(value "$CURRENT" c_max)")

    # =========================================================================
    # CLASSIFICAÇÕES
    # =========================================================================

    DD_STATUS=$(classify_demand "$DD_MISS_P" "$DD_TOTAL")

    L2_STATUS=$(classify_l2 "$L2_HIT_P" "$L2_TOTAL")

    POLLUTION=$(
        pollution_status \
            "$L2_MRU_P" \
            "$L2_HIT_P" \
            "$L2_TOTAL"
    )

    # =========================================================================
    # RESULTADO GERAL
    # =========================================================================

    if (( L2_LOWMEM > 0 )); then

        OVERALL="RUIM - houve low-memory abort"

    elif [[ "$DD_STATUS" == "RUIM" ]]; then

        OVERALL="RUIM - demand miss alto"

    elif [[ "$DD_STATUS" == "ATENCAO" ]]; then

        OVERALL="ATENCAO - demand miss acima do desejável"

    elif [[ "$DD_STATUS" == "AMOSTRA BAIXA" ]]; then

        OVERALL="INCONCLUSIVO - pouca amostra de Demand Data"

    elif [[ "$DD_STATUS" == "EXCELENTE" ]]; then

        OVERALL="EXCELENTE - ARC atendendo muito bem a carga atual"

    else

        OVERALL="BOM - ARC atendendo bem a carga atual"

    fi

    # =========================================================================
    # CABEÇALHO
    # =========================================================================

    echo
    line

    printf '%s%s ARC / L2ARC - RELATÓRIO DA JANELA%s\n' \
        "$BOLD" "$BRIGHT_CYAN" "$RESET"

    line

    printf '%-25s %s\n' \
        "Host:" \
        "$(value "$CURRENT" host)"

    printf '%-25s %s\n' \
        "Início:" \
        "$(value "$STATE" date)"

    printf '%-25s %s\n' \
        "Fim:" \
        "$(value "$CURRENT" date)"

    printf '%-25s %s\n' \
        "Duração:" \
        "$(duration_fmt "$SECS")"

    echo

    printf '%s%-25s%s ' \
        "$BOLD" \
        "RESULTADO GERAL:" \
        "$RESET"

    status_color "$OVERALL"

    echo

    # =========================================================================
    # DEMAND DATA
    # =========================================================================

    section "DEMAND DATA - INDICADOR PRINCIPAL DE PERFORMANCE"

    printf '%-25s %12s %12s\n' \
        "Métrica" \
        "Quantidade" \
        "Percentual"

    printf '%-25s %12s %12s\n' \
        "Demand hits" \
        "$(human_count "$DD_HITS")" \
        "$(pct_fmt "$DD_HIT_P")"

    printf '%-25s %12s %12s\n' \
        "Demand I/O hits" \
        "$(human_count "$DD_IOHITS")" \
        "$(pct_fmt "$DD_IO_P")"

    printf '%-25s %12s %12s\n' \
        "Demand misses" \
        "$(human_count "$DD_MISSES")" \
        "$(pct_fmt "$DD_MISS_P")"

    printf '%-25s %12s\n' \
        "Amostra" \
        "$(human_count "$DD_TOTAL")"

    echo

    printf '%-25s ' "Status Demand:"

    status_color "$DD_STATUS"

    echo

    # =========================================================================
    # ARC TOTAL
    # =========================================================================

    section "ARC TOTAL - CONTEXTO SECUNDÁRIO"

    printf '%-25s %12s %12s\n' \
        "Métrica" \
        "Quantidade" \
        "Percentual"

    printf '%-25s %12s %12s\n' \
        "ARC hits" \
        "$(human_count "$HITS")" \
        "$(pct_fmt "$ARC_HIT_P")"

    printf '%-25s %12s %12s\n' \
        "ARC I/O hits" \
        "$(human_count "$IOHITS")" \
        "$(pct_fmt "$ARC_IO_P")"

    printf '%-25s %12s %12s\n' \
        "ARC misses" \
        "$(human_count "$MISSES")" \
        "$(pct_fmt "$ARC_MISS_P")"

    # =========================================================================
    # L2ARC
    # =========================================================================

    section "L2ARC - EFICIÊNCIA NA JANELA"

    printf '%-25s %12s %12s\n' \
        "Métrica" \
        "Quantidade" \
        "Percentual"

    printf '%-25s %12s %12s\n' \
        "L2ARC hits" \
        "$(human_count "$L2_HITS")" \
        "$(pct_fmt "$L2_HIT_P")"

    printf '%-25s %12s %12s\n' \
        "L2ARC misses" \
        "$(human_count "$L2_MISSES")" \
        "$(pct_fmt "$L2_MISS_P")"

    printf '%-25s %12s\n' \
        "Consultas L2ARC" \
        "$(human_count "$L2_TOTAL")"

    echo

    printf '%-25s ' "Status L2ARC:"

    status_color "$L2_STATUS"

    echo

    if (( L2_TOTAL < MIN_L2_SAMPLES )); then

        echo

        printf '%sOBSERVAÇÃO:%s\n' \
            "$BRIGHT_BLUE" "$RESET"

        echo "  Poucas consultas ao L2ARC nesta janela."
        echo "  Não use este hit ratio isoladamente para decidir tuning."

    fi

    # =========================================================================
    # PERFIL L2ARC
    # =========================================================================

    section "L2ARC - ATIVIDADE / PERFIL"

    printf '%-31s %s\n' \
        "Escrito na janela:" \
        "$(human_bytes "$L2_WRITES")"

    printf '%-31s %s\n' \
        "Taxa média de escrita:" \
        "$(human_rate "$L2_WRITES" "$SECS")"

    printf '%-31s %s\n' \
        "Variação logical size:" \
        "$(human_bytes "$L2_SIZE_DELTA")"

    printf '%-31s %s\n' \
        "Variação allocated size:" \
        "$(human_bytes "$L2_ASIZE_DELTA")"

    printf '%-31s %s\n' \
        "L2ARC logical size atual:" \
        "$(human_bytes "$L2_SIZE_NOW")"

    printf '%-31s %s\n' \
        "L2ARC allocated atual:" \
        "$(human_bytes "$L2_ASIZE_NOW")"

    echo

    printf '%-31s %s (%s)\n' \
        "MRU atual:" \
        "$(human_bytes "$L2_MRU")" \
        "$(pct_fmt "$L2_MRU_P")"

    printf '%-31s %s (%s)\n' \
        "MFU atual:" \
        "$(human_bytes "$L2_MFU")" \
        "$(pct_fmt "$L2_MFU_P")"

    printf '%-31s %s (%s)\n' \
        "Prefetch atual:" \
        "$(human_bytes "$L2_PREFETCH")" \
        "$(pct_fmt "$L2_PREFETCH_P")"

    echo

    printf '%-31s ' "Indício de poluição/churn:"

    status_color "$POLLUTION"

    echo

    # =========================================================================
    # MEMÓRIA
    # =========================================================================

    section "MEMÓRIA / ARC"

    printf '%-31s %s\n' \
        "ARC atual:" \
        "$(human_bytes "$ARC_SIZE_NOW")"

    printf '%-31s %s\n' \
        "ARC máximo:" \
        "$(human_bytes "$ARC_CMAX_NOW")"

    printf '%-31s %s\n' \
        "MemAvailable Linux:" \
        "$(human_bytes "$MEM_NOW")"

    printf '%-31s ' \
        "Novos low-memory aborts:"

    if (( L2_LOWMEM == 0 )); then

        printf '%s0 [OK]%s\n' \
            "$GREEN" "$RESET"

    else

        printf '%s%s [RUIM]%s\n' \
            "$BRIGHT_RED" \
            "$L2_LOWMEM" \
            "$RESET"

    fi

    # =========================================================================
    # DOCUMENTAÇÃO NO PRÓPRIO RELATÓRIO
    # =========================================================================

    print_thresholds

    print_glossary

    echo
    line
    ;;

# -----------------------------------------------------------------------------
# THRESHOLDS
# -----------------------------------------------------------------------------

thresholds)

    print_thresholds
    ;;

# -----------------------------------------------------------------------------
# GLOSSARY
# -----------------------------------------------------------------------------

glossary)

    print_glossary
    ;;

# -----------------------------------------------------------------------------
# HELP
# -----------------------------------------------------------------------------

help|-h|--help)

    show_help
    ;;

# -----------------------------------------------------------------------------
# INVALID
# -----------------------------------------------------------------------------

*)

    echo "Comando inválido: $1"

    show_help

    exit 1
    ;;

esac

EOF

chmod 700 /root/arc-monitor.sh

PROPÓSITO

Medir a eficiência do cache durante uma janela real de utilização, comparando os contadores do kernel entre dois momentos.

Quando usar: Quando os números acumulados desde o boot já não representam a carga atual e é preciso medir um período específico.

Pré-requisitos: TrueNAS SCALE ou OpenZFS. O script apenas lê contadores: não gera carga no pool nem altera parâmetros.