<commit_before>// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

#include <cstdio>

#include "platform/utils.h"

#include "vm/isolate.h"
#include "vm/json_stream.h"
#include "vm/native_symbol.h"
#include "vm/object.h"
#include "vm/os.h"
#include "vm/profiler.h"
#include "vm/signal_handler.h"

namespace dart {

// Notes on locking and signal handling:
//
// The ProfilerManager has a single monitor (monitor_). This monitor guards
// access to the schedule list of isolates (isolates_, isolates_size_, etc).
//
// Each isolate has a mutex (profiler_data_mutex_) which protects access
// to the isolate's profiler data.
//
// Locks can be taken in this order:
//   1. ProfilerManager::monitor_
//   2. isolate->profiler_data_mutex_
// In other words, it is not acceptable to take ProfilerManager::monitor_
// after grabbing isolate->profiler_data_mutex_.
//
// ProfileManager::monitor_ taking entry points:
//   InitOnce, Shutdown
//       ProfilerManager::monitor_
//   ScheduleIsolate, DescheduleIsolate.
//       ProfilerManager::monitor_, isolate->profiler_data_mutex_
//   ThreadMain
// isolate->profiler_data_mutex_ taking entry points:
//     SetupIsolateForProfiling, FreeIsolateForProfiling.
//       ProfilerManager::monitor_, isolate->profiler_data_mutex_
//     ScheduleIsolate, DescheduleIsolate.
//       ProfilerManager::monitor_, isolate->profiler_data_mutex_
//     ProfileSignalAction
//       isolate->profiler_data_mutex_
//       ProfilerManager::monitor_, isolate->profiler_data_mutex_
//
// Signal handling and locking:
// On OSes with pthreads (Android, Linux, and Mac) we use signal delivery
// to interrupt the isolate running thread for sampling. After a thread
// is sent the SIGPROF, it is removed from the scheduled isolate list.
// Inside the signal handler, after the sample is taken, the isolate is
// added to the scheduled isolate list again. The side effect of this is
// that the signal handler must be able to acquire the isolate profiler data
// mutex and the profile manager monitor. When an isolate running thread
// (potential signal target) calls into an entry point which acquires
// ProfileManager::monitor_ signal delivery must be blocked. An example is
// ProfileManager::ScheduleIsolate which blocks signal delivery while removing
// the scheduling the isolate.
//

// Notes on stack frame walking:
//
// The sampling profiler will collect up to Sample::kNumStackFrames stack frames
// The stack frame walking code uses the frame pointer to traverse the stack.
// If the VM is compiled without frame pointers (which is the default on
// recent GCC versions with optimizing enabled) the stack walking code will
// fail (sometimes leading to a crash).
//


DEFINE_FLAG(bool, profile, true, "Enable Sampling Profiler");
DEFINE_FLAG(bool, trace_profiled_isolates, false, "Trace profiled isolates.");

bool ProfilerManager::initialized_ = false;
bool ProfilerManager::shutdown_ = false;
Monitor* ProfilerManager::monitor_ = NULL;
Isolate** ProfilerManager::isolates_ = NULL;
intptr_t ProfilerManager::isolates_capacity_ = 0;
intptr_t ProfilerManager::isolates_size_ = 0;


void ProfilerManager::InitOnce() {
  if (!FLAG_profile) {
    return;
  }
  NativeSymbolResolver::InitOnce();
  ASSERT(!initialized_);
  monitor_ = new Monitor();
  initialized_ = true;
  ResizeIsolates(16);
  Thread::Start(ThreadMain, 0);
}


void ProfilerManager::Shutdown() {
  if (!FLAG_profile) {
    return;
  }
  ASSERT(initialized_);
  {
    ScopedSignalBlocker ssb;
    {
      ScopedMonitor lock(monitor_);
      shutdown_ = true;
      isolates_size_ = 0;
      free(isolates_);
      isolates_ = NULL;
      lock.Notify();
    }
  }
  NativeSymbolResolver::ShutdownOnce();
}


void ProfilerManager::SetupIsolateForProfiling(Isolate* isolate) {
  if (!FLAG_profile) {
    return;
  }
  ASSERT(isolate != NULL);
  {
    ScopedSignalBlocker ssb;
    {
      ScopedMutex profiler_data_lock(isolate->profiler_data_mutex());
      SampleBuffer* sample_buffer = new SampleBuffer();
      IsolateProfilerData* profiler_data =
          new IsolateProfilerData(isolate, sample_buffer);
      profiler_data->set_sample_interval_micros(1000);
      isolate->set_profiler_data(profiler_data);
      if (FLAG_trace_profiled_isolates) {
        OS::Print("PROF SETUP %p %s %p\n",
            isolate,
            isolate->name(),
            reinterpret_cast<void*>(Thread::GetCurrentThreadId()));
      }
    }
  }
}


void ProfilerManager::FreeIsolateProfilingData(Isolate* isolate) {
  ScopedMutex profiler_data_lock(isolate->profiler_data_mutex());
  IsolateProfilerData* profiler_data = isolate->profiler_data();
  if (profiler_data == NULL) {
    // Already freed.
    return;
  }
  isolate->set_profiler_data(NULL);
  SampleBuffer* sample_buffer = profiler_data->sample_buffer();
  ASSERT(sample_buffer != NULL);
  delete sample_buffer;
  delete profiler_data;
  if (FLAG_trace_profiled_isolates) {
    OS::Print("PROF SHUTDOWN %p %s %p\n", isolate,
        isolate->name(), reinterpret_cast<void*>(Thread::GetCurrentThreadId()));
  }
}


void ProfilerManager::ShutdownIsolateForProfiling(Isolate* isolate) {
  ASSERT(isolate != NULL);
  if (!FLAG_profile) {
    return;
  }
  {
    ScopedSignalBlocker ssb;
    FreeIsolateProfilingData(isolate);
  }
}


void ProfilerManager::ScheduleIsolateHelper(Isolate* isolate) {
  ScopedMonitor lock(monitor_);
  intptr_t i = FindIsolate(isolate);
  if (i >= 0) {
    // Already scheduled.
    return;
  }
  {
    ScopedMutex profiler_data_lock(isolate->profiler_data_mutex());
    IsolateProfilerData* profiler_data = isolate->profiler_data();
    if (profiler_data == NULL) {
      return;
    }
    profiler_data->Scheduled(OS::GetCurrentTimeMicros(),
                             Thread::GetCurrentThreadId());
  }
  AddIsolate(isolate);
  lock.Notify();
}


void ProfilerManager::ScheduleIsolate(Isolate* isolate, bool inside_signal) {
  if (!FLAG_profile) {
    return;
  }<commit_msg>Always update scheduled thread id<commit_after>// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

#include <cstdio>

#include "platform/utils.h"

#include "vm/isolate.h"
#include "vm/json_stream.h"
#include "vm/native_symbol.h"
#include "vm/object.h"
#include "vm/os.h"
#include "vm/profiler.h"
#include "vm/signal_handler.h"

namespace dart {

// Notes on locking and signal handling:
//
// The ProfilerManager has a single monitor (monitor_). This monitor guards
// access to the schedule list of isolates (isolates_, isolates_size_, etc).
//
// Each isolate has a mutex (profiler_data_mutex_) which protects access
// to the isolate's profiler data.
//
// Locks can be taken in this order:
//   1. ProfilerManager::monitor_
//   2. isolate->profiler_data_mutex_
// In other words, it is not acceptable to take ProfilerManager::monitor_
// after grabbing isolate->profiler_data_mutex_.
//
// ProfileManager::monitor_ taking entry points:
//   InitOnce, Shutdown
//       ProfilerManager::monitor_
//   ScheduleIsolate, DescheduleIsolate.
//       ProfilerManager::monitor_, isolate->profiler_data_mutex_
//   ThreadMain
// isolate->profiler_data_mutex_ taking entry points:
//     SetupIsolateForProfiling, FreeIsolateForProfiling.
//       ProfilerManager::monitor_, isolate->profiler_data_mutex_
//     ScheduleIsolate, DescheduleIsolate.
//       ProfilerManager::monitor_, isolate->profiler_data_mutex_
//     ProfileSignalAction
//       isolate->profiler_data_mutex_
//       ProfilerManager::monitor_, isolate->profiler_data_mutex_
//
// Signal handling and locking:
// On OSes with pthreads (Android, Linux, and Mac) we use signal delivery
// to interrupt the isolate running thread for sampling. After a thread
// is sent the SIGPROF, it is removed from the scheduled isolate list.
// Inside the signal handler, after the sample is taken, the isolate is
// added to the scheduled isolate list again. The side effect of this is
// that the signal handler must be able to acquire the isolate profiler data
// mutex and the profile manager monitor. When an isolate running thread
// (potential signal target) calls into an entry point which acquires
// ProfileManager::monitor_ signal delivery must be blocked. An example is
// ProfileManager::ScheduleIsolate which blocks signal delivery while removing
// the scheduling the isolate.
//

// Notes on stack frame walking:
//
// The sampling profiler will collect up to Sample::kNumStackFrames stack frames
// The stack frame walking code uses the frame pointer to traverse the stack.
// If the VM is compiled without frame pointers (which is the default on
// recent GCC versions with optimizing enabled) the stack walking code will
// fail (sometimes leading to a crash).
//


DEFINE_FLAG(bool, profile, true, "Enable Sampling Profiler");
DEFINE_FLAG(bool, trace_profiled_isolates, false, "Trace profiled isolates.");

bool ProfilerManager::initialized_ = false;
bool ProfilerManager::shutdown_ = false;
Monitor* ProfilerManager::monitor_ = NULL;
Isolate** ProfilerManager::isolates_ = NULL;
intptr_t ProfilerManager::isolates_capacity_ = 0;
intptr_t ProfilerManager::isolates_size_ = 0;


void ProfilerManager::InitOnce() {
  if (!FLAG_profile) {
    return;
  }
  NativeSymbolResolver::InitOnce();
  ASSERT(!initialized_);
  monitor_ = new Monitor();
  initialized_ = true;
  ResizeIsolates(16);
  Thread::Start(ThreadMain, 0);
}


void ProfilerManager::Shutdown() {
  if (!FLAG_profile) {
    return;
  }
  ASSERT(initialized_);
  {
    ScopedSignalBlocker ssb;
    {
      ScopedMonitor lock(monitor_);
      shutdown_ = true;
      isolates_size_ = 0;
      free(isolates_);
      isolates_ = NULL;
      lock.Notify();
    }
  }
  NativeSymbolResolver::ShutdownOnce();
}


void ProfilerManager::SetupIsolateForProfiling(Isolate* isolate) {
  if (!FLAG_profile) {
    return;
  }
  ASSERT(isolate != NULL);
  {
    ScopedSignalBlocker ssb;
    {
      ScopedMutex profiler_data_lock(isolate->profiler_data_mutex());
      SampleBuffer* sample_buffer = new SampleBuffer();
      IsolateProfilerData* profiler_data =
          new IsolateProfilerData(isolate, sample_buffer);
      profiler_data->set_sample_interval_micros(1000);
      isolate->set_profiler_data(profiler_data);
      if (FLAG_trace_profiled_isolates) {
        OS::Print("PROF SETUP %p %s %p\n",
            isolate,
            isolate->name(),
            reinterpret_cast<void*>(Thread::GetCurrentThreadId()));
      }
    }
  }
}


void ProfilerManager::FreeIsolateProfilingData(Isolate* isolate) {
  ScopedMutex profiler_data_lock(isolate->profiler_data_mutex());
  IsolateProfilerData* profiler_data = isolate->profiler_data();
  if (profiler_data == NULL) {
    // Already freed.
    return;
  }
  isolate->set_profiler_data(NULL);
  SampleBuffer* sample_buffer = profiler_data->sample_buffer();
  ASSERT(sample_buffer != NULL);
  delete sample_buffer;
  delete profiler_data;
  if (FLAG_trace_profiled_isolates) {
    OS::Print("PROF SHUTDOWN %p %s %p\n", isolate,
        isolate->name(), reinterpret_cast<void*>(Thread::GetCurrentThreadId()));
  }
}


void ProfilerManager::ShutdownIsolateForProfiling(Isolate* isolate) {
  ASSERT(isolate != NULL);
  if (!FLAG_profile) {
    return;
  }
  {
    ScopedSignalBlocker ssb;
    FreeIsolateProfilingData(isolate);
  }
}


void ProfilerManager::ScheduleIsolateHelper(Isolate* isolate) {
  ScopedMonitor lock(monitor_);
  {
    ScopedMutex profiler_data_lock(isolate->profiler_data_mutex());
    IsolateProfilerData* profiler_data = isolate->profiler_data();
    if (profiler_data == NULL) {
      return;
    }
    profiler_data->Scheduled(OS::GetCurrentTimeMicros(),
                             Thread::GetCurrentThreadId());
  }
  intptr_t i = FindIsolate(isolate);
  if (i >= 0) {
    // Already scheduled.
    return;
  }
  AddIsolate(isolate);
  lock.Notify();
}


void ProfilerManager::ScheduleIsolate(Isolate* isolate, bool inside_signal) {
  if (!FLAG_profile) {
    return;
  }
{'fraction_non_alphanumeric': 0.1047479197258933, 'fraction_numerical': 0.0027736988089410997, 'mean_word_length': 3.9411527609834742, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 51, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3673618', 'n_tokens_mistral': 3800, 'n_tokens_neox': 3735, 'n_words': 1008}