Bug 1369955: Introduce a perfstream::Measure subtree for SpiderMonkey.
js/src/vm/Measure.cpp implements a perfstream::Group under which SpiderMonkey
performance measurements can be placed. js/public/Measure.h holds the public
interface and comments.
MozReview-Commit-ID: 4azhU83aorE
--- a/config/check_spidermonkey_style.py
+++ b/config/check_spidermonkey_style.py
@@ -254,16 +254,21 @@ def check_style():
with get_repository_from_env() as repo:
# Select the appropriate files.
for filename in repo.get_files_in_working_directory():
for non_js_dir in non_js_dirnames:
if filename.startswith(non_js_dir) and filename.endswith('.h'):
inclname = 'mozilla/' + filename.split('/')[-1]
non_js_inclnames.add(inclname)
+ # perfstream headers appear as mozilla/perfstream/foo.h.
+ if filename.startswith('perfstream/') and filename.endswith('.h'):
+ inclname = 'mozilla/' + filename
+ non_js_inclnames.add(inclname)
+
if filename.startswith('js/public/') and filename.endswith('.h'):
inclname = 'js/' + filename[len('js/public/'):]
js_names[filename] = inclname
if filename.startswith('js/src/') and \
not filename.startswith(tuple(ignored_js_src_dirs)) and \
filename.endswith(('.c', '.cpp', '.h', '.tbl', '.msg')):
inclname = filename[len('js/src/'):]
new file mode 100644
--- /dev/null
+++ b/js/public/Measure.h
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * 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 js_Measure_h
+#define js_Measure_h
+
+#include "mozilla/perfstream/Measure.h"
+#include "mozilla/UniquePtr.h"
+
+#include "jspubtd.h"
+
+namespace JS {
+
+/**
+ * Return a tree of SpiderMonkey performance measures.
+ *
+ * This returns a mozilla::perfstream::Group that is the root of the measure
+ * tree for the given JSContext's runtime. See perfstream/Measure.h for an
+ * explanation of how to use Groups and Measures.
+ *
+ * On OOM, return a null UniquePtr.
+ */
+extern JS_PUBLIC_API(mozilla::perfstream::GroupPtr)
+GetMeasures(JSContext*);
+
+/**
+ * Like GetMeasures, but include testing-only measures.
+ */
+extern JS_PUBLIC_API(mozilla::perfstream::GroupPtr)
+GetMeasuresWithTests(JSContext*);
+
+} // namespace JS
+
+#endif /* js_Measure_h */
--- a/js/src/moz.build
+++ b/js/src/moz.build
@@ -109,16 +109,17 @@ EXPORTS.js += [
'../public/GCPolicyAPI.h',
'../public/GCVariant.h',
'../public/GCVector.h',
'../public/HashTable.h',
'../public/HeapAPI.h',
'../public/Id.h',
'../public/Initialization.h',
'../public/LegacyIntTypes.h',
+ '../public/Measure.h',
'../public/MemoryMetrics.h',
'../public/Principals.h',
'../public/ProfilingFrameIterator.h',
'../public/ProfilingStack.h',
'../public/Proxy.h',
'../public/Realm.h',
'../public/RefCounted.h',
'../public/RequiredDefines.h',
@@ -323,16 +324,17 @@ UNIFIED_SOURCES += [
'vm/GeckoProfiler.cpp',
'vm/GeneratorObject.cpp',
'vm/GlobalObject.cpp',
'vm/HelperThreads.cpp',
'vm/Id.cpp',
'vm/Initialization.cpp',
'vm/JSONParser.cpp',
'vm/JSONPrinter.cpp',
+ 'vm/Measure.cpp',
'vm/MemoryMetrics.cpp',
'vm/NativeObject.cpp',
'vm/ObjectGroup.cpp',
'vm/PIC.cpp',
'vm/Printer.cpp',
'vm/Probes.cpp',
'vm/ProxyObject.cpp',
'vm/Realm.cpp',
@@ -756,8 +758,10 @@ if CONFIG['CLANG_CXX'] or CONFIG['GNU_CX
# Generate GC statistics phase data.
GENERATED_FILES += ['gc/StatsPhasesGenerated.h']
StatsPhasesGeneratedHeader = GENERATED_FILES['gc/StatsPhasesGenerated.h']
StatsPhasesGeneratedHeader.script = 'gc/GenerateStatsPhases.py:generateHeader'
GENERATED_FILES += ['gc/StatsPhasesGenerated.cpp']
StatsPhasesGeneratedCpp = GENERATED_FILES['gc/StatsPhasesGenerated.cpp']
StatsPhasesGeneratedCpp.script = 'gc/GenerateStatsPhases.py:generateCpp'
+
+USE_LIBS += ['perfstream']
new file mode 100644
--- /dev/null
+++ b/js/src/vm/Measure.cpp
@@ -0,0 +1,208 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ * vim: set ts=8 sts=4 et sw=4 tw=99:
+ * 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/. */
+
+/* Root of the tree of mozilla::perfstream performance measures for Spidermonkey. */
+
+#include "js/Measure.h"
+
+#include "mozilla/ArrayUtils.h"
+#include "mozilla/Atomics.h"
+#include "mozilla/Maybe.h"
+#include "mozilla/Move.h"
+#include "mozilla/perfstream/Measure.h"
+#include "mozilla/perfstream/StaticGroup.h"
+
+#include "jscntxt.h"
+
+using mozilla::ArrayLength;
+using mozilla::Atomic;
+using mozilla::Maybe;
+using mozilla::Move;
+using mozilla::Nothing;
+using mozilla::perfstream::Description;
+using mozilla::perfstream::Group;
+using mozilla::perfstream::GroupPtr;
+using mozilla::perfstream::GroupVector;
+using mozilla::perfstream::Measure;
+using mozilla::perfstream::MeasurePtr;
+using mozilla::perfstream::MeasureVector;
+using mozilla::perfstream::StaticGroup;
+using mozilla::Some;
+
+
+namespace js {
+
+// A dummy measure, for testing only.
+class TestMeasure: public Measure {
+
+ public:
+ TestMeasure(const char* identifier, Atomic<bool>& enabled)
+ : identifier_(identifier), enabled_(enabled)
+ { }
+
+ static MeasurePtr Make(const char* identifier, Atomic<bool>& enabled) {
+ return mozilla::MakeUnique<TestMeasure>(identifier, enabled);
+ }
+
+ bool IsEnabled() const override {
+ return enabled_;
+ }
+ bool Enable() override {
+ enabled_ = true;
+ return true;
+ }
+ bool Disable() override {
+ enabled_ = false;
+ return false;
+ }
+
+ Description GetDescription() const override {
+ static const char* const metadata[] = {
+ "tooltip-fluent: SpiderMonkey.MeasureTests.toy",
+ "tooltip: A toy measure for testing the measure machinery. Can be enabled; does nothing.",
+ "help-url: https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey",
+ nullptr
+ };
+
+ Description description = {
+ identifier_,
+ metadata
+ };
+
+ return description;
+ }
+
+ private:
+ const char* identifier_;
+ Atomic<bool> &enabled_;
+};
+
+// A group of toy measures, for use in tests.
+// This is actually an impl class for use with StaticGroup.
+class MeasureTestsImpl {
+ public:
+ MeasureTestsImpl() = default;
+ MeasureTestsImpl(const MeasureTestsImpl&) = default;
+ MeasureTestsImpl(MeasureTestsImpl&&) = default;
+
+ template<typename Functor>
+ bool EnumerateMeasures(Functor F) const {
+ return F("Flopsy", [=] { return TestMeasure::Make("Flopsy", enabled[0]); }) &&
+ F("Mopsy", [=] { return TestMeasure::Make("Mopsy", enabled[1]); }) &&
+ F("Cottontail", [=] { return TestMeasure::Make("Cottontail", enabled[2]); });
+ }
+
+ template<typename Functor>
+ bool EnumerateSubgroups(Functor F) const { return true; }
+
+ static const Description sDescription;
+
+ private:
+ // Measures are supposed to be references to some underlying machinery that
+ // actually does the measurement. To emphasize this, all TestMeasures are references
+ // to the same underlying set of bits.
+ static Atomic<bool> enabled[3];
+
+ // Metadata for the group.
+ static const char* const metadata[];
+};
+
+Atomic<bool> MeasureTestsImpl::enabled[3];
+
+const Description MeasureTestsImpl::sDescription = { "MeasureTests", metadata };
+
+const char* const MeasureTestsImpl::metadata[] = {
+ "tooltip: Test measure group for SpiderMonkey.",
+ "prams: definitely",
+ "prawns: probably",
+ nullptr
+};
+
+using MeasureTests = StaticGroup<MeasureTestsImpl>;
+
+class JSMeasuresImpl {
+ public:
+ enum Options {
+ Testing = 1,
+ };
+
+ JSMeasuresImpl(JSContext* cx, bool options) : cx(cx), options(options) { }
+ JSMeasuresImpl(const JSMeasuresImpl& rhs) = default;
+ JSMeasuresImpl(JSMeasuresImpl&& rhs) = default;
+
+ template<typename F>
+ bool EnumerateMeasures(F functor) const { return true; }
+
+ template<typename F>
+ bool EnumerateSubgroups(F functor) const {
+ // If our JSRuntime is dead, then we have no children.
+ if (!checkContext())
+ return true;
+
+ // Add more children here.
+
+ if (options & Options::Testing) {
+ if (!functor("MeasureTests", [this]() {
+ return mozilla::MakeUnique<MeasureTests>(MeasureTestsImpl());
+ }))
+ return false;
+ // Add more testing-only children here.
+ }
+
+ return true;
+ }
+
+ static const Description sDescription;
+
+ private:
+ // The context for the JSRuntime we operate on. This JSRuntime could be
+ // destroyed, so we need to check it before using it.
+ JSContext* cx;
+
+ // Bits from JSMeasures::Options.
+ int options;
+
+ bool checkContext() const {
+ return cx == TlsContext.get() &&
+ cx->runtime()->activeContext() == cx;
+ }
+
+ static const char* const metadata[];
+};
+
+const Description JSMeasuresImpl::sDescription = {
+ "SpiderMonkey",
+ metadata
+};
+
+const char* const JSMeasuresImpl::metadata[] = {
+ "tooltip-fluent: SpiderMonkey.measureGroup.description",
+ "tooltip: the SpiderMonkey JavaScript engine",
+ "help-url: https://developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey",
+ nullptr
+};
+
+using JSMeasures = StaticGroup<JSMeasuresImpl>;
+
+} // namespace js
+
+namespace JS {
+
+JS_PUBLIC_API(GroupPtr)
+GetMeasures(JSContext* cx)
+{
+ JSMeasuresImpl impl(cx, 0);
+ return mozilla::MakeUnique<JSMeasures>(impl);
+}
+
+JS_PUBLIC_API(GroupPtr)
+GetMeasuresWithTests(JSContext* cx)
+{
+ JSMeasuresImpl impl(cx, JSMeasuresImpl::Testing);
+ return mozilla::MakeUnique<JSMeasures>(impl);
+}
+
+} // namespace JS