@@ -42,87 +42,90 @@ class CHotspotEventVisitor : public CInterfaceOf<IEventVisitor>
4242 Range range{std::numeric_limits<bucket_type>::max (), 0 };
4343
4444 Activity () = default ;
45+
4546 bool hasActivity () const
4647 {
4748 return !buckets.empty ();
4849 }
50+
51+ void recordEvent (bucket_type bucket)
52+ {
53+ bucket_type key = bucket2activityKey (bucket);
54+ unsigned short index = bucket2activityIndex (bucket);
55+ buckets[key][index]++;
56+ if (bucket < range.first )
57+ range.first = bucket;
58+ if (bucket > range.second )
59+ range.second = bucket;
60+ }
61+
62+ void forEachBucket (IBucketVisitor& visitor, NodeKind nodeKind)
63+ {
64+ if (!hasActivity ())
65+ return ;
66+ for (bucket_type bucket = range.first ; bucket <= range.second ; bucket++)
67+ {
68+ stat_type events = queryBucket (buckets, bucket);
69+ if (events)
70+ visitor.visitBucket (bucket, nodeKind, events);
71+ }
72+ }
73+
74+ protected:
75+ bucket_type bucket2activityKey (offset_t bucket)
76+ {
77+ return bucket >> bucketArrayBits;
78+ }
79+
80+ unsigned short bucket2activityIndex (offset_t bucket)
81+ {
82+ return bucket & bucketArrayMask;
83+ }
84+
85+ stat_type queryBucket (const Buckets& buckets, bucket_type bucket)
86+ {
87+ Buckets::const_iterator it = buckets.find (bucket2activityKey (bucket));
88+ if (it != buckets.end ())
89+ return it->second [bucket2activityIndex (bucket)];
90+ return 0 ;
91+ }
4992 };
5093 public:
51- CActivity (CHotspotEventVisitor& _container , __uint64 _id)
52- : container(_container )
94+ CActivity (CMetaInfoState& _metaInfoState , __uint64 _id)
95+ : metaInfoState(_metaInfoState )
5396 , id(_id)
5497 {
5598 }
5699
57- void recordEvent (offset_t offset, NodeKind nodeKind)
100+ void recordEvent (offset_t offset, NodeKind nodeKind, byte granularityBits )
58101 {
59- bucket_type bucket = page2bucket (offset2page (offset, defaultPageBits), granularityBits ());
60- bucket_type key = bucket2activityKey (bucket);
61- unsigned short index = bucket2activityIndex (bucket);
62- activity[nodeKind].buckets [key][index]++;
63- if (bucket < activity[nodeKind].range .first )
64- activity[nodeKind].range .first = bucket;
65- if (bucket > activity[nodeKind].range .second )
66- activity[nodeKind].range .second = bucket;
102+ activity[nodeKind].recordEvent (page2bucket (offset2page (offset, defaultPageBits), granularityBits));
67103 }
68104
69105 void forEachBucket (IBucketVisitor& visitor)
70106 {
71- const char * path = container.operation .queryMetaInfoState ().queryFilePath (id);
72107 if (!hasActivity ()) // suppress inactive files
73108 return ;
109+ const char * path = metaInfoState.queryFilePath (id);
74110 visitor.arrive (id, path);
75111 for (unsigned kind = 0 ; kind < NumNodeKinds; kind++)
76- {
77- Activity& act = activity[kind];
78- if (act.hasActivity ())
79- {
80- for (bucket_type bucket = act.range .first ; bucket <= act.range .second ; bucket++)
81- {
82- stat_type events = queryBucket (act.buckets , bucket);
83- if (events)
84- visitor.visitBucket (bucket, NodeKind (kind), events);
85- }
86- }
87- }
112+ activity[kind].forEachBucket (visitor, NodeKind (kind));
88113 visitor.depart ();
89114 }
90115
91116 protected:
92- inline byte granularityBits () const
93- {
94- return container.granularityBits ;
95- }
96- inline bucket_type bucket2activityKey (offset_t bucket)
97- {
98- return bucket >> bucketArrayBits;
99- }
100-
101- inline unsigned short bucket2activityIndex (offset_t bucket)
102- {
103- return bucket & bucketArrayMask;
104- }
105-
106- stat_type queryBucket (const Buckets& buckets, bucket_type bucket)
107- {
108- Buckets::const_iterator it = buckets.find (bucket2activityKey (bucket));
109- if (it != buckets.end ())
110- return it->second [bucket2activityIndex (bucket)];
111- return 0 ;
112- }
113-
114117 bool hasActivity () const
115118 {
116- for (const Activity& act : activity )
119+ for (unsigned kind = 0 ; kind < NumNodeKinds; kind++ )
117120 {
118- if (act .hasActivity ())
121+ if (activity[kind] .hasActivity ())
119122 return true ;
120123 }
121124 return false ;
122125 }
123126
124127 private:
125- CHotspotEventVisitor& container; // back reference to obtain shared configuration
128+ CMetaInfoState& metaInfoState;
126129 __uint64 id{0 };
127130 Activity activity[NumNodeKinds];
128131 };
@@ -135,41 +138,43 @@ class CHotspotEventVisitor : public CInterfaceOf<IEventVisitor>
135138
136139 virtual bool visitEvent (CEvent& event) override
137140 {
138- if (event.hasAttribute (EvAttrFileId))
139- {
140- EventType type = event.queryType ();
141- if (type == MetaFileInformation || observedEvents.count (type) == 0 )
142- return true ;
143- __uint64 fileId = event.queryNumericValue (EvAttrFileId);
144- auto [it, inserted] = activity.try_emplace (fileId, *this , fileId);
145- NodeKind nodeKind = queryIndexNodeKind (event);
146- it->second .recordEvent (event.queryNumericValue (EvAttrFileOffset), nodeKind);
147- }
141+ EventType type = event.queryType ();
142+ if (MetaFileInformation == type)
143+ return true ;
144+ if (observedEvents.find (type) == observedEvents.end ())
145+ return true ;
146+ __uint64 fileId = event.queryNumericValue (EvAttrFileId);
147+ NodeKind nodeKind = queryIndexNodeKind (event);
148+ auto [it, inserted] = activity.try_emplace (fileId, operation.queryMetaInfoState (), fileId);
149+ it->second .recordEvent (event.queryNumericValue (EvAttrFileOffset), nodeKind, granularityBits);
148150 return true ;
149151 }
150152
151- virtual void departFile (uint32_t bytesRead ) override
153+ virtual void departFile (uint32_t ) override
152154 {
153- analyzer->begin (observedEvents, granularityBits);
154- for (auto & [fileId, activity] : activity)
155- activity.forEachBucket (*analyzer);
156- analyzer->end ();
155+ // Intentionally empty.
157156 }
158157
159158public:
160- CHotspotEventVisitor (CIndexHotspotOp& _operation, IBucketVisitor& _analyzer, const std::set<EventType>& _observedEvents, byte _granularityBits)
159+ CHotspotEventVisitor (CIndexHotspotOp& _operation, const std::set<EventType>& _observedEvents, byte _granularityBits)
161160 : operation(_operation)
162- , analyzer(&_analyzer)
163161 , granularityBits(_granularityBits)
164162 , observedEvents(_observedEvents)
165163 {
166164 }
167165
166+ void generateReport (IBucketVisitor& analyzer)
167+ {
168+ analyzer.begin (observedEvents, granularityBits);
169+ for (auto & [fileId, activity] : activity)
170+ activity.forEachBucket (analyzer);
171+ analyzer.end ();
172+ }
173+
168174private:
169175 CIndexHotspotOp& operation;
170176 // map file id (as __uint64 due to visitor interface) to index activity
171177 using Activity = std::map<__uint64, CActivity>;
172- Linked<IBucketVisitor> analyzer;
173178 byte granularityBits{0 };
174179 Activity activity;
175180 std::set<EventType> observedEvents;
@@ -182,14 +187,18 @@ bool CIndexHotspotOp::ready() const
182187
183188bool CIndexHotspotOp::doOp ()
184189{
185- Owned<IBucketVisitor> analyzer;
186- if (limit)
187- analyzer.setown (createTopBucketVisitor (*out, limit));
188- else
189- analyzer.setown (createAllBucketVisitor (*out));
190-
191- CHotspotEventVisitor visitor (*this , *analyzer, observedEvents, granularityBits);
192- return traverseEvents (inputPath, visitor);
190+ Owned<CHotspotEventVisitor> visitor = new CHotspotEventVisitor (*this , observedEvents, granularityBits);
191+ if (traverseEvents (inputPath, *visitor))
192+ {
193+ Owned<IBucketVisitor> analyzer;
194+ if (limit)
195+ analyzer.setown (createTopBucketVisitor (*out, limit));
196+ else
197+ analyzer.setown (createAllBucketVisitor (*out));
198+ visitor->generateReport (*analyzer);
199+ return true ;
200+ }
201+ return false ;
193202}
194203
195204void CIndexHotspotOp::addObservedEvent (EventType observedEvent)
0 commit comments