зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1560425
- Remove old performance measurement API r=jorendorff
Differential Revision: https://phabricator.services.mozilla.com/D35522 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
f4b4b49bee
Коммит
680c9fdc50
|
@ -146,8 +146,6 @@ var whitelist = [
|
|||
{file: "resource://gre/modules/Manifest.jsm"},
|
||||
// Bug 1351097
|
||||
{file: "resource://gre/modules/accessibility/AccessFu.jsm"},
|
||||
// Bug 1356043
|
||||
{file: "resource://gre/modules/PerfMeasurement.jsm"},
|
||||
// Bug 1356045
|
||||
{file: "chrome://global/content/test-ipc.xul"},
|
||||
// Bug 1378173 (warning: still used by devtools)
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
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);
|
||||
}
|
|
@ -112,7 +112,6 @@ EXPORTS += [
|
|||
'jsfriendapi.h',
|
||||
'jspubtd.h',
|
||||
'jstypes.h',
|
||||
'perf/jsperf.h',
|
||||
]
|
||||
|
||||
EXPORTS.js += [
|
||||
|
@ -248,7 +247,6 @@ UNIFIED_SOURCES += [
|
|||
'jsexn.cpp',
|
||||
'jsfriendapi.cpp',
|
||||
'jsnum.cpp',
|
||||
'perf/jsperf.cpp',
|
||||
'proxy/BaseProxyHandler.cpp',
|
||||
'proxy/CrossCompartmentWrapper.cpp',
|
||||
'proxy/DeadObjectProxy.cpp',
|
||||
|
@ -347,9 +345,6 @@ UNIFIED_SOURCES += [
|
|||
# RtlGenRandom declaration's calling convention in <ntsecapi.h> on Windows.
|
||||
# jsutil.cpp cannot be built in unified mode because it is needed for
|
||||
# check-vanilla-allocations.
|
||||
# perf/ProfilingStack.cpp cannot be built in unified mode because we want to
|
||||
# suppress warnings due to usage of the system allocator, and this allows it
|
||||
# to have a deterministic object name.
|
||||
# util/DoubleToString.cpp cannot be built in unified mode because we want to
|
||||
# suppress compiler warnings in third-party dtoa.c.
|
||||
# vm/Interpreter.cpp is gigantic and destroys incremental build times for any
|
||||
|
@ -405,17 +400,6 @@ if CONFIG['MOZ_VTUNE']:
|
|||
]
|
||||
SOURCES['vtune/ittnotify_static.c'].flags += ['-Wno-varargs', '-Wno-unknown-pragmas']
|
||||
|
||||
if CONFIG['HAVE_LINUX_PERF_EVENT_H']:
|
||||
SOURCES += [
|
||||
'perf/pm_linux.cpp'
|
||||
]
|
||||
if CONFIG['LINUX_HEADERS_INCLUDES']:
|
||||
SOURCES['perf/pm_linux.cpp'].flags += [CONFIG['LINUX_HEADERS_INCLUDES']]
|
||||
else:
|
||||
SOURCES += [
|
||||
'perf/pm_stub.cpp'
|
||||
]
|
||||
|
||||
DIRS += [
|
||||
'build',
|
||||
'frontend',
|
||||
|
|
|
@ -1,245 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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 "js/PropertySpec.h"
|
||||
#include "vm/JSContext.h" /* for error messages */
|
||||
#include "vm/JSObject.h" /* for unwrapping without a context */
|
||||
|
||||
#include "gc/FreeOp-inl.h"
|
||||
|
||||
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(PerfMeasurement::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, 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) return false;
|
||||
|
||||
JS_InitPrivate(obj, p, sizeof(*p), JS::MemoryUse::PerfMeasurement);
|
||||
args.rval().setObject(*obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void pm_finalize(JSFreeOp* fop, JSObject* obj) {
|
||||
auto pm = static_cast<PerfMeasurement*>(JS_GetPrivate(obj));
|
||||
js::FreeOp::get(fop)->delete_(obj, pm, MemoryUse::PerfMeasurement);
|
||||
}
|
||||
|
||||
// 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_ReportErrorNumberUTF8(cx, GetErrorMessage, 0, JSMSG_OBJECT_REQUIRED,
|
||||
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)) 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
|
|
@ -1,132 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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 */
|
|
@ -1,272 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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;
|
||||
}
|
||||
return errno != ENOSYS;
|
||||
}
|
||||
|
||||
} // namespace JS
|
|
@ -1,47 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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
|
|
@ -107,7 +107,6 @@
|
|||
#include "js/SweepingAPI.h"
|
||||
#include "js/Warnings.h" // JS::SetWarningReporter
|
||||
#include "js/Wrapper.h"
|
||||
#include "perf/jsperf.h"
|
||||
#include "shell/jsoptparse.h"
|
||||
#include "shell/jsshell.h"
|
||||
#include "shell/OSObject.h"
|
||||
|
@ -9904,9 +9903,6 @@ static JSObject* NewGlobalObject(JSContext* cx, JS::RealmOptions& options,
|
|||
if (!JS_DefineDebuggerObject(cx, glob)) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!JS::RegisterPerfMeasurement(cx, glob)) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!JS_DefineFunctionsWithHelp(cx, glob, shell_functions) ||
|
||||
!JS_DefineProfilingFunctions(cx, glob)) {
|
||||
return nullptr;
|
||||
|
|
|
@ -115,9 +115,6 @@ with Files("**/browser/tools/mozscreenshots/**"):
|
|||
with Files("**/devtools/shared/test-helpers/**"):
|
||||
SCHEDULES.inclusive += ['test-verify', 'test-verify-gpu']
|
||||
|
||||
with Files("**/toolkit/components/perf/**"):
|
||||
SCHEDULES.inclusive += ['test-verify', 'test-verify-gpu']
|
||||
|
||||
CONFIGURE_SUBST_FILES += [
|
||||
'config/autoconf.mk',
|
||||
'config/emptyvars.mk',
|
||||
|
|
|
@ -49,7 +49,6 @@ DIRS += [
|
|||
'osfile',
|
||||
'parentalcontrols',
|
||||
'passwordmgr',
|
||||
'perf',
|
||||
'perfmonitoring',
|
||||
'pictureinpicture',
|
||||
'places',
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = {
|
||||
"extends": [
|
||||
"plugin:mozilla/chrome-test"
|
||||
]
|
||||
};
|
|
@ -1,74 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
|
||||
/* 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 "PerfMeasurement.h"
|
||||
#include "jsperf.h"
|
||||
#include "nsMemory.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozJSComponentLoader.h"
|
||||
#include "nsZipArchive.h"
|
||||
#include "xpc_make_class.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace jsperf {
|
||||
|
||||
NS_IMPL_ISUPPORTS(Module, nsIXPCScriptable)
|
||||
|
||||
Module::Module() = default;
|
||||
|
||||
Module::~Module() = default;
|
||||
|
||||
#define XPC_MAP_CLASSNAME Module
|
||||
#define XPC_MAP_QUOTED_CLASSNAME "Module"
|
||||
#define XPC_MAP_FLAGS XPC_SCRIPTABLE_WANT_CALL
|
||||
#include "xpc_map_end.h"
|
||||
|
||||
static bool SealObjectAndPrototype(JSContext* cx, JS::Handle<JSObject*> parent,
|
||||
const char* name) {
|
||||
JS::Rooted<JS::Value> prop(cx);
|
||||
if (!JS_GetProperty(cx, parent, name, &prop)) return false;
|
||||
|
||||
if (prop.isUndefined()) {
|
||||
// Pretend we sealed the object.
|
||||
return true;
|
||||
}
|
||||
|
||||
JS::Rooted<JSObject*> obj(cx, prop.toObjectOrNull());
|
||||
if (!JS_GetProperty(cx, obj, "prototype", &prop)) return false;
|
||||
|
||||
JS::Rooted<JSObject*> prototype(cx, prop.toObjectOrNull());
|
||||
return JS_FreezeObject(cx, obj) && JS_FreezeObject(cx, prototype);
|
||||
}
|
||||
|
||||
static bool InitAndSealPerfMeasurementClass(JSContext* cx,
|
||||
JS::Handle<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_FreezeObject(cx, global);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
Module::Call(nsIXPConnectWrappedNative* wrapper, JSContext* cx, JSObject* obj,
|
||||
const JS::CallArgs& args, bool* _retval) {
|
||||
mozJSComponentLoader* loader = mozJSComponentLoader::Get();
|
||||
JS::Rooted<JSObject*> targetObj(cx);
|
||||
loader->FindTargetObject(cx, &targetObj);
|
||||
|
||||
*_retval = InitAndSealPerfMeasurementClass(cx, targetObj);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace jsperf
|
||||
} // namespace mozilla
|
|
@ -1,29 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
|
||||
/* 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 COMPONENTS_PERFMEASUREMENT_H
|
||||
#define COMPONENTS_PERFMEASUREMENT_H
|
||||
|
||||
#include "nsIXPCScriptable.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace jsperf {
|
||||
|
||||
class Module final : public nsIXPCScriptable {
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIXPCSCRIPTABLE
|
||||
|
||||
Module();
|
||||
|
||||
private:
|
||||
~Module();
|
||||
};
|
||||
|
||||
} // namespace jsperf
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
|
@ -1,19 +0,0 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* 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/. */
|
||||
|
||||
var 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.
|
||||
*
|
||||
*/
|
||||
|
||||
Cc["@mozilla.org/jsperf;1"].createInstance()();
|
|
@ -1,3 +0,0 @@
|
|||
[DEFAULT]
|
||||
|
||||
[test_pm.xul]
|
|
@ -1,14 +0,0 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
Classes = [
|
||||
{
|
||||
'cid': '{421c38e6-aee0-4509-a025-130f4378035a}',
|
||||
'contract_ids': ['@mozilla.org/jsperf;1'],
|
||||
'type': 'mozilla::jsperf::Module',
|
||||
'headers': ['/toolkit/components/perf/PerfMeasurement.h'],
|
||||
},
|
||||
]
|
|
@ -1,28 +0,0 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
with Files('**'):
|
||||
BUG_COMPONENT = ('Core', 'JavaScript Engine')
|
||||
|
||||
SOURCES += [
|
||||
'PerfMeasurement.cpp',
|
||||
]
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
'PerfMeasurement.jsm',
|
||||
]
|
||||
|
||||
XPCOM_MANIFESTS += [
|
||||
'components.conf',
|
||||
]
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
'/js/xpconnect/loader',
|
||||
]
|
||||
|
||||
MOCHITEST_CHROME_MANIFESTS += ['chrome.ini']
|
|
@ -1,46 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<!-- 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/. -->
|
||||
|
||||
<window title="Performance measurement tests"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
onload="test()">
|
||||
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
|
||||
|
||||
<script><![CDATA[
|
||||
function test()
|
||||
{
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
const {PerfMeasurement} = ChromeUtils.import("resource://gre/modules/PerfMeasurement.jsm");
|
||||
let pm = new PerfMeasurement(PerfMeasurement.ALL);
|
||||
if (pm.eventsMeasured == 0) {
|
||||
todo(false, "stub, skipping test");
|
||||
} else {
|
||||
pm.start();
|
||||
for (let i = 0; i < 10000; i++) ;
|
||||
pm.stop();
|
||||
|
||||
events = ["cpu_cycles", "instructions", "cache_references", "cache_misses",
|
||||
"branch_instructions", "branch_misses", "bus_cycles", "page_faults",
|
||||
"major_page_faults", "context_switches", "cpu_migrations"];
|
||||
|
||||
for (var i = 0; i < events.length; i++) {
|
||||
var e = events[i];
|
||||
((pm.eventsMeasured & PerfMeasurement[e.toUpperCase()]) ? isnot : todo_is)(pm[e], -1, e);
|
||||
}
|
||||
}
|
||||
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>
|
Загрузка…
Ссылка в новой задаче