Bug 729182 - Implement visual event tracer, part1 - instrumentation, r=mcmanus,bz,ehsan,bsmedberg,michal
authorHonza Bambas <honzab.moz@firemni.cz>
Thu, 28 Mar 2013 18:38:04 +0100
changeset 126589 260e98308023b51ad665612bf4be04bd8d0e7aa1
parent 126588 c9e35e4221e5239d7044c70cb15893b8a7b9aad5
child 126590 85dd7094b78d0cce60b28adab74b14b9536e0846
push idunknown
push userunknown
push dateunknown
reviewersmcmanus, bz, ehsan, bsmedberg, michal
bugs729182
milestone22.0a1
Bug 729182 - Implement visual event tracer, part1 - instrumentation, r=mcmanus,bz,ehsan,bsmedberg,michal
docshell/base/nsDocShell.cpp
netwerk/base/src/nsSocketTransport2.cpp
netwerk/cache/nsCacheEntry.cpp
netwerk/cache/nsCacheService.cpp
netwerk/cache/nsDiskCacheMap.cpp
netwerk/cache/nsDiskCacheStreams.cpp
netwerk/dns/nsDNSService2.cpp
netwerk/dns/nsHostResolver.cpp
netwerk/protocol/http/nsHttpChannel.cpp
netwerk/protocol/http/nsHttpConnectionMgr.cpp
netwerk/protocol/http/nsHttpTransaction.cpp
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -77,16 +77,17 @@
 #include "nsIDocShellTreeItem.h"
 #include "nsIChannel.h"
 #include "IHistory.h"
 #include "mozilla/Services.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/AutoRestore.h"
 #include "mozilla/Attributes.h"
+#include "mozilla/VisualEventTracer.h"
 
 // we want to explore making the document own the load group
 // so we can associate the document URI with the load group.
 // until this point, we have an evil hack:
 #include "nsIHttpChannelInternal.h"  
 
 
 // Local Includes
@@ -6661,16 +6662,18 @@ nsDocShell::OnSecurityChange(nsIWebProgr
 
 nsresult
 nsDocShell::EndPageLoad(nsIWebProgress * aProgress,
                         nsIChannel * aChannel, nsresult aStatus)
 {
     if(!aChannel)
         return NS_ERROR_NULL_POINTER;
     
+    MOZ_EVENT_TRACER_DONE(this, "docshell::pageload");
+
     nsCOMPtr<nsIURI> url;
     nsresult rv = aChannel->GetURI(getter_AddRefs(url));
     if (NS_FAILED(rv)) return rv;
 
     nsCOMPtr<nsITimedChannel> timingChannel =
         do_QueryInterface(aChannel);
     if (timingChannel) {
         TimeStamp channelCreationTime;
@@ -9384,16 +9387,23 @@ nsDocShell::DoURILoad(nsIURI * aURI,
                       nsIInputStream * aHeadersData,
                       bool aFirstParty,
                       nsIDocShell ** aDocShell,
                       nsIRequest ** aRequest,
                       bool aIsNewWindowTarget,
                       bool aBypassClassifier,
                       bool aForceAllowCookies)
 {
+#ifdef MOZ_VISUAL_EVENT_TRACER
+    nsAutoCString urlSpec;
+    aURI->GetAsciiSpec(urlSpec);
+    MOZ_EVENT_TRACER_NAME_OBJECT(this, urlSpec.BeginReading());
+    MOZ_EVENT_TRACER_EXEC(this, "docshell::pageload");
+#endif
+
     nsresult rv;
     nsCOMPtr<nsIURILoader> uriLoader;
 
     uriLoader = do_GetService(NS_URI_LOADER_CONTRACTID, &rv);
     if (NS_FAILED(rv)) return rv;
 
     nsLoadFlags loadFlags = nsIRequest::LOAD_NORMAL;
     if (aFirstParty) {
--- a/netwerk/base/src/nsSocketTransport2.cpp
+++ b/netwerk/base/src/nsSocketTransport2.cpp
@@ -19,16 +19,17 @@
 #include "nsNetCID.h"
 #include "nsAutoPtr.h"
 #include "nsCOMPtr.h"
 #include "netCore.h"
 #include "plstr.h"
 #include "prnetdb.h"
 #include "prerr.h"
 #include "NetworkActivityMonitor.h"
+#include "mozilla/VisualEventTracer.h"
 
 #include "nsIServiceManager.h"
 #include "nsISocketProviderService.h"
 #include "nsISocketProvider.h"
 #include "nsISSLSocketControl.h"
 #include "nsINSSErrorsService.h"
 #include "nsIPipe.h"
 #include "nsIProgrammingLanguage.h"
@@ -724,16 +725,18 @@ nsSocketTransport::~nsSocketTransport()
     NS_RELEASE(serv); // nulls argument
 }
 
 nsresult
 nsSocketTransport::Init(const char **types, uint32_t typeCount,
                         const nsACString &host, uint16_t port,
                         nsIProxyInfo *givenProxyInfo)
 {
+    MOZ_EVENT_TRACER_NAME_OBJECT(this, host.BeginReading());
+
     nsCOMPtr<nsProxyInfo> proxyInfo;
     if (givenProxyInfo) {
         proxyInfo = do_QueryInterface(givenProxyInfo);
         NS_ENSURE_ARG(proxyInfo);
     }
 
     // init socket type info
 
@@ -1174,16 +1177,18 @@ nsSocketTransport::InitiateSocket()
     }
 #endif
 
     // 
     // Initiate the connect() to the host...  
     //
     PRNetAddr prAddr;
     NetAddrToPRNetAddr(&mNetAddr, &prAddr);
+
+    MOZ_EVENT_TRACER_EXEC(this, "net::tcp::connect");
     status = PR_Connect(fd, &prAddr, NS_SOCKET_CONNECT_TIMEOUT);
     if (status == PR_SUCCESS) {
         // 
         // we are connected!
         //
         OnSocketConnected();
     }
     else {
@@ -1399,16 +1404,18 @@ nsSocketTransport::OnSocketConnected()
     // to trample over mFDref if mFD is already set.
     {
         MutexAutoLock lock(mLock);
         NS_ASSERTION(mFD, "no socket");
         NS_ASSERTION(mFDref == 1, "wrong socket ref count");
         mFDconnected = true;
     }
 
+    MOZ_EVENT_TRACER_DONE(this, "net::tcp::connect");
+
     SendStatus(NS_NET_STATUS_CONNECTED_TO);
 }
 
 PRFileDesc *
 nsSocketTransport::GetFD_Locked()
 {
     // mFD is not available to the streams while disconnected.
     if (!mFDconnected)
@@ -2139,16 +2146,17 @@ nsSocketTransport::SetSendBufferSize(uin
 NS_IMETHODIMP
 nsSocketTransport::OnLookupComplete(nsICancelable *request,
                                     nsIDNSRecord  *rec,
                                     nsresult       status)
 {
     // flag host lookup complete for the benefit of the ResolveHost method.
     mResolving = false;
 
+    MOZ_EVENT_TRACER_WAIT(this, "net::tcp::connect");
     nsresult rv = PostEvent(MSG_DNS_LOOKUP_COMPLETE, status, rec);
 
     // if posting a message fails, then we should assume that the socket
     // transport has been shutdown.  this should never happen!  if it does
     // it means that the socket transport service was shutdown before the
     // DNS service.
     if (NS_FAILED(rv))
         NS_WARNING("unable to post DNS lookup complete message");
--- a/netwerk/cache/nsCacheEntry.cpp
+++ b/netwerk/cache/nsCacheEntry.cpp
@@ -12,16 +12,17 @@
 #include "nsCacheMetaData.h"
 #include "nsCacheRequest.h"
 #include "nsThreadUtils.h"
 #include "nsError.h"
 #include "nsICacheService.h"
 #include "nsCacheService.h"
 #include "nsCacheDevice.h"
 #include "nsHashKeys.h"
+#include "mozilla/VisualEventTracer.h"
 
 using namespace mozilla;
 
 nsCacheEntry::nsCacheEntry(const nsACString &   key,
                            bool                 streamBased,
                            nsCacheStoragePolicy storagePolicy)
     : mKey(key),
       mFetchCount(0),
@@ -39,16 +40,18 @@ nsCacheEntry::nsCacheEntry(const nsACStr
     PR_INIT_CLIST(this);
     PR_INIT_CLIST(&mRequestQ);
     PR_INIT_CLIST(&mDescriptorQ);
 
     if (streamBased) MarkStreamBased();
     SetStoragePolicy(storagePolicy);
 
     MarkPublic();
+
+    MOZ_EVENT_TRACER_NAME_OBJECT(this, key.BeginReading());
 }
 
 
 nsCacheEntry::~nsCacheEntry()
 {
     MOZ_COUNT_DTOR(nsCacheEntry);
     
     if (mData)
--- a/netwerk/cache/nsCacheService.cpp
+++ b/netwerk/cache/nsCacheService.cpp
@@ -32,18 +32,18 @@
 #include "nsProxyRelease.h"
 #include "nsVoidArray.h"
 #include "nsDeleteDir.h"
 #include "nsNetCID.h"
 #include <math.h>  // for log()
 #include "mozilla/Services.h"
 #include "nsITimer.h"
 
-
 #include "mozilla/net/NeckoCommon.h"
+#include "mozilla/VisualEventTracer.h"
 #include <algorithm>
 
 using namespace mozilla;
 
 /******************************************************************************
  * nsCacheProfilePrefObserver
  *****************************************************************************/
 #define DISK_CACHE_ENABLE_PREF      "browser.cache.disk.enable"
@@ -966,16 +966,18 @@ nsCacheProfilePrefObserver::CacheCompres
 /******************************************************************************
  * nsProcessRequestEvent
  *****************************************************************************/
 
 class nsProcessRequestEvent : public nsRunnable {
 public:
     nsProcessRequestEvent(nsCacheRequest *aRequest)
     {
+        MOZ_EVENT_TRACER_NAME_OBJECT(aRequest, aRequest->mKey.get());
+        MOZ_EVENT_TRACER_WAIT(aRequest, "net::cache::ProcessRequest");
         mRequest = aRequest;
     }
 
     NS_IMETHOD Run()
     {
         nsresult rv;
 
         NS_ASSERTION(mRequest->mListener,
@@ -1126,16 +1128,18 @@ nsCacheService::Init()
         return NS_ERROR_ALREADY_INITIALIZED;
 
     if (mozilla::net::IsNeckoChild()) {
         return NS_ERROR_UNEXPECTED;
     }
 
     CACHE_LOG_INIT();
 
+    MOZ_EVENT_TRACER_NAME_OBJECT(nsCacheService::gService, "nsCacheService");
+
     nsresult rv = NS_NewNamedThread("Cache I/O",
                                     getter_AddRefs(mCacheIOThread));
     if (NS_FAILED(rv)) {
         NS_RUNTIMEABORT("Can't create cache IO thread");
     }
 
     rv = nsDeleteDir::Init();
     if (NS_FAILED(rv)) {
@@ -1795,16 +1799,22 @@ public:
         : mListener(listener)      // transfers reference
         , mDescriptor(descriptor)  // transfers reference (may be null)
         , mAccessGranted(accessGranted)
         , mStatus(status)
     {}
 
     NS_IMETHOD Run()
     {
+        mozilla::eventtracer::AutoEventTracer tracer(
+            static_cast<nsIRunnable*>(this),
+            eventtracer::eExec,
+            eventtracer::eDone,
+            "net::cache::OnCacheEntryAvailable");
+
         mListener->OnCacheEntryAvailable(mDescriptor, mAccessGranted, mStatus);
 
         NS_RELEASE(mListener);
         NS_IF_RELEASE(mDescriptor);
         return NS_OK;
     }
 
 private:
@@ -1836,25 +1846,33 @@ nsCacheService::NotifyListener(nsCacheRe
                                      accessGranted, status);
     if (!ev) {
         // Better to leak listener and descriptor if we fail because we don't
         // want to destroy them inside the cache service lock or on potentially
         // the wrong thread.
         return NS_ERROR_OUT_OF_MEMORY;
     }
 
+    MOZ_EVENT_TRACER_NAME_OBJECT(ev.get(), request->mKey.get());
+    MOZ_EVENT_TRACER_WAIT(ev.get(), "net::cache::OnCacheEntryAvailable");
     return request->mThread->Dispatch(ev, NS_DISPATCH_NORMAL);
 }
 
 
 nsresult
 nsCacheService::ProcessRequest(nsCacheRequest *           request,
                                bool                       calledFromOpenCacheEntry,
                                nsICacheEntryDescriptor ** result)
 {
+    mozilla::eventtracer::AutoEventTracer tracer(
+        request,
+        eventtracer::eExec,
+        eventtracer::eDone,
+        "net::cache::ProcessRequest");
+
     // !!! must be called with mLock held !!!
     nsresult           rv;
     nsCacheEntry *     entry = nullptr;
     nsCacheEntry *     doomedEntry = nullptr;
     nsCacheAccessMode  accessGranted = nsICache::ACCESS_NONE;
     if (result) *result = nullptr;
 
     while(1) {  // Activate entry loop
@@ -2006,16 +2024,22 @@ nsresult
 nsCacheService::ActivateEntry(nsCacheRequest * request, 
                               nsCacheEntry ** result,
                               nsCacheEntry ** doomedEntry)
 {
     CACHE_LOG_DEBUG(("Activate entry for request %p\n", request));
     if (!mInitialized || mClearingEntries)
         return NS_ERROR_NOT_AVAILABLE;
 
+    mozilla::eventtracer::AutoEventTracer tracer(
+        request,
+        eventtracer::eExec,
+        eventtracer::eDone,
+        "net::cache::ActivateEntry");
+
     nsresult        rv = NS_OK;
 
     NS_ASSERTION(request != nullptr, "ActivateEntry called with no request");
     if (result) *result = nullptr;
     if (doomedEntry) *doomedEntry = nullptr;
     if ((!request) || (!result) || (!doomedEntry))
         return NS_ERROR_NULL_POINTER;
 
@@ -2107,16 +2131,23 @@ nsCacheService::ActivateEntry(nsCacheReq
 
 
 nsCacheEntry *
 nsCacheService::SearchCacheDevices(nsCString * key, nsCacheStoragePolicy policy, bool *collision)
 {
     Telemetry::AutoTimer<Telemetry::CACHE_DEVICE_SEARCH_2> timer;
     nsCacheEntry * entry = nullptr;
 
+    MOZ_EVENT_TRACER_NAME_OBJECT(key, key->BeginReading());
+    eventtracer::AutoEventTracer searchCacheDevices(
+        key,
+        eventtracer::eExec,
+        eventtracer::eDone,
+        "net::cache::SearchCacheDevices");
+
     CACHE_LOG_DEBUG(("mMemoryDevice: 0x%p\n", mMemoryDevice));
 
     *collision = false;
     if ((policy == nsICache::STORE_ANYWHERE) || (policy == nsICache::STORE_IN_MEMORY)) {
         // If there is no memory device, then there is nothing to search...
         if (mMemoryDevice) {
             entry = mMemoryDevice->FindEntry(key, collision);
             CACHE_LOG_DEBUG(("Searching mMemoryDevice for key %s found: 0x%p, "
@@ -2564,23 +2595,25 @@ nsCacheService::Lock(mozilla::Telemetry:
     mozilla::Telemetry::ID generalID;
 
     if (NS_IsMainThread()) {
         lockerID = mainThreadLockerID;
         generalID = mozilla::Telemetry::CACHE_SERVICE_LOCK_WAIT_MAINTHREAD_2;
     } else {
         lockerID = mozilla::Telemetry::HistogramCount;
         generalID = mozilla::Telemetry::CACHE_SERVICE_LOCK_WAIT_2;
-	}
+    }
 
     TimeStamp start(TimeStamp::Now());
+    MOZ_EVENT_TRACER_WAIT(nsCacheService::gService, "net::cache::lock");
 
     gService->mLock.Lock();
 
     TimeStamp stop(TimeStamp::Now());
+    MOZ_EVENT_TRACER_EXEC(nsCacheService::gService, "net::cache::lock");
 
     // Telemetry isn't thread safe on its own, but this is OK because we're
     // protecting it with the cache lock. 
     if (lockerID != mozilla::Telemetry::HistogramCount) {
         mozilla::Telemetry::AccumulateTimeDelta(lockerID, start, stop);
     }
     mozilla::Telemetry::AccumulateTimeDelta(generalID, start, stop);
 }
@@ -2590,16 +2623,18 @@ nsCacheService::Unlock()
 {
     gService->mLock.AssertCurrentThreadOwns();
 
     nsTArray<nsISupports*> doomed;
     doomed.SwapElements(gService->mDoomedObjects);
 
     gService->mLock.Unlock();
 
+    MOZ_EVENT_TRACER_DONE(nsCacheService::gService, "net::cache::lock");
+
     for (uint32_t i = 0; i < doomed.Length(); ++i)
         doomed[i]->Release();
 }
 
 void
 nsCacheService::ReleaseObject_Locked(nsISupports * obj,
                                      nsIEventTarget * target)
 {
@@ -2695,16 +2730,22 @@ nsCacheService::DeactivateEntry(nsCacheE
         delete entry; // because no one else will
     }
 }
 
 
 nsresult
 nsCacheService::ProcessPendingRequests(nsCacheEntry * entry)
 {
+    mozilla::eventtracer::AutoEventTracer tracer(
+        entry,
+        eventtracer::eExec,
+        eventtracer::eDone,
+        "net::cache::ProcessPendingRequests");
+
     nsresult            rv = NS_OK;
     nsCacheRequest *    request = (nsCacheRequest *)PR_LIST_HEAD(&entry->mRequestQ);
     nsCacheRequest *    nextRequest;
     bool                newWriter = false;
     
     CACHE_LOG_DEBUG(("ProcessPendingRequests for %sinitialized %s %salid entry %p\n",
                     (entry->IsInitialized()?"" : "Un"),
                     (entry->IsDoomed()?"DOOMED" : ""),
--- a/netwerk/cache/nsDiskCacheMap.cpp
+++ b/netwerk/cache/nsDiskCacheMap.cpp
@@ -13,16 +13,17 @@
 
 #include <string.h>
 #include "nsPrintfCString.h"
 
 #include "nsISerializable.h"
 #include "nsSerializationHelper.h"
 
 #include "mozilla/Telemetry.h"
+#include "mozilla/VisualEventTracer.h"
 #include <algorithm>
 
 using namespace mozilla;
 
 /******************************************************************************
  *  nsDiskCacheMap
  *****************************************************************************/
 
@@ -884,16 +885,22 @@ nsDiskCacheMap::CreateDiskCacheEntry(nsD
 
 
 nsresult
 nsDiskCacheMap::WriteDiskCacheEntry(nsDiskCacheBinding *  binding)
 {
     CACHE_LOG_DEBUG(("CACHE: WriteDiskCacheEntry [%x]\n",
         binding->mRecord.HashNumber()));
 
+    mozilla::eventtracer::AutoEventTracer writeDiskCacheEntry(
+        binding->mCacheEntry,
+        mozilla::eventtracer::eExec,
+        mozilla::eventtracer::eDone,
+        "net::cache::WriteDiskCacheEntry");
+
     nsresult            rv        = NS_OK;
     uint32_t            size;
     nsDiskCacheEntry *  diskEntry =  CreateDiskCacheEntry(binding, &size);
     if (!diskEntry)  return NS_ERROR_UNEXPECTED;
     
     uint32_t  fileIndex = CalculateFileIndex(size);
 
     // Deallocate old storage if necessary    
@@ -1008,16 +1015,22 @@ nsDiskCacheMap::ReadDataCacheBlocks(nsDi
 
 
 nsresult
 nsDiskCacheMap::WriteDataCacheBlocks(nsDiskCacheBinding * binding, char * buffer, uint32_t size)
 {
     CACHE_LOG_DEBUG(("CACHE: WriteDataCacheBlocks [%x size=%u]\n",
         binding->mRecord.HashNumber(), size));
 
+    mozilla::eventtracer::AutoEventTracer writeDataCacheBlocks(
+        binding->mCacheEntry,
+        mozilla::eventtracer::eExec,
+        mozilla::eventtracer::eDone,
+        "net::cache::WriteDataCacheBlocks");
+
     nsresult  rv = NS_OK;
     
     // determine block file & number of blocks
     uint32_t  fileIndex  = CalculateFileIndex(size);
     uint32_t  blockCount = 0;
     int32_t   startBlock = 0;
 
     if (size > 0) {
--- a/netwerk/cache/nsDiskCacheStreams.cpp
+++ b/netwerk/cache/nsDiskCacheStreams.cpp
@@ -10,17 +10,17 @@
 #include "nsDiskCacheDevice.h"
 #include "nsDiskCacheStreams.h"
 #include "nsCacheService.h"
 #include "mozilla/FileUtils.h"
 #include "nsThreadUtils.h"
 #include "mozilla/Telemetry.h"
 #include "mozilla/TimeStamp.h"
 #include <algorithm>
-
+#include "mozilla/VisualEventTracer.h"
 
 // we pick 16k as the max buffer size because that is the threshold above which
 //      we are unable to store the data in the cache block files
 //      see nsDiskCacheMap.[cpp,h]
 #define kMaxBufferSize      (16 * 1024)
 
 // Assumptions:
 //      - cache descriptors live for life of streams
@@ -530,16 +530,22 @@ nsDiskCacheStreamIO::OpenCacheFile(int f
     // create PRFileDesc for input stream - the 00600 is just for consistency
     return localFile->OpenNSPRFileDesc(flags, 00600, fd);
 }
 
 
 nsresult
 nsDiskCacheStreamIO::ReadCacheBlocks(uint32_t bufferSize)
 {
+    mozilla::eventtracer::AutoEventTracer readCacheBlocks(
+        mBinding->mCacheEntry,
+        mozilla::eventtracer::eExec,
+        mozilla::eventtracer::eDone,
+        "net::cache::ReadCacheBlocks");
+
     NS_ASSERTION(mStreamEnd == mBinding->mCacheEntry->DataSize(), "bad stream");
     NS_ASSERTION(bufferSize <= kMaxBufferSize, "bufferSize too large for buffer");
     NS_ASSERTION(mStreamEnd <= bufferSize, "data too large for buffer");
 
     nsDiskCacheRecord * record = &mBinding->mRecord;
     if (!record->DataLocationInitialized()) return NS_OK;
 
     NS_ASSERTION(record->DataFile() != kSeparateFile, "attempt to read cache blocks on separate file");
@@ -553,16 +559,22 @@ nsDiskCacheStreamIO::ReadCacheBlocks(uin
     nsDiskCacheMap *map = mDevice->CacheMap();  // get map reference
     return map->ReadDataCacheBlocks(mBinding, mBuffer, mStreamEnd);
 }
 
 
 nsresult
 nsDiskCacheStreamIO::FlushBufferToFile()
 {
+    mozilla::eventtracer::AutoEventTracer flushBufferToFile(
+        mBinding->mCacheEntry,
+        mozilla::eventtracer::eExec,
+        mozilla::eventtracer::eDone,
+        "net::cache::FlushBufferToFile");
+
     nsresult  rv;
     nsDiskCacheRecord * record = &mBinding->mRecord;
     
     if (!mFD) {
         if (record->DataLocationInitialized() && (record->DataFile() > 0)) {
             // remove cache block storage
             nsDiskCacheMap * cacheMap = mDevice->CacheMap();
             rv = cacheMap->DeleteStorage(record, nsDiskCache::kData);
--- a/netwerk/dns/nsDNSService2.cpp
+++ b/netwerk/dns/nsDNSService2.cpp
@@ -25,16 +25,17 @@
 #include "prio.h"
 #include "plstr.h"
 #include "nsIOService.h"
 #include "nsCharSeparatedTokenizer.h"
 #include "nsNetAddr.h"
 #include "nsProxyRelease.h"
 
 #include "mozilla/Attributes.h"
+#include "mozilla/VisualEventTracer.h"
 
 using namespace mozilla;
 using namespace mozilla::net;
 
 static const char kPrefDnsCacheEntries[]    = "network.dnsCacheEntries";
 static const char kPrefDnsCacheExpiration[] = "network.dnsCacheExpiration";
 static const char kPrefDnsCacheGrace[]      = "network.dnsCacheExpirationGracePeriod";
 static const char kPrefIPv4OnlyDomains[]    = "network.dns.ipv4OnlyDomains";
@@ -280,16 +281,18 @@ nsDNSAsyncRequest::OnLookupComplete(nsHo
     nsCOMPtr<nsIDNSRecord> rec;
     if (NS_SUCCEEDED(status)) {
         NS_ASSERTION(hostRecord, "no host record");
         rec = new nsDNSRecord(hostRecord);
         if (!rec)
             status = NS_ERROR_OUT_OF_MEMORY;
     }
 
+    MOZ_EVENT_TRACER_DONE(this, "net::dns::lookup");
+
     mListener->OnLookupComplete(this, rec, status);
     mListener = nullptr;
 
     // release the reference to ourselves that was added before we were
     // handed off to the host resolver.
     NS_RELEASE_THIS();
 }
 
@@ -624,16 +627,19 @@ nsDNSService::AsyncResolve(const nsACStr
     uint16_t af = GetAFForLookup(*hostPtr, flags);
 
     nsDNSAsyncRequest *req =
             new nsDNSAsyncRequest(res, *hostPtr, listener, flags, af);
     if (!req)
         return NS_ERROR_OUT_OF_MEMORY;
     NS_ADDREF(*result = req);
 
+    MOZ_EVENT_TRACER_NAME_OBJECT(req, hostname.BeginReading());
+    MOZ_EVENT_TRACER_WAIT(req, "net::dns::lookup");
+
     // addref for resolver; will be released when OnLookupComplete is called.
     NS_ADDREF(req);
     rv = res->ResolveHost(req->mHost.get(), flags, af, req);
     if (NS_FAILED(rv)) {
         NS_RELEASE(req);
         NS_RELEASE(*result);
     }
     return rv;
--- a/netwerk/dns/nsHostResolver.cpp
+++ b/netwerk/dns/nsHostResolver.cpp
@@ -31,16 +31,17 @@
 #include "pldhash.h"
 #include "plstr.h"
 #include "nsURLHelper.h"
 #include "nsThreadUtils.h"
 
 #include "mozilla/HashFunctions.h"
 #include "mozilla/TimeStamp.h"
 #include "mozilla/Telemetry.h"
+#include "mozilla/VisualEventTracer.h"
 
 using namespace mozilla;
 using namespace mozilla::net;
 
 //----------------------------------------------------------------------------
 
 // Use a persistent thread pool in order to avoid spinning up new threads all the time.
 // In particular, thread creation results in a res_init() call from libc which is 
@@ -164,16 +165,19 @@ nsHostRecord::Create(const nsHostKey *ke
     size_t hostLen = strlen(key->host) + 1;
     size_t size = hostLen + sizeof(nsHostRecord);
 
     // Use placement new to create the object with room for the hostname
     // allocated after it.
     void *place = ::operator new(size);
     *result = new(place) nsHostRecord(key);
     NS_ADDREF(*result);
+
+    MOZ_EVENT_TRACER_NAME_OBJECT(*result, key->host);
+
     return NS_OK;
 }
 
 nsHostRecord::~nsHostRecord()
 {
     delete addr_info;
     delete addr;
 }
@@ -707,16 +711,18 @@ nsHostResolver::ConditionallyCreateThrea
       LOG(("Unable to find a thread for looking up host [%s].\n", rec->host));
 #endif
     return NS_OK;
 }
 
 nsresult
 nsHostResolver::IssueLookup(nsHostRecord *rec)
 {
+    MOZ_EVENT_TRACER_WAIT(rec, "net::dns::resolve");
+
     nsresult rv = NS_OK;
     NS_ASSERTION(!rec->resolving, "record is already being resolved");
 
     // Add rec to one of the pending queues, possibly removing it from mEvictionQ.
     // If rec is on mEvictionQ, then we can just move the owning
     // reference over to the new active queue.
     if (rec->next == rec)
         NS_ADDREF(rec);
@@ -885,16 +891,18 @@ nsHostResolver::OnLookupComplete(nsHostR
                 }
 
                 // release reference to rec owned by mEvictionQ
                 NS_RELEASE(head);
             }
         }
     }
 
+    MOZ_EVENT_TRACER_DONE(rec, "net::dns::resolve");
+
     if (!PR_CLIST_IS_EMPTY(&cbs)) {
         PRCList *node = cbs.next;
         while (node != &cbs) {
             nsResolveHostCallback *callback =
                     static_cast<nsResolveHostCallback *>(node);
             node = node->next;
             callback->OnLookupComplete(this, rec, status);
             // NOTE: callback must not be dereferenced after this point!!
@@ -965,16 +973,17 @@ nsHostResolver::ThreadFunc(void *arg)
     while (resolver->GetHostToLookup(&rec)) {
         LOG(("Calling getaddrinfo for host [%s].\n", rec->host));
 
         int flags = PR_AI_ADDRCONFIG;
         if (!(rec->flags & RES_CANON_NAME))
             flags |= PR_AI_NOCANONNAME;
 
         TimeStamp startTime = TimeStamp::Now();
+        MOZ_EVENT_TRACER_EXEC(rec, "net::dns::resolve");
 
         // We need to remove IPv4 records manually
         // because PR_GetAddrInfoByName doesn't support PR_AF_INET6.
         bool disableIPv4 = rec->af == PR_AF_INET6;
         uint16_t af = disableIPv4 ? PR_AF_UNSPEC : rec->af;
         prai = PR_GetAddrInfoByName(rec->host, af, flags);
 #if defined(RES_RETRY_ON_FAILURE)
         if (!prai && rs.Reset())
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -29,16 +29,17 @@
 #include "mozilla/TimeStamp.h"
 #include "nsError.h"
 #include "nsAlgorithm.h"
 #include "GeckoProfiler.h"
 #include "nsIConsoleService.h"
 #include "base/compiler_specific.h"
 #include "NullHttpTransaction.h"
 #include "mozilla/Attributes.h"
+#include "mozilla/VisualEventTracer.h"
 
 namespace mozilla { namespace net {
  
 namespace {
 
 // Device IDs for various cache types
 const char kDiskDeviceID[] = "disk";
 const char kMemoryDeviceID[] = "memory";
@@ -156,19 +157,23 @@ AutoRedirectVetoNotifier::ReportRedirect
         return;
 
     mChannel->mRedirectChannel = nullptr;
 
     nsCOMPtr<nsIRedirectResultListener> vetoHook;
     NS_QueryNotificationCallbacks(mChannel, 
                                   NS_GET_IID(nsIRedirectResultListener), 
                                   getter_AddRefs(vetoHook));
+
+    nsHttpChannel * channel = mChannel;
     mChannel = nullptr;
     if (vetoHook)
         vetoHook->OnRedirectResult(succeeded);
+
+    MOZ_EVENT_TRACER_DONE(channel, "net::http::redirect-callbacks");
 }
 
 class HttpCacheQuery : public nsRunnable, public nsICacheListener
 {
 public:
     HttpCacheQuery(nsHttpChannel * channel,
                    const nsACString & clientID,
                    nsCacheStoragePolicy storagePolicy,
@@ -315,16 +320,22 @@ nsHttpChannel::~nsHttpChannel()
 
 nsresult
 nsHttpChannel::Init(nsIURI *uri,
                     uint32_t caps,
                     nsProxyInfo *proxyInfo,
                     uint32_t proxyResolveFlags,
                     nsIURI *proxyURI)
 {
+#ifdef MOZ_VISUAL_EVENT_TRACER
+    nsAutoCString url;
+    uri->GetAsciiSpec(url);
+    MOZ_EVENT_TRACER_NAME_OBJECT(this, url.get());
+#endif
+
     nsresult rv = HttpBaseChannel::Init(uri, caps, proxyInfo,
                                         proxyResolveFlags, proxyURI);
     if (NS_FAILED(rv))
         return rv;
 
     LOG(("nsHttpChannel::Init [this=%p]\n", this));
 
     return rv;
@@ -2327,16 +2338,18 @@ IsSubRangeRequest(nsHttpRequestHead &aRe
     nsAutoCString byteRange;
     aRequestHead.GetHeader(nsHttp::Range, byteRange);
     return !byteRange.EqualsLiteral("bytes=0-");
 }
 
 nsresult
 nsHttpChannel::OpenCacheEntry(bool usingSSL)
 {
+    MOZ_EVENT_TRACER_EXEC(this, "net::http::OpenCacheEntry");
+
     nsresult rv;
 
     NS_ASSERTION(!mOnCacheEntryAvailableCallback, "Unexpected state");
     mLoadedFromApplicationCache = false;
 
     LOG(("nsHttpChannel::OpenCacheEntry [this=%p]", this));
 
     // make sure we're not abusing this function
@@ -3976,16 +3989,21 @@ nsHttpChannel::SetupReplacementChannel(n
 }
 
 nsresult
 nsHttpChannel::AsyncProcessRedirection(uint32_t redirectType)
 {
     LOG(("nsHttpChannel::AsyncProcessRedirection [this=%p type=%u]\n",
         this, redirectType));
 
+    // The channel is actually starting its operation now, at least because
+    // we want it to appear like being in the waiting phase until now.
+    MOZ_EVENT_TRACER_EXEC(this, "net::http::channel");
+    MOZ_EVENT_TRACER_EXEC(this, "net::http::redirect-callbacks");
+
     const char *location = mResponseHead->PeekHeader(nsHttp::Location);
 
     // if a location header was not given, then we can't perform the redirect,
     // so just carry on as though this were a normal response.
     if (!location)
         return NS_ERROR_FAILURE;
 
     // make sure non-ASCII characters in the location header are escaped.
@@ -4329,16 +4347,18 @@ nsHttpChannel::GetSecurityInfo(nsISuppor
     *securityInfo = mSecurityInfo;
     NS_IF_ADDREF(*securityInfo);
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsHttpChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *context)
 {
+    MOZ_EVENT_TRACER_WAIT(this, "net::http::channel");
+
     LOG(("nsHttpChannel::AsyncOpen [this=%p]\n", this));
 
     NS_ENSURE_ARG_POINTER(listener);
     NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
     NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED);
 
     nsresult rv;
 
@@ -5064,16 +5084,18 @@ nsHttpChannel::OnStopRequest(nsIRequest 
         FinalizeCacheEntry();
     }
     
     if (mListener) {
         LOG(("  calling OnStopRequest\n"));
         mListener->OnStopRequest(this, mListenerContext, status);
     }
 
+    MOZ_EVENT_TRACER_DONE(this, "net::http::channel");
+
     CloseCacheEntry(!contentComplete);
 
     if (mOfflineCacheEntry)
         CloseOfflineCacheEntry();
 
     if (mLoadGroup)
         mLoadGroup->RemoveRequest(this, nullptr, status);
 
@@ -5144,16 +5166,18 @@ nsHttpChannel::OnDataAvailable(nsIReques
         OnTransportStatus(nullptr, transportStatus, progress, progressMax);
 
         //
         // we have to manually keep the logical offset of the stream up-to-date.
         // we cannot depend solely on the offset provided, since we may have 
         // already streamed some data from another source (see, for example,
         // OnDoneReadingPartialCacheEntry).
         //
+        if (!mLogicalOffset)
+            MOZ_EVENT_TRACER_EXEC(this, "net::http::channel");
 
         nsresult rv =  mListener->OnDataAvailable(this,
                                                   mListenerContext,
                                                   input,
                                                   mLogicalOffset,
                                                   count);
         if (NS_SUCCEEDED(rv))
             mLogicalOffset = progress;
@@ -5441,16 +5465,20 @@ nsHttpChannel::ResumeAt(uint64_t aStartP
 
 NS_IMETHODIMP
 nsHttpChannel::OnCacheEntryAvailable(nsICacheEntryDescriptor *entry,
                                      nsCacheAccessMode access,
                                      nsresult status)
 {
     MOZ_ASSERT(NS_IsMainThread());
 
+    mozilla::eventtracer::AutoEventTracer profiler(this,
+             eventtracer::eNone, eventtracer::eDone,
+             "net::http::OpenCacheEntry");
+
     nsresult rv;
 
     LOG(("nsHttpChannel::OnCacheEntryAvailable [this=%p entry=%p "
          "access=%x status=%x]\n", this, entry, access, status));
 
     if (mCacheQuery) {
         mRequestHead = mCacheQuery->mRequestHead;
         mRedirectedCachekeys = mCacheQuery->mRedirectedCachekeys.forget();
@@ -5786,16 +5814,17 @@ nsHttpChannel::OnRedirectVerifyCallback(
         // and let it be propagated to pumps.
         Cancel(result);
     }
 
     if (!mWaitingForRedirectCallback) {
         // We are not waiting for the callback. At this moment we must release
         // reference to the redirect target channel, otherwise we may leak.
         mRedirectChannel = nullptr;
+        MOZ_EVENT_TRACER_DONE(this, "net::http::channel");
     }
 
     // We always resume the pumps here. If all functions on stack have been
     // called we need OnStopRequest to be triggered, and if we broke out of the
     // loop above (and are thus waiting for a new callback) the suspension
     // count must be balanced in the pumps.
     if (mTransactionPump)
         mTransactionPump->Resume();
--- a/netwerk/protocol/http/nsHttpConnectionMgr.cpp
+++ b/netwerk/protocol/http/nsHttpConnectionMgr.cpp
@@ -15,16 +15,17 @@
 
 #include "nsIServiceManager.h"
 
 #include "nsIObserverService.h"
 
 #include "nsISSLSocketControl.h"
 #include "prnetdb.h"
 #include "mozilla/Telemetry.h"
+#include "mozilla/VisualEventTracer.h"
 #include <algorithm>
 
 using namespace mozilla;
 using namespace mozilla::net;
 
 // defined by the socket transport service while active
 extern PRThread *gSocketThread;
 
--- a/netwerk/protocol/http/nsHttpTransaction.cpp
+++ b/netwerk/protocol/http/nsHttpTransaction.cpp
@@ -18,16 +18,17 @@
 #include "nsProxyRelease.h"
 #include "nsIOService.h"
 #include "nsAtomicRefcnt.h"
 
 #include "nsISeekableStream.h"
 #include "nsISocketTransport.h"
 #include "nsMultiplexInputStream.h"
 #include "nsStringStream.h"
+#include "mozilla/VisualEventTracer.h"
 
 #include "nsComponentManagerUtils.h" // do_CreateInstance
 #include "nsServiceManagerUtils.h"   // do_GetService
 #include "nsIHttpActivityObserver.h"
 #include "nsSocketTransportService2.h"
 #include <algorithm>
 
 
@@ -175,16 +176,22 @@ nsHttpTransaction::Init(uint32_t caps,
                         nsHttpRequestHead *requestHead,
                         nsIInputStream *requestBody,
                         bool requestBodyHasHeaders,
                         nsIEventTarget *target,
                         nsIInterfaceRequestor *callbacks,
                         nsITransportEventSink *eventsink,
                         nsIAsyncInputStream **responseBody)
 {
+    MOZ_EVENT_TRACER_COMPOUND_NAME(static_cast<nsAHttpTransaction*>(this),
+                                   requestHead->PeekHeader(nsHttp::Host),
+                                   requestHead->RequestURI().BeginReading());
+
+    MOZ_EVENT_TRACER_WAIT(static_cast<nsAHttpTransaction*>(this),
+                          "net::http::transaction");
     nsresult rv;
 
     LOG(("nsHttpTransaction::Init [this=%x caps=%x]\n", this, caps));
 
     NS_ASSERTION(cinfo, "ouch");
     NS_ASSERTION(requestHead, "ouch");
     NS_ASSERTION(target, "ouch");
 
@@ -388,16 +395,21 @@ nsHttpTransaction::TakeSubTransactions(
 // nsHttpTransaction::nsAHttpTransaction
 //----------------------------------------------------------------------------
 
 void
 nsHttpTransaction::SetConnection(nsAHttpConnection *conn)
 {
     NS_IF_RELEASE(mConnection);
     NS_IF_ADDREF(mConnection = conn);
+
+    if (conn) {
+        MOZ_EVENT_TRACER_EXEC(static_cast<nsAHttpTransaction*>(this),
+                              "net::http::transaction");
+    }
 }
 
 void
 nsHttpTransaction::GetSecurityCallbacks(nsIInterfaceRequestor **cb)
 {
     MutexAutoLock lock(mCallbacksLock);
     NS_IF_ADDREF(*cb = mCallbacks);
 }
@@ -531,16 +543,22 @@ nsHttpTransaction::ReadRequestSegment(ns
     nsHttpTransaction *trans = (nsHttpTransaction *) closure;
     nsresult rv = trans->mReader->OnReadSegment(buf, count, countRead);
     if (NS_FAILED(rv)) return rv;
 
     if (trans->TimingEnabled() && trans->mTimings.requestStart.IsNull()) {
         // First data we're sending -> this is requestStart
         trans->mTimings.requestStart = TimeStamp::Now();
     }
+
+    if (!trans->mSentData) {
+        MOZ_EVENT_TRACER_MARK(static_cast<nsAHttpTransaction*>(trans),
+                              "net::http::first-write");
+    }
+
     trans->mSentData = true;
     return NS_OK;
 }
 
 nsresult
 nsHttpTransaction::ReadSegments(nsAHttpSegmentReader *reader,
                                 uint32_t count, uint32_t *countRead)
 {
@@ -601,16 +619,21 @@ nsHttpTransaction::WritePipeSegment(nsIO
 
     nsresult rv;
     //
     // OK, now let the caller fill this segment with data.
     //
     rv = trans->mWriter->OnWriteSegment(buf, count, countWritten);
     if (NS_FAILED(rv)) return rv; // caller didn't want to write anything
 
+    if (!trans->mReceivedData) {
+        MOZ_EVENT_TRACER_MARK(static_cast<nsAHttpTransaction*>(trans),
+                              "net::http::first-read");
+    }
+
     NS_ASSERTION(*countWritten > 0, "bad writer");
     trans->mReceivedData = true;
 
     // Let the transaction "play" with the buffer.  It is free to modify
     // the contents of the buffer and/or modify countWritten.
     // - Bytes in HTTP headers don't count towards countWritten, so the input
     // side of pipe (aka nsHttpChannel's mTransactionPump) won't hit
     // OnInputStreamReady until all headers have been parsed.
@@ -800,16 +823,19 @@ nsHttpTransaction::Close(nsresult reason
     mLineBuf.Truncate();
     if (mChunkedDecoder) {
         delete mChunkedDecoder;
         mChunkedDecoder = nullptr;
     }
 
     // closing this pipe triggers the channel's OnStopRequest method.
     mPipeOut->CloseWithStatus(reason);
+
+    MOZ_EVENT_TRACER_DONE(static_cast<nsAHttpTransaction*>(this),
+                          "net::http::transaction");
 }
 
 nsresult
 nsHttpTransaction::AddTransaction(nsAHttpTransaction *trans)
 {
     return NS_ERROR_NOT_IMPLEMENTED;
 }