1/* 2 * Copyright (C) 2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16class ProcedureThread extends Worker { 17 busy: boolean = false; 18 isCancelled: boolean = false; 19 id: number = -1; 20 taskMap: any = {}; 21 name: string | undefined 22 23 uuid(): string { 24 // @ts-ignore 25 return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c => (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)); 26 } 27 28 queryFunc(type: string, args: any, transfer: any, handler: Function) { 29 this.busy = true; 30 let id = this.uuid(); 31 this.taskMap[id] = handler 32 let pam = { 33 id: id, 34 type: type, 35 params: args, 36 } 37 if (transfer) { 38 try { 39 this.postMessage(pam, [transfer]); 40 } catch (e: any) { 41 } 42 } else { 43 this.postMessage(pam); 44 } 45 } 46 47 cancel() { 48 this.isCancelled = true; 49 this.terminate(); 50 } 51} 52 53class ProcedurePool { 54 maxThreadNumber: number = 1 55 works: Array<ProcedureThread> = [] 56 57 static build(name: string, len: number) { 58 return [...Array(len).keys()].map(it => `${name}${it}`) 59 } 60 61 timelineChange: ((a: any) => void) | undefined | null = null; 62 cpusLen = ProcedurePool.build('cpu', 8); 63 processLen = ProcedurePool.build('process', 8); 64 names = [...this.cpusLen, ...this.processLen]; 65 66 constructor(threadBuild: (() => ProcedureThread) | undefined = undefined) { 67 this.init(threadBuild); 68 } 69 70 init(threadBuild: (() => ProcedureThread) | undefined = undefined) { 71 this.maxThreadNumber = this.names.length 72 for (let i = 0; i < this.maxThreadNumber; i++) { 73 this.newThread(); 74 } 75 } 76 77 newThread() { 78 let thread: ProcedureThread = new ProcedureThread("trace/database/ProcedureWorker.js", {type: "module"}) 79 thread.name = this.names[this.works.length] 80 thread.onmessage = (event: MessageEvent) => { 81 thread.busy = false; 82 if ((event.data.type as string) == "timeline-range-changed") { 83 this.timelineChange && this.timelineChange(event.data.results); 84 return; 85 } 86 if (Reflect.has(thread.taskMap, event.data.id)) { 87 if (event.data) { 88 let fun = thread.taskMap[event.data.id]; 89 if (fun) { 90 fun(event.data.results, event.data.hover); 91 } 92 Reflect.deleteProperty(thread.taskMap, event.data.id) 93 } 94 } 95 } 96 thread.onmessageerror = e => { 97 } 98 thread.onerror = e => { 99 } 100 thread.id = this.works.length 101 thread.busy = false 102 this.works?.push(thread) 103 return thread; 104 } 105 106 close = () => { 107 for (let i = 0; i < this.works.length; i++) { 108 let thread = this.works[i]; 109 thread.terminate(); 110 } 111 this.works.length = 0; 112 } 113 114 clearCache = () => { 115 for (let i = 0; i < this.works.length; i++) { 116 let thread = this.works[i]; 117 thread.queryFunc("clear", {}, undefined, () => { 118 }) 119 } 120 } 121 122 submitWithName(name: string, type: string, args: any, transfer: any, handler: Function): ProcedureThread | undefined { 123 let noBusyThreads = this.works.filter(it => it.name === name); 124 let thread: ProcedureThread | undefined 125 if (noBusyThreads.length > 0) { 126 thread = noBusyThreads[0]; 127 if (thread.isCancelled) { 128 this.works.splice(0, 1) 129 thread = this.newThread(); 130 } 131 thread!.queryFunc(type, args, transfer, handler) 132 } 133 return thread; 134 } 135} 136 137export const procedurePool = new ProcedurePool()