mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 568863: Add a scriptable interface to operating-system performance measurement APIs (Linux only for now). r=cjones,waldo,mitch a2.0=bz
--HG-- rename : toolkit/components/ctypes/Module.cpp => toolkit/components/ctypes/ctypes.cpp rename : toolkit/components/ctypes/Module.h => toolkit/components/ctypes/ctypes.h
This commit is contained in:
parent
460cdeaae5
commit
788b4d617f
@ -322,6 +322,19 @@ INSTALLED_HEADERS += \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
# PerfMeasurement is available regardless of low-level support for it;
|
||||
# it just doesn't necessarily do anything useful. There is one
|
||||
# implementation source file per supported operating system, plus a stub
|
||||
# for unsupported OSes, plus the Javascript wrapper.
|
||||
VPATH += $(srcdir)/perf
|
||||
INSTALLED_HEADERS += jsperf.h
|
||||
CPPSRCS += jsperf.cpp
|
||||
ifdef HAVE_LINUX_PERF_EVENT_H
|
||||
CPPSRCS += pm_linux.cpp
|
||||
else
|
||||
CPPSRCS += pm_stub.cpp
|
||||
endif
|
||||
|
||||
ifeq (,$(filter-out WINNT WINCE,$(OS_ARCH)))
|
||||
INSTALLED_HEADERS += jscpucfg.h
|
||||
endif
|
||||
|
@ -338,3 +338,4 @@ WRAP_SYSTEM_INCLUDES = @WRAP_SYSTEM_INCLUDES@
|
||||
ENABLE_TRACEJIT = @ENABLE_TRACEJIT@
|
||||
NANOJIT_ARCH = @NANOJIT_ARCH@
|
||||
HAVE_ARM_SIMD= @HAVE_ARM_SIMD@
|
||||
HAVE_LINUX_PERF_EVENT_H = @HAVE_LINUX_PERF_EVENT_H@
|
||||
|
@ -3022,6 +3022,10 @@ case $target in
|
||||
;;
|
||||
esac
|
||||
|
||||
dnl Performance measurement headers.
|
||||
AC_CHECK_HEADER(linux/perf_event.h, HAVE_LINUX_PERF_EVENT_H=1)
|
||||
AC_SUBST(HAVE_LINUX_PERF_EVENT_H)
|
||||
|
||||
dnl Checks for libraries.
|
||||
dnl ========================================================
|
||||
case $target in
|
||||
|
278
js/src/perf/jsperf.cpp
Normal file
278
js/src/perf/jsperf.cpp
Normal file
@ -0,0 +1,278 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* the Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Zack Weinberg <zweinberg@mozilla.com> (original author)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "jsperf.h"
|
||||
#include "jscntxt.h" /* for error messages */
|
||||
#include "jsobj.h" /* for unwrapping without a context */
|
||||
|
||||
using JS::PerfMeasurement;
|
||||
|
||||
// You cannot forward-declare a static object in C++, so instead
|
||||
// we have to forward-declare the helper functions that refer to it.
|
||||
static PerfMeasurement* GetPM(JSContext* cx, JSObject* obj, const char* fname);
|
||||
static PerfMeasurement* GetPMFromThis(JSContext* cx, jsval* vp);
|
||||
|
||||
// Constructor and destructor
|
||||
|
||||
static JSBool
|
||||
pm_construct(JSContext* cx, JSObject* obj, uintN argc, jsval* argv, jsval* rval)
|
||||
{
|
||||
uint32 mask;
|
||||
if (!JS_ConvertArguments(cx, argc, argv, "u", &mask))
|
||||
return JS_FALSE;
|
||||
|
||||
if (!JS_SealObject(cx, obj, JS_FALSE))
|
||||
return JS_FALSE;
|
||||
|
||||
PerfMeasurement* p = new PerfMeasurement(PerfMeasurement::EventMask(mask));
|
||||
if (!p) {
|
||||
JS_ReportOutOfMemory(cx);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
JS_SetPrivate(cx, obj, p);
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
pm_finalize(JSContext* cx, JSObject* obj)
|
||||
{
|
||||
delete (PerfMeasurement*) JS_GetPrivate(cx, obj);
|
||||
}
|
||||
|
||||
// Property access
|
||||
|
||||
#define GETTER(name) \
|
||||
static JSBool \
|
||||
pm_get_##name(JSContext* cx, JSObject* obj, jsid /*unused*/, jsval* vp) \
|
||||
{ \
|
||||
PerfMeasurement* p = GetPM(cx, obj, #name); \
|
||||
if (!p) \
|
||||
return JS_FALSE; \
|
||||
return JS_NewNumberValue(cx, p->name, vp); \
|
||||
}
|
||||
|
||||
GETTER(cpu_cycles)
|
||||
GETTER(instructions)
|
||||
GETTER(cache_references)
|
||||
GETTER(cache_misses)
|
||||
GETTER(branch_instructions)
|
||||
GETTER(branch_misses)
|
||||
GETTER(bus_cycles)
|
||||
GETTER(page_faults)
|
||||
GETTER(major_page_faults)
|
||||
GETTER(context_switches)
|
||||
GETTER(cpu_migrations)
|
||||
GETTER(eventsMeasured)
|
||||
|
||||
#undef GETTER
|
||||
|
||||
// Calls
|
||||
|
||||
static JSBool
|
||||
pm_start(JSContext* cx, uintN /*unused*/, jsval* vp)
|
||||
{
|
||||
PerfMeasurement* p = GetPMFromThis(cx, vp);
|
||||
if (!p)
|
||||
return JS_FALSE;
|
||||
|
||||
p->start();
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
pm_stop(JSContext* cx, uintN /*unused*/, jsval* vp)
|
||||
{
|
||||
PerfMeasurement* p = GetPMFromThis(cx, vp);
|
||||
if (!p)
|
||||
return JS_FALSE;
|
||||
|
||||
p->stop();
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
pm_canMeasureSomething(JSContext* cx, uintN /*unused*/, jsval* vp)
|
||||
{
|
||||
PerfMeasurement* p = GetPMFromThis(cx, vp);
|
||||
if (!p)
|
||||
return JS_FALSE;
|
||||
|
||||
JS_SET_RVAL(cx, vp, BOOLEAN_TO_JSVAL(p->canMeasureSomething()));
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
const uint8 PM_FATTRS = JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_SHARED;
|
||||
static JSFunctionSpec pm_fns[] = {
|
||||
JS_FN("start", pm_start, 0, PM_FATTRS),
|
||||
JS_FN("stop", pm_stop, 0, PM_FATTRS),
|
||||
JS_FN("canMeasureSomething", pm_canMeasureSomething, 0, PM_FATTRS),
|
||||
JS_FS_END
|
||||
};
|
||||
|
||||
const uint8 PM_PATTRS =
|
||||
JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_SHARED;
|
||||
|
||||
#define GETTER(name) \
|
||||
{ #name, 0, PM_PATTRS, pm_get_##name, 0 }
|
||||
|
||||
static JSPropertySpec pm_props[] = {
|
||||
GETTER(cpu_cycles),
|
||||
GETTER(instructions),
|
||||
GETTER(cache_references),
|
||||
GETTER(cache_misses),
|
||||
GETTER(branch_instructions),
|
||||
GETTER(branch_misses),
|
||||
GETTER(bus_cycles),
|
||||
GETTER(page_faults),
|
||||
GETTER(major_page_faults),
|
||||
GETTER(context_switches),
|
||||
GETTER(cpu_migrations),
|
||||
GETTER(eventsMeasured),
|
||||
{0,0,0,0,0}
|
||||
};
|
||||
|
||||
#undef GETTER
|
||||
|
||||
// If this were C++ these would be "static const" members.
|
||||
|
||||
const uint8 PM_CATTRS = JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT;
|
||||
|
||||
#define CONSTANT(name) { #name, PerfMeasurement::name }
|
||||
|
||||
static const struct pm_const {
|
||||
const char *name;
|
||||
PerfMeasurement::EventMask value;
|
||||
} pm_consts[] = {
|
||||
CONSTANT(CPU_CYCLES),
|
||||
CONSTANT(INSTRUCTIONS),
|
||||
CONSTANT(CACHE_REFERENCES),
|
||||
CONSTANT(CACHE_MISSES),
|
||||
CONSTANT(BRANCH_INSTRUCTIONS),
|
||||
CONSTANT(BRANCH_MISSES),
|
||||
CONSTANT(BUS_CYCLES),
|
||||
CONSTANT(PAGE_FAULTS),
|
||||
CONSTANT(MAJOR_PAGE_FAULTS),
|
||||
CONSTANT(CONTEXT_SWITCHES),
|
||||
CONSTANT(CPU_MIGRATIONS),
|
||||
CONSTANT(ALL),
|
||||
CONSTANT(NUM_MEASURABLE_EVENTS),
|
||||
{ 0, PerfMeasurement::EventMask(0) }
|
||||
};
|
||||
|
||||
#undef CONSTANT
|
||||
|
||||
static JSClass pm_class = {
|
||||
"PerfMeasurement", JSCLASS_HAS_PRIVATE,
|
||||
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
|
||||
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, pm_finalize,
|
||||
JSCLASS_NO_OPTIONAL_MEMBERS
|
||||
};
|
||||
|
||||
// Helpers (declared above)
|
||||
|
||||
static PerfMeasurement*
|
||||
GetPM(JSContext* cx, JSObject* obj, const char* fname)
|
||||
{
|
||||
PerfMeasurement* p = (PerfMeasurement*)
|
||||
JS_GetInstancePrivate(cx, obj, &pm_class, 0);
|
||||
if (p)
|
||||
return p;
|
||||
|
||||
// JS_GetInstancePrivate only sets an exception if its last argument
|
||||
// is nonzero, so we have to do it by hand.
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, 0, JSMSG_INCOMPATIBLE_PROTO,
|
||||
pm_class.name, fname, JS_GET_CLASS(cx, obj)->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static PerfMeasurement*
|
||||
GetPMFromThis(JSContext* cx, jsval* vp)
|
||||
{
|
||||
JSObject* this_ = JS_THIS_OBJECT(cx, vp);
|
||||
if (!this_)
|
||||
return 0;
|
||||
return (PerfMeasurement*)
|
||||
JS_GetInstancePrivate(cx, this_, &pm_class, JS_ARGV(cx, vp));
|
||||
}
|
||||
|
||||
namespace JS {
|
||||
|
||||
JSObject*
|
||||
RegisterPerfMeasurement(JSContext *cx, JSObject *global)
|
||||
{
|
||||
JSObject *prototype = JS_InitClass(cx, global, 0 /* parent */,
|
||||
&pm_class, pm_construct, 1,
|
||||
pm_props, pm_fns, 0, 0);
|
||||
if (!prototype)
|
||||
return 0;
|
||||
|
||||
JSObject *ctor = JS_GetConstructor(cx, prototype);
|
||||
if (!ctor)
|
||||
return 0;
|
||||
|
||||
for (const pm_const *c = pm_consts; c->name; c++) {
|
||||
if (!JS_DefineProperty(cx, ctor, c->name, INT_TO_JSVAL(c->value),
|
||||
JS_PropertyStub, JS_PropertyStub, PM_CATTRS))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!JS_SealObject(cx, prototype, JS_FALSE) ||
|
||||
!JS_SealObject(cx, ctor, JS_FALSE)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return prototype;
|
||||
}
|
||||
|
||||
PerfMeasurement*
|
||||
ExtractPerfMeasurement(jsval wrapper)
|
||||
{
|
||||
if (JSVAL_IS_PRIMITIVE(wrapper))
|
||||
return 0;
|
||||
|
||||
// This is what JS_GetInstancePrivate does internally. We can't
|
||||
// call JS_anything from here, because we don't have a JSContext.
|
||||
JSObject *obj = JSVAL_TO_OBJECT(wrapper);
|
||||
if (obj->getClass() != js::Valueify(&pm_class))
|
||||
return 0;
|
||||
|
||||
return (PerfMeasurement*) obj->getPrivate();
|
||||
}
|
||||
|
||||
} // namespace JS
|
163
js/src/perf/jsperf.h
Normal file
163
js/src/perf/jsperf.h
Normal file
@ -0,0 +1,163 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* the Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Zack Weinberg <zweinberg@mozilla.com> (original author)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef jsperf_h___
|
||||
#define jsperf_h___
|
||||
|
||||
#include "jsapi.h"
|
||||
|
||||
namespace JS {
|
||||
|
||||
/*
|
||||
* JS::PerfMeasurement is a generic way to access detailed performance
|
||||
* measurement APIs provided by your operating system. The details of
|
||||
* exactly how this works and what can be measured are highly
|
||||
* system-specific, but this interface is (one hopes) implementable
|
||||
* on top of all of them.
|
||||
*
|
||||
* To use this API, create a PerfMeasurement object, passing its
|
||||
* constructor a bitmask indicating which events you are interested
|
||||
* in. Thereafter, Start() zeroes all counters and starts timing;
|
||||
* Stop() stops timing again; and the counters for the events you
|
||||
* requested are available as data values after calling Stop(). The
|
||||
* object may be reused for many measurements.
|
||||
*/
|
||||
class JS_FRIEND_API(PerfMeasurement)
|
||||
{
|
||||
protected:
|
||||
// Implementation-specific data, if any.
|
||||
void* impl;
|
||||
|
||||
public:
|
||||
/*
|
||||
* Events that may be measured. Taken directly from the list of
|
||||
* "generalized hardware performance event types" in the Linux
|
||||
* perf_event API, plus some of the "software events".
|
||||
*/
|
||||
enum EventMask {
|
||||
CPU_CYCLES = 0x00000001,
|
||||
INSTRUCTIONS = 0x00000002,
|
||||
CACHE_REFERENCES = 0x00000004,
|
||||
CACHE_MISSES = 0x00000008,
|
||||
BRANCH_INSTRUCTIONS = 0x00000010,
|
||||
BRANCH_MISSES = 0x00000020,
|
||||
BUS_CYCLES = 0x00000040,
|
||||
PAGE_FAULTS = 0x00000080,
|
||||
MAJOR_PAGE_FAULTS = 0x00000100,
|
||||
CONTEXT_SWITCHES = 0x00000200,
|
||||
CPU_MIGRATIONS = 0x00000400,
|
||||
|
||||
ALL = 0x000007ff,
|
||||
NUM_MEASURABLE_EVENTS = 11
|
||||
};
|
||||
|
||||
/*
|
||||
* Bitmask of events that will be measured when this object is
|
||||
* active (between Start() and Stop()). This may differ from the
|
||||
* bitmask passed to the constructor if the platform does not
|
||||
* support measuring all of the requested events.
|
||||
*/
|
||||
const EventMask eventsMeasured;
|
||||
|
||||
/*
|
||||
* Counters for each measurable event.
|
||||
* Immediately after one of these objects is created, all of the
|
||||
* counters for enabled events will be zero, and all of the
|
||||
* counters for disabled events will be uint64(-1).
|
||||
*/
|
||||
uint64 cpu_cycles;
|
||||
uint64 instructions;
|
||||
uint64 cache_references;
|
||||
uint64 cache_misses;
|
||||
uint64 branch_instructions;
|
||||
uint64 branch_misses;
|
||||
uint64 bus_cycles;
|
||||
uint64 page_faults;
|
||||
uint64 major_page_faults;
|
||||
uint64 context_switches;
|
||||
uint64 cpu_migrations;
|
||||
|
||||
/*
|
||||
* Prepare to measure the indicated set of events. If not all of
|
||||
* the requested events can be measured on the current platform,
|
||||
* then the eventsMeasured bitmask will only include the subset of
|
||||
* |toMeasure| corresponding to the events that can be measured.
|
||||
*/
|
||||
PerfMeasurement(EventMask toMeasure);
|
||||
|
||||
/* Done with this set of measurements, tear down OS-level state. */
|
||||
~PerfMeasurement();
|
||||
|
||||
/* Start a measurement cycle. */
|
||||
void start();
|
||||
|
||||
/*
|
||||
* End a measurement cycle, and for each enabled counter, add the
|
||||
* number of measured events of that type to the appropriate
|
||||
* visible variable.
|
||||
*/
|
||||
void stop();
|
||||
|
||||
/* Reset all enabled counters to zero. */
|
||||
void reset();
|
||||
|
||||
/*
|
||||
* True if this platform supports measuring _something_, i.e. it's
|
||||
* not using the stub implementation.
|
||||
*/
|
||||
static bool canMeasureSomething();
|
||||
};
|
||||
|
||||
/* Inject a Javascript wrapper around the above C++ class into the
|
||||
* Javascript object passed as an argument (this will normally be a
|
||||
* global object). The JS-visible API is identical to the C++ API.
|
||||
*/
|
||||
extern JS_FRIEND_API(JSObject*)
|
||||
RegisterPerfMeasurement(JSContext *cx, JSObject *global);
|
||||
|
||||
/*
|
||||
* Given a jsval which contains an instance of the aforementioned
|
||||
* wrapper class, extract the C++ object. Returns NULL if the
|
||||
* jsval is not an instance of the wrapper.
|
||||
*/
|
||||
extern JS_FRIEND_API(PerfMeasurement*)
|
||||
ExtractPerfMeasurement(jsval wrapper);
|
||||
|
||||
} // namespace JS
|
||||
|
||||
#endif // jsperf_h___
|
342
js/src/perf/pm_linux.cpp
Normal file
342
js/src/perf/pm_linux.cpp
Normal file
@ -0,0 +1,342 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* the Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Zack Weinberg <zweinberg@mozilla.com> (original author)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "jsperf.h"
|
||||
#include "jsutil.h"
|
||||
|
||||
/* This variant of nsIPerfMeasurement uses the perf_event interface
|
||||
* added in Linux 2.6.31. We key compilation of this file off the
|
||||
* existence of <linux/perf_event.h>.
|
||||
*/
|
||||
|
||||
#include <linux/perf_event.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
// As of July 2010, this system call has not been added to the
|
||||
// C library, so we have to provide our own wrapper function.
|
||||
// If this code runs on a kernel that does not implement the
|
||||
// system call (2.6.30 or older) nothing unpredictable will
|
||||
// happen - it will just always fail and return -1.
|
||||
static int
|
||||
sys_perf_event_open(struct perf_event_attr *attr, pid_t pid, int cpu,
|
||||
int group_fd, unsigned long flags)
|
||||
{
|
||||
return syscall(__NR_perf_event_open, attr, pid, cpu, group_fd, flags);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
using JS::PerfMeasurement;
|
||||
typedef PerfMeasurement::EventMask EventMask;
|
||||
|
||||
// Additional state required by this implementation.
|
||||
struct Impl
|
||||
{
|
||||
// Each active counter corresponds to an open file descriptor.
|
||||
int f_cpu_cycles;
|
||||
int f_instructions;
|
||||
int f_cache_references;
|
||||
int f_cache_misses;
|
||||
int f_branch_instructions;
|
||||
int f_branch_misses;
|
||||
int f_bus_cycles;
|
||||
int f_page_faults;
|
||||
int f_major_page_faults;
|
||||
int f_context_switches;
|
||||
int f_cpu_migrations;
|
||||
|
||||
// Counter group leader, for Start and Stop.
|
||||
int group_leader;
|
||||
|
||||
// Whether counters are running.
|
||||
bool running;
|
||||
|
||||
Impl();
|
||||
~Impl();
|
||||
|
||||
EventMask init(EventMask toMeasure);
|
||||
void start();
|
||||
void stop(PerfMeasurement* counters);
|
||||
};
|
||||
|
||||
// Mapping from our event bitmask to codes passed into the kernel, and
|
||||
// to fields in the PerfMeasurement and PerfMeasurement::impl structures.
|
||||
static const struct
|
||||
{
|
||||
EventMask bit;
|
||||
uint32 type;
|
||||
uint32 config;
|
||||
uint64 PerfMeasurement::* counter;
|
||||
int Impl::* fd;
|
||||
} kSlots[PerfMeasurement::NUM_MEASURABLE_EVENTS] = {
|
||||
#define HW(mask, constant, fieldname) \
|
||||
{ PerfMeasurement::mask, PERF_TYPE_HARDWARE, PERF_COUNT_HW_##constant, \
|
||||
&PerfMeasurement::fieldname, &Impl::f_##fieldname }
|
||||
#define SW(mask, constant, fieldname) \
|
||||
{ PerfMeasurement::mask, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_##constant, \
|
||||
&PerfMeasurement::fieldname, &Impl::f_##fieldname }
|
||||
|
||||
HW(CPU_CYCLES, CPU_CYCLES, cpu_cycles),
|
||||
HW(INSTRUCTIONS, INSTRUCTIONS, instructions),
|
||||
HW(CACHE_REFERENCES, CACHE_REFERENCES, cache_references),
|
||||
HW(CACHE_MISSES, CACHE_MISSES, cache_misses),
|
||||
HW(BRANCH_INSTRUCTIONS, BRANCH_INSTRUCTIONS, branch_instructions),
|
||||
HW(BRANCH_MISSES, BRANCH_MISSES, branch_misses),
|
||||
HW(BUS_CYCLES, BUS_CYCLES, bus_cycles),
|
||||
SW(PAGE_FAULTS, PAGE_FAULTS, page_faults),
|
||||
SW(MAJOR_PAGE_FAULTS, PAGE_FAULTS_MAJ, major_page_faults),
|
||||
SW(CONTEXT_SWITCHES, CONTEXT_SWITCHES, context_switches),
|
||||
SW(CPU_MIGRATIONS, CPU_MIGRATIONS, cpu_migrations),
|
||||
|
||||
#undef HW
|
||||
#undef SW
|
||||
};
|
||||
|
||||
Impl::Impl()
|
||||
: f_cpu_cycles(-1),
|
||||
f_instructions(-1),
|
||||
f_cache_references(-1),
|
||||
f_cache_misses(-1),
|
||||
f_branch_instructions(-1),
|
||||
f_branch_misses(-1),
|
||||
f_bus_cycles(-1),
|
||||
f_page_faults(-1),
|
||||
f_major_page_faults(-1),
|
||||
f_context_switches(-1),
|
||||
f_cpu_migrations(-1),
|
||||
group_leader(-1),
|
||||
running(false)
|
||||
{
|
||||
}
|
||||
|
||||
Impl::~Impl()
|
||||
{
|
||||
// Close all active counter descriptors. Take care to do the group
|
||||
// leader last (this may not be necessary, but it's unclear what
|
||||
// happens if you close the group leader out from under a group).
|
||||
for (int i = 0; i < PerfMeasurement::NUM_MEASURABLE_EVENTS; i++) {
|
||||
int fd = this->*(kSlots[i].fd);
|
||||
if (fd != -1 && fd != group_leader)
|
||||
close(fd);
|
||||
}
|
||||
|
||||
if (group_leader != -1)
|
||||
close(group_leader);
|
||||
}
|
||||
|
||||
EventMask
|
||||
Impl::init(EventMask toMeasure)
|
||||
{
|
||||
JS_ASSERT(group_leader == -1);
|
||||
if (!toMeasure)
|
||||
return EventMask(0);
|
||||
|
||||
EventMask measured = EventMask(0);
|
||||
struct perf_event_attr attr;
|
||||
for (int i = 0; i < PerfMeasurement::NUM_MEASURABLE_EVENTS; i++) {
|
||||
if (!(toMeasure & kSlots[i].bit))
|
||||
continue;
|
||||
|
||||
memset(&attr, 0, sizeof(attr));
|
||||
attr.size = sizeof(attr);
|
||||
|
||||
// Set the type and config fields to indicate the counter we
|
||||
// want to enable. We want read format 0, and we're not using
|
||||
// sampling, so leave those fields unset.
|
||||
attr.type = kSlots[i].type;
|
||||
attr.config = kSlots[i].config;
|
||||
|
||||
// If this will be the group leader it should start off
|
||||
// disabled. Otherwise it should start off enabled (but blocked
|
||||
// on the group leader).
|
||||
if (group_leader == -1)
|
||||
attr.disabled = 1;
|
||||
|
||||
// The rest of the bit fields are really poorly documented.
|
||||
// For instance, I have *no idea* whether we should be setting
|
||||
// the inherit, inherit_stat, or task flags. I'm pretty sure
|
||||
// we do want to set mmap and comm, and not any of the ones I
|
||||
// haven't mentioned.
|
||||
attr.mmap = 1;
|
||||
attr.comm = 1;
|
||||
|
||||
int fd = sys_perf_event_open(&attr,
|
||||
0 /* trace self */,
|
||||
-1 /* on any cpu */,
|
||||
group_leader,
|
||||
0 /* no flags presently defined */);
|
||||
if (fd == -1)
|
||||
continue;
|
||||
|
||||
measured = EventMask(measured | kSlots[i].bit);
|
||||
this->*(kSlots[i].fd) = fd;
|
||||
if (group_leader == -1)
|
||||
group_leader = fd;
|
||||
}
|
||||
return measured;
|
||||
}
|
||||
|
||||
void
|
||||
Impl::start()
|
||||
{
|
||||
if (running || group_leader == -1)
|
||||
return;
|
||||
|
||||
running = true;
|
||||
ioctl(group_leader, PERF_EVENT_IOC_ENABLE, 0);
|
||||
}
|
||||
|
||||
void
|
||||
Impl::stop(PerfMeasurement* counters)
|
||||
{
|
||||
// This scratch buffer is to ensure that we have read all the
|
||||
// available data, even if that's more than we expect.
|
||||
unsigned char buf[1024];
|
||||
|
||||
if (!running || group_leader == -1)
|
||||
return;
|
||||
|
||||
ioctl(group_leader, PERF_EVENT_IOC_DISABLE, 0);
|
||||
running = false;
|
||||
|
||||
// read out and reset all the counter values
|
||||
for (int i = 0; i < PerfMeasurement::NUM_MEASURABLE_EVENTS; i++) {
|
||||
int fd = this->*(kSlots[i].fd);
|
||||
if (fd == -1)
|
||||
continue;
|
||||
|
||||
if (read(fd, buf, sizeof(buf)) == sizeof(uint64)) {
|
||||
uint64 cur;
|
||||
memcpy(&cur, buf, sizeof(uint64));
|
||||
counters->*(kSlots[i].counter) += cur;
|
||||
}
|
||||
|
||||
// Reset the counter regardless of whether the read did what
|
||||
// we expected.
|
||||
ioctl(fd, PERF_EVENT_IOC_RESET, 0);
|
||||
}
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
namespace JS {
|
||||
|
||||
#define initCtr(flag) ((eventsMeasured & flag) ? 0 : -1)
|
||||
|
||||
PerfMeasurement::PerfMeasurement(PerfMeasurement::EventMask toMeasure)
|
||||
: impl(new Impl),
|
||||
eventsMeasured(impl ? static_cast<Impl*>(impl)->init(toMeasure)
|
||||
: EventMask(0)),
|
||||
cpu_cycles(initCtr(CPU_CYCLES)),
|
||||
instructions(initCtr(INSTRUCTIONS)),
|
||||
cache_references(initCtr(CACHE_REFERENCES)),
|
||||
cache_misses(initCtr(CACHE_MISSES)),
|
||||
branch_instructions(initCtr(BRANCH_INSTRUCTIONS)),
|
||||
branch_misses(initCtr(BRANCH_MISSES)),
|
||||
bus_cycles(initCtr(BUS_CYCLES)),
|
||||
page_faults(initCtr(PAGE_FAULTS)),
|
||||
major_page_faults(initCtr(MAJOR_PAGE_FAULTS)),
|
||||
context_switches(initCtr(CONTEXT_SWITCHES)),
|
||||
cpu_migrations(initCtr(CPU_MIGRATIONS))
|
||||
{
|
||||
}
|
||||
|
||||
#undef initCtr
|
||||
|
||||
PerfMeasurement::~PerfMeasurement()
|
||||
{
|
||||
delete static_cast<Impl*>(impl);
|
||||
}
|
||||
|
||||
void
|
||||
PerfMeasurement::start()
|
||||
{
|
||||
if (impl)
|
||||
static_cast<Impl*>(impl)->start();
|
||||
}
|
||||
|
||||
void
|
||||
PerfMeasurement::stop()
|
||||
{
|
||||
if (impl)
|
||||
static_cast<Impl*>(impl)->stop(this);
|
||||
}
|
||||
|
||||
void
|
||||
PerfMeasurement::reset()
|
||||
{
|
||||
for (int i = 0; i < NUM_MEASURABLE_EVENTS; i++) {
|
||||
if (eventsMeasured & kSlots[i].bit)
|
||||
this->*(kSlots[i].counter) = 0;
|
||||
else
|
||||
this->*(kSlots[i].counter) = -1;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
PerfMeasurement::canMeasureSomething()
|
||||
{
|
||||
// Find out if the kernel implements the performance measurement
|
||||
// API. If it doesn't, syscall(__NR_perf_event_open, ...) is
|
||||
// guaranteed to return -1 and set errno to ENOSYS.
|
||||
//
|
||||
// We set up input parameters that should provoke an EINVAL error
|
||||
// from a kernel that does implement perf_event_open, but we can't
|
||||
// be sure it will (newer kernels might add more event types), so
|
||||
// we have to take care to close any valid fd it might return.
|
||||
|
||||
struct perf_event_attr attr;
|
||||
memset(&attr, 0, sizeof(attr));
|
||||
attr.size = sizeof(attr);
|
||||
attr.type = PERF_TYPE_MAX;
|
||||
|
||||
int fd = sys_perf_event_open(&attr, 0, -1, -1, 0);
|
||||
if (fd >= 0) {
|
||||
close(fd);
|
||||
return true;
|
||||
} else {
|
||||
return errno != ENOSYS;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace JS
|
96
js/src/perf/pm_stub.cpp
Normal file
96
js/src/perf/pm_stub.cpp
Normal file
@ -0,0 +1,96 @@
|
||||
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* the Mozilla Foundation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Zack Weinberg <zweinberg@mozilla.com> (original author)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "jsperf.h"
|
||||
|
||||
namespace JS {
|
||||
|
||||
PerfMeasurement::PerfMeasurement(PerfMeasurement::EventMask)
|
||||
: impl(0),
|
||||
eventsMeasured(EventMask(0)),
|
||||
cpu_cycles(-1),
|
||||
instructions(-1),
|
||||
cache_references(-1),
|
||||
cache_misses(-1),
|
||||
branch_instructions(-1),
|
||||
branch_misses(-1),
|
||||
bus_cycles(-1),
|
||||
page_faults(-1),
|
||||
major_page_faults(-1),
|
||||
context_switches(-1),
|
||||
cpu_migrations(-1)
|
||||
{
|
||||
}
|
||||
|
||||
PerfMeasurement::~PerfMeasurement()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
PerfMeasurement::start()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
PerfMeasurement::stop()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
PerfMeasurement::reset()
|
||||
{
|
||||
cpu_cycles = -1;
|
||||
instructions = -1;
|
||||
cache_references = -1;
|
||||
cache_misses = -1;
|
||||
branch_instructions = -1;
|
||||
branch_misses = -1;
|
||||
bus_cycles = -1;
|
||||
page_faults = -1;
|
||||
major_page_faults = -1;
|
||||
context_switches = -1;
|
||||
cpu_migrations = -1;
|
||||
}
|
||||
|
||||
bool
|
||||
PerfMeasurement::canMeasureSomething()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace JS
|
@ -75,6 +75,7 @@
|
||||
#include "jsscript.h"
|
||||
#include "jstracer.h"
|
||||
#include "jsxml.h"
|
||||
#include "jsperf.h"
|
||||
|
||||
#include "prmjtime.h"
|
||||
|
||||
@ -4880,6 +4881,8 @@ NewGlobalObject(JSContext *cx, JSAutoCrossCompartmentCall &call)
|
||||
if (!JS_InitCTypesClass(cx, glob))
|
||||
return NULL;
|
||||
#endif
|
||||
if (!JS::RegisterPerfMeasurement(cx, glob))
|
||||
return NULL;
|
||||
if (!JS_DefineFunctions(cx, glob, shell_functions))
|
||||
return NULL;
|
||||
|
||||
|
34
js/src/trace-test/tests/basic/perf-smoketest.js
Normal file
34
js/src/trace-test/tests/basic/perf-smoketest.js
Normal file
@ -0,0 +1,34 @@
|
||||
function spin_loop()
|
||||
{
|
||||
for (let i = 0; i < 10000; i++) ;
|
||||
}
|
||||
|
||||
function check_timing(label, count) {
|
||||
if (count == -1) {
|
||||
print("TEST-UNEXPECTED-FAIL | TestPerf | " + label);
|
||||
throwError();
|
||||
} else {
|
||||
print("TEST-PASS | TestPerf | " + label + " = " + count);
|
||||
}
|
||||
}
|
||||
|
||||
var pm = new PerfMeasurement(PerfMeasurement.ALL);
|
||||
if (pm.eventsMeasured == 0) {
|
||||
print("TEST-KNOWN-FAIL | perf-smoketest | stub, skipping test");
|
||||
} else {
|
||||
pm.start();
|
||||
spin_loop();
|
||||
pm.stop();
|
||||
|
||||
check_timing("cpu_cycles", pm.cpu_cycles);
|
||||
check_timing("instructions", pm.instructions);
|
||||
check_timing("cache_references", pm.cache_references);
|
||||
check_timing("cache_misses", pm.cache_misses);
|
||||
check_timing("branch_instructions", pm.branch_instructions);
|
||||
check_timing("branch_misses", pm.branch_misses);
|
||||
check_timing("bus_cycles", pm.bus_cycles);
|
||||
check_timing("page_faults", pm.page_faults);
|
||||
check_timing("major_page_faults", pm.major_page_faults);
|
||||
check_timing("context_switches", pm.context_switches);
|
||||
check_timing("cpu_migrations", pm.cpu_migrations);
|
||||
}
|
@ -62,6 +62,7 @@ PARALLEL_DIRS += \
|
||||
microformats \
|
||||
parentalcontrols \
|
||||
passwordmgr \
|
||||
perf \
|
||||
places \
|
||||
prompts \
|
||||
startup \
|
||||
|
@ -57,7 +57,7 @@ EXPORT_LIBRARY = 1
|
||||
IS_COMPONENT = 1
|
||||
|
||||
CPPSRCS = \
|
||||
Module.cpp \
|
||||
ctypes.cpp \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_DSO_LDOPTS += \
|
||||
|
@ -37,7 +37,7 @@
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "Module.h"
|
||||
#include "ctypes.h"
|
||||
#include "jsapi.h"
|
||||
#include "mozilla/ModuleUtils.h"
|
||||
#include "nsMemory.h"
|
@ -36,8 +36,8 @@
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef MODULE_H
|
||||
#define MODULE_H
|
||||
#ifndef COMPONENTS_CTYPES_H
|
||||
#define COMPONENTS_CTYPES_H
|
||||
|
||||
#include "nsIXPCScriptable.h"
|
||||
|
81
toolkit/components/perf/Makefile.in
Normal file
81
toolkit/components/perf/Makefile.in
Normal file
@ -0,0 +1,81 @@
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
# Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
#
|
||||
# The contents of this file are subject to the Mozilla Public License Version
|
||||
# 1.1 (the "License"); you may not use this file except in compliance with
|
||||
# the License. You may obtain a copy of the License at
|
||||
# http://www.mozilla.org/MPL/
|
||||
#
|
||||
# Software distributed under the License is distributed on an "AS IS" basis,
|
||||
# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
# for the specific language governing rights and limitations under the
|
||||
# License.
|
||||
#
|
||||
# The Original Code is mozilla.org code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# The Mozilla Foundation <http://www.mozilla.org/>.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2010
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Zack Weinberg <zweinberg@mozilla.com> (original author)
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
# in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
# use your version of this file under the terms of the MPL, indicate your
|
||||
# decision by deleting the provisions above and replace them with the notice
|
||||
# and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the MPL, the GPL or the LGPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
|
||||
DEPTH = ../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = perf
|
||||
MODULE_NAME = perf
|
||||
GRE_MODULE = 1
|
||||
|
||||
EXTRA_JS_MODULES = \
|
||||
PerfMeasurement.jsm \
|
||||
$(NULL)
|
||||
|
||||
LIBRARY_NAME = jsperf
|
||||
LIBXUL_LIBRARY = 1
|
||||
EXPORT_LIBRARY = 1
|
||||
IS_COMPONENT = 1
|
||||
|
||||
CPPSRCS = \
|
||||
PerfMeasurement.cpp \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_DSO_LDOPTS += \
|
||||
$(MOZ_COMPONENT_LIBS) \
|
||||
$(MOZ_JS_LIBS) \
|
||||
$(NULL)
|
||||
|
||||
ifdef ENABLE_TESTS
|
||||
_CHROME_TEST_FILES = \
|
||||
test_pm.xul \
|
||||
$(NULL)
|
||||
|
||||
chrometestdir = \
|
||||
$(DEPTH)/_tests/testing/mochitest/chrome/toolkit/components/$(MODULE)
|
||||
endif
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
ifdef ENABLE_TESTS
|
||||
libs:: $(_CHROME_TEST_FILES)
|
||||
$(INSTALL) $(foreach f,$^,"$f") $(chrometestdir)
|
||||
endif
|
149
toolkit/components/perf/PerfMeasurement.cpp
Normal file
149
toolkit/components/perf/PerfMeasurement.cpp
Normal file
@ -0,0 +1,149 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* The Mozilla Foundation <http://www.mozilla.org/>.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Zack Weinberg <zweinberg@mozilla.com> (original author)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#include "PerfMeasurement.h"
|
||||
#include "jsperf.h"
|
||||
#include "mozilla/ModuleUtils.h"
|
||||
#include "nsMemory.h"
|
||||
|
||||
#define JSPERF_CONTRACTID \
|
||||
"@mozilla.org/jsperf;1"
|
||||
|
||||
#define JSPERF_CID \
|
||||
{ 0x421c38e6, 0xaee0, 0x4509, \
|
||||
{ 0xa0, 0x25, 0x13, 0x0f, 0x43, 0x78, 0x03, 0x5a } }
|
||||
|
||||
namespace mozilla {
|
||||
namespace jsperf {
|
||||
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(Module)
|
||||
|
||||
NS_IMPL_ISUPPORTS1(Module, nsIXPCScriptable)
|
||||
|
||||
Module::Module()
|
||||
{
|
||||
}
|
||||
|
||||
Module::~Module()
|
||||
{
|
||||
}
|
||||
|
||||
#define XPC_MAP_CLASSNAME Module
|
||||
#define XPC_MAP_QUOTED_CLASSNAME "Module"
|
||||
#define XPC_MAP_WANT_CALL
|
||||
#define XPC_MAP_FLAGS nsIXPCScriptable::WANT_CALL
|
||||
#include "xpc_map_end.h"
|
||||
|
||||
static JSBool
|
||||
SealObjectAndPrototype(JSContext* cx, JSObject* parent, const char* name)
|
||||
{
|
||||
jsval prop;
|
||||
if (!JS_GetProperty(cx, parent, name, &prop))
|
||||
return false;
|
||||
|
||||
JSObject* obj = JSVAL_TO_OBJECT(prop);
|
||||
if (!JS_GetProperty(cx, obj, "prototype", &prop))
|
||||
return false;
|
||||
|
||||
JSObject* prototype = JSVAL_TO_OBJECT(prop);
|
||||
return JS_SealObject(cx, obj, JS_FALSE) &&
|
||||
JS_SealObject(cx, prototype, JS_FALSE);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
InitAndSealPerfMeasurementClass(JSContext* cx, JSObject* global)
|
||||
{
|
||||
// Init the PerfMeasurement class
|
||||
if (!JS::RegisterPerfMeasurement(cx, global))
|
||||
return false;
|
||||
|
||||
// Seal up Object, Function, and Array and their prototypes. (This single
|
||||
// object instance is shared amongst everyone who imports the jsperf module.)
|
||||
if (!SealObjectAndPrototype(cx, global, "Object") ||
|
||||
!SealObjectAndPrototype(cx, global, "Function") ||
|
||||
!SealObjectAndPrototype(cx, global, "Array"))
|
||||
return false;
|
||||
|
||||
// Finally, seal the global object, for good measure. (But not recursively;
|
||||
// this breaks things.)
|
||||
return JS_SealObject(cx, global, JS_FALSE);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
Module::Call(nsIXPConnectWrappedNative* wrapper,
|
||||
JSContext* cx,
|
||||
JSObject* obj,
|
||||
PRUint32 argc,
|
||||
jsval* argv,
|
||||
jsval* vp,
|
||||
PRBool* _retval)
|
||||
{
|
||||
JSObject* scope = JS_GetScopeChain(cx);
|
||||
if (!scope)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
JSObject* global = JS_GetGlobalForObject(cx, scope);
|
||||
if (!global)
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
*_retval = InitAndSealPerfMeasurementClass(cx, global);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
NS_DEFINE_NAMED_CID(JSPERF_CID);
|
||||
|
||||
static const mozilla::Module::CIDEntry kPerfCIDs[] = {
|
||||
{ &kJSPERF_CID, false, NULL, mozilla::jsperf::ModuleConstructor },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static const mozilla::Module::ContractIDEntry kPerfContracts[] = {
|
||||
{ JSPERF_CONTRACTID, &kJSPERF_CID },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
static const mozilla::Module kPerfModule = {
|
||||
mozilla::Module::kVersion,
|
||||
kPerfCIDs,
|
||||
kPerfContracts
|
||||
};
|
||||
|
||||
NSMODULE_DEFN(jsperf) = &kPerfModule;
|
62
toolkit/components/perf/PerfMeasurement.h
Normal file
62
toolkit/components/perf/PerfMeasurement.h
Normal file
@ -0,0 +1,62 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* The Mozilla Foundation <http://www.mozilla.org/>.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Zack Weinberg <zweinberg@mozilla.com> (original author)
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
#ifndef COMPONENTS_PERFMEASUREMENT_H
|
||||
#define COMPONENTS_PERFMEASUREMENT_H
|
||||
|
||||
#include "nsIXPCScriptable.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace jsperf {
|
||||
|
||||
class Module : public nsIXPCScriptable
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIXPCSCRIPTABLE
|
||||
|
||||
Module();
|
||||
|
||||
private:
|
||||
~Module();
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
52
toolkit/components/perf/PerfMeasurement.jsm
Normal file
52
toolkit/components/perf/PerfMeasurement.jsm
Normal file
@ -0,0 +1,52 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
|
||||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is mozilla.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* The Mozilla Foundation <http://www.mozilla.org/>.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2010
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Zack Weinberg <zweinberg@mozilla.com>
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the terms of
|
||||
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
* in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
* of those above. If you wish to allow use of your version of this file only
|
||||
* under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
* use your version of this file under the terms of the MPL, indicate your
|
||||
* decision by deleting the provisions above and replace them with the notice
|
||||
* and other provisions required by the GPL or the LGPL. If you do not delete
|
||||
* the provisions above, a recipient may use your version of this file under
|
||||
* the terms of any one of the MPL, the GPL or the LGPL.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
let EXPORTED_SYMBOLS = [ "PerfMeasurement" ];
|
||||
|
||||
/*
|
||||
* This is the js module for jsperf. Import it like so:
|
||||
* Components.utils.import("resource://gre/modules/PerfMeasurement.jsm");
|
||||
*
|
||||
* This will create a 'PerfMeasurement' class. Instances of this class can
|
||||
* be used to benchmark browser operations.
|
||||
*
|
||||
* For documentation on the API, see js/src/perf/jsperf.h.
|
||||
*
|
||||
*/
|
||||
|
||||
Components.classes["@mozilla.org/jsperf;1"].createInstance()();
|
88
toolkit/components/perf/test_pm.xul
Normal file
88
toolkit/components/perf/test_pm.xul
Normal file
@ -0,0 +1,88 @@
|
||||
<?xml version="1.0"?>
|
||||
<!-- ***** BEGIN LICENSE BLOCK *****
|
||||
- Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
||||
-
|
||||
- The contents of this file are subject to the Mozilla Public License Version
|
||||
- 1.1 (the "License"); you may not use this file except in compliance with
|
||||
- the License. You may obtain a copy of the License at
|
||||
- http://www.mozilla.org/MPL/
|
||||
-
|
||||
- Software distributed under the License is distributed on an "AS IS" basis,
|
||||
- WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
- for the specific language governing rights and limitations under the
|
||||
- License.
|
||||
-
|
||||
- The Original Code is mozilla.org code.
|
||||
-
|
||||
- The Initial Developer of the Original Code is
|
||||
- The Mozilla Foundation.
|
||||
- Portions created by the Initial Developer are Copyright (C) 2010
|
||||
- the Initial Developer. All Rights Reserved.
|
||||
-
|
||||
- Contributor(s):
|
||||
- Zack Weinberg <zweinberg@mozilla.com>
|
||||
-
|
||||
- Alternatively, the contents of this file may be used under the terms of
|
||||
- either the GNU General Public License Version 2 or later (the "GPL"), or
|
||||
- the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
||||
- in which case the provisions of the GPL or the LGPL are applicable instead
|
||||
- of those above. If you wish to allow use of your version of this file only
|
||||
- under the terms of either the GPL or the LGPL, and not to allow others to
|
||||
- use your version of this file under the terms of the MPL, indicate your
|
||||
- decision by deleting the provisions above and replace them with the notice
|
||||
- and other provisions required by the LGPL or the GPL. If you do not delete
|
||||
- the provisions above, a recipient may use your version of this file under
|
||||
- the terms of any one of the MPL, the GPL or the LGPL.
|
||||
-
|
||||
- ***** END LICENSE BLOCK ***** -->
|
||||
|
||||
<window title="Performance measurement tests"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
onload="test()">
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/MochiKit/packed.js"/>
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
|
||||
|
||||
<script type="application/javascript"><![CDATA[
|
||||
function test()
|
||||
{
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
Components.utils.import("resource://gre/modules/PerfMeasurement.jsm");
|
||||
let pm = new PerfMeasurement(PerfMeasurement.ALL);
|
||||
if (pm.eventsMeasured == 0) {
|
||||
todo(false, "stub, skipping test");
|
||||
} else {
|
||||
is(pm.eventsMeasured, PerfMeasurement.ALL, "all events measurable");
|
||||
|
||||
pm.start();
|
||||
for (let i = 0; i < 10000; i++) ;
|
||||
pm.stop();
|
||||
|
||||
isnot(pm.cpu_cycles, -1, "cpu_cycles");
|
||||
isnot(pm.instructions, -1, "instructions");
|
||||
isnot(pm.cache_references, -1, "cache_references");
|
||||
isnot(pm.cache_misses, -1, "cache_misses");
|
||||
isnot(pm.branch_instructions, -1, "branch_instructions");
|
||||
isnot(pm.branch_misses, -1, "branch_misses");
|
||||
isnot(pm.bus_cycles, -1, "bus_cycles");
|
||||
isnot(pm.page_faults, -1, "page_faults");
|
||||
isnot(pm.major_page_faults, -1, "major_page_faults");
|
||||
isnot(pm.context_switches, -1, "context_switches");
|
||||
isnot(pm.cpu_migrations, -1, "cpu_migrations");
|
||||
}
|
||||
SimpleTest.finish();
|
||||
}
|
||||
]]></script>
|
||||
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display:none;"></div>
|
||||
<pre id="test"></pre>
|
||||
</body>
|
||||
<label id="test-result"/>
|
||||
</window>
|
@ -166,6 +166,8 @@ COMPONENT_LIBS += \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
COMPONENT_LIBS += jsperf
|
||||
|
||||
ifdef MOZ_PLUGINS
|
||||
DEFINES += -DMOZ_PLUGINS
|
||||
COMPONENT_LIBS += \
|
||||
|
@ -278,6 +278,7 @@
|
||||
OSXPROXY_MODULE \
|
||||
WINDOWSPROXY_MODULE \
|
||||
JSCTYPES_MODULE \
|
||||
MODULE(jsperf) \
|
||||
/* end of list */
|
||||
|
||||
#define MODULE(_name) \
|
||||
|
Loading…
Reference in New Issue
Block a user