Beispiel #1
0
// RUNS IN SIGHANDLER CONTEXT
void TableTicker::UnwinderTick(TickSample* sample)
{
    if (!sample->threadProfile) {
        // Platform doesn't support multithread, so use the main thread profile we created
        sample->threadProfile = GetPrimaryThreadProfile();
    }

    ThreadProfile& currThreadProfile = *sample->threadProfile;

    /* Get hold of an empty inter-thread buffer into which to park
       the ProfileEntries for this sample. */
    UnwinderThreadBuffer* utb = uwt__acquire_empty_buffer();

    /* This could fail, if no buffers are currently available, in which
       case we must give up right away.  We cannot wait for a buffer to
       become available, as that risks deadlock. */
    if (!utb)
        return;

    /* Manufacture the ProfileEntries that we will give to the unwinder
       thread, and park them in |utb|. */

    // Marker(s) come before the sample
    PseudoStack* stack = currThreadProfile.GetPseudoStack();
    for (int i = 0; stack->getMarker(i) != NULL; i++) {
        utb__addEntry( utb, ProfileEntry('m', stack->getMarker(i)) );
    }
    stack->mQueueClearMarker = true;

    bool recordSample = true;
    if (mJankOnly) {
        // if we are on a different event we can discard any temporary samples
        // we've kept around
        if (sLastSampledEventGeneration != sCurrentEventGeneration) {
            // XXX: we also probably want to add an entry to the profile to help
            // distinguish which samples are part of the same event. That, or record
            // the event generation in each sample
            currThreadProfile.erase();
        }
        sLastSampledEventGeneration = sCurrentEventGeneration;

        recordSample = false;
        // only record the events when we have a we haven't seen a tracer
        // event for 100ms
        if (!sLastTracerEvent.IsNull()) {
            TimeDuration delta = sample->timestamp - sLastTracerEvent;
            if (delta.ToMilliseconds() > 100.0) {
                recordSample = true;
            }
        }
    }

    // JRS 2012-Sept-27: this logic used to involve mUseStackWalk.
    // That should be reinstated, but for the moment, use the
    // settings in sUnwindMode and sUnwindInterval.
    // Add a native-backtrace request, or add pseudo backtrace entries,
    // or both.
    switch (sUnwindMode) {
    case UnwNATIVE: /* Native only */
        // add a "do native stack trace now" hint.  This will be actioned
        // by the unwinder thread as it processes the entries in this
        // sample.
        utb__addEntry( utb, ProfileEntry('h'/*hint*/, 'N'/*native-trace*/) );
        break;
    case UnwPSEUDO: /* Pseudo only */
        /* Add into |utb|, the pseudo backtrace entries */
        genPseudoBacktraceEntries(utb, stack, sample);
        break;
    case UnwCOMBINED: /* Both Native and Pseudo */
        utb__addEntry( utb, ProfileEntry('h'/*hint*/, 'N'/*native-trace*/) );
        genPseudoBacktraceEntries(utb, stack, sample);
        break;
    case UnwINVALID:
    default:
        MOZ_CRASH();
    }

    if (recordSample) {
        // add a "flush now" hint
        utb__addEntry( utb, ProfileEntry('h'/*hint*/, 'F'/*flush*/) );
    }

    // Add any extras
    if (!sLastTracerEvent.IsNull() && sample) {
        TimeDuration delta = sample->timestamp - sLastTracerEvent;
        utb__addEntry( utb, ProfileEntry('r', delta.ToMilliseconds()) );
    }

    if (sample) {
        TimeDuration delta = sample->timestamp - sStartTime;
        utb__addEntry( utb, ProfileEntry('t', delta.ToMilliseconds()) );
    }

    if (sLastFrameNumber != sFrameNumber) {
        utb__addEntry( utb, ProfileEntry('f', sFrameNumber) );
        sLastFrameNumber = sFrameNumber;
    }

    /* So now we have, in |utb|, the complete set of entries we want to
       push into the circular buffer.  This may also include a 'h' 'F'
       entry, which is "flush now" hint, and/or a 'h' 'N' entry, which
       is a "generate a native backtrace and add it to the buffer right
       now" hint.  Hand them off to the helper thread, together with
       stack and register context needed to do a native unwind, if that
       is currently enabled. */

    /* If a native unwind has been requested, we'll start it off using
       the context obtained from the signal handler, to avoid the
       problem of having to unwind through the signal frame itself. */

    /* On Linux and Android, the initial register state is in the
       supplied sample->context.  But on MacOS it's not, so we have to
       fake it up here (sigh). */
    if (sUnwindMode == UnwNATIVE || sUnwindMode == UnwCOMBINED) {
#   if defined(SPS_PLAT_amd64_linux) || defined(SPS_PLAT_arm_android) \
       || defined(SPS_PLAT_x86_linux) || defined(SPS_PLAT_x86_android)
        void* ucV = (void*)sample->context;
#   elif defined(SPS_PLAT_amd64_darwin)
        struct __darwin_mcontext64 mc;
        memset(&mc, 0, sizeof(mc));
        ucontext_t uc;
        memset(&uc, 0, sizeof(uc));
        uc.uc_mcontext = &mc;
        mc.__ss.__rip = (uint64_t)sample->pc;
        mc.__ss.__rsp = (uint64_t)sample->sp;
        mc.__ss.__rbp = (uint64_t)sample->fp;
        void* ucV = (void*)&uc;
#   elif defined(SPS_PLAT_x86_darwin)
        struct __darwin_mcontext32 mc;
        memset(&mc, 0, sizeof(mc));
        ucontext_t uc;
        memset(&uc, 0, sizeof(uc));
        uc.uc_mcontext = &mc;
        mc.__ss.__eip = (uint32_t)sample->pc;
        mc.__ss.__esp = (uint32_t)sample->sp;
        mc.__ss.__ebp = (uint32_t)sample->fp;
        void* ucV = (void*)&uc;
#   elif defined(SPS_OS_windows)
        /* Totally fake this up so it at least builds.  No idea if we can
           even ever get here on Windows. */
        void* ucV = NULL;
#   else
#     error "Unsupported platform"
#   endif
        uwt__release_full_buffer(&currThreadProfile, utb, ucV);
    } else {
        uwt__release_full_buffer(&currThreadProfile, utb, NULL);
    }
}
Beispiel #2
0
void TableTicker::InplaceTick(TickSample* sample)
{
  ThreadProfile& currThreadProfile = *sample->threadProfile;

  // Marker(s) come before the sample
  PseudoStack* stack = currThreadProfile.GetPseudoStack();
  for (int i = 0; stack->getMarker(i) != NULL; i++) {
    addDynamicTag(currThreadProfile, 'm', stack->getMarker(i));
  }
  stack->mQueueClearMarker = true;

  bool recordSample = true;
  if (mJankOnly) {
    // if we are on a different event we can discard any temporary samples
    // we've kept around
    if (sLastSampledEventGeneration != sCurrentEventGeneration) {
      // XXX: we also probably want to add an entry to the profile to help
      // distinguish which samples are part of the same event. That, or record
      // the event generation in each sample
      currThreadProfile.erase();
    }
    sLastSampledEventGeneration = sCurrentEventGeneration;

    recordSample = false;
    // only record the events when we have a we haven't seen a tracer event for 100ms
    if (!sLastTracerEvent.IsNull()) {
      TimeDuration delta = sample->timestamp - sLastTracerEvent;
      if (delta.ToMilliseconds() > 100.0) {
          recordSample = true;
      }
    }
  }

#if defined(USE_BACKTRACE) || defined(USE_NS_STACKWALK)
  if (mUseStackWalk) {
    doNativeBacktrace(currThreadProfile, sample);
  } else {
    doSampleStackTrace(stack, currThreadProfile, mAddLeafAddresses ? sample : nullptr);
  }
#else
  doSampleStackTrace(stack, currThreadProfile, mAddLeafAddresses ? sample : nullptr);
#endif

  if (recordSample)
    currThreadProfile.flush();

  if (!sLastTracerEvent.IsNull() && sample && currThreadProfile.IsMainThread()) {
    TimeDuration delta = sample->timestamp - sLastTracerEvent;
    currThreadProfile.addTag(ProfileEntry('r', delta.ToMilliseconds()));
  }

  if (sample) {
    TimeDuration delta = sample->timestamp - sStartTime;
    currThreadProfile.addTag(ProfileEntry('t', delta.ToMilliseconds()));
  }

  if (sLastFrameNumber != sFrameNumber) {
    currThreadProfile.addTag(ProfileEntry('f', sFrameNumber));
    sLastFrameNumber = sFrameNumber;
  }
}