From 1d85987d9685ac3f0a8b33773dba5c8a06421054 Mon Sep 17 00:00:00 2001 From: Justin Viiret Date: Thu, 14 Apr 2016 10:08:36 +1000 Subject: [PATCH] FINAL_REPORT: Add specialised instruction 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 | 12 ++++++++++ src/rose/rose_build_bytecode.cpp | 39 ++++++++++++++++++++++++++++++-- src/rose/rose_dump.cpp | 6 +++++ src/rose/rose_program.h | 12 ++++++++++ 4 files changed, 67 insertions(+), 2 deletions(-) diff --git a/src/rose/program_runtime.h b/src/rose/program_runtime.h index db1dc8c1..be56bec7 100644 --- a/src/rose/program_runtime.h +++ b/src/rose/program_runtime.h @@ -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); diff --git a/src/rose/rose_build_bytecode.cpp b/src/rose/rose_build_bytecode.cpp index add3ac2d..6407f125 100644 --- a/src/rose/rose_build_bytecode.cpp +++ b/src/rose/rose_build_bytecode.cpp @@ -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> &programs) { return out; } +static +void applyFinalSpecialisation(vector &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 &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 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 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}; } diff --git a/src/rose/rose_dump.cpp b/src/rose/rose_dump.cpp index 73f5940b..f6badd1b 100644 --- a/src/rose/rose_dump.cpp +++ b/src/rose/rose_dump.cpp @@ -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; diff --git a/src/rose/rose_program.h b/src/rose/rose_program.h index 834e997f..01572dbd 100644 --- a/src/rose/rose_program.h +++ b/src/rose/rose_program.h @@ -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.