Обсуждение: Special-case executor expression steps for common combinations

Поиск
Список
Период
Сортировка

Special-case executor expression steps for common combinations

От
Daniel Gustafsson
Дата:
The attached patch adds special-case expression steps for common sets of steps
in the executor to shave a few cycles off during execution, and make the JIT
generated code simpler.

* Adds EEOP_FUNCEXPR_STRICT_1 and EEOP_FUNCEXPR_STRICT_2 for function calls of
  strict functions with 1 or 2 arguments (EEOP_FUNCEXPR_STRICT remains used for
  > 2 arguments).
* Adds EEOP_AGG_STRICT_INPUT_CHECK_ARGS_1 which is a special case for the
  common case of one arg aggs.
* Replace EEOP_DONE with EEOP_DONE_RETURN and EEOP_DONE_NO_RETURN to be able to
  skip extra setup for steps which are only interested in the side effects.

Stressing the EEOP_FUNCEXPR_STRICT_* steps specifically shows a 1.5%
improvement and pgbench over the branch shows a ~1% improvement in TPS (both
measured over 6 runs with outliers removed).

EEOP_FUNCEXPR_STRICT_* (10M iterations):
    master  : (7503.317, 7553.691, 7634.524)
    patched : (7422.756, 7455.120, 7492.393)

pgbench:
    master  : (3653.83, 3792.97, 3863.70)
    patched : (3743.04, 3830.02, 3869.80)

This patch was extracted from a larger body of work from Andres [0] aiming at
providing the necessary executor infrastructure for making JIT expression
caching possible.  This patch, and more which are to be submitted, is however
separate in the sense that it is not part of the infrastructure, it's an
improvements on its own.

Thoughts?

--
Daniel Gustafsson

[0]: https://postgr.es/m/20191023163849.sosqbfs5yenocez3@alap3.anarazel.de


Вложения

Re: Special-case executor expression steps for common combinations

От
Heikki Linnakangas
Дата:
On 12/10/2023 12:48, Daniel Gustafsson wrote:
> The attached patch adds special-case expression steps for common sets of steps
> in the executor to shave a few cycles off during execution, and make the JIT
> generated code simpler.
> 
> * Adds EEOP_FUNCEXPR_STRICT_1 and EEOP_FUNCEXPR_STRICT_2 for function calls of
>    strict functions with 1 or 2 arguments (EEOP_FUNCEXPR_STRICT remains used for
>    > 2 arguments).
> * Adds EEOP_AGG_STRICT_INPUT_CHECK_ARGS_1 which is a special case for the
>    common case of one arg aggs.

Are these relevant when JITting? I'm a little sad if the JIT compiler 
cannot unroll these on its own. Is there something we could do to hint 
it, so that it could treat the number of arguments as a constant?

I understand that this can give a small boost in interpreter mode, so 
maybe we should do it in any case. But I'd like to know if we're missing 
a trick with the JITter, before we mask it with this.

> * Replace EEOP_DONE with EEOP_DONE_RETURN and EEOP_DONE_NO_RETURN to be able to
>    skip extra setup for steps which are only interested in the side effects.

I'm a little surprised if this makes a measurable performance 
difference, but sure, why not. It seems nice to be more explicit when 
you don't expect a return value.

-- 
Heikki Linnakangas
Neon (https://neon.tech)




Re: Special-case executor expression steps for common combinations

От
David Rowley
Дата:
On Thu, 12 Oct 2023 at 22:54, Daniel Gustafsson <daniel@yesql.se> wrote:
> EEOP_FUNCEXPR_STRICT_* (10M iterations):
>     master  : (7503.317, 7553.691, 7634.524)
>     patched : (7422.756, 7455.120, 7492.393)
>
> pgbench:
>     master  : (3653.83, 3792.97, 3863.70)
>     patched : (3743.04, 3830.02, 3869.80)
>
> Thoughts?

Did any of these tests compile the expression with JIT?

If not, how does the performance compare for a query that JITs the expression?

David



Re: Special-case executor expression steps for common combinations

От
Andres Freund
Дата:
Hi,

On 2023-10-12 13:24:27 +0300, Heikki Linnakangas wrote:
> On 12/10/2023 12:48, Daniel Gustafsson wrote:
> > The attached patch adds special-case expression steps for common sets of steps
> > in the executor to shave a few cycles off during execution, and make the JIT
> > generated code simpler.
> > 
> > * Adds EEOP_FUNCEXPR_STRICT_1 and EEOP_FUNCEXPR_STRICT_2 for function calls of
> >    strict functions with 1 or 2 arguments (EEOP_FUNCEXPR_STRICT remains used for
> >    > 2 arguments).
> > * Adds EEOP_AGG_STRICT_INPUT_CHECK_ARGS_1 which is a special case for the
> >    common case of one arg aggs.
> 
> Are these relevant when JITting? I'm a little sad if the JIT compiler cannot
> unroll these on its own. Is there something we could do to hint it, so that
> it could treat the number of arguments as a constant?

I think it's mainly important for interpreted execution.


> >    skip extra setup for steps which are only interested in the side effects.
> 
> I'm a little surprised if this makes a measurable performance difference,
> but sure, why not. It seems nice to be more explicit when you don't expect a
> return value.

IIRC this is more interesting for JIT than the above, because it allows LLVM
to know that the return value isn't needed and thus doesn't need to be
computed.

Greetings,

Andres Freund



Re: Special-case executor expression steps for common combinations

От
Daniel Gustafsson
Дата:
> On 12 Oct 2023, at 19:52, Andres Freund <andres@anarazel.de> wrote:
> On 2023-10-12 13:24:27 +0300, Heikki Linnakangas wrote:
>> On 12/10/2023 12:48, Daniel Gustafsson wrote:

>>> The attached patch adds special-case expression steps for common sets of steps
>>> in the executor to shave a few cycles off during execution, and make the JIT
>>> generated code simpler.
>>>
>>> * Adds EEOP_FUNCEXPR_STRICT_1 and EEOP_FUNCEXPR_STRICT_2 for function calls of
>>>   strict functions with 1 or 2 arguments (EEOP_FUNCEXPR_STRICT remains used for
>>>> 2 arguments).
>>> * Adds EEOP_AGG_STRICT_INPUT_CHECK_ARGS_1 which is a special case for the
>>>   common case of one arg aggs.
>>
>> Are these relevant when JITting? I'm a little sad if the JIT compiler cannot
>> unroll these on its own. Is there something we could do to hint it, so that
>> it could treat the number of arguments as a constant?
>
> I think it's mainly important for interpreted execution.

Agreed.

>>>   skip extra setup for steps which are only interested in the side effects.
>>
>> I'm a little surprised if this makes a measurable performance difference,
>> but sure, why not. It seems nice to be more explicit when you don't expect a
>> return value.

Right, performance benefits aside it does improve readability IMHO.

> IIRC this is more interesting for JIT than the above, because it allows LLVM
> to know that the return value isn't needed and thus doesn't need to be
> computed.

Correct, this is important to the JIT code which no longer has to perform two
Loads and one Store in order to get nothing, but can instead fastpath to
building a zero returnvalue.

--
Daniel Gustafsson