¿Por qué df y df -h muestran valores diferentes? ¿Cómo realiza df -h el cálculo?

¿Por qué df y df -h muestran valores diferentes? ¿Cómo realiza df -h el cálculo?

¿Cómo funciona exactamente df -h? Si ejecuto dfme sale esto:

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

Si ejecuto df -hme sale esto:

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

La pregunta es ¿cómo obtener los mismos números?

41943040/1024/1024 = 40 Bien, dividamos los demás por 1024.

7659828 / 1024 / 1024 = 7,304981

¿Entonces tal vez para el año 1000?

7659828 / 1000 / 1000 = 7,659828

¿Cómo df -hconsiguió 7,4G?

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

Si bien df es de código abierto, heclonadoel repositorio y verificó el código. Eso es lo que encontré:

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));
    }

No tengo experiencia con este lenguaje, pero según tengo entendido, intenta verificar si el valor de cada columna es divisible por 1024 o 1000 y elige lo que sea mejor para representar los valores de la -hopción. Pero no obtengo el mismo valor sin importar si lo divido entre 1000 o 1024. ¿Por qué?

Creo que sé por qué. Comprueba dividir por 1000 o 1024 encadadivisión.

          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;

así que desciframos 7659828/1024/1024 = 7,304981.-h dio respuesta de7,4G

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

mientras que 7659 es mayor que 7480, divídalo entre 1024.

Sigue siendo un número grande, continuemos:

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

se necesita 1000 ahora y da 7,48 y yocreerEn algún lugar del código se redondea hacia abajo, por lo que "es mejor decir menos que más", mientras que puedes ingresar 7,4G de datos pero no puedes ingresar 7,5G.

La misma historia con 33.4G

34283212 / 1024 / 1000 = 33.47...

Entonces se convierte en 33G.

Respuesta1

El código que publicó proviene de la función "get_header" que genera el texto en la primera fila. En su caso, esto se aplica al encabezado "1K-blocks" (llame df -B1023para ver la diferencia).

Importante tener en cuenta: "1K" se refiere a bloques de 1024 bytes, no a bloques de 1000 bytes (indicados por "bloques de 1kB", consulte df -B1000)

El cálculo de los números en formato legible por humanos se realiza mediante la función "human_readable" (human.c:153). En df.c:1571 puedes encontrar las opciones que se utilizan cuando se llama con la -hbandera:

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

Todos los cálculos se realizan con base 1024 en formato legible por humanos ("-h"). Además de los human_output_opts mostrados, hay una configuración predeterminada que se aplica aquí (consulte human.h, declaración de enumeración):

/* 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 no incluye human_round_to_nearest o human_floor, utilizará su valor predeterminado de human_ceiling. Por lo tanto, todos los valores calculados se redondearán hacia arriba.

Para verificar la configuración, podemos intentar calcular el formato legible por humanos en función de los bloques de 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

Que es lo mismo que la salida de df -h.

(... y si prefieres el formato de 1000 bytes, puedes simplemente llamar df -H).

Respuesta2

Ni el dfprograma de FreeBSD (de aquí es df -horiginario) ni la dfimplementación de Solaris se comportan de esta manera.

Dado que las fuentes de Solaris son OpenSource, puede verificar si puede compilar dfen su sistema operativo:

información relacionada