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

Last change on this file since 5480 was 5480, checked in by cameron, 22 months ago

Recognize all standard Posix and GNU grep flags; support in progress

File size: 8.2 KB
Line 
1/*
2 *  Copyright (c) 2016 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
7#include <cstdio>
8#include <vector>
9#include <llvm/Support/CommandLine.h>
10#include <llvm/Support/ErrorHandling.h>
11#include <llvm/Support/Signals.h>
12#include <llvm/Support/raw_ostream.h>
13#include <re/re_alt.h>
14#include <re/re_seq.h>
15#include <re/re_start.h>
16#include <re/re_end.h>
17#include <re/re_parser.h>
18#include <re/re_utility.h>
19#include <grep_engine.h>
20#include <grep_interface.h>
21#include <fstream>
22#include <string>
23#include <toolchain/toolchain.h>
24#include <re/re_toolchain.h>
25#include <pablo/pablo_toolchain.h>
26#include <mutex>
27#include <boost/filesystem.hpp>
28#include <iostream> // MEEE
29#ifdef PRINT_TIMING_INFORMATION
30#include <hrtime.h>
31#include <util/papi_helper.hpp>
32#endif
33#include <sys/stat.h>
34#include <fcntl.h>
35
36using namespace llvm;
37
38static cl::opt<bool> UTF_16("UTF-16", cl::desc("Regular expressions over the UTF-16 representation of Unicode."));
39
40static cl::list<std::string> inputFiles(cl::Positional, cl::desc("<regex> <input file ...>"), cl::OneOrMore);
41
42static cl::opt<int> Threads("t", cl::desc("Total number of threads."), cl::init(1));
43
44static cl::opt<bool> MultiGrepKernels("enable-multigrep-kernels", cl::desc("Construct separated kernels for each regular expression"));
45static cl::opt<int> REsPerGroup("re-num", cl::desc("Number of regular expressions processed by each kernel."), cl::init(1));
46static std::vector<std::string> allFiles;
47
48static re::ModeFlagSet globalFlags = 0;
49
50std::vector<re::RE *> readExpressions() {
51 
52    if (grep::FileFlag != "") {
53        std::ifstream regexFile(grep::FileFlag.c_str());
54        std::string r;
55        if (regexFile.is_open()) {
56            while (std::getline(regexFile, r)) {
57                grep::RegexpVector.push_back(r);
58            }
59            regexFile.close();
60        }
61    }
62   
63    // if there are no regexes specified through -e or -f, the first positional argument
64    // must be a regex, not an input file.
65   
66    if (grep::RegexpVector.size() == 0) {
67        grep::RegexpVector.push_back(inputFiles[0]);
68        inputFiles.erase(inputFiles.begin());
69    }
70    if (grep::IgnoreCaseFlag) {
71        globalFlags |= re::CASE_INSENSITIVE_MODE_FLAG;
72    }
73
74    std::vector<re::RE *> REs;
75    for (unsigned i = 0; i < grep::RegexpVector.size(); i++) {
76        re::RE * re_ast = re::RE_Parser::parse(grep::RegexpVector[i], globalFlags, grep::RegexpSyntax);
77        REs.push_back(re_ast);
78    }
79
80    if (MultiGrepKernels) {
81        std::vector<re::RE *> groups;
82        auto start = REs.begin();
83        auto end = start + REsPerGroup;
84        while (end < REs.end()) {
85            groups.push_back(re::makeAlt(start, end));
86            start = end;
87            end += REsPerGroup;
88        }
89        if ((REs.end() - start) > 1) {
90            groups.push_back(re::makeAlt(start, REs.end()));
91        } else {
92            groups.push_back(*start);
93        }
94        REs.swap(groups);
95    } else if (REs.size() > 1) {
96        re::RE * re_ast = re::makeAlt(REs.begin(), REs.end());
97        REs.assign({re_ast});
98    }
99
100    for (re::RE *& re_ast : REs) {
101        if (grep::WordRegexpFlag) {
102            re_ast = re::makeSeq({re::makeWordBoundary(), re_ast, re::makeWordBoundary()});
103        }
104        if (grep::LineRegexpFlag) {
105            re_ast = re::makeSeq({re::makeStart(), re_ast, re::makeEnd()});
106        }
107    }
108
109    return REs;
110}
111
112std::vector<size_t> total_Count;
113std::mutex count_mutex;
114size_t fileCount;
115void *DoGrep(void *args)
116{
117    size_t fileIdx;
118    grep::GrepEngine * grepEngine = (grep::GrepEngine *)args;
119
120    count_mutex.lock();
121    fileIdx = fileCount;
122    fileCount++;
123    count_mutex.unlock();
124
125    while (fileIdx < allFiles.size()) {
126        total_Count[fileIdx] = grepEngine->doGrep(allFiles[fileIdx], fileIdx);
127       
128        count_mutex.lock();
129        fileIdx = fileCount;
130        fileCount++;
131        count_mutex.unlock();
132    }
133
134    pthread_exit(nullptr);
135}
136
137
138// This is a stub, to be expanded later.
139bool excludeDirectory(boost::filesystem::path dirpath) { return dirpath.filename() == ".svn";}
140
141// Determine whether to skip a path based on -D skip or -d skip settings.
142bool skip_path(boost::filesystem::path p) {
143    using namespace boost::filesystem;
144    switch (status(p).type()) {
145        case directory_file: return grep::DirectoriesFlag == grep::Skip;
146        case block_file:
147        case character_file:
148        case fifo_file:
149        case socket_file:
150            return grep::DevicesFlag == grep::Skip;
151        default:
152            return false;
153    }
154}
155
156std::vector<std::string> getFullFileList(cl::list<std::string> & inputFiles) {
157    using namespace boost::filesystem;
158    symlink_option follow_symlink = grep::DereferenceRecursiveFlag ? symlink_option::recurse : symlink_option::none;
159    std::vector<std::string> expanded_paths;
160    boost::system::error_code errc;
161    for (const std::string & f : inputFiles) {
162        //        if (f == "-") {
163        //            continue;
164        //        }
165        path p(f);
166        if (skip_path(p)) {
167            continue;
168        }
169        if (LLVM_UNLIKELY((grep::DirectoriesFlag == grep::Recurse) && is_directory(p))) {
170            if (!excludeDirectory(p)) {
171                recursive_directory_iterator di(p, follow_symlink, errc), end;
172                if (errc) {
173                    // If we cannot enter the directory, keep it in the list of files.
174                    expanded_paths.push_back(f);
175                    continue;
176                }
177                while (di != end) {
178                    auto & e = di->path();
179                    if (is_directory(e)) {
180                        if (LLVM_UNLIKELY(excludeDirectory(e))) {
181                            di.no_push();
182                        }
183                    } else {
184                        if (!skip_path(e)) expanded_paths.push_back(e.string());
185                    }
186                    di.increment(errc);
187                    if (errc) {
188                        expanded_paths.push_back(e.string());
189                    }
190                }
191            }
192        } else {
193            expanded_paths.push_back(p.string());
194        }
195    }
196    return expanded_paths;
197}
198
199int main(int argc, char *argv[]) {
200
201    grep::InitializeCommandLineInterface(argc, argv);
202   
203    const auto REs = readExpressions();
204
205    allFiles = getFullFileList(inputFiles);
206
207    grep::GrepEngine grepEngine;
208
209    if (allFiles.empty()) {
210
211        grepEngine.grepCodeGen(REs, grep::Mode, UTF_16, GrepSource::StdIn);
212        allFiles = { "-" };
213        grep::initFileResult(allFiles);
214        total_Count.resize(1);
215        total_Count[0] = grepEngine.doGrep(STDIN_FILENO, 0);
216
217    } else {
218       
219        setNVPTXOption();
220       
221        if (codegen::NVPTX) {
222            grepEngine.grepCodeGen_nvptx(REs, grep::Mode, UTF_16);
223            for (unsigned i = 0; i != allFiles.size(); ++i) {
224                grepEngine.doGrep(allFiles[i]);
225            }
226            return 0;
227        } else {
228            grepEngine.grepCodeGen(REs, grep::Mode, UTF_16, GrepSource::File);
229        }
230
231        grep::initFileResult(allFiles);
232        total_Count.resize(allFiles.size());
233
234        if (Threads <= 1) {
235            for (unsigned i = 0; i != allFiles.size(); ++i) {
236                total_Count[i] = grepEngine.doGrep(allFiles[i], i);
237            }
238        } else if (Threads > 1) {
239            const unsigned numOfThreads = Threads; // <- convert the command line value into an integer to allow stack allocation
240            pthread_t threads[numOfThreads];
241
242            for(unsigned long i = 0; i < numOfThreads; ++i){
243                const int rc = pthread_create(&threads[i], nullptr, DoGrep, (void *)&grepEngine);
244                if (rc) {
245                    llvm::report_fatal_error("Failed to create thread: code " + std::to_string(rc));
246                }
247            }
248            for(unsigned i = 0; i < numOfThreads; ++i) {
249                void * status = nullptr;
250                const int rc = pthread_join(threads[i], &status);
251                if (rc) {
252                    llvm::report_fatal_error("Failed to join thread: code " + std::to_string(rc));
253                }
254            }
255        }
256
257    }
258   
259    grep::PrintResult(grep::Mode, total_Count);
260   
261    return 0;
262}
Note: See TracBrowser for help on using the repository browser.