Skip to content

Commit

Permalink
#19650 Moved maximumWorkerCount from WorkerTypeDefinition to TaskMana…
Browse files Browse the repository at this point in the history
…ger. Maximum number of workers for every type are created, but only maximum number is executed.

Removed the need for FileLoaderBufferAsync
  • Loading branch information
kaisalmen committed Jun 26, 2020
1 parent e8d0727 commit f6d5847
Show file tree
Hide file tree
Showing 3 changed files with 67 additions and 109 deletions.
62 changes: 45 additions & 17 deletions examples/jsm/loaders/TaskManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,27 @@
* @author Kai Salmen / https://kaisalmen.de
*/

import { FileLoaderBufferAsync } from "./obj2/utils/FileLoaderBufferAsync.js";
import { FileLoader } from "../../../build/three.module.js";

/**
*
*/
class TaskManager {

constructor () {
/**
*
* @param {number} [maximumWorkerCount] How many workers are allows. Set 0 for execution on Main ({@link FakeTaskWorker})
*/
constructor ( maximumWorkerCount ) {

this.types = new Map();
this.verbose = false;
this.maximumWorkerCount = 4
if ( maximumWorkerCount ) {

this.maximumWorkerCount = maximumWorkerCount;

}

}

Expand All @@ -30,6 +40,18 @@ class TaskManager {

}

/**
* @param {number} maximumWorkerCount How many workers are allows. Set 0 for execution on Main ({@link FakeTaskWorker})
* @return {TaskManager}
*/
setMaximumWorkerCount ( maximumWorkerCount ) {

this.maximumWorkerCount = maximumWorkerCount;
return this;

}


/**
* Returns true if support for the given task type is available.
* @param {string} type The type as string
Expand All @@ -44,16 +66,16 @@ class TaskManager {
/**
* Registers functionality for a new task type.
* @param {string} type The name to be used for registration.
* @param {number} maximumWorkerCount How many workers are allows. Set 0 for execution on Main ({@link FakeTaskWorker})
* @param {function} initFunction The function to be called when the worker is initialised
* @param {function} executeFunction The function to be called when the worker is executed
* @param {function} comRoutingFunction The function that should handle communication, leave undefined for default behavior
* @param {boolean} fallback Set to true if execution should be performed in main
* @param {String[]} [dependencyUrls]
* @return {TaskManager}
*/
registerType ( type, maximumWorkerCount, initFunction, executeFunction, comRoutingFunction, dependencyUrls ) {
registerType ( type, initFunction, executeFunction, comRoutingFunction, fallback, dependencyUrls ) {

let workerTypeDefinition = new WorkerTypeDefinition( type, maximumWorkerCount, this.verbose );
let workerTypeDefinition = new WorkerTypeDefinition( type, this.maximumWorkerCount, fallback, this.verbose );
workerTypeDefinition.setFunctions( initFunction, executeFunction, comRoutingFunction );
workerTypeDefinition.setDependencyUrls( dependencyUrls );
this.types.set( type, workerTypeDefinition );
Expand All @@ -64,13 +86,12 @@ class TaskManager {
/**
* Registers functionality for a new task type based on module file.
* @param {string} type The name to be used for registration.
* @param {number} maximumWorkerCount How many workers are allows. Set 0 for execution on Main ({@link FakeTaskWorker})
* @param {string} workerJsmUrl The URL to be used for the Worker. Module must provide logic to handle "init" and "execute" messages.
* @return {TaskManager}
*/
registerTypeJsm ( type, maximumWorkerCount, workerJsmUrl ) {
registerTypeJsm ( type, workerJsmUrl ) {

let workerTypeDefinition = new WorkerTypeDefinition( type, maximumWorkerCount, this.verbose );
let workerTypeDefinition = new WorkerTypeDefinition( type, this.maximumWorkerCount, false, this.verbose );
workerTypeDefinition.setWorkerJsm( workerJsmUrl );
this.types.set( type, workerTypeDefinition );
return this;
Expand Down Expand Up @@ -198,14 +219,16 @@ class WorkerTypeDefinition {
*
* @param {string} type The name of the registered task type.
* @param {Number} maximumCount Maximum worker count
* @param {boolean} fallback Set to true if execution should be performed in main
* @param {boolean} [verbose] Set if logging should be verbose
*/
/**
*/
constructor ( type, maximumCount, verbose ) {
constructor ( type, maximumCount, fallback, verbose ) {
this.type = type;
this.maximumCount = maximumCount;
this.fallback = fallback;
this.verbose = verbose === true;
this.functions = {
init: {
Expand Down Expand Up @@ -259,7 +282,7 @@ class WorkerTypeDefinition {
this.functions.execute.ref = executeFunction;
this.functions.comRouting.ref = comRoutingFunction;

if ( this.maximumCount > 0 && this.functions.comRouting.ref === undefined || this.functions.comRouting.ref === null ) {
if ( this.fallback && this.functions.comRouting.ref === undefined || this.functions.comRouting.ref === null ) {

let comRouting = function ( message, init, execute ) {

Expand Down Expand Up @@ -324,10 +347,11 @@ class WorkerTypeDefinition {
*/
async loadDependencies () {

let fileLoaderBufferAsync = new FileLoaderBufferAsync();
let fileLoader = new FileLoader();
fileLoader.setResponseType( 'arraybuffer' );
for ( let url of this.functions.dependencies.urls ) {

let dep = await fileLoaderBufferAsync.loadFileAsync( url, report => { if ( this.verbose ) console.log( report.detail.text ); } )
let dep = await fileLoader.loadAsync( url.href, report => { if ( this.verbose ) console.log( report.detail.text ); } )
this.functions.dependencies.code.push( dep );

}
Expand Down Expand Up @@ -367,14 +391,18 @@ class WorkerTypeDefinition {
async createWorkers ( code ) {

let worker, workerBlob;
for ( let i = 0; i < this.maximumCount; i++ ) {
if ( !this.fallback ) {

workerBlob = new Blob( this.functions.dependencies.code.concat( this.workers.code ), { type: 'application/javascript' } );
worker = new TaskWorker( i, window.URL.createObjectURL( workerBlob ) );
this.workers.instances[ i ] = worker;
for ( let i = 0; i < this.maximumCount; i ++ ) {

workerBlob = new Blob( this.functions.dependencies.code.concat( this.workers.code ), { type: 'application/javascript' } );
worker = new TaskWorker( i, window.URL.createObjectURL( workerBlob ) );
this.workers.instances[ i ] = worker;

}

}
if ( this.workers.instances.length === 0) {
else {

worker = new FakeTaskWorker( 0, this.functions.init.ref, this.functions.execute.ref );
this.workers.instances[ 0 ] = worker;
Expand Down
58 changes: 0 additions & 58 deletions examples/jsm/loaders/obj2/utils/FileLoaderBufferAsync.js

This file was deleted.

56 changes: 22 additions & 34 deletions examples/webgl_loader_taskmanager.html
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@
this.cameraTarget = this.cameraDefaults.posCameraTarget;

this.controls = null;
this.maximumWorkerCount = 4;

this.taskManager = new TaskManager();
let materialHandler = new MaterialHandler();
Expand All @@ -127,10 +128,10 @@
this.meshReceiver = new MeshReceiver( materialHandler );

this.taskNames = new Map ();
this.taskNames.set( 'tmProtoExample', { use: true, quantity: 4 } );
this.taskNames.set( 'tmProtoExampleJsm', { use: true, quantity: 4 } );
this.taskNames.set( 'tmProtoExampleJsmNoThree', { use: true, quantity: 4 } );
this.taskNames.set( 'tmProtoExampleMain', { use: false, quantity: 0 } );
this.taskNames.set( 'tmProtoExample', { use: true, fallback: false } );
this.taskNames.set( 'tmProtoExampleJsm', { use: true, fallback: false } );
this.taskNames.set( 'tmProtoExampleJsmNoThree', { use: true, fallback: false} );
this.taskNames.set( 'tmProtoExampleMain', { use: false, fallback: true } );

this.tasksToUse = [];
this.executions = [];
Expand Down Expand Up @@ -193,7 +194,7 @@
if ( valueObj.use ) {

this.tasksToUse.push( taskName );
this.taskManager.registerType( taskName, valueObj.quantity, workerInitFunction, workerExecFunction, null, ["../build/three.js"] );
this.taskManager.registerType( taskName, workerInitFunction, workerExecFunction, null, false, ["../build/three.js"] );
awaiting.push( this.taskManager.initType( taskName, { param1: 'param1value' } ).catch( e => console.error( e ) ) );

}
Expand All @@ -202,7 +203,7 @@
if ( valueObj.use ) {

this.tasksToUse.push( taskName );
this.taskManager.registerTypeJsm( taskName, valueObj.quantity, './jsm/taskmanager/tmJsmExample.js' );
this.taskManager.registerTypeJsm( taskName, './jsm/taskmanager/tmJsmExample.js' );
awaiting.push( this.taskManager.initType( taskName, { param1: 'param1value' } ).catch( e => console.error( e ) ) );

}
Expand All @@ -213,7 +214,7 @@
let torus = new THREE.TorusBufferGeometry( 25, 8, 16, 100 );
let torusPayload = TransferableUtils.packageBufferGeometry( torus, 'torus', 0 );
this.tasksToUse.push( taskName );
this.taskManager.registerTypeJsm( taskName, valueObj.quantity, './jsm/taskmanager/tmJsmExampleNoThree.js' );
this.taskManager.registerTypeJsm( taskName, './jsm/taskmanager/tmJsmExampleNoThree.js' );
awaiting.push( this.taskManager.initType( taskName, torusPayload, torusPayload.transferables ).catch( e => console.error( e ) ) );

}
Expand All @@ -222,7 +223,7 @@
if ( valueObj.use ) {

this.tasksToUse.push( taskName );
this.taskManager.registerType( taskName, valueObj.quantity, workerInitFunction, workerExecFunction, null );
this.taskManager.registerType( taskName, workerInitFunction, workerExecFunction, null, true );
awaiting.push( this.taskManager.initType( taskName, { param1: 'param1value' } ).catch( e => console.error( e ) ) );

}
Expand Down Expand Up @@ -380,12 +381,10 @@
let controlStop;
let tmControls = {
tmProtoExampleName: app.taskNames.get( 'tmProtoExample' ).use,
tmProtoExampleQuantity: app.taskNames.get( 'tmProtoExample' ).quantity,
tmProtoExampleJsm: app.taskNames.get( 'tmProtoExampleJsm' ).use,
tmProtoExampleJsmQuantity: app.taskNames.get( 'tmProtoExampleJsm' ).quantity,
tmProtoExampleJsmNoThree: app.taskNames.get( 'tmProtoExampleJsmNoThree' ).use,
tmProtoExampleJsmNoThreeQuantity: app.taskNames.get( 'tmProtoExampleJsmNoThree' ).quantity,
tmProtoExampleMain: app.taskNames.get( 'tmProtoExampleMain' ).use,
maximumWorkerCount: app.maximumWorkerCount,
blockEvent ( event ) {

event.stopPropagation();
Expand Down Expand Up @@ -421,38 +420,27 @@
} );
menuDiv.appendChild( gui.domElement );

let folderLegacy = gui.addFolder( 'Worker Legacy + three' );
let taskName0 = 'tmProtoExample';
controls[ 0 ] = folderLegacy.add( tmControls, taskName0 + 'Name' ).name( 'Use' );
controls[ 0 ] = gui.add( tmControls, taskName0 + 'Name' ).name( 'Worker Legacy + three' );
controls[ 0 ].onChange( value => { app.taskNames.get( taskName0 ).use = value; } );
controls[ 1 ] = folderLegacy.add( tmControls, taskName0 + 'Quantity', 1, 16 ).step( 1 ).name( 'Quantity' );
controls[ 1 ].onChange( value => { app.taskNames.get( taskName0 ).quantity = value; } );
folderLegacy.open();

let folderJsmThree = gui.addFolder( 'Worker Jsm + three' );
let taskName1 = 'tmProtoExampleJsm';
controls[ 2 ] = folderJsmThree.add( tmControls, taskName1 ).name( 'Use' );
controls[ 2 ].onChange( value => { app.taskNames.get( taskName1 ).use = value; } );
controls[ 3 ] = folderJsmThree.add( tmControls, taskName1 + 'Quantity', 1, 16 ).step( 1 ).name( 'Quantity' );
controls[ 3 ].onChange( value => { app.taskNames.get( taskName1 ).quantity = value; } );
folderJsmThree.open();
controls[ 1 ] = gui.add( tmControls, taskName1 ).name( 'Worker Jsm + three' );
controls[ 1 ].onChange( value => { app.taskNames.get( taskName1 ).use = value; } );

let folderJsmNoThree = gui.addFolder( 'Worker Jsm solo' );
let taskName2 = 'tmProtoExampleJsmNoThree';
controls[ 4 ] = folderJsmNoThree.add( tmControls, taskName2 ).name( 'Use' );
controls[ 4 ].onChange( value => { app.taskNames.get( taskName2 ).use = value; } );
controls[ 5 ] = folderJsmNoThree.add( tmControls, taskName2 + 'Quantity', 1, 16 ).step( 1 ).name( 'Quantity' );
controls[ 5 ].onChange( value => { app.taskNames.get( taskName2 ).quantity = value; } );
folderJsmNoThree.open();
controls[ 2 ] = gui.add( tmControls, taskName2 ).name( 'Worker Jsm solo' );
controls[ 2 ].onChange( value => { app.taskNames.get( taskName2 ).use = value; } );

let folderLegacyMain = gui.addFolder( 'Worker Legacy Main' );
let taskName3 = 'tmProtoExampleMain';
controls[ 6 ] = folderLegacyMain.add( tmControls, taskName3 ).name( 'Use' );
controls[ 6 ].onChange( value => { app.taskNames.get( taskName3 ).use = value;} );
folderLegacyMain.open();
controls[ 3 ] = gui.add( tmControls, taskName3 ).name( 'Worker Legacy Main' );
controls[ 3 ].onChange( value => { app.taskNames.get( taskName3 ).use = value;} );

controls[ 7 ] = gui.add( tmControls, 'executeLoading' ).name( 'Engage' );
controls[ 7 ].domElement.id = 'startButton';
controls[ 4 ] = gui.add( tmControls, 'maximumWorkerCount', 1, 16 ).step( 1 ).name( 'Maximum worker count' );
controls[ 4 ].onChange( value => { app.taskManager.setMaximumWorkerCount( value ) } );

controls[ 5 ] = gui.add( tmControls, 'executeLoading' ).name( 'Engage' );
controls[ 5 ].domElement.id = 'startButton';

controlStop = gui.add( tmControls, 'stopExecution' ).name( 'Stop' );

Expand Down

0 comments on commit f6d5847

Please sign in to comment.