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 16import { convertJSON, LogicHandler } from './ProcedureLogicWorkerCommon'; 17 18interface SPT { 19 title: string; 20 count: number; 21 wallDuration: number; 22 minDuration: number; 23 maxDuration: number; 24 avgDuration: string; 25 children: Array<SPT>; 26 state: string; 27 pid: number; 28 tid: number; 29} 30 31export class ProcedureLogicWorkerSPT extends LogicHandler { 32 threadSlice: Array<ThreadSlice> = []; 33 currentEventId: string = ''; 34 35 clearAll(): void { 36 this.threadSlice.length = 0; 37 } 38 39 handle(data: unknown): void { 40 //@ts-ignore 41 this.currentEventId = data.id; 42 //@ts-ignore 43 if (data && data.type) { 44 //@ts-ignore 45 switch (data.type) { 46 case 'spt-init': 47 this.sptInit(data); 48 break; 49 case 'spt-getPTS': 50 //@ts-ignore 51 this.sptGetPTS(data.params); 52 break; 53 case 'spt-getSPT': 54 //@ts-ignore 55 this.sptGetSPT(data.params); 56 break; 57 case 'spt-getCpuPriority': 58 this.sptGetCpuPriority(); 59 break; 60 case 'spt-getCpuPriorityByTime': 61 //@ts-ignore 62 this.sptGetCpuPriorityByTime(data.params); 63 break; 64 } 65 } 66 } 67 private sptInit(data: unknown): void { 68 //@ts-ignore 69 if (data.params.list) { 70 //@ts-ignore 71 this.threadSlice = convertJSON(data.params.list); 72 self.postMessage({ 73 id: this.currentEventId, 74 action: 'spt-init', 75 results: [], 76 }); 77 } else { 78 this.getThreadState(); 79 } 80 } 81 82 private sptGetPTS(params: { leftNs: number; rightNs: number; cpus: Array<number> }): void { 83 self.postMessage({ 84 id: this.currentEventId, 85 action: 'spt-getPTS', 86 results: this.getPTSData(params.leftNs, params.rightNs, params.cpus), 87 }); 88 } 89 private sptGetSPT(params: { leftNs: number; rightNs: number; cpus: Array<number> }): void { 90 self.postMessage({ 91 id: this.currentEventId, 92 action: 'spt-getSPT', 93 results: this.getSPTData(params.leftNs, params.rightNs, params.cpus), 94 }); 95 } 96 private sptGetCpuPriority(): void { 97 self.postMessage({ 98 id: this.currentEventId, 99 action: 'spt-getCpuPriority', 100 results: this.threadSlice, 101 }); 102 } 103 private sptGetCpuPriorityByTime(params: { leftNs: number; rightNs: number; cpus: Array<number> }): void { 104 const result = this.threadSlice.filter((item: ThreadSlice) => { 105 return !(item.endTs! < params.leftNs || item.startTs! > params.rightNs); 106 }); 107 self.postMessage({ 108 id: this.currentEventId, 109 action: 'spt-getCpuPriorityByTime', 110 results: result, 111 }); 112 } 113 queryData(queryName: string, sql: string, args: unknown): void { 114 self.postMessage({ 115 id: this.currentEventId, 116 type: queryName, 117 isQuery: true, 118 args: args, 119 sql: sql, 120 }); 121 } 122 123 getThreadState(): void { 124 this.queryData( 125 'spt-init', 126 ` 127 select 128 state, 129 dur, 130 (ts - start_ts) as startTs, 131 (ts - start_ts + dur) as endTs, 132 cpu, 133 tid, 134 itid as itId, 135 arg_setid as argSetID, 136 pid 137from thread_state,trace_range where dur > 0 and (ts - start_ts) >= 0; 138`, 139 {} 140 ); 141 } 142 143 private getPTSData(ptsLeftNs: number, ptsRightNs: number, cpus: Array<number>): unknown[] { 144 let ptsFilter = this.threadSlice.filter( 145 (it) => 146 Math.max(ptsLeftNs, it.startTs!) < Math.min(ptsRightNs, it.startTs! + it.dur!) && 147 (it.cpu === null || it.cpu === undefined || cpus.includes(it.cpu)) 148 ); 149 let group: unknown = {}; 150 ptsFilter.forEach((slice) => { 151 let title = `S-${slice.state}`; 152 let item = this.setStateData(slice, title) as SPT; 153 //@ts-ignore 154 if (group[`${slice.pid}`]) { 155 //@ts-ignore 156 let process = group[`${slice.pid}`] as SPT; 157 process.count += 1; 158 process.wallDuration += slice.dur!; 159 process.minDuration = Math.min(process.minDuration, slice.dur!); 160 process.maxDuration = Math.max(process.maxDuration, slice.dur!); 161 process.avgDuration = (process.wallDuration / process.count).toFixed(2); 162 let thread = process.children.find((child: SPT) => child.title === `T-${slice.tid}`); 163 if (thread) { 164 thread.count += 1; 165 thread.wallDuration += slice.dur!; 166 thread.minDuration = Math.min(thread.minDuration, slice.dur!); 167 thread.maxDuration = Math.max(thread.maxDuration, slice.dur!); 168 thread.avgDuration = (thread.wallDuration / thread.count).toFixed(2); 169 let state = thread.children.find((child: SPT) => child.title === `S-${slice.state}`); 170 if (state) { 171 state.count += 1; 172 state.wallDuration += slice.dur!; 173 state.minDuration = Math.min(state.minDuration, slice.dur!); 174 state.maxDuration = Math.max(state.maxDuration, slice.dur!); 175 state.avgDuration = (state.wallDuration / state.count).toFixed(2); 176 } else { 177 thread.children.push(item); 178 } 179 } else { 180 let processChild = this.setThreadData(slice, item) as SPT; 181 process.children.push(processChild); 182 } 183 } else { 184 //@ts-ignore 185 group[`${slice.pid}`] = this.setProcessData(slice, item); 186 } 187 }); 188 //@ts-ignore 189 return Object.values(group); 190 } 191 private setStateData(slice: ThreadSlice, title: string): unknown { 192 return { 193 title: title, 194 count: 1, 195 state: slice.state, 196 tid: slice.tid, 197 pid: slice.pid, 198 minDuration: slice.dur || 0, 199 maxDuration: slice.dur || 0, 200 wallDuration: slice.dur || 0, 201 avgDuration: `${slice.dur}`, 202 }; 203 } 204 private setProcessData(slice: ThreadSlice, item: SPT): unknown { 205 return { 206 title: `P-${slice.pid}`, 207 count: 1, 208 pid: slice.pid, 209 minDuration: slice.dur || 0, 210 maxDuration: slice.dur || 0, 211 wallDuration: slice.dur || 0, 212 avgDuration: `${slice.dur}`, 213 children: [ 214 { 215 title: `T-${slice.tid}`, 216 count: 1, 217 pid: slice.pid, 218 tid: slice.tid, 219 minDuration: slice.dur || 0, 220 maxDuration: slice.dur || 0, 221 wallDuration: slice.dur || 0, 222 avgDuration: `${slice.dur}`, 223 children: [item], 224 }, 225 ], 226 }; 227 } 228 private setThreadData(slice: ThreadSlice, item: SPT): unknown { 229 return { 230 title: `T-${slice.tid}`, 231 count: 1, 232 tid: slice.tid, 233 pid: slice.pid, 234 minDuration: slice.dur || 0, 235 maxDuration: slice.dur || 0, 236 wallDuration: slice.dur || 0, 237 avgDuration: `${slice.dur}`, 238 children: [item], 239 }; 240 } 241 private getSPTData(sptLeftNs: number, sptRightNs: number, cpus: Array<number>): unknown { 242 let sptFilter = this.threadSlice.filter( 243 (it) => 244 Math.max(sptLeftNs, it.startTs!) < Math.min(sptRightNs, it.startTs! + it.dur!) && 245 (it.cpu === null || it.cpu === undefined || cpus.includes(it.cpu)) 246 ); 247 let group: unknown = {}; 248 sptFilter.forEach((slice) => { 249 let item = { 250 title: `T-${slice.tid}`, 251 count: 1, 252 state: slice.state, 253 pid: slice.pid, 254 tid: slice.tid, 255 minDuration: slice.dur || 0, 256 maxDuration: slice.dur || 0, 257 wallDuration: slice.dur || 0, 258 avgDuration: `${slice.dur}`, 259 } as SPT; 260 //@ts-ignore 261 if (group[`${slice.state}`]) { 262 this.setSPTData(group, slice, item); 263 } else { 264 //@ts-ignore 265 group[`${slice.state}`] = { 266 title: `S-${slice.state}`, 267 count: 1, 268 state: slice.state, 269 minDuration: slice.dur || 0, 270 maxDuration: slice.dur || 0, 271 wallDuration: slice.dur || 0, 272 avgDuration: `${slice.dur}`, 273 children: [ 274 { 275 title: `P-${slice.pid}`, 276 count: 1, 277 state: slice.state, 278 pid: slice.pid, 279 minDuration: slice.dur || 0, 280 maxDuration: slice.dur || 0, 281 wallDuration: slice.dur || 0, 282 avgDuration: `${slice.dur}`, 283 children: [item], 284 }, 285 ], 286 }; 287 } 288 }); 289 //@ts-ignore 290 return Object.values(group); 291 } 292 private setSPTData(group: unknown, slice: ThreadSlice, item: SPT): void { 293 //@ts-ignore 294 let state = group[`${slice.state}`]; 295 state.count += 1; 296 state.wallDuration += slice.dur; 297 state.minDuration = Math.min(state.minDuration, slice.dur!); 298 state.maxDuration = Math.max(state.maxDuration, slice.dur!); 299 state.avgDuration = (state.wallDuration / state.count).toFixed(2); 300 let process = state.children.find((child: SPT) => child.title === `P-${slice.pid}`); 301 if (process) { 302 process.count += 1; 303 process.wallDuration += slice.dur; 304 process.minDuration = Math.min(process.minDuration, slice.dur!); 305 process.maxDuration = Math.max(process.maxDuration, slice.dur!); 306 process.avgDuration = (process.wallDuration / process.count).toFixed(2); 307 let thread = process.children.find((child: SPT) => child.title === `T-${slice.tid}`); 308 if (thread) { 309 thread.count += 1; 310 thread.wallDuration += slice.dur; 311 thread.minDuration = Math.min(thread.minDuration, slice.dur!); 312 thread.maxDuration = Math.max(thread.maxDuration, slice.dur!); 313 thread.avgDuration = (thread.wallDuration / thread.count).toFixed(2); 314 } else { 315 process.children.push(item); 316 } 317 } else { 318 state.children.push({ 319 title: `P-${slice.pid}`, 320 count: 1, 321 state: slice.state, 322 pid: slice.pid, 323 minDuration: slice.dur || 0, 324 maxDuration: slice.dur || 0, 325 wallDuration: slice.dur || 0, 326 avgDuration: `${slice.dur}`, 327 children: [item], 328 }); 329 } 330 } 331} 332 333export class ThreadSlice { 334 state?: string; 335 dur?: number; 336 startTs?: number; 337 endTs?: number; 338 cpu?: number | null; 339 tid?: number; 340 pid?: number; 341 itId?: number; 342 priorityType?: string; 343 end_state?: string; 344 priority?: number; 345 argSetID?: number; 346} 347