]> git.ipfire.org Git - thirdparty/vectorscan.git/commitdiff
FINAL_REPORT: Add specialised instruction
authorJustin Viiret <justin.viiret@intel.com>
Thu, 14 Apr 2016 00:08:36 +0000 (10:08 +1000)
committerMatthew Barr <matthew.barr@intel.com>
Wed, 20 Apr 2016 03:34:57 +0000 (13:34 +1000)
Specialisation of the REPORT instruction that also terminates execution
of the program. Improves performance on programs that generate many
reports.

src/rose/program_runtime.h
src/rose/rose_build_bytecode.cpp
src/rose/rose_dump.cpp
src/rose/rose_program.h

index db1dc8c163e98ae54572f9293bad96f3f3d887a6..be56bec7b36b767e96835b7e167ec714e3bfc19a 100644 (file)
@@ -1165,6 +1165,18 @@ hwlmcb_rv_t roseRunProgram(const struct RoseEngine *t,
             }
             PROGRAM_NEXT_INSTRUCTION
 
+            PROGRAM_CASE(FINAL_REPORT) {
+                updateSeqPoint(tctxt, end, from_mpv);
+                if (roseReport(t, scratch, end, ri->onmatch, ri->offset_adjust,
+                               INVALID_EKEY) == HWLM_TERMINATE_MATCHING) {
+                    return HWLM_TERMINATE_MATCHING;
+                }
+                /* One-shot specialisation: this instruction always terminates
+                 * execution of the program. */
+                return HWLM_CONTINUE_MATCHING;
+            }
+            PROGRAM_NEXT_INSTRUCTION
+
             PROGRAM_CASE(CHECK_EXHAUSTED) {
                 DEBUG_PRINTF("check ekey %u\n", ri->ekey);
                 assert(ri->ekey != INVALID_EKEY);
index add3ac2d8c76ca633a5cd6591839965b46b0a59e..6407f125ecaa27afc6d1fc5dc0df8c73df2e62ce 100644 (file)
@@ -212,6 +212,7 @@ public:
         case ROSE_INSTR_REPORT_SOM: return &u.reportSom;
         case ROSE_INSTR_REPORT_SOM_EXHAUST: return &u.reportSomExhaust;
         case ROSE_INSTR_DEDUPE_AND_REPORT: return &u.dedupeAndReport;
+        case ROSE_INSTR_FINAL_REPORT: return &u.finalReport;
         case ROSE_INSTR_CHECK_EXHAUSTED: return &u.checkExhausted;
         case ROSE_INSTR_CHECK_MIN_LENGTH: return &u.checkMinLength;
         case ROSE_INSTR_SET_STATE: return &u.setState;
@@ -257,6 +258,7 @@ public:
         case ROSE_INSTR_REPORT_SOM: return sizeof(u.reportSom);
         case ROSE_INSTR_REPORT_SOM_EXHAUST: return sizeof(u.reportSomExhaust);
         case ROSE_INSTR_DEDUPE_AND_REPORT: return sizeof(u.dedupeAndReport);
+        case ROSE_INSTR_FINAL_REPORT: return sizeof(u.finalReport);
         case ROSE_INSTR_CHECK_EXHAUSTED: return sizeof(u.checkExhausted);
         case ROSE_INSTR_CHECK_MIN_LENGTH: return sizeof(u.checkMinLength);
         case ROSE_INSTR_SET_STATE: return sizeof(u.setState);
@@ -301,6 +303,7 @@ public:
         ROSE_STRUCT_REPORT_SOM reportSom;
         ROSE_STRUCT_REPORT_SOM_EXHAUST reportSomExhaust;
         ROSE_STRUCT_DEDUPE_AND_REPORT dedupeAndReport;
+        ROSE_STRUCT_FINAL_REPORT finalReport;
         ROSE_STRUCT_CHECK_EXHAUSTED checkExhausted;
         ROSE_STRUCT_CHECK_MIN_LENGTH checkMinLength;
         ROSE_STRUCT_SET_STATE setState;
@@ -2160,6 +2163,31 @@ flattenProgram(const vector<vector<RoseInstruction>> &programs) {
     return out;
 }
 
+static
+void applyFinalSpecialisation(vector<RoseInstruction> &program) {
+    assert(!program.empty());
+    assert(program.back().code() == ROSE_INSTR_END);
+    if (program.size() < 2) {
+        return;
+    }
+
+    /* Replace the second-to-last instruction (before END) with a one-shot
+     * specialisation if available. */
+    auto &ri = *(next(program.rbegin()));
+    switch (ri.code()) {
+    case ROSE_INSTR_REPORT: {
+        DEBUG_PRINTF("replacing REPORT with FINAL_REPORT\n");
+        auto ri2 = RoseInstruction(ROSE_INSTR_FINAL_REPORT);
+        ri2.u.finalReport.onmatch = ri.u.report.onmatch;
+        ri2.u.finalReport.offset_adjust = ri.u.report.offset_adjust;
+        ri = ri2;
+        break;
+    }
+    default:
+        break;
+    }
+}
+
 static
 void recordResources(RoseResources &resources,
                      const vector<RoseInstruction> &program) {
@@ -3020,7 +3048,9 @@ u32 writeBoundaryProgram(RoseBuildImpl &build, build_context &bc,
     for (const auto &id : reports) {
         makeReport(build, id, has_som, program);
     }
-    return writeProgram(bc, flattenProgram({program}));
+    program = flattenProgram({program});
+    applyFinalSpecialisation(program);
+    return writeProgram(bc, program);
 }
 
 static
@@ -3374,6 +3404,7 @@ pair<u32, u32> makeSparseIterProgram(build_context &bc,
         program.insert(end(program), begin(root_program), end(root_program));
     }
 
+    applyFinalSpecialisation(program);
     return {writeProgram(bc, program), iter_offset};
 }
 
@@ -3634,6 +3665,7 @@ u32 buildDelayRebuildProgram(RoseBuildImpl &build, build_context &bc,
     makePushDelayedInstructions(build, final_id, program);
     assert(!program.empty());
     program = flattenProgram({program});
+    applyFinalSpecialisation(program);
     return writeProgram(bc, program);
 }
 
@@ -3714,7 +3746,9 @@ u32 buildReportPrograms(RoseBuildImpl &build, build_context &bc) {
         const bool has_som = false;
         makeCatchupMpv(build, bc, id, program);
         makeReport(build, id, has_som, program);
-        programs[id] = writeProgram(bc, flattenProgram({program}));
+        program = flattenProgram({program});
+        applyFinalSpecialisation(program);
+        programs[id] = writeProgram(bc, program);
         DEBUG_PRINTF("program for report %u @ %u (%zu instructions)\n", id,
                      programs.back(), program.size());
     }
@@ -3792,6 +3826,7 @@ pair<u32, u32> buildEodAnchorProgram(RoseBuildImpl &build, build_context &bc) {
     u32 iter_offset = addPredBlocks(bc, predProgramLists, program, true);
 
     assert(program.size() > 1);
+    applyFinalSpecialisation(program);
     return {writeProgram(bc, program), iter_offset};
 }
 
index 73f5940ba2cab7b7491161c435e7c72e07c02d2d..f6badd1ba74cdc32d7e7100a3f5686135a7dab6c 100644 (file)
@@ -416,6 +416,12 @@ void dumpProgram(ofstream &os, const RoseEngine *t, const char *pc) {
             }
             PROGRAM_NEXT_INSTRUCTION
 
+            PROGRAM_CASE(FINAL_REPORT) {
+                os << "    onmatch " << ri->onmatch << endl;
+                os << "    offset_adjust " << ri->offset_adjust << endl;
+            }
+            PROGRAM_NEXT_INSTRUCTION
+
             PROGRAM_CASE(CHECK_EXHAUSTED) {
                 os << "    ekey " << ri->ekey << endl;
                 os << "    fail_jump " << offset + ri->fail_jump << endl;
index 834e997f74bac87e6c8386d696dec83e83793238..01572dbd061cdf3c96b8a424045fce840ce8862d 100644 (file)
@@ -82,6 +82,12 @@ enum RoseInstructionCode {
     /** \brief Super-instruction combining DEDUPE and REPORT. */
     ROSE_INSTR_DEDUPE_AND_REPORT,
 
+    /**
+     * \brief Fire a report and stop program execution. This is a
+     * specialisation intended for short, frequently-executed programs.
+     */
+    ROSE_INSTR_FINAL_REPORT,
+
     ROSE_INSTR_CHECK_EXHAUSTED,   //!< Check if an ekey has already been set.
     ROSE_INSTR_CHECK_MIN_LENGTH,  //!< Check (EOM - SOM) against min length.
     ROSE_INSTR_SET_STATE,         //!< Switch a state index on.
@@ -282,6 +288,12 @@ struct ROSE_STRUCT_DEDUPE_AND_REPORT {
     u32 fail_jump; //!< Jump forward this many bytes on failure.
 };
 
+struct ROSE_STRUCT_FINAL_REPORT {
+    u8 code; //!< From enum RoseInstructionCode.
+    ReportID onmatch; //!< Report ID to deliver to user.
+    s32 offset_adjust; //!< Offset adjustment to apply to end offset.
+};
+
 struct ROSE_STRUCT_CHECK_EXHAUSTED {
     u8 code; //!< From enum RoseInstructionCode.
     u32 ekey; //!< Exhaustion key to check.