Profiler.cc revision 7454:3a3e8e8cce1b
1/* 2 * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29/* 30 This file has been modified by Kevin Moore and Dan Nussbaum of the 31 Scalable Systems Research Group at Sun Microsystems Laboratories 32 (http://research.sun.com/scalable/) to support the Adaptive 33 Transactional Memory Test Platform (ATMTP). 34 35 Please send email to atmtp-interest@sun.com with feedback, questions, or 36 to request future announcements about ATMTP. 37 38 ---------------------------------------------------------------------- 39 40 File modification date: 2008-02-23 41 42 ---------------------------------------------------------------------- 43*/ 44 45// Allows use of times() library call, which determines virtual runtime 46#include <sys/resource.h> 47#include <sys/times.h> 48 49#include <algorithm> 50 51#include "base/stl_helpers.hh" 52#include "base/str.hh" 53#include "mem/gems_common/Map.hh" 54#include "mem/gems_common/PrioHeap.hh" 55#include "mem/protocol/CacheMsg.hh" 56#include "mem/protocol/MachineType.hh" 57#include "mem/protocol/Protocol.hh" 58#include "mem/ruby/common/Debug.hh" 59#include "mem/ruby/network/Network.hh" 60#include "mem/ruby/profiler/AddressProfiler.hh" 61#include "mem/ruby/profiler/Profiler.hh" 62#include "mem/ruby/system/System.hh" 63#include "mem/ruby/system/System.hh" 64 65using namespace std; 66using m5::stl_helpers::operator<<; 67 68extern ostream* debug_cout_ptr; 69 70static double process_memory_total(); 71static double process_memory_resident(); 72 73Profiler::Profiler(const Params *p) 74 : SimObject(p) 75{ 76 m_requestProfileMap_ptr = new Map<string, int>; 77 78 m_inst_profiler_ptr = NULL; 79 m_address_profiler_ptr = NULL; 80 81 m_real_time_start_time = time(NULL); // Not reset in clearStats() 82 m_stats_period = 1000000; // Default 83 m_periodic_output_file_ptr = &cerr; 84 85 m_hot_lines = p->hot_lines; 86 m_all_instructions = p->all_instructions; 87 88 m_num_of_sequencers = p->num_of_sequencers; 89 90 m_hot_lines = false; 91 m_all_instructions = false; 92 93 m_address_profiler_ptr = new AddressProfiler(m_num_of_sequencers); 94 m_address_profiler_ptr->setHotLines(m_hot_lines); 95 m_address_profiler_ptr->setAllInstructions(m_all_instructions); 96 97 if (m_all_instructions) { 98 m_inst_profiler_ptr = new AddressProfiler(m_num_of_sequencers); 99 m_inst_profiler_ptr->setHotLines(m_hot_lines); 100 m_inst_profiler_ptr->setAllInstructions(m_all_instructions); 101 } 102} 103 104Profiler::~Profiler() 105{ 106 if (m_periodic_output_file_ptr != &cerr) { 107 delete m_periodic_output_file_ptr; 108 } 109 110 delete m_requestProfileMap_ptr; 111} 112 113void 114Profiler::wakeup() 115{ 116 // FIXME - avoid the repeated code 117 118 vector<integer_t> perProcCycleCount(m_num_of_sequencers); 119 120 for (int i = 0; i < m_num_of_sequencers; i++) { 121 perProcCycleCount[i] = 122 g_system_ptr->getCycleCount(i) - m_cycles_executed_at_start[i] + 1; 123 // The +1 allows us to avoid division by zero 124 } 125 126 ostream &out = *m_periodic_output_file_ptr; 127 128 out << "ruby_cycles: " << g_eventQueue_ptr->getTime()-m_ruby_start << endl 129 << "mbytes_resident: " << process_memory_resident() << endl 130 << "mbytes_total: " << process_memory_total() << endl; 131 132 if (process_memory_total() > 0) { 133 out << "resident_ratio: " 134 << process_memory_resident() / process_memory_total() << endl; 135 } 136 137 out << "miss_latency: " << m_allMissLatencyHistogram << endl; 138 139 out << endl; 140 141 if (m_all_instructions) { 142 m_inst_profiler_ptr->printStats(out); 143 } 144 145 //g_system_ptr->getNetwork()->printStats(out); 146 g_eventQueue_ptr->scheduleEvent(this, m_stats_period); 147} 148 149void 150Profiler::setPeriodicStatsFile(const string& filename) 151{ 152 cout << "Recording periodic statistics to file '" << filename << "' every " 153 << m_stats_period << " Ruby cycles" << endl; 154 155 if (m_periodic_output_file_ptr != &cerr) { 156 delete m_periodic_output_file_ptr; 157 } 158 159 m_periodic_output_file_ptr = new ofstream(filename.c_str()); 160 g_eventQueue_ptr->scheduleEvent(this, 1); 161} 162 163void 164Profiler::setPeriodicStatsInterval(integer_t period) 165{ 166 cout << "Recording periodic statistics every " << m_stats_period 167 << " Ruby cycles" << endl; 168 169 m_stats_period = period; 170 g_eventQueue_ptr->scheduleEvent(this, 1); 171} 172 173void 174Profiler::printConfig(ostream& out) const 175{ 176 out << endl; 177 out << "Profiler Configuration" << endl; 178 out << "----------------------" << endl; 179 out << "periodic_stats_period: " << m_stats_period << endl; 180} 181 182void 183Profiler::print(ostream& out) const 184{ 185 out << "[Profiler]"; 186} 187 188void 189Profiler::printStats(ostream& out, bool short_stats) 190{ 191 out << endl; 192 if (short_stats) { 193 out << "SHORT "; 194 } 195 out << "Profiler Stats" << endl; 196 out << "--------------" << endl; 197 198 time_t real_time_current = time(NULL); 199 double seconds = difftime(real_time_current, m_real_time_start_time); 200 double minutes = seconds / 60.0; 201 double hours = minutes / 60.0; 202 double days = hours / 24.0; 203 Time ruby_cycles = g_eventQueue_ptr->getTime()-m_ruby_start; 204 205 if (!short_stats) { 206 out << "Elapsed_time_in_seconds: " << seconds << endl; 207 out << "Elapsed_time_in_minutes: " << minutes << endl; 208 out << "Elapsed_time_in_hours: " << hours << endl; 209 out << "Elapsed_time_in_days: " << days << endl; 210 out << endl; 211 } 212 213 // print the virtual runtimes as well 214 struct tms vtime; 215 times(&vtime); 216 seconds = (vtime.tms_utime + vtime.tms_stime) / 100.0; 217 minutes = seconds / 60.0; 218 hours = minutes / 60.0; 219 days = hours / 24.0; 220 out << "Virtual_time_in_seconds: " << seconds << endl; 221 out << "Virtual_time_in_minutes: " << minutes << endl; 222 out << "Virtual_time_in_hours: " << hours << endl; 223 out << "Virtual_time_in_days: " << days << endl; 224 out << endl; 225 226 out << "Ruby_current_time: " << g_eventQueue_ptr->getTime() << endl; 227 out << "Ruby_start_time: " << m_ruby_start << endl; 228 out << "Ruby_cycles: " << ruby_cycles << endl; 229 out << endl; 230 231 if (!short_stats) { 232 out << "mbytes_resident: " << process_memory_resident() << endl; 233 out << "mbytes_total: " << process_memory_total() << endl; 234 if (process_memory_total() > 0) { 235 out << "resident_ratio: " 236 << process_memory_resident()/process_memory_total() << endl; 237 } 238 out << endl; 239 } 240 241 vector<integer_t> perProcCycleCount(m_num_of_sequencers); 242 243 for (int i = 0; i < m_num_of_sequencers; i++) { 244 perProcCycleCount[i] = 245 g_system_ptr->getCycleCount(i) - m_cycles_executed_at_start[i] + 1; 246 // The +1 allows us to avoid division by zero 247 } 248 249 out << "ruby_cycles_executed: " << perProcCycleCount << endl; 250 251 out << endl; 252 253 if (!short_stats) { 254 out << "Busy Controller Counts:" << endl; 255 for (int i = 0; i < MachineType_NUM; i++) { 256 int size = MachineType_base_count((MachineType)i); 257 for (int j = 0; j < size; j++) { 258 MachineID machID; 259 machID.type = (MachineType)i; 260 machID.num = j; 261 out << machID << ":" << m_busyControllerCount[i][j] << " "; 262 if ((j + 1) % 8 == 0) { 263 out << endl; 264 } 265 } 266 out << endl; 267 } 268 out << endl; 269 270 out << "Busy Bank Count:" << m_busyBankCount << endl; 271 out << endl; 272 273 out << "sequencer_requests_outstanding: " 274 << m_sequencer_requests << endl; 275 out << endl; 276 } 277 278 if (!short_stats) { 279 out << "All Non-Zero Cycle Demand Cache Accesses" << endl; 280 out << "----------------------------------------" << endl; 281 out << "miss_latency: " << m_allMissLatencyHistogram << endl; 282 for (int i = 0; i < m_missLatencyHistograms.size(); i++) { 283 if (m_missLatencyHistograms[i].size() > 0) { 284 out << "miss_latency_" << RubyRequestType(i) << ": " 285 << m_missLatencyHistograms[i] << endl; 286 } 287 } 288 for (int i = 0; i < m_machLatencyHistograms.size(); i++) { 289 if (m_machLatencyHistograms[i].size() > 0) { 290 out << "miss_latency_" << GenericMachineType(i) << ": " 291 << m_machLatencyHistograms[i] << endl; 292 } 293 } 294 295 out << endl; 296 297 out << "All Non-Zero Cycle SW Prefetch Requests" << endl; 298 out << "------------------------------------" << endl; 299 out << "prefetch_latency: " << m_allSWPrefetchLatencyHistogram << endl; 300 for (int i = 0; i < m_SWPrefetchLatencyHistograms.size(); i++) { 301 if (m_SWPrefetchLatencyHistograms[i].size() > 0) { 302 out << "prefetch_latency_" << CacheRequestType(i) << ": " 303 << m_SWPrefetchLatencyHistograms[i] << endl; 304 } 305 } 306 for (int i = 0; i < m_SWPrefetchMachLatencyHistograms.size(); i++) { 307 if (m_SWPrefetchMachLatencyHistograms[i].size() > 0) { 308 out << "prefetch_latency_" << GenericMachineType(i) << ": " 309 << m_SWPrefetchMachLatencyHistograms[i] << endl; 310 } 311 } 312 out << "prefetch_latency_L2Miss:" 313 << m_SWPrefetchL2MissLatencyHistogram << endl; 314 315 if (m_all_sharing_histogram.size() > 0) { 316 out << "all_sharing: " << m_all_sharing_histogram << endl; 317 out << "read_sharing: " << m_read_sharing_histogram << endl; 318 out << "write_sharing: " << m_write_sharing_histogram << endl; 319 320 out << "all_sharing_percent: "; 321 m_all_sharing_histogram.printPercent(out); 322 out << endl; 323 324 out << "read_sharing_percent: "; 325 m_read_sharing_histogram.printPercent(out); 326 out << endl; 327 328 out << "write_sharing_percent: "; 329 m_write_sharing_histogram.printPercent(out); 330 out << endl; 331 332 int64 total_miss = m_cache_to_cache + m_memory_to_cache; 333 out << "all_misses: " << total_miss << endl; 334 out << "cache_to_cache_misses: " << m_cache_to_cache << endl; 335 out << "memory_to_cache_misses: " << m_memory_to_cache << endl; 336 out << "cache_to_cache_percent: " 337 << 100.0 * (double(m_cache_to_cache) / double(total_miss)) 338 << endl; 339 out << "memory_to_cache_percent: " 340 << 100.0 * (double(m_memory_to_cache) / double(total_miss)) 341 << endl; 342 out << endl; 343 } 344 345 if (m_outstanding_requests.size() > 0) { 346 out << "outstanding_requests: "; 347 m_outstanding_requests.printPercent(out); 348 out << endl; 349 out << endl; 350 } 351 } 352 353 if (!short_stats) { 354 out << "Request vs. RubySystem State Profile" << endl; 355 out << "--------------------------------" << endl; 356 out << endl; 357 358 vector<string> requestProfileKeys = m_requestProfileMap_ptr->keys(); 359 sort(requestProfileKeys.begin(), requestProfileKeys.end()); 360 361 for (int i = 0; i < requestProfileKeys.size(); i++) { 362 int temp_int = 363 m_requestProfileMap_ptr->lookup(requestProfileKeys[i]); 364 double percent = (100.0 * double(temp_int)) / double(m_requests); 365 vector<string> items; 366 tokenize(items, requestProfileKeys[i], ':'); 367 vector<string>::iterator i = items.begin(); 368 vector<string>::iterator end = items.end(); 369 for (; i != end; ++i) 370 out << setw(10) << *i; 371 out << setw(11) << temp_int; 372 out << setw(14) << percent << endl; 373 } 374 out << endl; 375 376 out << "filter_action: " << m_filter_action_histogram << endl; 377 378 if (!m_all_instructions) { 379 m_address_profiler_ptr->printStats(out); 380 } 381 382 if (m_all_instructions) { 383 m_inst_profiler_ptr->printStats(out); 384 } 385 386 out << endl; 387 out << "Message Delayed Cycles" << endl; 388 out << "----------------------" << endl; 389 out << "Total_delay_cycles: " << m_delayedCyclesHistogram << endl; 390 out << "Total_nonPF_delay_cycles: " 391 << m_delayedCyclesNonPFHistogram << endl; 392 for (int i = 0; i < m_delayedCyclesVCHistograms.size(); i++) { 393 out << " virtual_network_" << i << "_delay_cycles: " 394 << m_delayedCyclesVCHistograms[i] << endl; 395 } 396 397 printResourceUsage(out); 398 } 399} 400 401void 402Profiler::printResourceUsage(ostream& out) const 403{ 404 out << endl; 405 out << "Resource Usage" << endl; 406 out << "--------------" << endl; 407 408 integer_t pagesize = getpagesize(); // page size in bytes 409 out << "page_size: " << pagesize << endl; 410 411 rusage usage; 412 getrusage (RUSAGE_SELF, &usage); 413 414 out << "user_time: " << usage.ru_utime.tv_sec << endl; 415 out << "system_time: " << usage.ru_stime.tv_sec << endl; 416 out << "page_reclaims: " << usage.ru_minflt << endl; 417 out << "page_faults: " << usage.ru_majflt << endl; 418 out << "swaps: " << usage.ru_nswap << endl; 419 out << "block_inputs: " << usage.ru_inblock << endl; 420 out << "block_outputs: " << usage.ru_oublock << endl; 421} 422 423void 424Profiler::clearStats() 425{ 426 m_ruby_start = g_eventQueue_ptr->getTime(); 427 428 m_cycles_executed_at_start.resize(m_num_of_sequencers); 429 for (int i = 0; i < m_num_of_sequencers; i++) { 430 if (g_system_ptr == NULL) { 431 m_cycles_executed_at_start[i] = 0; 432 } else { 433 m_cycles_executed_at_start[i] = g_system_ptr->getCycleCount(i); 434 } 435 } 436 437 m_busyControllerCount.resize(MachineType_NUM); // all machines 438 for (int i = 0; i < MachineType_NUM; i++) { 439 int size = MachineType_base_count((MachineType)i); 440 m_busyControllerCount[i].resize(size); 441 for (int j = 0; j < size; j++) { 442 m_busyControllerCount[i][j] = 0; 443 } 444 } 445 m_busyBankCount = 0; 446 447 m_delayedCyclesHistogram.clear(); 448 m_delayedCyclesNonPFHistogram.clear(); 449 int size = RubySystem::getNetwork()->getNumberOfVirtualNetworks(); 450 m_delayedCyclesVCHistograms.resize(size); 451 for (int i = 0; i < size; i++) { 452 m_delayedCyclesVCHistograms[i].clear(); 453 } 454 455 m_missLatencyHistograms.resize(RubyRequestType_NUM); 456 for (int i = 0; i < m_missLatencyHistograms.size(); i++) { 457 m_missLatencyHistograms[i].clear(200); 458 } 459 m_machLatencyHistograms.resize(GenericMachineType_NUM+1); 460 for (int i = 0; i < m_machLatencyHistograms.size(); i++) { 461 m_machLatencyHistograms[i].clear(200); 462 } 463 m_allMissLatencyHistogram.clear(200); 464 465 m_SWPrefetchLatencyHistograms.resize(CacheRequestType_NUM); 466 for (int i = 0; i < m_SWPrefetchLatencyHistograms.size(); i++) { 467 m_SWPrefetchLatencyHistograms[i].clear(200); 468 } 469 m_SWPrefetchMachLatencyHistograms.resize(GenericMachineType_NUM+1); 470 for (int i = 0; i < m_SWPrefetchMachLatencyHistograms.size(); i++) { 471 m_SWPrefetchMachLatencyHistograms[i].clear(200); 472 } 473 m_allSWPrefetchLatencyHistogram.clear(200); 474 475 m_sequencer_requests.clear(); 476 m_read_sharing_histogram.clear(); 477 m_write_sharing_histogram.clear(); 478 m_all_sharing_histogram.clear(); 479 m_cache_to_cache = 0; 480 m_memory_to_cache = 0; 481 482 // clear HashMaps 483 m_requestProfileMap_ptr->clear(); 484 485 // count requests profiled 486 m_requests = 0; 487 488 m_outstanding_requests.clear(); 489 m_outstanding_persistent_requests.clear(); 490 491 // Flush the prefetches through the system - used so that there 492 // are no outstanding requests after stats are cleared 493 //g_eventQueue_ptr->triggerAllEvents(); 494 495 // update the start time 496 m_ruby_start = g_eventQueue_ptr->getTime(); 497} 498 499void 500Profiler::addAddressTraceSample(const CacheMsg& msg, NodeID id) 501{ 502 if (msg.getType() != CacheRequestType_IFETCH) { 503 // Note: The following line should be commented out if you 504 // want to use the special profiling that is part of the GS320 505 // protocol 506 507 // NOTE: Unless PROFILE_HOT_LINES is enabled, nothing will be 508 // profiled by the AddressProfiler 509 m_address_profiler_ptr-> 510 addTraceSample(msg.getLineAddress(), msg.getProgramCounter(), 511 msg.getType(), msg.getAccessMode(), id, false); 512 } 513} 514 515void 516Profiler::profileSharing(const Address& addr, AccessType type, 517 NodeID requestor, const Set& sharers, 518 const Set& owner) 519{ 520 Set set_contacted(owner); 521 if (type == AccessType_Write) { 522 set_contacted.addSet(sharers); 523 } 524 set_contacted.remove(requestor); 525 int number_contacted = set_contacted.count(); 526 527 if (type == AccessType_Write) { 528 m_write_sharing_histogram.add(number_contacted); 529 } else { 530 m_read_sharing_histogram.add(number_contacted); 531 } 532 m_all_sharing_histogram.add(number_contacted); 533 534 if (number_contacted == 0) { 535 m_memory_to_cache++; 536 } else { 537 m_cache_to_cache++; 538 } 539} 540 541void 542Profiler::profileMsgDelay(int virtualNetwork, int delayCycles) 543{ 544 assert(virtualNetwork < m_delayedCyclesVCHistograms.size()); 545 m_delayedCyclesHistogram.add(delayCycles); 546 m_delayedCyclesVCHistograms[virtualNetwork].add(delayCycles); 547 if (virtualNetwork != 0) { 548 m_delayedCyclesNonPFHistogram.add(delayCycles); 549 } 550} 551 552// profiles original cache requests including PUTs 553void 554Profiler::profileRequest(const string& requestStr) 555{ 556 m_requests++; 557 558 if (m_requestProfileMap_ptr->exist(requestStr)) { 559 (m_requestProfileMap_ptr->lookup(requestStr))++; 560 } else { 561 m_requestProfileMap_ptr->add(requestStr, 1); 562 } 563} 564 565void 566Profiler::controllerBusy(MachineID machID) 567{ 568 m_busyControllerCount[(int)machID.type][(int)machID.num]++; 569} 570 571void 572Profiler::profilePFWait(Time waitTime) 573{ 574 m_prefetchWaitHistogram.add(waitTime); 575} 576 577void 578Profiler::bankBusy() 579{ 580 m_busyBankCount++; 581} 582 583// non-zero cycle demand request 584void 585Profiler::missLatency(Time t, RubyRequestType type) 586{ 587 m_allMissLatencyHistogram.add(t); 588 m_missLatencyHistograms[type].add(t); 589} 590 591// non-zero cycle prefetch request 592void 593Profiler::swPrefetchLatency(Time t, CacheRequestType type, 594 GenericMachineType respondingMach) 595{ 596 m_allSWPrefetchLatencyHistogram.add(t); 597 m_SWPrefetchLatencyHistograms[type].add(t); 598 m_SWPrefetchMachLatencyHistograms[respondingMach].add(t); 599 if (respondingMach == GenericMachineType_Directory || 600 respondingMach == GenericMachineType_NUM) { 601 m_SWPrefetchL2MissLatencyHistogram.add(t); 602 } 603} 604 605void 606Profiler::profileTransition(const string& component, NodeID version, 607 Address addr, const string& state, const string& event, 608 const string& next_state, const string& note) 609{ 610 const int EVENT_SPACES = 20; 611 const int ID_SPACES = 3; 612 const int TIME_SPACES = 7; 613 const int COMP_SPACES = 10; 614 const int STATE_SPACES = 6; 615 616 if (g_debug_ptr->getDebugTime() <= 0 || 617 g_eventQueue_ptr->getTime() < g_debug_ptr->getDebugTime()) 618 return; 619 620 ostream &out = *debug_cout_ptr; 621 out.flags(ios::right); 622 out << setw(TIME_SPACES) << g_eventQueue_ptr->getTime() << " "; 623 out << setw(ID_SPACES) << version << " "; 624 out << setw(COMP_SPACES) << component; 625 out << setw(EVENT_SPACES) << event << " "; 626 627 out.flags(ios::right); 628 out << setw(STATE_SPACES) << state; 629 out << ">"; 630 out.flags(ios::left); 631 out << setw(STATE_SPACES) << next_state; 632 633 out << " " << addr << " " << note; 634 635 out << endl; 636} 637 638// Helper function 639static double 640process_memory_total() 641{ 642 // 4kB page size, 1024*1024 bytes per MB, 643 const double MULTIPLIER = 4096.0 / (1024.0 * 1024.0); 644 ifstream proc_file; 645 proc_file.open("/proc/self/statm"); 646 int total_size_in_pages = 0; 647 int res_size_in_pages = 0; 648 proc_file >> total_size_in_pages; 649 proc_file >> res_size_in_pages; 650 return double(total_size_in_pages) * MULTIPLIER; // size in megabytes 651} 652 653static double 654process_memory_resident() 655{ 656 // 4kB page size, 1024*1024 bytes per MB, 657 const double MULTIPLIER = 4096.0 / (1024.0 * 1024.0); 658 ifstream proc_file; 659 proc_file.open("/proc/self/statm"); 660 int total_size_in_pages = 0; 661 int res_size_in_pages = 0; 662 proc_file >> total_size_in_pages; 663 proc_file >> res_size_in_pages; 664 return double(res_size_in_pages) * MULTIPLIER; // size in megabytes 665} 666 667void 668Profiler::rubyWatch(int id) 669{ 670 uint64 tr = 0; 671 Address watch_address = Address(tr); 672 const int ID_SPACES = 3; 673 const int TIME_SPACES = 7; 674 675 ostream &out = *debug_cout_ptr; 676 677 out.flags(ios::right); 678 out << setw(TIME_SPACES) << g_eventQueue_ptr->getTime() << " "; 679 out << setw(ID_SPACES) << id << " " 680 << "RUBY WATCH " << watch_address << endl; 681 682 if (!m_watch_address_list_ptr->exist(watch_address)) { 683 m_watch_address_list_ptr->add(watch_address, 1); 684 } 685} 686 687bool 688Profiler::watchAddress(Address addr) 689{ 690 if (m_watch_address_list_ptr->exist(addr)) 691 return true; 692 else 693 return false; 694} 695 696Profiler * 697RubyProfilerParams::create() 698{ 699 return new Profiler(this); 700} 701