| OLD | NEW |
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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 <cstdlib> | 5 #include <cstdlib> |
| 6 | 6 |
| 7 #include "vm/atomic.h" | 7 #include "vm/atomic.h" |
| 8 #include "vm/isolate.h" | 8 #include "vm/isolate.h" |
| 9 #include "vm/json_stream.h" | 9 #include "vm/json_stream.h" |
| 10 #include "vm/lockers.h" | 10 #include "vm/lockers.h" |
| 11 #include "vm/log.h" | 11 #include "vm/log.h" |
| 12 #include "vm/object.h" | 12 #include "vm/object.h" |
| 13 #include "vm/service_event.h" | 13 #include "vm/service_event.h" |
| 14 #include "vm/thread.h" | 14 #include "vm/thread.h" |
| 15 #include "vm/timeline.h" | 15 #include "vm/timeline.h" |
| 16 | 16 |
| 17 namespace dart { | 17 namespace dart { |
| 18 | 18 |
| 19 #ifndef PRODUCT | 19 #ifndef PRODUCT |
| 20 | 20 |
| 21 DEFINE_FLAG(bool, complete_timeline, false, "Record the complete timeline"); | 21 DEFINE_FLAG(bool, complete_timeline, false, "Record the complete timeline"); |
| 22 DEFINE_FLAG(bool, startup_timeline, false, "Record the startup timeline"); |
| 22 DEFINE_FLAG(bool, trace_timeline, false, | 23 DEFINE_FLAG(bool, trace_timeline, false, |
| 23 "Trace timeline backend"); | 24 "Trace timeline backend"); |
| 24 DEFINE_FLAG(bool, trace_timeline_analysis, false, | 25 DEFINE_FLAG(bool, trace_timeline_analysis, false, |
| 25 "Trace timeline analysis backend"); | 26 "Trace timeline analysis backend"); |
| 26 DEFINE_FLAG(bool, timing, false, | 27 DEFINE_FLAG(bool, timing, false, |
| 27 "Dump isolate timing information from timeline."); | 28 "Dump isolate timing information from timeline."); |
| 28 DEFINE_FLAG(charp, timeline_dir, NULL, | 29 DEFINE_FLAG(charp, timeline_dir, NULL, |
| 29 "Enable all timeline trace streams and output VM global trace " | 30 "Enable all timeline trace streams and output VM global trace " |
| 30 "into specified directory."); | 31 "into specified directory."); |
| 31 DEFINE_FLAG(charp, timeline_streams, NULL, | 32 DEFINE_FLAG(charp, timeline_streams, NULL, |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 104 } | 105 } |
| 105 for (intptr_t i = 0; i < streams->length(); i++) { | 106 for (intptr_t i = 0; i < streams->length(); i++) { |
| 106 free((*streams)[i]); | 107 free((*streams)[i]); |
| 107 } | 108 } |
| 108 delete streams; | 109 delete streams; |
| 109 } | 110 } |
| 110 | 111 |
| 111 | 112 |
| 112 // Returns true if |streams| contains |stream| or "all". Not case sensitive. | 113 // Returns true if |streams| contains |stream| or "all". Not case sensitive. |
| 113 static bool HasStream(MallocGrowableArray<char*>* streams, const char* stream) { | 114 static bool HasStream(MallocGrowableArray<char*>* streams, const char* stream) { |
| 114 if ((FLAG_timeline_dir != NULL) || FLAG_timing || FLAG_complete_timeline) { | 115 if ((FLAG_timeline_dir != NULL) || |
| 116 FLAG_timing || FLAG_complete_timeline || FLAG_startup_timeline) { |
| 115 return true; | 117 return true; |
| 116 } | 118 } |
| 117 for (intptr_t i = 0; i < streams->length(); i++) { | 119 for (intptr_t i = 0; i < streams->length(); i++) { |
| 118 const char* checked_stream = (*streams)[i]; | 120 const char* checked_stream = (*streams)[i]; |
| 119 if ((strstr(checked_stream, "all") != NULL) || | 121 if ((strstr(checked_stream, "all") != NULL) || |
| 120 (strstr(checked_stream, stream) != NULL)) { | 122 (strstr(checked_stream, stream) != NULL)) { |
| 121 return true; | 123 return true; |
| 122 } | 124 } |
| 123 } | 125 } |
| 124 return false; | 126 return false; |
| 125 } | 127 } |
| 126 | 128 |
| 127 | 129 |
| 128 void Timeline::InitOnce() { | 130 void Timeline::InitOnce() { |
| 129 ASSERT(recorder_ == NULL); | 131 ASSERT(recorder_ == NULL); |
| 130 // Default to ring recorder being enabled. | 132 // Default to ring recorder being enabled. |
| 131 const bool use_ring_recorder = true; | 133 const bool use_ring_recorder = true; |
| 132 // Some flags require that we use the endless recorder. | 134 // Some flags require that we use the endless recorder. |
| 133 const bool use_endless_recorder = | 135 const bool use_endless_recorder = |
| 134 (FLAG_timeline_dir != NULL) || FLAG_timing || FLAG_complete_timeline; | 136 (FLAG_timeline_dir != NULL) || FLAG_timing || FLAG_complete_timeline; |
| 135 if (use_endless_recorder) { | 137 if (use_endless_recorder) { |
| 136 recorder_ = new TimelineEventEndlessRecorder(); | 138 recorder_ = new TimelineEventEndlessRecorder(); |
| 139 } else if (FLAG_startup_timeline) { |
| 140 recorder_ = new TimelineEventStartupRecorder(); |
| 137 } else if (use_ring_recorder) { | 141 } else if (use_ring_recorder) { |
| 138 recorder_ = new TimelineEventRingRecorder(); | 142 recorder_ = new TimelineEventRingRecorder(); |
| 139 } | 143 } |
| 140 enabled_streams_ = GetEnabledByDefaultTimelineStreams(); | 144 enabled_streams_ = GetEnabledByDefaultTimelineStreams(); |
| 141 // Global overrides. | 145 // Global overrides. |
| 142 #define TIMELINE_STREAM_FLAG_DEFAULT(name, not_used) \ | 146 #define TIMELINE_STREAM_FLAG_DEFAULT(name, not_used) \ |
| 143 stream_##name##_enabled_ = HasStream(enabled_streams_, #name); \ | 147 stream_##name##_enabled_ = HasStream(enabled_streams_, #name); \ |
| 144 stream_##name##_.Init(#name, \ | 148 stream_##name##_.Init(#name, \ |
| 145 stream_##name##_enabled_, \ | 149 stream_##name##_enabled_, \ |
| 146 &stream_##name##_enabled_); | 150 &stream_##name##_enabled_); |
| (...skipping 900 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1047 block->Finish(); | 1051 block->Finish(); |
| 1048 } | 1052 } |
| 1049 | 1053 |
| 1050 | 1054 |
| 1051 TimelineEventBlock* TimelineEventRecorder::GetNewBlock() { | 1055 TimelineEventBlock* TimelineEventRecorder::GetNewBlock() { |
| 1052 MutexLocker ml(&lock_); | 1056 MutexLocker ml(&lock_); |
| 1053 return GetNewBlockLocked(); | 1057 return GetNewBlockLocked(); |
| 1054 } | 1058 } |
| 1055 | 1059 |
| 1056 | 1060 |
| 1057 TimelineEventRingRecorder::TimelineEventRingRecorder(intptr_t capacity) | 1061 TimelineEventFixedBufferRecorder::TimelineEventFixedBufferRecorder( |
| 1062 intptr_t capacity) |
| 1058 : blocks_(NULL), | 1063 : blocks_(NULL), |
| 1059 capacity_(capacity), | 1064 capacity_(capacity), |
| 1060 num_blocks_(0), | 1065 num_blocks_(0), |
| 1061 block_cursor_(0) { | 1066 block_cursor_(0) { |
| 1062 // Capacity must be a multiple of TimelineEventBlock::kBlockSize | 1067 // Capacity must be a multiple of TimelineEventBlock::kBlockSize |
| 1063 ASSERT((capacity % TimelineEventBlock::kBlockSize) == 0); | 1068 ASSERT((capacity % TimelineEventBlock::kBlockSize) == 0); |
| 1064 // Allocate blocks array. | 1069 // Allocate blocks array. |
| 1065 num_blocks_ = capacity / TimelineEventBlock::kBlockSize; | 1070 num_blocks_ = capacity / TimelineEventBlock::kBlockSize; |
| 1066 blocks_ = | 1071 blocks_ = |
| 1067 reinterpret_cast<TimelineEventBlock**>( | 1072 reinterpret_cast<TimelineEventBlock**>( |
| 1068 calloc(num_blocks_, sizeof(TimelineEventBlock*))); | 1073 calloc(num_blocks_, sizeof(TimelineEventBlock*))); |
| 1069 // Allocate each block. | 1074 // Allocate each block. |
| 1070 for (intptr_t i = 0; i < num_blocks_; i++) { | 1075 for (intptr_t i = 0; i < num_blocks_; i++) { |
| 1071 blocks_[i] = new TimelineEventBlock(i); | 1076 blocks_[i] = new TimelineEventBlock(i); |
| 1072 } | 1077 } |
| 1073 // Chain blocks together. | 1078 // Chain blocks together. |
| 1074 for (intptr_t i = 0; i < num_blocks_ - 1; i++) { | 1079 for (intptr_t i = 0; i < num_blocks_ - 1; i++) { |
| 1075 blocks_[i]->set_next(blocks_[i + 1]); | 1080 blocks_[i]->set_next(blocks_[i + 1]); |
| 1076 } | 1081 } |
| 1077 } | 1082 } |
| 1078 | 1083 |
| 1079 | 1084 |
| 1080 TimelineEventRingRecorder::~TimelineEventRingRecorder() { | 1085 TimelineEventFixedBufferRecorder::~TimelineEventFixedBufferRecorder() { |
| 1081 // Delete all blocks. | 1086 // Delete all blocks. |
| 1082 for (intptr_t i = 0; i < num_blocks_; i++) { | 1087 for (intptr_t i = 0; i < num_blocks_; i++) { |
| 1083 TimelineEventBlock* block = blocks_[i]; | 1088 TimelineEventBlock* block = blocks_[i]; |
| 1084 delete block; | 1089 delete block; |
| 1085 } | 1090 } |
| 1086 free(blocks_); | 1091 free(blocks_); |
| 1087 } | 1092 } |
| 1088 | 1093 |
| 1089 | 1094 |
| 1090 void TimelineEventRingRecorder::PrintJSONEvents( | 1095 void TimelineEventFixedBufferRecorder::PrintJSONEvents( |
| 1091 JSONArray* events, | 1096 JSONArray* events, |
| 1092 TimelineEventFilter* filter) { | 1097 TimelineEventFilter* filter) { |
| 1093 if (!FLAG_support_service) { | 1098 if (!FLAG_support_service) { |
| 1094 return; | 1099 return; |
| 1095 } | 1100 } |
| 1096 MutexLocker ml(&lock_); | 1101 MutexLocker ml(&lock_); |
| 1097 intptr_t block_offset = FindOldestBlockIndex(); | 1102 intptr_t block_offset = FindOldestBlockIndex(); |
| 1098 if (block_offset == -1) { | 1103 if (block_offset == -1) { |
| 1099 // All blocks are empty. | 1104 // All blocks are empty. |
| 1100 return; | 1105 return; |
| 1101 } | 1106 } |
| 1102 for (intptr_t block_idx = 0; block_idx < num_blocks_; block_idx++) { | 1107 for (intptr_t block_idx = 0; block_idx < num_blocks_; block_idx++) { |
| 1103 TimelineEventBlock* block = | 1108 TimelineEventBlock* block = |
| 1104 blocks_[(block_idx + block_offset) % num_blocks_]; | 1109 blocks_[(block_idx + block_offset) % num_blocks_]; |
| 1105 if (!filter->IncludeBlock(block)) { | 1110 if (!filter->IncludeBlock(block)) { |
| 1106 continue; | 1111 continue; |
| 1107 } | 1112 } |
| 1108 for (intptr_t event_idx = 0; event_idx < block->length(); event_idx++) { | 1113 for (intptr_t event_idx = 0; event_idx < block->length(); event_idx++) { |
| 1109 TimelineEvent* event = block->At(event_idx); | 1114 TimelineEvent* event = block->At(event_idx); |
| 1110 if (filter->IncludeEvent(event) && | 1115 if (filter->IncludeEvent(event) && |
| 1111 event->Within(filter->time_origin_micros(), | 1116 event->Within(filter->time_origin_micros(), |
| 1112 filter->time_extent_micros())) { | 1117 filter->time_extent_micros())) { |
| 1113 events->AddValue(event); | 1118 events->AddValue(event); |
| 1114 } | 1119 } |
| 1115 } | 1120 } |
| 1116 } | 1121 } |
| 1117 } | 1122 } |
| 1118 | 1123 |
| 1119 | 1124 |
| 1120 void TimelineEventRingRecorder::PrintJSON(JSONStream* js, | 1125 void TimelineEventFixedBufferRecorder::PrintJSON(JSONStream* js, |
| 1121 TimelineEventFilter* filter) { | 1126 TimelineEventFilter* filter) { |
| 1122 if (!FLAG_support_service) { | 1127 if (!FLAG_support_service) { |
| 1123 return; | 1128 return; |
| 1124 } | 1129 } |
| 1125 JSONObject topLevel(js); | 1130 JSONObject topLevel(js); |
| 1126 topLevel.AddProperty("type", "_Timeline"); | 1131 topLevel.AddProperty("type", "_Timeline"); |
| 1127 { | 1132 { |
| 1128 JSONArray events(&topLevel, "traceEvents"); | 1133 JSONArray events(&topLevel, "traceEvents"); |
| 1129 PrintJSONMeta(&events); | 1134 PrintJSONMeta(&events); |
| 1130 PrintJSONEvents(&events, filter); | 1135 PrintJSONEvents(&events, filter); |
| 1131 } | 1136 } |
| 1132 } | 1137 } |
| 1133 | 1138 |
| 1134 | 1139 |
| 1135 void TimelineEventRingRecorder::PrintTraceEvent(JSONStream* js, | 1140 void TimelineEventFixedBufferRecorder::PrintTraceEvent( |
| 1136 TimelineEventFilter* filter) { | 1141 JSONStream* js, |
| 1142 TimelineEventFilter* filter) { |
| 1137 if (!FLAG_support_service) { | 1143 if (!FLAG_support_service) { |
| 1138 return; | 1144 return; |
| 1139 } | 1145 } |
| 1140 JSONArray events(js); | 1146 JSONArray events(js); |
| 1141 PrintJSONEvents(&events, filter); | 1147 PrintJSONEvents(&events, filter); |
| 1142 } | 1148 } |
| 1143 | 1149 |
| 1144 | 1150 |
| 1145 TimelineEventBlock* TimelineEventRingRecorder::GetHeadBlockLocked() { | 1151 TimelineEventBlock* TimelineEventFixedBufferRecorder::GetHeadBlockLocked() { |
| 1146 return blocks_[0]; | 1152 return blocks_[0]; |
| 1147 } | 1153 } |
| 1148 | 1154 |
| 1149 | 1155 |
| 1150 TimelineEventBlock* TimelineEventRingRecorder::GetNewBlockLocked() { | 1156 void TimelineEventFixedBufferRecorder::Clear() { |
| 1151 // TODO(johnmccutchan): This function should only hand out blocks | |
| 1152 // which have been marked as finished. | |
| 1153 if (block_cursor_ == num_blocks_) { | |
| 1154 block_cursor_ = 0; | |
| 1155 } | |
| 1156 TimelineEventBlock* block = blocks_[block_cursor_++]; | |
| 1157 block->Reset(); | |
| 1158 block->Open(); | |
| 1159 return block; | |
| 1160 } | |
| 1161 | |
| 1162 | |
| 1163 void TimelineEventRingRecorder::Clear() { | |
| 1164 MutexLocker ml(&lock_); | 1157 MutexLocker ml(&lock_); |
| 1165 for (intptr_t i = 0; i < num_blocks_; i++) { | 1158 for (intptr_t i = 0; i < num_blocks_; i++) { |
| 1166 TimelineEventBlock* block = blocks_[i]; | 1159 TimelineEventBlock* block = blocks_[i]; |
| 1167 block->Reset(); | 1160 block->Reset(); |
| 1168 } | 1161 } |
| 1169 } | 1162 } |
| 1170 | 1163 |
| 1171 | 1164 |
| 1172 intptr_t TimelineEventRingRecorder::FindOldestBlockIndex() const { | 1165 intptr_t TimelineEventFixedBufferRecorder::FindOldestBlockIndex() const { |
| 1173 int64_t earliest_time = kMaxInt64; | 1166 int64_t earliest_time = kMaxInt64; |
| 1174 intptr_t earliest_index = -1; | 1167 intptr_t earliest_index = -1; |
| 1175 for (intptr_t block_idx = 0; block_idx < num_blocks_; block_idx++) { | 1168 for (intptr_t block_idx = 0; block_idx < num_blocks_; block_idx++) { |
| 1176 TimelineEventBlock* block = blocks_[block_idx]; | 1169 TimelineEventBlock* block = blocks_[block_idx]; |
| 1177 if (block->IsEmpty()) { | 1170 if (block->IsEmpty()) { |
| 1178 // Skip empty blocks. | 1171 // Skip empty blocks. |
| 1179 continue; | 1172 continue; |
| 1180 } | 1173 } |
| 1181 if (block->LowerTimeBound() < earliest_time) { | 1174 if (block->LowerTimeBound() < earliest_time) { |
| 1182 earliest_time = block->LowerTimeBound(); | 1175 earliest_time = block->LowerTimeBound(); |
| 1183 earliest_index = block_idx; | 1176 earliest_index = block_idx; |
| 1184 } | 1177 } |
| 1185 } | 1178 } |
| 1186 return earliest_index; | 1179 return earliest_index; |
| 1187 } | 1180 } |
| 1188 | 1181 |
| 1189 | 1182 |
| 1190 TimelineEvent* TimelineEventRingRecorder::StartEvent() { | 1183 TimelineEvent* TimelineEventFixedBufferRecorder::StartEvent() { |
| 1191 return ThreadBlockStartEvent(); | 1184 return ThreadBlockStartEvent(); |
| 1192 } | 1185 } |
| 1193 | 1186 |
| 1194 | 1187 |
| 1195 void TimelineEventRingRecorder::CompleteEvent(TimelineEvent* event) { | 1188 void TimelineEventFixedBufferRecorder::CompleteEvent(TimelineEvent* event) { |
| 1196 if (event == NULL) { | 1189 if (event == NULL) { |
| 1197 return; | 1190 return; |
| 1198 } | 1191 } |
| 1199 ThreadBlockCompleteEvent(event); | 1192 ThreadBlockCompleteEvent(event); |
| 1200 } | 1193 } |
| 1201 | 1194 |
| 1202 | 1195 |
| 1196 TimelineEventBlock* TimelineEventRingRecorder::GetNewBlockLocked() { |
| 1197 // TODO(johnmccutchan): This function should only hand out blocks |
| 1198 // which have been marked as finished. |
| 1199 if (block_cursor_ == num_blocks_) { |
| 1200 block_cursor_ = 0; |
| 1201 } |
| 1202 TimelineEventBlock* block = blocks_[block_cursor_++]; |
| 1203 block->Reset(); |
| 1204 block->Open(); |
| 1205 return block; |
| 1206 } |
| 1207 |
| 1208 |
| 1209 TimelineEventBlock* TimelineEventStartupRecorder::GetNewBlockLocked() { |
| 1210 if (block_cursor_ == num_blocks_) { |
| 1211 return NULL; |
| 1212 } |
| 1213 TimelineEventBlock* block = blocks_[block_cursor_++]; |
| 1214 block->Reset(); |
| 1215 block->Open(); |
| 1216 return block; |
| 1217 } |
| 1218 |
| 1219 |
| 1203 TimelineEventCallbackRecorder::TimelineEventCallbackRecorder() { | 1220 TimelineEventCallbackRecorder::TimelineEventCallbackRecorder() { |
| 1204 } | 1221 } |
| 1205 | 1222 |
| 1206 | 1223 |
| 1207 TimelineEventCallbackRecorder::~TimelineEventCallbackRecorder() { | 1224 TimelineEventCallbackRecorder::~TimelineEventCallbackRecorder() { |
| 1208 } | 1225 } |
| 1209 | 1226 |
| 1210 | 1227 |
| 1211 void TimelineEventCallbackRecorder::PrintJSON(JSONStream* js, | 1228 void TimelineEventCallbackRecorder::PrintJSON(JSONStream* js, |
| 1212 TimelineEventFilter* filter) { | 1229 TimelineEventFilter* filter) { |
| (...skipping 291 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1504 TimelineEventBlock* TimelineEventBlockIterator::Next() { | 1521 TimelineEventBlock* TimelineEventBlockIterator::Next() { |
| 1505 ASSERT(current_ != NULL); | 1522 ASSERT(current_ != NULL); |
| 1506 TimelineEventBlock* r = current_; | 1523 TimelineEventBlock* r = current_; |
| 1507 current_ = current_->next(); | 1524 current_ = current_->next(); |
| 1508 return r; | 1525 return r; |
| 1509 } | 1526 } |
| 1510 | 1527 |
| 1511 #endif // !PRODUCT | 1528 #endif // !PRODUCT |
| 1512 | 1529 |
| 1513 } // namespace dart | 1530 } // namespace dart |
| OLD | NEW |