[apparmor] [patch] Add Differential State Compression to the DFA
Seth Arnold
seth.arnold at canonical.com
Sat Dec 14 05:37:27 UTC 2013
On Tue, Dec 10, 2013 at 06:38:51AM -0800, John Johansen wrote:
> This is a slightly updated (to apply against current dev) version of the
> differential compression patch.
>
> Differential state compression encodes a state's transitions as the
> difference between the state and its default state (the state it is
> relative too).
> [...]
> Signed-off-by: John Johansen <john.johansen at canonical.com>
Impressive; I think I understood very nearly all of it, thanks for the
copius documentation, comments, and above-all, clear code, though I'm
afraid I haven't yet figured out if this requires kernel modifications to
support the differential compression.
I have some questions inline.
With the caveat that I haven't looked at how well the _other_ code
will handle this, only the code in this patch:
Acked-by: Seth Arnold <seth.arnold at canonical.com>
> === modified file 'parser/libapparmor_re/aare_rules.cc'
> --- parser/libapparmor_re/aare_rules.cc 2013-10-14 21:36:05 +0000
> +++ parser/libapparmor_re/aare_rules.cc 2013-12-10 13:24:18 +0000
> @@ -315,6 +315,13 @@
> } else if (flags & DFA_DUMP_EQUIV)
> cerr << "\nDFA did not generate an equivalence class\n";
>
> + if (flags & DFA_CONTROL_DIFF_ENCODE) {
> + dfa.diff_encode(flags);
> +
> + if (flags & DFA_DUMP_DIFF_ENCODE)
> + dfa.dump_diff_encode(cerr);
> + }
> +
> CHFA chfa(dfa, eq, flags);
> if (flags & DFA_DUMP_TRANS_TABLE)
> chfa.dump(cerr);
>
> === modified file 'parser/libapparmor_re/apparmor_re.h'
> --- parser/libapparmor_re/apparmor_re.h 2013-09-27 23:13:22 +0000
> +++ parser/libapparmor_re/apparmor_re.h 2013-12-10 13:27:08 +0000
> @@ -31,7 +31,11 @@
> #define DFA_CONTROL_FILTER_DENY (1 << 6)
> #define DFA_CONTROL_REMOVE_UNREACHABLE (1 << 7)
> #define DFA_CONTROL_TRANS_HIGH (1 << 8)
> +#define DFA_CONTROL_DIFF_ENCODE (1 << 9)
>
> +#define DFA_DUMP_DIFF_PROGRESS (1 << 10)
> +#define DFA_DUMP_DIFF_ENCODE (1 << 11)
> +#define DFA_DUMP_DIFF_STATS (1 << 12)
> #define DFA_DUMP_MIN_PARTS (1 << 13)
> #define DFA_DUMP_UNIQ_PERMS (1 << 14)
> #define DFA_DUMP_MIN_UNIQ_PERMS (1 << 15)
>
> === modified file 'parser/libapparmor_re/chfa.cc'
> --- parser/libapparmor_re/chfa.cc 2012-02-24 12:21:59 +0000
> +++ parser/libapparmor_re/chfa.cc 2013-12-10 14:26:52 +0000
> @@ -32,6 +32,7 @@
> #include "hfa.h"
> #include "chfa.h"
> #include "../immunix.h"
> +#include "flex-tables.h"
>
> void CHFA::init_free_list(vector<pair<size_t, size_t> > &free_list,
> size_t prev, size_t start)
> @@ -53,6 +54,11 @@
> if (flags & DFA_DUMP_TRANS_PROGRESS)
> fprintf(stderr, "Compressing HFA:\r");
>
> + if (dfa.diffcount)
> + flags = YYTH_FLAG_DIFF_ENCODE;
> + else
> + flags = 0;
> +
> if (eq.empty())
> max_eq = 255;
> else {
> @@ -242,6 +248,8 @@
> }
>
> do_insert:
> + if (from->flags & DiffEncodeFlag)
> + base |= DiffEncodeBit32;
> default_base.push_back(make_pair(default_state, base));
> }
>
> @@ -279,7 +287,7 @@
> << *next_check[i].second << " -> "
> << *next_check[i].first << ": ";
>
> - size_t offs = i - default_base[num[next_check[i].second]].second;
> + size_t offs = i - base_mask_size(default_base[num[next_check[i].second]].second);
> if (eq.size())
> os << offs;
> else
> @@ -296,7 +304,6 @@
> * (Only the -Cf and -Ce formats are currently supported.)
> */
>
> -#include "flex-tables.h"
> #define YYTH_REGEX_MAGIC 0x1B5E783D
>
> static inline size_t pad64(size_t i)
> @@ -395,6 +402,7 @@
>
> size_t hsize = pad64(sizeof(th) + sizeof(th_version) + strlen(name) + 1);
> th.th_magic = htonl(YYTH_REGEX_MAGIC);
> + th.th_flags = htonl(flags);
> th.th_hsize = htonl(hsize);
> th.th_ssize = htonl(hsize +
> flex_table_size(accept.begin(), accept.end()) +
>
> === modified file 'parser/libapparmor_re/chfa.h'
> --- parser/libapparmor_re/chfa.h 2012-02-24 12:21:59 +0000
> +++ parser/libapparmor_re/chfa.h 2013-12-10 14:19:05 +0000
> @@ -26,6 +26,10 @@
>
> #include "hfa.h"
>
> +#define BASE32_FLAGS 0xff000000
> +#define DiffEncodeBit32 0x80000000
> +#define base_mask_size(X) ((X) & ~BASE32_FLAGS)
> +
I know with only one use it's not a big deal, but I do prefer macros in
upper-case.
> using namespace std;
>
> class CHFA {
> @@ -51,6 +55,7 @@
> map<uchar, uchar> &eq;
> uchar max_eq;
> size_t first_free;
> + unsigned int flags;
> };
>
> #endif /* __LIBAA_RE_CHFA_H */
>
> === modified file 'parser/libapparmor_re/flex-tables.h'
> --- parser/libapparmor_re/flex-tables.h 2010-11-09 21:39:18 +0000
> +++ parser/libapparmor_re/flex-tables.h 2013-12-10 14:17:09 +0000
> @@ -5,6 +5,7 @@
> #include <stdint.h>
>
> #define YYTH_MAGIC 0xF13C57B1
> +#define YYTH_FLAG_DIFF_ENCODE 1
>
> struct table_set_header {
> uint32_t th_magic; /* TH_MAGIC */
>
> === modified file 'parser/libapparmor_re/hfa.cc'
> --- parser/libapparmor_re/hfa.cc 2012-05-30 21:31:41 +0000
> +++ parser/libapparmor_re/hfa.cc 2013-12-10 14:06:00 +0000
> @@ -73,6 +73,194 @@
> return os;
> }
>
> +/**
> + * diff_weight - Find differential compression distance between @rel and @this
> + * @rel: State to compare too
> + * Returns: An integer indicating how good rel is as a base, larger == better
> + *
> + * Find the relative weighted difference for differential state compression
> + * with queried state being compressed against @rel
> + *
> + * +1 for each transition that matches (char and dest - saves a transition)
> + * 0 for each transition that doesn't match and exists in both states
> + * 0 for transition that self has and @other doesn't (no extra required)
> + * -1 for each transition that is in @rel and not in @this (have to override)
> + *
> + * @rel should not be a state that has already been made differential or it may
> + * introduce extra transitions as it does not recurse to find all transitions
> + *
> + * Should be applied after state minimization
> +*/
> +int State::diff_weight(State *rel)
> +{
> + int weight = 0;
> +
> + if (this == rel)
> + return 0;
> +
> + if (rel->diff->rel) {
> + /* Can only be diff encoded against states that are relative
> + * to a state of a lower depth. ie, at most one sibling in
> + * the chain
> + */
> + if (rel->diff->rel->diff->depth >= this->diff->depth)
> + return 0;
> + } else if (rel->diff->depth >= this->diff->depth)
> + return 0;
> +
> + if (rel->flags & DiffEncodeFlag) {
> + for (uchar i = 0; i < 256; i++) {
I think I'd rather see this as a standard 'int' or 'unsigned int'; '256'
isn't expressible as an unsigned char, so every i < 256 will involve the
usual integer promotion rules. Might as well just make 'i' an integer and
avoid the whole thing. :)
> + State *state = rel->next(i);
> + StateTrans::iterator j = trans.find(i);
> + if (j != trans.end()) {
> + if (state == j->second)
> + weight++;
> + /* else
> + 0 - keep transition to mask
> + */
> + } else if (state == otherwise) {
> + /* 0 - match of default against @rel
> + * We don't save a transition but don't have
> + * to mask either
> + */
> + } else {
> + /* @rel has transition not covered by @this.
> + * Need to add a transition to mask it
> + */
> + weight--;
> + }
> + }
> + return weight;
> + }
> +
> + unsigned int count = 0;
> + for (StateTrans::iterator i = rel->trans.begin(); i != rel->trans.end();
> + i++) {
> + StateTrans::iterator j = trans.find(i->first);
> + if (j != trans.end()) {
> + if (i->second == j->second)
> + weight++;
> + /* } else {
> + 0 - keep transition to mask
> + */
> + count++;
> + } else if (i->second == otherwise) {
> + /* 0 - match of default against @rel
> + * We don't save a transition but don't have to
> + * mask either
> + */
> + } else {
> + /* rel has transition not covered by @this. Need to
> + * add a transition to mask
> + */
> + weight--;
> + }
> + }
> +
> + /* cover transitions in @this but not in @rel */
> + unsigned int this_count = 0;
> + if (count < trans.size()) {
> + for (StateTrans::iterator i = trans.begin(); i != trans.end(); i++) {
> + StateTrans::iterator j = rel->trans.find(i->first);
> + if (j == rel->trans.end()) {
> + this_count++;
> + if (i->second == rel->otherwise)
> + /* replaced by rel->cases.otherwise */
> + weight++;
> + }
> + }
> + }
The previous two loops look like they are an O(M*log(N) + N*log(M)) operation
(assuming trans.find() is O(log(N)) operation) -- while in the long run,
this would be obviously better than an O(N^2) nested loops, I wonder if
the smaller amounts of data that I suspect will be involved here if the
simplicity of nested loops would go more quickly.
> + if (rel->otherwise != otherwise) {
> + /* rel default transitions have to be masked with transitions
> + * This covers all transitions not covered above
> + */
> + weight -= 256 - (rel->trans.size() + this_count);
> + }
> +
> + return weight;
> +}
> +
> +/**
> + * make_relative - Make this state relative to @rel
> + * @rel: state to make this state relative too
> + *
> + * @rel can be a relative (differentially compressed state)
> + */
> +int State::make_relative(State *rel)
> +{
> + int weight = 0;
> +
> + if (this == rel || !rel)
> + return 0;
> +
> + if (flags & DiffEncodeFlag)
> + return 0;
> +
> + flags |= DiffEncodeFlag;
> +
> + for (int i = 0; i < 256 ; i++) {
> + State *next = rel->next(i);
> +
> + StateTrans::iterator j = trans.find(i);
> + if (j != trans.end()) {
> + if (j->second == next) {
> + trans.erase(j);
> + weight++;
> + }
> + /* else keep transition to mask */
> + } else if (otherwise == next) {
> + /* do nothing, otherwise transition disappears when
> + * reassigned
> + */
> + } else {
> + /* need a new transition to mask those in lower state */
> + trans[i] = otherwise;
> + weight--;
> + }
> + }
> +
> + otherwise = rel;
> +
> + return weight;
> +}
> +
> +/**
> + * flatten_differential - remove differential encode from this state
> + */
> +void State::flatten_relative(void)
> +{
> + if (!(flags & DiffEncodeFlag))
> + return;
> +
> + map<State *, int> count;
> +
> + for (int i = 0; i < 256; i++)
> + count[next(i)] += 1;
> +
> + int j = 0;
> + State *def = next(0);
> + for (int i = 1; i < 256; i++) {
> + if (count[next(i)] > count[next(j)]) {
> + j = i;
> + def = next(i);
> + }
> + }
> +
> + for (int i = 0; i < 256; i++) {
> + if (trans.find(i) != trans.end()) {
> + if (trans[i] == def)
> + trans.erase(i);
> + } else {
> + if (trans[i] != def)
> + trans[i] = next(i);
> + }
> + }
> +
> + otherwise = def;
> + flags = flags & ~DiffEncodeFlag;
> +}
> +
> static void split_node_types(NodeSet *nodes, NodeSet **anodes, NodeSet **nnodes
> )
> {
> @@ -175,6 +363,7 @@
> DFA::DFA(Node *root, dfaflags_t flags): root(root)
> {
> int i = 0;
> + diffcount = 0; /* set by diff_encode */
>
> if (flags & DFA_DUMP_PROGRESS)
> fprintf(stderr, "Creating dfa:\r");
> @@ -606,6 +795,239 @@
> }
> }
>
> +
> +/* diff_encode helper functions */
> +static unsigned int add_to_dag(DiffDag *dag, State *state,
> + State *parent)
> +{
> + unsigned int rc = 0;
> + if (!state->diff) {
> + dag->rel = NULL;
> + if (parent)
> + dag->depth = parent->diff->depth + 1;
> + else
> + dag->depth = 1;
> + dag->state = state;
> + state->diff = dag;
> + rc = 1;
> + }
> + if (parent && parent->diff->depth < state->diff->depth)
> + state->diff->parents.push_back(parent);
> + return rc;
> +}
> +
> +static int diff_partition(State *state, Partition &part, State **candidate)
> +{
> + int weight = 0;
> + *candidate = NULL;
> +
> + for (Partition::iterator i = part.begin(); i != part.end(); i++) {
> + if (*i == state)
> + continue;
> +
> + int tmp = state->diff_weight(*i);
> + if (tmp > weight) {
> + weight = tmp;
> + *candidate = *i;
> + }
> + }
> + return weight;
> +}
> +
> +/**
> + * diff_encode - compress dfa by differentially encoding state transitions
> + * @dfa_flags: flags controling dfa creation
> + *
> + * This function reduces the number of transitions that need to be stored
> + * by encoding transitions as the difference between the state and a
> + * another transitions that is set as the states default.
> + *
> + * For performance reasons this function does not try to compute the
> + * absolute best encoding (maximal spanning tree) but instead computes
> + * a very good encoding within the following limitations.
> + * - Not all states have to be differentially encoded. This allows for
> + * multiple states to be used as a terminating basis.
> + * - The number of state transitions needed to match an input of length
> + * m will be 2m
> + *
> + * To guarentee this the ordering and distance calculation is done in the
> + * following manner.
> + * - A DAG of the DFA is created starting with the start state(s).
> + * - A state can only be relative (have a differential encoding) to
> + * another state if that state has
> + * - a lower depth in the DAG
> + * - is a sibling (same depth) that is not relative
> + * - is a sibling that is relative to a state with lower depth in the DAG
> + *
> + * The run time constraints are maintained by the DAG ordering + relative
> + * state constraints. For any input character C when at state S with S being
> + * at level N in the DAG then at most 2N states must be traversed to find the
> + * transition for C. However on the maximal number of transitions is not m*m,
> + * because when a character is matched and forward movement is made through
> + * the DFA any relative transition search will move back through the DAG order.
> + * So say for character C we start matching on a state S that is at depth 10
> + * in the DAG. The transition for C is not found in S and we recurse backwards
> + * to a depth of 6. A transition is found and it steps to the next state, but
> + * the state transition at most will only move 1 deeper into the DAG so for
> + * the next state the maximum number of states traversed is 2*7.
> + */
> +void DFA::diff_encode(dfaflags_t flags)
> +{
> + DiffDag *dag;
> + unsigned int xcount = 0, xweight = 0, transitions = 0, depth = 0;
> +
> + /* clear the depth flag */
> + for (Partition::iterator i = states.begin(); i != states.end(); i++) {
> + (*i)->diff = NULL;
> + transitions += (*i)->trans.size();
> + }
> +
> + /* Prealloc structures we need. We know the exact number of elements,
> + * and once setup they don't change so we don't need the flexibility
> + * or overhead of stl, just allocate the needed data as an array
> + */
> + dag = new DiffDag [states.size()];
> +
> + /* Generate DAG ordering and parent sets */
> + add_to_dag(&dag[0], nonmatching, NULL);
> + add_to_dag(&dag[1], start, NULL);
> +
> + unsigned int tail = 2;
> + for (unsigned int i = 1; i < tail; i++) {
> + State *state = dag[i].state;
> + State *child = dag[i].state->otherwise;
> + if (child)
> + tail += add_to_dag(&dag[tail], child, state);
> +
> + for (StateTrans::iterator j = state->trans.begin(); j != state->trans.end(); j++) {
> + child = j->second;
> + tail += add_to_dag(&dag[tail], child, state);
> + }
> + }
> + depth = dag[tail - 1].depth;
> +
> + /* calculate which state to make a transitions relative too */
> + for (unsigned int i = 2; i < tail; i++) {
> + State *state = dag[i].state;
> + State *candidate = NULL;
> +
> + int weight = diff_partition(state,
> + state->otherwise->diff->parents,
> + &candidate);
> +
> + for (StateTrans::iterator j = state->trans.begin(); j != state->trans.end(); j++) {
> + State *tmp_candidate;
> + int tmp = diff_partition(state,
> + j->second->diff->parents,
> + &tmp_candidate);
> + if (tmp > weight) {
> + weight = tmp;
> + candidate = tmp_candidate;
> + }
> + }
> +
> + if ((flags & DFA_DUMP_DIFF_PROGRESS) && (i % 100 == 0))
> + cerr << "\033[2KDiff Encode: " << i << " of "
> + << tail << ". Diff states " << xcount
> + << " Savings " << xweight << "\r";
> +
> + state->diff->rel = candidate;
> + if (candidate) {
> + xcount++;
> + xweight += weight;
> + }
> + }
> +
> + /* now make transitions relative, start at the back of the list so
> + * as to start with the last transitions and work backwards to avoid
> + * having to traverse multiple previous states (that have been made
> + * relative already) to reconstruct previous state transition table
> + */
> + unsigned int aweight = 0;
> + diffcount = 0;
> + for (int i = tail - 1; i > 1; i--) {
> + if (dag[i].rel) {
> + int weight = dag[i].state->make_relative(dag[i].rel);
> + aweight += weight;
> + diffcount++;
> + }
> + }
> +
> + if (flags & DFA_DUMP_DIFF_STATS)
> + cerr << "Diff encode states: " << diffcount << " of "
> + << tail << " reached @ depth " << depth << ". "
> + << aweight << " trans removed\n";
> +
> + if (xweight != aweight)
> + cerr << "Diff encode error: actual savings " << aweight
> + << " != expected " << xweight << "\n";
> +
> + if (xcount != diffcount)
> + cerr << "Diff encode error: actual count " << diffcount
> + << " != expected " << xcount << " \n";
> +
> + /* cleanup */
> + for (unsigned int i = 0; i < tail; i++)
> + dag[i].parents.clear();
> + delete [] dag;
Something about the dag[i].parents.clear() seems out of place; will it
leak the 'shells' of the data structures? Can these be fiddled with so
they'll be properly cleaned up when they go out of scope?
> +}
> +
> +/**
> + * flatten_differential - remove differential state encoding
> + *
> + * Flatten the dfa back into a flat encoding.
> + */
> +void DFA::undiff_encode(void)
> +{
> + for (Partition::iterator i = states.begin(); i != states.end(); i++)
> + (*i)->flatten_relative();
> + diffcount = 0;
> +}
> +
> +void DFA::dump_diff_chain(ostream &os, map<State *, Partition> &relmap,
> + Partition &chain, State *state, unsigned int &count,
> + unsigned int &total, unsigned int &max)
> +{
> + if (relmap[state].size() == 0) {
> + for (Partition::iterator i = chain.begin(); i != chain.end(); i++)
> + os << **i << " <- ";
> + os << *state << "\n";
> +
> + count++;
> + total += chain.size() + 1;
> + if (chain.size() + 1 > max)
> + max = chain.size() + 1;
> + }
> +
> + chain.push_back(state);
> + for (Partition::iterator i = relmap[state].begin(); i != relmap[state].end(); i++)
> + dump_diff_chain(os, relmap, chain, *i, count, total, max);
> + chain.pop_back();
> +}
> +
> +/* Dump the DFA diff_encoding chains */
> +void DFA::dump_diff_encode(ostream &os)
> +{
> + map<State *, Partition> rel;
> + Partition base, chain;
> +
> + for (Partition::iterator i = states.begin(); i != states.end(); i++) {
> + if ((*i)->flags & DiffEncodeFlag)
> + rel[(*i)->otherwise].push_back(*i);
> + else
> + base.push_back(*i);
> + }
> +
> + unsigned int count = 0, total = 0, max = 0;
> + for (Partition::iterator i = base.begin(); i != base.end(); i++)
> + dump_diff_chain(os, rel, chain, *i, count, total, max);
> +
> + os << base.size() << " non-differentially encoded states\n";
> + os << "chains: " << count - base.size() << "\n";
> + os << "average chain size: " << (double) (total - base.size()) / (double) (count - base.size()) << "\n";
> + os << "longest chain: " << max << "\n";
> +}
> +
> /**
> * text-dump the DFA (for debugging).
> */
>
> === modified file 'parser/libapparmor_re/hfa.h'
> --- parser/libapparmor_re/hfa.h 2012-05-30 21:31:41 +0000
> +++ parser/libapparmor_re/hfa.h 2013-12-10 14:10:29 +0000
> @@ -28,10 +28,13 @@
> #include <map>
> #include <vector>
>
> +#include <assert.h>
> #include <stdint.h>
>
> #include "expr-tree.h"
>
> +#define DiffEncodeFlag 1
> +
> class State;
>
> typedef map<uchar, State *> StateTrans;
> @@ -334,6 +337,19 @@
> }
> };
>
> +/* Temporary state structure used when building differential encoding
> + * @parents - set of states that have transitions to this state
> + * @depth - level in the DAG
> + * @state - back reference to state this DAG entry belongs
> + * @rel - state that this state is relative to for differential encoding
> + */
> +struct DiffDag {
> + Partition parents;
> + int depth;
> + State *state;
> + State *rel;
> +};
> +
> /*
> * State - DFA individual state information
> * label: a unique label to identify the state used for pretty printing
> @@ -352,7 +368,7 @@
> class State {
> public:
> State(int l, ProtoState &n, State *other) throw(int):
> - label(l), perms(), trans()
> + label(l), flags(0), perms(), trans()
> {
> int error;
>
> @@ -372,15 +388,30 @@
> };
>
> State *next(uchar c) {
> - StateTrans::iterator i = trans.find(c);
> - if (i != trans.end())
> - return i->second;
> - return otherwise;
> - };
> + State *state = this;
> + do {
> + StateTrans::iterator i = state->trans.find(c);
> + if (i != state->trans.end())
> + return i->second;
> +
> + if (!(state->flags & DiffEncodeFlag))
> + return state->otherwise;
> + state = state->otherwise;
> + } while (state);
> +
> + /* never reached */
> + assert(0);
> + return NULL;
> + }
> +
> + int diff_weight(State *rel);
> + int make_relative(State *rel);
> + void flatten_relative(void);
>
> int apply_and_clear_deny(void) { return perms.apply_and_clear_deny(); }
>
> int label;
> + int flags;
> perms_t perms;
> StateTrans trans;
> State *otherwise;
> @@ -389,6 +420,7 @@
> union {
> Partition *partition; /* used during minimization */
> ProtoState proto; /* used during creation */
> + DiffDag *diff; /* used during diff encoding */
> };
> };
>
> @@ -429,12 +461,16 @@
> }
> };
>
> +
> /* Transitions in the DFA. */
> -
> class DFA {
> void dump_node_to_dfa(void);
> State *add_new_state(NodeSet *nodes, State *other);
> void update_state_transitions(State *state);
> + void dump_diff_chain(ostream &os, map<State *, Partition> &relmap,
> + Partition &chain, State *state,
> + unsigned int &count, unsigned int &total,
> + unsigned int &max);
>
> /* temporary values used during computations */
> NodeCache anodes_cache;
> @@ -455,11 +491,19 @@
> size_t hash_trans(State *s);
> void minimize(dfaflags_t flags);
> int apply_and_clear_deny(void);
> +
> + void diff_encode(dfaflags_t flags);
> + void undiff_encode(void);
> + void dump_diff_encode(ostream &os);
> +
> void dump(ostream &os);
> void dump_dot_graph(ostream &os);
> void dump_uniq_perms(const char *s);
> +
> map<uchar, uchar> equivalence_classes(dfaflags_t flags);
> void apply_equivalence_classes(map<uchar, uchar> &eq);
> +
> + unsigned int diffcount;
> Node *root;
> State *nonmatching, *start;
> Partition states;
>
> === modified file 'parser/parser_main.c'
> --- parser/parser_main.c 2013-10-30 00:03:23 +0000
> +++ parser/parser_main.c 2013-12-10 14:34:13 +0000
> @@ -194,10 +194,10 @@
> DFA_DUMP_SIMPLE_TREE },
> { 1, "stats", "Dump all compile stats",
> DFA_DUMP_TREE_STATS | DFA_DUMP_STATS | DFA_DUMP_TRANS_STATS |
> - DFA_DUMP_EQUIV_STATS },
> + DFA_DUMP_EQUIV_STATS | DFA_DUMP_DIFF_STATS },
> { 1, "progress", "Dump progress for all compile phases",
> DFA_DUMP_PROGRESS | DFA_DUMP_STATS | DFA_DUMP_TRANS_PROGRESS |
> - DFA_DUMP_TRANS_STATS },
> + DFA_DUMP_TRANS_STATS | DFA_DUMP_DIFF_PROGRESS | DFA_DUMP_DIFF_STATS },
> { 1, "dfa-progress", "Dump dfa creation as in progress",
> DFA_DUMP_PROGRESS | DFA_DUMP_STATS },
> { 1, "dfa-stats", "Dump dfa creation stats", DFA_DUMP_STATS },
> @@ -222,6 +222,12 @@
> { 1, "equiv-stats", "Dump equivance class stats",
> DFA_DUMP_EQUIV_STATS },
> { 1, "equiv", "Dump equivance class", DFA_DUMP_EQUIV },
> + { 1, "diff-encode", "Dump differential encoding",
> + DFA_DUMP_DIFF_ENCODE },
> + { 1, "diff-stats", "Dump differential encoding stats",
> + DFA_DUMP_DIFF_STATS },
> + { 1, "diff-progress", "Dump progress of differential encoding",
> + DFA_DUMP_DIFF_PROGRESS | DFA_DUMP_DIFF_STATS },
> { 0, NULL, NULL, 0 },
> };
>
> @@ -251,6 +257,8 @@
> DFA_CONTROL_TRANS_HIGH },
> { 2, "compress-fast", "do faster dfa transition table compression",
> DFA_CONTROL_TRANS_HIGH },
> + { 1, "diff-encode", "Differentially encode transitions",
> + DFA_CONTROL_DIFF_ENCODE },
> { 0, NULL, NULL, 0 },
> };
>
Thanks!
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 490 bytes
Desc: Digital signature
URL: <https://lists.ubuntu.com/archives/apparmor/attachments/20131213/b498b432/attachment.pgp>
More information about the AppArmor
mailing list