-
Notifications
You must be signed in to change notification settings - Fork 29.3k
[SPARK-12018][SQL] Refactor common subexpression elimination code #10009
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
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -104,16 +104,13 @@ class CodeGenContext { | |
| val equivalentExpressions: EquivalentExpressions = new EquivalentExpressions | ||
|
|
||
| // State used for subexpression elimination. | ||
| case class SubExprEliminationState( | ||
| isLoaded: String, | ||
| code: GeneratedExpressionCode, | ||
| fnName: String) | ||
| case class SubExprEliminationState(isNull: String, value: String) | ||
|
|
||
| // Foreach expression that is participating in subexpression elimination, the state to use. | ||
| val subExprEliminationExprs = mutable.HashMap.empty[Expression, SubExprEliminationState] | ||
|
|
||
| // The collection of isLoaded variables that need to be reset on each row. | ||
| val subExprIsLoadedVariables = mutable.ArrayBuffer.empty[String] | ||
| // The collection of variables that need to be initialized on each row. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think |
||
| val subExprInitVariables = mutable.ArrayBuffer.empty[String] | ||
|
|
||
| final val JAVA_BOOLEAN = "boolean" | ||
| final val JAVA_BYTE = "byte" | ||
|
|
@@ -408,7 +405,6 @@ class CodeGenContext { | |
| val commonExprs = equivalentExpressions.getAllEquivalentExprs.filter(_.size > 1) | ||
| commonExprs.foreach(e => { | ||
| val expr = e.head | ||
| val isLoaded = freshName("isLoaded") | ||
| val isNull = freshName("isNull") | ||
| val value = freshName("value") | ||
| val fnName = freshName("evalExpr") | ||
|
|
@@ -417,18 +413,12 @@ class CodeGenContext { | |
| val code = expr.gen(this) | ||
| val fn = | ||
| s""" | ||
| |private void $fnName(InternalRow ${INPUT_ROW}) { | ||
| | if (!$isLoaded) { | ||
| | ${code.code.trim} | ||
| | $isLoaded = true; | ||
| | $isNull = ${code.isNull}; | ||
| | $value = ${code.value}; | ||
| | } | ||
| |private ${javaType(expr.dataType)} $fnName(InternalRow ${INPUT_ROW}) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: if there is only one variable, we can omit the |
||
| | ${code.code.trim} | ||
| | $isNull = ${code.isNull}; | ||
| | return ${code.value}; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can we make this method return void? we can just assign values to
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ok. make sense. |
||
| |} | ||
| """.stripMargin | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Am I right in saying you've picked a different approach to do this? You removed isLoaded and just load it every time. I think this is scary because it does not allow shortcircuiting. This can be bad if it is expr1 AND expr2 and expr1 is selective or expr2 is expensive.
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't understand your point. $fnName will be called only once for each row. This patch doesn't change that.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nvm, what I said doesn't apply for this operator. I was thinking for Filter you wouldn't want to call fnName once for each row. It can be called less than once. LGTM |
||
| code.code = fn | ||
| code.isNull = isNull | ||
| code.value = value | ||
|
|
||
| addNewFunction(fnName, fn) | ||
|
|
||
|
|
@@ -448,18 +438,12 @@ class CodeGenContext { | |
| // 2. Less code. | ||
| // Currently, we will do this for all non-leaf only expression trees (i.e. expr trees with | ||
| // at least two nodes) as the cost of doing it is expected to be low. | ||
|
|
||
| // Maintain the loaded value and isNull as member variables. This is necessary if the codegen | ||
| // function is split across multiple functions. | ||
| // TODO: maintaining this as a local variable probably allows the compiler to do better | ||
| // optimizations. | ||
| addMutableState("boolean", isLoaded, s"$isLoaded = false;") | ||
| addMutableState("boolean", isNull, s"$isNull = false;") | ||
| addMutableState(javaType(expr.dataType), value, | ||
| s"$value = ${defaultValue(expr.dataType)};") | ||
| subExprIsLoadedVariables += isLoaded | ||
|
|
||
| val state = SubExprEliminationState(isLoaded, code, fnName) | ||
| subExprInitVariables += s"$value = ${fnName}(${INPUT_ROW});" | ||
| val state = SubExprEliminationState(isNull, value) | ||
| e.foreach(subExprEliminationExprs.put(_, state)) | ||
| }) | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, the above variables are not unnecessary. I will remove them later if the test is passed.