/* * Copyright (C) 2022 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ importScripts('trace_converter_builtin.js'); self.onerror = function (error: unknown): void {}; let convertModule: unknown = null; const CONTENT_TYPE_CMDLINES = 2; const CONTENT_TYPE_TGIDS = 3; const CONTENT_TYPE_HEADER_PAGE = 30; const CONTENT_TYPE_PRINTK_FORMATS = 31; const CONTENT_TYPE_KALLSYMS = 32; function initConvertWASM(): Promise { return new Promise((resolve, reject) => { // @ts-ignore let wasm = trace_converter_builtin_wasm; convertModule = wasm({ locateFile: (s: unknown): unknown => { return s; }, print: (line: unknown): void => {}, printErr: (line: unknown): void => {}, onAbort: (): void => { reject('on abort'); }, onRuntimeInitialized: (): void => { resolve('ok'); }, }); }); } function isRawTrace(uint8Array: Uint8Array): boolean { let rowTraceStr = Array.from(new Uint16Array(uint8Array.buffer.slice(0, 2))); return rowTraceStr[0] === 57161; } const ARRAY_BUF_SIZE = 2 * 1024 * 1024; self.onmessage = async (e: MessageEvent): Promise => { if (e.data.action === 'getConvertData') { await initConvertWASM(); let fileData = e.data.buffer; const stepSize = 4 * 1024 * 1024; let totalSize = fileData.byteLength; // @ts-ignore let traceInsPtr = convertModule._GetTraceConverterIns(); // 获取TraceConverter 实例 // @ts-ignore convertModule._SetDebugFlag(false, traceInsPtr); // 设置是否为debug模式 let currentPosition = 1024; // @ts-ignore let dataHeader = convertModule._malloc(1100); let traceAllData = new Uint8Array(e.data.buffer); let isRawTraceConvert = isRawTrace(e.data); if (isRawTraceConvert) { [totalSize, currentPosition, traceAllData] = handleRowTrace( e, fileData, dataHeader, traceInsPtr, currentPosition, traceAllData, totalSize ); } else { handleHTrace(fileData, dataHeader, traceInsPtr); } // @ts-ignore let dataPtr = convertModule._malloc(stepSize); // @ts-ignore let arrayBufferPtr = convertModule._malloc(ARRAY_BUF_SIZE); // @ts-ignore convertModule._free(dataHeader); let bodyDataStr: string[] = []; let callback = (heapPtr: number, size: number): void => { // @ts-ignore let out = convertModule.HEAPU8.slice(heapPtr, heapPtr + size); let dec = new TextDecoder(); let str = dec.decode(out); bodyDataStr.push(str); }; // @ts-ignore let bodyFn = convertModule.addFunction(callback, 'vii'); // @ts-ignore convertModule._SetCallback(bodyFn, traceInsPtr); convertData( currentPosition, traceAllData, arrayBufferPtr, dataPtr, traceInsPtr, isRawTraceConvert, stepSize, totalSize ); // @ts-ignore convertModule._GetRemainingData(traceInsPtr); let headerData: string[] = []; let headerCallback = (heapPtr: number, size: number): void => { // @ts-ignore let out = convertModule.HEAPU8.slice(heapPtr, heapPtr + size); let dec = new TextDecoder(); let str = dec.decode(out); headerData.push(str); }; // @ts-ignore let headerFn = convertModule.addFunction(headerCallback, 'vii'); // @ts-ignore convertModule._SetCallback(headerFn, traceInsPtr); // @ts-ignore convertModule._GetFinalHeader(traceInsPtr); let allDataStr = headerData.concat(bodyDataStr); // @ts-ignore convertModule._ReleaseTraceConverterIns(traceInsPtr); // 释放TraceConverter 实例 // @ts-ignore convertModule._free(arrayBufferPtr); //释放分片内存 // @ts-ignore convertModule._free(dataPtr); postMessage(e, allDataStr); } }; function handleHTrace(fileData: Array, dataHeader: unknown, traceInsPtr: unknown): void { // @ts-ignore let uint8Array = new Uint8Array(fileData.slice(0, 1024)); // @ts-ignore convertModule.HEAPU8.set(uint8Array, dataHeader); // @ts-ignore convertModule._SendFileHeader(dataHeader, 1024, traceInsPtr); } function handleRowTrace( e: MessageEvent, fileData: Array, dataHeader: unknown, traceInsPtr: unknown, currentPosition: number, traceAllData: Uint8Array, totalSize: number ): [number, number, Uint8Array] { // @ts-ignore let uint8Array = new Uint8Array(fileData.slice(0, 12)); // @ts-ignore convertModule.HEAPU8.set(uint8Array, dataHeader); // @ts-ignore convertModule._SendRawFileHeader(dataHeader, 12, traceInsPtr); currentPosition = 12; let allRowTraceData = new Uint8Array(e.data.buffer); let commonDataOffsetList: Array<{ startOffset: number; endOffset: number; }> = []; let commonTotalLength = setCommonDataOffsetList(e, allRowTraceData, commonDataOffsetList); let commonTotalOffset = 0; let commonTotalData = new Uint8Array(commonTotalLength); commonDataOffsetList.forEach((item) => { commonTotalData.set(allRowTraceData.slice(item.startOffset, item.endOffset), commonTotalOffset); commonTotalOffset += item.endOffset - item.startOffset; }); traceAllData = new Uint8Array(allRowTraceData.length + commonTotalData.length); traceAllData.set(allRowTraceData.slice(0, currentPosition), 0); traceAllData.set(commonTotalData, currentPosition); traceAllData.set(allRowTraceData.slice(currentPosition), commonTotalData.length + currentPosition); totalSize += commonTotalData.length; return [totalSize, currentPosition, traceAllData]; } function isCommonData(dataType: number): boolean { return ( dataType === CONTENT_TYPE_CMDLINES || dataType === CONTENT_TYPE_TGIDS || dataType === CONTENT_TYPE_HEADER_PAGE || dataType === CONTENT_TYPE_PRINTK_FORMATS || dataType === CONTENT_TYPE_KALLSYMS ); } function setCommonDataOffsetList( e: MessageEvent, allRowTraceData: Uint8Array, commonDataOffsetList: Array ): number { let commonTotalLength: number = 0; let commonOffset = 12; let tlvTypeLength = 4; while (commonOffset < allRowTraceData.length) { let commonDataOffset = { startOffset: commonOffset, endOffset: commonOffset, }; let dataTypeData = e.data.buffer.slice(commonOffset, commonOffset + tlvTypeLength); commonOffset += tlvTypeLength; let dataType = Array.from(new Uint32Array(dataTypeData)); let currentLData = e.data.buffer.slice(commonOffset, commonOffset + tlvTypeLength); commonOffset += tlvTypeLength; let currentVLength = Array.from(new Uint32Array(currentLData)); commonOffset += currentVLength[0]; commonDataOffset.endOffset = commonOffset; if (isCommonData(dataType[0])) { commonTotalLength += commonDataOffset.endOffset - commonDataOffset.startOffset; commonDataOffsetList.push(commonDataOffset); } } return commonTotalLength; } function convertData( currentPosition: number, traceAllData: Uint8Array, arrayBufferPtr: unknown, dataPtr: unknown, traceInsPtr: unknown, isRawTraceConvert: boolean = false, stepSize: number, totalSize: number ): void { while (currentPosition < totalSize) { let endPosition = Math.min(currentPosition + stepSize, totalSize); let currentChunk = new Uint8Array(traceAllData.slice(currentPosition, endPosition)); // @ts-ignore convertModule.HEAPU8.set(currentChunk, dataPtr); let leftLen = currentChunk.length; let processedLen = 0; let blockSize = 0; let blockPtr = dataPtr; while (leftLen > 0) { if (leftLen > ARRAY_BUF_SIZE) { blockSize = ARRAY_BUF_SIZE; } else { blockSize = leftLen; } // @ts-ignore let subArrayBuffer = convertModule.HEAPU8.subarray(blockPtr, blockPtr + blockSize); // @ts-ignore convertModule.HEAPU8.set(subArrayBuffer, arrayBufferPtr); // 调用分片转换接口 if (isRawTraceConvert) { // @ts-ignore convertModule._ConvertRawBlockData(arrayBufferPtr, subArrayBuffer.length, traceInsPtr); // raw trace } else { // @ts-ignore convertModule._ConvertBlockData(arrayBufferPtr, subArrayBuffer.length, traceInsPtr); // htrace } processedLen = processedLen + blockSize; // @ts-ignore blockPtr = dataPtr + processedLen; leftLen = currentChunk.length - processedLen; } currentPosition = endPosition; } } function postMessage(e: MessageEvent, allDataStr: Array): void { self.postMessage( { id: e.data.id, action: 'convert', status: true, results: new Blob(allDataStr, { type: 'text/plain' }), buffer: e.data.buffer, }, // @ts-ignore [e.data.buffer!] ); }