@@ -1938,11 +1938,6 @@ void TimelineEventBufferedRecorder::PrintTraceEvent(
19381938}
19391939#endif // !defined(PRODUCT)
19401940
1941- TimelineEventBlock* TimelineEventFixedBufferRecorder::GetHeadBlockLocked () {
1942- ASSERT (lock_.IsOwnedByCurrentThread ());
1943- return &blocks_[0 ];
1944- }
1945-
19461941void TimelineEventFixedBufferRecorder::ClearLocked () {
19471942 ASSERT (lock_.IsOwnedByCurrentThread ());
19481943 for (intptr_t i = 0 ; i < num_blocks_; i++) {
@@ -2151,14 +2146,7 @@ static void TimelineEventFileRecorderBaseStart(uword parameter) {
21512146}
21522147
21532148TimelineEventFileRecorderBase::TimelineEventFileRecorderBase (const char * path)
2154- : TimelineEventPlatformRecorder(),
2155- monitor_(),
2156- head_(nullptr ),
2157- tail_(nullptr ),
2158- file_(nullptr ),
2159- shutting_down_(false ),
2160- drained_(false ),
2161- thread_id_(OSThread::kInvalidThreadJoinId ) {
2149+ : TimelineEventRecorder() {
21622150 Dart_FileOpenCallback file_open = Dart::file_open_callback ();
21632151 Dart_FileWriteCallback file_write = Dart::file_write_callback ();
21642152 Dart_FileCloseCallback file_close = Dart::file_close_callback ();
@@ -2189,8 +2177,20 @@ TimelineEventFileRecorderBase::~TimelineEventFileRecorderBase() {
21892177 OSThread::Join (thread_id_);
21902178 thread_id_ = OSThread::kInvalidThreadJoinId ;
21912179
2192- ASSERT (head_ == nullptr );
2193- ASSERT (tail_ == nullptr );
2180+ // At this point all blocks created by this recorder should be drained
2181+ // and placed into |empty_blocks_|. Delete all of them.
2182+ ASSERT (drained_);
2183+ ASSERT (completed_blocks_head_ == nullptr );
2184+ ASSERT (completed_blocks_tail_ == nullptr );
2185+ while (empty_blocks_ != nullptr ) {
2186+ auto block = empty_blocks_;
2187+ empty_blocks_ = empty_blocks_->next ();
2188+ delete block;
2189+ block_count_--;
2190+ }
2191+ ASSERT (block_count_ == 0 );
2192+
2193+ FlushBuffer ();
21942194
21952195 Dart_FileCloseCallback file_close = Dart::file_close_callback ();
21962196 (*file_close)(file_);
@@ -2202,36 +2202,83 @@ void TimelineEventFileRecorderBase::Drain() {
22022202 thread_id_ = OSThread::GetCurrentThreadJoinId (OSThread::Current ());
22032203 ml.Notify ();
22042204 for (;;) {
2205- if (head_ == nullptr ) {
2205+ if (completed_blocks_head_ == nullptr ) {
2206+ ASSERT (completed_blocks_tail_ == nullptr );
22062207 if (shutting_down_) {
22072208 break ;
22082209 }
22092210 ml.Wait ();
22102211 continue ; // Recheck empty.
22112212 }
2212- TimelineEvent* event = head_;
2213- TimelineEvent* next = event->next ();
2214- head_ = next;
2215- if (next == nullptr ) {
2216- tail_ = nullptr ;
2217- }
2218- ml.Exit ();
2213+ // Take the whole list of pending blocks and drain all of them.
2214+ auto blocks = completed_blocks_head_;
2215+ completed_blocks_tail_ = completed_blocks_head_ = nullptr ;
22192216 {
2220- DrainImpl (*event );
2221- delete event ;
2217+ MonitorLeaveScope leave_ml (&ml );
2218+ DrainBlockChain (blocks) ;
22222219 }
2223- ml.Enter ();
22242220 }
22252221 drained_ = true ;
22262222 ml.Notify ();
22272223}
22282224
2229- void TimelineEventFileRecorderBase::Write (const char * buffer,
2230- intptr_t len) const {
2225+ void TimelineEventFileRecorderBase::DrainBlockChain (TimelineEventBlock* block) {
2226+ while (block != nullptr ) {
2227+ auto next_block = block->next ();
2228+ block->set_next (nullptr );
2229+
2230+ for (intptr_t i = 0 , length = block->length (); i < length; i++) {
2231+ DrainImpl (*block->At (i));
2232+ }
2233+ block->Reset ();
2234+
2235+ // Place block for reuse.
2236+ {
2237+ MonitorLocker ml (&monitor_);
2238+ block->set_next (empty_blocks_);
2239+ empty_blocks_ = block;
2240+ }
2241+ block = next_block;
2242+ }
2243+ }
2244+
2245+ void TimelineEventFileRecorderBase::FlushBuffer () {
2246+ if (buffer_pos_ != 0 ) {
2247+ WriteToFile (buffer_.get (), buffer_pos_);
2248+ buffer_pos_ = 0 ;
2249+ }
2250+ }
2251+
2252+ void TimelineEventFileRecorderBase::Write (const char * bytes, intptr_t length) {
2253+ if (length >= kBufferSize / 2 ) {
2254+ FlushBuffer ();
2255+ WriteToFile (bytes, length);
2256+ return ;
2257+ }
2258+
2259+ do {
2260+ intptr_t space_left = kBufferSize - buffer_pos_;
2261+ intptr_t bytes_to_write = Utils::Minimum (length, space_left);
2262+ memcpy (buffer_.get () + buffer_pos_, bytes, bytes_to_write); // NOLINT
2263+ buffer_pos_ += bytes_to_write;
2264+ length -= bytes_to_write;
2265+ bytes += bytes_to_write;
2266+ if (buffer_pos_ == kBufferSize ) {
2267+ FlushBuffer ();
2268+ }
2269+ } while (length > 0 );
2270+ }
2271+
2272+ void TimelineEventFileRecorderBase::WriteToFile (const char * buffer,
2273+ intptr_t len) const {
22312274 Dart_FileWriteCallback file_write = Dart::file_write_callback ();
22322275 (*file_write)(buffer, len, file_);
22332276}
22342277
2278+ TimelineEvent* TimelineEventFileRecorderBase::StartEvent () {
2279+ return ThreadBlockStartEvent ();
2280+ }
2281+
22352282void TimelineEventFileRecorderBase::CompleteEvent (TimelineEvent* event) {
22362283 if (event == nullptr ) {
22372284 return ;
@@ -2240,17 +2287,26 @@ void TimelineEventFileRecorderBase::CompleteEvent(TimelineEvent* event) {
22402287 delete event;
22412288 return ;
22422289 }
2290+ ThreadBlockCompleteEvent (event);
2291+ }
22432292
2244- MonitorLocker ml (&monitor_);
2245- ASSERT (!shutting_down_);
2246- event->set_next (nullptr );
2247- if (tail_ == nullptr ) {
2248- head_ = tail_ = event;
2249- } else {
2250- tail_->set_next (event);
2251- tail_ = event;
2293+ void TimelineEventFileRecorderBase::FinishBlock (TimelineEventBlock* block) {
2294+ TimelineEventRecorder::FinishBlock (block);
2295+
2296+ if (block != nullptr ) {
2297+ // Append completed block to the end of the list of completed blocks.
2298+ // We want to keep events from the same thread ordered in sequentially
2299+ // in the output.
2300+ MonitorLocker ml (&monitor_);
2301+ block->set_next (nullptr );
2302+ if (completed_blocks_tail_ != nullptr ) {
2303+ completed_blocks_tail_->set_next (block);
2304+ completed_blocks_tail_ = block;
2305+ } else {
2306+ completed_blocks_head_ = completed_blocks_tail_ = block;
2307+ }
2308+ ml.Notify ();
22522309 }
2253- ml.Notify ();
22542310}
22552311
22562312void TimelineEventFileRecorderBase::StartUp (const char * name) {
@@ -2274,6 +2330,37 @@ void TimelineEventFileRecorderBase::ShutDown() {
22742330 }
22752331}
22762332
2333+ TimelineEventBlock* TimelineEventFileRecorderBase::GetNewBlockLocked () {
2334+ ASSERT (lock_.IsOwnedByCurrentThread ());
2335+ // Start by reusing a block.
2336+ TimelineEventBlock* block = nullptr ;
2337+ if (empty_blocks_ != nullptr ) {
2338+ // TODO(vegorov) maybe we don't want to take a lock just to grab an empty
2339+ // block?
2340+ MonitorLocker ml (&monitor_);
2341+ if (empty_blocks_ != nullptr ) {
2342+ block = empty_blocks_;
2343+ empty_blocks_ = empty_blocks_->next ();
2344+ if (FLAG_trace_timeline) {
2345+ OS::PrintErr (" Reused empty block %p\n " , block);
2346+ }
2347+ }
2348+ }
2349+ if (block == nullptr ) {
2350+ block = new TimelineEventBlock (block_count_++);
2351+ if (FLAG_trace_timeline) {
2352+ OS::PrintErr (" Created new block %p\n " , block);
2353+ }
2354+ }
2355+ block->Open ();
2356+
2357+ return block;
2358+ }
2359+
2360+ void TimelineEventFileRecorderBase::ClearLocked () {
2361+ ASSERT (lock_.IsOwnedByCurrentThread ());
2362+ }
2363+
22772364TimelineEventFileRecorder::TimelineEventFileRecorder (const char * path)
22782365 : TimelineEventFileRecorderBase(path), first_(true ) {
22792366 // Chrome trace format has two forms:
@@ -2295,7 +2382,7 @@ void TimelineEventFileRecorder::AddTrackMetadataBasedOnThread(
22952382 const intptr_t process_id,
22962383 const intptr_t trace_id,
22972384 const char * thread_name) {
2298- TimelineEvent* event = new TimelineEvent ();
2385+ TimelineEvent* event = StartEvent ();
22992386 event->Metadata (" thread_name" );
23002387 event->SetNumArguments (1 );
23012388 event->CopyArgument (0 , " name" , thread_name);
@@ -2327,8 +2414,7 @@ class TimelineEventPerfettoFileRecorder : public TimelineEventFileRecorderBase {
23272414
23282415 private:
23292416 void WritePacket (
2330- protozero::HeapBuffered<perfetto::protos::pbzero::TracePacket>* packet)
2331- const ;
2417+ protozero::HeapBuffered<perfetto::protos::pbzero::TracePacket>* packet);
23322418 void DrainImpl (const TimelineEvent& event) final ;
23332419
23342420 TracePacketWriter writer_;
@@ -2361,9 +2447,10 @@ TimelineEventPerfettoFileRecorder::TimelineEventPerfettoFileRecorder(
23612447}
23622448
23632449TimelineEventPerfettoFileRecorder::~TimelineEventPerfettoFileRecorder () {
2450+ ShutDown ();
2451+
23642452 protozero::HeapBuffered<perfetto::protos::pbzero::TracePacket>& packet =
23652453 this ->packet ();
2366- ShutDown ();
23672454 // We do not need to lock the following section, because at this point
23682455 // |RecorderSynchronizationLock| must have been put in a state that prevents
23692456 // the metadata maps from being modified.
@@ -2388,15 +2475,14 @@ TimelineEventPerfettoFileRecorder::~TimelineEventPerfettoFileRecorder() {
23882475}
23892476
23902477void TimelineEventPerfettoFileRecorder::WritePacket (
2391- protozero::HeapBuffered<perfetto::protos::pbzero::TracePacket>* packet)
2392- const {
2478+ protozero::HeapBuffered<perfetto::protos::pbzero::TracePacket>* packet) {
23932479 const std::tuple<std::unique_ptr<const uint8_t []>, intptr_t >& response =
23942480 perfetto_utils::GetProtoPreamble (packet);
23952481 Write (reinterpret_cast <const char *>(std::get<0 >(response).get ()),
23962482 std::get<1 >(response));
23972483 for (const protozero::ScatteredHeapBuffer::Slice& slice :
23982484 packet->GetSlices ()) {
2399- Write (reinterpret_cast <char *>(slice.start ()),
2485+ Write (reinterpret_cast <const char *>(slice.start ()),
24002486 slice.size () - slice.unused_bytes ());
24012487 }
24022488}
@@ -2435,11 +2521,6 @@ void TimelineEventEndlessRecorder::ForEachNonEmptyBlock(
24352521}
24362522#endif // !defined(PRODUCT)
24372523
2438- TimelineEventBlock* TimelineEventEndlessRecorder::GetHeadBlockLocked () {
2439- ASSERT (lock_.IsOwnedByCurrentThread ());
2440- return head_;
2441- }
2442-
24432524TimelineEvent* TimelineEventEndlessRecorder::StartEvent () {
24442525 return ThreadBlockStartEvent ();
24452526}
0 commit comments