Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compile time optimizations #134

Merged
merged 6 commits into from
Oct 26, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 60 additions & 1 deletion src/execution_plan/execution_plan_build/execution_plan_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,16 @@
*/

#include "execution_plan_util.h"
#include "../ops/op_skip.h"
#include "../ops/op_limit.h"

// returns true if an operation in the op-tree rooted at `root` is eager
bool ExecutionPlan_isEager
(
OpBase *root
) {
return ExecutionPlan_LocateOpMatchingTypes(root, EAGER_OPERATIONS, 6) != NULL;
return ExecutionPlan_LocateOpMatchingTypes(root, EAGER_OPERATIONS,
EAGER_OP_COUNT) != NULL;
}

OpBase *ExecutionPlan_LocateOpResolvingAlias
Expand Down Expand Up @@ -189,6 +192,62 @@ OpBase *ExecutionPlan_LocateReferencesExcludingOps
return resolving_op;
}

// scans plan from root via parent nodes until a limit operation is found
// eager operation will terminate the scan
// return true if a limit operation was found, in which case 'limit' is set
// otherwise return false
bool ExecutionPlan_ContainsLimit
(
OpBase *root, // root to start the scan from
uint64_t *limit // limit value
) {
ASSERT(root != NULL);
ASSERT(limit != NULL);

while(root != NULL) {
// halt if we encounter an eager operation
if(ExecutionPlan_isEager(root)) return false;

// found a limit operation
if(root->type == OPType_LIMIT) {
*limit = ((const OpLimit*)root)->limit;
return true;
}

root = root->parent;
}

return false;
}

// scans plan from root via parent nodes until a skip operation is found
// eager operation will terminate the scan
// return true if a skip operation was found, in which case 'skip' is set
// otherwise return false
bool ExecutionPlan_ContainsSkip
(
OpBase *root, // root to start the scan from
uint64_t *skip // skip value
) {
ASSERT(root != NULL);
ASSERT(skip != NULL);

while(root != NULL) {
// halt if we encounter an eager operation
if(ExecutionPlan_isEager(root)) return false;

// found a skip operation
if(root->type == OPType_SKIP) {
*skip = ((const OpSkip*)root)->skip;
return true;
}

root = root->parent;
}

return false;
}

OpBase *ExecutionPlan_LocateReferences
(
OpBase *root,
Expand Down
20 changes: 20 additions & 0 deletions src/execution_plan/execution_plan_build/execution_plan_util.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,26 @@ OpBase *ExecutionPlan_LocateReferencesExcludingOps
rax *refs_to_resolve
);

// scans plan from root via parent nodes until a limit operation is found
// eager operation will terminate the scan
// return true if a limit operation was found, in which case 'limit' is set
// otherwise return false
bool ExecutionPlan_ContainsLimit
(
OpBase *root, // root to start the scan from
uint64_t *limit // limit value
);

// scans plan from root via parent nodes until a skip operation is found
// eager operation will terminate the scan
// return true if a skip operation was found, in which case 'skip' is set
// otherwise return false
bool ExecutionPlan_ContainsSkip
(
OpBase *root, // root to start the scan from
uint64_t *skip // skip value
);

//------------------------------------------------------------------------------
// ExecutionPlan_Collect API:
// For collecting all matching operations in tree.
Expand Down
14 changes: 14 additions & 0 deletions src/execution_plan/ops/op.c
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,20 @@ bool OpBase_IsWriter
return op->writer;
}

// indicates if the operation is an eager operation
bool OpBase_IsEager
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is already one like this called ExecutionPlan_isEager

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A bit confusing but ExecutionPlan_isEager checks to see if the Execution-Plan spanned from the given root contains an eager operation while OpBase_IsEager checks if the given operation is an eager op.

(
const OpBase *op
) {
ASSERT(op != NULL);

for(int i = 0; i < EAGER_OP_COUNT; i++) {
if(op->type == EAGER_OPERATIONS[i]) return true;
}

return false;
}

void OpBase_UpdateConsume
(
OpBase *op,
Expand Down
6 changes: 6 additions & 0 deletions src/execution_plan/ops/op.h
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,12 @@ bool OpBase_IsWriter
OpBase *op
);

// indicates if the operation is an eager operation
bool OpBase_IsEager
(
const OpBase *op
);

// update operation consume function
void OpBase_UpdateConsume
(
Expand Down
16 changes: 10 additions & 6 deletions src/execution_plan/ops/op_conditional_traverse.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@
* the Server Side Public License v1 (SSPLv1).
*/

#include "op_conditional_traverse.h"
#include "RG.h"
#include "shared/print_functions.h"
#include "../../query_ctx.h"
#include "shared/print_functions.h"
#include "op_conditional_traverse.h"
#include "../execution_plan_build/execution_plan_util.h"

// default number of records to accumulate before traversing
#define BATCH_SIZE 16
Expand Down Expand Up @@ -109,11 +110,14 @@ OpBase *NewCondTraverseOp

static OpResult CondTraverseInit(OpBase *opBase) {
OpCondTraverse *op = (OpCondTraverse *)opBase;
// Create 'records' with this Init function as 'record_cap'
// might be set during optimization time (applyLimit)
// If cap greater than BATCH_SIZE is specified,
// use BATCH_SIZE as the value.

// in case this operation is restricted by a limit
// set record_cap to the specified limit
ExecutionPlan_ContainsLimit(opBase, &op->record_cap);

// record_cap should not be greater than BATCH_SIZE
if(op->record_cap > BATCH_SIZE) op->record_cap = BATCH_SIZE;

op->records = rm_calloc(op->record_cap, sizeof(Record));

return OP_OK;
Expand Down
4 changes: 2 additions & 2 deletions src/execution_plan/ops/op_conditional_traverse.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ typedef struct {
RG_MatrixTupleIter iter; // Iterator over M.
int srcNodeIdx; // Source node index into record.
int destNodeIdx; // Destination node index into record.
uint record_count; // Number of held records.
uint record_cap; // Max number of records to process.
uint64_t record_count; // Number of held records.
uint64_t record_cap; // Max number of records to process.
Record *records; // Array of records.
Record r; // Currently selected record.
} OpCondTraverse;
Expand Down
12 changes: 7 additions & 5 deletions src/execution_plan/ops/op_expand_into.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
*/

#include "op_expand_into.h"
#include "shared/print_functions.h"
#include "../../query_ctx.h"
#include "shared/print_functions.h"
#include "../execution_plan_build/execution_plan_util.h"

// default number of records to accumulate before traversing
#define BATCH_SIZE 16
Expand Down Expand Up @@ -131,6 +132,10 @@ static OpResult ExpandIntoInit
) {
OpExpandInto *op = (OpExpandInto *)opBase;

// in case this operation is restricted by a limit
// set record_cap to the specified limit
ExecutionPlan_ContainsLimit(opBase, &op->record_cap);

// see if we can optimize by avoiding matrix multiplication
// if the algebraic expression passed in is just a single operand
// there's no need to compute F and perform F*X, we can simply inspect X
Expand Down Expand Up @@ -161,10 +166,7 @@ static OpResult ExpandIntoInit
}
}

// create 'records' within this Init function as 'record_cap'
// might be set during optimization time (applyLimit)
// If cap greater than BATCH_SIZE is specified,
// use BATCH_SIZE as the value.
// allocate record buffer, limited to a maximum of BATCH_SIZE
if(op->record_cap > BATCH_SIZE) op->record_cap = BATCH_SIZE;

op->records = rm_calloc(op->record_cap, sizeof(Record));
Expand Down
4 changes: 2 additions & 2 deletions src/execution_plan/ops/op_expand_into.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ typedef struct {
int srcNodeIdx; // source node index into record
int destNodeIdx; // destination node index into record
bool single_operand; // expression contains a single operand
uint record_count; // number of held records
uint record_cap; // max number of records to process
uint64_t record_count; // number of held records
uint64_t record_cap; // max number of records to process
Record *records; // array of records
Record r; // currently selected record
} OpExpandInto;
Expand Down
8 changes: 7 additions & 1 deletion src/execution_plan/ops/op_sort.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@
#include "op_project.h"
#include "op_aggregate.h"
#include "../../util/arr.h"
#include "../../query_ctx.h"
#include "../../util/qsort.h"
#include "../../util/rmalloc.h"
#include "../../query_ctx.h"
#include "../execution_plan_build/execution_plan_util.h"

// forward declarations
static OpResult SortInit(OpBase *opBase);
Expand Down Expand Up @@ -111,6 +112,11 @@ OpBase *NewSortOp

static OpResult SortInit(OpBase *opBase) {
OpSort *op = (OpSort *)opBase;

// set skip and limit if present in the execution-plan
ExecutionPlan_ContainsSkip(opBase, &op->skip);
ExecutionPlan_ContainsLimit(opBase, &op->limit);

// if there is LIMIT value, l, set in the current clause,
// the operation must return the top l records with respect to
// the sorting criteria. In order to do so, it must collect the l records,
Expand Down
4 changes: 2 additions & 2 deletions src/execution_plan/ops/op_sort.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ typedef struct {
Record *buffer; // Holds all records.
heap_t *heap; // Holds top n records.
bool first; // first visit to consume func
uint skip; // Total number of records to skip
uint64_t skip; // Total number of records to skip
uint record_idx; // index of current record to return
uint limit; // Total number of records to produce
uint64_t limit; // Total number of records to produce
uint *record_offsets; // All Record offsets containing values to sort by
int *directions; // Array of sort directions(ascending / descending)
AR_ExpNode **exps; // Projected expressons.
Expand Down
56 changes: 0 additions & 56 deletions src/execution_plan/optimizations/apply_limit.c

This file was deleted.

40 changes: 0 additions & 40 deletions src/execution_plan/optimizations/apply_skip.c

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
// Scan(B)
// Traverse A*R

static void _optimizeLabelScan
static void _costBaseLabelScan
(
NodeByLabelScan *scan
) {
Expand Down Expand Up @@ -127,7 +127,7 @@ static void _optimizeLabelScan
_AlgebraicExpression_InplaceRepurpose(operand, replacement);
}

void optimizeLabelScan
void costBaseLabelScan
(
ExecutionPlan *plan
) {
Expand All @@ -142,7 +142,7 @@ void optimizeLabelScan
uint op_count = array_len(label_scan_ops);
for(uint i = 0; i < op_count; i++) {
NodeByLabelScan *label_scan = (NodeByLabelScan*)label_scan_ops[i];
_optimizeLabelScan(label_scan);
_costBaseLabelScan(label_scan);
}
array_free(label_scan_ops);
}
Expand Down
Loading
Loading