Por que df e df -h mostram valor diferente? Como o df -h executa o cálculo?

5

como exatamente funciona o df -h? Se eu executar df , obtenho isto:

Filesystem     1K-blocks    Used Available Use% Mounted on
/dev/simfs      41943040 7659828  34283212  19% /

Se eu executar df -h , obtenho isto:

Filesystem      Size  Used Avail Use% Mounted on
/dev/simfs       40G  7.4G   33G  19% /

A questão é como obter os mesmos números?

41943040/1024/1024 = 40 OK, vamos dividir os outros por 1024.

7659828 / 1024 / 1024 = 7,304981

Então talvez por 1000?

7659828 / 1000 / 1000 = 7,659828

Como df -h obteve 7,4G?

34283212 / 1024 / 1024 = 32,695, which is ±33G

Embora df seja open source, eu clonei o repo e verifiquei o código. Foi o que eu encontrei:

for (col = 0; col < ncolumns; col++)
    {
      char *cell = NULL;
      char const *header = _(columns[col]->caption);

      if (columns[col]->field == SIZE_FIELD
          && (header_mode == DEFAULT_MODE
              || (header_mode == OUTPUT_MODE
                  && !(human_output_opts & human_autoscale))))
        {
          char buf[LONGEST_HUMAN_READABLE + 1];

          int opts = (human_suppress_point_zero
                      | human_autoscale | human_SI
                      | (human_output_opts
                         & (human_group_digits | human_base_1024 | human_B)));

          /* Prefer the base that makes the human-readable value more exact,
             if there is a difference.  */

          uintmax_t q1000 = output_block_size;
          uintmax_t q1024 = output_block_size;
          bool divisible_by_1000;
          bool divisible_by_1024;

          do
            {
              divisible_by_1000 = q1000 % 1000 == 0;  q1000 /= 1000;
              divisible_by_1024 = q1024 % 1024 == 0;  q1024 /= 1024;
            }
          while (divisible_by_1000 & divisible_by_1024);

          if (divisible_by_1000 < divisible_by_1024)
            opts |= human_base_1024;
          if (divisible_by_1024 < divisible_by_1000)
            opts &= ~human_base_1024;
          if (! (opts & human_base_1024))
            opts |= human_B;

          char *num = human_readable (output_block_size, buf, opts, 1, 1);

          /* Reset the header back to the default in OUTPUT_MODE.  */
          header = _("blocks");

          /* TRANSLATORS: this is the "1K-blocks" header in "df" output.  */
          if (asprintf (&cell, _("%s-%s"), num, header) == -1)
            cell = NULL;
        }
      else if (header_mode == POSIX_MODE && columns[col]->field == SIZE_FIELD)
        {
          char buf[INT_BUFSIZE_BOUND (uintmax_t)];
          char *num = umaxtostr (output_block_size, buf);

          /* TRANSLATORS: this is the "1024-blocks" header in "df -P".  */
          if (asprintf (&cell, _("%s-%s"), num, header) == -1)
            cell = NULL;
        }
      else
        cell = strdup (header);

      if (!cell)
        xalloc_die ();

      hide_problematic_chars (cell);

      table[nrows - 1][col] = cell;

      columns[col]->width = MAX (columns[col]->width, mbswidth (cell, 0));
    }

Eu não tenho experiência com essa linguagem, mas pelo que entendi, ela tenta verificar se o valor em cada coluna é divisível por 1024 ou 1000 e escolha o que é melhor para renderizar valores para a opção -h . Mas eu não tenho o mesmo valor, não importa se eu divido por 1000 ou 1024. Por quê?

Eu acho que sei porque. Ele verifica para dividir por 1000 ou 1024 em cada divisão.

          if (divisible_by_1000 < divisible_by_1024)
            opts |= human_base_1024;
          if (divisible_by_1024 < divisible_by_1000)
            opts &= ~human_base_1024;
          if (! (opts & human_base_1024))
            opts |= human_B;

então vamos quebrar 7659828/1024/1024 = 7,304981. -h deu resposta de 7.4G

7659828 / 1024 = 7480,xxx
7659828 / 1000 = 7659,xxx

enquanto 7659 é mais que 7480, divida por 1024.

Ainda um grande número, vamos continuar:

7659828 / 1024 / 1024 = 7,xxx  (7,3049..)
7659828 / 1024 / 1000 = 7,xxx  (7,4803..)

leva 1000 agora e dá 7,48 e eu acredito em algum lugar no código que é arredondado para baixo, então "melhor dizer menos que mais" enquanto você pode colocar 7,4G de dados, mas você pode ' Coloque 7,5G.

Mesma história com 33.4G

34283212 / 1024 / 1000 = 33.47...

Assim, torna-se 33G.

    
por Lukas 30.05.2018 / 23:42

2 respostas

5

O código que você postou é da função "get_header" que gera o texto na primeira linha. No seu caso, isso se aplica ao título "blocos 1K" (chame df -B1023 para ver a diferença).

Importante notar: "1K" refere-se a blocos de 1024 bytes, não a blocos de 1000 bytes (indicados por "blocos de 1kB", consulte df -B1000 )

O cálculo dos números no formato legível é tratado pela função "human_readable" (human.c: 153). Em df.c: 1571 você pode encontrar as opções que são usadas quando chamadas com o sinalizador -h :

case 'h':
    human_output_opts = human_autoscale | human_SI | human_base_1024;
    output_block_size = 1;
    break;

Todos os cálculos são feitos com base 1024 em formato legível por humanos ("-h"). Além do human_output_opts mostrado, existe uma configuração padrão que se aplica aqui (veja human.h, enum declaration):

/* The following three options are mutually exclusive.  */
/* Round to plus infinity (default).  */
human_ceiling = 0,
/* Round to nearest, ties to even.  */
human_round_to_nearest = 1,
/* Round to minus infinity.  */
human_floor = 2,

Como human_output_opts não inclui human_round_to_nearest ou human_floor, ele usará seu valor padrão human_ceiling. Todos os valores calculados serão arredondados.

Para verificar as configurações, podemos tentar calcular o formato legível com base nos blocos 1K de df :

Size = ceil(41943040/1024/1024) = ceil(40) = 40
Used = ceil(7659828/1024/1024) = ceil(7.305) = 7.4
Available = ceil(34283212/1024/1024) = ceil(32.695) = 33

Qual é o mesmo que a saída de df -h .

(... e se você preferir o formato de 1000 bytes, você pode simplesmente chamar df -H ).

    
por 31.05.2018 / 12:49
0

Nem o programa df do FreeBSD (de onde o df -h é originalmente) nem a implementação df do Solaris se comportam dessa maneira.

Como os fontes do Solaris são OpenSource, você pode verificar se você pode compilar df no seu sistema operacional:

    
por 31.05.2018 / 12:34