Skip to content

Commit

Permalink
fix(core): limit rate of markers invocations (#52742)
Browse files Browse the repository at this point in the history
This PR assures that the performance markers are invoked
only once for a given feature.

Closes #52524

PR Close #52742
  • Loading branch information
pkozlowski-opensource authored and thePunderWoman committed Nov 9, 2023
1 parent cfb42ee commit b16fc26
Show file tree
Hide file tree
Showing 14 changed files with 43 additions and 47 deletions.
4 changes: 2 additions & 2 deletions packages/common/http/src/transfer_cache.ts
Expand Up @@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/

import {APP_BOOTSTRAP_LISTENER, ApplicationRef, inject, InjectionToken, makeStateKey, Provider, StateKey, TransferState, ɵformatRuntimeError as formatRuntimeError, ɵperformanceMark as performanceMark, ɵtruncateMiddle as truncateMiddle, ɵwhenStable as whenStable} from '@angular/core';
import {APP_BOOTSTRAP_LISTENER, ApplicationRef, inject, InjectionToken, makeStateKey, Provider, StateKey, TransferState, ɵformatRuntimeError as formatRuntimeError, ɵperformanceMarkFeature as performanceMarkFeature, ɵtruncateMiddle as truncateMiddle, ɵwhenStable as whenStable} from '@angular/core';
import {Observable, of} from 'rxjs';
import {tap} from 'rxjs/operators';

Expand Down Expand Up @@ -227,7 +227,7 @@ export function withHttpTransferCache(cacheOptions: HttpTransferCacheOptions): P
{
provide: CACHE_OPTIONS,
useFactory: (): CacheOptions => {
performanceMark('mark_use_counter', {detail: {feature: 'NgHttpTransferCache'}});
performanceMarkFeature('NgHttpTransferCache');
return {isCacheActive: true, ...cacheOptions};
}
},
Expand Down
Expand Up @@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/

import {booleanAttribute, Directive, ElementRef, inject, Injector, Input, NgZone, numberAttribute, OnChanges, OnDestroy, OnInit, PLATFORM_ID, Renderer2, SimpleChanges, ɵformatRuntimeError as formatRuntimeError, ɵIMAGE_CONFIG as IMAGE_CONFIG, ɵIMAGE_CONFIG_DEFAULTS as IMAGE_CONFIG_DEFAULTS, ɵImageConfig as ImageConfig, ɵperformanceMark as performanceMark, ɵRuntimeError as RuntimeError, ɵSafeValue as SafeValue, ɵunwrapSafeValue as unwrapSafeValue} from '@angular/core';
import {booleanAttribute, Directive, ElementRef, inject, Injector, Input, NgZone, numberAttribute, OnChanges, OnDestroy, OnInit, PLATFORM_ID, Renderer2, SimpleChanges, ɵformatRuntimeError as formatRuntimeError, ɵIMAGE_CONFIG as IMAGE_CONFIG, ɵIMAGE_CONFIG_DEFAULTS as IMAGE_CONFIG_DEFAULTS, ɵImageConfig as ImageConfig, ɵperformanceMarkFeature as performanceMarkFeature, ɵRuntimeError as RuntimeError, ɵSafeValue as SafeValue, ɵunwrapSafeValue as unwrapSafeValue} from '@angular/core';

import {RuntimeErrorCode} from '../../errors';
import {isPlatformServer} from '../../platform_id';
Expand Down Expand Up @@ -302,7 +302,7 @@ export class NgOptimizedImage implements OnInit, OnChanges, OnDestroy {

/** @nodoc */
ngOnInit() {
performanceMark('mark_use_counter', {'detail': {'feature': 'NgOptimizedImage'}});
performanceMarkFeature('NgOptimizedImage');

if (ngDevMode) {
const ngZone = this.injector.get(NgZone);
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/core_private_export.ts
Expand Up @@ -41,6 +41,6 @@ export {booleanAttribute, numberAttribute} from './util/coercion';
export {devModeEqual as ɵdevModeEqual} from './util/comparison';
export {global as ɵglobal} from './util/global';
export {isPromise as ɵisPromise, isSubscribable as ɵisSubscribable} from './util/lang';
export {performanceMark as ɵperformanceMark} from './util/performance';
export {performanceMarkFeature as ɵperformanceMarkFeature} from './util/performance';
export {stringify as ɵstringify, truncateMiddle as ɵtruncateMiddle} from './util/stringify';
export {NOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR as ɵNOT_FOUND_CHECK_ONLY_ELEMENT_INJECTOR} from './view/provider_flags';
4 changes: 2 additions & 2 deletions packages/core/src/defer/instructions.ts
Expand Up @@ -29,7 +29,7 @@ import {isPlatformBrowser} from '../render3/util/misc_utils';
import {getConstant, getTNode, removeLViewOnDestroy, storeLViewOnDestroy} from '../render3/util/view_utils';
import {addLViewToLContainer, createAndRenderEmbeddedLView, removeLViewFromLContainer, shouldAddViewToDom} from '../render3/view_manipulation';
import {assertDefined, throwError} from '../util/assert';
import {performanceMark} from '../util/performance';
import {performanceMarkFeature} from '../util/performance';

import {invokeAllTriggerCleanupFns, invokeTriggerCleanupFns, storeTriggerCleanupFn} from './cleanup';
import {onHover, onInteraction, onViewport, registerDomTrigger} from './dom_triggers';
Expand Down Expand Up @@ -130,7 +130,7 @@ export function ɵɵdefer(
ɵɵtemplate(index, null, 0, 0);

if (tView.firstCreatePass) {
performanceMark('mark_use_counter', {detail: {feature: 'NgDefer'}});
performanceMarkFeature('NgDefer');

const tDetails: TDeferBlockDetails = {
primaryTmplIndex,
Expand Down
4 changes: 2 additions & 2 deletions packages/core/src/hydration/api.ts
Expand Up @@ -20,7 +20,7 @@ import {enableLocateOrCreateTextNodeImpl} from '../render3/instructions/text';
import {getDocument} from '../render3/interfaces/document';
import {isPlatformBrowser} from '../render3/util/misc_utils';
import {TransferState} from '../transfer_state';
import {performanceMark} from '../util/performance';
import {performanceMarkFeature} from '../util/performance';
import {NgZone} from '../zone';

import {cleanupDehydratedViews} from './cleanup';
Expand Down Expand Up @@ -137,7 +137,7 @@ export function withDomHydration(): EnvironmentProviders {
}
}
if (isEnabled) {
performanceMark('mark_use_counter', {detail: {feature: 'NgHydration'}});
performanceMarkFeature('NgHydration');
}
return isEnabled;
},
Expand Down
6 changes: 3 additions & 3 deletions packages/core/src/render3/after_render_hooks.ts
Expand Up @@ -13,7 +13,7 @@ import {ErrorHandler} from '../error_handler';
import {RuntimeError, RuntimeErrorCode} from '../errors';
import {DestroyRef} from '../linker/destroy_ref';
import {assertGreaterThan} from '../util/assert';
import {performanceMark} from '../util/performance';
import {performanceMarkFeature} from '../util/performance';
import {NgZone} from '../zone';

import {isPlatformBrowser} from './util/misc_utils';
Expand Down Expand Up @@ -225,7 +225,7 @@ export function afterRender(callback: VoidFunction, options?: AfterRenderOptions
return NOOP_AFTER_RENDER_REF;
}

performanceMark('mark_use_counter', {detail: {feature: 'NgAfterRender'}});
performanceMarkFeature('NgAfterRender');

const afterRenderEventManager = injector.get(AfterRenderEventManager);
// Lazily initialize the handler implementation, if necessary. This is so that it can be
Expand Down Expand Up @@ -301,7 +301,7 @@ export function afterNextRender(
return NOOP_AFTER_RENDER_REF;
}

performanceMark('mark_use_counter', {detail: {feature: 'NgAfterNextRender'}});
performanceMarkFeature('NgAfterNextRender');

const afterRenderEventManager = injector.get(AfterRenderEventManager);
// Lazily initialize the handler implementation, if necessary. This is so that it can be
Expand Down
7 changes: 2 additions & 5 deletions packages/core/src/render3/features/standalone_feature.ts
Expand Up @@ -10,7 +10,7 @@ import {ɵɵdefineInjectable as defineInjectable} from '../../di/interface/defs'
import {internalImportProvidersFrom} from '../../di/provider_collection';
import {EnvironmentInjector} from '../../di/r3_injector';
import {OnDestroy} from '../../interface/lifecycle_hooks';
import {performanceMark} from '../../util/performance';
import {performanceMarkFeature} from '../../util/performance';
import {ComponentDef} from '../interfaces/definition';
import {createEnvironmentInjector} from '../ng_module_ref';

Expand Down Expand Up @@ -61,9 +61,6 @@ class StandaloneService implements OnDestroy {
});
}

const PERF_MARK_STANDALONE = {
detail: {feature: 'NgStandalone'}
};

/**
* A feature that acts as a setup code for the {@link StandaloneService}.
Expand All @@ -76,7 +73,7 @@ const PERF_MARK_STANDALONE = {
* @codeGenApi
*/
export function ɵɵStandaloneFeature(definition: ComponentDef<unknown>) {
performanceMark('mark_use_counter', PERF_MARK_STANDALONE);
performanceMarkFeature('NgStandalone');
definition.getStandaloneInjector = (parentInjector: EnvironmentInjector) => {
return parentInjector.get(StandaloneService).getOrCreateStandaloneInjector(definition);
};
Expand Down
10 changes: 3 additions & 7 deletions packages/core/src/render3/instructions/control_flow.ts
Expand Up @@ -12,7 +12,7 @@ import {TrackByFunction} from '../../change_detection';
import {DehydratedContainerView} from '../../hydration/interfaces';
import {findMatchingDehydratedView} from '../../hydration/views';
import {assertDefined} from '../../util/assert';
import {performanceMark} from '../../util/performance';
import {performanceMarkFeature} from '../../util/performance';
import {assertLContainer, assertLView, assertTNode} from '../assert';
import {bindingUpdated} from '../bindings';
import {CONTAINER_HEADER_OFFSET, LContainer} from '../interfaces/container';
Expand All @@ -27,10 +27,6 @@ import {addLViewToLContainer, createAndRenderEmbeddedLView, getLViewFromLContain

import {ɵɵtemplate} from './template';

const PERF_MARK_CONTROL_FLOW = {
detail: {feature: 'NgControlFlow'}
};

/**
* The conditional instruction represents the basic building block on the runtime side to support
* built-in "if" and "switch". On the high level this instruction is responsible for adding and
Expand All @@ -43,7 +39,7 @@ const PERF_MARK_CONTROL_FLOW = {
* @codeGenApi
*/
export function ɵɵconditional<T>(containerIndex: number, matchingTemplateIndex: number, value?: T) {
performanceMark('mark_use_counter', PERF_MARK_CONTROL_FLOW);
performanceMarkFeature('NgControlFlow');

const hostLView = getLView();
const bindingIndex = nextBindingIndex();
Expand Down Expand Up @@ -149,7 +145,7 @@ export function ɵɵrepeaterCreate(
tagName: string|null, attrsIndex: number|null, trackByFn: TrackByFunction<unknown>,
trackByUsesComponentInstance?: boolean, emptyTemplateFn?: ComponentTemplate<unknown>,
emptyDecls?: number, emptyVars?: number): void {
performanceMark('mark_use_counter', PERF_MARK_CONTROL_FLOW);
performanceMarkFeature('NgControlFlow');
const hasEmptyBlock = emptyTemplateFn !== undefined;
const hostLView = getLView();
const boundTrackBy = trackByUsesComponentInstance ?
Expand Down
15 changes: 9 additions & 6 deletions packages/core/src/util/performance.ts
Expand Up @@ -6,17 +6,20 @@
* found in the LICENSE file at https://angular.io/license
*/

const markedFeatures = new Set<string>();

// tslint:disable:ban
/**
* A guarded `performance.mark`.
* A guarded `performance.mark` for feature marking.
*
* This method exists because while all supported browser and node.js version supported by Angular
* support performance.mark API. This is not the case for other environments such as JSDOM and
* Cloudflare workers.
*/
export function performanceMark(
markName: string,
markOptions?: PerformanceMarkOptions|undefined,
): PerformanceMark|undefined {
return performance?.mark?.(markName, markOptions);
export function performanceMarkFeature(feature: string): void {
if (markedFeatures.has(feature)) {
return;
}
markedFeatures.add(feature);
performance?.mark?.('mark_use_counter', {detail: {feature}});
}
Expand Up @@ -404,9 +404,6 @@
{
"name": "PARAM_REGEX"
},
{
"name": "PERF_MARK_STANDALONE"
},
{
"name": "PLATFORM_DESTROY_LISTENERS"
},
Expand Down Expand Up @@ -1208,6 +1205,9 @@
{
"name": "markViewForRefresh"
},
{
"name": "markedFeatures"
},
{
"name": "maybeWrapInNotSelector"
},
Expand Down
8 changes: 4 additions & 4 deletions packages/core/test/bundling/defer/bundle.golden_symbols.json
Expand Up @@ -374,9 +374,6 @@
{
"name": "Observable"
},
{
"name": "PERF_MARK_STANDALONE"
},
{
"name": "PLATFORM_DESTROY_LISTENERS"
},
Expand Down Expand Up @@ -2144,6 +2141,9 @@
{
"name": "markViewForRefresh"
},
{
"name": "markedFeatures"
},
{
"name": "maybeWrapInNotSelector"
},
Expand Down Expand Up @@ -2199,7 +2199,7 @@
"name": "onLeave"
},
{
"name": "performanceMark"
"name": "performanceMarkFeature"
},
{
"name": "populateDehydratedViewsInLContainer"
Expand Down
Expand Up @@ -374,9 +374,6 @@
{
"name": "Observable"
},
{
"name": "PERF_MARK_STANDALONE"
},
{
"name": "PLATFORM_DESTROY_LISTENERS"
},
Expand Down Expand Up @@ -1103,6 +1100,9 @@
{
"name": "markViewForRefresh"
},
{
"name": "markedFeatures"
},
{
"name": "maybeWrapInNotSelector"
},
Expand Down Expand Up @@ -1167,7 +1167,7 @@
"name": "onLeave"
},
{
"name": "performanceMark"
"name": "performanceMarkFeature"
},
{
"name": "populateDehydratedViewsInLContainerImpl"
Expand Down
6 changes: 3 additions & 3 deletions packages/core/test/bundling/router/bundle.golden_symbols.json
Expand Up @@ -527,9 +527,6 @@
{
"name": "OutletInjector"
},
{
"name": "PERF_MARK_STANDALONE"
},
{
"name": "PLATFORM_DESTROY_LISTENERS"
},
Expand Down Expand Up @@ -1700,6 +1697,9 @@
{
"name": "markViewForRefresh"
},
{
"name": "markedFeatures"
},
{
"name": "match"
},
Expand Down
Expand Up @@ -296,9 +296,6 @@
{
"name": "Observable"
},
{
"name": "PERF_MARK_STANDALONE"
},
{
"name": "PLATFORM_DESTROY_LISTENERS"
},
Expand Down Expand Up @@ -890,6 +887,9 @@
{
"name": "markViewForRefresh"
},
{
"name": "markedFeatures"
},
{
"name": "maybeWrapInNotSelector"
},
Expand Down

0 comments on commit b16fc26

Please sign in to comment.