author | Zack Weinberg <zweinberg@mozilla.com> |
Fri, 30 Jul 2010 12:17:56 -0700 | |
changeset 48637 | 0406c26819576bc40fdae527a99c24ef9fdf497c |
parent 48636 | d1b8dd1632bf2cd5bdc2b29bfb965ee8ae17007b |
child 48638 | af011e92ad0b6a80ea782c427e9ecef92ceb73fb |
push id | unknown |
push user | unknown |
push date | unknown |
reviewers | cjones, waldo, mitch |
bugs | 568863 |
milestone | 2.0b3pre |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/js/src/Makefile.in +++ b/js/src/Makefile.in @@ -317,16 +317,29 @@ endif # JS_HAS_CTYPES ifdef HAVE_DTRACE INSTALLED_HEADERS += \ jsdtracef.h \ $(CURDIR)/javascript-trace.h \ $(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 EXPORTS = $(INSTALLED_HEADERS) DASH_R = -r
--- a/js/src/config/autoconf.mk.in +++ b/js/src/config/autoconf.mk.in @@ -333,8 +333,9 @@ UNIVERSAL_BINARY= @UNIVERSAL_BINARY@ HAVE_DTRACE= @HAVE_DTRACE@ VISIBILITY_FLAGS = @VISIBILITY_FLAGS@ 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@
--- a/js/src/configure.in +++ b/js/src/configure.in @@ -3017,16 +3017,20 @@ AC_SUBST(HAVE_DTRACE) case $target in *-aix4.3*|*-aix5*) ;; *) AC_CHECK_HEADERS(sys/cdefs.h) ;; 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 *-hpux11.*) ;; *) AC_CHECK_LIB(c_r, gethostbyname_r) ;;
new file mode 100644 --- /dev/null +++ b/js/src/perf/jsperf.cpp @@ -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
new file mode 100644 --- /dev/null +++ b/js/src/perf/jsperf.h @@ -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___
new file mode 100644 --- /dev/null +++ b/js/src/perf/pm_linux.cpp @@ -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
new file mode 100644 --- /dev/null +++ b/js/src/perf/pm_stub.cpp @@ -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
--- a/js/src/shell/js.cpp +++ b/js/src/shell/js.cpp @@ -70,16 +70,17 @@ #include "jslock.h" #include "jsnum.h" #include "jsobj.h" #include "jsparse.h" #include "jsscope.h" #include "jsscript.h" #include "jstracer.h" #include "jsxml.h" +#include "jsperf.h" #include "prmjtime.h" #ifdef JSDEBUGGER #include "jsdebug.h" #ifdef JSDEBUGGER_JAVA_UI #include "jsdjava.h" #endif /* JSDEBUGGER_JAVA_UI */ @@ -4875,16 +4876,18 @@ NewGlobalObject(JSContext *cx, JSAutoCro #else if (!JS_InitStandardClasses(cx, glob)) return NULL; #endif #ifdef JS_HAS_CTYPES if (!JS_InitCTypesClass(cx, glob)) return NULL; #endif + if (!JS::RegisterPerfMeasurement(cx, glob)) + return NULL; if (!JS_DefineFunctions(cx, glob, shell_functions)) return NULL; JSObject *it = JS_DefineObject(cx, glob, "it", &its_class, NULL, 0); if (!it) return NULL; if (!JS_DefineProperties(cx, it, its_props)) return NULL;
new file mode 100644 --- /dev/null +++ b/js/src/trace-test/tests/basic/perf-smoketest.js @@ -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); +}
--- a/toolkit/components/Makefile.in +++ b/toolkit/components/Makefile.in @@ -57,16 +57,17 @@ PARALLEL_DIRS += \ contentprefs \ cookie \ exthelper \ filepicker \ find \ microformats \ parentalcontrols \ passwordmgr \ + perf \ places \ prompts \ startup \ statusfilter \ typeaheadfind \ urlformatter \ viewconfig \ $(NULL)
--- a/toolkit/components/ctypes/Makefile.in +++ b/toolkit/components/ctypes/Makefile.in @@ -52,17 +52,17 @@ EXTRA_JS_MODULES = \ $(NULL) LIBRARY_NAME = jsctypes LIBXUL_LIBRARY = 1 EXPORT_LIBRARY = 1 IS_COMPONENT = 1 CPPSRCS = \ - Module.cpp \ + ctypes.cpp \ $(NULL) EXTRA_DSO_LDOPTS += \ $(MOZ_COMPONENT_LIBS) \ $(MOZ_JS_LIBS) \ $(NULL) ifdef ENABLE_TESTS
rename from toolkit/components/ctypes/Module.cpp rename to toolkit/components/ctypes/ctypes.cpp --- a/toolkit/components/ctypes/Module.cpp +++ b/toolkit/components/ctypes/ctypes.cpp @@ -32,17 +32,17 @@ * 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 "Module.h" +#include "ctypes.h" #include "jsapi.h" #include "mozilla/ModuleUtils.h" #include "nsMemory.h" #define JSCTYPES_CONTRACTID \ "@mozilla.org/jsctypes;1" #define JSCTYPES_CID \
rename from toolkit/components/ctypes/Module.h rename to toolkit/components/ctypes/ctypes.h --- a/toolkit/components/ctypes/Module.h +++ b/toolkit/components/ctypes/ctypes.h @@ -31,18 +31,18 @@ * 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 MODULE_H -#define MODULE_H +#ifndef COMPONENTS_CTYPES_H +#define COMPONENTS_CTYPES_H #include "nsIXPCScriptable.h" namespace mozilla { namespace ctypes { class Module : public nsIXPCScriptable {
new file mode 100644 --- /dev/null +++ b/toolkit/components/perf/Makefile.in @@ -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
new file mode 100644 --- /dev/null +++ b/toolkit/components/perf/PerfMeasurement.cpp @@ -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;
new file mode 100644 --- /dev/null +++ b/toolkit/components/perf/PerfMeasurement.h @@ -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
new file mode 100644 --- /dev/null +++ b/toolkit/components/perf/PerfMeasurement.jsm @@ -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()();
new file mode 100644 --- /dev/null +++ b/toolkit/components/perf/test_pm.xul @@ -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>
--- a/toolkit/library/libxul-config.mk +++ b/toolkit/library/libxul-config.mk @@ -161,16 +161,18 @@ COMPONENT_LIBS += jetpack_s endif ifdef BUILD_CTYPES COMPONENT_LIBS += \ jsctypes \ $(NULL) endif +COMPONENT_LIBS += jsperf + ifdef MOZ_PLUGINS DEFINES += -DMOZ_PLUGINS COMPONENT_LIBS += \ gkplugin \ $(NULL) endif ifdef MOZ_XUL
--- a/toolkit/library/nsStaticXULComponents.cpp +++ b/toolkit/library/nsStaticXULComponents.cpp @@ -273,16 +273,17 @@ MODULE(NSS) \ SYSTEMPREF_MODULES \ SPELLCHECK_MODULE \ LAYOUT_DEBUG_MODULE \ UNIXPROXY_MODULE \ OSXPROXY_MODULE \ WINDOWSPROXY_MODULE \ JSCTYPES_MODULE \ + MODULE(jsperf) \ /* end of list */ #define MODULE(_name) \ NSMODULE_DECL(_name); XUL_MODULES #undef MODULE