test(ivy): clean up class_binding perf tests for readability (#33413)

PR Close #33413
This commit is contained in:
Miško Hevery 2019-10-25 13:55:43 -07:00 committed by Andrew Kushnir
parent 26f44c0d6b
commit 7a280b1a21
2 changed files with 198 additions and 136 deletions

View File

@ -7,159 +7,221 @@
*/ */
import {ɵɵproperty} from '@angular/core/src/core'; import {ɵɵproperty} from '@angular/core/src/core';
import {AttributeMarker, TAttributes} from '@angular/core/src/render3/interfaces/node'; import {AttributeMarker, TAttributes} from '@angular/core/src/render3/interfaces/node';
import {ɵɵelement} from '../../../../src/render3/instructions/element'; import {ɵɵelement} from '../../../../src/render3/instructions/element';
import {ɵɵclassMap, ɵɵclassProp} from '../../../../src/render3/instructions/styling'; import {ɵɵclassMap, ɵɵclassProp} from '../../../../src/render3/instructions/styling';
import {ComponentTemplate, RenderFlags} from '../../../../src/render3/interfaces/definition'; import {ComponentTemplate, RenderFlags} from '../../../../src/render3/interfaces/definition';
import {createBenchmark} from '../micro_bench'; import {Benchmark, createBenchmark} from '../micro_bench';
import {setupTestHarness} from '../setup'; import {setupTestHarness} from '../setup';
const PROFILE_CREATE = true;
const PROFILE_UPDATE = true;
const PROFILE_NOOP = true;
const CLASSES_1_A = 'one';
const CLASSES_1_B = CLASSES_1_A.toUpperCase(); function benchmark(
const CLASSES_2_A = 'one two'; name: string, template: ComponentTemplate<any>, baselineTemplate: ComponentTemplate<any>) {
const CLASSES_2_B = CLASSES_2_A.toUpperCase(); const ivyHarness = setupTestHarness(template, 1, 1, 1000, context, consts);
const CLASSES_10_A = 'one two three four five six seven eight nine ten'; const baseHarness = setupTestHarness(baselineTemplate, 1, 1, 1000, context, consts);
const CLASSES_10_B = CLASSES_10_A.toUpperCase();
let toggleClasses = true; if (PROFILE_CREATE) {
const benchmark = createBenchmark('class binding[create]: ' + name);
benchmarks.push(benchmark);
const ivyProfile = benchmark('styling');
console.profile(benchmark.name + ':' + ivyProfile.name);
while (ivyProfile()) {
ivyHarness.createEmbeddedLView();
}
console.profileEnd();
const baseProfile = benchmark('base');
console.profile(benchmark.name + ':' + baseProfile.name);
while (baseProfile()) {
baseHarness.createEmbeddedLView();
}
console.profileEnd();
}
if (PROFILE_UPDATE) {
const benchmark = createBenchmark('class binding[update]: ' + name);
benchmarks.push(benchmark);
const ivyProfile = benchmark('styling');
console.profile(benchmark.name + ':' + ivyProfile.name);
while (ivyProfile()) {
toggle = !toggle;
ivyHarness.detectChanges();
}
console.profileEnd();
const baseProfile = benchmark('base');
console.profile(benchmark.name + ':' + baseProfile.name);
while (baseProfile()) {
toggle = !toggle;
baseHarness.detectChanges();
}
console.profileEnd();
}
if (PROFILE_NOOP) {
const benchmark = createBenchmark('class binding[noop]: ' + name);
benchmarks.push(benchmark);
const ivyProfile = benchmark('styling');
console.profile(benchmark.name + ':' + ivyProfile.name);
while (ivyProfile()) {
ivyHarness.detectChanges();
}
console.profileEnd();
const baseProfile = benchmark('base');
console.profile(benchmark.name + ':' + baseProfile.name);
while (baseProfile()) {
baseHarness.detectChanges();
}
console.profileEnd();
}
}
const A_1 = 'one';
const B_1 = A_1.toUpperCase();
const A_10 = 'one two three four five six seven eight nine ten';
const B_10 = A_10.toUpperCase();
let toggle = true;
const consts: TAttributes[] = [ const consts: TAttributes[] = [
[AttributeMarker.Classes, 'A', 'B'] // 0 [AttributeMarker.Classes, 'A', 'B'] // 0
]; ];
const context: any = {}; const context: any = {};
const createClassBindingBenchmark = createBenchmark('class binding: create:'); const benchmarks: Benchmark[] = [];
const updateClassBindingBenchmark = createBenchmark('class binding: update:');
const noopClassBindingBenchmark = createBenchmark('class binding: noop:');
function benchmark(name: string, template: ComponentTemplate<any>) {
const harness = setupTestHarness(template, 1, 1, 1000, context, consts);
const createProfile = createClassBindingBenchmark(name);
console.profile('create: ' + name);
while (createProfile()) {
harness.createEmbeddedLView();
}
console.profileEnd();
const updateProfile = updateClassBindingBenchmark(name);
console.profile('update: ' + name);
while (updateProfile()) {
toggleClasses = !toggleClasses;
harness.detectChanges();
}
console.profileEnd();
const noopProfile = noopClassBindingBenchmark(name);
console.profile('nop: ' + name);
while (noopProfile()) {
harness.detectChanges();
}
console.profileEnd();
}
`<div [class]="toggleClasses ? CLASSES_1_A : CLASSES_1_B">`;
benchmark(`[class]="CLASSES_1"`, function(rf: RenderFlags, ctx: any) {
if (rf & 1) {
ɵɵelement(0, 'div');
}
if (rf & 2) {
ɵɵclassMap(toggleClasses ? CLASSES_1_A : CLASSES_1_B);
}
});
`<div [class]="toggleClasses ? CLASSES_2_A : CLASSES_2_B">`;
benchmark(`[class]="CLASSES_2"`, function(rf: RenderFlags, ctx: any) {
if (rf & 1) {
ɵɵelement(0, 'div');
}
if (rf & 2) {
ɵɵclassMap(toggleClasses ? CLASSES_2_A : CLASSES_2_B);
}
});
`<div [class]="toggleClasses ? CLASSES_10_A : CLASSES_10_B">`;
benchmark(`[class]="CLASSES_10"`, function(rf: RenderFlags, ctx: any) {
if (rf & 1) {
ɵɵelement(0, 'div');
}
if (rf & 2) {
ɵɵclassMap(toggleClasses ? CLASSES_10_A : CLASSES_10_B);
}
});
`<div class="A B">`;
benchmark(`class="A B"`, function(rf: RenderFlags, ctx: any) {
if (rf & 1) {
ɵɵelement(0, 'div', 0);
}
if (rf & 2) {
}
});
`<div class="A B"
[class]="toggleClasses ? CLASSES_1_A : CLASSES_1_B">`;
benchmark(`class="A B" [class]="CLASSES_1"`, function(rf: RenderFlags, ctx: any) {
if (rf & 1) {
ɵɵelement(0, 'div', 0);
}
if (rf & 2) {
ɵɵclassMap(toggleClasses ? CLASSES_1_A : CLASSES_1_B);
}
});
`<div class="A B"
[class]="toggleClasses ? CLASSES_10_A : CLASSES_10_B">`;
benchmark(`class="A B" [class]="CLASSES_10"`, function(rf: RenderFlags, ctx: any) {
if (rf & 1) {
ɵɵelement(0, 'div', 0);
}
if (rf & 2) {
ɵɵclassMap(toggleClasses ? CLASSES_10_A : CLASSES_10_B);
}
});
`<div class="A B"
[class]="toggleClasses ? CLASSES_1_A : CLASSES_1_B"
[class.foo]="toggleClasses">`;
benchmark(`class="A B" [class]="CLASSES_1" [class.foo]="exp"`, function(rf: RenderFlags, ctx: any) {
if (rf & 1) {
ɵɵelement(0, 'div', 0);
}
if (rf & 2) {
ɵɵclassMap(toggleClasses ? CLASSES_1_A : CLASSES_1_B);
ɵɵclassProp('foo', toggleClasses);
}
});
`<div class="A B"
[class]="toggleClasses ? CLASSES_10_A : CLASSES_10_B"
[class.foo]="toggleClasses">`;
benchmark( benchmark(
`class="A B" [class]="CLASSES_10" [class.foo]="exp"`, function(rf: RenderFlags, ctx: any) { `<div class="A B">`,
function(rf: RenderFlags, ctx: any) {
if (rf & 1) { if (rf & 1) {
ɵɵelement(0, 'div', 0); ɵɵelement(0, 'div', 0);
} }
if (rf & 2) { },
ɵɵclassMap(toggleClasses ? CLASSES_10_A : CLASSES_10_B); function(rf: RenderFlags, ctx: any) {
ɵɵclassProp('foo', toggleClasses); if (rf & 1) {
ɵɵelement(0, 'div', 1);
} }
}); });
`<div [className]="toggleClasses ? CLASSES_10_A : CLASSES_10_B">`; benchmark(
benchmark(`[className]="CLASSES_10"`, function(rf: RenderFlags, ctx: any) { `<div [class]="toggle ? A_1 : B_1">`,
if (rf & 1) { function(rf: RenderFlags, ctx: any) {
ɵɵelement(0, 'div'); if (rf & 1) {
} ɵɵelement(0, 'div');
if (rf & 2) { }
ɵɵproperty('className', toggleClasses ? CLASSES_10_A : CLASSES_10_B); if (rf & 2) {
} ɵɵclassMap(toggle ? A_1 : B_1);
}); }
},
function(rf: RenderFlags, ctx: any) {
if (rf & 1) {
ɵɵelement(0, 'div');
}
if (rf & 2) {
ɵɵproperty('className', toggle ? A_1 : B_1);
}
});
createClassBindingBenchmark.report(); benchmark(
updateClassBindingBenchmark.report(); `<div [class]="toggle ? A_10 : B_10">`,
noopClassBindingBenchmark.report(); function(rf: RenderFlags, ctx: any) {
if (rf & 1) {
ɵɵelement(0, 'div');
}
if (rf & 2) {
ɵɵclassMap(toggle ? A_10 : B_10);
}
},
function(rf: RenderFlags, ctx: any) {
if (rf & 1) {
ɵɵelement(0, 'div');
}
if (rf & 2) {
ɵɵproperty('className', toggle ? A_10 : B_10);
}
});
benchmark(
`<div [class]="toggle ? A_1 : B_1">`,
function(rf: RenderFlags, ctx: any) {
if (rf & 1) {
ɵɵelement(0, 'div');
}
if (rf & 2) {
ɵɵclassMap(toggle ? A_1 : B_1);
}
},
function(rf: RenderFlags, ctx: any) {
if (rf & 1) {
ɵɵelement(0, 'div');
}
if (rf & 2) {
ɵɵproperty('className', toggle ? A_1 : B_1);
}
});
benchmark(
`<div class="A B" [class]="toggle ? A_1 : B_1">`,
function(rf: RenderFlags, ctx: any) {
if (rf & 1) {
ɵɵelement(0, 'div', 0);
}
if (rf & 2) {
ɵɵclassMap(toggle ? A_1 : B_1);
}
},
function(rf: RenderFlags, ctx: any) {
if (rf & 1) {
ɵɵelement(0, 'div', 1);
}
if (rf & 2) {
ɵɵproperty('className', toggle ? A_1 : B_1);
}
});
benchmark(
`<div class="A B" [class]="toggle ? A_10 : B_10">`,
function(rf: RenderFlags, ctx: any) {
if (rf & 1) {
ɵɵelement(0, 'div', 0);
}
if (rf & 2) {
ɵɵclassMap(toggle ? A_10 : B_10);
}
},
function(rf: RenderFlags, ctx: any) {
if (rf & 1) {
ɵɵelement(0, 'div', 1);
}
if (rf & 2) {
ɵɵproperty('className', toggle ? A_10 : B_10);
}
});
benchmark(
`<div class="A B" [class]="toggle ? A_1 : B_1" [class.foo]="toggle">`,
function(rf: RenderFlags, ctx: any) {
if (rf & 1) {
ɵɵelement(0, 'div', 0);
}
if (rf & 2) {
ɵɵclassMap(toggle ? A_1 : B_1);
ɵɵclassProp('foo', toggle);
}
},
function(rf: RenderFlags, ctx: any) {
if (rf & 1) {
ɵɵelement(0, 'div', 1);
}
if (rf & 2) {
ɵɵproperty('className', toggle ? A_1 + 'foo' : B_1);
}
});
benchmarks.forEach(b => b.report());

View File

@ -43,7 +43,7 @@ export function createBenchmark(benchmarkName: string): Benchmark {
iterationCounter = profile.iterationCount; iterationCounter = profile.iterationCount;
runAgain = true; runAgain = true;
// tslint:disable-next-line:no-console // tslint:disable-next-line:no-console
console.log(profileName, '...'); console.log(benchmarkName, profileName, '...');
} else { } else {
profile.sampleCount++; profile.sampleCount++;
// we came to an end of a sample, compute the time. // we came to an end of a sample, compute the time.