tools/profiler/TableTicker.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     2 /* This Source Code Form is subject to the terms of the Mozilla Public
     3  * License, v. 2.0. If a copy of the MPL was not distributed with this
     4  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     6 #include <string>
     7 #include <stdio.h>
     8 #include <fstream>
     9 #include <sstream>
    10 #include "GeckoProfiler.h"
    11 #include "SaveProfileTask.h"
    12 #include "ProfileEntry.h"
    13 #include "SyncProfile.h"
    14 #include "platform.h"
    15 #include "nsThreadUtils.h"
    16 #include "prenv.h"
    17 #include "prtime.h"
    18 #include "shared-libraries.h"
    19 #include "mozilla/StackWalk.h"
    20 #include "TableTicker.h"
    21 #include "nsXULAppAPI.h"
    23 // JSON
    24 #include "JSStreamWriter.h"
    26 // Meta
    27 #include "nsXPCOM.h"
    28 #include "nsXPCOMCID.h"
    29 #include "nsIHttpProtocolHandler.h"
    30 #include "nsServiceManagerUtils.h"
    31 #include "nsIXULRuntime.h"
    32 #include "nsIXULAppInfo.h"
    33 #include "nsDirectoryServiceUtils.h"
    34 #include "nsDirectoryServiceDefs.h"
    35 #include "nsIObserverService.h"
    36 #include "mozilla/Services.h"
    37 #include "PlatformMacros.h"
    39 #if defined(SPS_OS_android) && !defined(MOZ_WIDGET_GONK)
    40   #include "AndroidBridge.h"
    41 #endif
    43 // JS
    44 #include "js/OldDebugAPI.h"
    46 #if defined(MOZ_PROFILING) && (defined(XP_MACOSX) || defined(XP_WIN))
    47  #define USE_NS_STACKWALK
    48 #endif
    49 #ifdef USE_NS_STACKWALK
    50  #include "nsStackWalk.h"
    51 #endif
    53 #if defined(XP_WIN)
    54 typedef CONTEXT tickcontext_t;
    55 #elif defined(LINUX)
    56 #include <ucontext.h>
    57 typedef ucontext_t tickcontext_t;
    58 #endif
    60 #if defined(LINUX) || defined(XP_MACOSX)
    61 #include <sys/types.h>
    62 pid_t gettid();
    63 #endif
    65 #if defined(SPS_ARCH_arm) && defined(MOZ_WIDGET_GONK)
    66  // Should also work on other Android and ARM Linux, but not tested there yet.
    67  #define USE_EHABI_STACKWALK
    68 #endif
    69 #ifdef USE_EHABI_STACKWALK
    70  #include "EHABIStackWalk.h"
    71 #endif
    73 using std::string;
    74 using namespace mozilla;
    76 #ifndef MAXPATHLEN
    77  #ifdef PATH_MAX
    78   #define MAXPATHLEN PATH_MAX
    79  #elif defined(MAX_PATH)
    80   #define MAXPATHLEN MAX_PATH
    81  #elif defined(_MAX_PATH)
    82   #define MAXPATHLEN _MAX_PATH
    83  #elif defined(CCHMAXPATH)
    84   #define MAXPATHLEN CCHMAXPATH
    85  #else
    86   #define MAXPATHLEN 1024
    87  #endif
    88 #endif
    90 ///////////////////////////////////////////////////////////////////////
    91 // BEGIN SaveProfileTask et al
    93 std::string GetSharedLibraryInfoString();
    95 void TableTicker::HandleSaveRequest()
    96 {
    97   if (!mSaveRequested)
    98     return;
    99   mSaveRequested = false;
   101   // TODO: Use use the ipc/chromium Tasks here to support processes
   102   // without XPCOM.
   103   nsCOMPtr<nsIRunnable> runnable = new SaveProfileTask();
   104   NS_DispatchToMainThread(runnable);
   105 }
   107 void TableTicker::StreamMetaJSCustomObject(JSStreamWriter& b)
   108 {
   109   b.BeginObject();
   111     b.NameValue("version", 2);
   112     b.NameValue("interval", interval());
   113     b.NameValue("stackwalk", mUseStackWalk);
   114     b.NameValue("jank", mJankOnly);
   115     b.NameValue("processType", XRE_GetProcessType());
   117     TimeDuration delta = TimeStamp::Now() - sStartTime;
   118     b.NameValue("startTime", static_cast<float>(PR_Now()/1000.0 - delta.ToMilliseconds()));
   120     nsresult res;
   121     nsCOMPtr<nsIHttpProtocolHandler> http = do_GetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "http", &res);
   122     if (!NS_FAILED(res)) {
   123       nsAutoCString string;
   125       res = http->GetPlatform(string);
   126       if (!NS_FAILED(res))
   127         b.NameValue("platform", string.Data());
   129       res = http->GetOscpu(string);
   130       if (!NS_FAILED(res))
   131         b.NameValue("oscpu", string.Data());
   133       res = http->GetMisc(string);
   134       if (!NS_FAILED(res))
   135         b.NameValue("misc", string.Data());
   136     }
   138     nsCOMPtr<nsIXULRuntime> runtime = do_GetService("@mozilla.org/xre/runtime;1");
   139     if (runtime) {
   140       nsAutoCString string;
   142       res = runtime->GetXPCOMABI(string);
   143       if (!NS_FAILED(res))
   144         b.NameValue("abi", string.Data());
   146       res = runtime->GetWidgetToolkit(string);
   147       if (!NS_FAILED(res))
   148         b.NameValue("toolkit", string.Data());
   149     }
   151     nsCOMPtr<nsIXULAppInfo> appInfo = do_GetService("@mozilla.org/xre/app-info;1");
   152     if (appInfo) {
   153       nsAutoCString string;
   155       res = appInfo->GetName(string);
   156       if (!NS_FAILED(res))
   157         b.NameValue("product", string.Data());
   158     }
   160   b.EndObject();
   161 }
   163 void TableTicker::ToStreamAsJSON(std::ostream& stream)
   164 {
   165   JSStreamWriter b(stream);
   166   StreamJSObject(b);
   167 }
   169 JSObject* TableTicker::ToJSObject(JSContext *aCx)
   170 {
   171   JS::RootedValue val(aCx);
   172   std::stringstream ss;
   173   {
   174     // Define a scope to prevent a moving GC during ~JSStreamWriter from
   175     // trashing the return value.
   176     JSStreamWriter b(ss);
   177     StreamJSObject(b);
   178     NS_ConvertUTF8toUTF16 js_string(nsDependentCString(ss.str().c_str()));
   179     JS_ParseJSON(aCx, static_cast<const jschar*>(js_string.get()), js_string.Length(), &val);
   180   }
   181   return &val.toObject();
   182 }
   184 struct SubprocessClosure {
   185   SubprocessClosure(JSStreamWriter *aWriter)
   186     : mWriter(aWriter)
   187   {}
   189   JSStreamWriter* mWriter;
   190 };
   192 void SubProcessCallback(const char* aProfile, void* aClosure)
   193 {
   194   // Called by the observer to get their profile data included
   195   // as a sub profile
   196   SubprocessClosure* closure = (SubprocessClosure*)aClosure;
   198   // Add the string profile into the profile
   199   closure->mWriter->Value(aProfile);
   200 }
   203 #if defined(SPS_OS_android) && !defined(MOZ_WIDGET_GONK)
   204 static
   205 void BuildJavaThreadJSObject(JSStreamWriter& b)
   206 {
   207   b.BeginObject();
   209     b.NameValue("name", "Java Main Thread");
   211     b.Name("samples");
   212     b.BeginArray();
   214       // for each sample
   215       for (int sampleId = 0; true; sampleId++) {
   216         bool firstRun = true;
   217         // for each frame
   218         for (int frameId = 0; true; frameId++) {
   219           nsCString result;
   220           bool hasFrame = AndroidBridge::Bridge()->GetFrameNameJavaProfiling(0, sampleId, frameId, result);
   221           // when we run out of frames, we stop looping
   222           if (!hasFrame) {
   223             // if we found at least one frame, we have objects to close
   224             if (!firstRun) {
   225                 b.EndArray();
   226               b.EndObject();
   227             }
   228             break;
   229           }
   230           // the first time around, open the sample object and frames array
   231           if (firstRun) {
   232             firstRun = false;
   234             double sampleTime =
   235               mozilla::widget::android::GeckoJavaSampler::GetSampleTimeJavaProfiling(0, sampleId);
   237             b.BeginObject();
   238               b.NameValue("time", sampleTime);
   240               b.Name("frames");
   241               b.BeginArray();
   242           }
   243           // add a frame to the sample
   244           b.BeginObject();
   245             b.NameValue("location", result.BeginReading());
   246           b.EndObject();
   247         }
   248         // if we found no frames for this sample, we are done
   249         if (firstRun) {
   250           break;
   251         }
   252       }
   254     b.EndArray();
   256   b.EndObject();
   257 }
   258 #endif
   260 void TableTicker::StreamJSObject(JSStreamWriter& b)
   261 {
   262   b.BeginObject();
   263     // Put shared library info
   264     b.NameValue("libs", GetSharedLibraryInfoString().c_str());
   266     // Put meta data
   267     b.Name("meta");
   268     StreamMetaJSCustomObject(b);
   270     // Lists the samples for each ThreadProfile
   271     b.Name("threads");
   272     b.BeginArray();
   274       SetPaused(true);
   276       {
   277         mozilla::MutexAutoLock lock(*sRegisteredThreadsMutex);
   279         for (size_t i = 0; i < sRegisteredThreads->size(); i++) {
   280           // Thread not being profiled, skip it
   281           if (!sRegisteredThreads->at(i)->Profile())
   282             continue;
   284           MutexAutoLock lock(*sRegisteredThreads->at(i)->Profile()->GetMutex());
   286           sRegisteredThreads->at(i)->Profile()->StreamJSObject(b);
   287         }
   288       }
   290       if (Sampler::CanNotifyObservers()) {
   291         // Send a event asking any subprocesses (plugins) to
   292         // give us their information
   293         SubprocessClosure closure(&b);
   294         nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
   295         if (os) {
   296           nsRefPtr<ProfileSaveEvent> pse = new ProfileSaveEvent(SubProcessCallback, &closure);
   297           os->NotifyObservers(pse, "profiler-subprocess", nullptr);
   298         }
   299       }
   301   #if defined(SPS_OS_android) && !defined(MOZ_WIDGET_GONK)
   302       if (ProfileJava()) {
   303         mozilla::widget::android::GeckoJavaSampler::PauseJavaProfiling();
   305         BuildJavaThreadJSObject(b);
   307         mozilla::widget::android::GeckoJavaSampler::UnpauseJavaProfiling();
   308       }
   309   #endif
   311       SetPaused(false);
   312     b.EndArray();
   314   b.EndObject();
   315 }
   317 // END SaveProfileTask et al
   318 ////////////////////////////////////////////////////////////////////////
   320 static
   321 void addDynamicTag(ThreadProfile &aProfile, char aTagName, const char *aStr)
   322 {
   323   aProfile.addTag(ProfileEntry(aTagName, ""));
   324   // Add one to store the null termination
   325   size_t strLen = strlen(aStr) + 1;
   326   for (size_t j = 0; j < strLen;) {
   327     // Store as many characters in the void* as the platform allows
   328     char text[sizeof(void*)];
   329     size_t len = sizeof(void*)/sizeof(char);
   330     if (j+len >= strLen) {
   331       len = strLen - j;
   332     }
   333     memcpy(text, &aStr[j], len);
   334     j += sizeof(void*)/sizeof(char);
   335     // Cast to *((void**) to pass the text data to a void*
   336     aProfile.addTag(ProfileEntry('d', *((void**)(&text[0]))));
   337   }
   338 }
   340 static
   341 void addProfileEntry(volatile StackEntry &entry, ThreadProfile &aProfile,
   342                      PseudoStack *stack, void *lastpc)
   343 {
   344   int lineno = -1;
   346   // First entry has tagName 's' (start)
   347   // Check for magic pointer bit 1 to indicate copy
   348   const char* sampleLabel = entry.label();
   349   if (entry.isCopyLabel()) {
   350     // Store the string using 1 or more 'd' (dynamic) tags
   351     // that will happen to the preceding tag
   353     addDynamicTag(aProfile, 'c', sampleLabel);
   354     if (entry.js()) {
   355       if (!entry.pc()) {
   356         // The JIT only allows the top-most entry to have a nullptr pc
   357         MOZ_ASSERT(&entry == &stack->mStack[stack->stackSize() - 1]);
   358         // If stack-walking was disabled, then that's just unfortunate
   359         if (lastpc) {
   360           jsbytecode *jspc = js::ProfilingGetPC(stack->mRuntime, entry.script(),
   361                                                 lastpc);
   362           if (jspc) {
   363             lineno = JS_PCToLineNumber(nullptr, entry.script(), jspc);
   364           }
   365         }
   366       } else {
   367         lineno = JS_PCToLineNumber(nullptr, entry.script(), entry.pc());
   368       }
   369     } else {
   370       lineno = entry.line();
   371     }
   372   } else {
   373     aProfile.addTag(ProfileEntry('c', sampleLabel));
   374     lineno = entry.line();
   375   }
   376   if (lineno != -1) {
   377     aProfile.addTag(ProfileEntry('n', lineno));
   378   }
   379 }
   381 #if defined(USE_NS_STACKWALK) || defined(USE_EHABI_STACKWALK)
   382 typedef struct {
   383   void** array;
   384   void** sp_array;
   385   size_t size;
   386   size_t count;
   387 } PCArray;
   389 static void mergeNativeBacktrace(ThreadProfile &aProfile, const PCArray &array) {
   390   aProfile.addTag(ProfileEntry('s', "(root)"));
   392   PseudoStack* stack = aProfile.GetPseudoStack();
   393   uint32_t pseudoStackPos = 0;
   395   /* We have two stacks, the native C stack we extracted from unwinding,
   396    * and the pseudostack we managed during execution. We want to consolidate
   397    * the two in order. We do so by merging using the approximate stack address
   398    * when each entry was push. When pushing JS entry we may not now the stack
   399    * address in which case we have a nullptr stack address in which case we assume
   400    * that it follows immediatly the previous element.
   401    *
   402    *  C Stack | Address    --  Pseudo Stack | Address
   403    *  main()  | 0x100          run_js()     | 0x40
   404    *  start() | 0x80           jsCanvas()   | nullptr
   405    *  timer() | 0x50           drawLine()   | nullptr
   406    *  azure() | 0x10
   407    *
   408    * Merged: main(), start(), timer(), run_js(), jsCanvas(), drawLine(), azure()
   409    */
   410   // i is the index in C stack starting at main and decreasing
   411   // pseudoStackPos is the position in the Pseudo stack starting
   412   // at the first frame (run_js in the example) and increasing.
   413   for (size_t i = array.count; i > 0; --i) {
   414     while (pseudoStackPos < stack->stackSize()) {
   415       volatile StackEntry& entry = stack->mStack[pseudoStackPos];
   417       if (entry.stackAddress() < array.sp_array[i-1] && entry.stackAddress())
   418         break;
   420       addProfileEntry(entry, aProfile, stack, array.array[0]);
   421       pseudoStackPos++;
   422     }
   424     aProfile.addTag(ProfileEntry('l', (void*)array.array[i-1]));
   425   }
   426 }
   428 #endif
   430 #ifdef USE_NS_STACKWALK
   431 static
   432 void StackWalkCallback(void* aPC, void* aSP, void* aClosure)
   433 {
   434   PCArray* array = static_cast<PCArray*>(aClosure);
   435   MOZ_ASSERT(array->count < array->size);
   436   array->sp_array[array->count] = aSP;
   437   array->array[array->count] = aPC;
   438   array->count++;
   439 }
   441 void TableTicker::doNativeBacktrace(ThreadProfile &aProfile, TickSample* aSample)
   442 {
   443 #ifndef XP_MACOSX
   444   uintptr_t thread = GetThreadHandle(aSample->threadProfile->GetPlatformData());
   445   MOZ_ASSERT(thread);
   446 #endif
   447   void* pc_array[1000];
   448   void* sp_array[1000];
   449   PCArray array = {
   450     pc_array,
   451     sp_array,
   452     mozilla::ArrayLength(pc_array),
   453     0
   454   };
   456   // Start with the current function.
   457   StackWalkCallback(aSample->pc, aSample->sp, &array);
   459   uint32_t maxFrames = uint32_t(array.size - array.count);
   460 #ifdef XP_MACOSX
   461   pthread_t pt = GetProfiledThread(aSample->threadProfile->GetPlatformData());
   462   void *stackEnd = reinterpret_cast<void*>(-1);
   463   if (pt)
   464     stackEnd = static_cast<char*>(pthread_get_stackaddr_np(pt));
   465   nsresult rv = NS_OK;
   466   if (aSample->fp >= aSample->sp && aSample->fp <= stackEnd)
   467     rv = FramePointerStackWalk(StackWalkCallback, /* skipFrames */ 0,
   468                                maxFrames, &array,
   469                                reinterpret_cast<void**>(aSample->fp), stackEnd);
   470 #else
   471   void *platformData = nullptr;
   472 #ifdef XP_WIN
   473   if (aSample->isSamplingCurrentThread) {
   474     // In this case we want NS_StackWalk to know that it's walking the
   475     // current thread's stack, so we pass 0 as the thread handle.
   476     thread = 0;
   477   }
   478   platformData = aSample->context;
   479 #endif // XP_WIN
   481   nsresult rv = NS_StackWalk(StackWalkCallback, /* skipFrames */ 0, maxFrames,
   482                              &array, thread, platformData);
   483 #endif
   484   if (NS_SUCCEEDED(rv))
   485     mergeNativeBacktrace(aProfile, array);
   486 }
   487 #endif
   489 #ifdef USE_EHABI_STACKWALK
   490 void TableTicker::doNativeBacktrace(ThreadProfile &aProfile, TickSample* aSample)
   491 {
   492   void *pc_array[1000];
   493   void *sp_array[1000];
   494   PCArray array = {
   495     pc_array,
   496     sp_array,
   497     mozilla::ArrayLength(pc_array),
   498     0
   499   };
   501   const mcontext_t *mcontext = &reinterpret_cast<ucontext_t *>(aSample->context)->uc_mcontext;
   502   mcontext_t savedContext;
   503   PseudoStack *pseudoStack = aProfile.GetPseudoStack();
   505   array.count = 0;
   506   // The pseudostack contains an "EnterJIT" frame whenever we enter
   507   // JIT code with profiling enabled; the stack pointer value points
   508   // the saved registers.  We use this to unwind resume unwinding
   509   // after encounting JIT code.
   510   for (uint32_t i = pseudoStack->stackSize(); i > 0; --i) {
   511     // The pseudostack grows towards higher indices, so we iterate
   512     // backwards (from callee to caller).
   513     volatile StackEntry &entry = pseudoStack->mStack[i - 1];
   514     if (!entry.js() && strcmp(entry.label(), "EnterJIT") == 0) {
   515       // Found JIT entry frame.  Unwind up to that point (i.e., force
   516       // the stack walk to stop before the block of saved registers;
   517       // note that it yields nondecreasing stack pointers), then restore
   518       // the saved state.
   519       uint32_t *vSP = reinterpret_cast<uint32_t*>(entry.stackAddress());
   521       array.count += EHABIStackWalk(*mcontext,
   522                                     /* stackBase = */ vSP,
   523                                     sp_array + array.count,
   524                                     pc_array + array.count,
   525                                     array.size - array.count);
   527       memset(&savedContext, 0, sizeof(savedContext));
   528       // See also: struct EnterJITStack in js/src/jit/arm/Trampoline-arm.cpp
   529       savedContext.arm_r4 = *vSP++;
   530       savedContext.arm_r5 = *vSP++;
   531       savedContext.arm_r6 = *vSP++;
   532       savedContext.arm_r7 = *vSP++;
   533       savedContext.arm_r8 = *vSP++;
   534       savedContext.arm_r9 = *vSP++;
   535       savedContext.arm_r10 = *vSP++;
   536       savedContext.arm_fp = *vSP++;
   537       savedContext.arm_lr = *vSP++;
   538       savedContext.arm_sp = reinterpret_cast<uint32_t>(vSP);
   539       savedContext.arm_pc = savedContext.arm_lr;
   540       mcontext = &savedContext;
   541     }
   542   }
   544   // Now unwind whatever's left (starting from either the last EnterJIT
   545   // frame or, if no EnterJIT was found, the original registers).
   546   array.count += EHABIStackWalk(*mcontext,
   547                                 aProfile.GetStackTop(),
   548                                 sp_array + array.count,
   549                                 pc_array + array.count,
   550                                 array.size - array.count);
   552   mergeNativeBacktrace(aProfile, array);
   553 }
   555 #endif
   557 static
   558 void doSampleStackTrace(PseudoStack *aStack, ThreadProfile &aProfile, TickSample *sample)
   559 {
   560   // Sample
   561   // 's' tag denotes the start of a sample block
   562   // followed by 0 or more 'c' tags.
   563   aProfile.addTag(ProfileEntry('s', "(root)"));
   564   for (uint32_t i = 0; i < aStack->stackSize(); i++) {
   565     addProfileEntry(aStack->mStack[i], aProfile, aStack, nullptr);
   566   }
   567 #ifdef ENABLE_SPS_LEAF_DATA
   568   if (sample) {
   569     aProfile.addTag(ProfileEntry('l', (void*)sample->pc));
   570 #ifdef ENABLE_ARM_LR_SAVING
   571     aProfile.addTag(ProfileEntry('L', (void*)sample->lr));
   572 #endif
   573   }
   574 #endif
   575 }
   577 void TableTicker::Tick(TickSample* sample)
   578 {
   579   if (HasUnwinderThread()) {
   580     UnwinderTick(sample);
   581   } else {
   582     InplaceTick(sample);
   583   }
   584 }
   586 void TableTicker::InplaceTick(TickSample* sample)
   587 {
   588   ThreadProfile& currThreadProfile = *sample->threadProfile;
   590   PseudoStack* stack = currThreadProfile.GetPseudoStack();
   591   bool recordSample = true;
   592 #if defined(XP_WIN)
   593   bool powerSample = false;
   594 #endif
   596   /* Don't process the PeudoStack's markers or honour jankOnly if we're
   597      immediately sampling the current thread. */
   598   if (!sample->isSamplingCurrentThread) {
   599     // Marker(s) come before the sample
   600     ProfilerMarkerLinkedList* pendingMarkersList = stack->getPendingMarkers();
   601     while (pendingMarkersList && pendingMarkersList->peek()) {
   602       ProfilerMarker* marker = pendingMarkersList->popHead();
   603       stack->addStoredMarker(marker);
   604       currThreadProfile.addTag(ProfileEntry('m', marker));
   605     }
   606     stack->updateGeneration(currThreadProfile.GetGenerationID());
   608 #if defined(XP_WIN)
   609     if (mProfilePower) {
   610       mIntelPowerGadget->TakeSample();
   611       powerSample = true;
   612     }
   613 #endif
   615     if (mJankOnly) {
   616       // if we are on a different event we can discard any temporary samples
   617       // we've kept around
   618       if (sLastSampledEventGeneration != sCurrentEventGeneration) {
   619         // XXX: we also probably want to add an entry to the profile to help
   620         // distinguish which samples are part of the same event. That, or record
   621         // the event generation in each sample
   622         currThreadProfile.erase();
   623       }
   624       sLastSampledEventGeneration = sCurrentEventGeneration;
   626       recordSample = false;
   627       // only record the events when we have a we haven't seen a tracer event for 100ms
   628       if (!sLastTracerEvent.IsNull()) {
   629         TimeDuration delta = sample->timestamp - sLastTracerEvent;
   630         if (delta.ToMilliseconds() > 100.0) {
   631             recordSample = true;
   632         }
   633       }
   634     }
   635   }
   637 #if defined(USE_NS_STACKWALK) || defined(USE_EHABI_STACKWALK)
   638   if (mUseStackWalk) {
   639     doNativeBacktrace(currThreadProfile, sample);
   640   } else {
   641     doSampleStackTrace(stack, currThreadProfile, mAddLeafAddresses ? sample : nullptr);
   642   }
   643 #else
   644   doSampleStackTrace(stack, currThreadProfile, mAddLeafAddresses ? sample : nullptr);
   645 #endif
   647   if (recordSample)
   648     currThreadProfile.flush();
   650   if (!sLastTracerEvent.IsNull() && sample && currThreadProfile.IsMainThread()) {
   651     TimeDuration delta = sample->timestamp - sLastTracerEvent;
   652     currThreadProfile.addTag(ProfileEntry('r', static_cast<float>(delta.ToMilliseconds())));
   653   }
   655   if (sample) {
   656     TimeDuration delta = sample->timestamp - sStartTime;
   657     currThreadProfile.addTag(ProfileEntry('t', static_cast<float>(delta.ToMilliseconds())));
   658   }
   660 #if defined(XP_WIN)
   661   if (powerSample) {
   662     currThreadProfile.addTag(ProfileEntry('p', static_cast<float>(mIntelPowerGadget->GetTotalPackagePowerInWatts())));
   663   }
   664 #endif
   666   if (sLastFrameNumber != sFrameNumber) {
   667     currThreadProfile.addTag(ProfileEntry('f', sFrameNumber));
   668     sLastFrameNumber = sFrameNumber;
   669   }
   670 }
   672 namespace {
   674 SyncProfile* NewSyncProfile()
   675 {
   676   PseudoStack* stack = tlsPseudoStack.get();
   677   if (!stack) {
   678     MOZ_ASSERT(stack);
   679     return nullptr;
   680   }
   681   Thread::tid_t tid = Thread::GetCurrentId();
   683   SyncProfile* profile = new SyncProfile("SyncProfile",
   684                                          GET_BACKTRACE_DEFAULT_ENTRY,
   685                                          stack, tid, NS_IsMainThread());
   686   return profile;
   687 }
   689 } // anonymous namespace
   691 SyncProfile* TableTicker::GetBacktrace()
   692 {
   693   SyncProfile* profile = NewSyncProfile();
   695   TickSample sample;
   696   sample.threadProfile = profile;
   698 #if defined(HAVE_NATIVE_UNWIND)
   699 #if defined(XP_WIN) || defined(LINUX)
   700   tickcontext_t context;
   701   sample.PopulateContext(&context);
   702 #elif defined(XP_MACOSX)
   703   sample.PopulateContext(nullptr);
   704 #endif
   705 #endif
   707   sample.isSamplingCurrentThread = true;
   708   sample.timestamp = mozilla::TimeStamp::Now();
   710   if (!HasUnwinderThread()) {
   711     profile->BeginUnwind();
   712   }
   714   Tick(&sample);
   716   if (!HasUnwinderThread()) {
   717     profile->EndUnwind();
   718   }
   720   return profile;
   721 }
   723 static void print_callback(const ProfileEntry& entry, const char* tagStringData)
   724 {
   725   switch (entry.getTagName()) {
   726     case 's':
   727     case 'c':
   728       printf_stderr("  %s\n", tagStringData);
   729   }
   730 }
   732 void mozilla_sampler_print_location1()
   733 {
   734   if (!stack_key_initialized)
   735     profiler_init(nullptr);
   737   SyncProfile* syncProfile = NewSyncProfile();
   738   if (!syncProfile) {
   739     return;
   740   }
   742   syncProfile->BeginUnwind();
   743   doSampleStackTrace(syncProfile->GetPseudoStack(), *syncProfile, nullptr);
   744   syncProfile->EndUnwind();
   746   printf_stderr("Backtrace:\n");
   747   syncProfile->IterateTags(print_callback);
   748   delete syncProfile;
   749 }

mercurial