Pegar dados especificos de do /proc/stat

1. Pegar dados especificos de do /proc/stat

William Lima
willdoidao

(usa Ubuntu)

Enviado em 09/09/2014 - 09:37h

Pessoal,

Como faço para caprturar dados sepadorados de uma linha de arquivo, tipo se der um cat /proc/stat obtenho em uma das linhas o seguinte retorno:

 cpu0 96804 9119 387122 6739554 62390 456399 64543 0 0 0  


Fiz um script bem ralé só para testar, pretendo melhorar bem o código e otimizar mas primeiro preciso fazer funcionar.
Já consegui fazer o levantamento da quantidade, setar a linha que contém
cpu0, mas não sei como dividir esses números na frente dela em variavés.

Segue meu rascunho de código:


#include <iostream>
#include <fstream>
#include <cstring>
#include <stdlib.h>
#include <sstream>
#include <fcntl.h>
#include <stdint.h>


//Variaveis
  FILE *fp;
  int line_num =1;
  int find_result =0;
  char buffer[8192];
  

int Pesquisa()
{
 
  if((fp = fopen("/proc/stat","r")) != NULL)
  {
    while(fgets(buffer,8192,fp) != NULL)
    {
      if((strstr(buffer,"cpu"))!= NULL)
      {
	find_result++;
      }
      line_num++;
    }
     if(fp)
     fclose(fp);     
    return find_result;
  }
  else{
	return -1;
  }  
}

void cpus_valores(int total)
{
  int stat,useVmstatfile,cpu;
  std::string Testes;
    
  cpu = total -1;
  
  std::ostringstream ss;
  
  if((fp = fopen("/proc/stat","r")) != NULL)
  {
    for(int i = 0; i< cpu; i++)
    {
      ss << "cpu" << i;
      Testes = ss.str();
      //Teste de Captura do Arquivo
      while(fgets(buffer,8192,fp) != NULL)
      {
	if((strstr(buffer,"Testes"))!= NULL)
	{
	  
	
	  
	}
	line_num++;
      }
      ss.str("");
    }
      if(fp)
      fclose(fp);     
   
  }
 
}  



int  main(int argc, char *argv[])
{
  int Total = 0;

  Total = Pesquisa();
  std::cout<< Total << std::endl;
  cpus_valores(Total);   
  
  
  return 0;
} 



  


2. Re: Pegar dados especificos de do /proc/stat

euteste da silva
foxbit3r

(usa Solaris)

Enviado em 09/09/2014 - 09:49h

Resp.: strtok, sscanf e outros...
Dà uma olha nas funçoes da biblioteca string.h, vc encontra muitas coisas dela no google.


3. Re: Pegar dados especificos de do /proc/stat

Paulo
paulo1205

(usa Ubuntu)

Enviado em 09/09/2014 - 13:04h

willdoidao escreveu:

Pessoal,

Como faço para caprturar dados sepadorados de uma linha de arquivo, tipo se der um cat /proc/stat obtenho em uma das linhas o seguinte retorno:

 cpu0 96804 9119 387122 6739554 62390 456399 64543 0 0 0  


Fiz um script bem ralé só para testar, pretendo melhorar bem o código e otimizar mas primeiro preciso fazer funcionar.
Já consegui fazer o levantamento da quantidade, setar a linha que contém
cpu0, mas não sei como dividir esses números na frente dela em variavés.


Como você está usando C++, pode usar std::getline() (dentro de <string>) para ler as linhas, e depois colocar essa linha dentro de um std::istringstring, para enfim separar os campos através de usos sucessivos de std::istream::operator>>() (uso semelhante a quando você lê de std::cin, por exemplo). Pode também aplicar sobre esse std::istringstream um loop com std::getline(), usando espaços (e não '\n', que é o default) como separador. Pode, ainda, descer um pouco mais o nível, e usar std::string::find(), std::string::substr() e outras funções relacionadas.

Segue um exemplo usando C++11.

#include <iostream>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <string>
#include <map>
#include <vector>

using namespace std;

// Largura das colunas na hora de imprimir os dados lidos.
const unsigned col_width=11u;

int main(){
  // Vetor com os titulos das colunas.  Os nomes das colunas são
  // passados para um construtor que utiliza a nova sintaxe do
  // C++11, que aceita uma lista de elementos.
  vector<string> col_names{
    "CPU", "user", "nice", "system", "idle", "iowait",
    "irq", "softirq", "stolen", "guest", "guest_nice"
  };

  // cpu_data faz o mapeamento entre o nome de uma CPU (string) e
  // uma lista de contadores (vetor de inteiros sem sinal).  Eu
  // usei um vetor de valores sem nomes predefinidos porque cada
  // versão de kernel pode ter mais ou menos campos do que outras
  // versões (sendo que as primeiras quatro ou cinco colunas pa-
  // recem ter "sempre" existido).  Mas como este programa monta
  // uma tabela, eu acabei usando o vetor col_names, definido acima,
  // com os nomes de colunas que vi numa manpage.
  map<string, vector<unsigned long long>> cpu_data;

  // Uma variável inteira sem sinal, que será usada no loop de
  // leitura dos sucessivos contadores associados a cada CPU.
  unsigned long long counter;

  // Um buffer para armazenar cada linha lida.
  string line;

  // Depois de ler cada linha, eu uso um "input string stream"
  // (istringstream, definido em <sstream>) para separar as colunas.
  istringstream line_parser;

  // Tente descobri qual informação a variável abaixo armazena. ;)
  string cpu_name;

  // Declara um stream de entrada para ler do arquivo, e já define
  // de que arquivo será feita a leitura.
  ifstream proc_stat("/proc/stat");

  // Lê uma linha do arquivo de entrada.  Se a leitura for bem sucedida,
  // entra no corpo do while.
  while(getline(proc_stat, line)){
    // Limpa do objeto separador eventuais sinalizações de erro e/ou
    // fim de dados, que podem ter permanecido da iteração anterior do
    // loop.  Em seguida, alimenta o separador com a linha que acabou
    // de ser lida, para que possamos separar suas partes.
    line_parser.clear();
    line_parser.str(line);

    // A primeira coluna da linha é o nome da entidade cujos contadores
    // estarão nas colunas seguintes.  Como só temos interesse nos con-
    // tadores de CPUs, só se entra no corpo do if se essa primeira co-
    // luna lida tiver realmente os três primeiros caracteres (i.e. a
    // substring começando na posição 0 e com 3 caracteres de compri-
    // mento) iguais ao texto "cpu".
    if((line_parser >> cpu_name) && cpu_name.substr(0, 3)=="cpu"){
      // Existem dois tipo de linha com informações de CPU: as que são
      // relativas a cada core, que aparecem com a string "cpu" seguida
      // de um número, e a do total consolidado, que aparece apenas como
      // "cpu", sem sufixo.  Para deixar mais claro, este programa troca
      // o rótulo da linha consolidada pela string "TOTAL", usando as
      // letras maiúsculas para dar ainda mais destaque à diferença.
      if(cpu_name=="cpu")
        cpu_name="TOTAL";

      // Loop de leitura dos contadores.  Cada contador é lido do sepa-
      // rador de colunas para a variável counter.  Se a leitura for bem
      // sucedida, esse valor é colocado ao final do vetor de contadores
      // associados à CPU indicada por cpu_name.
      while(line_parser >> counter)
        cpu_data[cpu_name].push_back(counter);
    }
  }

  // Fecha o arquivo de onde os dados foram lidos.
  proc_stat.close();

  // Imprime os dados lidos, começando com os títulos das colunas (lem-
  // brando que setw() é um manipulador que informa a largura usada para
  // o próximo dado a ser impresso)...
  for(auto &col : col_names)  // itera sobre os nomes das colunas.
    cout << setw(col_width) << col;
  cout << '\n';

  // ... e terminando com a impressão dos dados em si.
  for(auto &cpu_info : cpu_data){  //  itera sobre os registros do mapa.
    // Primeiro imprime o nome da CPU (primeiro campo do registro, que
    // é usado no momento da leitura como chave de indexação do mapa)...
    cout << setw(col_width) << cpu_info.first;

    // ... e depois o valor de cada contador do vetor de contadores (o
    // vetor é o segundo campo do registro do mapa).
    for(auto &col : cpu_info.second)
      cout << setw(col_width) << col;

    // Fim dos dados desta CPU: pula a linha.
    cout << '\n';
  }
} 



4. Re: Pegar dados especificos de do /proc/stat

Luís Fernando C. Cavalheiro
lcavalheiro

(usa Slackware)

Enviado em 09/09/2014 - 14:15h

willdoidao escreveu:

Pessoal,

Como faço para caprturar dados sepadorados de uma linha de arquivo, tipo se der um cat /proc/stat obtenho em uma das linhas o seguinte retorno:

 cpu0 96804 9119 387122 6739554 62390 456399 64543 0 0 0  


Fiz um script bem ralé só para testar, pretendo melhorar bem o código e otimizar mas primeiro preciso fazer funcionar.
Já consegui fazer o levantamento da quantidade, setar a linha que contém
cpu0, mas não sei como dividir esses números na frente dela em variavés.

Segue meu rascunho de código:


#include <iostream>
#include <fstream>
#include <cstring>
#include <stdlib.h>
#include <sstream>
#include <fcntl.h>
#include <stdint.h>


//Variaveis
  FILE *fp;
  int line_num =1;
  int find_result =0;
  char buffer[8192];
  

int Pesquisa()
{
 
  if((fp = fopen("/proc/stat","r")) != NULL)
  {
    while(fgets(buffer,8192,fp) != NULL)
    {
      if((strstr(buffer,"cpu"))!= NULL)
      {
	find_result++;
      }
      line_num++;
    }
     if(fp)
     fclose(fp);     
    return find_result;
  }
  else{
	return -1;
  }  
}

void cpus_valores(int total)
{
  int stat,useVmstatfile,cpu;
  std::string Testes;
    
  cpu = total -1;
  
  std::ostringstream ss;
  
  if((fp = fopen("/proc/stat","r")) != NULL)
  {
    for(int i = 0; i< cpu; i++)
    {
      ss << "cpu" << i;
      Testes = ss.str();
      //Teste de Captura do Arquivo
      while(fgets(buffer,8192,fp) != NULL)
      {
	if((strstr(buffer,"Testes"))!= NULL)
	{
	  
	
	  
	}
	line_num++;
      }
      ss.str("");
    }
      if(fp)
      fclose(fp);     
   
  }
 
}  



int  main(int argc, char *argv[])
{
  int Total = 0;

  Total = Pesquisa();
  std::cout<< Total << std::endl;
  cpus_valores(Total);   
  
  
  return 0;
} 


Admiro muito o seu trabalho em bolar algo em C, mas só por curiosidade, usar cat, grep, cut e paste não lhe passou pela cabeça?

EDIT: usando um exemplo tosco com esse caso do /proc/stat,

 $ cat /proc/stat | grep cpu0 | sed -e "s/\ /\n/g" 


Isso vai organizar aquela linha que você me deu em uma coluna, vai ficar assim:
cpu0
96804
9119
387122
6739554
62390
456399
64543
0
0
0

Pulo do gato: crie um arquivo que contenha o nome das variáveis em colunas, assim:
VAR1
VAR2
VAR3
VAR4
VAR5
VAR6
VAR7
VAR8
VAR9
VAR0
VARA


Agora, o como faz. Vamos chamar o arquivo com o nome das variáveis de variaveis.txt. Rode os comandos:
 $ cat /proc/stat | grep cpu0 | sed -e "s/\ /\n/g" >> dados.txt
$ paste -d"=" variaveis.txt dados.txt >> source.txt 

O conteúdo de source.txt vai ser
VAR1=cpu0
VAR2=96804
VAR3=9119
VAR4=387122
VAR5=6739554
VAR6=62390
VAR7=456399
VAR8=64543
VAR9=0
VAR0=0
VARA=0

Em um shellscript, você pode usar a linha
 . source.txt 

Pra chamar todas essas variáveis


5. Re: Pegar dados especificos de do /proc/stat

William Lima
willdoidao

(usa Ubuntu)

Enviado em 09/09/2014 - 14:32h

Caras agradeço pela ajuda, estou perto de resolver a parada, mas ainda preciso de uma ajuda, orientação a objeto ainda está me tirando umas noites de sono.

O que fiz após a dica do foxbit3r fiz o seguinte:

no cpu.h criei um objeto:

class Valores{
public:
std::string cuse;
std::string cice;
std::string csys;
std::string cide;
std::string cwio;
};

o vou postar somente a classe que estou trabalhando:


void cpus_valores(int total)
{
  std::ostringstream ss;  
  std::string Nome_cpu;
  char buffe[255];
  
  total = total-1;
  
  for(int i =0; i<=total;i++)
  {
    //Montando a string de pesquisa
    ss << "cpu" << i;
    Nome_cpu = ss.str();
    
    FILE *arquivo = fopen("/proc/stat","r");
    char buffe[255];
    if(arquivo !=NULL)
    {
      while(fgets(buffe,255,arquivo))
      {
	if((strstr(buffe,Nome_cpu.c_str()))!=NULL)
	{
	  
	 Valores *cpu = new Valores();
	 
	 std::sscanf(buffe, "%s  %s  %s  %s  %s",cpu->cuse.c_str(),cpu->cice.c_str(),cpu->csys.c_str(),cpu->cide.c_str(),cpu->cwio.c_str());
	 
	 std::cout << i <<":" 
	 << cpu->cuse.c_str()<< " "
	 << cpu->cice.c_str()<< " "
	 << cpu->csys.c_str()<< " "
	 << cpu->cide.c_str()<< " "
	 << cpu->cwio.c_str()<< " "
	 << std::endl;
	}
      }
      fclose(arquivo);
    }
    else
      std::cout<<"falha a abrir arquivo" << std::endl;
  
    ss.str("");
  }
}
 


A saida que está dando é:


0:67176 67176 67176 67176 67176 
1:67175 67175 67175 67175 67175 
2:67174 67174 67174 67174 67174 
3:67173 67173 67173 67173 67173 
 


Sendo que o correto seria:

49998 51 45304 67176 24479
49997 50 45303 67175 24478
49996 49 45302 67174 24477
49995 48 45301 67173 24466
 


Poderia me mostrar meu erro?


6. Re: Pegar dados especificos de do /proc/stat

Paulo
paulo1205

(usa Ubuntu)

Enviado em 09/09/2014 - 14:44h

std::string::c_str() lhe devolve uma referência ao conteúdo do objeto std::string que não deve ser usada para fazer modificações nesse objeto. Você nem mesmo tem garantias de que se trata do próprio objeto, e não somente de uma cópia. Note, inclusive, que o ponteiro devolvido pela função é designado como const char *. Ao usá-lo como argumento de sscanf(), você tacitamente descarta o const.

Você chegou a olhar a mensagem que enviei acima? Acho que dali você pode obter a informação de que precisa. Se não tiver entendido o código, pode perguntar, que eu explico.


7. Re: Pegar dados especificos de do /proc/stat

William Lima
willdoidao

(usa Ubuntu)

Enviado em 09/09/2014 - 15:21h

paulo1205

Cheguei até rodar o seu exemplo e funciona legal, mas como falei antes estou aprendendo orientação a objeto, não consegui entender quase nada do seu exemplo, teria como colocar uns comentários ali?


8. Re: Pegar dados especificos de do /proc/stat

Paulo
paulo1205

(usa Ubuntu)

Enviado em 09/09/2014 - 17:54h

Acabei de confirmar o preceito de que comentar demais é uma boa maneira de transformar um programa elegante e de poucas linhas num monstro. ;) De todo modo, editei minha primeira postagem com esses comentários. Espero que lhe sejam úteis.

Tenho a impressão de que o problema que você enfrenta é menos com OO e mais com conhecer as ferramentas e a própria sintaxe da linguagem. Acho que, se você tivesse lido sobre std::istringstream ou sobre a nova forma do loop for que automaticamente itera sobre os valores de arrays ou containers da biblioteca padrão do C++, você provavelmente teria entendido o programa não-comentado logo de primeira, até porque os nomes das variáveis indicam claramente seus papéis no programa.


9. Re: Pegar dados especificos de do /proc/stat

Paulo
paulo1205

(usa Ubuntu)

Enviado em 09/09/2014 - 18:21h

Pelo que me pareceu, o seu programa deveria ser muito parecido com o meu, com a diferença de que em lugar de ler para um vetor de contadores genéricos, você quer ler algumas das colunas para uma estrutura com campos que têm nomes bem conhecidos.

Em C++, você trocaria (simplificando o programa anterior)

map<string, vector<unsigned long long>> cpu_data;

/* ... */

if((line_parser >> cpu_name) && cpu_name.substr(0, 3)=="cpu"){
  while(line_parser >> counter)
    cpu_data[cpu_name].push_back(counter);
} 


por algo como vai abaixo (também simplificado: você talvez queira tratar possíveis erros de leitura, com os quais não estou me preocupando neste exemplo).

struct exemplo {
  unsigned long long user, system, idle, iowait;  // Nomes de exemplo!!!
};

map<string, exemplo> cpu_data;

/* ... */

if((line_parser >> cpu_name) && cpu_name.substr(0, 3)=="cpu"){
  // Note que é uma linha de código só, que eu quebrei para ficar mais legível.
  line_parser
    >> cpu_data[cpu_name].user
    >> cpu_data[cpu_name].system
    >> cpu_data[cpu_name].idle
    >> cpu_data[cpu_name].iowait
  ;
} 







Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts