diff options
Diffstat (limited to 'js/src/perf/jsperf.cpp')
-rw-r--r-- | js/src/perf/jsperf.cpp | 295 |
1 files changed, 295 insertions, 0 deletions
diff --git a/js/src/perf/jsperf.cpp b/js/src/perf/jsperf.cpp new file mode 100644 index 0000000..3c99722 --- /dev/null +++ b/js/src/perf/jsperf.cpp @@ -0,0 +1,295 @@ +/* -*- 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, uintN argc, jsval* vp) +{ + uint32 mask; + if (!JS_ConvertArguments(cx, argc, JS_ARGV(cx, vp), "u", &mask)) + return JS_FALSE; + + JSObject *obj = JS_NewObjectForConstructor(cx, vp); + if (!obj) + return JS_FALSE; + + if (!JS_FreezeObject(cx, obj)) + return JS_FALSE; + + PerfMeasurement* p = js_new<PerfMeasurement>(PerfMeasurement::EventMask(mask)); + if (!p) { + JS_ReportOutOfMemory(cx); + return JS_FALSE; + } + + JS_SetPrivate(cx, obj, p); + *vp = OBJECT_TO_JSVAL(obj); + return JS_TRUE; +} + +static void +pm_finalize(JSContext* cx, JSObject* obj) +{ + js_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, jsdouble(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_reset(JSContext* cx, uintN /*unused*/, jsval* vp) +{ + PerfMeasurement* p = GetPMFromThis(cx, vp); + if (!p) + return JS_FALSE; + + p->reset(); + 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("reset", pm_reset, 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_StrictPropertyStub, + 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_StrictPropertyStub, PM_CATTRS)) + return 0; + } + + if (!JS_FreezeObject(cx, prototype) || + !JS_FreezeObject(cx, ctor)) { + 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 |