Panda3D
|
00001 // Filename: pStatStripChart.cxx 00002 // Created by: drose (15Jul00) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "pStatStripChart.h" 00016 #include "pStatClientData.h" 00017 #include "pStatMonitor.h" 00018 00019 #include "pStatFrameData.h" 00020 #include "pStatCollectorDef.h" 00021 #include "string_utils.h" 00022 #include "config_pstats.h" 00023 00024 #include <algorithm> 00025 00026 //////////////////////////////////////////////////////////////////// 00027 // Function: PStatStripChart::Constructor 00028 // Access: Public 00029 // Description: 00030 //////////////////////////////////////////////////////////////////// 00031 PStatStripChart:: 00032 PStatStripChart(PStatMonitor *monitor, PStatView &view, 00033 int thread_index, int collector_index, int xsize, int ysize) : 00034 PStatGraph(monitor, xsize, ysize), 00035 _thread_index(thread_index), 00036 _view(view), 00037 _collector_index(collector_index) 00038 { 00039 _scroll_mode = pstats_scroll_mode; 00040 _average_mode = false; 00041 00042 _next_frame = 0; 00043 _first_data = true; 00044 _cursor_pixel = 0; 00045 00046 _time_width = 20.0; 00047 _value_height = 1.0/10.0; 00048 _start_time = 0.0; 00049 00050 _level_index = -1; 00051 _title_unknown = true; 00052 00053 const PStatClientData *client_data = _monitor->get_client_data(); 00054 if (client_data->has_collector(_collector_index)) { 00055 const PStatCollectorDef &def = client_data->get_collector_def(_collector_index); 00056 _unit_name = def._level_units; 00057 } 00058 00059 set_default_vertical_scale(); 00060 } 00061 00062 //////////////////////////////////////////////////////////////////// 00063 // Function: PStatStripChart::Destructor 00064 // Access: Public, Virtual 00065 // Description: 00066 //////////////////////////////////////////////////////////////////// 00067 PStatStripChart:: 00068 ~PStatStripChart() { 00069 } 00070 00071 //////////////////////////////////////////////////////////////////// 00072 // Function: PStatStripChart::new_data 00073 // Access: Public 00074 // Description: Indicates that new data has become available. 00075 //////////////////////////////////////////////////////////////////// 00076 void PStatStripChart:: 00077 new_data(int frame_number) { 00078 // If the new frame is older than the last one we've drawn, we'll 00079 // need to back up and redraw it. This can happen when frames 00080 // arrive out of order from the client. 00081 _next_frame = min(frame_number, _next_frame); 00082 } 00083 00084 //////////////////////////////////////////////////////////////////// 00085 // Function: PStatStripChart::update 00086 // Access: Public 00087 // Description: Updates the chart with the latest data. 00088 //////////////////////////////////////////////////////////////////// 00089 void PStatStripChart:: 00090 update() { 00091 const PStatClientData *client_data = get_monitor()->get_client_data(); 00092 00093 // Don't bother to update the thread data until we know at least 00094 // something about the collectors and threads. 00095 if (client_data->get_num_collectors() != 0 && 00096 client_data->get_num_threads() != 0) { 00097 const PStatThreadData *thread_data = _view.get_thread_data(); 00098 if (!thread_data->is_empty()) { 00099 int latest = thread_data->get_latest_frame_number(); 00100 00101 if (latest > _next_frame) { 00102 draw_frames(_next_frame, latest); 00103 } 00104 _next_frame = latest; 00105 00106 // Clean out the old data. 00107 double oldest_time = 00108 thread_data->get_frame(latest).get_start() - _time_width; 00109 00110 Data::iterator di; 00111 di = _data.begin(); 00112 while (di != _data.end() && 00113 thread_data->get_frame((*di).first).get_start() < oldest_time) { 00114 dec_label_usage((*di).second); 00115 _data.erase(di); 00116 di = _data.begin(); 00117 } 00118 } 00119 } 00120 00121 if (_level_index != _view.get_level_index()) { 00122 update_labels(); 00123 } 00124 00125 idle(); 00126 } 00127 00128 //////////////////////////////////////////////////////////////////// 00129 // Function: PStatStripChart::first_data 00130 // Access: Public 00131 // Description: Returns true if the chart has seen its first data 00132 // appear on it, false if it is still a virgin chart. 00133 //////////////////////////////////////////////////////////////////// 00134 bool PStatStripChart:: 00135 first_data() const { 00136 return _first_data; 00137 } 00138 00139 //////////////////////////////////////////////////////////////////// 00140 // Function: PStatStripChart::set_collector_index 00141 // Access: Public 00142 // Description: Changes the collector represented by this strip 00143 // chart. This may force a redraw. 00144 //////////////////////////////////////////////////////////////////// 00145 void PStatStripChart:: 00146 set_collector_index(int collector_index) { 00147 if (_collector_index != collector_index) { 00148 _collector_index = collector_index; 00149 _title_unknown = true; 00150 _data.clear(); 00151 clear_label_usage(); 00152 force_redraw(); 00153 update_labels(); 00154 } 00155 } 00156 00157 //////////////////////////////////////////////////////////////////// 00158 // Function: PStatStripChart::set_default_vertical_scale 00159 // Access: Public 00160 // Description: Sets the vertical scale according to the suggested 00161 // scale of the base collector, if any, or to center the 00162 // target frame rate bar otherwise. 00163 //////////////////////////////////////////////////////////////////// 00164 void PStatStripChart:: 00165 set_default_vertical_scale() { 00166 const PStatClientData *client_data = _monitor->get_client_data(); 00167 if (client_data->has_collector(_collector_index)) { 00168 const PStatCollectorDef &def = 00169 client_data->get_collector_def(_collector_index); 00170 if (def._suggested_scale != 0.0) { 00171 set_vertical_scale(def._suggested_scale); 00172 return; 00173 } 00174 } 00175 00176 set_vertical_scale(2.0 / get_target_frame_rate()); 00177 } 00178 00179 //////////////////////////////////////////////////////////////////// 00180 // Function: PStatStripChart::set_auto_vertical_scale 00181 // Access: Public 00182 // Description: Sets the vertical scale to make all the data visible. 00183 //////////////////////////////////////////////////////////////////// 00184 void PStatStripChart:: 00185 set_auto_vertical_scale() { 00186 const PStatThreadData *thread_data = _view.get_thread_data(); 00187 00188 double max_value = 0.0; 00189 00190 int frame_number = -1; 00191 for (int x = 0; x <= _xsize; x++) { 00192 double time = pixel_to_timestamp(x); 00193 frame_number = 00194 thread_data->get_frame_number_at_time(time, frame_number); 00195 00196 if (thread_data->has_frame(frame_number)) { 00197 double net_value = get_net_value(frame_number); 00198 max_value = max(max_value, net_value); 00199 } 00200 } 00201 00202 // Ok, now we know what the max value visible in the chart is. 00203 // Choose a scale that will show all of this sensibly. 00204 if (max_value == 0.0) { 00205 set_vertical_scale(1.0); 00206 } else { 00207 set_vertical_scale(max_value * 1.1); 00208 } 00209 } 00210 00211 //////////////////////////////////////////////////////////////////// 00212 // Function: PStatStripChart::get_collector_under_pixel 00213 // Access: Public 00214 // Description: Return the collector index associated with the 00215 // particular band of color at the indicated pixel 00216 // location, or -1 if no band of color was at the pixel. 00217 //////////////////////////////////////////////////////////////////// 00218 int PStatStripChart:: 00219 get_collector_under_pixel(int xpoint, int ypoint) { 00220 // First, we need to know what frame it was; to know that, we need 00221 // to determine the time corresponding to the x pixel. 00222 double time = pixel_to_timestamp(xpoint); 00223 00224 // Now use that time to determine the frame. 00225 const PStatThreadData *thread_data = _view.get_thread_data(); 00226 00227 // And now we can determine which collector within the frame, 00228 // based on the value height. 00229 if (_average_mode) { 00230 double start_time = pixel_to_timestamp(xpoint); 00231 int then_i = thread_data->get_frame_number_at_time(start_time - pstats_average_time); 00232 int now_i = thread_data->get_frame_number_at_time(start_time, then_i); 00233 00234 FrameData fdata; 00235 compute_average_pixel_data(fdata, then_i, now_i, start_time); 00236 double overall_value = 0.0; 00237 int y = get_ysize(); 00238 00239 FrameData::const_iterator fi; 00240 for (fi = fdata.begin(); fi != fdata.end(); ++fi) { 00241 const ColorData &cd = (*fi); 00242 overall_value += cd._net_value; 00243 y = height_to_pixel(overall_value); 00244 if (y <= ypoint) { 00245 return cd._collector_index; 00246 } 00247 } 00248 00249 } else { 00250 int frame_number = thread_data->get_frame_number_at_time(time); 00251 const FrameData &fdata = get_frame_data(frame_number); 00252 double overall_value = 0.0; 00253 int y = get_ysize(); 00254 00255 FrameData::const_iterator fi; 00256 for (fi = fdata.begin(); fi != fdata.end(); ++fi) { 00257 const ColorData &cd = (*fi); 00258 overall_value += cd._net_value; 00259 y = height_to_pixel(overall_value); 00260 if (y <= ypoint) { 00261 return cd._collector_index; 00262 } 00263 } 00264 } 00265 00266 return -1; 00267 } 00268 00269 //////////////////////////////////////////////////////////////////// 00270 // Function: PStatStripChart::get_title_text 00271 // Access: Private 00272 // Description: Returns the text suitable for the title label on the 00273 // top line. 00274 //////////////////////////////////////////////////////////////////// 00275 string PStatStripChart:: 00276 get_title_text() { 00277 string text; 00278 00279 _title_unknown = false; 00280 00281 const PStatClientData *client_data = _monitor->get_client_data(); 00282 if (client_data->has_collector(_collector_index)) { 00283 text = client_data->get_collector_fullname(_collector_index); 00284 const PStatCollectorDef &def = client_data->get_collector_def(_collector_index); 00285 if (_view.get_show_level()) { 00286 if (!def._level_units.empty()) { 00287 text += " (" + def._level_units + ")"; 00288 } 00289 } else { 00290 text += " time"; 00291 } 00292 } else { 00293 _title_unknown = true; 00294 } 00295 00296 if (_thread_index != 0) { 00297 if (client_data->has_thread(_thread_index)) { 00298 text += " (" + client_data->get_thread_name(_thread_index) + " thread)"; 00299 } else { 00300 _title_unknown = true; 00301 } 00302 } 00303 00304 return text; 00305 } 00306 00307 //////////////////////////////////////////////////////////////////// 00308 // Function: PStatStripChart::is_title_unknown 00309 // Access: Public 00310 // Description: Returns true if get_title_text() has never yet 00311 // returned an answer, false if it has. 00312 //////////////////////////////////////////////////////////////////// 00313 bool PStatStripChart:: 00314 is_title_unknown() const { 00315 return _title_unknown; 00316 } 00317 00318 //////////////////////////////////////////////////////////////////// 00319 // Function: PStatStripChart::accumulate_frame_data 00320 // Access: Protected, Static 00321 // Description: Adds the data from additional into the data from 00322 // fdata, after applying the scale weight. 00323 //////////////////////////////////////////////////////////////////// 00324 void PStatStripChart:: 00325 accumulate_frame_data(FrameData &fdata, const FrameData &additional, 00326 double weight) { 00327 FrameData::iterator ai; 00328 FrameData::const_iterator bi; 00329 00330 ai = fdata.begin(); 00331 bi = additional.begin(); 00332 00333 FrameData result; 00334 00335 if (fdata.size() == additional.size()) { 00336 // Start out assuming that fdata and additional contain exactly 00337 // the same set of collectors. If we discover otherwise, we'll 00338 // have to bail at that point. 00339 while (ai != fdata.end() && 00340 (*ai)._collector_index == (*bi)._collector_index) { 00341 (*ai)._net_value += ((*bi)._net_value * weight); 00342 ++ai; 00343 ++bi; 00344 } 00345 00346 if (ai == fdata.end()) { 00347 // If we successfully reached the end of the list, great! 00348 // We're done without any merging. 00349 return; 00350 } 00351 00352 // Otherwise, the two lists weren't identical. In that case, copy 00353 // the accumulated data so far and continue from this point with 00354 // the full-blown merge. 00355 result.reserve(max(fdata.size(), additional.size())); 00356 FrameData::const_iterator ci; 00357 for (ci = fdata.begin(); ci != ai; ++ci) { 00358 result.push_back(*ci); 00359 } 00360 00361 } else { 00362 // If the two lists had different lengths, clearly they aren't 00363 // identical. 00364 result.reserve(max(fdata.size(), additional.size())); 00365 } 00366 00367 while (ai != fdata.end() && bi != additional.end()) { 00368 if ((*ai)._i < (*bi)._i) { 00369 // Here's a data value that's in data, but not in additional. 00370 result.push_back(*ai); 00371 ++ai; 00372 00373 } else if ((*bi)._i < (*ai)._i) { 00374 // Here's a data value that's in additional, but not in data. 00375 ColorData scaled; 00376 scaled._collector_index = (*bi)._collector_index; 00377 scaled._i = (*bi)._i; 00378 scaled._net_value = (*bi)._net_value * weight; 00379 result.push_back(scaled); 00380 ++bi; 00381 00382 } else { 00383 // Here's a data value that's in both. 00384 ColorData combined; 00385 combined._collector_index = (*ai)._collector_index; 00386 combined._i = (*bi)._i; 00387 combined._net_value = (*ai)._net_value + (*bi)._net_value * weight; 00388 result.push_back(combined); 00389 ++ai; 00390 ++bi; 00391 } 00392 } 00393 00394 while (ai != fdata.end()) { 00395 // Here's a data value that's in data, but not in additional. 00396 result.push_back(*ai); 00397 ++ai; 00398 } 00399 00400 while (bi != additional.end()) { 00401 // Here's a data value that's in additional, but not in data. 00402 ColorData scaled; 00403 scaled._collector_index = (*bi)._collector_index; 00404 scaled._i = (*bi)._i; 00405 scaled._net_value = (*bi)._net_value * weight; 00406 result.push_back(scaled); 00407 ++bi; 00408 } 00409 00410 fdata.swap(result); 00411 } 00412 00413 //////////////////////////////////////////////////////////////////// 00414 // Function: PStatStripChart::scale_frame_data 00415 // Access: Protected, Static 00416 // Description: Applies the indicated scale to all collector values 00417 // in data. 00418 //////////////////////////////////////////////////////////////////// 00419 void PStatStripChart:: 00420 scale_frame_data(FrameData &fdata, double factor) { 00421 FrameData::iterator fi; 00422 for (fi = fdata.begin(); fi != fdata.end(); ++fi) { 00423 (*fi)._net_value *= factor; 00424 } 00425 } 00426 00427 00428 //////////////////////////////////////////////////////////////////// 00429 // Function: PStatStripChart::get_frame_data 00430 // Access: Protected 00431 // Description: Returns the cached FrameData associated with the 00432 // given frame number. This describes the lengths of 00433 // the color bands for a single vertical stripe in the 00434 // chart. 00435 //////////////////////////////////////////////////////////////////// 00436 const PStatStripChart::FrameData &PStatStripChart:: 00437 get_frame_data(int frame_number) { 00438 Data::const_iterator di; 00439 di = _data.find(frame_number); 00440 if (di != _data.end()) { 00441 return (*di).second; 00442 } 00443 00444 const PStatThreadData *thread_data = _view.get_thread_data(); 00445 _view.set_to_frame(thread_data->get_frame(frame_number)); 00446 00447 FrameData &fdata = _data[frame_number]; 00448 00449 const PStatViewLevel *level = _view.get_level(_collector_index); 00450 int num_children = level->get_num_children(); 00451 for (int i = 0; i < num_children; i++) { 00452 const PStatViewLevel *child = level->get_child(i); 00453 ColorData cd; 00454 cd._collector_index = (unsigned short)child->get_collector(); 00455 cd._i = (unsigned short)i; 00456 cd._net_value = child->get_net_value(); 00457 if (cd._net_value != 0.0) { 00458 fdata.push_back(cd); 00459 } 00460 } 00461 00462 // Also, there might be some value in the overall Collector that 00463 // wasn't included in all of the children. 00464 ColorData cd; 00465 cd._collector_index = (unsigned short)level->get_collector(); 00466 cd._i = (unsigned short)num_children; 00467 cd._net_value = level->get_value_alone(); 00468 if (cd._net_value > 0.0) { 00469 fdata.push_back(cd); 00470 } 00471 00472 inc_label_usage(fdata); 00473 00474 return fdata; 00475 } 00476 00477 //////////////////////////////////////////////////////////////////// 00478 // Function: PStatStripChart::compute_average_pixel_data 00479 // Access: Protected 00480 // Description: Fills the indicated FrameData structure with the 00481 // color data for the indicated pixel, averaged over the 00482 // past pstats_average_time seconds. 00483 // 00484 // now is the timestamp for which we are computing the 00485 // data; then_i and now_i are the frame numbers that 00486 // bound (now - pstats_average_time) and now. At 00487 // function initialization time, these should be at or 00488 // below the actual values; they will be incremented as 00489 // needed by this function. This allows the function to 00490 // be called repeatedly for successive pixels. 00491 //////////////////////////////////////////////////////////////////// 00492 void PStatStripChart:: 00493 compute_average_pixel_data(PStatStripChart::FrameData &result, 00494 int &then_i, int &now_i, double now) { 00495 result.clear(); 00496 00497 const PStatThreadData *thread_data = _view.get_thread_data(); 00498 if (thread_data->is_empty() || thread_data->get_oldest_time() > now) { 00499 // No data. 00500 return; 00501 } 00502 00503 double then = now - pstats_average_time; 00504 00505 int latest_frame = thread_data->get_latest_frame_number(); 00506 while (then_i <= latest_frame && 00507 thread_data->get_frame(then_i).get_end() < then) { 00508 then_i++; 00509 } 00510 while (now_i <= latest_frame && 00511 thread_data->get_frame(now_i).get_end() < now) { 00512 now_i++; 00513 } 00514 00515 then = max(then, thread_data->get_frame(then_i).get_start()); 00516 00517 // Sum up a weighted average of all of the individual frames we 00518 // pass. 00519 00520 // We start with just the portion of frame then_i that actually 00521 // does fall within our "then to now" window. 00522 accumulate_frame_data(result, get_frame_data(then_i), 00523 thread_data->get_frame(then_i).get_end() - then); 00524 double last = thread_data->get_frame(then_i).get_end(); 00525 00526 // Then we get all of each of the middle frames. 00527 for (int frame_number = then_i + 1; 00528 frame_number < now_i; 00529 frame_number++) { 00530 accumulate_frame_data(result, get_frame_data(frame_number), 00531 thread_data->get_frame(frame_number).get_end() - last); 00532 last = thread_data->get_frame(frame_number).get_end(); 00533 } 00534 00535 // And finally, we get the remainder as now_i. 00536 if (last <= now) { 00537 accumulate_frame_data(result, get_frame_data(now_i), now - last); 00538 } 00539 00540 scale_frame_data(result, 1.0f / (now - then)); 00541 } 00542 00543 //////////////////////////////////////////////////////////////////// 00544 // Function: PStatStripChart::get_net_value 00545 // Access: Protected 00546 // Description: Returns the net value of the chart's collector for 00547 // the indicated frame number. 00548 //////////////////////////////////////////////////////////////////// 00549 double PStatStripChart:: 00550 get_net_value(int frame_number) const { 00551 const FrameData &frame = 00552 ((PStatStripChart *)this)->get_frame_data(frame_number); 00553 00554 double net_value = 0.0; 00555 FrameData::const_iterator fi; 00556 for (fi = frame.begin(); fi != frame.end(); ++fi) { 00557 const ColorData &cd = (*fi); 00558 net_value += cd._net_value; 00559 } 00560 00561 return net_value; 00562 } 00563 00564 //////////////////////////////////////////////////////////////////// 00565 // Function: PStatStripChart::get_average_net_value 00566 // Access: Protected 00567 // Description: Computes the average value of the chart's collector 00568 // over the past pstats_average_time number of seconds. 00569 //////////////////////////////////////////////////////////////////// 00570 double PStatStripChart:: 00571 get_average_net_value() const { 00572 const PStatThreadData *thread_data = _view.get_thread_data(); 00573 int now_i, then_i; 00574 if (!thread_data->get_elapsed_frames(then_i, now_i)) { 00575 return 0.0f; 00576 } 00577 double now = _time_width + _start_time; 00578 double then = now - pstats_average_time; 00579 00580 int num_frames = now_i - then_i + 1; 00581 00582 if (_collector_index == 0 && !_view.get_show_level()) { 00583 // If we're showing the time for the whole frame, compute this 00584 // from the total elapsed time, rather than summing up individual 00585 // frames. This is more accurate and exactly matches what is 00586 // reported by thread_data->get_frame_rate(). 00587 00588 const PStatFrameData &now_frame_data = thread_data->get_frame(now_i); 00589 const PStatFrameData &then_frame_data = thread_data->get_frame(then_i); 00590 double now = now_frame_data.get_end(); 00591 double elapsed_time = (now - then_frame_data.get_start()); 00592 return elapsed_time / (double)num_frames; 00593 00594 } else { 00595 // On the other hand, if we're showing the time for some 00596 // sub-frame, we have to do it the less-accurate way of summing up 00597 // individual frames, which might introduce errors if we are 00598 // missing data for some frames, but what can you do? 00599 00600 const PStatThreadData *thread_data = _view.get_thread_data(); 00601 00602 double net_value = 0.0f; 00603 double net_time = 0.0f; 00604 00605 // We start with just the portion of frame then_i that actually 00606 // does fall within our "then to now" window (usually some portion 00607 // of it will). 00608 if (thread_data->get_frame(then_i).get_end() > then) { 00609 double this_time = (thread_data->get_frame(then_i).get_end() - then); 00610 net_value += get_net_value(then_i) * this_time; 00611 net_time += this_time; 00612 } 00613 // Then we get all of each of the remaining frames. 00614 for (int frame_number = then_i + 1; 00615 frame_number <= now_i; 00616 frame_number++) { 00617 double this_time = thread_data->get_frame(frame_number).get_net_time(); 00618 net_value += get_net_value(frame_number) * this_time; 00619 net_time += this_time; 00620 } 00621 00622 return net_value / net_time; 00623 } 00624 } 00625 00626 //////////////////////////////////////////////////////////////////// 00627 // Function: PStatStripChart::changed_size 00628 // Access: Protected 00629 // Description: To be called by the user class when the widget size 00630 // has changed. This updates the chart's internal data 00631 // and causes it to issue redraw commands to reflect the 00632 // new size. 00633 //////////////////////////////////////////////////////////////////// 00634 void PStatStripChart:: 00635 changed_size(int xsize, int ysize) { 00636 if (xsize != _xsize || ysize != _ysize) { 00637 _xsize = xsize; 00638 _ysize = ysize; 00639 if (_xsize > 0 && _ysize > 0) { 00640 _cursor_pixel = xsize * _cursor_pixel / _xsize; 00641 00642 if (!_first_data) { 00643 if (_scroll_mode) { 00644 draw_pixels(0, _xsize); 00645 00646 } else { 00647 // Redraw the stats that were there before. 00648 double old_start_time = _start_time; 00649 00650 // Back up a bit to draw the stuff to the right of the cursor. 00651 _start_time -= _time_width; 00652 draw_pixels(_cursor_pixel, _xsize); 00653 00654 // Now draw the stuff to the left of the cursor. 00655 _start_time = old_start_time; 00656 draw_pixels(0, _cursor_pixel); 00657 } 00658 } 00659 } 00660 } 00661 } 00662 00663 //////////////////////////////////////////////////////////////////// 00664 // Function: PStatStripChart::force_redraw 00665 // Access: Protected 00666 // Description: To be called by the user class when the whole thing 00667 // needs to be redrawn for some reason. 00668 //////////////////////////////////////////////////////////////////// 00669 void PStatStripChart:: 00670 force_redraw() { 00671 if (!_first_data) { 00672 draw_pixels(0, _xsize); 00673 } 00674 } 00675 00676 //////////////////////////////////////////////////////////////////// 00677 // Function: PStatStripChart::force_reset 00678 // Access: Protected 00679 // Description: To be called by the user class to cause the chart to 00680 // reset to empty and start filling again. 00681 //////////////////////////////////////////////////////////////////// 00682 void PStatStripChart:: 00683 force_reset() { 00684 clear_region(); 00685 _first_data = true; 00686 } 00687 00688 00689 //////////////////////////////////////////////////////////////////// 00690 // Function: PStatStripChart::clear_region 00691 // Access: Protected, Virtual 00692 // Description: Should be overridden by the user class to wipe out 00693 // the entire strip chart region. 00694 //////////////////////////////////////////////////////////////////// 00695 void PStatStripChart:: 00696 clear_region() { 00697 } 00698 00699 //////////////////////////////////////////////////////////////////// 00700 // Function: PStatStripChart::copy_region 00701 // Access: Protected, Virtual 00702 // Description: Should be overridden by the user class to copy a 00703 // region of the chart from one part of the chart to 00704 // another. This is used to implement scrolling. 00705 //////////////////////////////////////////////////////////////////// 00706 void PStatStripChart:: 00707 copy_region(int, int, int) { 00708 } 00709 00710 //////////////////////////////////////////////////////////////////// 00711 // Function: PStatStripChart::begin_draw 00712 // Access: Protected, Virtual 00713 // Description: Should be overridden by the user class. This hook 00714 // will be called before drawing any color bars in the 00715 // strip chart; it gives the pixel range that's about to 00716 // be redrawn. 00717 //////////////////////////////////////////////////////////////////// 00718 void PStatStripChart:: 00719 begin_draw(int, int) { 00720 } 00721 00722 //////////////////////////////////////////////////////////////////// 00723 // Function: PStatStripChart::draw_slice 00724 // Access: Protected, Virtual 00725 // Description: Should be overridden by the user class to draw a 00726 // single vertical slice in the strip chart at the 00727 // indicated pixel, with the data for the indicated 00728 // frame. 00729 //////////////////////////////////////////////////////////////////// 00730 void PStatStripChart:: 00731 draw_slice(int, int, const PStatStripChart::FrameData &fdata) { 00732 } 00733 00734 //////////////////////////////////////////////////////////////////// 00735 // Function: PStatStripChart::draw_empty 00736 // Access: Protected, Virtual 00737 // Description: This is similar to draw_slice(), except it should 00738 // draw a vertical line of the background color to 00739 // represent a portion of the chart that has no data. 00740 //////////////////////////////////////////////////////////////////// 00741 void PStatStripChart:: 00742 draw_empty(int, int) { 00743 } 00744 00745 //////////////////////////////////////////////////////////////////// 00746 // Function: PStatStripChart::draw_cursor 00747 // Access: Protected, Virtual 00748 // Description: This is similar to draw_slice(), except that it 00749 // should draw the black vertical stripe that represents 00750 // the current position when not in scrolling mode. 00751 //////////////////////////////////////////////////////////////////// 00752 void PStatStripChart:: 00753 draw_cursor(int) { 00754 } 00755 00756 //////////////////////////////////////////////////////////////////// 00757 // Function: PStatStripChart::end_draw 00758 // Access: Protected, Virtual 00759 // Description: Should be overridden by the user class. This hook 00760 // will be called after drawing a series of color bars 00761 // in the strip chart; it gives the pixel range that 00762 // was just redrawn. 00763 //////////////////////////////////////////////////////////////////// 00764 void PStatStripChart:: 00765 end_draw(int, int) { 00766 } 00767 00768 //////////////////////////////////////////////////////////////////// 00769 // Function: PStatStripChart::idle 00770 // Access: Protected, Virtual 00771 // Description: Should be overridden by the user class to perform any 00772 // other updates might be necessary after the color bars 00773 // have been redrawn. For instance, it could check the 00774 // state of _labels_changed, and redraw the labels if it 00775 // is true. 00776 //////////////////////////////////////////////////////////////////// 00777 void PStatStripChart:: 00778 idle() { 00779 } 00780 00781 00782 // STL function object for sorting labels in order by the collector's 00783 // sort index, used in update_labels(), below. 00784 class SortCollectorLabels2 { 00785 public: 00786 SortCollectorLabels2(const PStatClientData *client_data) : 00787 _client_data(client_data) { 00788 } 00789 bool operator () (int a, int b) const { 00790 return 00791 _client_data->get_collector_def(a)._sort > 00792 _client_data->get_collector_def(b)._sort; 00793 } 00794 const PStatClientData *_client_data; 00795 }; 00796 00797 //////////////////////////////////////////////////////////////////// 00798 // Function: PStatStripChart::update_labels 00799 // Access: Protected, Virtual 00800 // Description: Resets the list of labels. 00801 //////////////////////////////////////////////////////////////////// 00802 void PStatStripChart:: 00803 update_labels() { 00804 const PStatViewLevel *level = _view.get_level(_collector_index); 00805 _labels.clear(); 00806 00807 int num_children = level->get_num_children(); 00808 for (int i = 0; i < num_children; i++) { 00809 const PStatViewLevel *child = level->get_child(i); 00810 int collector_index = child->get_collector(); 00811 if (is_label_used(collector_index)) { 00812 _labels.push_back(collector_index); 00813 } 00814 } 00815 00816 SortCollectorLabels2 sort_labels(get_monitor()->get_client_data()); 00817 sort(_labels.begin(), _labels.end(), sort_labels); 00818 00819 int collector_index = level->get_collector(); 00820 _labels.push_back(collector_index); 00821 00822 _labels_changed = true; 00823 _level_index = _view.get_level_index(); 00824 } 00825 00826 //////////////////////////////////////////////////////////////////// 00827 // Function: PStatStripChart::normal_guide_bars 00828 // Access: Protected, Virtual 00829 // Description: Calls update_guide_bars with parameters suitable to 00830 // this kind of graph. 00831 //////////////////////////////////////////////////////////////////// 00832 void PStatStripChart:: 00833 normal_guide_bars() { 00834 update_guide_bars(4, _value_height); 00835 } 00836 00837 00838 //////////////////////////////////////////////////////////////////// 00839 // Function: PStatStripChart::draw_frames 00840 // Access: Private 00841 // Description: Draws the levels for the indicated frame range. 00842 //////////////////////////////////////////////////////////////////// 00843 void PStatStripChart:: 00844 draw_frames(int first_frame, int last_frame) { 00845 const PStatThreadData *thread_data = _view.get_thread_data(); 00846 00847 last_frame = min(last_frame, thread_data->get_latest_frame_number()); 00848 00849 if (_first_data) { 00850 if (_scroll_mode) { 00851 _start_time = 00852 thread_data->get_frame(last_frame).get_start() - _time_width; 00853 } else { 00854 _start_time = thread_data->get_frame(first_frame).get_start(); 00855 _cursor_pixel = 0; 00856 } 00857 } 00858 00859 int first_pixel; 00860 if (thread_data->has_frame(first_frame)) { 00861 first_pixel = 00862 timestamp_to_pixel(thread_data->get_frame(first_frame).get_start()); 00863 } else { 00864 first_pixel = 0; 00865 } 00866 00867 int last_pixel = 00868 timestamp_to_pixel(thread_data->get_frame(last_frame).get_start()); 00869 00870 if (_first_data && !_scroll_mode) { 00871 first_pixel = min(_cursor_pixel, first_pixel); 00872 } 00873 _first_data = false; 00874 00875 if (last_pixel - first_pixel >= _xsize) { 00876 // If we're drawing the whole thing all in this one swoop, just 00877 // start over. 00878 _start_time = thread_data->get_frame(last_frame).get_start() - _time_width; 00879 first_pixel = 0; 00880 last_pixel = _xsize; 00881 } 00882 00883 if (last_pixel <= _xsize) { 00884 // It all fits in one block. 00885 _cursor_pixel = last_pixel; 00886 draw_pixels(first_pixel, last_pixel); 00887 00888 } else { 00889 if (_scroll_mode) { 00890 // In scrolling mode, slide the world back. 00891 int slide_pixels = last_pixel - _xsize; 00892 copy_region(slide_pixels, first_pixel, 0); 00893 first_pixel -= slide_pixels; 00894 last_pixel -= slide_pixels; 00895 _start_time += (double)slide_pixels / (double)_xsize * _time_width; 00896 draw_pixels(first_pixel, last_pixel); 00897 00898 } else { 00899 // In wrapping mode, do it in two blocks. 00900 _cursor_pixel = -1; 00901 draw_pixels(first_pixel, _xsize); 00902 _start_time = pixel_to_timestamp(_xsize); 00903 last_pixel -= _xsize; 00904 _cursor_pixel = last_pixel; 00905 draw_pixels(0, last_pixel); 00906 } 00907 } 00908 } 00909 00910 //////////////////////////////////////////////////////////////////// 00911 // Function: PStatStripChart::draw_pixels 00912 // Access: Private 00913 // Description: Draws the levels for the indicated pixel range. 00914 //////////////////////////////////////////////////////////////////// 00915 void PStatStripChart:: 00916 draw_pixels(int first_pixel, int last_pixel) { 00917 begin_draw(first_pixel, last_pixel); 00918 const PStatThreadData *thread_data = _view.get_thread_data(); 00919 00920 if (_average_mode && !thread_data->is_empty()) { 00921 // In average mode, we have to calculate the average value for each pixel. 00922 double start_time = pixel_to_timestamp(first_pixel); 00923 int then_i = thread_data->get_frame_number_at_time(start_time - pstats_average_time); 00924 int now_i = thread_data->get_frame_number_at_time(start_time, then_i); 00925 for (int x = first_pixel; x <= last_pixel; x++) { 00926 if (x == _cursor_pixel && !_scroll_mode) { 00927 draw_cursor(x); 00928 } else { 00929 FrameData fdata; 00930 compute_average_pixel_data(fdata, then_i, now_i, pixel_to_timestamp(x)); 00931 draw_slice(x, 1, fdata); 00932 } 00933 } 00934 00935 } else { 00936 // When average mode is false, we are in frame mode; just show the 00937 // actual frame data. 00938 int frame_number = -1; 00939 int x = first_pixel; 00940 while (x <= last_pixel) { 00941 if (x == _cursor_pixel && !_scroll_mode) { 00942 draw_cursor(x); 00943 x++; 00944 00945 } else { 00946 double time = pixel_to_timestamp(x); 00947 frame_number = thread_data->get_frame_number_at_time(time, frame_number); 00948 int w = 1; 00949 int stop_pixel = last_pixel; 00950 if (!_scroll_mode) { 00951 stop_pixel = min(stop_pixel, _cursor_pixel); 00952 } 00953 while (x + w < stop_pixel && 00954 thread_data->get_frame_number_at_time(pixel_to_timestamp(x + w), frame_number) == frame_number) { 00955 w++; 00956 } 00957 if (thread_data->has_frame(frame_number)) { 00958 draw_slice(x, w, get_frame_data(frame_number)); 00959 } else { 00960 draw_empty(x, w); 00961 } 00962 x += w; 00963 } 00964 } 00965 } 00966 00967 end_draw(first_pixel, last_pixel); 00968 } 00969 00970 //////////////////////////////////////////////////////////////////// 00971 // Function: PStatStripChart::clear_label_usage 00972 // Access: Private 00973 // Description: Erases all elements from the label usage data. 00974 //////////////////////////////////////////////////////////////////// 00975 void PStatStripChart:: 00976 clear_label_usage() { 00977 _label_usage.clear(); 00978 } 00979 00980 //////////////////////////////////////////////////////////////////// 00981 // Function: PStatStripChart::dec_label_usage 00982 // Access: Private 00983 // Description: Erases the indicated frame data from the current 00984 // label usage. This indicates that the given FrameData 00985 // has fallen off the end of the chart. This must have 00986 // been proceeded by an earlier call to 00987 // inc_label_usage() for the same FrameData 00988 //////////////////////////////////////////////////////////////////// 00989 void PStatStripChart:: 00990 dec_label_usage(const FrameData &fdata) { 00991 FrameData::const_iterator fi; 00992 for (fi = fdata.begin(); fi != fdata.end(); ++fi) { 00993 const ColorData &cd = (*fi); 00994 nassertv(cd._collector_index < (int)_label_usage.size()); 00995 nassertv(_label_usage[cd._collector_index] > 0); 00996 _label_usage[cd._collector_index]--; 00997 if (_label_usage[cd._collector_index] == 0) { 00998 // If a label drops out of usage, it's time to regenerate 00999 // labels. 01000 _level_index = -1; 01001 } 01002 } 01003 } 01004 01005 //////////////////////////////////////////////////////////////////// 01006 // Function: PStatStripChart::inc_label_usage 01007 // Access: Private 01008 // Description: Records the labels named in the indicated FrameData 01009 // in the table of current labels in use. This should 01010 // be called when the given FrameData has been added to 01011 // the chart; it will increment the reference count for 01012 // each collector named in the FrameData. The reference 01013 // count will eventually be decremented when 01014 // dec_label_usage() is called later. 01015 //////////////////////////////////////////////////////////////////// 01016 void PStatStripChart:: 01017 inc_label_usage(const FrameData &fdata) { 01018 FrameData::const_iterator fi; 01019 for (fi = fdata.begin(); fi != fdata.end(); ++fi) { 01020 const ColorData &cd = (*fi); 01021 while (cd._collector_index >= (int)_label_usage.size()) { 01022 _label_usage.push_back(0); 01023 } 01024 nassertv(_label_usage[cd._collector_index] >= 0); 01025 _label_usage[cd._collector_index]++; 01026 if (_label_usage[cd._collector_index] == 1) { 01027 // If a label appears for the first time, it's time to 01028 // regenerate labels. 01029 _level_index = -1; 01030 } 01031 } 01032 }