sbTimingService.cpp
Go to the documentation of this file.
1 /*
2 //
3 // BEGIN SONGBIRD GPL
4 //
5 // This file is part of the Songbird web player.
6 //
7 // Copyright(c) 2005-2008 POTI, Inc.
8 // http://songbirdnest.com
9 //
10 // This file may be licensed under the terms of of the
11 // GNU General Public License Version 2 (the "GPL").
12 //
13 // Software distributed under the License is distributed
14 // on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either
15 // express or implied. See the GPL for the specific language
16 // governing rights and limitations.
17 //
18 // You should have received a copy of the GPL along with this
19 // program. If not, go to http://www.gnu.org/licenses/gpl.html
20 // or write to the Free Software Foundation, Inc.,
21 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 //
23 // END SONGBIRD GPL
24 //
25 */
26 
27 #include "sbTimingService.h"
28 #include "sbTestHarnessCID.h"
29 
30 #include <nsICategoryManager.h>
31 #include <nsIDateTimeFormat.h>
32 #include <nsILocale.h>
33 #include <nsILocaleService.h>
34 #include <nsIObserverService.h>
35 
36 #include <nsAutoPtr.h>
37 #include <nsComponentManagerUtils.h>
38 #include <nsDateTimeFormatCID.h>
39 #include <nsILocalFile.h>
40 #include <nsNetUtil.h>
41 #include <nsServiceManagerUtils.h>
42 #include <nsXPCOMCID.h>
43 
44 #include <sbStringUtils.h>
45 
46 #define NS_APPSTARTUP_CATEGORY "app-startup"
47 #define NS_APPSTARTUP_TOPIC "app-startup"
48 
51 
53 : mTimerLock(nsnull)
54 , mTimerStartTime(0)
55 , mTimerStopTime(0)
56 , mTimerTotalTime(0)
57 {
58  MOZ_COUNT_CTOR(sbTimingService);
59 }
60 
62 {
63  MOZ_COUNT_DTOR(sbTimingService);
64 
65  if(mTimerLock) {
66  nsAutoLock::DestroyLock(mTimerLock);
67  }
68 }
69 
70 nsresult
71 sbTimingServiceTimer::Init(const nsAString &aTimerName)
72 {
73  mTimerLock = nsAutoLock::NewLock("sbTimingServiceTimer::mTimerLock");
74  NS_ENSURE_TRUE(mTimerLock, NS_ERROR_OUT_OF_MEMORY);
75 
76  nsAutoLock lock(mTimerLock);
77  mTimerName = aTimerName;
78 
79  mTimerStartTime = PR_Now();
80 
81  return NS_OK;
82 }
83 
84 NS_IMETHODIMP sbTimingServiceTimer::GetName(nsAString & aName)
85 {
86  nsAutoLock lock(mTimerLock);
87  aName = mTimerName;
88 
89  return NS_OK;
90 }
91 
92 NS_IMETHODIMP sbTimingServiceTimer::GetStartTime(PRInt64 *aStartTime)
93 {
94  NS_ENSURE_ARG_POINTER(aStartTime);
95 
96  nsAutoLock lock(mTimerLock);
97  *aStartTime = mTimerStartTime;
98 
99  return NS_OK;
100 }
101 
102 NS_IMETHODIMP sbTimingServiceTimer::GetStopTime(PRInt64 *aStopTime)
103 {
104  NS_ENSURE_ARG_POINTER(aStopTime);
105 
106  nsAutoLock lock(mTimerLock);
107  *aStopTime = mTimerStopTime;
108 
109  return NS_OK;
110 }
111 
112 NS_IMETHODIMP sbTimingServiceTimer::GetTotalTime(PRInt64 *aTotalTime)
113 {
114  NS_ENSURE_ARG_POINTER(aTotalTime);
115 
116  nsAutoLock lock(mTimerLock);
117  *aTotalTime = mTimerTotalTime;
118 
119  return NS_OK;
120 }
121 
122 
125 
127 : mLoggingLock(nsnull)
128 , mLoggingEnabled(PR_TRUE)
129 , mTimersLock(nsnull)
130 , mResultsLock(nsnull)
131 {
132  MOZ_COUNT_CTOR(sbTimingService);
133 }
134 
136 {
137  MOZ_COUNT_DTOR(sbTimingService);
138 
139  if(mLoggingLock) {
140  nsAutoLock::DestroyLock(mLoggingLock);
141  }
142  if(mTimersLock) {
143  nsAutoLock::DestroyLock(mTimersLock);
144  }
145  if(mResultsLock) {
146  nsAutoLock::DestroyLock(mResultsLock);
147  }
148 
149  mTimers.Clear();
150  mResults.Clear();
151 }
152 
153 /*static*/ NS_METHOD
154 sbTimingService::RegisterSelf(nsIComponentManager* aCompMgr,
155  nsIFile* aPath,
156  const char* aLoaderStr,
157  const char* aType,
158  const nsModuleComponentInfo *aInfo)
159 {
160  NS_ENSURE_ARG_POINTER(aCompMgr);
161  NS_ENSURE_ARG_POINTER(aPath);
162  NS_ENSURE_ARG_POINTER(aLoaderStr);
163  NS_ENSURE_ARG_POINTER(aType);
164  NS_ENSURE_ARG_POINTER(aInfo);
165 
166  nsresult rv = NS_ERROR_UNEXPECTED;
167  nsCOMPtr<nsICategoryManager> categoryManager =
168  do_GetService(NS_CATEGORYMANAGER_CONTRACTID, &rv);
169  NS_ENSURE_SUCCESS(rv, rv);
170 
171  rv = categoryManager->AddCategoryEntry(NS_APPSTARTUP_CATEGORY,
173  "service,"
175  PR_TRUE, PR_TRUE, nsnull);
176  NS_ENSURE_SUCCESS(rv, rv);
177 
178  return NS_OK;
179 }
180 
181 static nsresult
182 CheckEnvironmentVariable(nsIFile ** aFile)
183 {
184  nsresult rv;
185 
186  char const * const fileName = getenv("SB_TIMING_SERVICE_LOG");
187  if (!fileName)
188  return NS_OK;
189 
190  nsCOMPtr<nsILocalFile> file =
191  do_CreateInstance(NS_LOCAL_FILE_CONTRACTID, &rv);
192  NS_ENSURE_SUCCESS(rv, rv);
193 
194  rv = file->InitWithNativePath(nsDependentCString(fileName));
195  NS_ENSURE_SUCCESS(rv, rv);
196 
197  return CallQueryInterface(file, aFile);
198 }
199 
200 NS_METHOD
202  mLoggingLock = nsAutoLock::NewLock("sbTimingService::mLoggingLock");
203  NS_ENSURE_TRUE(mLoggingLock, NS_ERROR_OUT_OF_MEMORY);
204 
205  mTimersLock = nsAutoLock::NewLock("sbTimingService::mTimersLock");
206  NS_ENSURE_TRUE(mTimersLock, NS_ERROR_OUT_OF_MEMORY);
207 
208  mResultsLock = nsAutoLock::NewLock("sbTimingService::mResultsLock");
209  NS_ENSURE_TRUE(mResultsLock, NS_ERROR_OUT_OF_MEMORY);
210 
211  PRBool success = mTimers.Init();
212  NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY);
213 
214  success = mResults.Init();
215  NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY);
216 
217  nsresult rv = CheckEnvironmentVariable(getter_AddRefs(mLogFile));
218  NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "CheckEnvironmentVariable failed");
219 
220  nsCOMPtr<nsIObserverService> observerService =
221  do_GetService("@mozilla.org/observer-service;1", &rv);
222  NS_ENSURE_SUCCESS(rv, rv);
223 
224  rv = observerService->AddObserver(this, "profile-before-change", PR_FALSE);
225  NS_ENSURE_SUCCESS(rv, rv);
226 
227  return NS_OK;
228 }
229 
230 NS_IMETHODIMP
231 sbTimingService::GetEnabled(PRBool *aEnabled)
232 {
233  NS_ENSURE_ARG_POINTER(aEnabled);
234 
235  nsAutoLock lock(mLoggingLock);
236  *aEnabled = mLoggingEnabled;
237 
238  return NS_OK;
239 }
240 NS_IMETHODIMP
241 sbTimingService::SetEnabled(PRBool aEnabled)
242 {
243  nsAutoLock lock(mLoggingLock);
244  mLoggingEnabled = aEnabled;
245 
246  return NS_OK;
247 }
248 
249 NS_IMETHODIMP
250 sbTimingService::GetLogFile(nsIFile * *aLogFile)
251 {
252  NS_ENSURE_ARG_POINTER(aLogFile);
253 
254  nsAutoLock lock(mLoggingLock);
255  NS_ADDREF(*aLogFile = mLogFile);
256 
257  return NS_OK;
258 }
259 NS_IMETHODIMP
260 sbTimingService::SetLogFile(nsIFile * aLogFile)
261 {
262  NS_ENSURE_ARG_POINTER(aLogFile);
263 
264  nsAutoLock lock(mLoggingLock);
265  mLogFile = aLogFile;
266 
267  return NS_OK;
268 }
269 
270 NS_IMETHODIMP
271 sbTimingService::StartPerfTimer(const nsAString & aTimerName)
272 {
273  nsRefPtr<sbTimingServiceTimer> timer;
274  NS_NEWXPCOM(timer, sbTimingServiceTimer);
275  NS_ENSURE_TRUE(timer, NS_ERROR_OUT_OF_MEMORY);
276 
277  nsresult rv = timer->Init(aTimerName);
278  NS_ENSURE_SUCCESS(rv, rv);
279 
280  nsAutoLock lockTimers(mTimersLock);
281 
282  if(mTimers.Get(aTimerName, nsnull)) {
283  return NS_ERROR_ALREADY_INITIALIZED;
284  }
285 
286  PRBool success = mTimers.Put(aTimerName, timer);
287  NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY);
288 
289  return NS_OK;
290 }
291 
292 NS_IMETHODIMP
293 sbTimingService::StopPerfTimer(const nsAString & aTimerName, PRInt64 *_retval)
294 {
295  NS_ENSURE_ARG_POINTER(_retval);
296 
297  PRTime stopTime = PR_Now();
298  nsCOMPtr<sbITimingServiceTimer> timer;
299 
300  {
301  nsAutoLock lockTimers(mTimersLock);
302 
303  if(!mTimers.Get(aTimerName, getter_AddRefs(timer))) {
304  return NS_ERROR_NOT_INITIALIZED;
305  }
306 
307  mTimers.Remove(aTimerName);
308  }
309 
310  sbTimingServiceTimer *rawTimer =
311  reinterpret_cast<sbTimingServiceTimer *>(timer.get());
312 
313  rawTimer->mTimerStopTime = stopTime;
314  rawTimer->mTimerTotalTime = stopTime - rawTimer->mTimerStartTime;
315  *_retval = rawTimer->mTimerTotalTime;
316 
317  {
318  nsAutoLock lockResults(mResultsLock);
319  PRUint32 resultCount = mResults.Count();
320 
321  PRBool success = mResults.Put(resultCount, timer);
322  NS_ENSURE_TRUE(success, NS_ERROR_OUT_OF_MEMORY);
323  }
324 
325  return NS_OK;
326 }
327 
328 NS_IMETHODIMP
329 sbTimingService::Observe(nsISupports* aSubject,
330  const char* aTopic,
331  const PRUnichar* aData)
332 {
333  nsresult rv;
334  nsCOMPtr<nsIObserverService> observerService =
335  do_GetService(NS_OBSERVERSERVICE_CONTRACTID, &rv);
336 
337  nsAutoLock lock(mLoggingLock);
338 
339  if(strcmp(aTopic, "profile-before-change") == 0) {
340 
341  nsCOMPtr<nsIObserverService> observerService =
342  do_GetService("@mozilla.org/observer-service;1", &rv);
343  NS_ENSURE_SUCCESS(rv, rv);
344 
345  rv = observerService->RemoveObserver(this, "profile-before-change");
346  NS_ENSURE_SUCCESS(rv, rv);
347 
348  if(mLoggingEnabled) {
349  // Logging output is enabled; format and output to the console.
350  nsCString output;
351  rv = FormatResultsToString(output);
352  NS_ENSURE_SUCCESS(rv, rv);
353 
354  printf("%s", output.BeginReading());
355 
356  // If we also have a log file, output to the logfile.
357  if(mLogFile) {
358  nsCOMPtr<nsIOutputStream> outputStream;
359  rv = NS_NewLocalFileOutputStream(getter_AddRefs(outputStream),
360  mLogFile,
361  PR_APPEND | PR_CREATE_FILE | PR_WRONLY);
362  NS_ENSURE_SUCCESS(rv, rv);
363 
364  PRUint32 bytesOut = 0;
365  rv = outputStream->Write(output.BeginReading(),
366  output.Length(),
367  &bytesOut);
368 
369  // Close it off regardless of the error
370  nsresult rvclose = outputStream->Close();
371 
372  // Handle write errors before the close error
373  NS_ENSURE_SUCCESS(rv, rv);
374  NS_ENSURE_TRUE(bytesOut == output.Length(), NS_ERROR_UNEXPECTED);
375 
376  // Now handle any error from close
377  NS_ENSURE_SUCCESS(rvclose, rvclose);
378  }
379  }
380  }
381 
382  return NS_OK;
383 }
384 
385 nsresult sbTimingService::FormatResultsToString(nsACString &aOutput)
386 {
387  nsAutoLock lockResults(mResultsLock);
388  PRUint32 resultCount = mResults.Count();
389 
390  nsresult rv = NS_ERROR_UNEXPECTED;
391 
392  nsCOMPtr<nsILocaleService> localeService =
393  do_GetService("@mozilla.org/intl/nslocaleservice;1", &rv);
394  NS_ENSURE_SUCCESS(rv, rv);
395 
396  nsCOMPtr<nsILocale> locale;
397  rv = localeService->GetApplicationLocale(getter_AddRefs(locale));
398  NS_ENSURE_SUCCESS(rv, rv);
399 
400  nsCOMPtr<nsIDateTimeFormat> dateTimeFormat =
401  do_CreateInstance(NS_DATETIMEFORMAT_CONTRACTID, &rv);
402 
403  PRTime startTime = 0;
404  PRTime stopTime = 0;
405  PRTime totalTime = 0;
406 
407  nsCOMPtr<sbITimingServiceTimer> timer;
408 
409  nsString out, output, timerName;
410 
411  output.AppendLiteral("\n\n\t\tsbTimingService Results\n\n");
412 
413  for(PRUint32 current = 0; current < resultCount; ++current) {
414  PRBool success = mResults.Get(current, getter_AddRefs(timer));
415  NS_ENSURE_TRUE(success, NS_ERROR_NOT_AVAILABLE);
416 
417  rv = timer->GetStartTime(&startTime);
418  NS_ENSURE_SUCCESS(rv, rv);
419 
420  rv = timer->GetStopTime(&stopTime);
421  NS_ENSURE_SUCCESS(rv, rv);
422 
423  rv = timer->GetTotalTime(&totalTime);
424  NS_ENSURE_SUCCESS(rv, rv);
425 
426  rv = timer->GetName(timerName);
427  NS_ENSURE_SUCCESS(rv, rv);
428 
429  output.Append(timerName);
430  output.AppendLiteral("\t");
431 
432  PRExplodedTime explodedTime = {0};
433  PR_ExplodeTime(startTime, PR_LocalTimeParameters, &explodedTime);
434 
435  rv = dateTimeFormat->FormatPRExplodedTime(locale,
436  kDateFormatNone,
437  kTimeFormatSeconds,
438  &explodedTime,
439  out);
440  NS_ENSURE_SUCCESS(rv, rv);
441 
442  output.Append(out);
443  output.AppendLiteral(" ");
444  output.AppendInt(static_cast<PRInt32>((startTime % PR_USEC_PER_SEC) / PR_USEC_PER_MSEC ));
445  output.AppendLiteral("ms\t");
446 
447  PR_ExplodeTime(stopTime, PR_LocalTimeParameters, &explodedTime);
448 
449  rv = dateTimeFormat->FormatPRExplodedTime(locale,
450  kDateFormatNone,
451  kTimeFormatSeconds,
452  &explodedTime,
453  out);
454  NS_ENSURE_SUCCESS(rv, rv);
455 
456  output.Append(out);
457  output.AppendLiteral(" ");
458  output.AppendInt(static_cast<PRInt32>((stopTime % PR_USEC_PER_SEC) / PR_USEC_PER_MSEC ));
459  output.AppendLiteral("ms\t");
460 
461  AppendInt(output, totalTime / PR_USEC_PER_MSEC);
462  output.AppendLiteral("ms\n");
463  }
464 
465  output.AppendLiteral("\n\n");
466  aOutput.Assign(NS_ConvertUTF16toUTF8(output));
467 
468  return NS_OK;
469 }
return NS_OK
_updateCookies aPath
NS_IMPL_THREADSAFE_ISUPPORTS1(sbTimingServiceTimer, sbITimingServiceTimer) sbTimingServiceTimer
static nsCOMPtr< nsIObserverService > observerService
Definition: UnityProxy.cpp:6
static nsresult CheckEnvironmentVariable(nsIFile **aFile)
var PR_CREATE_FILE
#define NS_APPSTARTUP_CATEGORY
#define SB_TIMINGSERVICE_CONTRACTID
#define SB_TIMINGSERVICE_DESCRIPTION
_updateCookies aName
var PR_WRONLY
static void AppendInt(nsAString &str, PRInt64 val)
nsresult FormatResultsToString(nsACString &aOutput)
static NS_METHOD RegisterSelf(nsIComponentManager *aCompMgr, nsIFile *aPath, const char *aLoaderStr, const char *aType, const nsModuleComponentInfo *aInfo)
An interface for running simple, time based, profiling.
nsresult Init(const nsAString &aTimerName)
_updateTextAndScrollDataForFrame aData
var file