confuso sobre o PSS em / proc / pid / maps

1

Encontrei uma ótima explicação sobre os smaps de informações sobre smaps

No meu entender, pensei que

shared_clean + shared_dirty + private_clean + private_dirty = rss

Eu escrevi um programa para verificar isso:

void sa();
int main(int argc,char *argv[])
{
    sa();
    sleep(1000);
}

void sa()
{
   char *pi=new char[1024*1024*10];
   for(int i=0;i<4;++i) {   //dirty should be 4M
        for(int j=0;j<1024*1024;++j){
                *pi='o';
                pi++;
        }
   }
   int cnt;
   for(int i=0;i<6;++i) {   //clean should be 6M
        for(int j=0;j<1024*1024;++j){
                cnt+=*pi;
                pi++;
        }
   }
   printf("%d",cnt);
}

Mas, para minha surpresa, o /proc/pid/smaps é:

09b69000-09b8c000 rw-p 00000000 00:00 0 [heap]
...
Size:           10252 kB
Rss:            10252 kB
Pss:             4108 kB //<----I thought it should be 10M
Shared_Clean:       0 kB
Shared_Dirty:       0 kB
Private_Clean:      0 kB //<----I thought it should be 6M
Private_Dirty:   4108 kB
Referenced:      4108 kB
Swap:               0 kB
KernelPageSize:     4 kB
MMUPageSize:        4 kB

Algo de errado com o meu entendimento?

de acordo com a resposta do Mat,

The pages in the 6M you're only reading can't really be considered clean. A clean page is one that is synchronized with its backing store (whatever that is, swap, a file, etc.).

.

Eu reescrevo os códigos usando o mmap, desta vez o resultado é o esperado:)

crie primeiro um arquivo fictício:

time dd if=/dev/zero of=test.bin bs=30000000 count=1

novo código:

void sa(char *pi)
{
   for(int i=0;i<4;++i) {
        for(int j=0;j<1024*1024;++j){
                *pi='a';
                pi++;
        }
   }
   //just to use it to avoid the following code will not optimized off by the compiler 
   int dummycnt=0;
   for(int i=0;i<6;++i) {
        for(int j=0;j<1024*1024;++j){
                dummycnt+=*pi;
                pi++;
        }
   }
   printf("%d",dummycnt);
}


int main()
{
       int fd  = open("./test.bin",O_RDWR);
       char *p = (char *)mmap(0,
                      1024*1024*10, //10M
                      PROT_READ|PROT_WRITE,
                      MAP_SHARED,
                      fd,
                      0);
       sa(p);
       sleep(10000);
} 

cat / proc / pid / smaps:

b6eae000-b78ae000 rw-s 00000000 08:05 134424     ..../test.bin
Size:              10240 kB
Rss:               10240 kB
Pss:               10240 kB
Shared_Clean:          0 kB
Shared_Dirty:          0 kB
Private_Clean:      6144 kB
Private_Dirty:      4096 kB
Referenced:        10240 kB
Swap:                  0 kB
KernelPageSize:        4 kB
MMUPageSize:           4 kB
    
por camino 31.03.2012 / 03:00

1 resposta

3

Primeiro, seu código exibe um comportamento indefinido ( cnt é usado sem ter sido inicializado, mesmo para os 6M que você está lendo sem inicializar), portanto certifique-se de que seu compilador produza instruções que correspondam ao seu código: não é preciso. (Eu estou supondo que você tenha verificado isso.)

As páginas do 6M que você está lendo só não podem ser consideradas limpas. Uma página limpa é aquela que é sincronizada com seu armazenamento de apoio (o que quer que seja, swap, um arquivo, etc.). Essas páginas não têm nada que as apoie.
Eles não são realmente sujos no sentido usual - afinal, eles não foram modificados.

Então, o que está acontecendo aqui? Todas as páginas no bloco 6M que você está lendo são mapeadas para a mesma página, e essa página é a "página zero" (ou seja, uma página compartilhada (em x86 pelo menos) que contém 4k bytes zero).

Quando o kernel recebe uma falha de página em uma página anônima não mapeada, e essa falha é uma leitura, ela mapeia em uma página zero (a mesma página a cada vez). (Isso está em do_anonymous_page in mm/memory.c )
Esse não é um mapeamento "normal" (no vm_normal_page sense) e não é contabilizado nos campos smaps como nada compartilhado ou privado ( smaps_pte_entry in fs/proc/task_mmu.c ignora totalmente as páginas "especiais"). Ele é contabilizado em RSS e Size: na perspectiva do espaço de endereço, essas páginas virtuais existem e foram "usadas". Se você começar a modificar (gravar) qualquer página nessa área, ele obterá um mapeamento normal e adequado com uma página anônima (zero-inicializada neste caso específico, curiosamente - ela não será inicializada com zero se a anterior (não (normal / falso) mapeamento não foi para a página zero). (Veja do_wp_page in mm/memory.c .) Nesse ponto, você verá smaps exibir o que espera.

Por favor, note que nada em C, POSIX ou qualquer outra coisa garante que estas páginas contenham zeros, você não pode confiar nisso. (Você também não pode confiar nisso no Linux - é assim que é implementado agora, mas pode mudar).

    
por 31.03.2012 / 10:24

Tags