/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2020, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*/
static constexpr u32 NO_STATE = ~0;
+/* Maximum number of states taken as a small NFA */
+static constexpr u32 MAX_SMALL_NFA_STATES = 64;
+
+/* Maximum bounded repeat upper bound to consider as a fast NFA */
+static constexpr u64a MAX_REPEAT_SIZE = 200;
+
+/* Maximum bounded repeat char reach size to consider as a fast NFA */
+static constexpr u32 MAX_REPEAT_CHAR_REACH = 26;
+
+/* Minimum bounded repeat trigger distance to consider as a fast NFA */
+static constexpr u8 MIN_REPEAT_TRIGGER_DISTANCE = 6;
+
namespace {
struct precalcAccel {
}
#endif // NDEBUG
+static
+bool isFast(const build_info &args) {
+ const NGHolder &h = args.h;
+ const u32 num_states = args.num_states;
+
+ if (num_states > MAX_SMALL_NFA_STATES) {
+ return false;
+ }
+
+ unordered_map<NFAVertex, bool> pos_trigger;
+ for (u32 i = 0; i < args.repeats.size(); i++) {
+ const BoundedRepeatData &br = args.repeats[i];
+ assert(!contains(pos_trigger, br.pos_trigger));
+ pos_trigger[br.pos_trigger] = br.repeatMax <= MAX_REPEAT_SIZE;
+ }
+
+ // Small NFA without bounded repeat should be fast.
+ if (pos_trigger.empty()) {
+ return true;
+ }
+
+ vector<NFAVertex> cur;
+ unordered_set<NFAVertex> visited;
+ for (const auto &m : args.tops) {
+ for (NFAVertex v : m.second) {
+ cur.push_back(v);
+ visited.insert(v);
+ }
+ }
+
+ u8 pos_dist = 0;
+ while (!cur.empty()) {
+ vector<NFAVertex> next;
+ for (const auto &v : cur) {
+ if (contains(pos_trigger, v)) {
+ const CharReach &cr = h[v].char_reach;
+ if (!pos_trigger[v] && cr.count() > MAX_REPEAT_CHAR_REACH) {
+ return false;
+ }
+ }
+ for (const auto &w : adjacent_vertices_range(v, h)) {
+ if (w == v) {
+ continue;
+ }
+ u32 j = args.state_ids.at(w);
+ if (j == NO_STATE) {
+ continue;
+ }
+ if (!contains(visited, w)) {
+ next.push_back(w);
+ visited.insert(w);
+ }
+ }
+ }
+ if (++pos_dist >= MIN_REPEAT_TRIGGER_DISTANCE) {
+ break;
+ }
+ swap(cur, next);
+ }
+ return true;
+}
+
static
u32 max_state(const unordered_map<NFAVertex, u32> &state_ids) {
u32 rv = 0;
const unordered_map<NFAVertex, NFAStateSet> &squashMap,
const map<u32, set<NFAVertex>> &tops,
const set<NFAVertex> &zombies, bool do_accel,
- bool stateCompression, u32 hint,
+ bool stateCompression, bool &fast, u32 hint,
const CompileContext &cc) {
const u32 num_states = max_state(states) + 1;
DEBUG_PRINTF("total states: %u\n", num_states);
if (nfa) {
DEBUG_PRINTF("successful build with NFA engine: %s\n",
nfa_type_name(limex_model));
+ fast = isFast(arg);
return nfa;
}
}
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2020, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
const std::set<NFAVertex> &zombies,
bool do_accel,
bool stateCompression,
+ bool &fast,
u32 hint,
const CompileContext &cc);
static const nfa_dispatch_fn has_repeats_other_than_firsts; \
static const u32 stateAlign = \
MAX(mlt_align, alignof(RepeatControl)); \
- static const bool fast = mlt_size <= 64; \
}; \
const nfa_dispatch_fn NFATraits<LIMEX_NFA_##mlt_size>::has_accel \
= has_accel_limex<LimExNFA##mlt_size>; \
UNUSED static const char *name;
static const NFACategory category = NFA_OTHER;
static const u32 stateAlign = 1;
- static const bool fast = true;
static const nfa_dispatch_fn has_accel;
static const nfa_dispatch_fn has_repeats;
static const nfa_dispatch_fn has_repeats_other_than_firsts;
UNUSED static const char *name;
static const NFACategory category = NFA_OTHER;
static const u32 stateAlign = 2;
- static const bool fast = true;
static const nfa_dispatch_fn has_accel;
static const nfa_dispatch_fn has_repeats;
static const nfa_dispatch_fn has_repeats_other_than_firsts;
UNUSED static const char *name;
static const NFACategory category = NFA_OTHER;
static const u32 stateAlign = 8;
- static const bool fast = true;
static const nfa_dispatch_fn has_accel;
static const nfa_dispatch_fn has_repeats;
static const nfa_dispatch_fn has_repeats_other_than_firsts;
UNUSED static const char *name;
static const NFACategory category = NFA_OTHER;
static const u32 stateAlign = 8;
- static const bool fast = true;
static const nfa_dispatch_fn has_accel;
static const nfa_dispatch_fn has_repeats;
static const nfa_dispatch_fn has_repeats_other_than_firsts;
UNUSED static const char *name;
static const NFACategory category = NFA_OTHER;
static const u32 stateAlign = 8;
- static const bool fast = true;
static const nfa_dispatch_fn has_accel;
static const nfa_dispatch_fn has_repeats;
static const nfa_dispatch_fn has_repeats_other_than_firsts;
UNUSED static const char *name;
static const NFACategory category = NFA_OTHER;
static const u32 stateAlign = 8;
- static const bool fast = true;
static const nfa_dispatch_fn has_accel;
static const nfa_dispatch_fn has_repeats;
static const nfa_dispatch_fn has_repeats_other_than_firsts;
UNUSED static const char *name;
static const NFACategory category = NFA_OTHER;
static const u32 stateAlign = 8;
- static const bool fast = true;
static const nfa_dispatch_fn has_accel;
static const nfa_dispatch_fn has_repeats;
static const nfa_dispatch_fn has_repeats_other_than_firsts;
UNUSED static const char *name;
static const NFACategory category = NFA_OTHER;
static const u32 stateAlign = 8;
- static const bool fast = true;
static const nfa_dispatch_fn has_accel;
static const nfa_dispatch_fn has_repeats;
static const nfa_dispatch_fn has_repeats_other_than_firsts;
UNUSED static const char *name;
static const NFACategory category = NFA_OTHER;
static const u32 stateAlign = 8;
- static const bool fast = true;
static const nfa_dispatch_fn has_accel;
static const nfa_dispatch_fn has_repeats;
static const nfa_dispatch_fn has_repeats_other_than_firsts;
UNUSED static const char *name;
static const NFACategory category = NFA_OTHER;
static const u32 stateAlign = 8;
- static const bool fast = true;
static const nfa_dispatch_fn has_accel;
static const nfa_dispatch_fn has_repeats;
static const nfa_dispatch_fn has_repeats_other_than_firsts;
UNUSED static const char *name;
static const NFACategory category = NFA_OTHER;
static const u32 stateAlign = 8;
- static const bool fast = true;
static const nfa_dispatch_fn has_accel;
static const nfa_dispatch_fn has_repeats;
static const nfa_dispatch_fn has_repeats_other_than_firsts;
UNUSED static const char *name;
static const NFACategory category = NFA_OTHER;
static const u32 stateAlign = 1;
- static const bool fast = true;
static const nfa_dispatch_fn has_accel;
static const nfa_dispatch_fn has_repeats;
static const nfa_dispatch_fn has_repeats_other_than_firsts;
UNUSED static const char *name;
static const NFACategory category = NFA_OTHER;
static const u32 stateAlign = 64;
- static const bool fast = true;
static const nfa_dispatch_fn has_accel;
static const nfa_dispatch_fn has_repeats;
static const nfa_dispatch_fn has_repeats_other_than_firsts;
UNUSED static const char *name;
static const NFACategory category = NFA_OTHER;
static const u32 stateAlign = 1;
- static const bool fast = true;
static const nfa_dispatch_fn has_accel;
static const nfa_dispatch_fn has_repeats;
static const nfa_dispatch_fn has_repeats_other_than_firsts;
UNUSED static const char *name;
static const NFACategory category = NFA_OTHER;
static const u32 stateAlign = 2;
- static const bool fast = true;
static const nfa_dispatch_fn has_accel;
static const nfa_dispatch_fn has_repeats;
static const nfa_dispatch_fn has_repeats_other_than_firsts;
UNUSED static const char *name;
static const NFACategory category = NFA_OTHER;
static const u32 stateAlign = 1;
- static const bool fast = true;
static const nfa_dispatch_fn has_accel;
static const nfa_dispatch_fn has_repeats;
static const nfa_dispatch_fn has_repeats_other_than_firsts;
UNUSED static const char *name;
static const NFACategory category = NFA_OTHER;
static const u32 stateAlign = 1;
- static const bool fast = true;
static const nfa_dispatch_fn has_accel;
static const nfa_dispatch_fn has_repeats;
static const nfa_dispatch_fn has_repeats_other_than_firsts;
UNUSED static const char *name;
static const NFACategory category = NFA_OTHER;
static const u32 stateAlign = 1;
- static const bool fast = true;
static const nfa_dispatch_fn has_accel;
static const nfa_dispatch_fn has_repeats;
static const nfa_dispatch_fn has_repeats_other_than_firsts;
UNUSED static const char *name;
static const NFACategory category = NFA_OTHER;
static const u32 stateAlign = 2;
- static const bool fast = true;
static const nfa_dispatch_fn has_accel;
static const nfa_dispatch_fn has_repeats;
static const nfa_dispatch_fn has_repeats_other_than_firsts;
return DISPATCH_BY_NFA_TYPE((NFAEngineType)nfa.type, getStateAlign, nullptr);
}
-namespace {
-template<NFAEngineType t>
-struct getFastness {
- static u32 call(void *) {
- return NFATraits<t>::fast;
- }
-};
-}
-
-bool is_fast(const NFA &nfa) {
- NFAEngineType t = (NFAEngineType)nfa.type;
- return DISPATCH_BY_NFA_TYPE(t, getFastness, nullptr);
-}
-
namespace {
template<NFAEngineType t>
struct is_limex {
/*
- * Copyright (c) 2015, Intel Corporation
+ * Copyright (c) 2015-2020, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
// For a given NFA, retrieve the alignment required by its uncompressed state.
u32 state_alignment(const NFA &nfa);
-/* returns true if the nfa is considered 'fast'. TODO: work out what we mean by
- * fast. */
-bool is_fast(const NFA &n);
-
bool has_bounded_repeats_other_than_firsts(const NFA &n);
bool has_bounded_repeats(const NFA &n);
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2020, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
constructNFA(const NGHolder &h_in, const ReportManager *rm,
const map<u32, u32> &fixed_depth_tops,
const map<u32, vector<vector<CharReach>>> &triggers,
- bool compress_state, bool do_accel, bool impl_test_only, u32 hint,
- const CompileContext &cc) {
+ bool compress_state, bool do_accel, bool impl_test_only,
+ bool &fast, u32 hint, const CompileContext &cc) {
if (!has_managed_reports(h_in)) {
rm = nullptr;
} else {
}
return generate(*h, state_ids, repeats, reportSquashMap, squashMap, tops,
- zombies, do_accel, compress_state, hint, cc);
+ zombies, do_accel, compress_state, fast, hint, cc);
}
bytecode_ptr<NFA>
constructNFA(const NGHolder &h_in, const ReportManager *rm,
const map<u32, u32> &fixed_depth_tops,
const map<u32, vector<vector<CharReach>>> &triggers,
- bool compress_state, const CompileContext &cc) {
+ bool compress_state, bool &fast, const CompileContext &cc) {
const u32 hint = INVALID_NFA;
const bool do_accel = cc.grey.accelerateNFA;
const bool impl_test_only = false;
return constructNFA(h_in, rm, fixed_depth_tops, triggers, compress_state,
- do_accel, impl_test_only, hint, cc);
+ do_accel, impl_test_only, fast, hint, cc);
}
#ifndef RELEASE_BUILD
constructNFA(const NGHolder &h_in, const ReportManager *rm,
const map<u32, u32> &fixed_depth_tops,
const map<u32, vector<vector<CharReach>>> &triggers,
- bool compress_state, u32 hint, const CompileContext &cc) {
+ bool compress_state, bool &fast, u32 hint, const CompileContext &cc) {
const bool do_accel = cc.grey.accelerateNFA;
const bool impl_test_only = false;
- return constructNFA(h_in, rm, fixed_depth_tops, triggers,
- compress_state, do_accel, impl_test_only, hint, cc);
+ return constructNFA(h_in, rm, fixed_depth_tops, triggers, compress_state,
+ do_accel, impl_test_only, fast, hint, cc);
}
#endif // RELEASE_BUILD
vector<BoundedRepeatData> repeats;
unordered_map<NFAVertex, NFAStateSet> reportSquashMap;
unordered_map<NFAVertex, NFAStateSet> squashMap;
+ UNUSED bool fast = false;
return generate(h, state_ids, repeats, reportSquashMap, squashMap, tops,
- zombies, false, false, hint, cc);
+ zombies, false, false, fast, hint, cc);
}
bytecode_ptr<NFA> constructReversedNFA(const NGHolder &h_in,
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2020, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
constructNFA(const NGHolder &g, const ReportManager *rm,
const std::map<u32, u32> &fixed_depth_tops,
const std::map<u32, std::vector<std::vector<CharReach>>> &triggers,
- bool compress_state, const CompileContext &cc);
+ bool compress_state, bool &fast, const CompileContext &cc);
/**
* \brief Build a reverse NFA from the graph given, which should have already
constructNFA(const NGHolder &g, const ReportManager *rm,
const std::map<u32, u32> &fixed_depth_tops,
const std::map<u32, std::vector<std::vector<CharReach>>> &triggers,
- bool compress_state, u32 hint, const CompileContext &cc);
+ bool compress_state, bool &fast, u32 hint, const CompileContext &cc);
/**
* \brief Build a reverse NFA (with model type hint) from the graph given,
*/
static
bytecode_ptr<NFA> pickImpl(bytecode_ptr<NFA> dfa_impl,
- bytecode_ptr<NFA> nfa_impl) {
+ bytecode_ptr<NFA> nfa_impl,
+ bool fast_nfa) {
assert(nfa_impl);
assert(dfa_impl);
assert(isDfaType(dfa_impl->type));
return nfa_impl;
}
} else {
- if (n_accel) {
+ if (n_accel && fast_nfa) {
return nfa_impl;
} else {
return dfa_impl;
}
}
+ bool fast_nfa = false;
auto n = constructNFA(holder, &rm, fixed_depth_tops, triggers,
- compress_state, cc);
+ compress_state, fast_nfa, cc);
assert(n);
if (oneTop && cc.grey.roseMcClellanSuffix) {
if (cc.grey.roseMcClellanSuffix == 2 || n->nPositions > 128 ||
- !has_bounded_repeats_other_than_firsts(*n)) {
+ !has_bounded_repeats_other_than_firsts(*n) || !fast_nfa) {
auto rdfa = buildMcClellan(holder, &rm, false, triggers.at(0),
cc.grey);
if (rdfa) {
auto d = getDfa(*rdfa, false, cc, rm);
assert(d);
if (cc.grey.roseMcClellanSuffix != 2) {
- n = pickImpl(move(d), move(n));
+ n = pickImpl(move(d), move(n), fast_nfa);
} else {
n = move(d);
}
n = constructLBR(*left.graph(), triggers.begin()->second, cc, rm);
}
+ bool fast_nfa = false;
if (!n && left.graph()) {
map<u32, vector<vector<CharReach>>> triggers;
if (left.graph()->kind == NFA_INFIX) {
findTriggerSequences(tbi, infixTriggers.at(left), &triggers);
}
n = constructNFA(*left.graph(), nullptr, fixed_depth_tops, triggers,
- compress_state, cc);
+ compress_state, fast_nfa, cc);
}
if (cc.grey.roseMcClellanPrefix == 1 && is_prefix && !left.dfa()
&& left.graph()
- && (!n || !has_bounded_repeats_other_than_firsts(*n) || !is_fast(*n))) {
+ && (!n || !has_bounded_repeats_other_than_firsts(*n) || !fast_nfa)) {
auto rdfa = buildMcClellan(*left.graph(), nullptr, cc.grey);
if (rdfa) {
auto d = getDfa(*rdfa, is_transient, cc, rm);
assert(d);
- n = pickImpl(move(d), move(n));
+ n = pickImpl(move(d), move(n), fast_nfa);
}
}
const map<u32, u32> fixed_depth_tops; /* no tops */
const map<u32, vector<vector<CharReach>>> triggers; /* no tops */
bool compress_state = cc.streaming;
+ bool fast_nfa = false;
auto n = constructNFA(h, &rm, fixed_depth_tops, triggers,
- compress_state, cc);
+ compress_state, fast_nfa, cc);
// Try for a DFA upgrade.
if (n && cc.grey.roseMcClellanOutfix &&
- !has_bounded_repeats_other_than_firsts(*n)) {
+ (!has_bounded_repeats_other_than_firsts(*n) || !fast_nfa)) {
auto rdfa = buildMcClellan(h, &rm, cc.grey);
if (rdfa) {
auto d = getDfa(*rdfa, false, cc, rm);
if (d) {
- n = pickImpl(move(d), move(n));
+ n = pickImpl(move(d), move(n), fast_nfa);
}
}
}
/*
- * Copyright (c) 2015-2017, Intel Corporation
+ * Copyright (c) 2015-2020, Intel Corporation
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
const map<u32, u32> fixed_depth_tops;
const map<u32, vector<vector<CharReach>>> triggers;
bool compress_state = false;
+ bool fast_nfa = false;
nfa = constructNFA(*g, &rm, fixed_depth_tops, triggers, compress_state,
- type, cc);
+ fast_nfa, type, cc);
ASSERT_TRUE(nfa != nullptr);
full_state = make_bytecode_ptr<char>(nfa->scratchStateSize, 64);
const map<u32, u32> fixed_depth_tops;
const map<u32, vector<vector<CharReach>>> triggers;
bool compress_state = false;
+ bool fast_nfa = false;
nfa = constructNFA(*g, &rm, fixed_depth_tops, triggers, compress_state,
- type, cc);
+ fast_nfa, type, cc);
ASSERT_TRUE(nfa != nullptr);
full_state = make_bytecode_ptr<char>(nfa->scratchStateSize, 64);