Jak szybki jest grep? -> grep vs awk, python, rugby, java, perl, C - przeszukiwanie logów - część 2.



C

Do tej pory porównałem programy w językach, które nie słyną z wydajności. Nie dla takiego celu były stworzone. Spróbujmy więc stworzyć program w języku kompilowanym - do kodu maszynowego, a nie do B-kodu (smile)

W wielu dystrybucjach, przed uruchomieniem poniższych programów, trzeba zmienić jeden z parametrów jądra. Od razu widać, jak rzadko używa sie pamięci współdzielonej nawet oprogramowaniu:

Pierwszy program z użyciem, jakże intuicyjnej w tym zastosowaniu, pętli for:
for()
//
// Copyright (c) 2016 Rafal Jackiewicz
//
#define _GNU_SOURCE
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <string.h>
#define TRUE  1
#define FALSE 0
#define Dneedle_max 6
#define Dnew_line 10
int
main(int argc, char *argv[])
{
    int             fd;
    size_t          len_max;
    char           *fileinmemory;
    struct stat     fd_st;
    char            needle[Dneedle_max];
    int             madret;
    if (argc < 3) {
    fprintf(stderr,
        "Za mamlo danych (nazwa pliku i 6 szukanych znakow).\n",
        argv[0]);
    return 1;
    }
    fd = open(argv[2], O_RDONLY);
    if (fd == -1) {
    perror("Onlyfind: open.");
    return 1;
    }
    if (fstat(fd, &fd_st) == -1) {
    perror("Onlyfind: fstat.");
    return 1;
    }
    if (!S_ISREG(fd_st.st_mode)) {
    fprintf(stderr, "%sOnlyfind: to nie plik.\n", argv[2]);
    return 1;
    }
    len_max = fd_st.st_size;
    // POSIX API
    fileinmemory =
    mmap(0, len_max, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, fd, 0);
    if (fileinmemory == MAP_FAILED) {
    perror("Onlyfind: nmap.");
    return 1;
    }
    madret = madvise(fileinmemory, 0, MADV_WILLNEED);
    if (madret < 0) {
    perror("Onlyfind: madvise.");
    }
    if (close(fd) == -1) {
    perror("Onlyfind: close.");
    return 1;
    }
    if (strlen(argv[1]) != Dneedle_max) {
    fprintf(stderr, "%sZla dlugośc needle.\n", argv[2]);
    return 1;
    else {
    strcpy(needle, argv[1]);
    }
    char           *endfileinmemory =
    fileinmemory + len_max - Dneedle_max + 1;
    char           *copyfileinmemory = fileinmemory;
    char           *mark = fileinmemory;
    char           *copymarkstart,
                   *copymarkstop;
    char           *i;
    for (mark = fileinmemory; mark < endfileinmemory; ++mark) {
    if (*mark == needle[0]) {
        if (*(++mark) == needle[1]) {
        if (*(++mark) == needle[2]) {
            if (*(++mark) == needle[3]) {
            if ((*(mark + 1) == needle[4])
                && (*(mark + 2) == needle[5])) {
                copymarkstart = mark - Dneedle_max;
                while (*(--copymarkstart) != (char) Dnew_line);
                copymarkstop = mark;
                while (*(++copymarkstop) != (char) Dnew_line);
                mark = copymarkstop;
                for (i = copymarkstart + 1; i <= copymarkstop;
                 ++i) {
                putchar(*i);
                }
            }
            }
        }
        }
    }
    }
    if (munmap(fileinmemory, fd_st.st_size) == -1) {
    perror("Onlyfind: munmap.");
    return 1;
    }
    return 0;
}

Ponieważ interpretujący wyrażenia regularne(!) greep jest szybszy od maksymalnie uproszczonego programu, to spróbujmy czegoś innego: poszukajmy ciągu znaków w pamięci funkcją systemową:
memmem()
 //
// Copyright (c) 2016 Rafal Jackiewicz
//
#define _GNU_SOURCE
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <string.h>
#define TRUE  1
#define FALSE 0
#define Dneedle_max 6
#define Dnew_line 10
#define _USE_MATH_DEFINES
#include <sys/ipc.h>
#include <sys/shm.h>
int
main(int argc, char *argv[])
{
    int             fd;
    size_t          len_max;
    char           *fileinmemory;
    struct stat     fd_st;
    char            needle[Dneedle_max];
    int             madret;
    if (argc < 3) {
    fprintf(stderr,
        "Za mamlo danych (nazwa pliku i 6 szukanych znakow).\n",
        argv[0]);
    return 1;
    }
    fd = open(argv[2], O_RDONLY);
    if (fd == -1) {
    perror("Onlyfind: open.");
    return 1;
    }
    if (fstat(fd, &fd_st) == -1) {
    perror("Onlyfind: fstat.");
    return 1;
    }
    if (!S_ISREG(fd_st.st_mode)) {
    fprintf(stderr, "%sOnlyfind: to nie plik.\n", argv[2]);
    return 1;
    }
    len_max = fd_st.st_size;
    // POSIX API
    fileinmemory =
    mmap(0, len_max, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, fd, 0);
    if (fileinmemory == MAP_FAILED) {
    perror("Onlyfind: nmap.");
    return 1;
    }
    madret = madvise(fileinmemory, 0, MADV_WILLNEED);
    if (madret < 0) {
    perror("Onlyfind: madvise.");
    }
    if (close(fd) == -1) {
    perror("Onlyfind: close.");
    return 1;
    }
    if (strlen(argv[1]) != Dneedle_max) {
    fprintf(stderr, "%sZla dlugośc needle.\n", argv[1]);
    return 1;
    else {
    strcpy(needle, argv[1]);
    }
    char           *endfileinmemory =
    fileinmemory + len_max - Dneedle_max + 1;
    char           *mark = fileinmemory;
    char           *copymarkstart,
                   *copymarkstop;
    size_t          copylen_max = len_max;
    while ((mark = memmem(mark, copylen_max, needle, Dneedle_max))) {
    copymarkstart = mark;
    while (*(--copymarkstart) != (char) Dnew_line);
    copymarkstop = mark + Dneedle_max;
    while (*(++copymarkstop) != (char) Dnew_line);
    mark = copymarkstop;
    printf("%-.*s", copymarkstop - copymarkstart, copymarkstart + 1);
    copylen_max = endfileinmemory - mark;
    }
    if (munmap(fileinmemory, fd_st.st_size) == -1) {
    perror("Onlyfind: munmap.");
    return 1;
    }
    return 0;
}



********

Więcej informacji:
Informatyka, FreeBSD, Debian


***

Inne wpisy:



Update: 2018.07.17
Create: 2018.07.17

Brak komentarzy:

Prześlij komentarz