source: icGREP/icgrep-devel/icgrep/icgrep.cpp @ 4128

Last change on this file since 4128 was 4128, checked in by linmengl, 5 years ago

modify perf.py; add an interactive perf data viewer; add make target 'perf_icgrep' and 'viewer';

File size: 15.3 KB
RevLine 
[3850]1/*
2 *  Copyright (c) 2014 International Characters.
3 *  This software is licensed to the public under the Open Software License 3.0.
4 *  icgrep is a trademark of International Characters.
5 */
6
[3965]7#include "icgrep.h"
8
[3850]9#include "utf_encoding.h"
10#include "re_compiler.h"
11
12#include <fstream>
13#include <sstream>
14#include <iostream>
15#include <string>
16#include <stdint.h>
17
18#include <stdio.h>
19#include <stdlib.h>
20#include <unistd.h>
21#include <errno.h>
22#include <sys/types.h>
23#include <sys/stat.h>
24
25#include <simd-lib/bitblock.hpp>
26#include <simd-lib/carryQ.hpp>
27#include <simd-lib/pabloSupport.hpp>
28#include <simd-lib/s2p.hpp>
29#include <simd-lib/buffer.hpp>
30#include <simd-lib/bitblock_iterator.hpp>
31
[4038]32// mmap system
33#include <sys/mman.h>
34#include <fcntl.h>
35
36
[3850]37#define SEGMENT_BLOCKS 15
38#define SEGMENT_SIZE (BLOCK_SIZE * SEGMENT_BLOCKS)
39
40#define BUFFER_SEGMENTS 15
41#define BUFFER_SIZE (BUFFER_SEGMENTS * SEGMENT_SIZE)
42
43#define BitBlock_declare(name)  BitBlock name
44
45#define ubitblock_declare(name, n) \
46  ubitblock name[n];\
47  do {int i;\
48      for (i = 0; i < n; i++) name[i]._128 = simd<1>::constant<0>();\
49     }\
50  while (0)
51
52BitBlock EOF_mask = simd<1>::constant<1>();
53
54struct Output {
55    BitBlock matches;
56    BitBlock LF;
57};
58
59#include <simd-lib/transpose.hpp>
60
61using namespace std;
62
63typedef void (*process_block_fcn)(const Basis_bits &basis_bits, BitBlock carry_q[], Output &output);
64
[4038]65
[4074]66#define USE_MMAP
[4038]67#ifndef USE_MMAP
[3850]68void do_process(FILE *infile, FILE *outfile, int count_only_option, int carry_count, process_block_fcn process_block);
[4038]69#endif
70#ifdef USE_MMAP
71void do_process(char * infile_buffer, size_t infile_size, FILE *outfile, int count_only_option, int carry_count, process_block_fcn process_block);
72#endif
73
[4118]74//define this indicates that we use llvm.uadd.with.overflow for genAddWithCarry
[4128]75//#define USE_UADD_OVERFLOW
[4118]76
[3969]77BitBlock get_category(Basis_bits &basis_bits, const char* category);
[3850]78
79int main(int argc, char *argv[])
80{
81    char * inregex, * fileregex, * infilename, * outfilename;
82    FILE *infile, *outfile, *regexfile;
83
[4038]84#ifdef USE_MMAP
85    int fdSrc;
86    struct stat infile_sb;
87    char * infile_buffer;
88#endif
[4118]89
[3850]90    int opt_code;
91    int count_only_option = 0;
92    int print_version_option = 0;
93    int regex_from_file_option = 0;
[3914]94    int ascii_only_option = 0;
[3850]95
96    int compile_time_option = 0;
97
[3914]98    unsigned long long cycles = 0;
99    double timer = 0;
100
101    long lSize = 0;
102
[3850]103    size_t result;
104
[3914]105    while ((opt_code = getopt(argc, argv, "cvfta")) != -1)
[3850]106    {
107        switch (opt_code)
108        {
109        case 'c':
110            count_only_option = 1;
111            break;
112        case 'v':
113            print_version_option = 1;
114            break;
115        case 'f':
116            regex_from_file_option = 1;
117            break;
118        case 't':
119            compile_time_option = 1;
120            break;
[3914]121        case 'a':
122            ascii_only_option = 1;
123            break;
[3850]124        case '?':
125            break;
126        default:
127            printf ("Invalid option: %c\n", opt_code);
[3914]128            printf("Usage: %s [-c] [-v] [-f] [-t] [-a] <regex|regexfile> <inputfile> [<outputfile>]\n", argv[0]);
[3850]129                    exit(-1);
130        }
131    }
132
133    if (optind >= argc)
134    {
135        printf ("Too few arguments\n");
[3914]136        printf("Usage: %s [-c] [-v] [-f] [-t] [-a] <regex|regexfile> <inputfile> [<outputfile>]\n", argv[0]);
[3850]137        exit(-1);
138    }
139
140    inregex = argv[optind++];
141    if (inregex == 0)
142    {
143        fprintf(stderr, "Error: cannot read the regular expression.\n");
144        exit(-1);
145    }
146
147    if (regex_from_file_option)
148    {
149        regexfile = fopen(inregex, "rb");
150        if (!regexfile){
151            fprintf(stderr, "Error: cannot open %s for processing.\n", inregex);
152            exit(-1);
153        }
154
155        fseek (regexfile , 0 , SEEK_END);
156        lSize = ftell (regexfile);
157        rewind (regexfile);
158
159        fileregex = (char*) malloc (sizeof(char)*lSize);
160        if (fileregex == NULL) {fputs ("Memory error",stderr); exit (2);}
161
162        result = fread (fileregex, 1, lSize, regexfile);
163        if (result != lSize) {fputs ("Reading error",stderr); exit (3);}
164        fclose(regexfile);
165
166        if (fileregex[lSize - 1] == '\n') fileregex[lSize - 1] = '\0';
167    }
168
169    infilename = argv[optind++];
[4038]170#ifndef USE_MMAP
[3850]171    infile = fopen(infilename, "rb");
172    if (!infile) {
173        fprintf(stderr, "Error: cannot open %s for processing.\n", infilename);
174        exit(-1);
175    }
[4038]176#endif
177#ifdef USE_MMAP
178    fdSrc = open(infilename, O_RDONLY);
179    if (fdSrc == -1) {
180        fprintf(stderr, "Error: cannot open %s for processing.\n", infilename);
181        exit(-1);
182    }
183    if (fstat(fdSrc, &infile_sb) == -1) {
184        fprintf(stderr, "Error: cannot stat %s for processing.\n", infilename);
185        exit(-1);
186    }
187    if (infile_sb.st_size == 0) {
188        if (count_only_option) fprintf(outfile, "Matching Lines%d\n", 0);
189        exit(0);
190    }
191    infile_buffer = (char *) mmap(NULL, infile_sb.st_size, PROT_READ, MAP_PRIVATE, fdSrc, 0);
192    if (infile_buffer == MAP_FAILED) {
193        fprintf(stderr, "Error: mmap of %s failure.\n", infilename);
194        exit(-1);
195    }
196#endif
[3850]197
198    if (optind >= argc) outfile = stdout;
199    else
200    {
201        outfilename = argv[optind++];
202        if (optind != argc)
203        {
204            printf ("Too many arguments\n");
[3914]205            printf("Usage: %s [-c] [-v] [-f] [-t] [-a] <regex|regexfile> <inputfile> [<outputfile>]\n", argv[0]);
[3850]206            exit(-1);
207        }
208        outfile = fopen(outfilename, "wb");
209        if (!outfile)
210        {
211            fprintf(stderr, "Error: cannot open %s for writing.\n", outfilename);
212            exit(-1);
213        }
214    }
215
216    if (print_version_option)
217    {
[4038]218        fprintf(outfile, "Parabix icgrep implementation: August 2014\n");
[3850]219    }
220
221    UTF_Encoding encoding;
222    encoding.setName("UTF-8");
223    encoding.setBits(8);
224    encoding.setMask(0xFF);
225
226    RE_Compiler* re_compiler = new RE_Compiler();
[3914]227    if (compile_time_option)
228    {
229        cycles = get_hrcycles();
230        timer = getElapsedTime();
231    }
232    LLVM_Gen_RetVal llvm_codegen = re_compiler->compile(compile_time_option,
233                                                        ascii_only_option,
234                                                        "basis_bits.bit_",
235                                                        "temp",
236                                                        encoding ,
237                                                        (regex_from_file_option ? fileregex : inregex));
[3850]238
239    if (compile_time_option)
240    {
[3914]241        cycles = get_hrcycles() - cycles;
[3850]242        timer = getElapsedTime() - timer;
[3914]243        std::cout << "Total compile time - cycles:       " << cycles << std::endl;
244        std::cout << "Total compile time - milliseconds: " << timer << std::endl;
[3850]245    }
246
247    if (llvm_codegen.process_block_fptr != 0)
248    {
249        void (*FP)(const Basis_bits &basis_bits, BitBlock carry_q[], Output &output) = (void (*)(const Basis_bits &basis_bits, BitBlock carry_q[], Output &output))(void*)llvm_codegen.process_block_fptr;
[4038]250#ifndef USE_MMAP
[3850]251        do_process(infile, outfile, count_only_option, llvm_codegen.carry_q_size, FP);
[4038]252#endif
253#ifdef USE_MMAP
254        do_process(infile_buffer, infile_sb.st_size, outfile, count_only_option, llvm_codegen.carry_q_size, FP);
255#endif
[3850]256    }
257
258    delete re_compiler;
[4038]259#ifndef USE_MMAP
[3850]260    fclose(infile);
[4038]261#endif
262#ifdef USE_MMAP
[4080]263    munmap((void *) infile_buffer, infile_sb.st_size);
[4038]264    close(fdSrc);
265#endif
[3850]266    fclose(outfile);
267    if (regex_from_file_option) free(fileregex);
268
269    return 0;
270}
271
[4038]272#ifndef USE_MMAP
[3850]273void do_process(FILE *infile, FILE *outfile, int count_only_option, int carry_count, process_block_fcn process_block) {
[4038]274#endif
275#ifdef USE_MMAP
276void do_process(char * infile_buffer, size_t infile_size, FILE *outfile, int count_only_option, int carry_count, process_block_fcn process_block) {
277#endif
[3850]278
279    struct Basis_bits basis_bits;
280    struct Output output;
281
282    BitBlock carry_q[carry_count];
283    memset (carry_q, 0, sizeof(BitBlock) * carry_count);
284
285    BitBlock match_vector = simd<1>::constant<0>();
286    int match_count=0;
287    int blk = 0;
288    int block_base  = 0;
289    int block_pos   = 0;
290    int buffer_pos  = 0;
291    int chars_avail = 0;
292    int chars_read  = 0;
293
294    int line_start = 0;
295    int line_end = 0;
296    int match_pos = 0;
297    int line_no = 0;
298
299    BitStreamScanner<BitBlock, uint64_t, uint64_t, SEGMENT_BLOCKS> LF_scanner;
300    BitStreamScanner<BitBlock, uint64_t, uint64_t, SEGMENT_BLOCKS> match_scanner;
[4118]301
302
[4038]303#ifndef USE_MMAP
[3850]304    ATTRIBUTE_SIMD_ALIGN char src_buffer[SEGMENT_SIZE];
[4118]305
[3850]306    chars_read = fread((void *)&src_buffer[0], 1, SEGMENT_SIZE, infile);
307    chars_avail = chars_read;
308    if (chars_avail >= SEGMENT_SIZE) chars_avail = SEGMENT_SIZE;
[4038]309#endif
[4118]310#ifdef USE_MMAP
[4038]311    int segment = 0;
312    int segment_base = 0;
313    chars_avail = infile_size;
[4118]314
[4038]315#endif
[3850]316//////////////////////////////////////////////////////////////////////////////////////////
317// Full Segments
318//////////////////////////////////////////////////////////////////////////////////////////
319
[4118]320
321
[3850]322    while (chars_avail >= SEGMENT_SIZE) {
323
[4038]324#ifdef USE_MMAP
325        segment_base = segment * SEGMENT_SIZE;
326#endif
[3850]327        LF_scanner.init();
328        match_scanner.init();
329
330        for (blk = 0; blk < SEGMENT_BLOCKS; blk++) {
[4038]331#ifndef USE_MMAP
[3850]332            block_base = blk*BLOCK_SIZE;
333            s2p_do_block((BytePack *) &src_buffer[block_base], basis_bits);
[4038]334#endif
335#ifdef USE_MMAP
336            block_base = blk*BLOCK_SIZE + segment_base;
[4118]337            s2p_do_block((BytePack *) &infile_buffer[block_base], basis_bits);
[4038]338#endif
[3850]339            process_block(basis_bits, carry_q, output);
340
341            LF_scanner.load_block(output.LF, blk);
342            match_scanner.load_block(output.matches, blk);
343            if (count_only_option){
344                if (bitblock::any(output.matches))
345                {
346                    if (bitblock::any(simd_and(match_vector, output.matches))){
347                        match_count += bitblock::popcount(match_vector);
348                        match_vector = output.matches;
349                    }
350                    else
351                    {
352                        match_vector = simd_or(match_vector, output.matches);
353                    }
354                }
355            }
356        }
357
[4038]358#ifndef USE_MMAP
[3850]359        int copy_back_pos = 0;
360
[3914]361
[3850]362        if (LF_scanner.count() > 0) {
363            copy_back_pos = LF_scanner.get_final_pos() + 1;
364            memset (carry_q, 0, sizeof(BitBlock) * carry_count);
365        }
366        else {
367            copy_back_pos =  SEGMENT_SIZE;
368        }
369
370        int  copy_back_size = SEGMENT_SIZE - copy_back_pos;
[4038]371#endif
372#ifdef USE_MMAP
[4118]373
[4038]374#endif
[3850]375
376        if (!count_only_option) {
[4038]377#ifndef USE_MMAP
[3850]378            line_start = 0;
[4038]379#endif
[3850]380
381            while (match_scanner.has_next()) {
382                match_pos = match_scanner.scan_to_next();
383                line_end = LF_scanner.scan_to_next();
384                while (line_end < match_pos) {
385                    line_start = line_end+1;
386                    line_no++;
387                    line_end = LF_scanner.scan_to_next();
388                }
[4038]389#ifndef USE_MMAP
[3850]390                fwrite(&src_buffer[line_start], 1, line_end - line_start + 1, outfile);
[4038]391#endif
392#ifdef USE_MMAP
393                fwrite(&infile_buffer[segment_base + line_start], 1, line_end - line_start + 1, outfile);
[4118]394
[4038]395#endif
396
[3850]397                line_start = line_end+1;
398                line_no++;
399            }
400            while (LF_scanner.has_next()) {
401                line_end = LF_scanner.scan_to_next();
[4074]402                line_start = line_end+1;
[3850]403                line_no++;
404            }
405
406        }
[4038]407#ifndef USE_MMAP
[3850]408        memmove(&src_buffer[0], &src_buffer[copy_back_pos], copy_back_size);
409
[4038]410        //Do another read.
[3850]411        chars_read = fread(&src_buffer[copy_back_size], 1, copy_back_pos, infile);
412        chars_avail = chars_read + copy_back_size;
413        if (chars_avail >= SEGMENT_SIZE) chars_avail = SEGMENT_SIZE;
414        buffer_pos += chars_avail;
[4038]415#endif
416#ifdef USE_MMAP
417        segment++;
418        line_start -= SEGMENT_SIZE;  /* Will be negative offset for use within next segment. */
419        chars_avail -= SEGMENT_SIZE;
[4118]420
[4038]421#endif
[3850]422    }
423
424
425//////////////////////////////////////////////////////////////////////////////////////////
426// For the Final Partial Segment.
427//////////////////////////////////////////////////////////////////////////////////////////
428
[4038]429#ifdef USE_MMAP
430    segment_base = segment * SEGMENT_SIZE;
431#endif
[3850]432    int remaining = chars_avail;
433
434    LF_scanner.init();
435    match_scanner.init();
436
437    /* Full Blocks */
438    blk = 0;
439    while (remaining >= BLOCK_SIZE) {
[4038]440    //fprintf(outfile, "Remaining = %i\n", remaining);
441#ifndef USE_MMAP
[3850]442        block_base = block_pos;
[4038]443        s2p_do_block((BytePack *) &src_buffer[block_base], basis_bits);
444#endif
445#ifdef USE_MMAP
446        block_base = block_pos + segment_base;
[4118]447        s2p_do_block((BytePack *) &infile_buffer[block_base], basis_bits);
[4038]448#endif
[3850]449        process_block(basis_bits, carry_q, output);
450
451        LF_scanner.load_block(output.LF, blk);
452        match_scanner.load_block(output.matches, blk);
453        if (count_only_option)
454        {
455            if (bitblock::any(output.matches))
456            {
457                if (bitblock::any(simd_and(match_vector, output.matches)))
458                {
459                    match_count += bitblock::popcount(match_vector);
460                    match_vector = output.matches;
461                }
462                else
463                {
464                    match_vector = simd_or(match_vector, output.matches);
465                }
466            }
467        }
468
469        block_pos += BLOCK_SIZE;
470        remaining -= BLOCK_SIZE;
471        blk++;
472    }
473    block_base = block_pos;
[4038]474    //fprintf(stderr, "Remaining = %i\n", remaining);
[3850]475
476    //For the last partial block, or for any carry.
477    EOF_mask = bitblock::srl(simd<1>::constant<1>(), convert(BLOCK_SIZE-remaining));
[4038]478#ifndef USE_MMAP
479     block_base = block_pos;
480     s2p_do_final_block((BytePack *) &src_buffer[block_base], basis_bits, EOF_mask);
481#endif
482#ifdef USE_MMAP
483     block_base = block_pos + segment_base;
[4118]484     s2p_do_final_block((BytePack *) &infile_buffer[block_base], basis_bits, EOF_mask);
[4038]485#endif
[3850]486    process_block(basis_bits, carry_q, output);
487
488    if (count_only_option)
489    {
490        match_count += bitblock::popcount(match_vector);
491        if (bitblock::any(output.matches))
492        {
493            match_count += bitblock::popcount(output.matches);
494        }
495        fprintf(outfile, "Matching Lines:%d\n", match_count);
496    }
497    else
498    {
499        LF_scanner.load_block(output.LF, blk);
500        match_scanner.load_block(output.matches, blk);
501        blk++;
502        for (int i = blk; i < SEGMENT_BLOCKS; i++)
503        {
504            LF_scanner.load_block(simd<1>::constant<0>(), i);
505            match_scanner.load_block(simd<1>::constant<0>(), i);
506        }
[4038]507#ifndef USE_MMAP
[3850]508        line_start = 0;
[4038]509#endif
[3850]510        while (match_scanner.has_next())
511        {
512            match_pos = match_scanner.scan_to_next();
513            line_end = LF_scanner.scan_to_next();
514            while(line_end < match_pos)
515            {
516                line_start = line_end + 1;
517                line_no++;
518                line_end = LF_scanner.scan_to_next();
519            }
[4038]520#ifndef USE_MMAP
[3850]521            fwrite(&src_buffer[line_start], 1, line_end - line_start + 1, outfile);
[4038]522#endif
523#ifdef USE_MMAP
524            fwrite(&infile_buffer[segment_base + line_start], 1, line_end - line_start + 1, outfile);
[4118]525
[4038]526#endif
[3850]527            line_start = line_end + 1;
528            line_no++;
529        }
530        while(LF_scanner.has_next())
531        {
532            line_end = LF_scanner.scan_to_next();
[4074]533            line_start = line_end+1;
[3850]534            line_no++;
535        }
536    }
537
538    buffer_pos += chars_avail;
539}
540
541
542
Note: See TracBrowser for help on using the repository browser.