Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,47 @@ public GroupByResultHolder createGroupByResultHolder(int initialCapacity, int ma
@Override
public void aggregate(int length, AggregationResultHolder aggregationResultHolder,
Map<ExpressionContext, BlockValSet> blockValSetMap) {
double[] valueArray = blockValSetMap.get(_expression).getDoubleValuesSV();
double max = aggregationResultHolder.getDoubleResult();
for (int i = 0; i < length; i++) {
double value = valueArray[i];
if (value > max) {
max = value;
BlockValSet blockValSet = blockValSetMap.get(_expression);
Copy link
Contributor

Choose a reason for hiding this comment

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

I understand how delaying conversion to double will help with heap usage. Couple of questions on performance:

  • Now every aggregate() call has to execute switch condition once. Will there be any perf penalty for this ?
  • Why does conversion to double[] prevent auto-vectorizatonn ?

Copy link
Member Author

Choose a reason for hiding this comment

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

You can see some numbers on #7920 (read longs as longs vs convert to double) but I’ll pull out some disassembly to demonstrate, as well as attach some numbers here.

Copy link
Member Author

Choose a reason for hiding this comment

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

Regarding the switch statement, there is one per block, so it’s cost is amortised (just like all the virtual calls we do)

Copy link
Member Author

Choose a reason for hiding this comment

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

@siddharthteotia I've added some rationale and numbers to the PR description, please take a look.

Copy link
Contributor

Choose a reason for hiding this comment

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

Thanks for sharing perf numbers, @richardstartin. I was also curious to see the disassembled code as you said auto-vectorization probability increases with continuing to treat as long. Please share if you have.

I am good with the PR. Please also check-in the benchmark

Copy link
Member Author

Choose a reason for hiding this comment

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

The vectorized method is Copy::conjoint_swap, as mentioned above, which hsdis does not dissemble.

switch (blockValSet.getValueType().getStoredType()) {
case INT: {
int[] values = blockValSet.getIntValuesSV();
int max = values[0];
for (int i = 0; i < length & i < values.length; i++) {
max = Math.max(values[i], max);
}
aggregationResultHolder.setValue(Math.max(max, aggregationResultHolder.getDoubleResult()));
break;
}
case LONG: {
long[] values = blockValSet.getLongValuesSV();
long max = values[0];
for (int i = 0; i < length & i < values.length; i++) {
max = Math.max(values[i], max);
}
aggregationResultHolder.setValue(Math.max(max, aggregationResultHolder.getDoubleResult()));
break;
}
case FLOAT: {
float[] values = blockValSet.getFloatValuesSV();
float max = values[0];
for (int i = 0; i < length & i < values.length; i++) {
max = Math.max(values[i], max);
}
aggregationResultHolder.setValue(Math.max(max, aggregationResultHolder.getDoubleResult()));
break;
}
case DOUBLE: {
double[] values = blockValSet.getDoubleValuesSV();
double max = values[0];
for (int i = 0; i < length & i < values.length; i++) {
max = Math.max(values[i], max);
}
aggregationResultHolder.setValue(Math.max(max, aggregationResultHolder.getDoubleResult()));
break;
}
default:
throw new IllegalStateException("Cannot compute min for non-numeric type: " + blockValSet.getValueType());
}
aggregationResultHolder.setValue(max);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,47 @@ public GroupByResultHolder createGroupByResultHolder(int initialCapacity, int ma
@Override
public void aggregate(int length, AggregationResultHolder aggregationResultHolder,
Map<ExpressionContext, BlockValSet> blockValSetMap) {
double[] valueArray = blockValSetMap.get(_expression).getDoubleValuesSV();
double min = aggregationResultHolder.getDoubleResult();
for (int i = 0; i < length; i++) {
double value = valueArray[i];
if (value < min) {
min = value;
BlockValSet blockValSet = blockValSetMap.get(_expression);
switch (blockValSet.getValueType().getStoredType()) {
case INT: {
int[] values = blockValSet.getIntValuesSV();
int min = values[0];
for (int i = 0; i < length & i < values.length; i++) {
min = Math.min(values[i], min);
}
aggregationResultHolder.setValue(Math.min(min, aggregationResultHolder.getDoubleResult()));
break;
}
case LONG: {
long[] values = blockValSet.getLongValuesSV();
long min = values[0];
for (int i = 0; i < length & i < values.length; i++) {
min = Math.min(values[i], min);
}
aggregationResultHolder.setValue(Math.min(min, aggregationResultHolder.getDoubleResult()));
break;
}
case FLOAT: {
float[] values = blockValSet.getFloatValuesSV();
float min = values[0];
for (int i = 0; i < length & i < values.length; i++) {
min = Math.min(values[i], min);
}
aggregationResultHolder.setValue(Math.min(min, aggregationResultHolder.getDoubleResult()));
break;
}
case DOUBLE: {
double[] values = blockValSet.getDoubleValuesSV();
double min = values[0];
for (int i = 0; i < length & i < values.length; i++) {
min = Math.min(values[i], min);
}
aggregationResultHolder.setValue(Math.min(min, aggregationResultHolder.getDoubleResult()));
break;
}
default:
throw new IllegalStateException("Cannot compute min for non-numeric type: " + blockValSet.getValueType());
}
aggregationResultHolder.setValue(min);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,39 @@ public GroupByResultHolder createGroupByResultHolder(int initialCapacity, int ma
@Override
public void aggregate(int length, AggregationResultHolder aggregationResultHolder,
Map<ExpressionContext, BlockValSet> blockValSetMap) {
double[] valueArray = blockValSetMap.get(_expression).getDoubleValuesSV();
double sum = aggregationResultHolder.getDoubleResult();
for (int i = 0; i < length; i++) {
sum += valueArray[i];
BlockValSet blockValSet = blockValSetMap.get(_expression);
switch (blockValSet.getValueType().getStoredType()) {
case INT: {
int[] values = blockValSet.getIntValuesSV();
for (int i = 0; i < length & i < values.length; i++) {
sum += values[i];
}
break;
}
case LONG: {
long[] values = blockValSet.getLongValuesSV();
for (int i = 0; i < length & i < values.length; i++) {
sum += values[i];
}
break;
}
case FLOAT: {
float[] values = blockValSet.getFloatValuesSV();
for (int i = 0; i < length & i < values.length; i++) {
sum += values[i];
}
break;
}
case DOUBLE: {
double[] values = blockValSet.getDoubleValuesSV();
for (int i = 0; i < length & i < values.length; i++) {
sum += values[i];
}
break;
}
default:
throw new IllegalStateException("Cannot compute min for non-numeric type: " + blockValSet.getValueType());
Copy link
Contributor

Choose a reason for hiding this comment

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

Fix the exception message to reflect the correct aggregation

Copy link
Member Author

Choose a reason for hiding this comment

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

Will follow up

}
aggregationResultHolder.setValue(sum);
}
Expand Down