Panda3D
pStatStripChart.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 pStatStripChart.cxx
10 * @author drose
11 * @date 2000-07-15
12 */
13
14#include "pStatStripChart.h"
15#include "pStatClientData.h"
16#include "pStatMonitor.h"
17
18#include "pStatFrameData.h"
19#include "pStatCollectorDef.h"
20#include "string_utils.h"
21#include "config_pstatclient.h"
22
23#include <algorithm>
24
25using std::max;
26using std::min;
27
28/**
29 *
30 */
31PStatStripChart::
32PStatStripChart(PStatMonitor *monitor, PStatView &view,
33 int thread_index, int collector_index, int xsize, int ysize) :
34 PStatGraph(monitor, xsize, ysize),
35 _thread_index(thread_index),
36 _view(view),
37 _collector_index(collector_index)
38{
39 _scroll_mode = pstats_scroll_mode;
40 _average_mode = false;
41
42 _next_frame = 0;
43 _first_data = true;
44 _cursor_pixel = 0;
45
46 _time_width = 20.0;
47 _value_height = 1.0/10.0;
48 _start_time = 0.0;
49
50 _level_index = -1;
51 _title_unknown = true;
52
53 const PStatClientData *client_data = _monitor->get_client_data();
54 if (client_data->has_collector(_collector_index)) {
55 const PStatCollectorDef &def = client_data->get_collector_def(_collector_index);
56 _unit_name = def._level_units;
57 }
58
59 set_default_vertical_scale();
60}
61
62/**
63 *
64 */
65PStatStripChart::
66~PStatStripChart() {
67}
68
69/**
70 * Indicates that new data has become available.
71 */
73new_data(int frame_number) {
74 // If the new frame is older than the last one we've drawn, we'll need to
75 // back up and redraw it. This can happen when frames arrive out of order
76 // from the client.
77 _next_frame = min(frame_number, _next_frame);
78}
79
80/**
81 * Updates the chart with the latest data.
82 */
84update() {
85 const PStatClientData *client_data = get_monitor()->get_client_data();
86
87 // Don't bother to update the thread data until we know at least something
88 // about the collectors and threads.
89 if (client_data->get_num_collectors() != 0 &&
90 client_data->get_num_threads() != 0) {
91 const PStatThreadData *thread_data = _view.get_thread_data();
92 if (!thread_data->is_empty()) {
93 int latest = thread_data->get_latest_frame_number();
94
95 if (latest > _next_frame) {
96 draw_frames(_next_frame, latest);
97 }
98 _next_frame = latest;
99
100 // Clean out the old data.
101 double oldest_time =
102 thread_data->get_frame(latest).get_start() - _time_width;
103
104 Data::iterator di;
105 di = _data.begin();
106 while (di != _data.end() &&
107 thread_data->get_frame((*di).first).get_start() < oldest_time) {
108 dec_label_usage((*di).second);
109 _data.erase(di);
110 di = _data.begin();
111 }
112 }
113 }
114
115 if (_level_index != _view.get_level_index()) {
116 update_labels();
117 }
118
119 idle();
120}
121
122/**
123 * Returns true if the chart has seen its first data appear on it, false if it
124 * is still a virgin chart.
125 */
127first_data() const {
128 return _first_data;
129}
130
131/**
132 * Changes the collector represented by this strip chart. This may force a
133 * redraw.
134 */
136set_collector_index(int collector_index) {
137 if (_collector_index != collector_index) {
138 _collector_index = collector_index;
139 _title_unknown = true;
140 _data.clear();
141 clear_label_usage();
142 force_redraw();
143 update_labels();
144 }
145}
146
147/**
148 * Sets the vertical scale according to the suggested scale of the base
149 * collector, if any, or to center the target frame rate bar otherwise.
150 */
153 const PStatClientData *client_data = _monitor->get_client_data();
154 if (client_data->has_collector(_collector_index)) {
155 const PStatCollectorDef &def =
156 client_data->get_collector_def(_collector_index);
157 if (def._suggested_scale != 0.0) {
158 set_vertical_scale(def._suggested_scale);
159 return;
160 }
161 }
162
164}
165
166/**
167 * Sets the vertical scale to make all the data visible.
168 */
171 const PStatThreadData *thread_data = _view.get_thread_data();
172
173 double max_value = 0.0;
174
175 int frame_number = -1;
176 for (int x = 0; x <= _xsize; x++) {
177 double time = pixel_to_timestamp(x);
178 frame_number =
179 thread_data->get_frame_number_at_time(time, frame_number);
180
181 if (thread_data->has_frame(frame_number)) {
182 double net_value = get_net_value(frame_number);
183 max_value = max(max_value, net_value);
184 }
185 }
186
187 // Ok, now we know what the max value visible in the chart is. Choose a
188 // scale that will show all of this sensibly.
189 if (max_value == 0.0) {
191 } else {
192 set_vertical_scale(max_value * 1.1);
193 }
194}
195
196/**
197 * Return the collector index associated with the particular band of color at
198 * the indicated pixel location, or -1 if no band of color was at the pixel.
199 */
201get_collector_under_pixel(int xpoint, int ypoint) {
202 // First, we need to know what frame it was; to know that, we need to
203 // determine the time corresponding to the x pixel.
204 double time = pixel_to_timestamp(xpoint);
205
206 // Now use that time to determine the frame.
207 const PStatThreadData *thread_data = _view.get_thread_data();
208
209 // And now we can determine which collector within the frame, based on the
210 // value height.
211 if (_average_mode) {
212 double start_time = pixel_to_timestamp(xpoint);
213 int then_i = thread_data->get_frame_number_at_time(start_time - pstats_average_time);
214 int now_i = thread_data->get_frame_number_at_time(start_time, then_i);
215
216 FrameData fdata;
217 compute_average_pixel_data(fdata, then_i, now_i, start_time);
218 double overall_value = 0.0;
219 int y = get_ysize();
220
221 FrameData::const_iterator fi;
222 for (fi = fdata.begin(); fi != fdata.end(); ++fi) {
223 const ColorData &cd = (*fi);
224 overall_value += cd._net_value;
225 y = height_to_pixel(overall_value);
226 if (y <= ypoint) {
227 return cd._collector_index;
228 }
229 }
230
231 } else {
232 int frame_number = thread_data->get_frame_number_at_time(time);
233 const FrameData &fdata = get_frame_data(frame_number);
234 double overall_value = 0.0;
235 int y = get_ysize();
236
237 FrameData::const_iterator fi;
238 for (fi = fdata.begin(); fi != fdata.end(); ++fi) {
239 const ColorData &cd = (*fi);
240 overall_value += cd._net_value;
241 y = height_to_pixel(overall_value);
242 if (y <= ypoint) {
243 return cd._collector_index;
244 }
245 }
246 }
247
248 return -1;
249}
250
251/**
252 * Returns the text suitable for the title label on the top line.
253 */
256 std::string text;
257
258 _title_unknown = false;
259
260 const PStatClientData *client_data = _monitor->get_client_data();
261 if (client_data->has_collector(_collector_index)) {
262 text = client_data->get_collector_fullname(_collector_index);
263 const PStatCollectorDef &def = client_data->get_collector_def(_collector_index);
264 if (_view.get_show_level()) {
265 if (!def._level_units.empty()) {
266 text += " (" + def._level_units + ")";
267 }
268 } else {
269 text += " time";
270 }
271 } else {
272 _title_unknown = true;
273 }
274
275 if (_thread_index != 0) {
276 if (client_data->has_thread(_thread_index)) {
277 text += " (" + client_data->get_thread_name(_thread_index) + " thread)";
278 } else {
279 _title_unknown = true;
280 }
281 }
282
283 return text;
284}
285
286/**
287 * Returns true if get_title_text() has never yet returned an answer, false if
288 * it has.
289 */
291is_title_unknown() const {
292 return _title_unknown;
293}
294
295/**
296 * Adds the data from additional into the data from fdata, after applying the
297 * scale weight.
298 */
299void PStatStripChart::
300accumulate_frame_data(FrameData &fdata, const FrameData &additional,
301 double weight) {
302 FrameData::iterator ai;
303 FrameData::const_iterator bi;
304
305 ai = fdata.begin();
306 bi = additional.begin();
307
308 FrameData result;
309
310 if (fdata.size() == additional.size()) {
311 // Start out assuming that fdata and additional contain exactly the same
312 // set of collectors. If we discover otherwise, we'll have to bail at
313 // that point.
314 while (ai != fdata.end() &&
315 (*ai)._collector_index == (*bi)._collector_index) {
316 (*ai)._net_value += ((*bi)._net_value * weight);
317 ++ai;
318 ++bi;
319 }
320
321 if (ai == fdata.end()) {
322 // If we successfully reached the end of the list, great! We're done
323 // without any merging.
324 return;
325 }
326
327 // Otherwise, the two lists weren't identical. In that case, copy the
328 // accumulated data so far and continue from this point with the full-
329 // blown merge.
330 result.reserve(max(fdata.size(), additional.size()));
331 FrameData::const_iterator ci;
332 for (ci = fdata.begin(); ci != ai; ++ci) {
333 result.push_back(*ci);
334 }
335
336 } else {
337 // If the two lists had different lengths, clearly they aren't identical.
338 result.reserve(max(fdata.size(), additional.size()));
339 }
340
341 while (ai != fdata.end() && bi != additional.end()) {
342 if ((*ai)._i < (*bi)._i) {
343 // Here's a data value that's in data, but not in additional.
344 result.push_back(*ai);
345 ++ai;
346
347 } else if ((*bi)._i < (*ai)._i) {
348 // Here's a data value that's in additional, but not in data.
349 ColorData scaled;
350 scaled._collector_index = (*bi)._collector_index;
351 scaled._i = (*bi)._i;
352 scaled._net_value = (*bi)._net_value * weight;
353 result.push_back(scaled);
354 ++bi;
355
356 } else {
357 // Here's a data value that's in both.
358 ColorData combined;
359 combined._collector_index = (*ai)._collector_index;
360 combined._i = (*bi)._i;
361 combined._net_value = (*ai)._net_value + (*bi)._net_value * weight;
362 result.push_back(combined);
363 ++ai;
364 ++bi;
365 }
366 }
367
368 while (ai != fdata.end()) {
369 // Here's a data value that's in data, but not in additional.
370 result.push_back(*ai);
371 ++ai;
372 }
373
374 while (bi != additional.end()) {
375 // Here's a data value that's in additional, but not in data.
376 ColorData scaled;
377 scaled._collector_index = (*bi)._collector_index;
378 scaled._i = (*bi)._i;
379 scaled._net_value = (*bi)._net_value * weight;
380 result.push_back(scaled);
381 ++bi;
382 }
383
384 fdata.swap(result);
385}
386
387/**
388 * Applies the indicated scale to all collector values in data.
389 */
390void PStatStripChart::
391scale_frame_data(FrameData &fdata, double factor) {
392 FrameData::iterator fi;
393 for (fi = fdata.begin(); fi != fdata.end(); ++fi) {
394 (*fi)._net_value *= factor;
395 }
396}
397
398
399/**
400 * Returns the cached FrameData associated with the given frame number. This
401 * describes the lengths of the color bands for a single vertical stripe in
402 * the chart.
403 */
404const PStatStripChart::FrameData &PStatStripChart::
405get_frame_data(int frame_number) {
406 Data::const_iterator di;
407 di = _data.find(frame_number);
408 if (di != _data.end()) {
409 return (*di).second;
410 }
411
412 const PStatThreadData *thread_data = _view.get_thread_data();
413 _view.set_to_frame(thread_data->get_frame(frame_number));
414
415 FrameData &fdata = _data[frame_number];
416
417 const PStatViewLevel *level = _view.get_level(_collector_index);
418 int num_children = level->get_num_children();
419 for (int i = 0; i < num_children; i++) {
420 const PStatViewLevel *child = level->get_child(i);
421 ColorData cd;
422 cd._collector_index = (unsigned short)child->get_collector();
423 cd._i = (unsigned short)i;
424 cd._net_value = child->get_net_value();
425 if (cd._net_value != 0.0) {
426 fdata.push_back(cd);
427 }
428 }
429
430 // Also, there might be some value in the overall Collector that wasn't
431 // included in all of the children.
432 ColorData cd;
433 cd._collector_index = (unsigned short)level->get_collector();
434 cd._i = (unsigned short)num_children;
435 cd._net_value = level->get_value_alone();
436 if (cd._net_value > 0.0) {
437 fdata.push_back(cd);
438 }
439
440 inc_label_usage(fdata);
441
442 return fdata;
443}
444
445/**
446 * Fills the indicated FrameData structure with the color data for the
447 * indicated pixel, averaged over the past pstats_average_time seconds.
448 *
449 * now is the timestamp for which we are computing the data; then_i and now_i
450 * are the frame numbers that bound (now - pstats_average_time) and now. At
451 * function initialization time, these should be at or below the actual
452 * values; they will be incremented as needed by this function. This allows
453 * the function to be called repeatedly for successive pixels.
454 */
455void PStatStripChart::
456compute_average_pixel_data(PStatStripChart::FrameData &result,
457 int &then_i, int &now_i, double now) {
458 result.clear();
459
460 const PStatThreadData *thread_data = _view.get_thread_data();
461 if (thread_data->is_empty() || thread_data->get_oldest_time() > now) {
462 // No data.
463 return;
464 }
465
466 double then = now - pstats_average_time;
467
468 int latest_frame = thread_data->get_latest_frame_number();
469 while (then_i <= latest_frame &&
470 thread_data->get_frame(then_i).get_end() < then) {
471 then_i++;
472 }
473 while (now_i <= latest_frame &&
474 thread_data->get_frame(now_i).get_end() < now) {
475 now_i++;
476 }
477
478 then = max(then, thread_data->get_frame(then_i).get_start());
479
480 // Sum up a weighted average of all of the individual frames we pass.
481
482 // We start with just the portion of frame then_i that actually does fall
483 // within our "then to now" window.
484 accumulate_frame_data(result, get_frame_data(then_i),
485 thread_data->get_frame(then_i).get_end() - then);
486 double last = thread_data->get_frame(then_i).get_end();
487
488 // Then we get all of each of the middle frames.
489 for (int frame_number = then_i + 1;
490 frame_number < now_i;
491 frame_number++) {
492 accumulate_frame_data(result, get_frame_data(frame_number),
493 thread_data->get_frame(frame_number).get_end() - last);
494 last = thread_data->get_frame(frame_number).get_end();
495 }
496
497 // And finally, we get the remainder as now_i.
498 if (last <= now) {
499 accumulate_frame_data(result, get_frame_data(now_i), now - last);
500 }
501
502 scale_frame_data(result, 1.0f / (now - then));
503}
504
505/**
506 * Returns the net value of the chart's collector for the indicated frame
507 * number.
508 */
509double PStatStripChart::
510get_net_value(int frame_number) const {
511 const FrameData &frame =
512 ((PStatStripChart *)this)->get_frame_data(frame_number);
513
514 double net_value = 0.0;
515 FrameData::const_iterator fi;
516 for (fi = frame.begin(); fi != frame.end(); ++fi) {
517 const ColorData &cd = (*fi);
518 net_value += cd._net_value;
519 }
520
521 return net_value;
522}
523
524/**
525 * Computes the average value of the chart's collector over the past
526 * pstats_average_time number of seconds.
527 */
528double PStatStripChart::
529get_average_net_value() const {
530 const PStatThreadData *thread_data = _view.get_thread_data();
531 int now_i, then_i;
532 if (!thread_data->get_elapsed_frames(then_i, now_i)) {
533 return 0.0f;
534 }
535 double now = _time_width + _start_time;
536 double then = now - pstats_average_time;
537
538 int num_frames = now_i - then_i + 1;
539
540 if (_collector_index == 0 && !_view.get_show_level()) {
541 // If we're showing the time for the whole frame, compute this from the
542 // total elapsed time, rather than summing up individual frames. This is
543 // more accurate and exactly matches what is reported by
544 // thread_data->get_frame_rate().
545
546 const PStatFrameData &now_frame_data = thread_data->get_frame(now_i);
547 const PStatFrameData &then_frame_data = thread_data->get_frame(then_i);
548 double now = now_frame_data.get_end();
549 double elapsed_time = (now - then_frame_data.get_start());
550 return elapsed_time / (double)num_frames;
551
552 } else {
553 // On the other hand, if we're showing the time for some sub-frame, we
554 // have to do it the less-accurate way of summing up individual frames,
555 // which might introduce errors if we are missing data for some frames,
556 // but what can you do?
557
558 const PStatThreadData *thread_data = _view.get_thread_data();
559
560 double net_value = 0.0f;
561 double net_time = 0.0f;
562
563 // We start with just the portion of frame then_i that actually does fall
564 // within our "then to now" window (usually some portion of it will).
565 if (thread_data->get_frame(then_i).get_end() > then) {
566 double this_time = (thread_data->get_frame(then_i).get_end() - then);
567 net_value += get_net_value(then_i) * this_time;
568 net_time += this_time;
569 }
570 // Then we get all of each of the remaining frames.
571 for (int frame_number = then_i + 1;
572 frame_number <= now_i;
573 frame_number++) {
574 double this_time = thread_data->get_frame(frame_number).get_net_time();
575 net_value += get_net_value(frame_number) * this_time;
576 net_time += this_time;
577 }
578
579 return net_value / net_time;
580 }
581}
582
583/**
584 * To be called by the user class when the widget size has changed. This
585 * updates the chart's internal data and causes it to issue redraw commands to
586 * reflect the new size.
587 */
588void PStatStripChart::
589changed_size(int xsize, int ysize) {
590 if (xsize != _xsize || ysize != _ysize) {
591 _xsize = xsize;
592 _ysize = ysize;
593 if (_xsize > 0 && _ysize > 0) {
594 _cursor_pixel = xsize * _cursor_pixel / _xsize;
595
596 if (!_first_data) {
597 if (_scroll_mode) {
598 draw_pixels(0, _xsize);
599
600 } else {
601 // Redraw the stats that were there before.
602 double old_start_time = _start_time;
603
604 // Back up a bit to draw the stuff to the right of the cursor.
605 _start_time -= _time_width;
606 draw_pixels(_cursor_pixel, _xsize);
607
608 // Now draw the stuff to the left of the cursor.
609 _start_time = old_start_time;
610 draw_pixels(0, _cursor_pixel);
611 }
612 }
613 }
614 }
615}
616
617/**
618 * To be called by the user class when the whole thing needs to be redrawn for
619 * some reason.
620 */
621void PStatStripChart::
622force_redraw() {
623 if (!_first_data) {
624 draw_pixels(0, _xsize);
625 }
626}
627
628/**
629 * To be called by the user class to cause the chart to reset to empty and
630 * start filling again.
631 */
632void PStatStripChart::
633force_reset() {
634 clear_region();
635 _first_data = true;
636}
637
638
639/**
640 * Should be overridden by the user class to wipe out the entire strip chart
641 * region.
642 */
643void PStatStripChart::
644clear_region() {
645}
646
647/**
648 * Should be overridden by the user class to copy a region of the chart from
649 * one part of the chart to another. This is used to implement scrolling.
650 */
651void PStatStripChart::
652copy_region(int, int, int) {
653}
654
655/**
656 * Should be overridden by the user class. This hook will be called before
657 * drawing any color bars in the strip chart; it gives the pixel range that's
658 * about to be redrawn.
659 */
660void PStatStripChart::
661begin_draw(int, int) {
662}
663
664/**
665 * Should be overridden by the user class to draw a single vertical slice in
666 * the strip chart at the indicated pixel, with the data for the indicated
667 * frame.
668 */
669void PStatStripChart::
670draw_slice(int, int, const PStatStripChart::FrameData &fdata) {
671}
672
673/**
674 * This is similar to draw_slice(), except it should draw a vertical line of
675 * the background color to represent a portion of the chart that has no data.
676 */
677void PStatStripChart::
678draw_empty(int, int) {
679}
680
681/**
682 * This is similar to draw_slice(), except that it should draw the black
683 * vertical stripe that represents the current position when not in scrolling
684 * mode.
685 */
686void PStatStripChart::
687draw_cursor(int) {
688}
689
690/**
691 * Should be overridden by the user class. This hook will be called after
692 * drawing a series of color bars in the strip chart; it gives the pixel range
693 * that was just redrawn.
694 */
695void PStatStripChart::
696end_draw(int, int) {
697}
698
699/**
700 * Should be overridden by the user class to perform any other updates might
701 * be necessary after the color bars have been redrawn. For instance, it
702 * could check the state of _labels_changed, and redraw the labels if it is
703 * true.
704 */
705void PStatStripChart::
706idle() {
707}
708
709
710// STL function object for sorting labels in order by the collector's sort
711// index, used in update_labels(), below.
712class SortCollectorLabels2 {
713public:
714 SortCollectorLabels2(const PStatClientData *client_data) :
715 _client_data(client_data) {
716 }
717 bool operator () (int a, int b) const {
718 return
719 _client_data->get_collector_def(a)._sort >
720 _client_data->get_collector_def(b)._sort;
721 }
722 const PStatClientData *_client_data;
723};
724
725/**
726 * Resets the list of labels.
727 */
728void PStatStripChart::
729update_labels() {
730 const PStatViewLevel *level = _view.get_level(_collector_index);
731 _labels.clear();
732
733 int num_children = level->get_num_children();
734 for (int i = 0; i < num_children; i++) {
735 const PStatViewLevel *child = level->get_child(i);
736 int collector_index = child->get_collector();
737 if (is_label_used(collector_index)) {
738 _labels.push_back(collector_index);
739 }
740 }
741
742 SortCollectorLabels2 sort_labels(get_monitor()->get_client_data());
743 sort(_labels.begin(), _labels.end(), sort_labels);
744
745 int collector_index = level->get_collector();
746 _labels.push_back(collector_index);
747
748 _labels_changed = true;
749 _level_index = _view.get_level_index();
750}
751
752/**
753 * Calls update_guide_bars with parameters suitable to this kind of graph.
754 */
755void PStatStripChart::
756normal_guide_bars() {
757 update_guide_bars(4, _value_height);
758}
759
760
761/**
762 * Draws the levels for the indicated frame range.
763 */
764void PStatStripChart::
765draw_frames(int first_frame, int last_frame) {
766 const PStatThreadData *thread_data = _view.get_thread_data();
767
768 last_frame = min(last_frame, thread_data->get_latest_frame_number());
769
770 if (_first_data) {
771 if (_scroll_mode) {
772 _start_time =
773 thread_data->get_frame(last_frame).get_start() - _time_width;
774 } else {
775 _start_time = thread_data->get_frame(first_frame).get_start();
776 _cursor_pixel = 0;
777 }
778 }
779
780 int first_pixel;
781 if (thread_data->has_frame(first_frame)) {
782 first_pixel =
783 timestamp_to_pixel(thread_data->get_frame(first_frame).get_start());
784 } else {
785 first_pixel = 0;
786 }
787
788 int last_pixel =
789 timestamp_to_pixel(thread_data->get_frame(last_frame).get_start());
790
791 if (_first_data && !_scroll_mode) {
792 first_pixel = min(_cursor_pixel, first_pixel);
793 }
794 _first_data = false;
795
796 if (last_pixel - first_pixel >= _xsize) {
797 // If we're drawing the whole thing all in this one swoop, just start
798 // over.
799 _start_time = thread_data->get_frame(last_frame).get_start() - _time_width;
800 first_pixel = 0;
801 last_pixel = _xsize;
802 }
803
804 if (last_pixel <= _xsize) {
805 // It all fits in one block.
806 _cursor_pixel = last_pixel;
807 draw_pixels(first_pixel, last_pixel);
808
809 } else {
810 if (_scroll_mode) {
811 // In scrolling mode, slide the world back.
812 int slide_pixels = last_pixel - _xsize;
813 copy_region(slide_pixels, first_pixel, 0);
814 first_pixel -= slide_pixels;
815 last_pixel -= slide_pixels;
816 _start_time += (double)slide_pixels / (double)_xsize * _time_width;
817 draw_pixels(first_pixel, last_pixel);
818
819 } else {
820 // In wrapping mode, do it in two blocks.
821 _cursor_pixel = -1;
822 draw_pixels(first_pixel, _xsize);
823 _start_time = pixel_to_timestamp(_xsize);
824 last_pixel -= _xsize;
825 _cursor_pixel = last_pixel;
826 draw_pixels(0, last_pixel);
827 }
828 }
829}
830
831/**
832 * Draws the levels for the indicated pixel range.
833 */
834void PStatStripChart::
835draw_pixels(int first_pixel, int last_pixel) {
836 begin_draw(first_pixel, last_pixel);
837 const PStatThreadData *thread_data = _view.get_thread_data();
838
839 if (_average_mode && !thread_data->is_empty()) {
840 // In average mode, we have to calculate the average value for each pixel.
841 double start_time = pixel_to_timestamp(first_pixel);
842 int then_i = thread_data->get_frame_number_at_time(start_time - pstats_average_time);
843 int now_i = thread_data->get_frame_number_at_time(start_time, then_i);
844 for (int x = first_pixel; x <= last_pixel; x++) {
845 if (x == _cursor_pixel && !_scroll_mode) {
846 draw_cursor(x);
847 } else {
848 FrameData fdata;
849 compute_average_pixel_data(fdata, then_i, now_i, pixel_to_timestamp(x));
850 draw_slice(x, 1, fdata);
851 }
852 }
853
854 } else {
855 // When average mode is false, we are in frame mode; just show the actual
856 // frame data.
857 int frame_number = -1;
858 int x = first_pixel;
859 while (x <= last_pixel) {
860 if (x == _cursor_pixel && !_scroll_mode) {
861 draw_cursor(x);
862 x++;
863
864 } else {
865 double time = pixel_to_timestamp(x);
866 frame_number = thread_data->get_frame_number_at_time(time, frame_number);
867 int w = 1;
868 int stop_pixel = last_pixel;
869 if (!_scroll_mode) {
870 stop_pixel = min(stop_pixel, _cursor_pixel);
871 }
872 while (x + w < stop_pixel &&
873 thread_data->get_frame_number_at_time(pixel_to_timestamp(x + w), frame_number) == frame_number) {
874 w++;
875 }
876 if (thread_data->has_frame(frame_number)) {
877 draw_slice(x, w, get_frame_data(frame_number));
878 } else {
879 draw_empty(x, w);
880 }
881 x += w;
882 }
883 }
884 }
885
886 end_draw(first_pixel, last_pixel);
887}
888
889/**
890 * Erases all elements from the label usage data.
891 */
892void PStatStripChart::
893clear_label_usage() {
894 _label_usage.clear();
895}
896
897/**
898 * Erases the indicated frame data from the current label usage. This
899 * indicates that the given FrameData has fallen off the end of the chart.
900 * This must have been proceeded by an earlier call to inc_label_usage() for
901 * the same FrameData
902 */
903void PStatStripChart::
904dec_label_usage(const FrameData &fdata) {
905 FrameData::const_iterator fi;
906 for (fi = fdata.begin(); fi != fdata.end(); ++fi) {
907 const ColorData &cd = (*fi);
908 nassertv(cd._collector_index < (int)_label_usage.size());
909 nassertv(_label_usage[cd._collector_index] > 0);
910 _label_usage[cd._collector_index]--;
911 if (_label_usage[cd._collector_index] == 0) {
912 // If a label drops out of usage, it's time to regenerate labels.
913 _level_index = -1;
914 }
915 }
916}
917
918/**
919 * Records the labels named in the indicated FrameData in the table of current
920 * labels in use. This should be called when the given FrameData has been
921 * added to the chart; it will increment the reference count for each
922 * collector named in the FrameData. The reference count will eventually be
923 * decremented when dec_label_usage() is called later.
924 */
925void PStatStripChart::
926inc_label_usage(const FrameData &fdata) {
927 FrameData::const_iterator fi;
928 for (fi = fdata.begin(); fi != fdata.end(); ++fi) {
929 const ColorData &cd = (*fi);
930 while (cd._collector_index >= (int)_label_usage.size()) {
931 _label_usage.push_back(0);
932 }
933 nassertv(_label_usage[cd._collector_index] >= 0);
934 _label_usage[cd._collector_index]++;
935 if (_label_usage[cd._collector_index] == 1) {
936 // If a label appears for the first time, it's time to regenerate
937 // labels.
938 _level_index = -1;
939 }
940 }
941}
The data associated with a particular client, but not with any one particular frame or thread: the li...
std::string get_collector_fullname(int index) const
Returns the "full name" of the indicated collector.
bool has_thread(int index) const
Returns true if the indicated thread has been defined by the client already, false otherwise.
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.
std::string get_thread_name(int index) const
Returns the name of 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.
Defines the details about the Collectors: the name, the suggested color, etc.
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_net_time() const
Returns the total time elapsed for the frame.
double get_start() const
Returns the time of the first data point in the frame data.
This is an abstract base class for several different kinds of graphs that have a few things in common...
Definition: pStatGraph.h:33
double get_target_frame_rate() const
Returns the indicated target frame rate in Hz.
Definition: pStatGraph.I:74
PStatMonitor * get_monitor() const
Returns the monitor associated with this chart.
Definition: pStatGraph.I:18
int get_ysize() const
Returns the height of the chart in pixels.
Definition: pStatGraph.I:90
This is an abstract class that presents the interface to any number of different front-ends for the s...
Definition: pStatMonitor.h:39
const PStatClientData * get_client_data() const
Returns the client data associated with this monitor.
Definition: pStatMonitor.I:26
This is an abstract class that presents the interface for drawing a basic strip-chart,...
std::string get_title_text()
Returns the text suitable for the title label on the top line.
bool is_title_unknown() const
Returns true if get_title_text() has never yet returned an answer, false if it has.
int height_to_pixel(double value) const
Converts a value (i.e.
void set_auto_vertical_scale()
Sets the vertical scale to make all the data visible.
void update()
Updates the chart with the latest data.
int get_collector_under_pixel(int xpoint, int ypoint)
Return the collector index associated with the particular band of color at the indicated pixel locati...
void set_collector_index(int collector_index)
Changes the collector represented by this strip chart.
double pixel_to_timestamp(int x) const
Converts a horizontal pixel offset to a timestamp.
void set_default_vertical_scale()
Sets the vertical scale according to the suggested scale of the base collector, if any,...
void new_data(int frame_number)
Indicates that new data has become available.
int timestamp_to_pixel(double time) const
Converts a timestamp to a horizontal pixel offset.
bool first_data() const
Returns true if the chart has seen its first data appear on it, false if it is still a virgin chart.
void set_vertical_scale(double value_height)
Changes the value the height of the vertical axis represents.
A collection of FrameData structures for recently-received frames within a particular thread.
bool get_elapsed_frames(int &then_i, int &now_i) const
Computes the oldest frame number not older than pstats_average_time seconds, and the newest frame num...
int get_frame_number_at_time(double time, int hint=-1) const
Returns the frame number of the latest frame not later than the indicated time.
bool is_empty() const
Returns true if the structure contains no frames, false otherwise.
bool has_frame(int frame_number) const
Returns true if we have received data for the indicated frame number from the client and we still hav...
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.
double get_oldest_time() const
Returns the timestamp (in seconds elapsed since connection) of the oldest available frame.
This is a single level value, or band of color, within a View.
const PStatViewLevel * get_child(int n) const
Returns the nth child of this Level/Collector.
double get_net_value() const
Returns the total level value (or elapsed time) represented by this Collector, including all values i...
int get_num_children() const
Returns the number of children of this Level/Collector.
int get_collector() const
Returns the Collector index associated with this level.
double get_value_alone() const
Returns the total level value (or elapsed time value) for this Collector, not including any values ac...
A View boils down the frame data to a linear list of times spent in a number of different Collectors,...
Definition: pStatView.h:31
int get_level_index() const
Returns an index number that can be used to determine when the set of known levels has changed.
Definition: pStatView.I:68
void set_to_frame(const PStatFrameData &frame_data)
Supplies the View with the data for the current frame.
Definition: pStatView.cxx:194
bool get_show_level() const
Returns true if we are showing level data, false if time data.
Definition: pStatView.I:57
const PStatThreadData * get_thread_data()
Returns the current PStatThreadData associated with the view.
Definition: pStatView.I:19
PStatViewLevel * get_level(int collector)
Returns a pointer to the level that corresponds to the indicated Collector.
Definition: pStatView.cxx:260
This is our own Panda specialization on the default STL vector.
Definition: pvector.h:42
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.