c++ - sacar - Convertir statvfs a porcentaje libre correctamente
restar porcentaje en c++ (5)
En su Edición # 2, el cálculo de% de uso debe actualizarse para que coincida con la salida de df:
100.0 * (double) (vfs.f_blocks - vfs.f_bfree) / (double) (vfs.f_blocks - vfs.f_bfree + vfs.f_bavail)
Razonamiento:
Utilizado = f_blocks - f_bfree
Avail = f_bavail
df% = Usado / (Usado + Disponibilidad)
Tengo un programa de prueba terriblemente sencillo que imprime los siguientes números.
es decir
int main(int argc, char* argv[])
struct statvfs vfs;
statvfs(argv[1], &vfs);
printf("f_bsize (block size): %lu/n"
"f_frsize (fragment size): %lu/n"
"f_blocks (size of fs in f_frsize units): %lu/n"
"f_bfree (free blocks): %lu/n"
"f_bavail free blocks for unprivileged users): %lu/n"
"f_files (inodes): %lu/n"
"f_ffree (free inodes): %lu/n"
"f_favail (free inodes for unprivileged users): %lu/n"
"f_fsid (file system ID): %lu/n"
"f_flag (mount flags): %lu/n"
"f_namemax (maximum filename length)%lu/n",
vfs.f_bsize,
vfs.f_frsize,
vfs.f_blocks,
vfs.f_bfree,
vfs.f_bavail,
vfs.f_files,
vfs.f_ffree,
vfs.f_favail,
vfs.f_fsid,
vfs.f_flag,
vfs.f_namemax);
return 0;
}
Imprime:
f_bsize (block size): 4096
f_frsize (fragment size): 4096
f_blocks (size of fs in f_frsize units): 10534466
f_bfree (free blocks): 6994546
f_bavail free blocks for unprivileged users): 6459417
f_files (inodes): 2678784
f_ffree (free inodes): 2402069
f_favail (free inodes for unprivileged users): 2402069
f_fsid (file system ID): 12719298601114463092
f_flag (mount flags): 4096
f_namemax (maximum filename length)255
df imprime para la raíz fs:
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/sda5 42137864 14159676 25837672 36% /
Pero aquí es donde estoy confundido.
25837672 + 14159676! = 42137846 (en realidad 39997348)
Por lo tanto, si tuviera que hacer el cálculo 14159676/42137864 * 100 obtendré el 33%, no el 36% como impresiones df.
Pero si me calculo
14159676/39997348 * 100 Tengo 35%.
¿Por qué todas las discrepancias y dónde está df obteniendo el número 42137864? ¿Está relacionado con alguna conversión a bloques de 1k frente al tamaño real del bloque del sistema que es 4k?
Esto se integrará en mi aplicación de almacenamiento en caché para indicarme cuándo el disco está en algún umbral ... por ejemplo, 90% antes de que comience a liberar bloques de tamaño fijo con un tamaño de 2 ^ n. Entonces, lo que busco es una función que me dé un% de precisión razonable.
EDIT: Ahora puedo hacer coincidir lo que df imprime. Excepto por el% utilizado. Nos hace preguntarnos qué tan preciso es todo esto. ¿Cuál es el tamaño del fragmento?
unsigned long total = vfs.f_blocks * vfs.f_frsize / 1024;
unsigned long available = vfs.f_bavail * vfs.f_frsize / 1024;
unsigned long free = vfs.f_bfree * vfs.f_frsize / 1024;
printf("Total: %luK/n", total);
printf("Available: %luK/n", available);
printf("Used: %luK/n", total - free);
EDIT2:
unsigned long total = vfs.f_blocks * vfs.f_frsize / 1024;
unsigned long available = vfs.f_bavail * vfs.f_frsize / 1024;
unsigned long free = vfs.f_bfree * vfs.f_frsize / 1024;
unsigned long used = total - free;
printf("Total: %luK/n", total);
printf("Available: %luK/n", available);
printf("Used: %luK/n", used);
printf("Free: %luK/n", free);
// Calculate % used based on f_bavail not f_bfree. This is still giving out a different answer to df???
printf("Use%%: %f%%/n", (vfs.f_blocks - vfs.f_bavail) / (double)(vfs.f_blocks) * 100.0);
f_bsize (block size): 4096
f_frsize (fragment size): 4096
f_blocks (size of fs in f_frsize units): 10534466
f_bfree (free blocks): 6994182
f_bavail (free blocks for unprivileged users): 6459053
f_files (inodes): 2678784
f_ffree (free inodes): 2402056
f_favail (free inodes for unprivileged users): 2402056
f_fsid (file system ID): 12719298601114463092
f_flag (mount flags): 4096
f_namemax (maximum filename length)255
Total: 42137864K
Available: 25836212K
Used: 14161136K
Free: 27976728K
Use%: 38.686470%
matth@kubuntu:~/dev$ df
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/sda5 42137864 14161136 25836212 36% /
Obtengo el 38%, no el 36. Si se calcula por f_bfree, obtengo el 33%. ¿Está df equivocado o esto nunca va a ser preciso? Si este es el caso, entonces quiero apoyarme en ser conservador.
Esto es lo más cercano que he encontrado para hacer coincidir la salida de df -h
para el porcentaje utilizado:
const uint GB = (1024 * 1024) * 1024;
struct statvfs buffer;
int ret = statvfs(diskMountPoint.c_str(), &buffer);
const double total = ceil((double)(buffer.f_blocks * buffer.f_frsize) / GB);
const double available = ceil((double)(buffer.f_bfree * buffer.f_frsize) / GB);
const double used = total - available;
const double usedPercentage = ceil((double)(used / total) * (double)100);
return usedPercentage;
Las métricas de statvfs son un poco confusas. Puede usar el código fuente psutil como ejemplo de cómo obtener valores significativos en bytes: https://github.com/giampaolo/psutil/blob/f4734c80203023458cb05b1499db611ed4916af2/psutil/_psposix.py#L119
Los datos de df
pueden estar basados en f_bavail
, no en f_bfree
. Puede que le resulte útil consultar el código fuente de df para ver cómo hace las cosas. Tiene una serie de casos de borde con los que debe lidiar (por ejemplo, cuando el espacio utilizado excede la cantidad de espacio disponible para usuarios no root), pero el código relevante para el caso normal está aquí:
uintmax_t u100 = used * 100;
uintmax_t nonroot_total = used + available;
pct = u100 / nonroot_total + (u100 % nonroot_total != 0);
En otras palabras, 100 * used / (used + available)
, redondeado hacia arriba. Al conectar los valores de su salida de df se obtienen 100 * 14159676 / (14159676 + 25837672) = 35.4015371
, que se redondearon al 36%, tal como se calculó df
.
Parece que me confundo cada vez que trato con este problema. Espero que el siguiente código C sea útil para alguien que busca un porcentaje del espacio utilizado:
/*
* It is helpful to use a picture to aid the calculation of disk space.
*
* |<--------------------- f_blocks ---------------------------->|
* |<---------------- f_bfree ------------------>|
*
* ---------------------------------------------------------------
* | USED | f_bavail | Reserved for root |
* ---------------------------------------------------------------
*
* We want the percentage of used blocks vs. all the
* non-reserved blocks: USED / (USED + f_bavail)
*/
fsblkcnt_t used = fs_stats.f_blocks - fs_stats.f_bfree;
double fraction_used = (double) used / ((double) used + (double) fs_stats.f_bavail);
uint8_t percent_used = (uint8_t) ((fraction_used * 100.0) + 0.5); // Add 0.5 for rounding