| OLD | NEW |
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/compiler_stats.h" | 5 #include "vm/compiler_stats.h" |
| 6 | 6 |
| 7 #include "vm/flags.h" | 7 #include "vm/flags.h" |
| 8 #include "vm/log.h" | 8 #include "vm/log.h" |
| 9 #include "vm/object_graph.h" | 9 #include "vm/object_graph.h" |
| 10 #include "vm/object_store.h" | 10 #include "vm/object_store.h" |
| 11 #include "vm/timer.h" | 11 #include "vm/timer.h" |
| 12 | 12 |
| 13 | |
| 14 namespace dart { | 13 namespace dart { |
| 15 | 14 |
| 16 DEFINE_FLAG(bool, compiler_stats, false, "Compiler stat counters."); | 15 DEFINE_FLAG(bool, compiler_stats, false, "Compiler stat counters."); |
| 17 DEFINE_FLAG(bool, | 16 DEFINE_FLAG(bool, |
| 18 compiler_benchmark, | 17 compiler_benchmark, |
| 19 false, | 18 false, |
| 20 "Compiler stat counters for benchmark."); | 19 "Compiler stat counters for benchmark."); |
| 21 | 20 |
| 22 | |
| 23 class TokenStreamVisitor : public ObjectVisitor { | 21 class TokenStreamVisitor : public ObjectVisitor { |
| 24 public: | 22 public: |
| 25 explicit TokenStreamVisitor(CompilerStats* compiler_stats) | 23 explicit TokenStreamVisitor(CompilerStats* compiler_stats) |
| 26 : obj_(Object::Handle()), stats_(compiler_stats) {} | 24 : obj_(Object::Handle()), stats_(compiler_stats) {} |
| 27 | 25 |
| 28 void VisitObject(RawObject* raw_obj) { | 26 void VisitObject(RawObject* raw_obj) { |
| 29 if (raw_obj->IsPseudoObject()) { | 27 if (raw_obj->IsPseudoObject()) { |
| 30 return; // Cannot be wrapped in handles. | 28 return; // Cannot be wrapped in handles. |
| 31 } | 29 } |
| 32 obj_ = raw_obj; | 30 obj_ = raw_obj; |
| 33 if (obj_.GetClassId() == TokenStream::kClassId) { | 31 if (obj_.GetClassId() == TokenStream::kClassId) { |
| 34 TokenStream::Iterator tkit( | 32 TokenStream::Iterator tkit( |
| 35 Thread::Current()->zone(), TokenStream::Cast(obj_), | 33 Thread::Current()->zone(), TokenStream::Cast(obj_), |
| 36 TokenPosition::kMinSource, TokenStream::Iterator::kNoNewlines); | 34 TokenPosition::kMinSource, TokenStream::Iterator::kNoNewlines); |
| 37 Token::Kind kind = tkit.CurrentTokenKind(); | 35 Token::Kind kind = tkit.CurrentTokenKind(); |
| 38 while (kind != Token::kEOS) { | 36 while (kind != Token::kEOS) { |
| 39 ++stats_->num_tokens_total; | 37 ++stats_->num_tokens_total; |
| 40 tkit.Advance(); | 38 tkit.Advance(); |
| 41 kind = tkit.CurrentTokenKind(); | 39 kind = tkit.CurrentTokenKind(); |
| 42 } | 40 } |
| 43 } | 41 } |
| 44 } | 42 } |
| 45 | 43 |
| 46 private: | 44 private: |
| 47 Object& obj_; | 45 Object& obj_; |
| 48 CompilerStats* stats_; | 46 CompilerStats* stats_; |
| 49 }; | 47 }; |
| 50 | 48 |
| 51 | |
| 52 CompilerStats::CompilerStats(Isolate* isolate) | 49 CompilerStats::CompilerStats(Isolate* isolate) |
| 53 : isolate_(isolate), | 50 : isolate_(isolate), |
| 54 #define INITIALIZE_TIMER(timer_name, description) timer_name(true, description), | 51 #define INITIALIZE_TIMER(timer_name, description) timer_name(true, description), |
| 55 STAT_TIMERS(INITIALIZE_TIMER) | 52 STAT_TIMERS(INITIALIZE_TIMER) |
| 56 #undef INITIALIZE_TIMER | 53 #undef INITIALIZE_TIMER |
| 57 | 54 |
| 58 #define INITIALIZE_COUNTERS(counter_name) counter_name(0), | 55 #define INITIALIZE_COUNTERS(counter_name) counter_name(0), |
| 59 STAT_COUNTERS(INITIALIZE_COUNTERS) | 56 STAT_COUNTERS(INITIALIZE_COUNTERS) |
| 60 #undef INITIALIZE_COUNTERS | 57 #undef INITIALIZE_COUNTERS |
| 61 text(NULL), | 58 text(NULL), |
| 62 use_benchmark_output(false) { | 59 use_benchmark_output(false) { |
| 63 } | 60 } |
| 64 | 61 |
| 65 | |
| 66 #ifndef PRODUCT | 62 #ifndef PRODUCT |
| 67 | 63 |
| 68 | |
| 69 // Used to aggregate stats. Must be atomic. | 64 // Used to aggregate stats. Must be atomic. |
| 70 void CompilerStats::Add(const CompilerStats& other) { | 65 void CompilerStats::Add(const CompilerStats& other) { |
| 71 #define ADD_TOTAL(timer_name, literal) timer_name.AddTotal(other.timer_name); | 66 #define ADD_TOTAL(timer_name, literal) timer_name.AddTotal(other.timer_name); |
| 72 | 67 |
| 73 STAT_TIMERS(ADD_TOTAL) | 68 STAT_TIMERS(ADD_TOTAL) |
| 74 #undef ADD_TOTAL | 69 #undef ADD_TOTAL |
| 75 | 70 |
| 76 #define ADD_COUNTER(counter_name) \ | 71 #define ADD_COUNTER(counter_name) \ |
| 77 AtomicOperations::IncrementInt64By(&counter_name, other.counter_name); | 72 AtomicOperations::IncrementInt64By(&counter_name, other.counter_name); |
| 78 | 73 |
| 79 STAT_COUNTERS(ADD_COUNTER) | 74 STAT_COUNTERS(ADD_COUNTER) |
| 80 #undef ADD_COUNTER | 75 #undef ADD_COUNTER |
| 81 } | 76 } |
| 82 | 77 |
| 83 | |
| 84 void CompilerStats::Clear() { | 78 void CompilerStats::Clear() { |
| 85 #define CLEAR_TIMER(timer_name, literal) timer_name.Reset(); | 79 #define CLEAR_TIMER(timer_name, literal) timer_name.Reset(); |
| 86 | 80 |
| 87 STAT_TIMERS(CLEAR_TIMER) | 81 STAT_TIMERS(CLEAR_TIMER) |
| 88 #undef CLEAR_TIMER | 82 #undef CLEAR_TIMER |
| 89 | 83 |
| 90 #define CLEAR_COUNTER(counter_name) counter_name = 0; | 84 #define CLEAR_COUNTER(counter_name) counter_name = 0; |
| 91 | 85 |
| 92 STAT_COUNTERS(CLEAR_COUNTER) | 86 STAT_COUNTERS(CLEAR_COUNTER) |
| 93 #undef CLEAR_COUNTER | 87 #undef CLEAR_COUNTER |
| 94 } | 88 } |
| 95 | 89 |
| 96 | |
| 97 bool CompilerStats::IsCleared() const { | 90 bool CompilerStats::IsCleared() const { |
| 98 #define CHECK_TIMERS(timer_name, literal) \ | 91 #define CHECK_TIMERS(timer_name, literal) \ |
| 99 if (!timer_name.IsReset()) return false; | 92 if (!timer_name.IsReset()) return false; |
| 100 | 93 |
| 101 STAT_TIMERS(CHECK_TIMERS) | 94 STAT_TIMERS(CHECK_TIMERS) |
| 102 #undef CHECK_TIMERS | 95 #undef CHECK_TIMERS |
| 103 | 96 |
| 104 #define CHECK_COUNTERS(counter_name) \ | 97 #define CHECK_COUNTERS(counter_name) \ |
| 105 if (counter_name != 0) return false; | 98 if (counter_name != 0) return false; |
| 106 | 99 |
| 107 STAT_COUNTERS(CHECK_COUNTERS) | 100 STAT_COUNTERS(CHECK_COUNTERS) |
| 108 #undef CHECK_COUNTERS | 101 #undef CHECK_COUNTERS |
| 109 return true; | 102 return true; |
| 110 } | 103 } |
| 111 | 104 |
| 112 | |
| 113 // This function is used as a callback in the log object to which the | 105 // This function is used as a callback in the log object to which the |
| 114 // compiler stats are printed. It will be called only once, to print | 106 // compiler stats are printed. It will be called only once, to print |
| 115 // the accumulated text when all of the compiler stats values are | 107 // the accumulated text when all of the compiler stats values are |
| 116 // added to the log. | 108 // added to the log. |
| 117 static void PrintToStats(const char* format, ...) PRINTF_ATTRIBUTE(1, 2); | 109 static void PrintToStats(const char* format, ...) PRINTF_ATTRIBUTE(1, 2); |
| 118 static void PrintToStats(const char* format, ...) { | 110 static void PrintToStats(const char* format, ...) { |
| 119 Thread* thread = Thread::Current(); | 111 Thread* thread = Thread::Current(); |
| 120 Isolate* isolate = thread->isolate(); | 112 Isolate* isolate = thread->isolate(); |
| 121 CompilerStats* stats = isolate->aggregate_compiler_stats(); | 113 CompilerStats* stats = isolate->aggregate_compiler_stats(); |
| 122 Zone* zone = thread->zone(); | 114 Zone* zone = thread->zone(); |
| 123 ASSERT(stats != NULL); | 115 ASSERT(stats != NULL); |
| 124 va_list args; | 116 va_list args; |
| 125 va_start(args, format); | 117 va_start(args, format); |
| 126 stats->text = zone->VPrint(format, args); | 118 stats->text = zone->VPrint(format, args); |
| 127 va_end(args); | 119 va_end(args); |
| 128 } | 120 } |
| 129 | 121 |
| 130 | |
| 131 void CompilerStats::Update() { | 122 void CompilerStats::Update() { |
| 132 // Traverse the heap and compute number of tokens in all | 123 // Traverse the heap and compute number of tokens in all |
| 133 // TokenStream objects. | 124 // TokenStream objects. |
| 134 num_tokens_total = 0; | 125 num_tokens_total = 0; |
| 135 TokenStreamVisitor visitor(this); | 126 TokenStreamVisitor visitor(this); |
| 136 isolate_->heap()->IterateObjects(&visitor); | 127 isolate_->heap()->IterateObjects(&visitor); |
| 137 Dart::vm_isolate()->heap()->IterateObjects(&visitor); | 128 Dart::vm_isolate()->heap()->IterateObjects(&visitor); |
| 138 } | 129 } |
| 139 | 130 |
| 140 | |
| 141 void CompilerStats::EnableBenchmark() { | 131 void CompilerStats::EnableBenchmark() { |
| 142 FLAG_compiler_stats = true; | 132 FLAG_compiler_stats = true; |
| 143 use_benchmark_output = true; | 133 use_benchmark_output = true; |
| 144 } | 134 } |
| 145 | 135 |
| 146 | |
| 147 // Generate output for Golem benchmark harness. If the output format | 136 // Generate output for Golem benchmark harness. If the output format |
| 148 // changes, the parsing function in Golem must be updated. | 137 // changes, the parsing function in Golem must be updated. |
| 149 char* CompilerStats::BenchmarkOutput() { | 138 char* CompilerStats::BenchmarkOutput() { |
| 150 Update(); | 139 Update(); |
| 151 Log log(PrintToStats); | 140 Log log(PrintToStats); |
| 152 LogBlock lb(Thread::Current(), &log); | 141 LogBlock lb(Thread::Current(), &log); |
| 153 log.Print("==== Compiler Stats for isolate '%s' ====\n", | 142 log.Print("==== Compiler Stats for isolate '%s' ====\n", |
| 154 isolate_->debugger_name()); | 143 isolate_->debugger_name()); |
| 155 | 144 |
| 156 log.Print("NumberOfTokens: %" Pd64 "\n", num_tokens_total); | 145 log.Print("NumberOfTokens: %" Pd64 "\n", num_tokens_total); |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 191 : 0; | 180 : 0; |
| 192 | 181 |
| 193 log.Print("CodeDensity: %" Pd64 " tokens/KB\n", code_density); | 182 log.Print("CodeDensity: %" Pd64 " tokens/KB\n", code_density); |
| 194 log.Print("InstrSize: %" Pd64 " KB\n", total_instr_size / 1024); | 183 log.Print("InstrSize: %" Pd64 " KB\n", total_instr_size / 1024); |
| 195 log.Flush(); | 184 log.Flush(); |
| 196 char* benchmark_text = text; | 185 char* benchmark_text = text; |
| 197 text = NULL; | 186 text = NULL; |
| 198 return benchmark_text; | 187 return benchmark_text; |
| 199 } | 188 } |
| 200 | 189 |
| 201 | |
| 202 char* CompilerStats::PrintToZone() { | 190 char* CompilerStats::PrintToZone() { |
| 203 if (!FLAG_compiler_stats) { | 191 if (!FLAG_compiler_stats) { |
| 204 return NULL; | 192 return NULL; |
| 205 } else if (use_benchmark_output) { | 193 } else if (use_benchmark_output) { |
| 206 return BenchmarkOutput(); | 194 return BenchmarkOutput(); |
| 207 } | 195 } |
| 208 | 196 |
| 209 Update(); | 197 Update(); |
| 210 | 198 |
| 211 Log log(PrintToStats); | 199 Log log(PrintToStats); |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 307 log.Print(" VarDesc size: %" Pd64 " KB\n", vardesc_size / 1024); | 295 log.Print(" VarDesc size: %" Pd64 " KB\n", vardesc_size / 1024); |
| 308 log.Flush(); | 296 log.Flush(); |
| 309 char* stats_text = text; | 297 char* stats_text = text; |
| 310 text = NULL; | 298 text = NULL; |
| 311 return stats_text; | 299 return stats_text; |
| 312 } | 300 } |
| 313 | 301 |
| 314 #endif // !PRODUCT | 302 #endif // !PRODUCT |
| 315 | 303 |
| 316 } // namespace dart | 304 } // namespace dart |
| OLD | NEW |