Did I do some stupid math mistake in the Python code?
Na verdade, é o seu código C que está errado.
A correção mais direta para o seu código é esta:
#include <stdio.h>
#include <sys/sysctl.h>
int main(void)
{
int64_t bytes;
size_t len = sizeof(bytes);
sysctl({ CTL_HW, HW_PHYSMEM64 }, 2, &bytes, &len, NULL, 0);
int megs = bytes / 1024 / 1024;
printf("AMT MEM: %d MiB\n", megs);
}
Se você usar HW_PHYSMEM
, ele só funcionará em máquinas com até 2 GiB de RAM, já que está armazenando uma contagem de bytes em uma variável que é considerada de 32 bits. A alteração em um argumento de 64 bits requer um novo valor sysctl
para evitar a quebra de compatibilidade. É por isso que a página sysctl(3)
man do OpenBSD diz que HW_PHYSMEM
é obsoleto.
Eu tomei algumas liberdades no código acima. Eu estou fazendo parte da matemática no código C para que eu possa ler a saída sem alimentá-la através de uma calculadora.¹ Eu também fixei vários avisos do tipo inteiro e renomei a variável num_
para bytes
para clareza.
Esse código funciona bem em alguns dos BSDs, ² mas não no OS X ou no FreeBSD.
Ao olhar para a página de manual do OS X, parece que eles querem que você use sysctlbyname(3)
em vez disso. Isso funciona bem aqui no Yosemite:
#include <stdio.h>
#include <sys/sysctl.h>
int main(void)
{
int64_t bytes;
size_t len = sizeof(bytes);
sysctlbyname("hw.memsize", &bytes, &len, NULL, 0);
int megs = bytes / 1024 / 1024;
printf("AMT MEM: %d MiB\n", megs);
}
Eu tenho 16 GiB de RAM física e relata corretamente 16384 MiB.
Se você tentar isso no FreeBSD, receberá 0 como resposta. Um pouco de cutucando diz que ele quer hw.physmem
.
E mais uma vez batemos na parede, porque tentar esse sysctlbyname
valor no OS X dá o tipo de resultados falsos que você encontrou.
Portanto, a resposta final é que tudo isso é altamente específico do sistema. Se você precisar que ele seja multi-plataforma, você precisará de muito #ifdefs
.
Notas de rodapé:
-
Desculpe, ainda não tenho meus poderes de 2 memorizados nos bilhões. :)
-
Testado no OpenBSD 5.5 e no NetBSD 6.0.1.