Panda3D
Loading...
Searching...
No Matches
pStatPianoRoll.cxx
Go to the documentation of this file.
1/**
2 * PANDA 3D SOFTWARE
3 * Copyright (c) Carnegie Mellon University. All rights reserved.
4 *
5 * All use of this software is subject to the terms of the revised BSD
6 * license. You should have received a copy of this license along
7 * with this source code in a file named "LICENSE."
8 *
9 * @file pStatPianoRoll.cxx
10 * @author drose
11 * @date 2000-07-18
12 */
13
14#include "pStatPianoRoll.h"
15
16#include "pStatFrameData.h"
17#include "pStatCollectorDef.h"
18#include "string_utils.h"
19#include "config_pstatclient.h"
20
21#include <algorithm>
22
23/**
24 * This class is used internally to build up the set of color bars defined by
25 * a frame's worth of data.
26 */
27PStatPianoRoll::BarBuilder::
28BarBuilder() {
29 _is_new = true;
30}
31
32/**
33 * Resets the data in the BarBuilder for a new frame.
34 */
35void PStatPianoRoll::BarBuilder::
36clear() {
37 _is_new = false;
38 _color_bars.clear();
39}
40
41/**
42 * Adds a new data point. The first data point for a given collector turns in
43 * on (starts the bar), the second data point turns it off (ends the bar).
44 */
45void PStatPianoRoll::BarBuilder::
46add_data_point(double time, bool is_start) {
47 if (is_start) {
48 // This is a "start" data point: start the bar.
49 if (_color_bars.empty() || _color_bars.back()._end >= 0.0) {
50 ColorBar bar;
51 bar._start = time;
52 bar._end = -1.0;
53 _color_bars.push_back(bar);
54 }
55
56 } else {
57 // This is a "stop" data point: end the bar.
58 if (_color_bars.empty()) {
59 // A "stop" in the middle of the frame implies a "start" at time 0.
60 ColorBar bar;
61 bar._start = 0.0;
62 bar._end = time;
63 _color_bars.push_back(bar);
64
65 } else {
66 _color_bars.back()._end = time;
67 }
68 }
69}
70
71/**
72 * Makes sure that each start-bar data point was matched by a corresponding
73 * end-bar data point.
74 */
75void PStatPianoRoll::BarBuilder::
76finish(double time) {
77 if (!_color_bars.empty() && _color_bars.back()._end < 0.0) {
78 _color_bars.back()._end = time;
79 }
80}
81
82/**
83 *
84 */
85PStatPianoRoll::
86PStatPianoRoll(PStatMonitor *monitor, int thread_index, int xsize, int ysize) :
87 PStatGraph(monitor, xsize, ysize),
88 _thread_index(thread_index)
89{
90 _time_width = 1.0 / pstats_target_frame_rate;
91 _start_time = 0.0;
92
93 _current_frame = -1;
94 _guide_bar_units = GBU_ms | GBU_hz | GBU_show_units;
95 normal_guide_bars();
96}
97
98/**
99 *
100 */
101PStatPianoRoll::
102~PStatPianoRoll() {
103}
104
105/**
106 * Updates the chart with the latest data.
107 */
109update() {
110 const PStatClientData *client_data = _monitor->get_client_data();
111
112 // Don't bother to update the thread data until we know at least something
113 // about the collectors and threads.
114 if (client_data->get_num_collectors() != 0 &&
115 client_data->get_num_threads() != 0) {
116 const PStatThreadData *thread_data =
117 client_data->get_thread_data(_thread_index);
118 if (!thread_data->is_empty()) {
119 int frame_number = thread_data->get_latest_frame_number();
120 if (frame_number != _current_frame) {
121 compute_page(thread_data->get_frame(frame_number));
122 _current_frame = frame_number;
123 force_redraw();
124 }
125 }
126 }
127
128 idle();
129}
130
131/**
132 * To be called by the user class when the widget size has changed. This
133 * updates the chart's internal data and causes it to issue redraw commands to
134 * reflect the new size.
135 */
136void PStatPianoRoll::
137changed_size(int xsize, int ysize) {
138 if (xsize != _xsize || ysize != _ysize) {
139 _xsize = xsize;
140 _ysize = ysize;
141
142 normal_guide_bars();
143 force_redraw();
144 }
145}
146
147/**
148 * To be called by the user class when the whole thing needs to be redrawn for
149 * some reason.
150 */
151void PStatPianoRoll::
152force_redraw() {
153 if (!_labels.empty()) {
154 begin_draw();
155 for (int i = 0; i < (int)_labels.size(); i++) {
156 int collector_index = _labels[i];
157 const ColorBars &bars = _page_data[collector_index]._color_bars;
158
159 begin_row(i);
160 ColorBars::const_iterator bi;
161 for (bi = bars.begin(); bi != bars.end(); ++bi) {
162 const ColorBar &bar = (*bi);
163 draw_bar(i, timestamp_to_pixel(bar._start), timestamp_to_pixel(bar._end));
164 }
165 end_row(i);
166 }
167 end_draw();
168 }
169}
170
171/**
172 * Calls update_guide_bars with parameters suitable to this kind of graph.
173 */
174void PStatPianoRoll::
175normal_guide_bars() {
176 // We want vaguely 100 pixels between guide bars.
177 update_guide_bars(get_xsize() / 100, _time_width);
178}
179
180/**
181 * Should be overridden by the user class. This hook will be called before
182 * drawing any bars in the chart.
183 */
184void PStatPianoRoll::
185begin_draw() {
186}
187
188/**
189 * Should be overridden by the user class. This hook will be called before
190 * drawing any one row of bars. These bars correspond to the collector whose
191 * index is get_row_collector(row), and in the color get_row_color(row).
192 */
193void PStatPianoRoll::
194begin_row(int) {
195}
196
197/**
198 * Draws a single bar in the chart for the indicated row, in the color
199 * get_row_color(row), for the indicated horizontal pixel range.
200 */
201void PStatPianoRoll::
202draw_bar(int, int, int) {
203}
204
205/**
206 * Should be overridden by the user class. This hook will be called after
207 * drawing a series of color bars for a single row.
208 */
209void PStatPianoRoll::
210end_row(int) {
211}
212
213/**
214 * Should be overridden by the user class. This hook will be called after
215 * drawing a series of color bars in the chart.
216 */
217void PStatPianoRoll::
218end_draw() {
219}
220
221/**
222 * Should be overridden by the user class to perform any other updates might
223 * be necessary after the bars have been redrawn.
224 */
225void PStatPianoRoll::
226idle() {
227}
228
229
230// STL function object for sorting labels in order by the collector's sort
231// index, used in compute_page(), below.
232class SortCollectorLabels1 {
233public:
234 SortCollectorLabels1(const PStatClientData *client_data) :
235 _client_data(client_data) {
236 }
237 bool operator () (int a, int b) const {
238 return
239 _client_data->get_collector_def(a)._sort >
240 _client_data->get_collector_def(b)._sort;
241 }
242 const PStatClientData *_client_data;
243};
244
245/**
246 * Examines the given frame data and rebuilds the _page_data to match it.
247 */
248void PStatPianoRoll::
249compute_page(const PStatFrameData &frame_data) {
250 _start_time = frame_data.get_start();
251
252 // Clear out the page data and copy it to previous, so we can fill it up
253 // again and then check to see if we changed the set of bars this frame.
254 PageData previous;
255 _page_data.swap(previous);
256
257 int num_events = frame_data.get_num_events();
258 for (int i = 0; i < num_events; i++) {
259 int collector_index = frame_data.get_time_collector(i);
260 double time = frame_data.get_time(i);
261 bool is_start = frame_data.is_start(i);
262 _page_data[collector_index].add_data_point(time, is_start);
263 }
264
265 // Now check to see if the set of bars has changed.
266 bool changed_bars = (_page_data.size() != previous.size());
267
268 if (!changed_bars) {
269 PageData::const_iterator ai, bi;
270 ai = _page_data.begin();
271 bi = previous.begin();
272 while (ai != _page_data.end() && !changed_bars) {
273 changed_bars = ((*ai).first == (*bi).first);
274 ++ai;
275 ++bi;
276 }
277 }
278
279 if (changed_bars) {
280 // If we added or removed some new bars this time, we'll have to update
281 // our list.
282 const PStatClientData *client_data = _monitor->get_client_data();
283
284 _labels.clear();
285 PageData::const_iterator pi;
286 for (pi = _page_data.begin(); pi != _page_data.end(); ++pi) {
287 int collector_index = (*pi).first;
288 if (client_data->has_collector(collector_index)) {
289 _labels.push_back(collector_index);
290 }
291 }
292
293 SortCollectorLabels1 sort_labels(client_data);
294 sort(_labels.begin(), _labels.end(), sort_labels);
295
296 _labels_changed = true;
297 }
298
299 // Finally, make sure all of the bars are closed.
300 double time = frame_data.get_end();
301 PageData::iterator pi;
302 for (pi = _page_data.begin(); pi != _page_data.end(); ++pi) {
303 (*pi).second.finish(time);
304 }
305}
The data associated with a particular client, but not with any one particular frame or thread: the li...
const PStatCollectorDef & get_collector_def(int index) const
Returns the nth collector definition.
int get_num_threads() const
Returns the total number of threads the Data knows about.
const PStatThreadData * get_thread_data(int index) const
Returns the data associated with the indicated thread.
int get_num_collectors() const
Returns the total number of collectors the Data knows about.
bool has_collector(int index) const
Returns true if the indicated collector has been defined by the client already, false otherwise.
Contains the raw timing and level data for a single frame.
double get_end() const
Returns the time of the last data point in the frame data.
double get_time(size_t n) const
Returns the timestamp of the nth event, in seconds elapsed since some undefined epoch (which is guara...
int get_time_collector(size_t n) const
Returns the index of the collector associated with the nth event.
bool is_start(size_t n) const
Returns true if the nth event represents a start event, or false if it represents a stop event.
double get_start() const
Returns the time of the first data point in the frame data.
size_t get_num_events() const
Returns the number of individual events stored in the FrameData.
This is an abstract base class for several different kinds of graphs that have a few things in common...
Definition pStatGraph.h:33
int get_xsize() const
Returns the width of the chart in pixels.
Definition pStatGraph.I:82
This is an abstract class that presents the interface to any number of different front-ends for the s...
void update()
Updates the chart with the latest data.
int timestamp_to_pixel(double time) const
Converts a timestamp to a horizontal pixel offset.
A collection of FrameData structures for recently-received frames within a particular thread.
bool is_empty() const
Returns true if the structure contains no frames, false otherwise.
const PStatFrameData & get_frame(int frame_number) const
Returns a FrameData structure associated with the indicated frame number.
int get_latest_frame_number() const
Returns the frame number of the most recent frame stored in the data.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.