Чтение и извлечение длинных данных int среди строк в фиксированном файле столбца, используя позиции файла? - PullRequest
0 голосов
/ 17 марта 2019

Я пытаюсь извлечь длинные данные int только из / proc / meminfo. Образец файла ниже. Я могу сделать это, но давно известная мантра в Linux гласит: делай одну вещь, и делай это хорошо . Меня раздражает, что я делаю это не так эффективно, как мог бы.

Я не хочу читать / собирать / хранить данные о символах до и после длинных целых. Я не хочу, чтобы программа проверяла символы, чтобы убедиться, что они такие или нет. Я только хочу, чтобы данные long int обрабатывались и сохранялись как переменные, и я хочу, чтобы это делалось с помощью файловых позиций, которые просто пропускают все бесполезные данные char.

Кроме того, я хочу, чтобы данные захватывались как long int и сохранялись как long int. Есть несколько программ, которые делают все, что я сказал, но они начинают хранить информацию в виде строки символов. Эту строку придется преобразовать обратно, сводя на нет большую часть выгоды.

Я бы хотел сделать это, переместив положение файла прямо перед длинным int, а затем сохранив его, но я не понял, как это сделать эффективно. Единственный способ заставить это работать - всегда начинать с начала файла и использовать все большие и большие позиции в файле, чтобы добраться до каждого последующего long int. Результатом было очень медленное выполнение - намного медленнее, чем мой код ниже (~ 30% медленнее). Возможно, программу пришлось перезапустить с самого начала и пройти весь файл, чтобы найти свою позицию?

Я хочу перейти к 766744 , захватить его, сохранить его, а затем перейти (начиная с этой новой текущей позиции) к 191680 , захватить его, сохранить его и прыгнуть 468276 ... Вы поняли.

Позиция файла переходит (за исключением самого первого перехода к 766744 , что составляет 18 символов), начиная с конца длинного целого, проходя после «kB», вниз по строке и заканчивающиеся следующим числом, всегда 22 символа.

/ Proc / MemInfo:

MemTotal:         766744 kB
MemFree:          191680 kB
MemAvailable:     468276 kB
Buffers:           30180 kB
Cached:           272476 kB

Вот две мои лучшие попытки сделать это. Они работают хорошо, но они не так эффективны, как могли бы; они сканируют и проверяют определенные данные и тратят ресурсы на это:

mem.cpp:

/*

Compile using:
g++ -Wall -O2 mem.cpp -o mem

*/

#include<fstream>
#include<unistd.h>   // Needed for usleep func.
#include<limits>

int mem()
{

    unsigned int memTotal, memFree, buffers, cached;

    std::ifstream file("/proc/meminfo");

    file.ignore(18, ' '); 
    file >> memTotal;
    file.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

    file.ignore(18, ' '); 
    file >> memFree;
    file.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

    // Skip 'MemAvailable:' line:
    file.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

    file.ignore(18, ' '); 
    file >> buffers;
    file.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

    file.ignore(18, ' '); 
    file >> cached;

    file.close();

    return ((memTotal - memFree) - (buffers + cached)) / 1024;
}

int main()
{

    do{

        // Everyday use:
        printf("mem: %im\n", mem());
        sleep(1);

        // For benchmarking:
        // mem();
        // usleep(55);

    }while(1);

    return 0;

}

Компиляция с использованием: [code] g ++ -Wall -O2 mem.cpp -o mem [/ code]

mem.c

/*

Compile using:
g++ -Wall -O2 mem.c -o mem

*/

#include<fstream>
#include<unistd.h>   // Needed for 'usleep' func.

unsigned int mem()
{

    unsigned int memTotal, memFree, buffers, cached;

    FILE * const file = fopen( "/proc/meminfo", "r" );

    fscanf(file, "%*19s %i %*2s %*19s %i %*2s %*19s %*i %*2s %*19s %i %*2s %*19s %i", &memTotal, &memFree, &buffers, &cached);

    fclose(file);

    return ((memTotal - memFree) - (buffers + cached)) / 1024;
}

int main()
{

    do{

        printf("mem: %im\n", mem());
        sleep(1);

        //For benchmarking:
        //mem();
        //usleep(55);

    }while(1);

    return 0;
}

Компиляция с использованием: g ++ -Wall -O2 mem.c -o mem

* РЕДАКТИРОВАТЬ *

При попытке воссоздать мой код, который у меня изначально был с использованием позиций файла, я заставил его работать так, как просили, но код на самом деле МЕНЬШЕ (на 2%), чем оба кода выше:

mem3.c

/*

  // -O3 seems to be .6% more efficient
  g++ -Wall -O3 mem3.c -o mem3 


  cpu 47.7% @ 55 microseconds

*/

#include<fstream>
#include<unistd.h>   // Needed for usleep func.

int mem()
{
    unsigned long memTotal, memFree, buffers, cached;

    FILE * file;
    file = fopen("/proc/meminfo", "r");

    fseek(file, 18, SEEK_SET);
    fscanf(file, "%lu", &memTotal);

    fseek(file, 22, SEEK_CUR);
    fscanf(file, "%lu", &memFree);

    fseek(file, 40, SEEK_CUR);
    fscanf(file, "%lu", &buffers);

    fseek(file, 22, SEEK_CUR);
    fscanf(file, "%lu", &cached);

    fclose (file);
    return ((memTotal - memFree) - (buffers + cached)) / 1024;

}

int main()
{

    do{

        printf("mem: %im\n", mem());
        sleep(1);

//      For testing:

//      mem();
//      usleep(55);

    }while(1);

    return 0;
}

Нет хранения бесполезных данных. Никакой дополнительной проверки, но приведенный выше код работает медленнее ?? Очевидно, что я что-то не так делаю, и я как-то вызываю повышенную нагрузку.

Спасибо за чтение. Ищу предложения.

* РЕДАКТИРОВАТЬ 2 *

Мне удалось получить приличный прирост эффективности на 7% благодаря использованию пользовательской функции. Примечания в коде.

mem.c:

/*

  // -O3 seems to give .6% increased efficiency
  g++ -Wall -O3 mem.c -o mem

  43.7% CPU usage @ usleep(55)

*/

#include<fstream>
#include<unistd.h>   // Needed for 'usleep' func.

/* Function courtesy of: https://stackoverflow.com/questions/16826422/c-most-efficient-way-to-convert-string-to-int-faster-than-atoi. With a personal modification to allow for conversion of an int between strings. */

void naive(const char *p, unsigned int &x)
{
    x = 0;
    do{

        // Nifty little trick with uint8_t... which I saw on stack! :D
        if (uint8_t(*p - '0') < 10)
            x = (x*10) + (*p - '0');

    }while(*++p != '\0');
}

unsigned int mem()
{
    unsigned int memTotal, memFree, buffers, cached;

    FILE * file;
    char str [30]; // Length of each file line

    file = fopen ("/proc/meminfo" , "r");

    /* Looking into finding a way to gather all the below info at once; likely, the 5 'fget' file calls are slowing things down. */

    fgets(str, 30, file);
    naive(str, memTotal);

    fgets(str, 30, file);
    naive(str, memFree);

    fgets(str, 30, file);

    fgets(str, 30, file);
    naive(str, buffers);

    fgets(str, 30 , file);
    naive(str, cached);

    fclose(file);

    return ((memTotal - memFree) - (buffers + cached)) / 1024;
}

int main()
{

    do{
        // Everyday usage:
        //printf("mem: %im\n", mem());
        //sleep(1);

        // For testing:
        mem();
        usleep(55);

    }while(1);

    return 0;
}
...