Skip to content

Commit

Permalink
Merge pull request #4510 from runspired/heimdall-instrumentation
Browse files Browse the repository at this point in the history
Heimdall instrumentation
  • Loading branch information
fivetanley committed Sep 30, 2016
2 parents 6dce4e8 + 7a1a957 commit 2340426
Show file tree
Hide file tree
Showing 54 changed files with 802 additions and 29 deletions.
3 changes: 3 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ module.exports = {
env: {
'browser': true,
},
globals: {
'heimdall': true
},
rules: {
'no-unused-vars': ['error', {
'args': 'none',
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ dist/
.idea
*.iml

benchmarks/results/*.json

.DS_Store
.project

Expand Down
21 changes: 21 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,27 @@ production builds automatically.
Be sure to leave a description of the feature and possible example of how to
use it (if necessary).

## Benchmarking

Ember Data is instrumented with [heimdalljs](https://github.com/heimdalljs/heimdalljs-lib)
Top level scenarios for benchmarking are available via the `query` route in
the dummy app, and desired scenarios to be run can be configured via `benchmarks/config.js`.

The scenarios are configured to interop with [heimdall-query](https://github.com/heimdalljs/heimdall-query)
for analysis. To run scenarios:

1. Start the dummy app with instrumentation on: `ember s --instrument`

2. Configure `benchmarks/config.js` with desired scenarios

3. To run both the benchmarks and the analysis: `node ./benchmarks`

a.) To just collect data (no analysis): `node ./benchmarks/bash-run.js`
b.) To just run analysis (w/cached data): `node ./benchmarks/bash-analyze.js`
c.) To cache a data set or use a cached data set, all commands accept `-c ./path/to/cache/dir`

4. Do not commit cached data results, these should be git ignored already.

# Pull Requests

We love pull requests. Here's a quick guide:
Expand Down
4 changes: 4 additions & 0 deletions addon/-private/debug.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ export function runInDebug() {
return Ember.runInDebug(...arguments);
}

export function instrument(method) {
return method();
}

export function warn() {
return Ember.warn(...arguments);
}
Expand Down
39 changes: 39 additions & 0 deletions addon/-private/system/model/internal-model.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,34 @@ function retrieveFromCurrentState(key) {
};
}

// this (and all heimdall instrumentation) will be stripped by a babel transform
// https://github.com/heimdalljs/babel5-plugin-strip-heimdall
const {
_triggerDeferredTriggers,
changedAttributes,
createSnapshot,
flushChangedAttributes,
hasChangedAttributes,
materializeRecord,
new_InternalModel,
send,
setupData,
transitionTo,
updateChangedAttributes
} = heimdall.registerMonitor('InternalModel',
'_triggerDeferredTriggers',
'changedAttributes',
'createSnapshot',
'flushChangedAttributes',
'hasChangedAttributes',
'materializeRecord',
'new_InternalModel',
'send',
'setupData',
'transitionTo',
'updateChangedAttributes'
);

/*
`InternalModel` is the Model class that we use internally inside Ember Data to represent models.
Internal ED methods should only deal with `InternalModel` objects. It is a fast, plain Javascript class.
Expand All @@ -61,6 +89,7 @@ function retrieveFromCurrentState(key) {
*/

export default function InternalModel(type, id, store, _, data) {
heimdall.increment(new_InternalModel);
this.type = type;
this.id = id;
this.store = store;
Expand Down Expand Up @@ -124,6 +153,7 @@ InternalModel.prototype = {

constructor: InternalModel,
materializeRecord() {
heimdall.increment(materializeRecord);
assert("Materialized " + this.modelName + " record with id:" + this.id + "more than once", this.record === null || this.record === undefined);

// lookupFactory should really return an object that creates
Expand Down Expand Up @@ -221,6 +251,7 @@ InternalModel.prototype = {
},

setupData(data) {
heimdall.increment(setupData);
var changedKeys = this._changedKeys(data.attributes);
assign(this._data, data.attributes);
this.pushedData();
Expand Down Expand Up @@ -252,6 +283,7 @@ InternalModel.prototype = {
@private
*/
createSnapshot(options) {
heimdall.increment(createSnapshot);
return new Snapshot(this, options);
},

Expand Down Expand Up @@ -290,11 +322,13 @@ InternalModel.prototype = {
},

flushChangedAttributes() {
heimdall.increment(flushChangedAttributes);
this._inFlightAttributes = this._attributes;
this._attributes = new EmptyObject();
},

hasChangedAttributes() {
heimdall.increment(hasChangedAttributes);
return Object.keys(this._attributes).length > 0;
},

Expand All @@ -309,6 +343,7 @@ InternalModel.prototype = {
@private
*/
updateChangedAttributes() {
heimdall.increment(updateChangedAttributes);
var changedAttributes = this.changedAttributes();
var changedAttributeNames = Object.keys(changedAttributes);

Expand All @@ -330,6 +365,7 @@ InternalModel.prototype = {
@private
*/
changedAttributes() {
heimdall.increment(changedAttributes);
var oldData = this._data;
var currentData = this._attributes;
var inFlightData = this._inFlightAttributes;
Expand Down Expand Up @@ -370,6 +406,7 @@ InternalModel.prototype = {
@param {Object} context
*/
send(name, context) {
heimdall.increment(send);
var currentState = get(this, 'currentState');

if (!currentState[name]) {
Expand Down Expand Up @@ -441,6 +478,7 @@ InternalModel.prototype = {
@param {String} name
*/
transitionTo(name) {
heimdall.increment(transitionTo);
// POSSIBLE TODO: Remove this code and replace with
// always having direct reference to state objects

Expand Down Expand Up @@ -509,6 +547,7 @@ InternalModel.prototype = {
},

_triggerDeferredTriggers() {
heimdall.increment(_triggerDeferredTriggers);
//TODO: Before 1.0 we want to remove all the events that happen on the pre materialized record,
//but for now, we queue up all the events triggered before the record was materialized, and flush
//them once we have the record
Expand Down
2 changes: 2 additions & 0 deletions addon/-private/system/model/states.js
Original file line number Diff line number Diff line change
Expand Up @@ -248,11 +248,13 @@ var DirtyState = {
},

pushedData(internalModel) {
let token = heimdall.start('stats.uncommitted.pushedData');
internalModel.updateChangedAttributes();

if (!internalModel.hasChangedAttributes()) {
internalModel.transitionTo('loaded.saved');
}
heimdall.stop(token);
},

becomeDirty: Ember.K,
Expand Down
61 changes: 61 additions & 0 deletions addon/-private/system/record-array-manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,48 @@ var MapWithDefault = Ember.MapWithDefault;
import OrderedSet from "ember-data/-private/system/ordered-set";
var get = Ember.get;

const {
_addRecordToRecordArray,
_recordWasChanged,
_recordWasDeleted,
array_flatten,
array_remove,
create,
createAdapterPopulatedRecordArray,
createFilteredRecordArray,
createRecordArray,
liveRecordArrayFor,
populateLiveRecordArray,
recordArraysForRecord,
recordDidChange,
recordWasLoaded,
registerFilteredRecordArray,
unregisterRecordArray,
updateFilter,
updateFilterRecordArray,
updateRecordArrays
} = heimdall.registerMonitor('recordArrayManager',
'_addRecordToRecordArray',
'_recordWasChanged',
'_recordWasDeleted',
'array_fatten',
'array_remove',
'create',
'createAdapterPopulatedRecordArray',
'createFilteredRecordArray',
'createRecordArray',
'liveRecordArrayFor',
'populateLiveRecordArray',
'recordArraysForRecord',
'recordDidChange',
'recordWasLoaded',
'registerFilteredRecordArray',
'unregisterRecordArray',
'updateFilter',
'updateFilterRecordArray',
'updateRecordArrays'
);

/**
@class RecordArrayManager
@namespace DS
Expand All @@ -20,6 +62,7 @@ var get = Ember.get;
*/
export default Ember.Object.extend({
init() {
heimdall.increment(create);
this.filteredRecordArrays = MapWithDefault.create({
defaultValue() { return []; }
});
Expand All @@ -35,12 +78,14 @@ export default Ember.Object.extend({
},

recordDidChange(record) {
heimdall.increment(recordDidChange);
if (this.changedRecords.push(record) !== 1) { return; }

Ember.run.schedule('actions', this, this.updateRecordArrays);
},

recordArraysForRecord(record) {
heimdall.increment(recordArraysForRecord);
record._recordArrays = record._recordArrays || OrderedSet.create();
return record._recordArrays;
},
Expand All @@ -56,6 +101,7 @@ export default Ember.Object.extend({
@method updateRecordArrays
*/
updateRecordArrays() {
heimdall.increment(updateRecordArrays);
this.changedRecords.forEach((internalModel) => {
if (get(internalModel, 'record.isDestroyed') || get(internalModel, 'record.isDestroying') ||
(get(internalModel, 'currentState.stateName') === 'root.deleted.saved')) {
Expand All @@ -69,6 +115,7 @@ export default Ember.Object.extend({
},

_recordWasDeleted(record) {
heimdall.increment(_recordWasDeleted);
var recordArrays = record._recordArrays;

if (!recordArrays) { return; }
Expand All @@ -80,6 +127,7 @@ export default Ember.Object.extend({


_recordWasChanged(record) {
heimdall.increment(_recordWasChanged);
var typeClass = record.type;
var recordArrays = this.filteredRecordArrays.get(typeClass);
var filter;
Expand All @@ -91,6 +139,7 @@ export default Ember.Object.extend({

//Need to update live arrays on loading
recordWasLoaded(record) {
heimdall.increment(recordWasLoaded);
var typeClass = record.type;
var recordArrays = this.filteredRecordArrays.get(typeClass);
var filter;
Expand All @@ -115,6 +164,7 @@ export default Ember.Object.extend({
@param {InternalModel} record
*/
updateFilterRecordArray(array, filter, typeClass, record) {
heimdall.increment(updateFilterRecordArray);
var shouldBeInArray = filter(record.getRecord());
var recordArrays = this.recordArraysForRecord(record);
if (shouldBeInArray) {
Expand All @@ -126,6 +176,7 @@ export default Ember.Object.extend({
},

_addRecordToRecordArray(array, record) {
heimdall.increment(_addRecordToRecordArray);
var recordArrays = this.recordArraysForRecord(record);
if (!recordArrays.has(array)) {
array.addInternalModel(record);
Expand All @@ -134,6 +185,7 @@ export default Ember.Object.extend({
},

populateLiveRecordArray(array, modelName) {
heimdall.increment(populateLiveRecordArray);
var typeMap = this.store.typeMapFor(modelName);
var records = typeMap.records;
var record;
Expand All @@ -160,6 +212,7 @@ export default Ember.Object.extend({
@param {Function} filter
*/
updateFilter(array, modelName, filter) {
heimdall.increment(updateFilter);
var typeMap = this.store.typeMapFor(modelName);
var records = typeMap.records;
var record;
Expand All @@ -182,6 +235,7 @@ export default Ember.Object.extend({
@return {DS.RecordArray}
*/
liveRecordArrayFor(typeClass) {
heimdall.increment(liveRecordArrayFor);
return this.liveRecordArrays.get(typeClass);
},

Expand All @@ -193,6 +247,7 @@ export default Ember.Object.extend({
@return {DS.RecordArray}
*/
createRecordArray(typeClass) {
heimdall.increment(createRecordArray);
var array = RecordArray.create({
type: typeClass,
content: Ember.A(),
Expand All @@ -214,6 +269,7 @@ export default Ember.Object.extend({
@return {DS.FilteredRecordArray}
*/
createFilteredRecordArray(typeClass, filter, query) {
heimdall.increment(createFilteredRecordArray);
var array = FilteredRecordArray.create({
query: query,
type: typeClass,
Expand All @@ -237,6 +293,7 @@ export default Ember.Object.extend({
@return {DS.AdapterPopulatedRecordArray}
*/
createAdapterPopulatedRecordArray(typeClass, query) {
heimdall.increment(createAdapterPopulatedRecordArray);
var array = AdapterPopulatedRecordArray.create({
type: typeClass,
query: query,
Expand All @@ -262,6 +319,7 @@ export default Ember.Object.extend({
@param {Function} filter
*/
registerFilteredRecordArray(array, typeClass, filter) {
heimdall.increment(registerFilteredRecordArray);
var recordArrays = this.filteredRecordArrays.get(typeClass);
recordArrays.push(array);

Expand All @@ -276,6 +334,7 @@ export default Ember.Object.extend({
@param {DS.RecordArray} array
*/
unregisterRecordArray(array) {
heimdall.increment(unregisterRecordArray);
var typeClass = array.type;

// unregister filtered record array
Expand Down Expand Up @@ -312,6 +371,7 @@ function destroy(entry) {
}

function flatten(list) {
heimdall.increment(array_flatten);
var length = list.length;
var result = Ember.A();

Expand All @@ -323,6 +383,7 @@ function flatten(list) {
}

function remove(array, item) {
heimdall.increment(array_remove);
const index = array.indexOf(item);

if (index !== -1) {
Expand Down
Loading

0 comments on commit 2340426

Please sign in to comment.