2525
2626#include " firebird.h"
2727#include " firebird/Message.h"
28+ #include " ../common/PerformanceStopWatch.h"
2829#include " ../common/classes/auto.h"
2930#include " ../common/classes/fb_string.h"
3031#include " ../common/classes/Nullable.h"
3132#include " ../common/classes/RefCounted.h"
3233#include " ../common/classes/TimerImpl.h"
34+ #include " ../jrd/recsrc/RecordSource.h"
35+ #include " ../jrd/req.h"
3336#include " ../jrd/SystemPackages.h"
3437
3538namespace Jrd {
@@ -43,7 +46,7 @@ class thread_db;
4346class ProfilerListener ;
4447
4548
46- class ProfilerManager final
49+ class ProfilerManager final : public Firebird::PerformanceStopWatch
4750{
4851 friend class ProfilerListener ;
4952 friend class ProfilerPackage ;
@@ -66,6 +69,70 @@ class ProfilerManager final
6669 FB_UINT64 elapsedTicks;
6770 };
6871
72+ class RecordSourceStopWatcher final
73+ {
74+ public:
75+ enum class Event
76+ {
77+ OPEN,
78+ GET_RECORD
79+ };
80+
81+ public:
82+ RecordSourceStopWatcher (thread_db* tdbb, const RecordSource* aRecordSource, Event aEvent)
83+ : recordSource(aRecordSource),
84+ event (aEvent)
85+ {
86+ const auto attachment = tdbb->getAttachment ();
87+ request = tdbb->getRequest ();
88+
89+ profilerManager = attachment->isProfilerActive () && !request->hasInternalStatement () ?
90+ attachment->getProfilerManager (tdbb) :
91+ nullptr ;
92+
93+ if (profilerManager)
94+ {
95+ lastTicks = profilerManager->queryTicks ();
96+
97+ profilerManager->prepareRecSource (tdbb, request, recordSource);
98+
99+ if (profilerManager->currentSession ->flags & Firebird::IProfilerSession::FLAG_BEFORE_EVENTS)
100+ {
101+ if (event == Event::OPEN)
102+ profilerManager->beforeRecordSourceOpen (request, recordSource);
103+ else
104+ profilerManager->beforeRecordSourceGetRecord (request, recordSource);
105+ }
106+
107+ lastAccumulatedOverhead = profilerManager->getAccumulatedOverhead ();
108+ }
109+ }
110+
111+ ~RecordSourceStopWatcher ()
112+ {
113+ if (profilerManager)
114+ {
115+ const SINT64 currentTicks = profilerManager->queryTicks ();
116+ const SINT64 elapsedTicks = profilerManager->getElapsedTicksAndAdjustOverhead (
117+ currentTicks, lastTicks, lastAccumulatedOverhead);
118+ Stats stats (elapsedTicks);
119+
120+ if (event == Event::OPEN)
121+ profilerManager->afterRecordSourceOpen (request, recordSource, stats);
122+ else
123+ profilerManager->afterRecordSourceGetRecord (request, recordSource, stats);
124+ }
125+ }
126+
127+ private:
128+ const RecordSource* recordSource;
129+ Request* request;
130+ ProfilerManager* profilerManager;
131+ SINT64 lastTicks;
132+ SINT64 lastAccumulatedOverhead;
133+ Event event;
134+ };
135+
69136private:
70137 class Statement final
71138 {
@@ -126,12 +193,70 @@ class ProfilerManager final
126193 void prepareCursor (thread_db* tdbb, Request* request, const Select* select);
127194 void prepareRecSource (thread_db* tdbb, Request* request, const RecordSource* rsb);
128195 void onRequestFinish (Request* request, Stats& stats);
129- void beforePsqlLineColumn (Request* request, ULONG line, ULONG column);
130- void afterPsqlLineColumn (Request* request, ULONG line, ULONG column, Stats& stats);
131- void beforeRecordSourceOpen (Request* request, const RecordSource* rsb);
132- void afterRecordSourceOpen (Request* request, const RecordSource* rsb, Stats& stats);
133- void beforeRecordSourceGetRecord (Request* request, const RecordSource* rsb);
134- void afterRecordSourceGetRecord (Request* request, const RecordSource* rsb, Stats& stats);
196+
197+ void beforePsqlLineColumn (Request* request, ULONG line, ULONG column)
198+ {
199+ if (const auto profileRequestId = getRequest (request, Firebird::IProfilerSession::FLAG_BEFORE_EVENTS))
200+ currentSession->pluginSession ->beforePsqlLineColumn (profileRequestId, line, column);
201+ }
202+
203+ void afterPsqlLineColumn (Request* request, ULONG line, ULONG column, Stats& stats)
204+ {
205+ if (const auto profileRequestId = getRequest (request, Firebird::IProfilerSession::FLAG_AFTER_EVENTS))
206+ currentSession->pluginSession ->afterPsqlLineColumn (profileRequestId, line, column, &stats);
207+ }
208+
209+ void beforeRecordSourceOpen (Request* request, const RecordSource* rsb)
210+ {
211+ if (const auto profileRequestId = getRequest (request, Firebird::IProfilerSession::FLAG_BEFORE_EVENTS))
212+ {
213+ const auto profileStatement = getStatement (request);
214+ const auto sequencePtr = profileStatement->recSourceSequence .get (rsb->getRecSourceProfileId ());
215+ fb_assert (sequencePtr);
216+
217+ currentSession->pluginSession ->beforeRecordSourceOpen (
218+ profileRequestId, rsb->getCursorProfileId (), *sequencePtr);
219+ }
220+ }
221+
222+ void afterRecordSourceOpen (Request* request, const RecordSource* rsb, Stats& stats)
223+ {
224+ if (const auto profileRequestId = getRequest (request, Firebird::IProfilerSession::FLAG_AFTER_EVENTS))
225+ {
226+ const auto profileStatement = getStatement (request);
227+ const auto sequencePtr = profileStatement->recSourceSequence .get (rsb->getRecSourceProfileId ());
228+ fb_assert (sequencePtr);
229+
230+ currentSession->pluginSession ->afterRecordSourceOpen (
231+ profileRequestId, rsb->getCursorProfileId (), *sequencePtr, &stats);
232+ }
233+ }
234+
235+ void beforeRecordSourceGetRecord (Request* request, const RecordSource* rsb)
236+ {
237+ if (const auto profileRequestId = getRequest (request, Firebird::IProfilerSession::FLAG_BEFORE_EVENTS))
238+ {
239+ const auto profileStatement = getStatement (request);
240+ const auto sequencePtr = profileStatement->recSourceSequence .get (rsb->getRecSourceProfileId ());
241+ fb_assert (sequencePtr);
242+
243+ currentSession->pluginSession ->beforeRecordSourceGetRecord (
244+ profileRequestId, rsb->getCursorProfileId (), *sequencePtr);
245+ }
246+ }
247+
248+ void afterRecordSourceGetRecord (Request* request, const RecordSource* rsb, Stats& stats)
249+ {
250+ if (const auto profileRequestId = getRequest (request, Firebird::IProfilerSession::FLAG_AFTER_EVENTS))
251+ {
252+ const auto profileStatement = getStatement (request);
253+ const auto sequencePtr = profileStatement->recSourceSequence .get (rsb->getRecSourceProfileId ());
254+ fb_assert (sequencePtr);
255+
256+ currentSession->pluginSession ->afterRecordSourceGetRecord (
257+ profileRequestId, rsb->getCursorProfileId (), *sequencePtr, &stats);
258+ }
259+ }
135260
136261 bool isActive () const
137262 {
@@ -161,7 +286,39 @@ class ProfilerManager final
161286 void updateFlushTimer (bool canStopTimer = true );
162287
163288 Statement* getStatement (Request* request);
164- SINT64 getRequest (Request* request, unsigned flags);
289+
290+ SINT64 getRequest (Request* request, unsigned flags)
291+ {
292+ using namespace Firebird ;
293+
294+ if (!isActive () || (flags && !(currentSession->flags & flags)))
295+ return 0 ;
296+
297+ const auto mainRequestId = request->getRequestId ();
298+
299+ if (!currentSession->requests .exist (mainRequestId))
300+ {
301+ const auto timestamp = TimeZoneUtil::getCurrentTimeStamp (request->req_attachment ->att_current_timezone );
302+
303+ do
304+ {
305+ getStatement (request); // define the statement and ignore the result
306+
307+ const StmtNumber callerRequestId = request->req_caller ? request->req_caller ->getRequestId () : 0 ;
308+
309+ LogLocalStatus status (" Profiler onRequestStart" );
310+ currentSession->pluginSession ->onRequestStart (&status,
311+ (SINT64) request->getRequestId (), (SINT64) request->getStatement ()->getStatementId (),
312+ (SINT64) callerRequestId, timestamp);
313+
314+ currentSession->requests .add (request->getRequestId ());
315+
316+ request = request->req_caller ;
317+ } while (request && !currentSession->requests .exist (request->getRequestId ()));
318+ }
319+
320+ return mainRequestId;
321+ }
165322
166323private:
167324 Firebird::AutoPtr<ProfilerListener> listener;
0 commit comments