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

Last change on this file since 5474 was 5474, checked in by nmedfort, 2 years ago

Eliminated ExecutionEngine? memory leak. Intentionally broke compatibility with prior versions to ensure unchecked in projects are restructured.

File size: 9.7 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 <fstream>
21#include <string>
22#include <toolchain/toolchain.h>
23#include <re/re_toolchain.h>
24#include <pablo/pablo_toolchain.h>
25#include <mutex>
26#include <boost/filesystem.hpp>
27#include <iostream> // MEEE
28#ifdef PRINT_TIMING_INFORMATION
29#include <hrtime.h>
30#include <util/papi_helper.hpp>
31#endif
32#include <sys/stat.h>
33#include <fcntl.h>
34
35using namespace llvm;
36
37static cl::OptionCategory LegacyGrepOptions("A. Standard Grep Options",
38                                       "These are standard grep options intended for compatibility with typical grep usage.");
39
40
41static cl::opt<bool> UTF_16("UTF-16", cl::desc("Regular expressions over the UTF-16 representation of Unicode."), cl::cat(LegacyGrepOptions));
42static cl::OptionCategory EnhancedGrepOptions("B. Enhanced Grep Options",
43                                       "These are additional options for icgrep functionality and performance.");
44
45
46static cl::list<std::string> inputFiles(cl::Positional, cl::desc("<regex> <input file ...>"), cl::OneOrMore);
47
48static cl::list<std::string> regexVector("e", cl::desc("Regular expression"), cl::ZeroOrMore, cl::cat(LegacyGrepOptions));
49static cl::opt<std::string> RegexFilename("f", cl::desc("Take regular expressions (one per line) from a file"), cl::value_desc("regex file"), cl::init(""), cl::cat(LegacyGrepOptions));
50
51static cl::opt<int> Threads("t", cl::desc("Total number of threads."), cl::init(1));
52
53static cl::opt<bool> MultiGrepKernels("enable-multigrep-kernels", cl::desc("Construct separated kernels for each regular expression"), cl::cat(EnhancedGrepOptions));
54static cl::opt<int> REsPerGroup("re-num", cl::desc("Number of regular expressions processed by each kernel."), cl::init(1));
55static std::vector<std::string> allFiles;
56//
57// Handler for errors reported through llvm::report_fatal_error.  Report
58// and signal error code 2 (grep convention).
59//
60static void icgrep_error_handler(void *UserData, const std::string &Message, bool GenCrashDiag) {
61    #ifndef NDEBUG
62    throw std::runtime_error(Message);
63    #else
64    // Modified from LLVM's internal report_fatal_error logic.
65    SmallVector<char, 64> Buffer;
66    raw_svector_ostream OS(Buffer);
67    OS << "icgrep ERROR: " << Message << "\n";
68    StringRef MessageStr = OS.str();
69    ssize_t written = ::write(2, MessageStr.data(), MessageStr.size());
70    (void)written; // If something went wrong, we deliberately just give up.
71    // Run the interrupt handlers to make sure any special cleanups get done, in
72    // particular that we remove files registered with RemoveFileOnSignal.
73    llvm::sys::RunInterruptHandlers();
74    exit(2);
75    #endif
76}
77
78static re::ModeFlagSet globalFlags = 0;
79
80std::vector<re::RE *> readExpressions() {
81 
82    if (RegexFilename != "") {
83        std::ifstream regexFile(RegexFilename.c_str());
84        std::string r;
85        if (regexFile.is_open()) {
86            while (std::getline(regexFile, r)) {
87                regexVector.push_back(r);
88            }
89            regexFile.close();
90        }
91    }
92   
93    // if there are no regexes specified through -e or -f, the first positional argument
94    // must be a regex, not an input file.
95   
96    if (regexVector.size() == 0) {
97        regexVector.push_back(inputFiles[0]);
98        inputFiles.erase(inputFiles.begin());
99    }
100    if (grep::IgnoreCaseFlag) {
101        globalFlags |= re::CASE_INSENSITIVE_MODE_FLAG;
102    }
103
104    std::vector<re::RE *> REs;
105    for (unsigned i = 0; i < regexVector.size(); i++) {
106        re::RE * re_ast = re::RE_Parser::parse(regexVector[i], globalFlags, grep::RegexpSyntax);
107        REs.push_back(re_ast);
108    }
109
110    if (MultiGrepKernels) {
111        std::vector<re::RE *> groups;
112        auto start = REs.begin();
113        auto end = start + REsPerGroup;
114        while (end < REs.end()) {
115            groups.push_back(re::makeAlt(start, end));
116            start = end;
117            end += REsPerGroup;
118        }
119        if ((REs.end() - start) > 1) {
120            groups.push_back(re::makeAlt(start, REs.end()));
121        } else {
122            groups.push_back(*start);
123        }
124        REs.swap(groups);
125    } else if (REs.size() > 1) {
126        re::RE * re_ast = re::makeAlt(REs.begin(), REs.end());
127        REs.assign({re_ast});
128    }
129
130    for (re::RE *& re_ast : REs) {
131        if (grep::WordRegexpFlag) {
132            re_ast = re::makeSeq({re::makeWordBoundary(), re_ast, re::makeWordBoundary()});
133        }
134        if (grep::LineRegexpFlag) {
135            re_ast = re::makeSeq({re::makeStart(), re_ast, re::makeEnd()});
136        }
137    }
138
139    return REs;
140}
141
142std::vector<size_t> total_Count;
143std::mutex count_mutex;
144size_t fileCount;
145void *DoGrep(void *args)
146{
147    size_t fileIdx;
148    grep::GrepEngine * grepEngine = (grep::GrepEngine *)args;
149
150    count_mutex.lock();
151    fileIdx = fileCount;
152    fileCount++;
153    count_mutex.unlock();
154
155    while (fileIdx < allFiles.size()) {
156        total_Count[fileIdx] = grepEngine->doGrep(allFiles[fileIdx], fileIdx);
157       
158        count_mutex.lock();
159        fileIdx = fileCount;
160        fileCount++;
161        count_mutex.unlock();
162    }
163
164    pthread_exit(nullptr);
165}
166
167
168// This is a stub, to be expanded later.
169bool excludeDirectory(boost::filesystem::path dirpath) { return dirpath.filename() == ".svn";}
170
171std::vector<std::string> getFullFileList(cl::list<std::string> & inputFiles) {
172    using namespace boost::filesystem;
173    symlink_option follow_symlink = grep::DereferenceRecursiveFlag ? symlink_option::recurse : symlink_option::none;
174    std::vector<std::string> expanded_paths;
175    boost::system::error_code errc;
176    if (grep::DereferenceRecursiveFlag) {
177        grep::RecursiveFlag = true;
178    }
179    for (const std::string & f : inputFiles) {
180//        if (f == "-") {
181//            continue;
182//        }
183        path p(f);
184        if (LLVM_UNLIKELY(grep::RecursiveFlag && is_directory(p))) {
185            if (!excludeDirectory(p)) {
186                recursive_directory_iterator di(p, follow_symlink, errc), end;
187                if (errc) {
188                    // If we cannot enter the directory, keep it in the list of files.
189                    expanded_paths.push_back(f); 
190                    continue;
191                }
192                while (di != end) {
193                    auto & e = di->path();
194                    if (is_directory(e)) {
195                        if (LLVM_UNLIKELY(excludeDirectory(e))) {
196                            di.no_push();
197                        }
198                    } else {
199                        expanded_paths.push_back(e.string());
200                    }
201                    di.increment(errc);
202                    if (errc) {
203                        expanded_paths.push_back(e.string()); 
204                    }
205                }
206            }
207        } else {
208            expanded_paths.push_back(p.string());
209        }
210    }
211    return expanded_paths;
212}
213
214
215int main(int argc, char *argv[]) {
216   
217    llvm::install_fatal_error_handler(&icgrep_error_handler);
218    AddParabixVersionPrinter();
219#ifndef USE_LLVM_3_6
220    cl::HideUnrelatedOptions(ArrayRef<const cl::OptionCategory *>{&LegacyGrepOptions, &EnhancedGrepOptions, grep::grep_regexp_flags(), grep::grep_output_flags(), re::re_toolchain_flags(), pablo::pablo_toolchain_flags(), codegen::codegen_flags()});
221#endif
222    cl::ParseCommandLineOptions(argc, argv);
223    if (grep::RegexpSyntax == re::RE_Syntax::FixedStrings) {
224        llvm::report_fatal_error("Sorry, FixedStrings syntax is not fully supported\n.");
225    }
226
227    const auto REs = readExpressions();
228
229    allFiles = getFullFileList(inputFiles);
230
231    grep::GrepEngine grepEngine;
232
233    if (allFiles.empty()) {
234
235        grepEngine.grepCodeGen(REs, grep::Mode, UTF_16, GrepSource::StdIn);
236        allFiles = { "-" };
237        grep::initFileResult(allFiles);
238        total_Count.resize(1);
239        total_Count[0] = grepEngine.doGrep(STDIN_FILENO, 0);
240
241    } else {
242       
243        setNVPTXOption();
244       
245        if (codegen::NVPTX) {
246            grepEngine.grepCodeGen_nvptx(REs, grep::Mode, UTF_16);
247            for (unsigned i = 0; i != allFiles.size(); ++i) {
248                grepEngine.doGrep(allFiles[i]);
249            }
250            return 0;
251        } else {
252            grepEngine.grepCodeGen(REs, grep::Mode, UTF_16, GrepSource::File);
253        }
254
255        grep::initFileResult(allFiles);
256        total_Count.resize(allFiles.size());
257
258        if (Threads <= 1) {
259            for (unsigned i = 0; i != allFiles.size(); ++i) {
260                total_Count[i] = grepEngine.doGrep(allFiles[i], i);
261            }
262        } else if (Threads > 1) {
263            const unsigned numOfThreads = Threads; // <- convert the command line value into an integer to allow stack allocation
264            pthread_t threads[numOfThreads];
265
266            for(unsigned long i = 0; i < numOfThreads; ++i){
267                const int rc = pthread_create(&threads[i], nullptr, DoGrep, (void *)&grepEngine);
268                if (rc) {
269                    llvm::report_fatal_error("Failed to create thread: code " + std::to_string(rc));
270                }
271            }
272            for(unsigned i = 0; i < numOfThreads; ++i) {
273                void * status = nullptr;
274                const int rc = pthread_join(threads[i], &status);
275                if (rc) {
276                    llvm::report_fatal_error("Failed to join thread: code " + std::to_string(rc));
277                }
278            }
279        }
280
281    }
282   
283    grep::PrintResult(grep::Mode, total_Count);
284   
285    return 0;
286}
Note: See TracBrowser for help on using the repository browser.