Skip to content

Commit

Permalink
Bug 1914235 [wpt PR 47718] - WebNN: add buffer usages for DML backend…
Browse files Browse the repository at this point in the history
…, a=testonly

Automatic update from web-platform-tests
WebNN: add buffer usages for DML backend

Exposes MLBufferUsageFlags to MLBufferDescriptor and adds new usages to
maximize device memory bandwidth. After this change, createBuffer()
assumes "no usage" by default. To readBuffer() or writeBuffer(), the
corresponding usage flag must be specified by the web developer.
Combining usages is allowed but could be inefficient. Usages are
always validated even if a backend doesn't use it.

webmachinelearning/webnn#542

Bug: 343638938
Change-Id: I4d78e3f8bacd7cbabce3038c234c062c7c07b095
Cq-Include-Trybots: luci.chromium.try​:win11-blink-rel
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5787041
Commit-Queue: Bryan Bernhart <[email protected]>
Reviewed-by: Alex Gough <[email protected]>
Reviewed-by: ningxin hu <[email protected]>
Reviewed-by: Austin Sullivan <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1344910}

--

wpt-commits: f21d93823c4ca8b1cb01b3ff1730af9c049840e5
wpt-pr: 47718
  • Loading branch information
bbernhar authored and moz-wptsync-bot committed Aug 23, 2024
1 parent cf5542c commit f4c5ea8
Show file tree
Hide file tree
Showing 4 changed files with 155 additions and 46 deletions.
105 changes: 80 additions & 25 deletions testing/web-platform/tests/webnn/conformance_tests/buffer.https.any.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,11 @@ const sizeOfDescriptor = (descriptor) => {
};

const getDescriptorFromBuffer = (buffer) => {
return {dataType: buffer.dataType, dimensions: buffer.shape};
return {
dataType: buffer.dataType,
dimensions: buffer.shape,
usage: buffer.usage
};
};


Expand Down Expand Up @@ -160,7 +164,11 @@ const testWriteWebNNBuffer = (testName) => {
});

promise_test(async () => {
const bufferDescriptor = {dataType: 'int32', dimensions: [1]};
const bufferDescriptor = {
dataType: 'int32',
dimensions: [1],
usage: MLBufferUsage.WRITE_TO,
};
let mlBuffer = await mlContext.createBuffer(bufferDescriptor);

const bufferByteLength = sizeOfDescriptor(bufferDescriptor);
Expand Down Expand Up @@ -205,7 +213,11 @@ const testWriteWebNNBuffer = (testName) => {
}, `${testName} / error`);

promise_test(async () => {
const bufferDescriptor = {dataType: 'int32', dimensions: [2, 2]};
const bufferDescriptor = {
dataType: 'int32',
dimensions: [2, 2],
usage: MLBufferUsage.WRITE_TO,
};
let mlBuffer = await mlContext.createBuffer(bufferDescriptor);

// Writing data to a destroyed MLBuffer should throw.
Expand All @@ -218,7 +230,11 @@ const testWriteWebNNBuffer = (testName) => {
}, `${testName} / destroy`);

promise_test(async () => {
const bufferDescriptor = {dataType: 'int32', dimensions: [2, 3]};
const bufferDescriptor = {
dataType: 'int32',
dimensions: [2, 3],
usage: MLBufferUsage.WRITE_TO,
};
let mlBuffer = await mlContext.createBuffer(bufferDescriptor);

let anotherMLContext = await navigator.ml.createContext(contextOptions);
Expand All @@ -233,8 +249,11 @@ const testWriteWebNNBuffer = (testName) => {
}, `${testName} / context_mismatch`);

promise_test(async () => {
let mlBuffer =
await mlContext.createBuffer({dataType: 'int32', dimensions: [1]});
let mlBuffer = await mlContext.createBuffer({
dataType: 'int32',
dimensions: [1],
usage: MLBufferUsage.WRITE_TO | MLBufferUsage.READ_FROM,
});

// Initialize the buffer.
const inputData = Uint8Array.from([0xAA, 0xAA, 0xAA, 0xAA]);
Expand All @@ -253,7 +272,11 @@ const testWriteWebNNBuffer = (testName) => {
}, `${testName} / zero_write`);

promise_test(async () => {
const bufferDescriptor = {dataType: 'int32', dimensions: [2, 2]};
const bufferDescriptor = {
dataType: 'int32',
dimensions: [2, 2],
usage: MLBufferUsage.WRITE_TO | MLBufferUsage.READ_FROM,
};
let mlBuffer = await mlContext.createBuffer(bufferDescriptor);

const bufferByteLength = sizeOfDescriptor(bufferDescriptor);
Expand Down Expand Up @@ -300,8 +323,11 @@ const testReadWebNNBuffer = (testName) => {
});

promise_test(async t => {
let mlBuffer =
await mlContext.createBuffer({dataType: 'int32', dimensions: [2, 2]});
let mlBuffer = await mlContext.createBuffer({
dataType: 'int32',
dimensions: [2, 2],
usage: MLBufferUsage.READ_FROM,
});

// Reading a destroyed MLBuffer should reject.
mlBuffer.destroy();
Expand All @@ -311,8 +337,11 @@ const testReadWebNNBuffer = (testName) => {
}, `${testName} / read_after_destroy`);

promise_test(async t => {
let mlBuffer =
await mlContext.createBuffer({dataType: 'int32', dimensions: [2, 3]});
let mlBuffer = await mlContext.createBuffer({
dataType: 'int32',
dimensions: [2, 3],
usage: MLBufferUsage.READ_FROM,
});

let promise = mlContext.readBuffer(mlBuffer);
let anotherPromise = mlContext.readBuffer(mlBuffer);
Expand All @@ -324,16 +353,22 @@ const testReadWebNNBuffer = (testName) => {
}, `${testName} / read_before_destroy`);

promise_test(async () => {
let mlBuffer =
await mlContext.createBuffer({dataType: 'int32', dimensions: [1024]});
let mlBuffer = await mlContext.createBuffer({
dataType: 'int32',
dimensions: [1024],
usage: MLBufferUsage.READ_FROM,
});

await assert_buffer_data_equals(
mlContext, mlBuffer, new Uint32Array(1024));
}, `${testName} / uninitialized`);

promise_test(async () => {
let mlBuffer =
await mlContext.createBuffer({dataType: 'int32', dimensions: [1]});
let mlBuffer = await mlContext.createBuffer({
dataType: 'int32',
dimensions: [1],
usage: MLBufferUsage.READ_FROM | MLBufferUsage.WRITE_TO,
});

// Initialize the buffer.
mlContext.writeBuffer(mlBuffer, Uint8Array.from([0xAA, 0xAA, 0xAA, 0xAA]));
Expand All @@ -345,8 +380,11 @@ const testReadWebNNBuffer = (testName) => {
}, `${testName} / full_size`);

promise_test(async () => {
let mlBuffer =
await mlContext.createBuffer({dataType: 'int32', dimensions: [1]});
let mlBuffer = await mlContext.createBuffer({
dataType: 'int32',
dimensions: [1],
usage: MLBufferUsage.WRITE_TO | MLBufferUsage.READ_FROM,
});

// Initialize the buffer.
mlContext.writeBuffer(mlBuffer, Uint8Array.from([0xAA, 0xAA, 0xAA, 0xAA]));
Expand All @@ -360,8 +398,11 @@ const testReadWebNNBuffer = (testName) => {
}, `${testName} / src_offset_only`);

promise_test(async () => {
let mlBuffer =
await mlContext.createBuffer({dataType: 'int32', dimensions: [1]});
let mlBuffer = await mlContext.createBuffer({
dataType: 'int32',
dimensions: [1],
usage: MLBufferUsage.WRITE_TO | MLBufferUsage.READ_FROM,
});

// Initialize the buffer.
mlContext.writeBuffer(mlBuffer, Uint8Array.from([0xAA, 0xAA, 0xAA, 0xAA]));
Expand All @@ -375,8 +416,11 @@ const testReadWebNNBuffer = (testName) => {
}, `${testName} / src_offset_and_size`);

promise_test(async () => {
let mlBuffer =
await mlContext.createBuffer({dataType: 'int32', dimensions: [1]});
let mlBuffer = await mlContext.createBuffer({
dataType: 'int32',
dimensions: [1],
usage: MLBufferUsage.WRITE_TO | MLBufferUsage.READ_FROM,
});

// Initialize the buffer.
mlContext.writeBuffer(mlBuffer, Uint8Array.from([0xAA, 0xAA, 0xAA, 0xAA]));
Expand All @@ -390,8 +434,11 @@ const testReadWebNNBuffer = (testName) => {
}, `${testName} / larger_src_data`);

promise_test(async () => {
let mlBuffer =
await mlContext.createBuffer({dataType: 'int32', dimensions: [1]});
let mlBuffer = await mlContext.createBuffer({
dataType: 'int32',
dimensions: [1],
usage: MLBufferUsage.WRITE_TO | MLBufferUsage.READ_FROM,
});

const inputData = [0xAA, 0xAA, 0xAA, 0xAA];

Expand All @@ -404,7 +451,11 @@ const testReadWebNNBuffer = (testName) => {
}, `${testName} / no_src_offset`);

promise_test(async t => {
const bufferDescriptor = {dataType: 'int32', dimensions: [2, 3]};
const bufferDescriptor = {
dataType: 'int32',
dimensions: [2, 3],
usage: MLBufferUsage.READ_FROM,
};
let mlBuffer = await mlContext.createBuffer(bufferDescriptor);

let anotherMLContext = await navigator.ml.createContext(contextOptions);
Expand Down Expand Up @@ -436,7 +487,11 @@ const testDispatchWebNNBuffer = (testName) => {
}
// Construct a simple graph: A = B + C, with two outputs.
const builder = new MLGraphBuilder(mlContext);
const bufferDescriptor = {dataType: 'float32', dimensions: shape};
const bufferDescriptor = {
dataType: 'float32',
dimensions: shape,
usage: MLBufferUsage.WRITE_TO | MLBufferUsage.READ_FROM,
};
const lhsOperand = builder.input('lhs', bufferDescriptor);
const rhsOperand = builder.input('rhs', bufferDescriptor);
const output1Operand = builder.add(lhsOperand, rhsOperand);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,11 @@ promise_setup(async () => {
}

try {
mlBuffer =
await mlContext.createBuffer({dataType: 'int32', dimensions: [2, 4]});
mlBuffer = await mlContext.createBuffer({
dataType: 'int32',
dimensions: [2, 4],
usage: MLBufferUsage.WRITE_TO | MLBufferUsage.READ_FROM,
});
} catch (e) {
throw new AssertionError(
`Unable to create buffer for ${variant} variant. ${e}`);
Expand Down Expand Up @@ -135,8 +138,11 @@ promise_test(async () => {
}, `readBuffer() with a larger TypedArray`);

promise_test(async (t) => {
const buffer =
await mlContext.createBuffer({dataType: 'int32', dimensions: [2, 2]});
const buffer = await mlContext.createBuffer({
dataType: 'int32',
dimensions: [2, 2],
usage: MLBufferUsage.READ_FROM,
});
const arrayBufferView = new Int32Array(2 * 2);
const arrayBuffer = arrayBufferView.buffer;

Expand All @@ -150,8 +156,11 @@ promise_test(async (t) => {
}, `readBuffer() rejects on a destroyed MLBuffer`);

promise_test(async (t) => {
const buffer =
await mlContext.createBuffer({dataType: 'int32', dimensions: [2, 2]});
const buffer = await mlContext.createBuffer({
dataType: 'int32',
dimensions: [2, 2],
usage: MLBufferUsage.READ_FROM,
});
const arrayBufferView = new Int32Array(2 * 2);
const arrayBuffer = arrayBufferView.buffer;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,11 @@ function buildMulGraph(context, operandDescriptor, multiplier) {
}

promise_test(async () => {
const operandDescriptor = {dataType: 'float32', dimensions: [1]};
const operandDescriptor = {
dataType: 'float32',
dimensions: [1],
usage: MLBufferUsage.WRITE_TO | MLBufferUsage.READ_FROM,
};

const [mlGraph, inputBuffer1, inputBuffer2, outputBuffer] =
await Promise.all([
Expand Down Expand Up @@ -66,7 +70,11 @@ promise_test(async () => {
}, 'dispatch queues behind readBuffer');

promise_test(async () => {
const operandDescriptor = {dataType: 'float32', dimensions: [1]};
const operandDescriptor = {
dataType: 'float32',
dimensions: [1],
usage: MLBufferUsage.WRITE_TO | MLBufferUsage.READ_FROM,
};
const mlGraph = await buildMulGraph(mlContext, operandDescriptor, 3);

// write/dispatch/read, write/dispatch/read, ...
Expand All @@ -90,7 +98,11 @@ promise_test(async () => {
}, 'same graph: write/dispatch/read, write/dispatch/read, ...');

promise_test(async () => {
const operandDescriptor = {dataType: 'float32', dimensions: [1]};
const operandDescriptor = {
dataType: 'float32',
dimensions: [1],
usage: MLBufferUsage.WRITE_TO | MLBufferUsage.READ_FROM,
};
const mlGraph = await buildMulGraph(mlContext, operandDescriptor, 10);

// write/write...
Expand Down Expand Up @@ -125,7 +137,11 @@ promise_test(async () => {
}, 'same graph: write/write..., dispatch/read, dispatch/read, ...');

promise_test(async () => {
const operandDescriptor = {dataType: 'float32', dimensions: [1]};
const operandDescriptor = {
dataType: 'float32',
dimensions: [1],
usage: MLBufferUsage.WRITE_TO | MLBufferUsage.READ_FROM,
};
const mlGraph = await buildMulGraph(mlContext, operandDescriptor, 9);

// write/write...
Expand Down Expand Up @@ -159,7 +175,11 @@ promise_test(async () => {
}, 'same graph: write/write..., dispatch/dispatch..., read/read...');

promise_test(async () => {
const operandDescriptor = {dataType: 'float32', dimensions: [1]};
const operandDescriptor = {
dataType: 'float32',
dimensions: [1],
usage: MLBufferUsage.WRITE_TO | MLBufferUsage.READ_FROM,
};
const mlGraph = await buildMulGraph(mlContext, operandDescriptor, 2);

const buffers = await Promise.all([
Expand Down Expand Up @@ -188,7 +208,11 @@ promise_test(async () => {
}, 'same graph serial inputs: dispatch/dispatch..., read/read...');

promise_test(async () => {
const operandDescriptor = {dataType: 'float32', dimensions: [1]};
const operandDescriptor = {
dataType: 'float32',
dimensions: [1],
usage: MLBufferUsage.WRITE_TO | MLBufferUsage.READ_FROM,
};

// write/write...
const testInputs = [1, 2, 3, 4];
Expand Down Expand Up @@ -223,7 +247,11 @@ promise_test(async () => {
}, 'different graphs: write/write..., dispatch/read, dispatch/read, ...');

promise_test(async () => {
const operandDescriptor = {dataType: 'float32', dimensions: [1]};
const operandDescriptor = {
dataType: 'float32',
dimensions: [1],
usage: MLBufferUsage.WRITE_TO | MLBufferUsage.READ_FROM,
};

// write/write...
const testInputs = [1, 2, 3, 4];
Expand Down Expand Up @@ -257,7 +285,11 @@ promise_test(async () => {
}, 'different graphs: write/write..., dispatch/dispatch..., read/read...');

promise_test(async () => {
const operandDescriptor = {dataType: 'float32', dimensions: [1]};
const operandDescriptor = {
dataType: 'float32',
dimensions: [1],
usage: MLBufferUsage.WRITE_TO | MLBufferUsage.READ_FROM,
};

const graphs = await Promise.all([3, 2].map(async (multiplier) => {
return buildMulGraph(mlContext, operandDescriptor, multiplier);
Expand Down Expand Up @@ -289,7 +321,11 @@ promise_test(async () => {
}, 'different graphs serial inputs: dispatch/dispatch..., read/read...');

promise_test(async () => {
const operandDescriptor = {dataType: 'float32', dimensions: [1]};
const operandDescriptor = {
dataType: 'float32',
dimensions: [1],
usage: MLBufferUsage.WRITE_TO | MLBufferUsage.READ_FROM,
};

const graphs = await Promise.all([2, 3].map(async (multiplier) => {
return buildMulGraph(mlContext, operandDescriptor, multiplier);
Expand Down
Loading

0 comments on commit f4c5ea8

Please sign in to comment.