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