toolkit/xre/EventTracer.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

     1 /* This Source Code Form is subject to the terms of the Mozilla Public
     2  * License, v. 2.0. If a copy of the MPL was not distributed with this
     3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     5 /*
     6  * Event loop instrumentation. This code attempts to measure the
     7  * latency of the UI-thread event loop by firing native events at it from
     8  * a background thread, and measuring how long it takes for them
     9  * to be serviced. The measurement interval (kMeasureInterval, below)
    10  * is also used as the upper bound of acceptable response time.
    11  * When an event takes longer than that interval to be serviced,
    12  * a sample will be written to the log.
    13  *
    14  * Usage:
    15  *
    16  * Set MOZ_INSTRUMENT_EVENT_LOOP=1 in the environment to enable
    17  * this instrumentation. Currently only the UI process is instrumented.
    18  *
    19  * Set MOZ_INSTRUMENT_EVENT_LOOP_OUTPUT in the environment to a
    20  * file path to contain the log output, the default is to log to stdout.
    21  *
    22  * Set MOZ_INSTRUMENT_EVENT_LOOP_THRESHOLD in the environment to an
    23  * integer number of milliseconds to change the threshold for reporting.
    24  * The default is 20 milliseconds. Unresponsive periods shorter than this
    25  * threshold will not be reported.
    26  *
    27  * Set MOZ_INSTRUMENT_EVENT_LOOP_INTERVAL in the environment to an
    28  * integer number of milliseconds to change the maximum sampling frequency.
    29  * This variable controls how often events will be sent to the main
    30  * thread's event loop to sample responsiveness. The sampler will not
    31  * send events twice within LOOP_INTERVAL milliseconds.
    32  * The default is 10 milliseconds.
    33  *
    34  * All logged output lines start with MOZ_EVENT_TRACE. All timestamps
    35  * output are milliseconds since the epoch (PRTime / 1000).
    36  *
    37  * On startup, a line of the form:
    38  *   MOZ_EVENT_TRACE start <timestamp>
    39  * will be output.
    40  *
    41  * On shutdown, a line of the form:
    42  *   MOZ_EVENT_TRACE stop <timestamp>
    43  * will be output.
    44  *
    45  * When an event servicing time exceeds the threshold, a line of the form:
    46  *   MOZ_EVENT_TRACE sample <timestamp> <duration>
    47  * will be output, where <duration> is the number of milliseconds that
    48  * it took for the event to be serviced. Duration may contain a fractional
    49  * component.
    50  */
    52 #include "GeckoProfiler.h"
    54 #include "EventTracer.h"
    56 #include <stdio.h>
    58 #include "mozilla/Preferences.h"
    59 #include "mozilla/TimeStamp.h"
    60 #include "mozilla/WidgetTraceEvent.h"
    61 #include "nsDebug.h"
    62 #include <limits.h>
    63 #include <prenv.h>
    64 #include <prinrval.h>
    65 #include <prthread.h>
    66 #include <prtime.h>
    68 #ifdef MOZ_WIDGET_GONK
    69 #include "nsThreadUtils.h"
    70 #include "nsIObserverService.h"
    71 #include "mozilla/Services.h"
    72 #endif
    74 using mozilla::TimeDuration;
    75 using mozilla::TimeStamp;
    76 using mozilla::FireAndWaitForTracerEvent;
    78 namespace {
    80 PRThread* sTracerThread = nullptr;
    81 bool sExit = false;
    83 struct TracerStartClosure {
    84   bool mLogTracing;
    85   int32_t mThresholdInterval;
    86 };
    88 #ifdef MOZ_WIDGET_GONK
    89 class EventLoopLagDispatcher : public nsRunnable
    90 {
    91   public:
    92     explicit EventLoopLagDispatcher(int aLag)
    93       : mLag(aLag) {}
    95     NS_IMETHODIMP Run()
    96     {
    97       nsCOMPtr<nsIObserverService> obsService =
    98         mozilla::services::GetObserverService();
    99       if (!obsService) {
   100         return NS_ERROR_FAILURE;
   101       }
   103       nsAutoString value;
   104       value.AppendInt(mLag);
   105       return obsService->NotifyObservers(nullptr, "event-loop-lag", value.get());
   106     }
   108   private:
   109     int mLag;
   110 };
   111 #endif
   113 /*
   114  * The tracer thread fires events at the native event loop roughly
   115  * every kMeasureInterval. It will sleep to attempt not to send them
   116  * more quickly, but if the response time is longer than kMeasureInterval
   117  * it will not send another event until the previous response is received.
   118  *
   119  * The output defaults to stdout, but can be redirected to a file by
   120  * settting the environment variable MOZ_INSTRUMENT_EVENT_LOOP_OUTPUT
   121  * to the name of a file to use.
   122  */
   123 void TracerThread(void *arg)
   124 {
   125   PR_SetCurrentThreadName("Event Tracer");
   127   TracerStartClosure* threadArgs = static_cast<TracerStartClosure*>(arg);
   129   // These are the defaults. They can be overridden by environment vars.
   130   // This should be set to the maximum latency we'd like to allow
   131   // for responsiveness.
   132   int32_t thresholdInterval = threadArgs->mThresholdInterval;
   133   PRIntervalTime threshold = PR_MillisecondsToInterval(thresholdInterval);
   134   // This is the sampling interval.
   135   PRIntervalTime interval = PR_MillisecondsToInterval(thresholdInterval / 2);
   137   sExit = false;
   138   FILE* log = nullptr;
   139   char* envfile = PR_GetEnv("MOZ_INSTRUMENT_EVENT_LOOP_OUTPUT");
   140   if (envfile) {
   141     log = fopen(envfile, "w");
   142   }
   143   if (log == nullptr)
   144     log = stdout;
   146   char* thresholdenv = PR_GetEnv("MOZ_INSTRUMENT_EVENT_LOOP_THRESHOLD");
   147   if (thresholdenv && *thresholdenv) {
   148     int val = atoi(thresholdenv);
   149     if (val != 0 && val != INT_MAX && val != INT_MIN) {
   150       threshold = PR_MillisecondsToInterval(val);
   151     }
   152   }
   154   char* intervalenv = PR_GetEnv("MOZ_INSTRUMENT_EVENT_LOOP_INTERVAL");
   155   if (intervalenv && *intervalenv) {
   156     int val = atoi(intervalenv);
   157     if (val != 0 && val != INT_MAX && val != INT_MIN) {
   158       interval = PR_MillisecondsToInterval(val);
   159     }
   160   }
   162   if (threadArgs->mLogTracing) {
   163     long long now = PR_Now() / PR_USEC_PER_MSEC;
   164     fprintf(log, "MOZ_EVENT_TRACE start %llu\n", now);
   165   }
   167   while (!sExit) {
   168     TimeStamp start(TimeStamp::Now());
   169     profiler_responsiveness(start);
   170     PRIntervalTime next_sleep = interval;
   172     //TODO: only wait up to a maximum of interval; return
   173     // early if that threshold is exceeded and dump a stack trace
   174     // or do something else useful.
   175     if (FireAndWaitForTracerEvent()) {
   176       TimeDuration duration = TimeStamp::Now() - start;
   177       // Only report samples that exceed our measurement threshold.
   178       long long now = PR_Now() / PR_USEC_PER_MSEC;
   179       if (threadArgs->mLogTracing && duration.ToMilliseconds() > threshold) {
   180         fprintf(log, "MOZ_EVENT_TRACE sample %llu %lf\n",
   181                 now,
   182                 duration.ToMilliseconds());
   183 #ifdef MOZ_WIDGET_GONK
   184         NS_DispatchToMainThread(
   185          new EventLoopLagDispatcher(int(duration.ToSecondsSigDigits() * 1000)));
   186 #endif
   187       }
   189       if (next_sleep > duration.ToMilliseconds()) {
   190         next_sleep -= int(duration.ToMilliseconds());
   191       }
   192       else {
   193         // Don't sleep at all if this event took longer than the measure
   194         // interval to deliver.
   195         next_sleep = 0;
   196       }
   197     }
   199     if (next_sleep != 0 && !sExit) {
   200       PR_Sleep(next_sleep);
   201     }
   202   }
   204   if (threadArgs->mLogTracing) {
   205     long long now = PR_Now() / PR_USEC_PER_MSEC;
   206     fprintf(log, "MOZ_EVENT_TRACE stop %llu\n", now);
   207   }
   209   if (log != stdout)
   210     fclose(log);
   212   delete threadArgs;
   213 }
   215 } // namespace
   217 namespace mozilla {
   219 bool InitEventTracing(bool aLog)
   220 {
   221   if (sTracerThread)
   222     return true;
   224   // Initialize the widget backend.
   225   if (!InitWidgetTracing())
   226     return false;
   228   // The tracer thread owns the object and will delete it.
   229   TracerStartClosure* args = new TracerStartClosure();
   230   args->mLogTracing = aLog;
   232   // Pass the default threshold interval.
   233   int32_t thresholdInterval = 20;
   234   Preferences::GetInt("devtools.eventlooplag.threshold", &thresholdInterval);
   235   args->mThresholdInterval = thresholdInterval;
   237   // Create a thread that will fire events back at the
   238   // main thread to measure responsiveness.
   239   NS_ABORT_IF_FALSE(!sTracerThread, "Event tracing already initialized!");
   240   sTracerThread = PR_CreateThread(PR_USER_THREAD,
   241                                   TracerThread,
   242                                   args,
   243                                   PR_PRIORITY_NORMAL,
   244                                   PR_GLOBAL_THREAD,
   245                                   PR_JOINABLE_THREAD,
   246                                   0);
   247   return sTracerThread != nullptr;
   248 }
   250 void ShutdownEventTracing()
   251 {
   252   if (!sTracerThread)
   253     return;
   255   sExit = true;
   256   // Ensure that the tracer thread doesn't hang.
   257   SignalTracerThread();
   259   if (sTracerThread)
   260     PR_JoinThread(sTracerThread);
   261   sTracerThread = nullptr;
   263   // Allow the widget backend to clean up.
   264   CleanUpWidgetTracing();
   265 }
   267 }  // namespace mozilla

mercurial