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.
This commit is contained in:
Justin Viiret 2016-04-14 10:08:36 +10:00 committed by Matthew Barr
parent 36150bbc19
commit 1d85987d96
4 changed files with 67 additions and 2 deletions

View 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);

View 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};
}

View 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;

View 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.