diff options
Diffstat (limited to 'js/src/perf')
-rw-r--r-- | js/src/perf/jsperf.cpp | 293 | ||||
-rw-r--r-- | js/src/perf/jsperf.h | 133 | ||||
-rw-r--r-- | js/src/perf/pm_linux.cpp | 310 | ||||
-rw-r--r-- | js/src/perf/pm_stub.cpp | 63 |
4 files changed, 799 insertions, 0 deletions
diff --git a/js/src/perf/jsperf.cpp b/js/src/perf/jsperf.cpp new file mode 100644 index 000000000..ca2db4458 --- /dev/null +++ b/js/src/perf/jsperf.cpp @@ -0,0 +1,293 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "perf/jsperf.h" + +#include "jscntxt.h" /* for error messages */ +#include "jsobj.h" /* for unwrapping without a context */ + +using namespace js; +using JS::PerfMeasurement; + +// You cannot forward-declare a static object in C++, so instead +// we have to forward-declare the helper function that refers to it. +static PerfMeasurement* GetPM(JSContext* cx, JS::HandleValue value, const char* fname); + +// Property access + +#define GETTER(name) \ + static bool \ + pm_get_##name(JSContext* cx, unsigned argc, Value* vp) \ + { \ + CallArgs args = CallArgsFromVp(argc, vp); \ + PerfMeasurement* p = GetPM(cx, args.thisv(), #name); \ + if (!p) \ + return false; \ + args.rval().setNumber(double(p->name)); \ + return true; \ + } + +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 bool +pm_start(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + PerfMeasurement* p = GetPM(cx, args.thisv(), "start"); + if (!p) + return false; + + p->start(); + args.rval().setUndefined(); + return true; +} + +static bool +pm_stop(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + PerfMeasurement* p = GetPM(cx, args.thisv(), "stop"); + if (!p) + return false; + + p->stop(); + args.rval().setUndefined(); + return true; +} + +static bool +pm_reset(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + PerfMeasurement* p = GetPM(cx, args.thisv(), "reset"); + if (!p) + return false; + + p->reset(); + args.rval().setUndefined(); + return true; +} + +static bool +pm_canMeasureSomething(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + PerfMeasurement* p = GetPM(cx, args.thisv(), "canMeasureSomething"); + if (!p) + return false; + + args.rval().setBoolean(p->canMeasureSomething()); + return true; +} + +static const uint8_t PM_FATTRS = JSPROP_READONLY | JSPROP_PERMANENT; +static const 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 +}; + +static const uint8_t PM_PATTRS = + JSPROP_ENUMERATE | JSPROP_PERMANENT; + +#define GETTER(name) \ + JS_PSG(#name, pm_get_##name, PM_PATTRS) + +static const 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), + JS_PS_END +}; + +#undef GETTER + +// If this were C++ these would be "static const" members. + +#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 bool pm_construct(JSContext* cx, unsigned argc, Value* vp); +static void pm_finalize(JSFreeOp* fop, JSObject* obj); + +static const JSClassOps pm_classOps = { + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + pm_finalize +}; + +static const JSClass pm_class = { + "PerfMeasurement", + JSCLASS_HAS_PRIVATE | + JSCLASS_FOREGROUND_FINALIZE, + &pm_classOps +}; + +// Constructor and destructor + +static bool +pm_construct(JSContext* cx, unsigned argc, Value* vp) +{ + CallArgs args = CallArgsFromVp(argc, vp); + + uint32_t mask; + if (!args.hasDefined(0)) { + ReportMissingArg(cx, args.calleev(), 0); + return false; + } + if (!JS::ToUint32(cx, args[0], &mask)) + return false; + + JS::RootedObject obj(cx, JS_NewObjectForConstructor(cx, &pm_class, args)); + if (!obj) + return false; + + if (!JS_FreezeObject(cx, obj)) + return false; + + PerfMeasurement* p = cx->new_<PerfMeasurement>(PerfMeasurement::EventMask(mask)); + if (!p) { + JS_ReportOutOfMemory(cx); + return false; + } + + JS_SetPrivate(obj, p); + args.rval().setObject(*obj); + return true; +} + +static void +pm_finalize(JSFreeOp* fop, JSObject* obj) +{ + js::FreeOp::get(fop)->delete_(static_cast<PerfMeasurement*>(JS_GetPrivate(obj))); +} + +// Helpers (declared above) + +static PerfMeasurement* +GetPM(JSContext* cx, JS::HandleValue value, const char* fname) +{ + if (!value.isObject()) { + UniqueChars bytes = DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, value, nullptr); + if (!bytes) + return nullptr; + JS_ReportErrorNumberLatin1(cx, GetErrorMessage, 0, JSMSG_NOT_NONNULL_OBJECT, bytes.get()); + return nullptr; + } + RootedObject obj(cx, &value.toObject()); + PerfMeasurement* p = (PerfMeasurement*) + JS_GetInstancePrivate(cx, obj, &pm_class, nullptr); + 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_ReportErrorNumberASCII(cx, GetErrorMessage, 0, JSMSG_INCOMPATIBLE_PROTO, + pm_class.name, fname, JS_GetClass(obj)->name); + return nullptr; +} + +namespace JS { + +JSObject* +RegisterPerfMeasurement(JSContext* cx, HandleObject globalArg) +{ + static const uint8_t PM_CATTRS = JSPROP_ENUMERATE|JSPROP_READONLY|JSPROP_PERMANENT; + + RootedObject global(cx, globalArg); + RootedObject prototype(cx); + prototype = JS_InitClass(cx, global, nullptr /* parent */, + &pm_class, pm_construct, 1, + pm_props, pm_fns, 0, 0); + if (!prototype) + return 0; + + RootedObject ctor(cx); + 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, c->value, PM_CATTRS, + JS_STUBGETTER, JS_STUBSETTER)) + return 0; + } + + if (!JS_FreezeObject(cx, prototype) || + !JS_FreezeObject(cx, ctor)) { + return 0; + } + + return prototype; +} + +PerfMeasurement* +ExtractPerfMeasurement(const Value& wrapper) +{ + if (wrapper.isPrimitive()) + 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 = wrapper.toObjectOrNull(); + if (obj->getClass() != js::Valueify(&pm_class)) + return 0; + + return (PerfMeasurement*) obj->as<js::NativeObject>().getPrivate(); +} + +} // namespace JS diff --git a/js/src/perf/jsperf.h b/js/src/perf/jsperf.h new file mode 100644 index 000000000..b8f2909ad --- /dev/null +++ b/js/src/perf/jsperf.h @@ -0,0 +1,133 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef perf_jsperf_h +#define perf_jsperf_h + +#include "jstypes.h" + +#include "js/TypeDecls.h" +#include "js/Utility.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_t(-1). + */ + uint64_t cpu_cycles; + uint64_t instructions; + uint64_t cache_references; + uint64_t cache_misses; + uint64_t branch_instructions; + uint64_t branch_misses; + uint64_t bus_cycles; + uint64_t page_faults; + uint64_t major_page_faults; + uint64_t context_switches; + uint64_t 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. + */ + explicit 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, JS::HandleObject global); + +/* + * Given a Value which contains an instance of the aforementioned + * wrapper class, extract the C++ object. Returns nullptr if the + * Value is not an instance of the wrapper. + */ +extern JS_FRIEND_API(PerfMeasurement*) + ExtractPerfMeasurement(const Value& wrapper); + +} // namespace JS + +#endif /* perf_jsperf_h */ diff --git a/js/src/perf/pm_linux.cpp b/js/src/perf/pm_linux.cpp new file mode 100644 index 000000000..54ba0c363 --- /dev/null +++ b/js/src/perf/pm_linux.cpp @@ -0,0 +1,310 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* 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 <errno.h> +#include <linux/perf_event.h> +#include <string.h> +#include <sys/ioctl.h> +#include <sys/syscall.h> +#include <unistd.h> + +#include "perf/jsperf.h" + +using namespace js; + +// 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_t type; + uint32_t config; + uint64_t 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 (const auto& slot : kSlots) { + int fd = this->*(slot.fd); + if (fd != -1 && fd != group_leader) + close(fd); + } + + if (group_leader != -1) + close(group_leader); +} + +EventMask +Impl::init(EventMask toMeasure) +{ + MOZ_ASSERT(group_leader == -1); + if (!toMeasure) + return EventMask(0); + + EventMask measured = EventMask(0); + struct perf_event_attr attr; + for (const auto& slot : kSlots) { + if (!(toMeasure & slot.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 = slot.type; + attr.config = slot.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 | slot.bit); + this->*(slot.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 (const auto& slot : kSlots) { + int fd = this->*(slot.fd); + if (fd == -1) + continue; + + if (read(fd, buf, sizeof(buf)) == sizeof(uint64_t)) { + uint64_t cur; + memcpy(&cur, buf, sizeof(uint64_t)); + counters->*(slot.counter) += cur; + } + + // Reset the counter regardless of whether the read did what + // we expected. + ioctl(fd, PERF_EVENT_IOC_RESET, 0); + } +} + +} // namespace + + +namespace JS { + +#define initCtr(flag) ((eventsMeasured & flag) ? 0 : -1) + +PerfMeasurement::PerfMeasurement(PerfMeasurement::EventMask toMeasure) + : impl(js_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() +{ + js_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 (const auto& slot : kSlots) { + if (eventsMeasured & slot.bit) + this->*(slot.counter) = 0; + else + this->*(slot.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 diff --git a/js/src/perf/pm_stub.cpp b/js/src/perf/pm_stub.cpp new file mode 100644 index 000000000..bb6910c73 --- /dev/null +++ b/js/src/perf/pm_stub.cpp @@ -0,0 +1,63 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "perf/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 |