Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement web-tracing-framework support #2610

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -8,6 +8,10 @@ import {ProtoRecord} from './proto_record';
import {Locals} from './parser/locals';
import {Pipes} from './pipes/pipes';
import {CHECK_ALWAYS, CHECK_ONCE, CHECKED, DETACHED, ON_PUSH} from './constants';
import {wtfCreateScope, wtfLeave, ScopeEventFactory} from 'angular2/src/core/wtf';
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pull WTF into separate module


var _scope_check: ScopeEventFactory =
wtfCreateScope(`ChangeDetector_#check(ascii id, bool throwOnChange)`);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove _


class _Context {
constructor(public element: any, public componentElement: any, public instance: any,
Expand Down Expand Up @@ -64,6 +68,8 @@ export class AbstractChangeDetector<T> implements ChangeDetector {
runDetectChanges(throwOnChange: boolean): void {
if (this.mode === DETACHED || this.mode === CHECKED) return;

var s = _scope_check(this.id, throwOnChange);

this.detectChangesInRecords(throwOnChange);

this._detectChangesInLightDomChildren(throwOnChange);
Expand All @@ -73,6 +79,7 @@ export class AbstractChangeDetector<T> implements ChangeDetector {
this._detectChangesInShadowDomChildren(throwOnChange);

if (this.mode === CHECK_ONCE) this.mode = CHECKED;
wtfLeave(s);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

add extra space

}

detectChangesInRecords(throwOnChange: boolean): void {}
Expand Down
2 changes: 2 additions & 0 deletions modules/angular2/src/core/application_common.ts
Expand Up @@ -69,6 +69,7 @@ import {
} from 'angular2/src/render/dom/view/shared_styles_host';
import {internalView} from 'angular2/src/core/compiler/view_ref';
import {appComponentRefPromiseToken, appComponentTypeToken} from './application_tokens';
import {wtfInit} from './wtf_init';

var _rootInjector: Injector;

Expand Down Expand Up @@ -286,6 +287,7 @@ export function commonBootstrap(
appComponentType: /*Type*/ any,
componentInjectableBindings: List<Type | Binding | List<any>> = null): Promise<ApplicationRef> {
BrowserDomAdapter.makeCurrent();
wtfInit();
var bootstrapProcess = PromiseWrapper.completer();
var zone = createNgZone(new ExceptionHandler(DOM, isDart ? false : true));
zone.run(() => {
Expand Down
7 changes: 6 additions & 1 deletion modules/angular2/src/core/compiler/compiler.ts
Expand Up @@ -25,6 +25,7 @@ import {ProtoViewFactory} from './proto_view_factory';
import {UrlResolver} from 'angular2/src/services/url_resolver';
import {AppRootUrl} from 'angular2/src/services/app_root_url';
import {ElementBinder} from './element_binder';
import {wtfStartTimeRange, wtfEndTimeRange} from 'angular2/src/core/wtf';

import * as renderApi from 'angular2/src/render/api';

Expand Down Expand Up @@ -127,6 +128,7 @@ export class Compiler {
compileInHost(componentTypeOrBinding: Type | Binding): Promise<ProtoViewRef> {
var componentType = isType(componentTypeOrBinding) ? componentTypeOrBinding :
(<Binding>componentTypeOrBinding).token;
var r = wtfStartTimeRange('Compiler#compile()', stringify(componentType));

var hostAppProtoView = this._compilerCache.getHost(componentType);
var hostPvPromise;
Expand All @@ -149,7 +151,10 @@ export class Compiler {
return appProtoView;
});
}
return hostPvPromise.then(hostAppProtoView => hostAppProtoView.ref);
return hostPvPromise.then((hostAppProtoView) => {
wtfEndTimeRange(r);
return hostAppProtoView.ref;
});
}

private _compile(componentBinding: DirectiveBinding,
Expand Down
34 changes: 26 additions & 8 deletions modules/angular2/src/core/compiler/view_manager.ts
Expand Up @@ -15,6 +15,7 @@ import {
import {AppViewManagerUtils} from './view_manager_utils';
import {AppViewPool} from './view_pool';
import {AppViewListener} from './view_listener';
import {wtfCreateScope, wtfLeave, ScopeEventFactory} from 'angular2/src/core/wtf';

/**
* Entry point for creating, moving views in the view hierarchy and destroying views.
Expand Down Expand Up @@ -83,6 +84,8 @@ export class AppViewManager {
return this._utils.getComponentInstance(hostView, boundElementIndex);
}

_scope_createRootHostView: ScopeEventFactory =
wtfCreateScope('AppViewManager#createRootHostView()');
/**
* Load component view into existing element.
*
Expand Down Expand Up @@ -139,6 +142,7 @@ export class AppViewManager {
*/
createRootHostView(hostProtoViewRef: ProtoViewRef, overrideSelector: string,
injector: Injector): HostViewRef {
var s = this._scope_createRootHostView();
var hostProtoView: viewModule.AppProtoView = internalProtoView(hostProtoViewRef);
var hostElementSelector = overrideSelector;
if (isBlank(hostElementSelector)) {
Expand All @@ -151,51 +155,58 @@ export class AppViewManager {

this._renderer.hydrateView(hostView.render);
this._utils.hydrateRootHostView(hostView, injector);

return hostView.ref;
return wtfLeave(s, hostView.ref);
}

_scope_destroyRootHostView: ScopeEventFactory =
wtfCreateScope('AppViewManager#destroyRootHostView()');
/**
* Remove the View created with {@link AppViewManager#createRootHostView}.
*/
destroyRootHostView(hostViewRef: HostViewRef) {
// Note: Don't put the hostView into the view pool
// as it is depending on the element for which it was created.
var s = this._scope_destroyRootHostView();
var hostView = internalView(<ViewRef>hostViewRef);
this._renderer.detachFragment(hostView.renderFragment);
this._renderer.dehydrateView(hostView.render);
this._viewDehydrateRecurse(hostView);
this._viewListener.viewDestroyed(hostView);
this._renderer.destroyView(hostView.render);
wtfLeave(s);
}

_scope_createEmbeddedViewInContainer: ScopeEventFactory = wtfCreateScope('AppViewManager#createEmbeddedViewInContainer()');
/**
*
* See {@link AppViewManager#destroyViewInContainer}.
*/
createEmbeddedViewInContainer(viewContainerLocation: ElementRef, atIndex: number,
templateRef: TemplateRef): ViewRef {
var s = this._scope_createEmbeddedViewInContainer();
var protoView = internalProtoView(templateRef.protoViewRef);
if (protoView.type !== ViewType.EMBEDDED) {
throw new BaseException('This method can only be called with embedded ProtoViews!');
}
return this._createViewInContainer(viewContainerLocation, atIndex, protoView,
templateRef.elementRef, null);
return wtfLeave(s, this._createViewInContainer(viewContainerLocation, atIndex, protoView,
templateRef.elementRef, null));
}

_scope_createHostViewInContainer: ScopeEventFactory = wtfCreateScope('AppViewManager#createHostViewInContainer()');
/**
*
* See {@link AppViewManager#destroyViewInContainer}.
*/
createHostViewInContainer(viewContainerLocation: ElementRef, atIndex: number,
protoViewRef: ProtoViewRef,
imperativelyCreatedInjector: ResolvedBinding[]): HostViewRef {
var s = this._scope_createHostViewInContainer();
var protoView = internalProtoView(protoViewRef);
if (protoView.type !== ViewType.HOST) {
throw new BaseException('This method can only be called with host ProtoViews!');
}
return this._createViewInContainer(viewContainerLocation, atIndex, protoView,
viewContainerLocation, imperativelyCreatedInjector);
return wtfLeave(s, this._createViewInContainer(viewContainerLocation, atIndex, protoView,
viewContainerLocation, imperativelyCreatedInjector));
}

/**
Expand Down Expand Up @@ -243,22 +254,27 @@ export class AppViewManager {
}
}

_scope_destroyViewInContainer = wtfCreateScope('AppViewMananger#destroyViewInContainer()');
/**
*
* See {@link AppViewManager#createViewInContainer}.
*/
destroyViewInContainer(viewContainerLocation: ElementRef, atIndex: number) {
var s = this._scope_destroyViewInContainer();
var parentView = internalView(viewContainerLocation.parentView);
var boundElementIndex = viewContainerLocation.boundElementIndex;
this._destroyViewInContainer(parentView, boundElementIndex, atIndex);
wtfLeave(s);
}

_scope_attachViewInContainer = wtfCreateScope('AppViewMananger#attachViewInContainer()');
/**
*
* See {@link AppViewManager#detachViewInContainer}.
*/
attachViewInContainer(viewContainerLocation: ElementRef, atIndex: number,
viewRef: ViewRef): ViewRef {
var s = this._scope_attachViewInContainer();
var view = internalView(viewRef);
var parentView = internalView(viewContainerLocation.parentView);
var boundElementIndex = viewContainerLocation.boundElementIndex;
Expand All @@ -270,21 +286,23 @@ export class AppViewManager {
// context view that might have been used.
this._utils.attachViewInContainer(parentView, boundElementIndex, null, null, atIndex, view);
this._attachRenderView(parentView, boundElementIndex, atIndex, view);
return viewRef;
return wtfLeave(s, viewRef);
}

_scope_detachViewInContainer = wtfCreateScope('AppViewMananger#detachViewInContainer()');
/**
*
* See {@link AppViewManager#attachViewInContainer}.
*/
detachViewInContainer(viewContainerLocation: ElementRef, atIndex: number): ViewRef {
var s = this._scope_detachViewInContainer();
var parentView = internalView(viewContainerLocation.parentView);
var boundElementIndex = viewContainerLocation.boundElementIndex;
var viewContainer = parentView.viewContainers[boundElementIndex];
var view = viewContainer.views[atIndex];
this._utils.detachViewInContainer(parentView, boundElementIndex, atIndex);
this._renderer.detachFragment(view.renderFragment);
return view.ref;
return wtfLeave(s, view.ref);
}

_createMainView(protoView: viewModule.AppProtoView,
Expand Down
5 changes: 5 additions & 0 deletions modules/angular2/src/core/life_cycle/life_cycle.ts
Expand Up @@ -2,6 +2,7 @@ import {Injectable} from 'angular2/di';
import {ChangeDetector} from 'angular2/src/change_detection/change_detection';
import {NgZone} from 'angular2/src/core/zone/ng_zone';
import {isPresent, BaseException} from 'angular2/src/facade/lang';
import {wtfLeave, wtfCreateScope, ScopeEventFactory} from 'angular2/src/core/wtf';

/**
* Provides access to explicitly trigger change detection in an application.
Expand Down Expand Up @@ -31,6 +32,8 @@ import {isPresent, BaseException} from 'angular2/src/facade/lang';
*/
@Injectable()
export class LifeCycle {
static _scope_tick: ScopeEventFactory = wtfCreateScope('LifeCycle#tick()');

_changeDetector: ChangeDetector;
_enforceNoNewChanges: boolean;
_runningTick: boolean = false;
Expand Down Expand Up @@ -71,6 +74,7 @@ export class LifeCycle {
throw new BaseException("LifeCycle.tick is called recursively");
}

var s = LifeCycle._scope_tick();
try {
this._runningTick = true;
this._changeDetector.detectChanges();
Expand All @@ -79,6 +83,7 @@ export class LifeCycle {
}
} finally {
this._runningTick = false;
wtfLeave(s);
}
}
}
76 changes: 76 additions & 0 deletions modules/angular2/src/core/wtf.ts
@@ -0,0 +1,76 @@
export {ScopeEventFactory} from './wtf_impl';

import * as impl from "./wtf_impl";

// Change exports to const once https://github.com/angular/ts2dart/issues/150

/**
* True if WTF is enabled.
*/
export var wtfEnabled = impl.detectWTF();

/**
* Create trace scope.
*
* Scopes must be strictly nested and are analogous to stack frames, but
* do not have to follow the stack frames. Instead it is recommended that they follow logical
* nesting. You may want to use
* [Event
* Signatures](http://google.github.io/tracing-framework/instrumenting-code.html#custom-events)
* as they are defined in WTF.
*
* Used to mark scope entry. The return value is used to leave the scope.
*
* final myScope = wtfCreateScope('MyClass#myMethod(ascii someVal)');
*
* someMethod() {
* var s = myScope('Foo'); // 'Foo' gets stored in tracing UI
* // DO SOME WORK HERE
* return wtfLeave(s, 123); // Return value 123
* }
*
* Note, adding try-finally block around the work to ensure that `wtfLeave` gets called can
* negatively impact the performance of your application. For this reason we recommend that
* you don't add them to ensure that `wtfLeave` gets called. In production `wtfLeave` is a noop and
* so try-finally block has no value. When debugging perf issues, skipping `wtfLeave`, do to
* exception, will produce incorrect trace, but presence of exception signifies logic error which
* needs to be fixed before the app should be profiled. Add try-finally only when you expect that
* an exception is expected during normal execution while profiling.
*
*/
export var wtfCreateScope: (signature: string, flags?: any) => impl.ScopeEventFactory =
wtfEnabled ? impl.createScope : (signature: string, flags?: any) => (arg0?: any, arg1?: any) =>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

have the return value share instance to conserve memory.

null;

/**
* Used to mark end of Scope.
*
* - `scope` to end.
* - `returnValue` (optional) to be passed to the WTF.
*
* Returns the `returnValue for easy chaining.
*/
export var wtfLeave:<T>(scope: any, returnValue?: T) => T = wtfEnabled ? impl.leave : (s, r?) => r;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

save instance, add types


/**
* Used to mark Async start. Async are similar to scope but they don't have to be strictly nested.
* The return value is used in the call to [endAsync]. Async ranges only work if WTF has been
* enabled.
*
* someMethod() {
* var s = wtfStartTimeRange('HTTP:GET', 'some.url');
* var future = new Future.delay(5).then((_) {
* wtfEndTimeRange(s);
* });
* }
*/
export var wtfStartTimeRange: (rangeType: string, action: string) => any =
wtfEnabled ? impl.startTimeRange : (rangeType: string, action: string) => null;

/**
* Ends a async time range operation.
* [range] is the return value from [wtfStartTimeRange] Async ranges only work if WTF has been
* enabled.
*/
export var wtfEndTimeRange: (range: any) => void = wtfEnabled ? impl.endTimeRange : (r: any) =>
null;