Back to index

lightning-sunbird  0.9+nobinonly
Classes | Defines | Functions
nsLoadCollector.cpp File Reference
#include "nsLoadCollector.h"
#include "nsMetricsService.h"
#include "nsCOMPtr.h"
#include "nsCURILoader.h"
#include "nsIServiceManager.h"
#include "nsIWebProgress.h"
#include "nsIDocShell.h"
#include "nsIDocShellTreeItem.h"
#include "nsIChannel.h"
#include "nsIDOMWindow.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsServiceManagerUtils.h"
#include "nsIURI.h"
#include "nsIDOMDocument.h"
#include "nsIDocument.h"
#include "nsDocShellLoadTypes.h"

Go to the source code of this file.

Classes

struct  MemUsage

Defines

#define MOZILLA_INTERNAL_API

Functions

static PRBool GetMemUsage (MemUsage *result)
 NS_IMPL_ISUPPORTS4 (nsLoadCollector, nsIMetricsCollector, nsIWebProgressListener, nsISupportsWeakReference, nsIDocumentObserver) NS_IMETHODIMP nsLoadCollector

Class Documentation

struct MemUsage

Definition at line 138 of file nsLoadCollector.cpp.

Collaboration diagram for MemUsage:
Class Members
PRInt64 resident
PRInt64 total

Define Documentation

Definition at line 79 of file nsLoadCollector.cpp.


Function Documentation

static PRBool GetMemUsage ( MemUsage result) [static]

Definition at line 144 of file nsLoadCollector.cpp.

{
  PRBool setResult = PR_FALSE;
#if defined(__linux)
  // Read /proc/<pid>/statm, and look at the first and second fields, which
  // report the program size and the number of resident pages for this process,
  // respectively.
 
  char buf[256];
  if (!sProcFP) {
    pid_t pid = getpid();
    snprintf(buf, sizeof(buf), "/proc/%d/statm", pid);
    sProcFP = fopen(buf, "rb");
  }
  if (sProcFP) {
    int vmsize, vmrss;

    int count = fscanf(sProcFP, "%d %d", &vmsize, &vmrss);
    rewind(sProcFP);

    if (count == 2) {
      static int ps = getpagesize();
      result->total = PRInt64(vmsize) * ps;
      result->resident = PRInt64(vmrss) * ps;
      setResult = PR_TRUE;
    }
  }
#elif defined(XP_WIN)
  // Use GetProcessMemoryInfo, which only works on WinNT and later.

  if (!sGetMemInfo) {
    sPSModule = LoadLibrary("psapi.dll");
    if (sPSModule) {
      sGetMemInfo = (GETPROCESSMEMORYINFO_FUNC)
          GetProcAddress(sPSModule, "GetProcessMemoryInfo");
      if (sGetMemInfo)
        sProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
                               FALSE, GetCurrentProcessId());
      // Don't leave ourselves partially initialized.
      if (!sProcess)
        GetMemUsage_Shutdown();
    }
  }
  if (sGetMemInfo) {
    PROCESS_MEMORY_COUNTERS pmc;
    if (sGetMemInfo(sProcess, &pmc, sizeof(pmc))) {
      result->total = PRInt64(pmc.PagefileUsage);
      result->resident = PRInt64(pmc.WorkingSetSize);
      setResult = PR_TRUE;
    }
  }
#elif defined(XP_MACOSX)
  // Use task_info

  task_basic_info_data_t ti;
  mach_msg_type_number_t count = TASK_BASIC_INFO_COUNT;
  kern_return_t error = task_info(mach_task_self(), TASK_BASIC_INFO,
                                  (task_info_t) &ti, &count);
  if (error == KERN_SUCCESS) {
    result->total = PRInt64(ti.virtual_size);
    result->resident = PRInt64(ti.resident_size);
    setResult = PR_TRUE;
  }
#endif
  return setResult;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 224 of file nsLoadCollector.cpp.

{
  NS_ASSERTION(flags & STATE_IS_DOCUMENT,
               "incorrect state change notification");

#ifdef PR_LOGGING
  if (MS_LOG_ENABLED()) {
    nsCString name;
    request->GetName(name);

    MS_LOG(("LoadCollector: progress = %p, request = %p [%s], flags = %x, status = %x",
            webProgress, request, name.get(), flags, status));
  }
#endif

  nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
  if (!channel) {
    // We don't care about non-channel requests
    return NS_OK;
  }

  nsresult rv;
  if (flags & STATE_START) {
    RequestEntry entry;
    NS_ASSERTION(!mRequestMap.Get(request, &entry), "duplicate STATE_START");

    nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(webProgress);
    nsCOMPtr<nsIDOMWindow> window = do_GetInterface(docShell);
    if (!window) {
      // We don't really care about windowless loads
      return NS_OK;
    }

    rv = nsMetricsUtils::NewPropertyBag(getter_AddRefs(entry.properties));
    NS_ENSURE_SUCCESS(rv, rv);
    nsIWritablePropertyBag2 *props = entry.properties;

    rv = props->SetPropertyAsUint32(NS_LITERAL_STRING("window"),
                                    nsMetricsService::GetWindowID(window));
    NS_ENSURE_SUCCESS(rv, rv);

    if (flags & STATE_RESTORING) {
      rv = props->SetPropertyAsBool(NS_LITERAL_STRING("bfCacheHit"), PR_TRUE);
      NS_ENSURE_SUCCESS(rv, rv);
    }

    nsString origin;
    PRUint32 loadType;
    docShell->GetLoadType(&loadType);

    switch (loadType) {
    case LOAD_NORMAL:
    case LOAD_NORMAL_REPLACE:
    case LOAD_BYPASS_HISTORY:
      origin = NS_LITERAL_STRING("typed");
      break;
    case LOAD_NORMAL_EXTERNAL:
      origin = NS_LITERAL_STRING("external");
      break;
    case LOAD_HISTORY:
      origin = NS_LITERAL_STRING("session-history");
      break;
    case LOAD_RELOAD_NORMAL:
    case LOAD_RELOAD_BYPASS_CACHE:
    case LOAD_RELOAD_BYPASS_PROXY:
    case LOAD_RELOAD_BYPASS_PROXY_AND_CACHE:
    case LOAD_RELOAD_CHARSET_CHANGE:
      origin = NS_LITERAL_STRING("reload");
      break;
    case LOAD_LINK:
      origin = NS_LITERAL_STRING("link");
      break;
    case LOAD_REFRESH:
      origin = NS_LITERAL_STRING("refresh");
      break;
    default:
      break;
    }
    if (!origin.IsEmpty()) {
      rv = props->SetPropertyAsAString(NS_LITERAL_STRING("origin"), origin);
      NS_ENSURE_SUCCESS(rv, rv);
    }
    entry.startTime = PR_Now();
    NS_ENSURE_TRUE(mRequestMap.Put(request, entry), NS_ERROR_OUT_OF_MEMORY);
  } else if (flags & STATE_STOP) {
    RequestEntry entry;
    if (mRequestMap.Get(request, &entry)) {
      mRequestMap.Remove(request);

      // Log a <document action="load"> event
      nsIWritablePropertyBag2 *props = entry.properties;
      rv = props->SetPropertyAsACString(NS_LITERAL_STRING("action"),
                                        NS_LITERAL_CSTRING("load"));
      NS_ENSURE_SUCCESS(rv, rv);
      
      // Compute the load time now that we have the end time.
      PRInt64 loadTime = (PR_Now() - entry.startTime) / PR_USEC_PER_MSEC;
      rv = props->SetPropertyAsUint64(NS_LITERAL_STRING("loadtime"), loadTime);
      NS_ENSURE_SUCCESS(rv, rv);

      MemUsage mu;
      if (GetMemUsage(&mu)) {
        rv = props->SetPropertyAsUint64(NS_LITERAL_STRING("memtotal"), mu.total);
        NS_ENSURE_SUCCESS(rv, rv);
        rv = props->SetPropertyAsUint64(NS_LITERAL_STRING("memresident"), mu.resident);
        NS_ENSURE_SUCCESS(rv, rv);
      }

      // Look up the document id, or assign a new one
      nsCOMPtr<nsIDocShell> docShell = do_QueryInterface(webProgress);
      nsCOMPtr<nsIDOMWindow> window = do_GetInterface(docShell);
      if (!window) {
        MS_LOG(("Couldn't get window"));
        return NS_ERROR_UNEXPECTED;
      }

      nsCOMPtr<nsIDOMDocument> domDoc;
      window->GetDocument(getter_AddRefs(domDoc));
      nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
      if (!doc) {
        MS_LOG(("Couldn't get document"));
        return NS_ERROR_UNEXPECTED;
      }

      nsCOMPtr<nsIDocShellTreeItem> item = do_QueryInterface(docShell);
      NS_ENSURE_STATE(item);
      PRBool subframe = nsMetricsUtils::IsSubframe(item);
      if (subframe) {
        rv = props->SetPropertyAsBool(NS_LITERAL_STRING("subframe"), PR_TRUE);
        NS_ENSURE_SUCCESS(rv, rv);
      }

      nsMetricsService *ms = nsMetricsService::get();
      DocumentEntry docEntry;
      if (!mDocumentMap.Get(doc, &docEntry)) {
        docEntry.docID = mNextDocID++;
        docEntry.subframe = subframe;

        if (!ms->WindowMap().Get(window, &docEntry.windowID)) {
          MS_LOG(("Window not in the window map"));
          return NS_ERROR_UNEXPECTED;
        }

        NS_ENSURE_TRUE(mDocumentMap.Put(doc, docEntry),
                       NS_ERROR_OUT_OF_MEMORY);
      }
      doc->AddObserver(this);  // set up to log the document destroy

      rv = props->SetPropertyAsUint32(NS_LITERAL_STRING("docid"),
                                      docEntry.docID);
      NS_ENSURE_SUCCESS(rv, rv);

      // If this was a load of a chrome document, hash the URL of the document
      // so it can be identified.

      nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
      if (channel) {
        nsCOMPtr<nsIURI> uri;
        channel->GetURI(getter_AddRefs(uri));
        if (uri) {
          PRBool isChrome = PR_FALSE;
          uri->SchemeIs("chrome", &isChrome);
          if (isChrome) {
            nsCString spec;
            uri->GetSpec(spec);

            nsCString hashedSpec;
            rv = ms->HashUTF8(spec, hashedSpec);
            NS_ENSURE_SUCCESS(rv, rv);

            rv = props->SetPropertyAsACString(NS_LITERAL_STRING("urlhash"),
                                              hashedSpec);
            NS_ENSURE_SUCCESS(rv, rv);
          }
        }
      }

      rv = ms->LogEvent(NS_LITERAL_STRING("document"), props);
      NS_ENSURE_SUCCESS(rv, rv);
    } else {
      NS_WARNING("STATE_STOP without STATE_START");
    }
  }

  return NS_OK;
}

Here is the call graph for this function: