rose_build: reduce size/scope of context objects

This commit is contained in:
Alex Coyte 2017-03-30 14:34:33 +11:00 committed by Matthew Barr
parent a2b2940f85
commit 37cb93e60f
14 changed files with 520 additions and 458 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015-2016, Intel Corporation
* Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@ -560,7 +560,7 @@ buildCastle(const CastleProto &proto,
DEBUG_PRINTF("%zu subcastles may go stale\n", may_stale.size());
vector<mmbit_sparse_iter> stale_iter;
if (!may_stale.empty()) {
mmbBuildSparseIterator(stale_iter, may_stale, numRepeats);
stale_iter = mmbBuildSparseIterator(may_stale, numRepeats);
}

View File

@ -30,6 +30,7 @@
#include "grey.h"
#include "rose_build_impl.h"
#include "rose_build_matchers.h"
#include "rose_internal.h"
#include "ue2common.h"
#include "nfa/dfa_min.h"
@ -71,6 +72,8 @@ namespace ue2 {
#define INIT_STATE (DEAD_STATE + 1)
#define NO_FRAG_ID (~0U)
// Adds a vertex with the given reach.
static
NFAVertex add_vertex(NGHolder &h, const CharReach &cr) {
@ -173,7 +176,7 @@ void mergeAnchoredDfas(vector<unique_ptr<raw_dfa>> &dfas,
}
static
void remapAnchoredReports(raw_dfa &rdfa, const RoseBuildImpl &build) {
void remapAnchoredReports(raw_dfa &rdfa, const vector<u32> &frag_map) {
for (dstate &ds : rdfa.states) {
assert(ds.reports_eod.empty()); // Not used in anchored matcher.
if (ds.reports.empty()) {
@ -182,8 +185,8 @@ void remapAnchoredReports(raw_dfa &rdfa, const RoseBuildImpl &build) {
flat_set<ReportID> new_reports;
for (auto id : ds.reports) {
assert(id < build.literal_info.size());
new_reports.insert(build.literal_info.at(id).fragment_id);
assert(id < frag_map.size());
new_reports.insert(frag_map[id]);
}
ds.reports = std::move(new_reports);
}
@ -194,21 +197,37 @@ void remapAnchoredReports(raw_dfa &rdfa, const RoseBuildImpl &build) {
* ids) with the fragment id for each literal.
*/
static
void remapAnchoredReports(RoseBuildImpl &build) {
void remapAnchoredReports(RoseBuildImpl &build, const vector<u32> &frag_map) {
for (auto &m : build.anchored_nfas) {
for (auto &rdfa : m.second) {
assert(rdfa);
remapAnchoredReports(*rdfa, build);
remapAnchoredReports(*rdfa, frag_map);
}
}
}
/**
* Returns mapping from literal ids to fragment ids.
*/
static
vector<u32> reverseFragMap(const RoseBuildImpl &build,
const vector<LitFragment> &fragments) {
vector<u32> rev(build.literal_info.size(), NO_FRAG_ID);
for (const auto &f : fragments) {
for (u32 lit_id : f.lit_ids) {
assert(lit_id < rev.size());
rev[lit_id] = f.fragment_id;
}
}
return rev;
}
/**
* \brief Replace the reports (which are literal final_ids) in the given
* raw_dfa with program offsets.
*/
static
void remapIdsToPrograms(const RoseBuildImpl &build, raw_dfa &rdfa) {
void remapIdsToPrograms(const vector<LitFragment> &fragments, raw_dfa &rdfa) {
for (dstate &ds : rdfa.states) {
assert(ds.reports_eod.empty()); // Not used in anchored matcher.
if (ds.reports.empty()) {
@ -217,7 +236,7 @@ void remapIdsToPrograms(const RoseBuildImpl &build, raw_dfa &rdfa) {
flat_set<ReportID> new_reports;
for (auto fragment_id : ds.reports) {
auto &frag = build.fragments.at(fragment_id);
const auto &frag = fragments.at(fragment_id);
new_reports.insert(frag.lit_program_offset);
}
ds.reports = std::move(new_reports);
@ -731,7 +750,7 @@ int addToAnchoredMatcher(RoseBuildImpl &build, const NGHolder &anchored,
}
static
void buildSimpleDfas(const RoseBuildImpl &build,
void buildSimpleDfas(const RoseBuildImpl &build, const vector<u32> &frag_map,
vector<unique_ptr<raw_dfa>> *anchored_dfas) {
/* we should have determinised all of these before so there should be no
* chance of failure. */
@ -739,7 +758,8 @@ void buildSimpleDfas(const RoseBuildImpl &build,
for (const auto &simple : build.anchored_simple) {
exit_ids.clear();
for (auto lit_id : simple.second) {
exit_ids.insert(build.literal_info[lit_id].fragment_id);
assert(lit_id < frag_map.size());
exit_ids.insert(frag_map[lit_id]);
}
auto h = populate_holder(simple.first, exit_ids);
Automaton_Holder autom(*h);
@ -760,7 +780,8 @@ void buildSimpleDfas(const RoseBuildImpl &build,
* from RoseBuildImpl.
*/
static
vector<unique_ptr<raw_dfa>> getAnchoredDfas(RoseBuildImpl &build) {
vector<unique_ptr<raw_dfa>> getAnchoredDfas(RoseBuildImpl &build,
const vector<u32> &frag_map) {
vector<unique_ptr<raw_dfa>> dfas;
// DFAs that already exist as raw_dfas.
@ -773,7 +794,7 @@ vector<unique_ptr<raw_dfa>> getAnchoredDfas(RoseBuildImpl &build) {
// DFAs we currently have as simple literals.
if (!build.anchored_simple.empty()) {
buildSimpleDfas(build, &dfas);
buildSimpleDfas(build, frag_map, &dfas);
build.anchored_simple.clear();
}
@ -825,7 +846,8 @@ size_t buildNfas(vector<raw_dfa> &anchored_dfas,
return total_size;
}
vector<raw_dfa> buildAnchoredDfas(RoseBuildImpl &build) {
vector<raw_dfa> buildAnchoredDfas(RoseBuildImpl &build,
const vector<LitFragment> &fragments) {
vector<raw_dfa> dfas;
if (build.anchored_nfas.empty() && build.anchored_simple.empty()) {
@ -833,9 +855,10 @@ vector<raw_dfa> buildAnchoredDfas(RoseBuildImpl &build) {
return dfas;
}
remapAnchoredReports(build);
const auto frag_map = reverseFragMap(build, fragments);
remapAnchoredReports(build, frag_map);
auto anch_dfas = getAnchoredDfas(build);
auto anch_dfas = getAnchoredDfas(build, frag_map);
mergeAnchoredDfas(anch_dfas, build);
dfas.reserve(anch_dfas.size());
@ -847,8 +870,8 @@ vector<raw_dfa> buildAnchoredDfas(RoseBuildImpl &build) {
}
aligned_unique_ptr<anchored_matcher_info>
buildAnchoredMatcher(RoseBuildImpl &build, vector<raw_dfa> &dfas,
size_t *asize) {
buildAnchoredMatcher(RoseBuildImpl &build, const vector<LitFragment> &fragments,
vector<raw_dfa> &dfas, size_t *asize) {
const CompileContext &cc = build.cc;
if (dfas.empty()) {
@ -858,7 +881,7 @@ buildAnchoredMatcher(RoseBuildImpl &build, vector<raw_dfa> &dfas,
}
for (auto &rdfa : dfas) {
remapIdsToPrograms(build, rdfa);
remapIdsToPrograms(fragments, rdfa);
}
vector<aligned_unique_ptr<NFA>> nfas;

View File

@ -44,11 +44,13 @@ namespace ue2 {
class RoseBuildImpl;
struct raw_dfa;
struct LitFragment;
/**
* \brief Construct a set of anchored DFAs from our anchored literals/engines.
*/
std::vector<raw_dfa> buildAnchoredDfas(RoseBuildImpl &build);
std::vector<raw_dfa> buildAnchoredDfas(RoseBuildImpl &build,
const std::vector<LitFragment> &fragments);
/**
* \brief Construct an anchored_matcher_info runtime structure from the given
@ -58,8 +60,9 @@ std::vector<raw_dfa> buildAnchoredDfas(RoseBuildImpl &build);
* given in litPrograms.
*/
aligned_unique_ptr<anchored_matcher_info>
buildAnchoredMatcher(RoseBuildImpl &build, std::vector<raw_dfa> &dfas,
size_t *asize);
buildAnchoredMatcher(RoseBuildImpl &build,
const std::vector<LitFragment> &fragments,
std::vector<raw_dfa> &dfas, size_t *asize);
u32 anchoredStateSize(const anchored_matcher_info &atable);

File diff suppressed because it is too large Load Diff

View File

@ -1669,7 +1669,7 @@ bool roleOffsetsAreValid(const RoseGraph &g) {
#endif // NDEBUG
aligned_unique_ptr<RoseEngine> RoseBuildImpl::buildRose(u32 minWidth) {
dumpRoseGraph(*this, nullptr, "rose_early.dot");
dumpRoseGraph(*this, "rose_early.dot");
// Early check for Rose implementability.
assert(canImplementGraphs(*this));
@ -1780,7 +1780,7 @@ aligned_unique_ptr<RoseEngine> RoseBuildImpl::buildRose(u32 minWidth) {
assert(roleOffsetsAreValid(g));
assert(historiesAreValid(g));
dumpRoseGraph(*this, nullptr, "rose_pre_norm.dot");
dumpRoseGraph(*this, "rose_pre_norm.dot");
return buildFinalEngine(minWidth);
}

View File

@ -112,8 +112,11 @@ string rose_off::str(void) const {
class RoseGraphWriter {
public:
RoseGraphWriter(const RoseBuildImpl &b_in, const RoseEngine *t_in) :
build(b_in), t(t_in) {
RoseGraphWriter(const RoseBuildImpl &b_in, const map<u32, u32> &frag_map_in,
const map<left_id, u32> &lqm_in,
const map<suffix_id, u32> &sqm_in, const RoseEngine *t_in)
: frag_map(frag_map_in), leftfix_queue_map(lqm_in),
suffix_queue_map(sqm_in), build(b_in), t(t_in) {
for (const auto &m : build.ghost) {
ghost.insert(m.second);
}
@ -160,8 +163,8 @@ public:
if (g[v].suffix) {
suffix_id suff(g[v].suffix);
os << "\\n" << render_kind(suff) << " (top " << g[v].suffix.top;
auto it = build.suffix_queue_map.find(suff);
if (it != end(build.suffix_queue_map)) {
auto it = suffix_queue_map.find(suff);
if (it != end(suffix_queue_map)) {
os << ", queue " << it->second;
}
os << ")";
@ -174,8 +177,8 @@ public:
if (g[v].left) {
left_id left(g[v].left);
os << "\\n" << render_kind(left) << " (queue ";
auto it = build.leftfix_queue_map.find(left);
if (it != end(build.leftfix_queue_map)) {
auto it = leftfix_queue_map.find(left);
if (it != end(leftfix_queue_map)) {
os << it->second;
} else {
os << "??";
@ -248,8 +251,8 @@ private:
// Render the literal associated with a vertex.
void writeLiteral(ostream &os, u32 id) const {
os << "lit=" << id;
if (id < build.literal_info.size()) {
os << "/" << build.literal_info[id].fragment_id << " ";
if (contains(frag_map, id)) {
os << "/" << frag_map.at(id) << " ";
} else {
os << "/nofrag ";
}
@ -269,13 +272,32 @@ private:
}
set<RoseVertex> ghost;
const map<u32, u32> &frag_map;
const map<left_id, u32> &leftfix_queue_map;
const map<suffix_id, u32> &suffix_queue_map;
const RoseBuildImpl &build;
const RoseEngine *t;
};
} // namespace
static
map<u32, u32> makeFragMap(const vector<LitFragment> &fragments) {
map<u32, u32> fm;
for (const auto &f : fragments) {
for (u32 id : f.lit_ids) {
fm[id] = f.fragment_id;
}
}
return fm;
}
static
void dumpRoseGraph(const RoseBuildImpl &build, const RoseEngine *t,
const vector<LitFragment> &fragments,
const map<left_id, u32> &leftfix_queue_map,
const map<suffix_id, u32> &suffix_queue_map,
const char *filename) {
const Grey &grey = build.cc.grey;
@ -293,10 +315,16 @@ void dumpRoseGraph(const RoseBuildImpl &build, const RoseEngine *t,
DEBUG_PRINTF("dumping graph to %s\n", ss.str().c_str());
ofstream os(ss.str());
RoseGraphWriter writer(build, t);
auto frag_map = makeFragMap(fragments);
RoseGraphWriter writer(build, frag_map, leftfix_queue_map, suffix_queue_map,
t);
writeGraphviz(os, build.g, writer, get(boost::vertex_index, build.g));
}
void dumpRoseGraph(const RoseBuildImpl &build, const char *filename) {
dumpRoseGraph(build, nullptr, {}, {}, {}, filename);
}
namespace {
struct CompareVertexRole {
explicit CompareVertexRole(const RoseGraph &g_in) : g(g_in) {}
@ -321,11 +349,14 @@ void lit_graph_info(const RoseBuildImpl &build, const rose_literal_info &li,
}
static
void dumpRoseLiterals(const RoseBuildImpl &build, const char *filename) {
void dumpRoseLiterals(const RoseBuildImpl &build,
const vector<LitFragment> &fragments,
const Grey &grey) {
const RoseGraph &g = build.g;
map<u32, u32> frag_map = makeFragMap(fragments);
DEBUG_PRINTF("dumping literals\n");
ofstream os(filename);
ofstream os(grey.dumpPath + "rose_literals.txt");
os << "ROSE LITERALS: a total of " << build.literals.right.size()
<< " literals and " << num_vertices(g) << " roles." << endl << endl;
@ -353,8 +384,11 @@ void dumpRoseLiterals(const RoseBuildImpl &build, const char *filename) {
break;
}
os << " ID " << id << "/" << lit_info.fragment_id << ": \""
<< escapeString(s.get_string()) << "\""
os << " ID " << id;
if (contains(frag_map, id)) {
os << "/" << frag_map.at(id);
}
os << ": \"" << escapeString(s.get_string()) << "\""
<< " (len " << s.length() << ",";
if (s.any_nocase()) {
os << " nocase,";
@ -833,7 +867,7 @@ void dumpMultipathShufti(ofstream &os, u32 len, const u8 *lo, const u8 *hi,
#define PROGRAM_CASE(name) \
case ROSE_INSTR_##name: { \
os << " " << std::setw(4) << std::setfill('0') << (pc - pc_base) \
<< ": " #name " (" << (int)ROSE_INSTR_##name << ")" << endl; \
<< ": " #name "\n"; \
const auto *ri = (const struct ROSE_STRUCT_##name *)pc;
#define PROGRAM_NEXT_INSTRUCTION \
@ -1444,13 +1478,13 @@ void dumpProgram(ofstream &os, const RoseEngine *t, const char *pc) {
#undef PROGRAM_NEXT_INSTRUCTION
static
void dumpRoseLitPrograms(const RoseBuildImpl &build, const RoseEngine *t,
const string &filename) {
void dumpRoseLitPrograms(const vector<LitFragment> &fragments,
const RoseEngine *t, const string &filename) {
ofstream os(filename);
// Collect all programs referenced by a literal fragment.
vector<u32> programs;
for (const auto &frag : build.fragments) {
for (const auto &frag : fragments) {
if (frag.lit_program_offset) {
programs.push_back(frag.lit_program_offset);
}
@ -2185,18 +2219,21 @@ void roseDumpComponents(const RoseEngine *t, bool dump_raw,
}
static
void roseDumpPrograms(const RoseBuildImpl &build, const RoseEngine *t,
void roseDumpPrograms(const vector<LitFragment> &fragments, const RoseEngine *t,
const string &base) {
dumpRoseLitPrograms(build, t, base + "/rose_lit_programs.txt");
dumpRoseLitPrograms(fragments, t, base + "/rose_lit_programs.txt");
dumpRoseEodPrograms(t, base + "/rose_eod_programs.txt");
dumpRoseReportPrograms(t, base + "/rose_report_programs.txt");
dumpRoseAnchoredPrograms(t, base + "/rose_anchored_programs.txt");
dumpRoseDelayPrograms(t, base + "/rose_delay_programs.txt");
}
void dumpRose(const RoseBuildImpl &build, const RoseEngine *t) {
void dumpRose(const RoseBuildImpl &build, const vector<LitFragment> &fragments,
const map<left_id, u32> &leftfix_queue_map,
const map<suffix_id, u32> &suffix_queue_map,
const RoseEngine *t) {
const Grey &grey = build.cc.grey;
if (!grey.dumpFlags) {
return;
}
@ -2218,16 +2255,14 @@ void dumpRose(const RoseBuildImpl &build, const RoseEngine *t) {
fclose(f);
roseDumpComponents(t, false, grey.dumpPath);
roseDumpPrograms(build, t, grey.dumpPath);
roseDumpPrograms(fragments, t, grey.dumpPath);
// Graph.
dumpRoseGraph(build, t, "rose.dot");
dumpRoseGraph(build, t, fragments, leftfix_queue_map, suffix_queue_map,
"rose.dot");
// Literals.
ss.str("");
ss.clear();
ss << grey.dumpPath << "rose_literals.txt";
dumpRoseLiterals(build, ss.str().c_str());
// Literals
dumpRoseLiterals(build, fragments, grey);
f = fopen((grey.dumpPath + "/rose_struct.txt").c_str(), "w");
roseDumpStructRaw(t, f);

View File

@ -29,6 +29,9 @@
#ifndef ROSE_BUILD_DUMP_H
#define ROSE_BUILD_DUMP_H
#include "ue2common.h"
#include <map>
#include <string>
#include <vector>
@ -39,30 +42,40 @@ namespace ue2 {
class RoseBuildImpl;
struct Grey;
struct hwlmLiteral;
struct LitFragment;
struct left_id;
struct suffix_id;
#ifdef DUMP_SUPPORT
// Dump the Rose graph in graphviz representation.
void dumpRoseGraph(const RoseBuildImpl &build, const RoseEngine *t,
const char *filename);
void dumpRoseGraph(const RoseBuildImpl &build, const char *filename);
void dumpRose(const RoseBuildImpl &build, const RoseEngine *t);
void dumpRose(const RoseBuildImpl &build,
const std::vector<LitFragment> &fragments,
const std::map<left_id, u32> &leftfix_queue_map,
const std::map<suffix_id, u32> &suffix_queue_map,
const RoseEngine *t);
void dumpMatcherLiterals(const std::vector<hwlmLiteral> &lits,
const std::string &name, const Grey &grey);
#else
static UNUSED
void dumpRoseGraph(const RoseBuildImpl &, const RoseEngine *, const char *) {
void dumpRoseGraph(const RoseBuildImpl &, const char *) {
}
static UNUSED
void dumpRose(const RoseBuildImpl &, const RoseEngine *) {
void dumpRose(const RoseBuildImpl &, const std::vector<LitFragment> &,
const std::map<left_id, u32> &, const std::map<suffix_id, u32> &,
const RoseEngine *) {
}
static UNUSED
void dumpMatcherLiterals(const std::vector<hwlmLiteral> &, const std::string &,
const Grey &) {
}
#endif
} // namespace ue2

View File

@ -264,7 +264,6 @@ struct rose_literal_info {
ue2::flat_set<RoseVertex> vertices;
rose_group group_mask = 0;
u32 undelayed_id = MO_INVALID_IDX;
u32 fragment_id = MO_INVALID_IDX; //!< ID corresponding to literal prog.
bool squash_group = false;
bool requires_benefits = false;
};
@ -437,15 +436,6 @@ private:
std::set<ReportID> all_reports(const OutfixInfo &outfix);
struct LitFragment {
LitFragment(u32 fragment_id_in, rose_group groups_in)
: fragment_id(fragment_id_in), groups(groups_in) {}
u32 fragment_id;
rose_group groups;
u32 lit_program_offset = ROSE_INVALID_PROG_OFFSET;
u32 delay_program_offset = ROSE_INVALID_PROG_OFFSET;
};
// Concrete impl class
class RoseBuildImpl : public RoseBuild {
public:
@ -576,19 +566,11 @@ public:
u32 ematcher_region_size; /**< number of bytes the eod table runs over */
/** \brief Mapping from leftfix to queue ID (used in dump code). */
unordered_map<left_id, u32> leftfix_queue_map;
/** \brief Mapping from suffix to queue ID (used in dump code). */
unordered_map<suffix_id, u32> suffix_queue_map;
/** \brief Mapping from anchored literal ID to the original literal suffix
* present when the literal was added to the literal matcher. Used for
* overlap calculation in history assignment. */
std::map<u32, rose_literal_id> anchoredLitSuffix;
std::vector<LitFragment> fragments;
unordered_set<left_id> transient;
unordered_map<left_id, rose_group> rose_squash_masks;

View File

@ -350,9 +350,6 @@ void findMoreLiteralMasks(RoseBuildImpl &build) {
const u32 id = e.first;
const auto &lit = e.second;
// This pass takes place before fragment IDs are assigned to literals.
assert(build.literal_info.at(id).fragment_id == MO_INVALID_IDX);
if (lit.delay || build.isDelayed(id)) {
continue;
}
@ -673,6 +670,7 @@ struct MatcherProto {
*/
static
MatcherProto makeMatcherProto(const RoseBuildImpl &build,
const vector<LitFragment> &fragments,
rose_literal_table table, bool delay_rebuild,
size_t max_len, u32 max_offset = ROSE_BOUND_INF) {
MatcherProto mp;
@ -682,92 +680,91 @@ MatcherProto makeMatcherProto(const RoseBuildImpl &build,
assert(build.cc.streaming);
}
for (const auto &e : build.literals.right) {
const u32 id = e.first;
if (build.literal_info.at(id).fragment_id == MO_INVALID_IDX) {
continue;
}
for (const auto &f : fragments) {
for (u32 id : f.lit_ids) {
const rose_literal_id &lit = build.literals.right.at(id);
if (e.second.delay) {
continue; /* delay id's are virtual-ish */
}
if (lit.table != table) {
continue; /* wrong table */
}
if (e.second.table != table) {
continue; /* wrong table */
}
if (lit.delay) {
continue; /* delay id's are virtual-ish */
}
assert(id < build.literal_info.size());
const rose_literal_info &info = build.literal_info[id];
/* Note: requires_benefits are handled in the literal entries */
const ue2_literal &lit = e.second.s;
assert(id < build.literal_info.size());
const auto &info = build.literal_info.at(id);
DEBUG_PRINTF("lit='%s' (len %zu)\n", escapeString(lit).c_str(),
lit.length());
/* Note: requires_benefits are handled in the literal entries */
const ue2_literal &s = lit.s;
// When building the delay rebuild table, we only want to include
// literals that have delayed variants.
if (delay_rebuild && info.delayed_ids.empty()) {
DEBUG_PRINTF("not needed for delay rebuild\n");
continue;
}
DEBUG_PRINTF("lit='%s' (len %zu)\n", escapeString(s).c_str(),
s.length());
if (max_offset != ROSE_BOUND_INF) {
u64a min_report = literalMinReportOffset(build, e.second, info);
if (min_report > max_offset) {
DEBUG_PRINTF("min report offset=%llu exceeds max_offset=%u\n",
min_report, max_offset);
// When building the delay rebuild table, we only want to include
// literals that have delayed variants.
if (delay_rebuild && info.delayed_ids.empty()) {
DEBUG_PRINTF("not needed for delay rebuild\n");
continue;
}
if (max_offset != ROSE_BOUND_INF) {
u64a min_report = literalMinReportOffset(build, lit, info);
if (min_report > max_offset) {
DEBUG_PRINTF("min report offset=%llu exceeds "
"max_offset=%u\n", min_report, max_offset);
continue;
}
}
const vector<u8> &msk = lit.msk;
const vector<u8> &cmp = lit.cmp;
bool noruns = isNoRunsLiteral(build, id, info, max_len);
size_t lit_hist_len = 0;
if (build.cc.streaming) {
lit_hist_len = max(msk.size(), min(s.length(), max_len));
lit_hist_len = lit_hist_len ? lit_hist_len - 1 : 0;
}
DEBUG_PRINTF("lit requires %zu bytes of history\n", lit_hist_len);
assert(lit_hist_len <= build.cc.grey.maxHistoryAvailable);
auto lit_final = s; // copy
if (lit_final.length() > ROSE_SHORT_LITERAL_LEN_MAX) {
DEBUG_PRINTF("truncating to tail of length %zu\n",
size_t{ROSE_SHORT_LITERAL_LEN_MAX});
lit_final.erase(0, lit_final.length()
- ROSE_SHORT_LITERAL_LEN_MAX);
// We shouldn't have set a threshold below 8 chars.
assert(msk.size() <= ROSE_SHORT_LITERAL_LEN_MAX);
assert(!noruns);
}
const auto &s_final = lit_final.get_string();
bool nocase = lit_final.any_nocase();
DEBUG_PRINTF("id=%u, s='%s', nocase=%d, noruns=%d, msk=%s, "
"cmp=%s\n", f.fragment_id,
escapeString(s_final).c_str(), (int)nocase, noruns,
dumpMask(msk).c_str(), dumpMask(cmp).c_str());
if (!maskIsConsistent(s_final, nocase, msk, cmp)) {
DEBUG_PRINTF("msk/cmp for literal can't match, skipping\n");
continue;
}
mp.accel_lits.emplace_back(s.get_string(), s.any_nocase(), msk, cmp,
info.group_mask);
mp.history_required = max(mp.history_required, lit_hist_len);
u32 prog_offset = delay_rebuild ? f.delay_program_offset
: f.lit_program_offset;
const auto &groups = f.groups;
mp.lits.emplace_back(move(s_final), nocase, noruns, prog_offset,
groups, msk, cmp);
}
const vector<u8> &msk = e.second.msk;
const vector<u8> &cmp = e.second.cmp;
bool noruns = isNoRunsLiteral(build, id, info, max_len);
size_t lit_hist_len = 0;
if (build.cc.streaming) {
lit_hist_len = max(msk.size(), min(lit.length(), max_len));
lit_hist_len = lit_hist_len ? lit_hist_len - 1 : 0;
}
DEBUG_PRINTF("lit requires %zu bytes of history\n", lit_hist_len);
assert(lit_hist_len <= build.cc.grey.maxHistoryAvailable);
auto lit_final = lit; // copy
if (lit_final.length() > ROSE_SHORT_LITERAL_LEN_MAX) {
DEBUG_PRINTF("truncating to tail of length %zu\n",
size_t{ROSE_SHORT_LITERAL_LEN_MAX});
lit_final.erase(0, lit_final.length() - ROSE_SHORT_LITERAL_LEN_MAX);
// We shouldn't have set a threshold below 8 chars.
assert(msk.size() <= ROSE_SHORT_LITERAL_LEN_MAX);
assert(!noruns);
}
const auto &s = lit_final.get_string();
bool nocase = lit_final.any_nocase();
DEBUG_PRINTF("id=%u, s='%s', nocase=%d, noruns=%d, msk=%s, "
"cmp=%s\n",
info.fragment_id, escapeString(s).c_str(), (int)nocase,
noruns, dumpMask(msk).c_str(), dumpMask(cmp).c_str());
if (!maskIsConsistent(s, nocase, msk, cmp)) {
DEBUG_PRINTF("msk/cmp for literal can't match, skipping\n");
continue;
}
mp.accel_lits.emplace_back(lit.get_string(), lit.any_nocase(), msk, cmp,
info.group_mask);
mp.history_required = max(mp.history_required, lit_hist_len);
assert(info.fragment_id < build.fragments.size());
const auto &frag = build.fragments.at(info.fragment_id);
u32 prog_offset =
delay_rebuild ? frag.delay_program_offset : frag.lit_program_offset;
const auto &groups = frag.groups;
mp.lits.emplace_back(move(s), nocase, noruns, prog_offset, groups, msk,
cmp);
}
sort_and_unique(mp.lits);
@ -809,14 +806,15 @@ void buildAccel(const RoseBuildImpl &build, const MatcherProto &mp,
}
aligned_unique_ptr<HWLM>
buildFloatingMatcher(const RoseBuildImpl &build, size_t longLitLengthThreshold,
rose_group *fgroups, size_t *fsize,
size_t *historyRequired) {
buildFloatingMatcher(const RoseBuildImpl &build,
const vector<LitFragment> &fragments,
size_t longLitLengthThreshold, rose_group *fgroups,
size_t *fsize, size_t *historyRequired) {
*fsize = 0;
*fgroups = 0;
auto mp =
makeMatcherProto(build, ROSE_FLOATING, false, longLitLengthThreshold);
auto mp = makeMatcherProto(build, fragments, ROSE_FLOATING, false,
longLitLengthThreshold);
if (mp.lits.empty()) {
DEBUG_PRINTF("empty floating matcher\n");
return nullptr;
@ -847,6 +845,7 @@ buildFloatingMatcher(const RoseBuildImpl &build, size_t longLitLengthThreshold,
}
aligned_unique_ptr<HWLM> buildDelayRebuildMatcher(const RoseBuildImpl &build,
const vector<LitFragment> &fragments,
size_t longLitLengthThreshold,
size_t *drsize) {
*drsize = 0;
@ -856,8 +855,8 @@ aligned_unique_ptr<HWLM> buildDelayRebuildMatcher(const RoseBuildImpl &build,
return nullptr;
}
auto mp =
makeMatcherProto(build, ROSE_FLOATING, true, longLitLengthThreshold);
auto mp = makeMatcherProto(build, fragments, ROSE_FLOATING, true,
longLitLengthThreshold);
if (mp.lits.empty()) {
DEBUG_PRINTF("empty delay rebuild matcher\n");
return nullptr;
@ -877,8 +876,9 @@ aligned_unique_ptr<HWLM> buildDelayRebuildMatcher(const RoseBuildImpl &build,
return hwlm;
}
aligned_unique_ptr<HWLM> buildSmallBlockMatcher(const RoseBuildImpl &build,
size_t *sbsize) {
aligned_unique_ptr<HWLM>
buildSmallBlockMatcher(const RoseBuildImpl &build,
const vector<LitFragment> &fragments, size_t *sbsize) {
*sbsize = 0;
if (build.cc.streaming) {
@ -893,7 +893,7 @@ aligned_unique_ptr<HWLM> buildSmallBlockMatcher(const RoseBuildImpl &build,
return nullptr;
}
auto mp = makeMatcherProto(build, ROSE_FLOATING, false,
auto mp = makeMatcherProto(build, fragments, ROSE_FLOATING, false,
ROSE_SMALL_BLOCK_LEN, ROSE_SMALL_BLOCK_LEN);
if (mp.lits.empty()) {
DEBUG_PRINTF("no floating table\n");
@ -903,9 +903,10 @@ aligned_unique_ptr<HWLM> buildSmallBlockMatcher(const RoseBuildImpl &build,
return nullptr;
}
auto mp_anchored =
makeMatcherProto(build, ROSE_ANCHORED_SMALL_BLOCK, false,
ROSE_SMALL_BLOCK_LEN, ROSE_SMALL_BLOCK_LEN);
auto mp_anchored = makeMatcherProto(build, fragments,
ROSE_ANCHORED_SMALL_BLOCK, false,
ROSE_SMALL_BLOCK_LEN,
ROSE_SMALL_BLOCK_LEN);
if (mp_anchored.lits.empty()) {
DEBUG_PRINTF("no small-block anchored literals\n");
return nullptr;
@ -937,11 +938,12 @@ aligned_unique_ptr<HWLM> buildSmallBlockMatcher(const RoseBuildImpl &build,
return hwlm;
}
aligned_unique_ptr<HWLM> buildEodAnchoredMatcher(const RoseBuildImpl &build,
size_t *esize) {
aligned_unique_ptr<HWLM>
buildEodAnchoredMatcher(const RoseBuildImpl &build,
const vector<LitFragment> &fragments, size_t *esize) {
*esize = 0;
auto mp = makeMatcherProto(build, ROSE_EOD_ANCHORED, false,
auto mp = makeMatcherProto(build, fragments, ROSE_EOD_ANCHORED, false,
build.ematcher_region_size);
if (mp.lits.empty()) {

View File

@ -36,25 +36,45 @@
#include "rose_build_impl.h"
#include <vector>
struct Grey;
struct HWLM;
namespace ue2 {
struct LitFragment {
LitFragment(u32 fragment_id_in, rose_group groups_in, u32 lit_id)
: fragment_id(fragment_id_in), groups(groups_in), lit_ids({lit_id}) {}
LitFragment(u32 fragment_id_in, rose_group groups_in,
std::vector<u32> lit_ids_in)
: fragment_id(fragment_id_in), groups(groups_in),
lit_ids(std::move(lit_ids_in)) {}
u32 fragment_id;
rose_group groups;
std::vector<u32> lit_ids;
u32 lit_program_offset = ROSE_INVALID_PROG_OFFSET;
u32 delay_program_offset = ROSE_INVALID_PROG_OFFSET;
};
aligned_unique_ptr<HWLM> buildFloatingMatcher(const RoseBuildImpl &build,
const std::vector<LitFragment> &fragments,
size_t longLitLengthThreshold,
rose_group *fgroups,
size_t *fsize,
size_t *historyRequired);
aligned_unique_ptr<HWLM> buildDelayRebuildMatcher(const RoseBuildImpl &build,
const std::vector<LitFragment> &fragments,
size_t longLitLengthThreshold,
size_t *drsize);
aligned_unique_ptr<HWLM> buildSmallBlockMatcher(const RoseBuildImpl &build,
const std::vector<LitFragment> &fragments,
size_t *sbsize);
aligned_unique_ptr<HWLM> buildEodAnchoredMatcher(const RoseBuildImpl &build,
const std::vector<LitFragment> &fragments,
size_t *esize);
void findMoreLiteralMasks(RoseBuildImpl &build);

View File

@ -450,8 +450,7 @@ void RoseInstrSparseIterBegin::write(void *dest, RoseEngineBlob &blob,
jump_offsets.push_back(offset_map.at(jump.second));
}
vector<mmbit_sparse_iter> iter;
mmbBuildSparseIterator(iter, keys, num_keys);
auto iter = mmbBuildSparseIterator(keys, num_keys);
assert(!iter.empty());
inst->iter_offset = blob.add_iterator(iter);
inst->jump_table = blob.add(jump_offsets.begin(), jump_offsets.end());
@ -485,8 +484,7 @@ void RoseInstrSparseIterAny::write(void *dest, RoseEngineBlob &blob,
inst->fail_jump = calc_jump(offset_map, this, target);
// Write the multibit sparse iterator.
vector<mmbit_sparse_iter> iter;
mmbBuildSparseIterator(iter, keys, num_keys);
auto iter = mmbBuildSparseIterator(keys, num_keys);
assert(!iter.empty());
inst->iter_offset = blob.add_iterator(iter);
}

View File

@ -155,9 +155,9 @@ void bfs(vector<mmbit_sparse_iter> &out, const TreeNode &tree) {
/** \brief Construct a sparse iterator over the values in \a bits for a
* multibit of size \a total_bits. */
void mmbBuildSparseIterator(vector<mmbit_sparse_iter> &out,
const vector<u32> &bits, u32 total_bits) {
assert(out.empty());
vector<mmbit_sparse_iter> mmbBuildSparseIterator(const vector<u32> &bits,
u32 total_bits) {
vector<mmbit_sparse_iter> out;
assert(!bits.empty());
assert(total_bits > 0);
assert(total_bits <= MMB_MAX_BITS);
@ -186,6 +186,7 @@ void mmbBuildSparseIterator(vector<mmbit_sparse_iter> &out,
#endif
DEBUG_PRINTF("iter has %zu records\n", out.size());
return out;
}
template<typename T>

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015-2016, Intel Corporation
* Copyright (c) 2015-2017, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@ -61,8 +61,8 @@ u32 mmbit_size(u32 total_bits);
/** \brief Construct a sparse iterator over the values in \a bits for a
* multibit of size \a total_bits. */
void mmbBuildSparseIterator(std::vector<mmbit_sparse_iter> &out,
const std::vector<u32> &bits, u32 total_bits);
std::vector<mmbit_sparse_iter>
mmbBuildSparseIterator(const std::vector<u32> &bits, u32 total_bits);
struct scatter_plan_raw;

View File

@ -782,7 +782,6 @@ TEST_P(MultiBitTest, InitRangePlanChunked) {
TEST(MultiBit, SparseIteratorBegin1) {
const u32 test_size = 100;
vector<mmbit_sparse_iter> it;
vector<u32> bits;
bits.push_back(1);
@ -791,7 +790,7 @@ TEST(MultiBit, SparseIteratorBegin1) {
bits.push_back(35);
bits.push_back(68);
mmbBuildSparseIterator(it, bits, test_size);
auto it = mmbBuildSparseIterator(bits, test_size);
//ASSERT_EQ(4U, it.size());
// Trivial initial test: all bits in 'bits' are on, all others are off
@ -820,7 +819,6 @@ TEST(MultiBit, SparseIteratorBegin1) {
TEST(MultiBit, SparseIteratorBegin2) {
const u32 test_size = 40000;
vector<mmbit_sparse_iter> it;
vector<u32> bits;
bits.push_back(1);
@ -830,7 +828,7 @@ TEST(MultiBit, SparseIteratorBegin2) {
bits.push_back(8920);
bits.push_back(37000);
mmbBuildSparseIterator(it, bits, test_size);
auto it = mmbBuildSparseIterator(bits, test_size);
//ASSERT_EQ(12U, it.size());
// Trivial initial test: all bits in 'bits' are on, all others are off
@ -859,7 +857,6 @@ TEST(MultiBit, SparseIteratorBegin2) {
TEST(MultiBit, SparseIteratorNext1) {
const u32 test_size = 100;
vector<mmbit_sparse_iter> it;
vector<u32> bits;
bits.push_back(1);
@ -868,7 +865,7 @@ TEST(MultiBit, SparseIteratorNext1) {
bits.push_back(35);
bits.push_back(68);
mmbBuildSparseIterator(it, bits, test_size);
auto it = mmbBuildSparseIterator(bits, test_size);
// Trivial initial test: all bits in 'bits' are on, all others are off
mmbit_holder ba(test_size);
@ -924,7 +921,6 @@ TEST(MultiBit, SparseIteratorNext1) {
TEST(MultiBit, SparseIteratorNext2) {
const u32 test_size = 40000;
vector<mmbit_sparse_iter> it;
vector<u32> bits;
bits.push_back(1);
@ -939,7 +935,7 @@ TEST(MultiBit, SparseIteratorNext2) {
bits.push_back(37000);
bits.push_back(39999);
mmbBuildSparseIterator(it, bits, test_size);
auto it = mmbBuildSparseIterator(bits, test_size);
// Trivial initial test: all bits in 'bits' are on, all others are off
mmbit_holder ba(test_size);
@ -995,7 +991,6 @@ TEST(MultiBit, SparseIteratorNext2) {
TEST(MultiBit, SparseIteratorNextSmall) {
const u32 test_size = 15;
vector<mmbit_sparse_iter> it;
vector<u32> bits;
bits.push_back(1);
@ -1005,7 +1000,7 @@ TEST(MultiBit, SparseIteratorNextSmall) {
bits.push_back(12);
bits.push_back(14);
mmbBuildSparseIterator(it, bits, test_size);
auto it = mmbBuildSparseIterator(bits, test_size);
// Trivial initial test: all bits in 'bits' are on, all others are off
mmbit_holder ba(test_size);
@ -1064,13 +1059,12 @@ TEST_P(MultiBitTest, SparseIteratorBeginAll) {
ASSERT_TRUE(ba != nullptr);
// Put all our bits into the sparse iterator.
vector<mmbit_sparse_iter> it;
vector<u32> bits;
bits.reserve(test_size / stride);
for (u64a i = 0; i < test_size; i += stride) {
bits.push_back(i);
}
mmbBuildSparseIterator(it, bits, test_size);
auto it = mmbBuildSparseIterator(bits, test_size);
// Switch all bits on in state.
mmbit_clear(ba, test_size);
@ -1104,12 +1098,11 @@ TEST_P(MultiBitTest, SparseIteratorBeginThirds) {
}
// Put all our bits into the sparse iterator
vector<mmbit_sparse_iter> it;
vector<u32> bits(test_size);
for (u32 i = 0; i != test_size; i++) {
bits[i] = i;
}
mmbBuildSparseIterator(it, bits, test_size);
auto it = mmbBuildSparseIterator(bits, test_size);
// Switch every third bits on in state
mmbit_clear(ba, test_size);
@ -1139,13 +1132,12 @@ TEST_P(MultiBitTest, SparseIteratorNextAll) {
ASSERT_TRUE(ba != nullptr);
// Put all our bits into the sparse iterator.
vector<mmbit_sparse_iter> it;
vector<u32> bits;
bits.reserve(test_size / stride);
for (u64a i = 0; i < test_size; i += stride) {
bits.push_back(i);
}
mmbBuildSparseIterator(it, bits, test_size);
auto it = mmbBuildSparseIterator(bits, test_size);
// Switch all bits on in state
mmbit_clear(ba, test_size);
@ -1182,14 +1174,13 @@ TEST_P(MultiBitTest, SparseIteratorNextExactStrided) {
// Put all our bits into the sparse iterator and switch them on in the
// state.
mmbit_clear(ba, test_size);
vector<mmbit_sparse_iter> it;
vector<u32> bits;
bits.reserve(test_size / stride);
for (u64a i = 0; i < test_size; i += stride) {
bits.push_back(i);
mmbit_set(ba, test_size, i);
}
mmbBuildSparseIterator(it, bits, test_size);
auto it = mmbBuildSparseIterator(bits, test_size);
// Iterate over all bits.
vector<mmbit_sparse_state> state(mmbit_sparse_iter_state_size(test_size));
@ -1214,13 +1205,12 @@ TEST_P(MultiBitTest, SparseIteratorNextNone) {
ASSERT_TRUE(ba != nullptr);
// Put all our bits into the sparse iterator.
vector<mmbit_sparse_iter> it;
vector<u32> bits;
bits.reserve(test_size / stride);
for (u64a i = 0; i < test_size; i += stride) {
bits.push_back(i);
}
mmbBuildSparseIterator(it, bits, test_size);
auto it = mmbBuildSparseIterator(bits, test_size);
// Switch only the first bit on
mmbit_clear(ba, test_size);
@ -1243,13 +1233,12 @@ TEST_P(MultiBitTest, SparseIteratorUnsetAll) {
ASSERT_TRUE(ba != nullptr);
// Put all our bits into the sparse iterator
vector<mmbit_sparse_iter> it;
vector<u32> bits;
bits.reserve(test_size / stride);
for (u64a i = 0; i < test_size; i += stride) {
bits.push_back(i);
}
mmbBuildSparseIterator(it, bits, test_size);
auto it = mmbBuildSparseIterator(bits, test_size);
// Switch all bits on
mmbit_clear(ba, test_size);
@ -1283,9 +1272,8 @@ TEST_P(MultiBitTest, SparseIteratorUnsetHalves) {
odd.push_back(i);
}
vector<mmbit_sparse_iter> it_even, it_odd;
mmbBuildSparseIterator(it_even, even, test_size);
mmbBuildSparseIterator(it_odd, odd, test_size);
auto it_even = mmbBuildSparseIterator(even, test_size);
auto it_odd = mmbBuildSparseIterator(odd, test_size);
// Switch all bits on
mmbit_clear(ba, test_size);