Skip to content

Commit

Permalink
Improvement #7687 - Add LEVEL column to PLG$PROF_RECORD_SOURCES and P…
Browse files Browse the repository at this point in the history
…LG$PROF_RECORD_SOURCE_STATS_VIEW.

Also avoid start collect profiling data for a record source not from its initial node.
  • Loading branch information
asfernandes committed Jul 28, 2023
1 parent fc24dfa commit c86bd3d
Show file tree
Hide file tree
Showing 7 changed files with 113 additions and 66 deletions.
3 changes: 3 additions & 0 deletions doc/sql.extensions/README.profiler.md
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,7 @@ Below is the list of tables that stores profile data.
- `CURSOR_ID` type `INTEGER` - Cursor ID
- `RECORD_SOURCE_ID` type `INTEGER` - Record source ID
- `PARENT_RECORD_SOURCE_ID` type `INTEGER` - Parent record source ID
- `LEVEL` type `INTEGER` - Indentation level for the record source
- `ACCESS_PATH` type `VARCHAR(255) CHARACTER SET UTF8` - Access path for the record source
- Primary key: `PROFILE_ID, STATEMENT_ID, CURSOR_ID, RECORD_SOURCE_ID`

Expand Down Expand Up @@ -419,6 +420,7 @@ select rstat.profile_id,
cur.column_num cursor_column_num,
rstat.record_source_id,
recsrc.parent_record_source_id,
recsrc.level,
recsrc.access_path,
cast(sum(rstat.open_counter) as bigint) open_counter,
min(rstat.open_min_elapsed_time) open_min_elapsed_time,
Expand Down Expand Up @@ -461,6 +463,7 @@ select rstat.profile_id,
cur.column_num,
rstat.record_source_id,
recsrc.parent_record_source_id,
recsrc.level,
recsrc.access_path
order by coalesce(sum(rstat.open_total_elapsed_time), 0) + coalesce(sum(rstat.fetch_total_elapsed_time), 0) desc
```
2 changes: 1 addition & 1 deletion src/include/firebird/FirebirdInterface.idl
Original file line number Diff line number Diff line change
Expand Up @@ -1744,7 +1744,7 @@ interface ProfilerSession : Disposable
void defineCursor(int64 statementId, uint cursorId, const string name, uint line, uint column);

void defineRecordSource(int64 statementId, uint cursorId, uint recSourceId,
const string accessPath, uint parentRecSourceId);
uint level, const string accessPath, uint parentRecSourceId);

void onRequestStart(Status status, int64 statementId, int64 requestId,
int64 callerStatementId, int64 callerRequestId, ISC_TIMESTAMP_TZ timestamp);
Expand Down
12 changes: 6 additions & 6 deletions src/include/firebird/IdlFbInterfaces.h
Original file line number Diff line number Diff line change
Expand Up @@ -6954,7 +6954,7 @@ namespace Firebird
void (CLOOP_CARG *finish)(IProfilerSession* self, IStatus* status, ISC_TIMESTAMP_TZ timestamp) CLOOP_NOEXCEPT;
void (CLOOP_CARG *defineStatement)(IProfilerSession* self, IStatus* status, ISC_INT64 statementId, ISC_INT64 parentStatementId, const char* type, const char* packageName, const char* routineName, const char* sqlText) CLOOP_NOEXCEPT;
void (CLOOP_CARG *defineCursor)(IProfilerSession* self, ISC_INT64 statementId, unsigned cursorId, const char* name, unsigned line, unsigned column) CLOOP_NOEXCEPT;
void (CLOOP_CARG *defineRecordSource)(IProfilerSession* self, ISC_INT64 statementId, unsigned cursorId, unsigned recSourceId, const char* accessPath, unsigned parentRecSourceId) CLOOP_NOEXCEPT;
void (CLOOP_CARG *defineRecordSource)(IProfilerSession* self, ISC_INT64 statementId, unsigned cursorId, unsigned recSourceId, unsigned level, const char* accessPath, unsigned parentRecSourceId) CLOOP_NOEXCEPT;
void (CLOOP_CARG *onRequestStart)(IProfilerSession* self, IStatus* status, ISC_INT64 statementId, ISC_INT64 requestId, ISC_INT64 callerStatementId, ISC_INT64 callerRequestId, ISC_TIMESTAMP_TZ timestamp) CLOOP_NOEXCEPT;
void (CLOOP_CARG *onRequestFinish)(IProfilerSession* self, IStatus* status, ISC_INT64 statementId, ISC_INT64 requestId, ISC_TIMESTAMP_TZ timestamp, IProfilerStats* stats) CLOOP_NOEXCEPT;
void (CLOOP_CARG *beforePsqlLineColumn)(IProfilerSession* self, ISC_INT64 statementId, ISC_INT64 requestId, unsigned line, unsigned column) CLOOP_NOEXCEPT;
Expand Down Expand Up @@ -7019,9 +7019,9 @@ namespace Firebird
static_cast<VTable*>(this->cloopVTable)->defineCursor(this, statementId, cursorId, name, line, column);
}

void defineRecordSource(ISC_INT64 statementId, unsigned cursorId, unsigned recSourceId, const char* accessPath, unsigned parentRecSourceId)
void defineRecordSource(ISC_INT64 statementId, unsigned cursorId, unsigned recSourceId, unsigned level, const char* accessPath, unsigned parentRecSourceId)
{
static_cast<VTable*>(this->cloopVTable)->defineRecordSource(this, statementId, cursorId, recSourceId, accessPath, parentRecSourceId);
static_cast<VTable*>(this->cloopVTable)->defineRecordSource(this, statementId, cursorId, recSourceId, level, accessPath, parentRecSourceId);
}

template <typename StatusType> void onRequestStart(StatusType* status, ISC_INT64 statementId, ISC_INT64 requestId, ISC_INT64 callerStatementId, ISC_INT64 callerRequestId, ISC_TIMESTAMP_TZ timestamp)
Expand Down Expand Up @@ -20528,11 +20528,11 @@ namespace Firebird
}
}

static void CLOOP_CARG cloopdefineRecordSourceDispatcher(IProfilerSession* self, ISC_INT64 statementId, unsigned cursorId, unsigned recSourceId, const char* accessPath, unsigned parentRecSourceId) CLOOP_NOEXCEPT
static void CLOOP_CARG cloopdefineRecordSourceDispatcher(IProfilerSession* self, ISC_INT64 statementId, unsigned cursorId, unsigned recSourceId, unsigned level, const char* accessPath, unsigned parentRecSourceId) CLOOP_NOEXCEPT
{
try
{
static_cast<Name*>(self)->Name::defineRecordSource(statementId, cursorId, recSourceId, accessPath, parentRecSourceId);
static_cast<Name*>(self)->Name::defineRecordSource(statementId, cursorId, recSourceId, level, accessPath, parentRecSourceId);
}
catch (...)
{
Expand Down Expand Up @@ -20672,7 +20672,7 @@ namespace Firebird
virtual void finish(StatusType* status, ISC_TIMESTAMP_TZ timestamp) = 0;
virtual void defineStatement(StatusType* status, ISC_INT64 statementId, ISC_INT64 parentStatementId, const char* type, const char* packageName, const char* routineName, const char* sqlText) = 0;
virtual void defineCursor(ISC_INT64 statementId, unsigned cursorId, const char* name, unsigned line, unsigned column) = 0;
virtual void defineRecordSource(ISC_INT64 statementId, unsigned cursorId, unsigned recSourceId, const char* accessPath, unsigned parentRecSourceId) = 0;
virtual void defineRecordSource(ISC_INT64 statementId, unsigned cursorId, unsigned recSourceId, unsigned level, const char* accessPath, unsigned parentRecSourceId) = 0;
virtual void onRequestStart(StatusType* status, ISC_INT64 statementId, ISC_INT64 requestId, ISC_INT64 callerStatementId, ISC_INT64 callerRequestId, ISC_TIMESTAMP_TZ timestamp) = 0;
virtual void onRequestFinish(StatusType* status, ISC_INT64 statementId, ISC_INT64 requestId, ISC_TIMESTAMP_TZ timestamp, IProfilerStats* stats) = 0;
virtual void beforePsqlLineColumn(ISC_INT64 statementId, ISC_INT64 requestId, unsigned line, unsigned column) = 0;
Expand Down
14 changes: 7 additions & 7 deletions src/include/gen/Firebird.pas
Original file line number Diff line number Diff line change
Expand Up @@ -727,7 +727,7 @@ ISC_TIMESTAMP_TZ_EX = record
IProfilerSession_finishPtr = procedure(this: IProfilerSession; status: IStatus; timestamp: ISC_TIMESTAMP_TZ); cdecl;
IProfilerSession_defineStatementPtr = procedure(this: IProfilerSession; status: IStatus; statementId: Int64; parentStatementId: Int64; type_: PAnsiChar; packageName: PAnsiChar; routineName: PAnsiChar; sqlText: PAnsiChar); cdecl;
IProfilerSession_defineCursorPtr = procedure(this: IProfilerSession; statementId: Int64; cursorId: Cardinal; name: PAnsiChar; line: Cardinal; column: Cardinal); cdecl;
IProfilerSession_defineRecordSourcePtr = procedure(this: IProfilerSession; statementId: Int64; cursorId: Cardinal; recSourceId: Cardinal; accessPath: PAnsiChar; parentRecSourceId: Cardinal); cdecl;
IProfilerSession_defineRecordSourcePtr = procedure(this: IProfilerSession; statementId: Int64; cursorId: Cardinal; recSourceId: Cardinal; level: Cardinal; accessPath: PAnsiChar; parentRecSourceId: Cardinal); cdecl;
IProfilerSession_onRequestStartPtr = procedure(this: IProfilerSession; status: IStatus; statementId: Int64; requestId: Int64; callerStatementId: Int64; callerRequestId: Int64; timestamp: ISC_TIMESTAMP_TZ); cdecl;
IProfilerSession_onRequestFinishPtr = procedure(this: IProfilerSession; status: IStatus; statementId: Int64; requestId: Int64; timestamp: ISC_TIMESTAMP_TZ; stats: IProfilerStats); cdecl;
IProfilerSession_beforePsqlLineColumnPtr = procedure(this: IProfilerSession; statementId: Int64; requestId: Int64; line: Cardinal; column: Cardinal); cdecl;
Expand Down Expand Up @@ -3838,7 +3838,7 @@ IProfilerSession = class(IDisposable)
procedure finish(status: IStatus; timestamp: ISC_TIMESTAMP_TZ);
procedure defineStatement(status: IStatus; statementId: Int64; parentStatementId: Int64; type_: PAnsiChar; packageName: PAnsiChar; routineName: PAnsiChar; sqlText: PAnsiChar);
procedure defineCursor(statementId: Int64; cursorId: Cardinal; name: PAnsiChar; line: Cardinal; column: Cardinal);
procedure defineRecordSource(statementId: Int64; cursorId: Cardinal; recSourceId: Cardinal; accessPath: PAnsiChar; parentRecSourceId: Cardinal);
procedure defineRecordSource(statementId: Int64; cursorId: Cardinal; recSourceId: Cardinal; level: Cardinal; accessPath: PAnsiChar; parentRecSourceId: Cardinal);
procedure onRequestStart(status: IStatus; statementId: Int64; requestId: Int64; callerStatementId: Int64; callerRequestId: Int64; timestamp: ISC_TIMESTAMP_TZ);
procedure onRequestFinish(status: IStatus; statementId: Int64; requestId: Int64; timestamp: ISC_TIMESTAMP_TZ; stats: IProfilerStats);
procedure beforePsqlLineColumn(statementId: Int64; requestId: Int64; line: Cardinal; column: Cardinal);
Expand All @@ -3859,7 +3859,7 @@ IProfilerSessionImpl = class(IProfilerSession)
procedure finish(status: IStatus; timestamp: ISC_TIMESTAMP_TZ); virtual; abstract;
procedure defineStatement(status: IStatus; statementId: Int64; parentStatementId: Int64; type_: PAnsiChar; packageName: PAnsiChar; routineName: PAnsiChar; sqlText: PAnsiChar); virtual; abstract;
procedure defineCursor(statementId: Int64; cursorId: Cardinal; name: PAnsiChar; line: Cardinal; column: Cardinal); virtual; abstract;
procedure defineRecordSource(statementId: Int64; cursorId: Cardinal; recSourceId: Cardinal; accessPath: PAnsiChar; parentRecSourceId: Cardinal); virtual; abstract;
procedure defineRecordSource(statementId: Int64; cursorId: Cardinal; recSourceId: Cardinal; level: Cardinal; accessPath: PAnsiChar; parentRecSourceId: Cardinal); virtual; abstract;
procedure onRequestStart(status: IStatus; statementId: Int64; requestId: Int64; callerStatementId: Int64; callerRequestId: Int64; timestamp: ISC_TIMESTAMP_TZ); virtual; abstract;
procedure onRequestFinish(status: IStatus; statementId: Int64; requestId: Int64; timestamp: ISC_TIMESTAMP_TZ; stats: IProfilerStats); virtual; abstract;
procedure beforePsqlLineColumn(statementId: Int64; requestId: Int64; line: Cardinal; column: Cardinal); virtual; abstract;
Expand Down Expand Up @@ -9428,9 +9428,9 @@ procedure IProfilerSession.defineCursor(statementId: Int64; cursorId: Cardinal;
ProfilerSessionVTable(vTable).defineCursor(Self, statementId, cursorId, name, line, column);
end;

procedure IProfilerSession.defineRecordSource(statementId: Int64; cursorId: Cardinal; recSourceId: Cardinal; accessPath: PAnsiChar; parentRecSourceId: Cardinal);
procedure IProfilerSession.defineRecordSource(statementId: Int64; cursorId: Cardinal; recSourceId: Cardinal; level: Cardinal; accessPath: PAnsiChar; parentRecSourceId: Cardinal);
begin
ProfilerSessionVTable(vTable).defineRecordSource(Self, statementId, cursorId, recSourceId, accessPath, parentRecSourceId);
ProfilerSessionVTable(vTable).defineRecordSource(Self, statementId, cursorId, recSourceId, level, accessPath, parentRecSourceId);
end;

procedure IProfilerSession.onRequestStart(status: IStatus; statementId: Int64; requestId: Int64; callerStatementId: Int64; callerRequestId: Int64; timestamp: ISC_TIMESTAMP_TZ);
Expand Down Expand Up @@ -16541,10 +16541,10 @@ procedure IProfilerSessionImpl_defineCursorDispatcher(this: IProfilerSession; st
end
end;

procedure IProfilerSessionImpl_defineRecordSourceDispatcher(this: IProfilerSession; statementId: Int64; cursorId: Cardinal; recSourceId: Cardinal; accessPath: PAnsiChar; parentRecSourceId: Cardinal); cdecl;
procedure IProfilerSessionImpl_defineRecordSourceDispatcher(this: IProfilerSession; statementId: Int64; cursorId: Cardinal; recSourceId: Cardinal; level: Cardinal; accessPath: PAnsiChar; parentRecSourceId: Cardinal); cdecl;
begin
try
IProfilerSessionImpl(this).defineRecordSource(statementId, cursorId, recSourceId, accessPath, parentRecSourceId);
IProfilerSessionImpl(this).defineRecordSource(statementId, cursorId, recSourceId, level, accessPath, parentRecSourceId);
except
on e: Exception do FbException.catchException(nil, e);
end
Expand Down
90 changes: 61 additions & 29 deletions src/jrd/ProfilerManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -475,13 +475,17 @@ void ProfilerManager::prepareCursor(thread_db* tdbb, Request* request, const Sel

auto cursorId = select->getCursorId();

if (profileStatement->definedCursors.exist(cursorId))
return;
if (!profileStatement->definedCursors.exist(cursorId))
{
currentSession->pluginSession->defineCursor(profileStatement->id, cursorId,
select->getName().nullStr(), select->getLine(), select->getColumn());

currentSession->pluginSession->defineCursor(profileStatement->id, cursorId,
select->getName().nullStr(), select->getLine(), select->getColumn());
profileStatement->definedCursors.add(cursorId);
}

profileStatement->definedCursors.add(cursorId);
const auto recordSource = select->getAccessPath();

prepareRecSource(tdbb, request, recordSource);
}

void ProfilerManager::prepareRecSource(thread_db* tdbb, Request* request, const RecordSource* rsb)
Expand All @@ -496,35 +500,32 @@ void ProfilerManager::prepareRecSource(thread_db* tdbb, Request* request, const

fb_assert(profileStatement->definedCursors.exist(rsb->getCursorId()));

Array<NonPooledPair<const RecordSource*, const RecordSource*>> tree;
tree.add({rsb, nullptr});

for (unsigned pos = 0; pos < tree.getCount(); ++pos)
struct PlanItem : PermanentStorage
{
const auto thisRsb = tree[pos].first;

Array<const RecordSource*> children;
thisRsb->getChildren(children);

unsigned childPos = pos;
explicit PlanItem(MemoryPool& p)
: PermanentStorage(p)
{
}

for (const auto child : children)
tree.insert(++childPos, {child, thisRsb});
}
const RecordSource* recordSource = nullptr;
const RecordSource* parentRecordSource = nullptr;
string accessPath{getPool()};
unsigned level = 0;
};

NonPooledMap<ULONG, ULONG> idSequenceMap;
auto sequencePtr = profileStatement->cursorNextSequence.getOrPut(rsb->getCursorId());
ObjectsArray<PlanItem> planItems;
planItems.add().recordSource = rsb;

for (const auto& pair : tree)
for (unsigned pos = 0; pos < planItems.getCount(); ++pos)
{
const auto cursorId = pair.first->getCursorId();
const auto recSourceId = pair.first->getRecSourceId();
idSequenceMap.put(recSourceId, ++*sequencePtr);
auto& planItem = planItems[pos];
const auto thisRsb = planItem.recordSource;

string accessPath;
pair.first->print(tdbb, accessPath, true, 0, false);
string& accessPath = planItem.accessPath;
thisRsb->print(tdbb, accessPath, true, 0, false);

constexpr auto INDENT_MARKER = "\n ";
constexpr unsigned INDENT_COUNT = 4;

if (accessPath.find(INDENT_MARKER) == 0)
{
Expand All @@ -535,13 +536,44 @@ void ProfilerManager::prepareRecSource(thread_db* tdbb, Request* request, const
} while ((pos = accessPath.find(INDENT_MARKER, pos + 1)) != string::npos);
}

if (accessPath.hasData() && accessPath[0] == '\n')
accessPath.erase(0, 1);

Array<const RecordSource*> children;
thisRsb->getChildren(children);

unsigned level = planItem.level;

if (const auto lastLinePos = accessPath.find_last_of('\n'); lastLinePos != string::npos)
level += (accessPath.find_first_not_of(' ', lastLinePos + 1) - lastLinePos + 1) / INDENT_COUNT;

unsigned childPos = pos;

for (const auto child : children)
{
auto& inserted = planItems.insert(++childPos);
inserted.recordSource = child;
inserted.parentRecordSource = thisRsb;
inserted.level = level + 1;
}
}

NonPooledMap<ULONG, ULONG> idSequenceMap;
auto sequencePtr = profileStatement->cursorNextSequence.getOrPut(rsb->getCursorId());

for (const auto& planItem : planItems)
{
const auto cursorId = planItem.recordSource->getCursorId();
const auto recSourceId = planItem.recordSource->getRecSourceId();
idSequenceMap.put(recSourceId, ++*sequencePtr);

ULONG parentSequence = 0;

if (pair.second)
parentSequence = *idSequenceMap.get(pair.second->getRecSourceId());
if (planItem.parentRecordSource)
parentSequence = *idSequenceMap.get(planItem.parentRecordSource->getRecSourceId());

currentSession->pluginSession->defineRecordSource(profileStatement->id, cursorId,
*sequencePtr, accessPath.c_str(), parentSequence);
*sequencePtr, planItem.level, planItem.accessPath.c_str(), parentSequence);

profileStatement->recSourceSequence.put(recSourceId, *sequencePtr);
}
Expand Down
Loading

0 comments on commit c86bd3d

Please sign in to comment.