Repository navigation
Improvement #9225 - Reduce Profiler overhead - #9238
asfernandes wants to merge 1 commit into
Conversation
Test setup
-- master
select rdb$profiler.start_session('bench', null, null, null, <plugin options>) from rdb$database;
-- branch
select rdb$profiler.start_session('bench', null, null, null, <plugin options>, <sampling interval>) from rdb$database;
-- timed statement
execute procedure rdb$profiler.finish_session(true);Tests1. PSQL loopPer-statement cost. execute block as
declare i integer = 0;
begin
while (i < 10000000) do
i = i + 1;
end2. SELECTPer-fetch cost of a record source tree. select count(*)
from (select 1 x
from rdb$types a
cross join rdb$types b
cross join rdb$types c
rows 3000000);3. Procedure callsPer-request cost: request start/finish, the plugin's request calls and the counter arrays. create procedure p_nop as
begin
end;
execute block as
declare i integer = 0;
begin
while (i < 1000000) do
begin
execute procedure p_nop;
i = i + 1;
end
end4. PSQL cursorPer-fetch cost of a PSQL cursor, which looks up its statement through the statement cache. execute block as
declare i integer = 0;
declare x integer;
begin
for select 1
from rdb$types a
cross join rdb$types b
cross join rdb$types c
rows 3000000
into x
do
i = i + 1;
end5. Join + group by, profiler offCost of the record source path with no profiler session. This checks that profiling support doesn't slow down unprofiled queries. It runs in the off mode only. -- setup (not timed)
create table t1 (id integer not null primary key, v integer);
create table t2 (id integer not null primary key, v integer);
execute block as
declare i integer = 0;
begin
while (i < 1000000) do
begin
insert into t1 values (:i, :i);
insert into t2 values (:i, :i);
i = i + 1;
end
end;
commit;
-- timed
select mod(t1.v, 100), count(*)
from t1
join t2 on t2.id = t1.id
group by 1; |
Test resultsTimes are median seconds of 10 runs. Overhead is the profiled time minus the off time of the same build. The change compares the branch overhead with the master overhead of the same mode. Sampled modes, which master doesn't have, are compared with master's measured mode, the only one master has. The off rows compare the times.
Profiled time / off time:
|
Conclusions
|
The Default_Profiler used to add a fixed cost to every PSQL statement, record source open and record fetch. That cost came from a clock read and a plugin call for each event, plus the bookkeeping around them. Measured times were also wrong, at about 40% of the real time. This PR makes profiling much cheaper and fixes the measured times. The data reported doesn't change, except that min/max times are NULL when timings are sampled.
Changes
StmtNodeprofile flags replace a virtual call per statement.query_performance_counter()is inline on POSIX.ProfilerSampler) wakes up at a randomized interval. It reads where each profiled attachment is executing from a seqlock-protected frame stack, and charges the elapsed wall time to each request, PSQL line/column and record source it finds there.IProfilerSessionmethodsadd*Stats.SAMPLING_INTERVAL: a new last parameter ofRDB$PROFILER.START_SESSION, in microseconds. The default is 100, and other values must be in 50..1000000.0measures every event, which gives exact min/max.