The jit_* family closes with the three parameters for people working on the JIT itself rather than with it. All three are booleans, all default off, all date to the original PostgreSQL 11 work, and all live in Developer Options. What makes them worth a post at all is that one of them is genuinely fun, and the other two demonstrate a GUC context this series hasn’t met before.

The fun one is jit_dump_bitcode. Context superuser, so a plain SET works, and when it’s on, every JIT compilation writes its LLVM module into the data directory, once as generated and once as optimized:

1$ ls -la $PGDATA/*.bc
2-rw------- 1 postgres postgres 7468 ... 498.0.bc
3-rw------- 1 postgres postgres 7420 ... 498.0.optimized.bc

The naming is process ID and a per-backend counter. Run the files through llvm-dis and you are looking at what your query became. The WHERE id % 3 = 0 aggregate from two posts ago, the one whose JIT block said “Functions: 5”, disassembles into exactly five definitions, and now they have names:

1define noundef i64 @evalexpr_0_0(...)
2define internal void @deform_0_1(...)
3define noundef i64 @evalexpr_0_2(...)
4define noundef i64 @evalexpr_0_3(...)
5define internal void @deform_0_4(...)

Three compiled expressions, two specialized deformers, and inside deform_0_1 a stream of getelementptr walks through TupleTableSlot and HeapTupleData with the generality compiled away, exactly as advertised. Two cautions before you try this anywhere that matters: the files land in the data directory, and PostgreSQL never deletes them, so a busy server with this on is a disk-fill incident on a timer; that, plus writing files at all, is why it’s superuser-only.

The other two parameters share a context we haven’t seen before in this series, superuser-backend, and it bites immediately:

1postgres=# SET jit_debugging_support = on;
2ERROR: parameter "jit_debugging_support" cannot be set after connection start

A superuser-backend parameter is fixed for the life of the backend, because the LLVM engine wires these options in when it’s created and won’t rewire them afterward. To turn one on you arrange it before the session exists: in postgresql.conf (a reload covers backends started afterward), or per connection the way anyone actually does it:

1$ PGOPTIONS='-c jit_profiling_support=on' psql
2psql> SHOW jit_profiling_support;
3 on

As for what they buy you: jit_debugging_support registers the generated functions with GDB, so a debugger attached to the backend sees named frames in JITed code instead of anonymous addresses. jit_profiling_support emits perf’s jitdump format into ~/.debug/jit/, so perf can attribute samples to the generated functions rather than to a mystery region. Both carry the documentation’s shrug of a caveat, “if LLVM has the required functionality,” meaning your LLVM build decides whether anything happens.

And that’s the family. None of the three belongs in a production configuration, and the two backend-context ones you will likely never touch unless you’re debugging the JIT implementation with a PostgreSQL hacker on the other end of the thread. But jit_dump_bitcode, ten minutes, and a scratch instance make the fastest demystification of this whole subsystem I know: five posts of Options lines and cost thresholds, and then you read the IR and it’s just code, doing the two jobs the family’s second post said it would.