michael@0: /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include michael@0: #include michael@0: #ifdef MOZ_INSTRUMENT_EVENT_LOOP michael@0: #include "EventTracer.h" michael@0: #endif michael@0: #include "GeckoProfiler.h" michael@0: #include "nsProfiler.h" michael@0: #include "nsMemory.h" michael@0: #include "nsString.h" michael@0: #include "mozilla/Services.h" michael@0: #include "nsIObserverService.h" michael@0: #include "nsIInterfaceRequestor.h" michael@0: #include "nsILoadContext.h" michael@0: #include "nsIWebNavigation.h" michael@0: #include "nsIInterfaceRequestorUtils.h" michael@0: #include "shared-libraries.h" michael@0: #include "js/Value.h" michael@0: michael@0: using std::string; michael@0: michael@0: NS_IMPL_ISUPPORTS(nsProfiler, nsIProfiler) michael@0: michael@0: nsProfiler::nsProfiler() michael@0: : mLockedForPrivateBrowsing(false) michael@0: { michael@0: } michael@0: michael@0: nsProfiler::~nsProfiler() michael@0: { michael@0: nsCOMPtr observerService = mozilla::services::GetObserverService(); michael@0: if (observerService) { michael@0: observerService->RemoveObserver(this, "chrome-document-global-created"); michael@0: observerService->RemoveObserver(this, "last-pb-context-exited"); michael@0: } michael@0: } michael@0: michael@0: nsresult michael@0: nsProfiler::Init() { michael@0: nsCOMPtr observerService = mozilla::services::GetObserverService(); michael@0: if (observerService) { michael@0: observerService->AddObserver(this, "chrome-document-global-created", false); michael@0: observerService->AddObserver(this, "last-pb-context-exited", false); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsProfiler::Observe(nsISupports *aSubject, michael@0: const char *aTopic, michael@0: const char16_t *aData) michael@0: { michael@0: if (strcmp(aTopic, "chrome-document-global-created") == 0) { michael@0: nsCOMPtr requestor = do_QueryInterface(aSubject); michael@0: nsCOMPtr parentWebNav = do_GetInterface(requestor); michael@0: nsCOMPtr loadContext = do_QueryInterface(parentWebNav); michael@0: if (loadContext && loadContext->UsePrivateBrowsing() && !mLockedForPrivateBrowsing) { michael@0: mLockedForPrivateBrowsing = true; michael@0: profiler_lock(); michael@0: } michael@0: } else if (strcmp(aTopic, "last-pb-context-exited") == 0) { michael@0: mLockedForPrivateBrowsing = false; michael@0: profiler_unlock(); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsProfiler::StartProfiler(uint32_t aEntries, double aInterval, michael@0: const char** aFeatures, uint32_t aFeatureCount, michael@0: const char** aThreadNameFilters, uint32_t aFilterCount) michael@0: { michael@0: if (mLockedForPrivateBrowsing) { michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: } michael@0: michael@0: profiler_start(aEntries, aInterval, michael@0: aFeatures, aFeatureCount, michael@0: aThreadNameFilters, aFilterCount); michael@0: #ifdef MOZ_INSTRUMENT_EVENT_LOOP michael@0: bool printToConsole = false; michael@0: mozilla::InitEventTracing(printToConsole); michael@0: #endif michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsProfiler::StopProfiler() michael@0: { michael@0: profiler_stop(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsProfiler::IsPaused(bool *aIsPaused) michael@0: { michael@0: *aIsPaused = profiler_is_paused(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsProfiler::PauseSampling() michael@0: { michael@0: profiler_pause(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsProfiler::ResumeSampling() michael@0: { michael@0: profiler_resume(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsProfiler::AddMarker(const char *aMarker) michael@0: { michael@0: PROFILER_MARKER(aMarker); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsProfiler::GetProfile(char **aProfile) michael@0: { michael@0: char *profile = profiler_get_profile(); michael@0: if (profile) { michael@0: size_t len = strlen(profile); michael@0: char *profileStr = static_cast michael@0: (nsMemory::Clone(profile, (len + 1) * sizeof(char))); michael@0: profileStr[len] = '\0'; michael@0: *aProfile = profileStr; michael@0: free(profile); michael@0: } michael@0: return NS_OK; michael@0: } michael@0: michael@0: static void michael@0: AddSharedLibraryInfoToStream(std::ostream& aStream, const SharedLibrary& aLib) michael@0: { michael@0: aStream << "{"; michael@0: aStream << "\"start\":" << aLib.GetStart(); michael@0: aStream << ",\"end\":" << aLib.GetEnd(); michael@0: aStream << ",\"offset\":" << aLib.GetOffset(); michael@0: aStream << ",\"name\":\"" << aLib.GetName() << "\""; michael@0: const std::string &breakpadId = aLib.GetBreakpadId(); michael@0: aStream << ",\"breakpadId\":\"" << breakpadId << "\""; michael@0: #ifdef XP_WIN michael@0: // FIXME: remove this XP_WIN code when the profiler plugin has switched to michael@0: // using breakpadId. michael@0: std::string pdbSignature = breakpadId.substr(0, 32); michael@0: std::string pdbAgeStr = breakpadId.substr(32, breakpadId.size() - 1); michael@0: michael@0: std::stringstream stream; michael@0: stream << pdbAgeStr; michael@0: michael@0: unsigned pdbAge; michael@0: stream << std::hex; michael@0: stream >> pdbAge; michael@0: michael@0: #ifdef DEBUG michael@0: std::ostringstream oStream; michael@0: oStream << pdbSignature << std::hex << std::uppercase << pdbAge; michael@0: MOZ_ASSERT(breakpadId == oStream.str()); michael@0: #endif michael@0: michael@0: aStream << ",\"pdbSignature\":\"" << pdbSignature << "\""; michael@0: aStream << ",\"pdbAge\":" << pdbAge; michael@0: aStream << ",\"pdbName\":\"" << aLib.GetName() << "\""; michael@0: #endif michael@0: aStream << "}"; michael@0: } michael@0: michael@0: std::string michael@0: GetSharedLibraryInfoString() michael@0: { michael@0: SharedLibraryInfo info = SharedLibraryInfo::GetInfoForSelf(); michael@0: if (info.GetSize() == 0) michael@0: return "[]"; michael@0: michael@0: std::ostringstream os; michael@0: os << "["; michael@0: AddSharedLibraryInfoToStream(os, info.GetEntry(0)); michael@0: michael@0: for (size_t i = 1; i < info.GetSize(); i++) { michael@0: os << ","; michael@0: AddSharedLibraryInfoToStream(os, info.GetEntry(i)); michael@0: } michael@0: michael@0: os << "]"; michael@0: return os.str(); michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsProfiler::GetSharedLibraryInformation(nsAString& aOutString) michael@0: { michael@0: aOutString.Assign(NS_ConvertUTF8toUTF16(GetSharedLibraryInfoString().c_str())); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP nsProfiler::GetProfileData(JSContext* aCx, michael@0: JS::MutableHandle aResult) michael@0: { michael@0: JS::RootedObject obj(aCx, profiler_get_profile_jsobject(aCx)); michael@0: if (!obj) { michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: aResult.setObject(*obj); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsProfiler::IsActive(bool *aIsActive) michael@0: { michael@0: *aIsActive = profiler_is_active(); michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsProfiler::GetResponsivenessTimes(uint32_t *aCount, double **aResult) michael@0: { michael@0: unsigned int len = 100; michael@0: const double* times = profiler_get_responsiveness(); michael@0: if (!times) { michael@0: *aCount = 0; michael@0: *aResult = nullptr; michael@0: return NS_OK; michael@0: } michael@0: michael@0: double *fs = static_cast michael@0: (nsMemory::Clone(times, len * sizeof(double))); michael@0: michael@0: *aCount = len; michael@0: *aResult = fs; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsProfiler::GetFeatures(uint32_t *aCount, char ***aFeatures) michael@0: { michael@0: uint32_t len = 0; michael@0: michael@0: const char **features = profiler_get_features(); michael@0: if (!features) { michael@0: *aCount = 0; michael@0: *aFeatures = nullptr; michael@0: return NS_OK; michael@0: } michael@0: michael@0: while (features[len]) { michael@0: len++; michael@0: } michael@0: michael@0: char **featureList = static_cast michael@0: (nsMemory::Alloc(len * sizeof(char*))); michael@0: michael@0: for (size_t i = 0; i < len; i++) { michael@0: size_t strLen = strlen(features[i]); michael@0: featureList[i] = static_cast michael@0: (nsMemory::Clone(features[i], (strLen + 1) * sizeof(char))); michael@0: } michael@0: michael@0: *aFeatures = featureList; michael@0: *aCount = len; michael@0: return NS_OK; michael@0: }