Contabilização de “falta de memória” do sysctl

1

Estou no OS X Yosemite, executei este código:

unsigned long num_;
sysctl((int[]){CTL_HW, HW_PHYSMEM}, 2, &num_, &len, NULL, 0);
printf("AMT MEM: , %lu\n", num_);

e recebendo de volta 140735340871680

O que não faz sentido: (no IPython 3)

In [3]: mem / (1024 ** 3)
mem / (1024 ** 3)
Out[3]: 131070.0

Desde que eu tenha 16 GB de memória física. Eu olhei para o cabeçalho de sysctl.h e veja

#define HW_PHYSMEM   5      /* int: total memory */
#define HW_USERMEM   6      /* int: non-kernel memory */

Então agora isso realmente não faz sentido, eu poderia acreditar na figura se eu passasse HW_USERMEM , mas eu pedi especialmente a memória total. O que dá?

Eu cometi algum erro estúpido de matemática no código Python?

    
por Edgar Aroutiounian 24.12.2014 / 18:27

1 resposta

2

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é:

  1. Desculpe, ainda não tenho meus poderes de 2 memorizados nos bilhões. :)

  2. Testado no OpenBSD 5.5 e no NetBSD 6.0.1.

por 24.12.2014 / 19:44

Tags