Читать и извлекать данные long int среди строк в файле с фиксированным столбцом, используя позиции файла?

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

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

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

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

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

Позиция файла перескакивает (кроме самого первого перехода к 766744, который составляет 18 символов), начиная с конца длинного int, проходя через '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;
}

person bedtime    schedule 17.03.2019    source источник
comment
Возможно, вы сэкономите несколько миллисекунд, применив подход, изложенный в вашем вопросе. Однако я очень сомневаюсь, что количество времени, сэкономленное за все время использования этой программы, превысит количество времени, которое потребуется вам для ее реализации. Если вы не планируете запускать свою программу несколько миллионов раз, маловероятно, что какая-либо разница в производительности будет измеримой.   -  person Sam Varshavchik    schedule 17.03.2019
comment
И если производительность действительно так важна для вас, последнее, что вы будете делать, - это использовать std::ifstream, который не имеет репутации эффективного. Скорее, вы будете использовать функции POSIX open(), lseek() и read(), а затем самостоятельно анализировать целочисленные значения вместо того, чтобы использовать для этого библиотеку C ++, которая также сжигает невероятное количество электронов, принимая во внимание такие вещи, как текущая локаль. , о котором вы действительно не заботитесь. Собственно, про lseek() забудь. Один read(), чтобы все проглотить, потом разобрать в памяти.   -  person Sam Varshavchik    schedule 17.03.2019
comment
Это Не имеет значения. Просто проанализируйте его самым простым и понятным способом. Как сказал @Sam, любые наносекунды, которые вы здесь сэкономите, не будут иметь значения в реальной жизни, но вы потратите часы / дни на их сохранение. Не беспокойся.   -  person Jesper Juhl    schedule 17.03.2019
comment
Сэм Варшавчик и Джеспер Джул: Я согласен, я ищу совсем незначительные изменения, но не в этом суть. Дело в том, чтобы сделать его максимально эффективным, чтобы я мог использовать этот тип кода и использовать эти знания в других местах кодирования, где это действительно будет иметь значение. Что касается POSIX open (), lseek () и read (), я их проверю ... Использование C или C ++ для меня не имеет значения. Если решения C более эффективны, я буду их использовать. Опять же, это только пример такой программы - это больше теория и потенциальное использование, которое мне нужно.   -  person bedtime    schedule 17.03.2019
comment
Как вы измеряете эффективность?   -  person Tobias Wollgam    schedule 18.03.2019
comment
Хороший вопрос! Я запускаю команду в цикле как просто mem () - без printf, но с usleep (55) в цикле. Я использую команду «top», чтобы узнать, сколько ЦП использует программа. Мое последнее обновление кода снизило его до 44% с 47%. Он включал извлечение всех данных, а затем использование специально созданной функции для преобразования из char * в int. Эта новая находка будет использована во многих других программах, которые я сделал. Эти программы работают на маломощном Rasberry Pi 3b + и скоро будут работать на 1 ядре, 1 ГГц, 500 МБ, Raspberry Pi Zero.   -  person bedtime    schedule 18.03.2019