Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
bcf7f9d
add tests for Profiler
Linchenn Jul 14, 2020
c2441ee
decouple Profiler.profileKernel
Linchenn Jul 14, 2020
5e4ef9f
use new Profiler
Linchenn Jul 14, 2020
125c5dd
fix
Linchenn Jul 14, 2020
7ef411e
move logging into scopedRun
Linchenn Jul 15, 2020
0009b81
Merge branch 'master' into decoupleProfilerLog
Linchenn Jul 15, 2020
74fdc92
change profileKernel return type from KernelProfile[] to KernelProfile
Linchenn Jul 16, 2020
00cb802
Merge branch 'master' into decoupleProfilerLog
Linchenn Jul 16, 2020
aa77a6c
Merge branch 'master' into decoupleProfilerLog
pyu10055 Jul 17, 2020
5571602
Merge branch 'master' into decoupleProfilerLog
Linchenn Jul 17, 2020
b8346dd
Merge branch 'master' into decoupleProfilerLog
Linchenn Jul 19, 2020
e48efcb
delete vals
Linchenn Jul 20, 2020
7ea1f79
Merge branch 'master' into decoupleProfilerLog
Linchenn Jul 20, 2020
a6e3e98
Merge branch 'master' into decoupleProfilerLog
Linchenn Jul 21, 2020
8e244f6
fix
Linchenn Jul 21, 2020
31cd1fb
Merge branch 'master' into decoupleProfilerLog
Linchenn Jul 22, 2020
e6648d4
Merge branch 'master' into decoupleProfilerLog
Linchenn Jul 22, 2020
a1ebf12
Merge branch 'master' into decoupleProfilerLog
Linchenn Jul 23, 2020
5f76bee
Merge branch 'master' into decoupleProfilerLog
Linchenn Jul 24, 2020
a41e9d1
Merge branch 'master' into decoupleProfilerLog
Linchenn Jul 24, 2020
41f7e62
Merge branch 'master' into decoupleProfilerLog
Linchenn Jul 27, 2020
ae0d5a6
Merge branch 'master' into decoupleProfilerLog
pyu10055 Jul 27, 2020
967829b
Merge branch 'master' into decoupleProfilerLog
pyu10055 Jul 30, 2020
faf0731
Merge branch 'master' into decoupleProfilerLog
pyu10055 Jul 30, 2020
25ce6eb
Merge branch 'master' into decoupleProfilerLog
Linchenn Jul 30, 2020
ef1b9e8
try fixing memory error
Linchenn Jul 31, 2020
b89996e
fix
Linchenn Jul 31, 2020
7a08c29
Merge branch 'master' into decoupleProfilerLog
Linchenn Jul 31, 2020
6b7afed
Merge branch 'master' into decoupleProfilerLog
Linchenn Aug 3, 2020
ac98440
Merge branch 'master' into decoupleProfilerLog
Linchenn Aug 3, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions tfjs-core/src/engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {BackendTimingInfo, DataMover, KernelBackend} from './backends/backend';
import {Environment, setEnvironmentGlobal} from './environment';
import {getGlobalNamespace} from './global_util';
import {getGradient, getKernel, getKernelsForBackend, GradFunc, NamedAttrMap, TensorInfo} from './kernel_registry';
import {Profiler} from './profiler';
import {KernelProfile, Profiler} from './profiler';
import {backpropagateGradients, getFilteredNodesXToY, TapeNode} from './tape';
import {DataId, setTensorTracker, Tensor, TensorTracker, Variable} from './tensor';
import {GradSaveFunc, NamedTensorMap, NamedVariableMap, TensorContainer} from './tensor_types';
Expand Down Expand Up @@ -51,7 +51,7 @@ export type MemoryInfo = {
unreliable?: boolean; reasons: string[];
};

type KernelProfile = {
type KernelInfo = {
name: string; bytesAdded: number; totalBytesSnapshot: number;
tensorsAdded: number;
totalTensorsSnapshot: number;
Expand All @@ -61,7 +61,7 @@ type KernelProfile = {

export type ProfileInfo = {
newBytes: number; newTensors: number; peakBytes: number;
kernels: KernelProfile[];
kernels: KernelInfo[];
result: TensorContainer;
};

Expand Down Expand Up @@ -618,8 +618,11 @@ export class Engine implements TensorTracker, DataMover {
if (!this.ENV.getBool('DEBUG')) {
outputs = kernelFunc();
} else {
outputs = this.profiler.profileKernel(
let kernelProfile: KernelProfile;
kernelProfile = this.profiler.profileKernel(
kernelName, inputs, () => kernelFunc());
this.profiler.logKernelProfile(kernelProfile);
outputs = kernelProfile.outputs;
}
});

Expand Down
48 changes: 34 additions & 14 deletions tfjs-core/src/profiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@ import {NamedTensorMap} from './tensor_types';
import {DataType, DataTypeMap, TypedArray} from './types';
import * as util from './util';

export type KernelProfile = {
kernelName: string,
outputs: Tensor[],
inputs: NamedTensorMap,
timeMs: Promise<number|{error: string}>,
extraInfo: Promise<string>
};

export class Profiler {
constructor(private backendTimer: BackendTimer, private logger?: Logger) {
if (logger == null) {
Expand All @@ -29,32 +37,44 @@ export class Profiler {
}

profileKernel(kernelName: string, inputs: NamedTensorMap, f: () => Tensor[]):
Tensor[] {
KernelProfile {
let outputs: Tensor[];
const holdResultWrapperFn = () => {
outputs = f();
};
const timer = this.backendTimer.time(holdResultWrapperFn);

outputs.forEach(r => {
outputs.map(r => {
// Dangling promise here because we don't want to propagate up
// asynchronicity.
r.data().then(vals => {
checkComputationForErrors(vals, r.dtype, kernelName);
r.data().then(tensorVals => {
checkComputationForErrors(tensorVals, r.dtype, kernelName);
});
});

timer.then(timing => {
let extraInfo = '';
if (timing.getExtraProfileInfo != null) {
extraInfo = timing.getExtraProfileInfo();
}
const kernelProfile = {
kernelName,
outputs,
inputs,
timeMs: timer.then(timing => timing.kernelMs),
extraInfo: timer.then(
timing => timing.getExtraProfileInfo != null ?
timing.getExtraProfileInfo() :
'')
};
return kernelProfile;
}

logKernelProfile(kernelProfile: KernelProfile): void {
const {kernelName, outputs, timeMs, inputs, extraInfo} = kernelProfile;

this.logger.logKernelProfile(
kernelName, r, vals, timing.kernelMs, inputs, extraInfo);
});
outputs.forEach(result => {
Promise.all([result.data(), timeMs, extraInfo]).then(valueContainer => {
this.logger.logKernelProfile(
kernelName, result, valueContainer[0], valueContainer[1], inputs,
valueContainer[2]);
});
});

return outputs;
}
}

Expand Down
112 changes: 86 additions & 26 deletions tfjs-core/src/profiler_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@
import {BackendTimer, BackendTimingInfo} from './backends/backend';
import * as tf from './index';
import {describeWithFlags, SYNC_BACKEND_ENVS} from './jasmine_util';
import {checkComputationForErrors, Logger, Profiler} from './profiler';
import {checkComputationForErrors, KernelProfile, Logger, Profiler} from './profiler';
import {Tensor} from './tensor';
import {NamedTensorMap} from './tensor_types';
import {TypedArray} from './types';

class TestBackendTimer implements BackendTimer {
Expand All @@ -42,6 +43,32 @@ class TestLogger extends Logger {
name: string, result: Tensor, vals: TypedArray, timeMs: number) {}
}

function promiseCheckWrapper(acturalValPromise: Promise<{}>, truthVal: {}) {
return acturalValPromise.then(acturalVal => {
expect(acturalVal).toEqual(truthVal);
});
}

function checkKernelProfile(acturalVal: KernelProfile, truthVal: {
kernelName: string,
outputs: Tensor[],
timeMs: number|{error: string},
inputs: NamedTensorMap,
extraInfo: string
}) {
expect(acturalVal.kernelName).toBe(truthVal.kernelName);
expect(acturalVal.inputs).toBe(truthVal.inputs);
acturalVal.outputs.forEach((output, index) => {
expect(output).toBe(truthVal.outputs[index]);
});

const promiseContainer = [
promiseCheckWrapper(acturalVal.timeMs, truthVal.timeMs),
promiseCheckWrapper(acturalVal.extraInfo, truthVal.extraInfo),
];
return Promise.all(promiseContainer);
}

describeWithFlags('profiler.Profiler', SYNC_BACKEND_ENVS, () => {
it('profiles simple function', doneFn => {
const delayMs = 5;
Expand All @@ -56,29 +83,26 @@ describeWithFlags('profiler.Profiler', SYNC_BACKEND_ENVS, () => {
spyOn(logger, 'logKernelProfile').and.callThrough();

const timeSpy = timer.time as jasmine.Spy;
const logKernelProfileSpy = logger.logKernelProfile as jasmine.Spy;

let kernelCalled = false;
const result = 1;
const resultScalar = tf.scalar(result);

profiler.profileKernel('MatMul', inputs, () => {
const kernelProfile = profiler.profileKernel('MatMul', inputs, () => {
kernelCalled = true;
return [resultScalar];
});

setTimeout(() => {
expect(timeSpy.calls.count()).toBe(1);

expect(logKernelProfileSpy.calls.count()).toBe(1);

expect(logKernelProfileSpy.calls.first().args).toEqual([
'MatMul', resultScalar, new Float32Array([result]), queryTimeMs, inputs,
extraInfo
]);

expect(kernelCalled).toBe(true);
doneFn();

checkKernelProfile(kernelProfile, {
kernelName: 'MatMul',
outputs: [resultScalar],
timeMs: queryTimeMs,
inputs,
extraInfo,
}).then(() => doneFn());
}, delayMs * 2);
});

Expand All @@ -95,37 +119,73 @@ describeWithFlags('profiler.Profiler', SYNC_BACKEND_ENVS, () => {
spyOn(timer, 'time').and.callThrough();
spyOn(logger, 'logKernelProfile').and.callThrough();
const timeSpy = timer.time as jasmine.Spy;
const logKernelProfileSpy = logger.logKernelProfile as jasmine.Spy;

let matmulKernelCalled = false;
let maxKernelCalled = false;
const result = 1;
const resultScalar = tf.scalar(result);

profiler.profileKernel('MatMul', inputs, () => {
const result = profiler.profileKernel('Max', inputs, () => {
let innerKernelProfile: KernelProfile;
const outerKernelProfile = profiler.profileKernel('MatMul', inputs, () => {
innerKernelProfile = profiler.profileKernel('Max', inputs, () => {
maxKernelCalled = true;
return [resultScalar];
});
matmulKernelCalled = true;
return result;
return innerKernelProfile.outputs;
});

setTimeout(() => {
expect(timeSpy.calls.count()).toBe(2);
expect(matmulKernelCalled).toBe(true);
expect(maxKernelCalled).toBe(true);

const checkInnerKernelProfile = checkKernelProfile(innerKernelProfile, {
kernelName: 'Max',
outputs: [resultScalar],
timeMs: queryTimeMs,
inputs,
extraInfo
});
const checkOuterKernelProfile = checkKernelProfile(outerKernelProfile, {
kernelName: 'MatMul',
outputs: [resultScalar],
timeMs: queryTimeMs * 2,
inputs,
extraInfo
});
Promise.all([checkInnerKernelProfile, checkOuterKernelProfile])
.then(() => doneFn());
}, delayMs * 2);
});

it('log kernelProfile', doneFn => {
const delayMs = 5;
const queryTimeMs = 10;
const inputs = {'x': tf.tensor1d([1])};
const extraInfo = '';
const timer = new TestBackendTimer(delayMs, queryTimeMs, extraInfo);
const logger = new TestLogger();
const profiler = new Profiler(timer, logger);

spyOn(logger, 'logKernelProfile').and.callThrough();
const logKernelProfileSpy = logger.logKernelProfile as jasmine.Spy;

const result = 1;
const resultScalar = tf.scalar(result);

const kernelProfiles = profiler.profileKernel('MatMul', inputs, () => {
return [resultScalar];
});
profiler.logKernelProfile(kernelProfiles);

setTimeout(() => {
expect(logKernelProfileSpy.calls.count()).toBe(1);

expect(logKernelProfileSpy.calls.count()).toBe(2);
expect(logKernelProfileSpy.calls.first().args).toEqual([
'Max', resultScalar, new Float32Array([result]), queryTimeMs, inputs,
'MatMul', resultScalar, new Float32Array([result]), queryTimeMs, inputs,
extraInfo
]);
expect(logKernelProfileSpy.calls.argsFor(1)).toEqual([
'MatMul', resultScalar, new Float32Array([result]), queryTimeMs * 2,
inputs, extraInfo
]);

expect(matmulKernelCalled).toBe(true);
expect(maxKernelCalled).toBe(true);
doneFn();
}, delayMs * 2);
});
Expand Down