diff --git a/host/ide/build.js b/host/ide/build.js index 6a5fbd5f22c8e3b5b2b9a13a8825742df7563583..dcdde431e0ea59d9e2779291f7340e3f36932026 100644 --- a/host/ide/build.js +++ b/host/ide/build.js @@ -24,6 +24,8 @@ const outDir = "dist" const staticPath = [ "/src/img", "/server/cert", + "/src/doc", + "/src/figures", ] const staticFiles = [ diff --git a/host/ide/package.json b/host/ide/package.json index bc4e0ea0d5faee107ccc936dd72fc662f27c4def..8d9652f70fa4fd0817ac8df8493f42e1d9ed526e 100644 --- a/host/ide/package.json +++ b/host/ide/package.json @@ -1,12 +1,12 @@ { "name": "SmartPerf", "version": "1.0.0", - "description": "SmartPerf", + "description": "Smart Perf", "main": "index.js", "scripts": { "compile": "node ./build.js", - "test": "jest", - "test-c": "jest --coverage" + "test": "jest -u", + "test-c": "jest --coverage -u" }, "jest": { "testEnvironment": "jsdom", @@ -18,7 +18,8 @@ "!/dist/trace/database/uuidv4.min.js", "!/dist/trace/database/worker.sql-wasm.js", "!/dist/trace/database/worker.sql-wasm-debug.js", - "!/node_modules/" + "!/dist/trace/database/trace_streamer_builtin.js" + ], "globals": { "useWb": true @@ -26,7 +27,8 @@ "setupFiles": [ "jsdom-worker", "jest-canvas-mock" - ] + ], + "setupFilesAfterEnv":["/jest.setup.js"] }, "repository": { "type": "git", @@ -44,7 +46,10 @@ "jest": "*", "jest-canvas-mock": "^2.3.1", "typescript": "^4.2.3", - "jsdom-worker": "^0.2.1" + "jsdom-worker": "^0.2.1", + "jest-environment-jsdom": "^28.1.0", + "node-fetch": "^2.6.7" }, - "dependencies": {} + "dependencies": { + } } diff --git a/host/ide/server/main.go b/host/ide/server/main.go index 995cffe734c904b684c312f684c1fba216080618..dfd01a3117d1f7b0d08c35797c7b9cde61f869ea 100644 --- a/host/ide/server/main.go +++ b/host/ide/server/main.go @@ -20,6 +20,7 @@ import ( "crypto/rsa" "crypto/x509" "crypto/x509/pkix" + "encoding/json" "encoding/pem" "math/big" "net" @@ -120,6 +121,7 @@ func main() { mime.AddExtensionType(".js", "application/javascript") log.Println(mime.TypeByExtension(".js")) mux.HandleFunc("/upload", uploadHandler) + mux.HandleFunc("/logger", consoleHandler) mux.Handle("/upload/", http.StripPrefix("/upload/", http.FileServer(http.Dir(exPath+"/upload")))) fs := http.FileServer(http.Dir(exPath + "/")) mux.Handle("/application/", http.StripPrefix("/application/", cors(fs, version))) @@ -135,6 +137,29 @@ func main() { select {} } +type LoggerReq struct { + FileName string `json:"fileName"` + FileSize string `json:"fileSize"` +} + +func consoleHandler(w http.ResponseWriter, r *http.Request) { + chekDir(exPath + "/logger") + var now = time.Now() + var fileName = fmt.Sprintf("%d-%d-%d", now.Year(), now.Month(), now.Day()) + dst, err := os.OpenFile(exPath+"/logger/"+fileName, os.O_WRONLY|os.O_CREATE|os.O_APPEND|os.O_SYNC, 0666) + CheckErr(err) + contentType := r.Header["Content-Type"] + if len(contentType) > 0 { + contentTypeName := contentType[0] + if strings.HasPrefix(contentTypeName, "application/json") { + decoder := json.NewDecoder(r.Body) + var req LoggerReq + decoder.Decode(&req) + dst.WriteString(fmt.Sprintf("%s %s (%s M)\n", now.Format("2006-01-02 15:04:05"), req.FileName, req.FileSize)) + fmt.Fprintf(w, fmt.Sprintf("日志写入成功%s", exPath)) + } + } +} func uploadHandler(w http.ResponseWriter, r *http.Request) { defer func() { var err = recover() diff --git a/host/ide/src/base-ui/button/LitButton.ts b/host/ide/src/base-ui/button/LitButton.ts index 516e1b8034f2ecce311aeceb23a526c8b3ed9063..fefe7e8d5153325fc48b72201aaa23c90bd125ea 100644 --- a/host/ide/src/base-ui/button/LitButton.ts +++ b/host/ide/src/base-ui/button/LitButton.ts @@ -13,14 +13,15 @@ * limitations under the License. */ -import {BaseElement} from "../BaseElement.js"; +import {BaseElement, element} from "../BaseElement.js"; +@element('lit-button') export class LitButton extends BaseElement { + initElements(): void { + } + initHtml(): string { return ""; } - initElements(): void { - - } } \ No newline at end of file diff --git a/host/ide/src/base-ui/checkbox/LitCheckBox.ts b/host/ide/src/base-ui/checkbox/LitCheckBox.ts index a6b5d913591c14e0eb6c81af6f883627c437833f..2939dd72a29afd5c26818881136a1b194b85a06b 100644 --- a/host/ide/src/base-ui/checkbox/LitCheckBox.ts +++ b/host/ide/src/base-ui/checkbox/LitCheckBox.ts @@ -60,11 +60,10 @@ export class LitCheckBox extends BaseElement { return ` `; diff --git a/host/ide/src/base-ui/checkbox/LitCheckBoxWithText.ts b/host/ide/src/base-ui/checkbox/LitCheckBoxWithText.ts index 2de00a3fe8b08a16bca6f42e2e9f9c2a6869466d..78ff088d4a0d59e1af844e09237958a9b61f8032 100644 --- a/host/ide/src/base-ui/checkbox/LitCheckBoxWithText.ts +++ b/host/ide/src/base-ui/checkbox/LitCheckBoxWithText.ts @@ -70,24 +70,25 @@ export class LitCheckBoxWithText extends BaseElement { initHtml(): string { return ` - - - + + + + `; } diff --git a/host/ide/src/base-ui/icon.svg b/host/ide/src/base-ui/icon.svg index 168c113b584dbbbfb6a69687e65adf634768dd8b..65d5e049f73f53653c4b0335bb97673e398b070a 100644 --- a/host/ide/src/base-ui/icon.svg +++ b/host/ide/src/base-ui/icon.svg @@ -1 +1,2191 @@ - + \ No newline at end of file diff --git a/host/ide/src/base-ui/menu/LitMainMenu.ts b/host/ide/src/base-ui/menu/LitMainMenu.ts index 008f584689ad7b12aae69de085f20124a0cb50c4..04dcb8b098f6e69d53f0b9e2bb173d8a0a66e3e6 100644 --- a/host/ide/src/base-ui/menu/LitMainMenu.ts +++ b/host/ide/src/base-ui/menu/LitMainMenu.ts @@ -89,73 +89,74 @@ export class LitMainMenu extends BaseElement { initHtml(): string { return ` - + } + .header{ + display: grid; + background-color: var(--dark-background1,#FFFFFF); + border-bottom: 1px solid var(--dark-background1,#EFEFEF); + color: #47A7E0; + font-size: 1.4rem; + padding-left: 20px; + /*padding-right: 10px;*/ + gap: 0 20px; + box-sizing: border-box; + width: 100%; + height: 56px; + grid-template-columns: min-content 1fr min-content; + grid-template-rows: auto; + } + .header *{ + align-self: center; + user-select: none; + } + .version{ + color: #94979d; + padding: 20px; + font-size: 0.6rem; + width: 100%; + text-align: right; + } + *{ + box-sizing: border-box; + } + .menu-button{ + height: 47px; + width: 48px; + display: flex; + align-content: center; + justify-content: right; + cursor: pointer; + } +
- + +
- -
`; } } diff --git a/host/ide/src/base-ui/menu/LitMainMenuItem.ts b/host/ide/src/base-ui/menu/LitMainMenuItem.ts index 4af57f10fed85138d48e26c44f29077500c01a80..25a854e1b850fd8d213a3b04ab86808d14f3e91f 100644 --- a/host/ide/src/base-ui/menu/LitMainMenuItem.ts +++ b/host/ide/src/base-ui/menu/LitMainMenuItem.ts @@ -85,72 +85,72 @@ export class LitMainMenuItem extends BaseElement { initHtml(): string { return ` - - - -`; + + + + `; } attributeChangedCallback(name: string, oldValue: string, newValue: string) { diff --git a/host/ide/src/base-ui/popover/LitPopoverV.ts b/host/ide/src/base-ui/popover/LitPopoverV.ts index 6fd0a0861715a7990ef0b08586dd0fc67a4dfb0a..eee4038eea28aad353beccdda43faeb064c3c50e 100644 --- a/host/ide/src/base-ui/popover/LitPopoverV.ts +++ b/host/ide/src/base-ui/popover/LitPopoverV.ts @@ -13,32 +13,32 @@ * limitations under the License. */ -import {element,BaseElement} from "../BaseElement.js"; +import {BaseElement, element} from "../BaseElement.js"; @element("lit-popover") export class LitPopover extends BaseElement { static get observedAttributes() { return [ - 'title',/*标题*/ - 'trigger',/*触发条件 hover | click | focus[未实现]*/ - 'width',/*自定义高度*/ - 'placement',/*设置方向 topLeft top topRight leftTop left leftBottom rightTop right rightBottom bottomLeft bottom bottomRight*/ - 'visible'/*控制popover是否显示*/ + 'title', + 'trigger', + 'width', + 'placement', + 'visible' ] } - initElements(): void { - } - get visible(){ + get visible() { return this.getAttribute('visible') || 'false'; } - set visible(value){ + + set visible(value) { if (value) { this.setAttribute('visible', 'true'); - }else{ + } else { this.setAttribute('visible', 'false'); } } + get trigger() { return this.getAttribute('trigger') || 'hover' } @@ -51,7 +51,7 @@ export class LitPopover extends BaseElement { return this.getAttribute('title'); } - set title(value:any) { + set title(value: any) { this.setAttribute('title', value); } @@ -63,13 +63,15 @@ export class LitPopover extends BaseElement { this.setAttribute('width', value); } - get haveRadio(){ + get haveRadio() { return this.getAttribute("haveRadio") } + initElements(): void { + + } + initHtml() { - // super(); - // const shadowRoot = this.attachShadow({mode: 'open'}); return ` -
-
-
-
+ +
+
+
+
`; } - } \ No newline at end of file diff --git a/host/ide/src/base-ui/radiobox/LitRadioBox.ts b/host/ide/src/base-ui/radiobox/LitRadioBox.ts index daef13552c3b351a2f4861bab54a3a97e8c6fc81..d5bf7bb313746bccabaaa7eb985ee7f9205aae01 100644 --- a/host/ide/src/base-ui/radiobox/LitRadioBox.ts +++ b/host/ide/src/base-ui/radiobox/LitRadioBox.ts @@ -185,7 +185,10 @@ export class LitRadioBox extends BaseElement { `; diff --git a/host/ide/src/base-ui/select/LitSelect.ts b/host/ide/src/base-ui/select/LitSelect.ts index 460cac9db3c0d3e23a1ea94f2cb96908c9442123..5f0162509dd4e9db3d0927b868aa7045a5bd20d5 100644 --- a/host/ide/src/base-ui/select/LitSelect.ts +++ b/host/ide/src/base-ui/select/LitSelect.ts @@ -17,586 +17,635 @@ import {BaseElement, element} from "../BaseElement.js"; @element('lit-select') export class LitSelect extends BaseElement { - private focused:any; - private inputElement:any; - private clearElement:any; - private iconElement:any; - private searchElement:any; - private multipleRootElement:any; - static get observedAttributes() { - return [ - 'value',//默认值 - 'default-value',//默认值 - 'placeholder',//placeholder - 'disabled', - 'loading',//是否处于加载状态 - 'allow-clear',//是否允许清除 - 'show-search',//是否允许搜索 - 'list-height',//设置弹窗滚动高度 默认256px - 'border',//是否显示边框 - 'mode',// mode='multiple'多选 - ]; - } - initElements(): void { - - } - - get value() { - return this.getAttribute('value') || this.defaultValue; - } - - set value(value) { - this.setAttribute('value', value); - } - - get border() { - return this.getAttribute('border') || 'true'; - } - - set border(value) { - if (value) { - this.setAttribute('border', 'true'); - } else { - this.setAttribute('border', 'false'); - } - } - - get listHeight() { - return this.getAttribute('list-height') || '256px'; - } - - set listHeight(value) { - this.setAttribute('list-height', value); - } - - get defaultPlaceholder() { - return this.getAttribute('placeholder') || '请选择'; - } - - get showSearch() { - return this.hasAttribute('show-search'); - } - - set defaultValue(value) { - this.setAttribute('default-value', value); - } - - get defaultValue() { - return this.getAttribute('default-value') || ''; - } - - set placeholder(value) { - this.setAttribute('placeholder', value); - } - - get placeholder() { - return this.getAttribute('placeholder') || this.defaultPlaceholder; - } - - get loading() { - return this.hasAttribute('loading'); - } - - set loading(value) { - if (value) { - this.setAttribute('loading', ''); - } else { - this.removeAttribute('loading') - } - } - - initHtml() { - // super(); - // const shadowRoot = this.attachShadow({mode: 'open'}); - return` + private focused: any; + private inputElement: any; + private clearElement: any; + private iconElement: any; + private searchElement: any; + private multipleRootElement: any; + + static get observedAttributes() { + return [ + 'value', + 'default-value', + 'placeholder', + 'disabled', + 'loading', + 'allow-clear', + 'show-search', + 'list-height', + 'border', + 'mode', + ]; + } + + get value() { + return this.getAttribute('value') || this.defaultValue; + } + + set value(value) { + this.setAttribute('value', value); + } + + get rounded() { + return this.hasAttribute("rounded"); + } + + set rounded(rounded: boolean) { + if (rounded) { + this.setAttribute("rounded", ''); + } else { + this.removeAttribute("rounded"); + } + } + + get placement(): string { + return this.getAttribute("placement") || ""; + } + + set placement(placement: string) { + if (placement) { + this.setAttribute("placement", placement); + } else { + this.removeAttribute("placement"); + } + } + + get border() { + return this.getAttribute('border') || 'true'; + } + + set border(value) { + if (value) { + this.setAttribute('border', 'true'); + } else { + this.setAttribute('border', 'false'); + } + } + + get listHeight() { + return this.getAttribute('list-height') || '256px'; + } + + set listHeight(value) { + this.setAttribute('list-height', value); + } + + get defaultPlaceholder() { + return this.getAttribute('placeholder') || '请选择'; + } + + set canInsert(can:boolean) { + if (can) { + this.setAttribute("canInsert",''); + } else { + this.removeAttribute("canInsert") + } + } + + get canInsert() { + return this.hasAttribute("canInsert") + } + get showSearch() { + return this.hasAttribute('show-search'); + } + + get defaultValue() { + return this.getAttribute('default-value') || ''; + } + + set defaultValue(value) { + this.setAttribute('default-value', value); + } + + get placeholder() { + return this.getAttribute('placeholder') || this.defaultPlaceholder; + } + + set placeholder(value) { + this.setAttribute('placeholder', value); + } + + get loading() { + return this.hasAttribute('loading'); + } + + set loading(value) { + if (value) { + this.setAttribute('loading', ''); + } else { + this.removeAttribute('loading') + } + } + + set dataSource(value: any) { + value.forEach((a: any) => { + let option = document.createElement('lit-select-option'); + option.setAttribute('value', a.key); + option.textContent = a.val; + this.append(option) + }) + this.initOptions(); + } + + initElements(): void { + } + + initHtml() { + return ` -
-
- - - - -
-
- - -
+ +
+
+
+ + + + +
+
+ + +
` - } - - isMultiple() { - return this.hasAttribute('mode') && this.getAttribute('mode') === 'multiple' - } - - newTag(value:any, text:any) { - let tag:any = document.createElement('div'); - let icon:any = document.createElement('lit-icon'); - icon.classList.add('tag-close') - icon.name = 'close' - let span = document.createElement('span'); - tag.classList.add('tag'); - span.dataset['value'] = value; - span.textContent = text; - tag.append(span); - tag.append(icon); - icon.onclick = (ev:any) => { - tag.parentElement.removeChild(tag); - this.querySelector(`lit-select-option[value=${value}]`)!.removeAttribute('selected') - if (this.shadowRoot!.querySelectorAll('.tag').length == 0) { - this.inputElement.style.width = 'auto'; - this.inputElement.placeholder = this.defaultPlaceholder; - } - ev.stopPropagation(); - } - tag.value = value; - tag.dataset['value'] = value; - tag.text = text; - tag.dataset['text'] = text; - return tag; - } - - //当 custom element首次被插入文档DOM时,被调用。 - connectedCallback() { - this.tabIndex = 0;//设置当前组件为可以获取焦点 - this.focused = false; - this.inputElement = this.shadowRoot!.querySelector('input'); - this.clearElement = this.shadowRoot!.querySelector('.clear'); - this.iconElement = this.shadowRoot!.querySelector('.icon'); - this.searchElement = this.shadowRoot!.querySelector('.search'); - this.multipleRootElement = this.shadowRoot!.querySelector('.multipleRoot'); - //点击清理 清空input值,展示placeholder, - this.clearElement.onclick = (ev:any) => { - if (this.isMultiple()) { - let delNodes:Array = [] - this.multipleRootElement.childNodes.forEach((a:any) => { - if (a.tagName === 'DIV') { - delNodes.push(a); - } - }) - for (let i = 0; i < delNodes.length; i++) { - delNodes[i].remove(); - } - if (this.shadowRoot!.querySelectorAll('.tag').length == 0) { - this.inputElement.style.width = 'auto'; - this.inputElement.placeholder = this.defaultPlaceholder; - } - } - this.querySelectorAll('lit-select-option').forEach(a => a.removeAttribute('selected')); - this.inputElement.value = '' - this.clearElement.style.display = 'none'; - this.iconElement.style.display = 'flex'; - this.blur(); - ev.stopPropagation();//这里不会因为点击清理而触发 选择栏目显示或者隐藏 - this.dispatchEvent(new CustomEvent('onClear', {detail: ev}))//向外派发清理事件 - } - //初始化时遍历所有的option节点 - this.initOptions(); - //当前控件点击时 如果时select本身 需要显示 或 隐藏选择栏目,通过this.focused变量控制(默认为false) - this.onclick = (ev:any) => { - if (ev.target.tagName === 'LIT-SELECT') { - if (this.focused === false) { - this.inputElement.focus(); - this.focused = true; - } else { - this.blur(); - this.focused = false; - } - } - } - this.onmouseover = this.onfocus = ev => { - if (this.hasAttribute('allow-clear')) { - if (this.inputElement.value.length > 0 || this.inputElement.placeholder !== this.defaultPlaceholder) { - this.clearElement.style.display = 'flex' - this.iconElement.style.display = 'none'; - } else { - this.clearElement.style.display = 'none' - this.iconElement.style.display = 'flex'; - } - } - } - this.onmouseout = this.onblur = ev => { - if (this.hasAttribute('allow-clear')) { - this.clearElement.style.display = 'none'; - this.iconElement.style.display = 'flex'; - } - this.focused = false; - } - //输入框获取焦点时,value值 暂存于 placeholder 然后value值清空,这样值会以placeholder形式灰色展示,鼠标位于第一个字符 - this.inputElement.onfocus = (ev:any) => { - if (this.hasAttribute('disabled')) return;//如果控件处于disabled状态 直接忽略 - if (this.inputElement.value.length > 0) { - this.inputElement.placeholder = this.inputElement.value; - this.inputElement.value = '' - } - if (this.hasAttribute('show-search')) {//如果有show-search属性 需要显示放大镜,隐藏向下的箭头 - this.searchElement.style.display = 'flex'; - this.iconElement.style.display = 'none'; - } - this.querySelectorAll('lit-select-option').forEach(a => {//input获取焦点时显示所有可选项,相当于清理了搜索结果 - // @ts-ignore - a.style.display = 'flex'; - }) - } - //当输入框失去焦点的时候 placeholder 的值 保存到value上,input显示值 - this.inputElement.onblur = (ev:any) => { - if (this.hasAttribute('disabled')) return;//如果控件处于disabled状态 直接忽略 - if (this.isMultiple()) { - if (this.hasAttribute('show-search')) {//如果有show-search属性 失去焦点需要 隐藏放大镜图标,显示默认的向下箭头图标 - this.searchElement.style.display = 'none'; - this.iconElement.style.display = 'flex'; - } - } else { - if (this.inputElement.placeholder !== this.defaultPlaceholder) {//如果placeholder为 请输入(默认值)不做处理 - this.inputElement.value = this.inputElement.placeholder; //placeholder 保存的值放入 value中 - this.inputElement.placeholder = this.defaultPlaceholder;//placeholder 值为 默认值(请输入) - } - if (this.hasAttribute('show-search')) {//如果有show-search属性 失去焦点需要 隐藏放大镜图标,显示默认的向下箭头图标 - this.searchElement.style.display = 'none'; - this.iconElement.style.display = 'flex'; - } - } - } - //输入框每次文本变化 会匹配搜索的option 显示或者隐藏,达到搜索的效果 - this.inputElement.oninput = (ev:any) => { - let els = [...this.querySelectorAll('lit-select-option')]; - if (!ev.target.value) { - els.forEach((a:any) => a.style.display = 'flex'); - } else { - els.forEach((a:any) => { - let value = a.getAttribute('value'); - if (value.toLowerCase().indexOf(ev.target.value.toLowerCase()) !== -1 || - a.textContent.toLowerCase().indexOf(ev.target.value.toLowerCase()) !== -1) { - a.style.display = 'flex'; - } else { - a.style.display = 'none'; - } - }) - } - } - //输入框按下回车键,自动输入当前搜索出来的第一行,及display!='none'的第一个,搜索会隐藏其他行 - this.inputElement.onkeydown = (ev:any) => { - if (ev.key === 'Backspace') { - if (this.isMultiple()) { - let tag = this.multipleRootElement.lastElementChild.previousElementSibling; - if (tag) { - this.querySelector(`lit-select-option[value=${tag.value}]`)?.removeAttribute('selected'); - tag.remove() - if (this.shadowRoot!.querySelectorAll('.tag').length == 0) { - this.inputElement.style.width = 'auto'; - this.inputElement.placeholder = this.defaultPlaceholder; - } - } - } else { - this.clear(); - this.dispatchEvent(new CustomEvent('onClear', {detail: ev}))//向外派发清理事件 - } - } else if (ev.key === 'Enter') { - let filter = [...this.querySelectorAll('lit-select-option')].filter((a:any) => a.style.display !== 'none'); - if (filter.length > 0) { - this.inputElement.value = filter[0].textContent; - this.inputElement.placeholder = filter[0].textContent; - this.blur(); - // @ts-ignore - this.value=filter[0].getAttribute('value') - this.dispatchEvent(new CustomEvent('change', { - detail: { - selected: true, - value: filter[0].getAttribute('value'), - text: filter[0].textContent - } - }));//向外层派发change事件,返回当前选中项 - } - } - } - } - - initOptions(){ - this.querySelectorAll('lit-select-option').forEach(a => { - //如果节点的值为 当前控件的默认值 defalut-value则 显示该值对应的option文本 - if (this.isMultiple()) { - a.setAttribute('check', ''); - if (a.getAttribute('value') === this.defaultValue) { - let tag = this.newTag(a.getAttribute('value'), a.textContent); - this.multipleRootElement.insertBefore(tag, this.inputElement); - this.inputElement.placeholder = ''; - this.inputElement.value = ''; - this.inputElement.style.width = '1px'; - a.setAttribute('selected', ''); - } - // this.inputElement.focus(); - } else { - if (a.getAttribute('value') === this.defaultValue) { - this.inputElement.value = a.textContent; - a.setAttribute('selected', ''); - } - } - //每个option设置onSelected事件 接受当前点击的option - a.addEventListener('onSelected', (e:any) => { - //所有option设置为未选中状态 - if (this.isMultiple()) {//多选 - if (a.hasAttribute('selected')) { - let tag = this.shadowRoot!.querySelector(`div[data-value=${e.detail.value}]`); - // @ts-ignore - tag.parentElement!.removeChild(tag); - e.detail.selected = false; - } else { - let tag = this.newTag(e.detail.value, e.detail.text); - this.multipleRootElement.insertBefore(tag, this.inputElement); - this.inputElement.placeholder = ''; - this.inputElement.value = ''; - this.inputElement.style.width = '1px'; - } - if (this.shadowRoot!.querySelectorAll('.tag').length == 0) { - this.inputElement.style.width = 'auto'; - this.inputElement.placeholder = this.defaultPlaceholder; - } - this.inputElement.focus(); - } else {//单选 - [...this.querySelectorAll('lit-select-option')].forEach(a => a.removeAttribute('selected')) - this.blur();//失去焦点,隐藏选择栏目列表 - // @ts-ignore - this.inputElement.value = e.detail.text; - } - //设置当前option为选择状态 - if (a.hasAttribute('selected')) { - a.removeAttribute('selected') - } else { - a.setAttribute('selected', '') - } - //设置input的值为当前选择的文本 - // @ts-ignore - this.value = e.detail.value; - this.dispatchEvent(new CustomEvent('change', {detail: e.detail}));//向外层派发change事件,返回当前选中项 - }) - }) - } - //js调用清理选项 - clear() { - this.inputElement.value = ''; - this.inputElement.placeholder = this.defaultPlaceholder; - } - - //重置为默认值 - reset() { - this.querySelectorAll('lit-select-option').forEach(a => { - //如果节点的值为 当前控件的默认值 defalut-value则 显示该值对应的option文本 - [...this.querySelectorAll('lit-select-option')].forEach(a => a.removeAttribute('selected')) - if (a.getAttribute('value') === this.defaultValue) { - this.inputElement.value = a.textContent; - a.setAttribute('selected', ''); - } - }) - } - - //当 custom element从文档DOM中删除时,被调用。 - disconnectedCallback() { - - } - - //当 custom element被移动到新的文档时,被调用。 - adoptedCallback() { - } - - //当 custom element增加、删除、修改自身属性时,被调用。 - attributeChangedCallback(name:any, oldValue:any, newValue:any) { - if (name === 'value' && this.inputElement) { - if(newValue){ - [...this.querySelectorAll('lit-select-option')].forEach(a => { - if (a.getAttribute('value') === newValue) { - a.setAttribute('selected', ''); - this.inputElement.value = a.textContent; - } else { - a.removeAttribute('selected') - } - }) - }else{ - this.clear(); - } - } - } - set dataSource(value:any){ - value.forEach((a:any)=>{ - let option = document.createElement('lit-select-option'); - option.setAttribute('value',a.key); - option.textContent = a.val; - this.append(option) - }) - this.initOptions(); - } + } + + isMultiple() { + return this.hasAttribute('mode') && this.getAttribute('mode') === 'multiple' + } + + newTag(value: any, text: any) { + let tag: any = document.createElement('div'); + let icon: any = document.createElement('lit-icon'); + icon.classList.add('tag-close') + icon.name = 'close' + let span = document.createElement('span'); + tag.classList.add('tag'); + span.dataset['value'] = value; + span.textContent = text; + tag.append(span); + tag.append(icon); + icon.onclick = (ev: any) => { + tag.parentElement.removeChild(tag); + this.querySelector(`lit-select-option[value=${value}]`)!.removeAttribute('selected') + if (this.shadowRoot!.querySelectorAll('.tag').length == 0) { + this.inputElement.style.width = 'auto'; + this.inputElement.placeholder = this.defaultPlaceholder; + } + ev.stopPropagation(); + } + tag.value = value; + tag.dataset['value'] = value; + tag.text = text; + tag.dataset['text'] = text; + return tag; + } + + connectedCallback() { + this.tabIndex = 0; + this.focused = false; + this.inputElement = this.shadowRoot!.querySelector('input'); + this.clearElement = this.shadowRoot!.querySelector('.clear'); + this.iconElement = this.shadowRoot!.querySelector('.icon'); + this.searchElement = this.shadowRoot!.querySelector('.search'); + this.multipleRootElement = this.shadowRoot!.querySelector('.multipleRoot'); + this.clearElement.onclick = (ev: any) => { + if (this.isMultiple()) { + let delNodes: Array = [] + this.multipleRootElement.childNodes.forEach((a: any) => { + if (a.tagName === 'DIV') { + delNodes.push(a); + } + }) + for (let i = 0; i < delNodes.length; i++) { + delNodes[i].remove(); + } + if (this.shadowRoot!.querySelectorAll('.tag').length == 0) { + this.inputElement.style.width = 'auto'; + this.inputElement.placeholder = this.defaultPlaceholder; + } + } + this.querySelectorAll('lit-select-option').forEach(a => a.removeAttribute('selected')); + this.inputElement.value = '' + this.clearElement.style.display = 'none'; + this.iconElement.style.display = 'flex'; + this.blur(); + ev.stopPropagation(); + this.dispatchEvent(new CustomEvent('onClear', {detail: ev})) + } + this.initOptions(); + this.onclick = (ev: any) => { + if (ev.target.tagName === 'LIT-SELECT') { + if (this.focused === false) { + this.inputElement.focus(); + this.focused = true; + } else { + this.blur(); + this.focused = false; + } + } + } + this.onmouseover = this.onfocus = ev => { + if (this.focused === false && this.hasAttribute("adaptive-expansion")) { + let body = this.shadowRoot!.querySelector(".body"); + if (this.parentElement!.offsetTop < body!.clientHeight) { + body!.classList.add('body-bottom'); + } else { + body!.classList.remove('body-bottom'); + } + } + if (this.hasAttribute('allow-clear')) { + if (this.inputElement.value.length > 0 || this.inputElement.placeholder !== this.defaultPlaceholder) { + this.clearElement.style.display = 'flex' + this.iconElement.style.display = 'none'; + } else { + this.clearElement.style.display = 'none' + this.iconElement.style.display = 'flex'; + } + } + } + this.onmouseout = this.onblur = ev => { + if (this.hasAttribute('allow-clear')) { + this.clearElement.style.display = 'none'; + this.iconElement.style.display = 'flex'; + } + this.focused = false; + } + this.inputElement.onfocus = (ev: any) => { + if (this.hasAttribute('disabled')) return; + if (this.inputElement.value.length > 0) { + this.inputElement.placeholder = this.inputElement.value; + this.inputElement.value = '' + } + if (this.hasAttribute('show-search')) { + this.searchElement.style.display = 'flex'; + this.iconElement.style.display = 'none'; + } + this.querySelectorAll('lit-select-option').forEach(a => { + // @ts-ignore + a.style.display = 'flex'; + }) + } + this.inputElement.onblur = (ev: any) => { + if (this.hasAttribute('disabled')) return; + if (this.isMultiple()) { + if (this.hasAttribute('show-search')) { + this.searchElement.style.display = 'none'; + this.iconElement.style.display = 'flex'; + } + } else { + if (this.inputElement.placeholder !== this.defaultPlaceholder) { + this.inputElement.value = this.inputElement.placeholder; + this.inputElement.placeholder = this.defaultPlaceholder; + } + if (this.hasAttribute('show-search')) { + this.searchElement.style.display = 'none'; + this.iconElement.style.display = 'flex'; + } + } + } + this.inputElement.oninput = (ev: any) => { + let els = [...this.querySelectorAll('lit-select-option')]; + if(this.hasAttribute("show-search")) { + if (!ev.target.value) { + els.forEach((a: any) => a.style.display = 'flex'); + } else { + els.forEach((a: any) => { + let value = a.getAttribute('value'); + if (value.toLowerCase().indexOf(ev.target.value.toLowerCase()) !== -1 || + a.textContent.toLowerCase().indexOf(ev.target.value.toLowerCase()) !== -1) { + a.style.display = 'flex'; + } else { + a.style.display = 'none'; + } + }) + } + } else { + this.value = ev.target.value + } + } + this.inputElement.onkeydown = (ev: any) => { + if (ev.key === 'Backspace') { + if (this.isMultiple()) { + let tag = this.multipleRootElement.lastElementChild.previousElementSibling; + if (tag) { + this.querySelector(`lit-select-option[value=${tag.value}]`)?.removeAttribute('selected'); + tag.remove() + if (this.shadowRoot!.querySelectorAll('.tag').length == 0) { + this.inputElement.style.width = 'auto'; + this.inputElement.placeholder = this.defaultPlaceholder; + } + } + } else { + this.clear(); + this.dispatchEvent(new CustomEvent('onClear', {detail: ev}))//向外派发清理事件 + } + } else if (ev.key === 'Enter') { + if (!this.canInsert) { + let filter = [...this.querySelectorAll('lit-select-option')].filter((a: any) => a.style.display !== 'none'); + if (filter.length > 0) { + this.inputElement.value = filter[0].textContent; + this.inputElement.placeholder = filter[0].textContent; + this.blur(); + // @ts-ignore + this.value = filter[0].getAttribute('value') + this.dispatchEvent(new CustomEvent('change', { + detail: { + selected: true, + value: filter[0].getAttribute('value'), + text: filter[0].textContent + } + })); + } + } + } + } + } + + initOptions() { + this.querySelectorAll('lit-select-option').forEach(a => { + if (this.isMultiple()) { + a.setAttribute('check', ''); + if (a.getAttribute('value') === this.defaultValue) { + let tag = this.newTag(a.getAttribute('value'), a.textContent); + this.multipleRootElement.insertBefore(tag, this.inputElement); + this.inputElement.placeholder = ''; + this.inputElement.value = ''; + this.inputElement.style.width = '1px'; + a.setAttribute('selected', ''); + } + } else { + if (a.getAttribute('value') === this.defaultValue) { + this.inputElement.value = a.textContent; + a.setAttribute('selected', ''); + } + } + a.addEventListener('onSelected', (e: any) => { + if (this.isMultiple()) { + if (a.hasAttribute('selected')) { + let tag = this.shadowRoot!.querySelector(`div[data-value=${e.detail.value}]`) as HTMLElement; + if (tag) { + tag.parentElement!.removeChild(tag); + } + e.detail.selected = false; + } else { + let tag = this.newTag(e.detail.value, e.detail.text); + this.multipleRootElement.insertBefore(tag, this.inputElement); + this.inputElement.placeholder = ''; + this.inputElement.value = ''; + this.inputElement.style.width = '1px'; + } + if (this.shadowRoot!.querySelectorAll('.tag').length == 0) { + this.inputElement.style.width = 'auto'; + this.inputElement.placeholder = this.defaultPlaceholder; + } + this.inputElement.focus(); + } else { + [...this.querySelectorAll('lit-select-option')].forEach(a => a.removeAttribute('selected')) + this.blur(); + // @ts-ignore + this.inputElement.value = e.detail.text; + } + if (a.hasAttribute('selected')) { + a.removeAttribute('selected') + } else { + a.setAttribute('selected', '') + } + // @ts-ignore + this.value = e.detail.value; + this.dispatchEvent(new CustomEvent('change', {detail: e.detail}));//向外层派发change事件,返回当前选中项 + }) + }) + } + + clear() { + this.inputElement.value = ''; + this.inputElement.placeholder = this.defaultPlaceholder; + } + + reset() { + this.querySelectorAll('lit-select-option').forEach(a => { + [...this.querySelectorAll('lit-select-option')].forEach(a => a.removeAttribute('selected')) + if (a.getAttribute('value') === this.defaultValue) { + this.inputElement.value = a.textContent; + a.setAttribute('selected', ''); + } + }) + } + + disconnectedCallback() { + + } + + adoptedCallback() { + } + + attributeChangedCallback(name: any, oldValue: any, newValue: any) { + if (name === 'value' && this.inputElement) { + if (newValue) { + [...this.querySelectorAll('lit-select-option')].forEach(a => { + if (a.getAttribute('value') === newValue) { + a.setAttribute('selected', ''); + this.inputElement.value = a.textContent; + } else { + a.removeAttribute('selected') + } + }) + } else { + this.clear(); + } + } + } } diff --git a/host/ide/src/base-ui/select/LitSelectOption.ts b/host/ide/src/base-ui/select/LitSelectOption.ts index 440097f0fbc379ebec633a082b9291028becca8d..0d1b967d5c3fe03cebcaaf7d46db5f73a5d95495 100644 --- a/host/ide/src/base-ui/select/LitSelectOption.ts +++ b/host/ide/src/base-ui/select/LitSelectOption.ts @@ -17,14 +17,14 @@ import {BaseElement} from "../BaseElement.js"; import "../icon/LitIcon.js" export class LitSelectOption extends BaseElement { - static get observedAttributes() { - return ['selected','disabled','check'] - } + static get observedAttributes() { + return ['selected', 'disabled', 'check'] + } - initHtml() { - // super(); - // const shadowRoot = this.attachShadow({mode: 'open'}); - return` + initHtml() { + // super(); + // const shadowRoot = this.attachShadow({mode: 'open'}); + return `
- +
` - } + } - initElements(): void { + initElements(): void { - } + } - //当 custom element首次被插入文档DOM时,被调用。 - connectedCallback() { - if(!this.hasAttribute('disabled')){ - this.onclick=ev => { - this.dispatchEvent(new CustomEvent('onSelected',{detail:{ - selected:true, - value: this.getAttribute('value'), - text: this.textContent - }})) - } - } + //当 custom element首次被插入文档DOM时,被调用。 + connectedCallback() { + if (!this.hasAttribute('disabled')) { + this.onclick = ev => { + this.dispatchEvent(new CustomEvent('onSelected', { + detail: { + selected: true, + value: this.getAttribute('value'), + text: this.textContent + } + })) + } + } - } + } - //当 custom element从文档DOM中删除时,被调用。 - disconnectedCallback() { + //当 custom element从文档DOM中删除时,被调用。 + disconnectedCallback() { - } + } - //当 custom element被移动到新的文档时,被调用。 - adoptedCallback() { - } + //当 custom element被移动到新的文档时,被调用。 + adoptedCallback() { + } - //当 custom element增加、删除、修改自身属性时,被调用。 - attributeChangedCallback(name:any, oldValue:any, newValue:any) { + //当 custom element增加、删除、修改自身属性时,被调用。 + attributeChangedCallback(name: any, oldValue: any, newValue: any) { - } + } } if (!customElements.get('lit-select-option')) { - customElements.define('lit-select-option', LitSelectOption); + customElements.define('lit-select-option', LitSelectOption); } diff --git a/host/ide/src/base-ui/slider/LitSlider.ts b/host/ide/src/base-ui/slider/LitSlider.ts index fa7042104174350c1e69c5345ca2aa7639b50c7e..9cd7d1ece2a71f89feab4cc59fd7441c28954e27 100644 --- a/host/ide/src/base-ui/slider/LitSlider.ts +++ b/host/ide/src/base-ui/slider/LitSlider.ts @@ -21,54 +21,57 @@ export class LitSlider extends BaseElement { private litSlider: HTMLInputElement | undefined | null; private litSliderCon: HTMLDivElement | undefined | null; private litResult: HTMLInputElement | undefined | null; - private litSliderButton: HTMLDivElement | undefined | null; private slotEl: HTMLSlotElement | undefined | null; private currentValue: number = 0; - private sliderLineHeight: string | undefined; - private sliderButtonHeight: string | undefined; - private sliderButtonWidth: string | undefined; private defaultTimeText: string | undefined | null; static get observedAttributes() { return ['percent', 'disabled-X', 'custom-slider', 'custom-line', 'custom-button'] } - get sliderStyle() { - if (this.hasAttribute('custom-slider')) { - this.defaultTimeText = "64"; - return { - minRange: 4, - maxRange: 512, - defaultValue: this.defaultTimeText, - resultUnit: "MB", - stepSize: 2, - lineColor: "var(--dark-color3,#46B1E3)", - buttonColor: "#999999" - } + get sliderStyle(): LitSliderStyle { + if (this.litSliderStyle) { + return this.litSliderStyle } else { - let defaultTime = "00:00:50"; - this.defaultTimeText = defaultTime.split(':')[2]; return { - minRange: 10, - maxRange: 600, - defaultValue: defaultTime, - resultUnit: "h:m:s", + minRange: 0, + maxRange: 100, + defaultValue: "0", + resultUnit: "", stepSize: 1, - lineColor: "var(--dark-color4,#61CFBE)", + lineColor: "var(--dark-color3,#46B1E3)", buttonColor: "#999999" } } - } - set sliderStyle(value) { + set sliderStyle(value: LitSliderStyle) { this.litSliderStyle = value; - this.litSliderStyle = this.sliderStyle; + this.currentValue = Number(value.defaultValue) this.litSliderStyle.defaultValue = value.defaultValue - if (this.hasAttribute('custom-slider')) { - this.renderCustomSlider(); + if (this.litSliderStyle.resultUnit === 'h:m:s') { + let timeData = this.litSliderStyle.defaultValue.split(':'); + let timeSize = Number(timeData[0]) * 3600 + Number(timeData[1]) * 60 + Number(timeData[2]); + this.defaultTimeText = timeSize.toString() + let defaultSize = (timeSize - this.litSliderStyle.minRange) * 100 / (this.litSliderStyle + .maxRange - this.litSliderStyle.minRange); + this.litSlider!.style.backgroundSize = defaultSize + '%' } else { - this.renderDefaultSlider(); + this.defaultTimeText = this.litSliderStyle.defaultValue + this.litSlider!.style.backgroundSize = '0%' + if (Number(this.litSliderStyle.defaultValue)) { + let defaultSize = (Number(this.litSliderStyle.defaultValue) - this.litSliderStyle.minRange) + / (this.litSliderStyle.maxRange - this.litSliderStyle.minRange) * 100; + this.litSlider!.style.backgroundSize = defaultSize + '%' + } + } + let htmlInputElement = this.shadowRoot?.querySelector('#slider') as HTMLInputElement; + let attribute = htmlInputElement.getAttribute('type'); + if (attribute === 'range') { + htmlInputElement!.setAttribute('value', this.defaultTimeText!) + htmlInputElement!.setAttribute('min', this.litSliderStyle!.minRange.toString()) + htmlInputElement!.setAttribute('max', this.litSliderStyle!.maxRange.toString()) + htmlInputElement!.setAttribute('step', this.litSliderStyle!.stepSize.toString()) } } @@ -118,6 +121,9 @@ export class LitSlider extends BaseElement { set percent(value: string) { this.setAttribute('percent', value); + if (Number(this.sliderStyle.defaultValue)) { + this.currentValue = Number(this.sliderStyle.defaultValue) + } } get resultUnit() { @@ -128,20 +134,11 @@ export class LitSlider extends BaseElement { this.setAttribute('resultUnit', value); } - get sliderSize() { - return this.currentValue; - } - initElements(): void { + this.litSlider = this.shadowRoot?.querySelector('#slider') as HTMLInputElement; } initHtml(): string { - this.litSliderStyle = this.sliderStyle; - this.currentValue = Number(this.sliderStyle.defaultValue); - let parentElement = this.parentNode as Element; - if (parentElement) { - parentElement.setAttribute('percent', this.defaultTimeText + ""); - } return `
- - ${this.litSliderStyle?.resultUnit} +
` } @@ -296,64 +248,35 @@ export class LitSlider extends BaseElement { // It is called when the custom element is first inserted into the document DOM. connectedCallback() { this.slotEl = this.shadowRoot?.querySelector('#slot'); - this.litSlider = this.shadowRoot?.querySelector('#slider'); this.litSliderCon = this.shadowRoot?.querySelector('#slider-con'); - this.litResult = this.shadowRoot?.querySelector('#result'); // Add a slider for input event listeners this.litSlider?.addEventListener('input', this.inputChangeEvent) this.litSlider?.addEventListener('change', this.inputChangeEvent) - // Add slot slot to change event listeners - this.slotEl?.addEventListener('slotchange', this.slotChangeEvent); - // Add a slider for line click event listeners - this.litSlider?.addEventListener('click', this.sliderClickEvent); - // Add a slider button to start touching the event listener - this.litSliderButton?.addEventListener('TouchEvent', this.sliderStartTouchEvent); this.litSliderStyle = this.sliderStyle; } - slotChangeEvent = (event: any) => { - } - - sliderClickEvent = (event: any) => { - } - inputChangeEvent = (event: any) => { if (this.litSlider) { this.currentValue = parseInt(this.litSlider?.value) - let resultNumber = (this.currentValue - this.litSliderStyle!.minRange) * 100 / (this.litSliderStyle!.maxRange - this.litSliderStyle!.minRange); - this.percent = Math.floor(resultNumber) + "%"; + let resultNumber = (this.currentValue - this.litSliderStyle!.minRange) * 100 / (this + .litSliderStyle!.maxRange - this.litSliderStyle!.minRange); + this.percent = Number(resultNumber) + "%"; this.litSliderCon?.style.setProperty('percent', this.currentValue + "%") let parentElement = this.parentNode as Element; parentElement.setAttribute('percent', this.currentValue + ""); - if (this.sliderStyle.resultUnit === 'MB') { + if (this.sliderStyle.resultUnit === 'h:m:s') { this.litSlider!.style.backgroundSize = this.percent; - this.litResult!.value = " " + this.currentValue; - } else if (this.sliderStyle.resultUnit === 'h:m:s') { + } else { this.litSlider!.style.backgroundSize = this.percent; - let time = this.formatSeconds(this.litSlider?.value); - this.litResult!.value = " " + time; } + this.parentElement!.setAttribute('percent', this.litSlider?.value) } } - sliderStartTouchEvent = (event: any) => { - - } - - sliderMoveTouchEvent = (event: any) => { - - } - - sliderEndTouchEvent = (event: any) => { - - } - disconnectedCallback() { this.litSlider?.removeEventListener('input', this.inputChangeEvent); this.litSlider?.removeEventListener('change', this.inputChangeEvent) - this.litSlider?.removeEventListener('click', this.sliderClickEvent); - this.litSliderButton?.removeEventListener('TouchEvent', this.sliderStartTouchEvent); } adoptedCallback() { @@ -374,17 +297,23 @@ export class LitSlider extends BaseElement { } } - renderCustomSlider() { - } - renderDefaultSlider() { - if (!this.litSliderStyle) return; + let htmlInputElement = this.shadowRoot?.querySelector('#slider') as HTMLInputElement; + let attribute = htmlInputElement.getAttribute('type'); + if (attribute === 'range') { + htmlInputElement!.setAttribute('value', this.defaultTimeText!) + htmlInputElement!.setAttribute('min', this.litSliderStyle!.minRange.toString()) + htmlInputElement!.setAttribute('max', this.litSliderStyle!.maxRange.toString()) + htmlInputElement!.setAttribute('step', this.litSliderStyle!.stepSize.toString()) + } } formatSeconds(value: string) { let result = parseInt(value) - let hours = Math.floor(result / 3600) < 10 ? '0' + Math.floor(result / 3600) : Math.floor(result / 3600); - let minute = Math.floor((result / 60 % 60)) < 10 ? '0' + Math.floor((result / 60 % 60)) : Math.floor((result / 60 % 60)); + let hours = Math.floor(result / 3600) < 10 ? '0' + Math.floor(result / 3600) : Math + .floor(result / 3600); + let minute = Math.floor((result / 60 % 60)) < 10 ? '0' + Math + .floor((result / 60 % 60)) : Math.floor((result / 60 % 60)); let second = Math.floor((result % 60)) < 10 ? '0' + Math.floor((result % 60)) : Math.floor((result % 60)); let resultTime = ''; if (hours === '00') { @@ -407,7 +336,7 @@ export interface LitSliderStyle { maxRange: number defaultValue: string resultUnit: string - stepSize?: number + stepSize: number lineColor?: string buttonColor?: string } diff --git a/host/ide/src/base-ui/switch/lit-switch.ts b/host/ide/src/base-ui/switch/lit-switch.ts index 2dc25eaef92b593d9f371b835930c43792c0cd6d..b9bf2e43247d1163815867201ad632ff00619187 100644 --- a/host/ide/src/base-ui/switch/lit-switch.ts +++ b/host/ide/src/base-ui/switch/lit-switch.ts @@ -71,9 +71,14 @@ export default class LitSwitch extends BaseElement { height:1.2em; padding:.125em; border-radius:1.2em; - background:#eee; + background: #3391FF; transition:.3s width,.3s height,.3s background-color; } + + :host(:not([checked])) #name { + background: #999999; + } + #name::before{ content:''; flex:0; diff --git a/host/ide/src/base-ui/table/lit-table-column.ts b/host/ide/src/base-ui/table/lit-table-column.ts index b66d3004018cbedfce1300070da3a6e1daad2fc3..9c9f1956b623494f8dd10e3c4cd70ac7120b4678 100644 --- a/host/ide/src/base-ui/table/lit-table-column.ts +++ b/host/ide/src/base-ui/table/lit-table-column.ts @@ -25,13 +25,13 @@ export class LitTableColumn extends HTMLElement { super(); const shadowRoot = this.attachShadow({mode: 'open'}); shadowRoot.innerHTML = ` - - + + ` } diff --git a/host/ide/src/base-ui/table/lit-table.ts b/host/ide/src/base-ui/table/lit-table.ts index 7a6dab11a1bd1461c481db69b432914305272191..ec325bde13c122f27dfec96c5048a0b89b0e5fe8 100644 --- a/host/ide/src/base-ui/table/lit-table.ts +++ b/host/ide/src/base-ui/table/lit-table.ts @@ -13,7 +13,6 @@ * limitations under the License. */ - import {LitTableColumn} from "./lit-table-column.js"; import {element} from "../BaseElement.js"; import "../utils/Template.js" @@ -24,6 +23,7 @@ export class LitTable extends HTMLElement { meauseRowElement: HTMLDivElement | undefined currentRecycleList: HTMLDivElement[] = [] currentTreeDivList: HTMLDivElement[] = [] + public rememberScrollTop = false private ds: Array = [] private recycleDs: Array = [] private gridTemplateColumns: any @@ -36,161 +36,167 @@ export class LitTable extends HTMLElement { private treeElement: HTMLDivElement | undefined | null private tableColumns: NodeListOf | undefined private colCount: number = 0 + private currentScrollTop: number = 0 constructor() { super(); const shadowRoot = this.attachShadow({mode: 'open'}); shadowRoot.innerHTML = ` - + } + :host([grid-line]) .td{ + border-left: 1px solid #f0f0f0; + } + :host([grid-line]) .td:last-of-type{ + border-right: 1px solid #f0f0f0; + } + .table{ + width: 100%; + color: var(--dark-color2,#262626); + } + .thead{ + display: grid; + position: sticky; + top: 0; + font-weight: bold; + font-size: .9rem; + color: var(--dark-color1,#000); + background-color: var(--dark-background,#FFFFFF); + z-index: 1; + } + .tbody{ + width: 100%; + top: 0; + left: 0; + right:0; + bottom:0; + display: flex; + flex-direction: row + row-gap: 1px; + column-gap: 1px; + } + .tree{ + overflow-x:overlay; + overflow-y:hidden; + display: grid; + grid-template-columns: 1fr; + row-gap: 1px; + column-gap: 1px; + position:relative; + } + .tree-first-body{ + min-width: 100%; + box-sizing: border-box; + display:flex; + align-items:center; + white-space: nowrap; + cursor: pointer; + } + .tree-first-body:hover{ + background-color: var(--dark-background6,#DEEDFF); /*antd #fafafa 42b983*/ + } + .body{ + display: grid; + grid-template-columns: 1fr; + row-gap: 1px; + column-gap: 1px; + flex:1; + position: relative; + } + :host([grid-line]) .tbody{ + border-bottom: 1px solid #f0f0f0; + background-color: #f0f0f0; + } + .th{ + display: grid; + } - -
-
-
-
-
-
-
- ` + .tree-icon{ + font-size: 1.2rem; + width: 20px; + height: 20px; + padding-right: 5px; + padding-left: 5px; + cursor: pointer; + } + .tree-icon:hover{ + color: #42b983; + } + .row-checkbox,row-checkbox-all{ + + } + :host([no-head]) .thead{ + display: none; + } + .up-svg{ + position: absolute; + right: 5px; + top: 8px; + bottom: 8px; + width: 15px; + height: 15px; + } + .down-svg{ + position: absolute; + top: 8px; + right: 5px; + bottom: 8px; + width: 15px; + height: 15px; + } + .mouse-select{ + background-color: var(--dark-background6,#DEEDFF); + } + .mouse-in{ + background-color: var(--dark-background6,#DEEDFF); + } + + +
+
+
+
+
+
+
+ ` } static get observedAttributes() { @@ -235,15 +241,25 @@ export class LitTable extends HTMLElement { } set recycleDataSource(value) { - this.tableElement!.scrollTop = 0 + if(this.rememberScrollTop){ + this.currentScrollTop = this.tableElement!.scrollTop; + this.tableElement!.scrollTop = 0 + }else { + this.tableElement!.scrollTop = 0 + } if (this.hasAttribute('tree')) { this.recycleDs = this.meauseTreeRowElement(value) } else { this.recycleDs = this.meauseAllRowHeight(value) } + + + } + + move1px(){ + this.tableElement!.scrollTop = this.tableElement!.scrollTop + 1 } - // It is called when the custom element is first inserted into the document DOM. connectedCallback() { this.st = this.shadowRoot?.querySelector('#slot'); this.tableElement = this.shadowRoot?.querySelector('.table'); @@ -411,6 +427,7 @@ export class LitTable extends HTMLElement { rowElement.style.gridTemplateRows = `repeat(${area.length},1fr)` rowElement.style.gridTemplateAreas = s } + this.theadElement!.innerHTML = '' this.theadElement!.append(rowElement); this.treeElement!.style.top = this.theadElement?.clientHeight + "px" }); @@ -718,7 +735,7 @@ export class LitTable extends HTMLElement { tableRowObject.data = rowData tableRowObject.rowIndex = index if (Math.max(totalHeight, this.tableElement!.scrollTop + headHeight) <= Math.min(totalHeight + height, this.tableElement!.scrollTop + this.tableElement!.clientHeight + headHeight)) { - let newTableElement = this.createNewTableElement(rowData); + let newTableElement = this.createNewTableElement(tableRowObject); newTableElement.style.transform = `translateY(${totalHeight}px)` this.tbodyElement?.append(newTableElement) this.currentRecycleList.push(newTableElement) @@ -736,12 +753,12 @@ export class LitTable extends HTMLElement { break; } } - let reduce = this.currentRecycleList.map((item) => item.clientHeight).reduce((a, b) => a + b,0); - if(reduce == 0){ + let reduce = this.currentRecycleList.map((item) => item.clientHeight).reduce((a, b) => a + b, 0); + if (reduce == 0) { return } while (reduce <= this.tableElement!.clientHeight) { - let newTableElement = this.createNewTableElement(visibleObjects[skip].data); + let newTableElement = this.createNewTableElement(visibleObjects[skip]); this.tbodyElement?.append(newTableElement) this.currentRecycleList.push(newTableElement) reduce += newTableElement.clientHeight @@ -804,8 +821,8 @@ export class LitTable extends HTMLElement { break; } } - let reduce = this.currentRecycleList.map((item) => item.clientHeight).reduce((a, b) => a + b,0); - if(reduce == 0){ + let reduce = this.currentRecycleList.map((item) => item.clientHeight).reduce((a, b) => a + b, 0); + if (reduce == 0) { return } while (reduce <= this.tableElement!.clientHeight) { @@ -853,6 +870,7 @@ export class LitTable extends HTMLElement { } else { td.style.paddingLeft = rowData.depth * 15 + 20 + 'px'; } + (td as any).data = rowData.data td.classList.add('tree-first-body'); td.style.position = 'absolute'; td.style.top = '0px' @@ -860,20 +878,18 @@ export class LitTable extends HTMLElement { td.onmouseover = () => { let indexOf = this.currentTreeDivList.indexOf(td); if (indexOf >= 0 && indexOf < this.currentRecycleList.length && td.innerHTML != "") { - this.setSelectedRow(true,[(this.treeElement?.children[indexOf] as HTMLElement),newTableElement]); + this.setMouseIn(true, [(this.treeElement?.children[indexOf] as HTMLElement), newTableElement]); } } td.onmouseout = () => { let indexOf = this.currentTreeDivList.indexOf(td); if (indexOf >= 0 && indexOf < this.currentRecycleList.length) { - this.setSelectedRow(false,[(this.treeElement?.children[indexOf] as HTMLElement),newTableElement]); + this.setMouseIn(false, [(this.treeElement?.children[indexOf] as HTMLElement), newTableElement]); } } td.onclick = () => { - this.dispatchEvent(new CustomEvent('row-click', {detail: {...rowData.data,callBack:(isSelected:boolean)=>{ - let indexOf = this.currentTreeDivList.indexOf(td); - this.setSelectedRow(isSelected,[(this.currentRecycleList[indexOf] as HTMLElement),td]) - }}, composed: true,})); + let indexOf = this.currentTreeDivList.indexOf(td); + this.dispatchRowClickEvent(rowData, [(this.treeElement?.children[indexOf] as HTMLElement), newTableElement]) } this.treeElement!.style.width = column.getAttribute('width') this.treeElement?.append(td) @@ -889,7 +905,7 @@ export class LitTable extends HTMLElement { td.title = rowData.data[dataIndex] // td.innerHTML = rowData.data[dataIndex]; td.dataIndex = dataIndex - td.style.justifyContent = column.getAttribute('align')||'flex-start' + td.style.justifyContent = column.getAttribute('align') || 'flex-start' if (column.template) { td.appendChild(column.template.render(rowData.data).content.cloneNode(true)); td.template = column.template @@ -900,25 +916,29 @@ export class LitTable extends HTMLElement { } }); (this.treeElement?.lastChild as HTMLElement).style.transform = `translateY(${treeTop}px)`; + (newTableElement as any).data = rowData.data newTableElement.style.gridTemplateColumns = gridTemplateColumns.join(' '); newTableElement.style.position = 'absolute'; newTableElement.style.top = '0px' newTableElement.style.left = '0px' newTableElement.style.cursor = 'pointer' newTableElement.onmouseover = () => { + if ((newTableElement as any).data.isSelected) return; let indexOf = this.currentRecycleList.indexOf(newTableElement); if (indexOf >= 0 && indexOf < this.treeElement!.children.length) { - this.setSelectedRow(true,[(this.treeElement?.children[indexOf] as HTMLElement),newTableElement]); + this.setMouseIn(true, [(this.treeElement?.children[indexOf] as HTMLElement), newTableElement]); } } newTableElement.onmouseout = () => { + if ((newTableElement as any).data.isSelected) return; let indexOf = this.currentRecycleList.indexOf(newTableElement); if (indexOf >= 0 && indexOf < this.treeElement!.children.length) { - this.setSelectedRow(false,[(this.treeElement?.children[indexOf] as HTMLElement),newTableElement]); + this.setMouseIn(false, [(this.treeElement?.children[indexOf] as HTMLElement), newTableElement]); } } newTableElement.onclick = e => { - this.dispatchEvent(new CustomEvent('row-click', {detail: rowData.data, composed: true})); + let indexOf = this.currentRecycleList.indexOf(newTableElement); + this.dispatchRowClickEvent(rowData, [(this.treeElement?.children[indexOf] as HTMLElement), newTableElement]) } return newTableElement } @@ -993,8 +1013,8 @@ export class LitTable extends HTMLElement { break; } } - let reduce = this.currentRecycleList.map((item) => item.clientHeight).reduce((a, b) => a + b,0); - if(reduce == 0){ + let reduce = this.currentRecycleList.map((item) => item.clientHeight).reduce((a, b) => a + b, 0); + if (reduce == 0) { return } while (reduce <= this.tableElement!.clientHeight) { @@ -1002,7 +1022,7 @@ export class LitTable extends HTMLElement { if (this.hasAttribute('tree')) { newTableElement = this.createNewTreeTableElement(visibleObjects[skip]); } else { - newTableElement = this.createNewTableElement(visibleObjects[skip].data) + newTableElement = this.createNewTableElement(visibleObjects[skip]) } this.tbodyElement?.append(newTableElement) if (this.hasAttribute('tree')) { @@ -1036,36 +1056,23 @@ export class LitTable extends HTMLElement { td.style.textOverflow = 'ellipsis' td.style.whiteSpace = "nowrap" td.dataIndex = dataIndex - td.style.justifyContent = column.getAttribute('align')||'flex-start' - td.title = rowData[dataIndex] + td.style.justifyContent = column.getAttribute('align') || 'flex-start' + td.title = rowData.data[dataIndex] if (column.template) { - td.appendChild(column.template.render(rowData).content.cloneNode(true)); + td.appendChild(column.template.render(rowData.data).content.cloneNode(true)); td.template = column.template } else { - td.innerHTML = rowData[dataIndex]; + td.innerHTML = rowData.data[dataIndex]; } newTableElement.append(td) }) - newTableElement.onclick = ()=>{ - let detail = {...rowData,selectedCallback:()=>{ - if (detail.isSelected != undefined) { - if(detail.isSelected){ - newTableElement.setAttribute("selected","") - }else { - newTableElement.removeAttribute("selected") - } - rowData.isSelected = !rowData.isSelected - } - }} - this.dispatchEvent(new CustomEvent('row-click', {detail: detail, composed: true})); + newTableElement.onclick = () => { + this.dispatchRowClickEvent(rowData, [newTableElement]) } - if (rowData.isSelected != undefined) { - if(rowData.isSelected){ - newTableElement.setAttribute("selected","") - }else { - newTableElement.removeAttribute("selected") - } + if (rowData.data.isSelected != undefined) { + this.setSelectedRow(rowData.data.isSelected, [newTableElement]) } + (newTableElement as any).data = rowData.data newTableElement.style.cursor = "pointer" newTableElement.style.gridTemplateColumns = gridTemplateColumns.join(' '); newTableElement.style.position = 'absolute'; @@ -1084,10 +1091,11 @@ export class LitTable extends HTMLElement { } let childIndex = -1 element.childNodes.forEach((child) => { - if(child.nodeType!=1)return + if (child.nodeType != 1) return childIndex++; let idx = firstElement != undefined ? childIndex + 1 : childIndex; if (firstElement != undefined && childIndex == 0) { + (firstElement as any).data = rowObject.data if ((this.columns![0] as any).template) { firstElement.innerHTML = (this.columns![0] as any).template.render(rowObject.data).content.cloneNode(true).innerHTML } else { @@ -1100,12 +1108,17 @@ export class LitTable extends HTMLElement { firstElement.insertBefore(btn, firstElement.firstChild); firstElement.style.paddingLeft = 15 * rowObject.depth + "px" } else { - firstElement.style.paddingLeft = 15 + 20 * rowObject.depth + "px" + firstElement.style.paddingLeft = 20 + 15 * rowObject.depth + "px" } firstElement.onclick = () => { - this.dispatchEvent(new CustomEvent('row-click', {detail: rowObject.data, composed: true})); + this.dispatchRowClickEvent(rowObject, [firstElement, element]) } firstElement.style.transform = `translateY(${rowObject.top - this.tableElement!.scrollTop}px)` + if (rowObject.data.isSelected != undefined) { + this.setSelectedRow(rowObject.data.isSelected, [firstElement]) + } else { + this.setSelectedRow(false, [firstElement]) + } } if ((this.columns![idx] as any).template) { (child as HTMLElement).innerHTML = ""; @@ -1116,7 +1129,7 @@ export class LitTable extends HTMLElement { (child as HTMLElement).title = rowObject.data[dataIndex]; } }) - if(element.style.display == 'none'){ + if (element.style.display == 'none') { element.style.display = 'grid' } element.style.transform = `translateY(${rowObject.top}px)` @@ -1124,38 +1137,108 @@ export class LitTable extends HTMLElement { firstElement.style.display = 'flex' } element.onclick = e => { - let datail = {...rowObject.data,selectedCallback:()=>{ - if (datail.isSelected != undefined) { - if(datail.isSelected){ - element.setAttribute("selected","") - }else { - element.removeAttribute("selected") - } - rowObject.data.isSelected = !rowObject.data.isSelected - } - }} - this.dispatchEvent(new CustomEvent('row-click', {detail: datail, composed: true})); + if (firstElement != undefined) { + this.dispatchRowClickEvent(rowObject, [firstElement, element]) + } else { + this.dispatchRowClickEvent(rowObject, [element]) + } } + (element as any).data = rowObject.data if (rowObject.data.isSelected != undefined) { - if(rowObject.data.isSelected){ - element.setAttribute("selected","") - }else { - element.removeAttribute("selected") + this.setSelectedRow(rowObject.data.isSelected, [element]) + } else { + this.setSelectedRow(false, [element]) + } + } + + setSelectedRow(isSelected: boolean, rows: any[]) { + if (isSelected) { + rows.forEach((row) => { + if (row.classList.contains("mouse-in")) row.classList.remove('mouse-in'); + row.classList.add('mouse-select') + // row.style.backgroundColor = "var(--dark-background6,#DEEDFF)" + }) + } else { + rows.forEach((row) => { + row.classList.remove('mouse-select') + // row.style.backgroundColor = "var(--dark-background,#FFFFFF)" + }) + } + } + + setMouseIn(isMouseIn: boolean, rows: any[]) { + if (isMouseIn) { + rows.forEach((row) => { + row.classList.add('mouse-in') + }) + } else { + rows.forEach((row) => { + row.classList.remove('mouse-in') + }) + } + } + + scrollToData(data: any) { + if (this.recycleDs.length > 0) { + let filter = this.recycleDs.filter((item) => { + return item.data == data + }); + if (filter.length > 0) { + this.tableElement!.scrollTop = filter[0].top } - }else { - element.removeAttribute("selected") + this.setCurrentSelection(data) } + } - setSelectedRow(isSelected:boolean,rows:any[]){ - if(isSelected){ - rows.forEach((row)=>{ - row.style.backgroundColor = "var(--dark-background6,#DEEDFF)" + expandList(datasource: any[]) { + let filter = this.recycleDs.filter((item) => { + return datasource.indexOf(item.data) != -1 + }); + if (filter.length > 0) { + filter.forEach((item) => { + item.expanded = true + item.rowHidden = false }) - }else { - rows.forEach((row)=>{ - row.style.backgroundColor = "var(--dark-background,#FFFFFF)" + } + this.reMeauseHeight() + } + + clearAllSelection(rowObjectData: any) { + this.recycleDs.forEach((item) => { + if (item.data != rowObjectData && item.data.isSelected) { + item.data.isSelected = false + } + }) + this.setSelectedRow(false, this.currentTreeDivList) + this.setSelectedRow(false, this.currentRecycleList) + } + + setCurrentSelection(data: any) { + if (data.isSelected != undefined) { + this.currentTreeDivList.forEach((item) => { + if ((item as any).data == data) { + this.setSelectedRow(data.isSelected, [item]) + } + }) + this.currentRecycleList.forEach((item) => { + if ((item as any).data == data) { + this.setSelectedRow(data.isSelected, [item]) + } }) } } + + dispatchRowClickEvent(rowObject: any, elements: any[]) { + this.dispatchEvent(new CustomEvent('row-click', { + detail: { + ...rowObject.data, data: rowObject.data, callBack: (isSelected: boolean) => {//是否爲单选 + if (isSelected) { + this.clearAllSelection(rowObject.data) + } + this.setSelectedRow(rowObject.data.isSelected, elements) + } + }, composed: true, + })); + } } diff --git a/host/ide/src/base-ui/tabs/lit-tabpane.ts b/host/ide/src/base-ui/tabs/lit-tabpane.ts index 1f8c681b7b443bac9f651fe04018fe9d42a8fa4c..ab2f8c9094c20421012084037961afaeaab606fd 100644 --- a/host/ide/src/base-ui/tabs/lit-tabpane.ts +++ b/host/ide/src/base-ui/tabs/lit-tabpane.ts @@ -80,16 +80,16 @@ export class LitTabpane extends BaseElement { initHtml(): string { return ` - - -`; + + + `; } connectedCallback() { diff --git a/host/ide/src/command/cmd.ts b/host/ide/src/command/cmd.ts new file mode 100644 index 0000000000000000000000000000000000000000..2b22a567348112ce184de032d508c1124ddcd855 --- /dev/null +++ b/host/ide/src/command/cmd.ts @@ -0,0 +1,40 @@ +/* + * 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. + */ +export class Cmd { + /** + * exec objdump to disassembling binary and find addr to show 100 line + * @param command obj dump command + * @param addr addr of select line + * @param callback result callback + */ + static execObjDump(command : string, addr : string, callback: Function){ + const data = { cmd: command ,addr : addr}; + let uri = `http://${window.location.host.split(':')[0]}:${window.location.port}/exec`; + fetch(uri, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify(data), + }).then(response => { + if (response.ok) { + let result = response.text(); + result.then(output =>{ + callback(output); + }); + } + }); + } +} \ No newline at end of file diff --git a/host/ide/src/figures/Options.jpg b/host/ide/src/figures/Options.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4d8dbf96bf958027b2bd27390dd19bbc5d396514 Binary files /dev/null and b/host/ide/src/figures/Options.jpg differ diff --git a/host/ide/src/figures/PerfProfile.jpg b/host/ide/src/figures/PerfProfile.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a348c291172e0c5ca0a25356d25cc5d738f49aa1 Binary files /dev/null and b/host/ide/src/figures/PerfProfile.jpg differ diff --git a/host/ide/src/figures/ProcessesHistory.jpg b/host/ide/src/figures/ProcessesHistory.jpg new file mode 100644 index 0000000000000000000000000000000000000000..59ddc205b3b4ca3fa6ee13342c2e251494677896 Binary files /dev/null and b/host/ide/src/figures/ProcessesHistory.jpg differ diff --git a/host/ide/src/figures/Samplelist.jpg b/host/ide/src/figures/Samplelist.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f161a6c5a40405149ae296df339b43c154c2f81d Binary files /dev/null and b/host/ide/src/figures/Samplelist.jpg differ diff --git a/host/ide/src/figures/Scheduling.jpg b/host/ide/src/figures/Scheduling.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f7c5dd57bfcb038656d0fbe80cc7e685701ae479 Binary files /dev/null and b/host/ide/src/figures/Scheduling.jpg differ diff --git a/host/ide/src/figures/abilitymonitorflowchart.jpg b/host/ide/src/figures/abilitymonitorflowchart.jpg new file mode 100644 index 0000000000000000000000000000000000000000..15c86a5b816003dbb850e203794d3ee8c7a0c2f7 Binary files /dev/null and b/host/ide/src/figures/abilitymonitorflowchart.jpg differ diff --git a/host/ide/src/figures/callstack.jpg b/host/ide/src/figures/callstack.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7da3c78f87ebbd4653ddbdd9b0036c5a2814fe8e Binary files /dev/null and b/host/ide/src/figures/callstack.jpg differ diff --git a/host/ide/src/figures/callstackclick.jpg b/host/ide/src/figures/callstackclick.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bd9ed65526a34d967a1ac45b15aa8ecf96a0d1a4 Binary files /dev/null and b/host/ide/src/figures/callstackclick.jpg differ diff --git a/host/ide/src/figures/callstackselect.jpg b/host/ide/src/figures/callstackselect.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ccdbde9c618790875c1d1646f49504eca1f39583 Binary files /dev/null and b/host/ide/src/figures/callstackselect.jpg differ diff --git a/host/ide/src/figures/chart.jpg b/host/ide/src/figures/chart.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c17758ab78a2fd465bed0c13eeb84ad9e95fe588 Binary files /dev/null and b/host/ide/src/figures/chart.jpg differ diff --git a/host/ide/src/figures/command.jpg b/host/ide/src/figures/command.jpg new file mode 100644 index 0000000000000000000000000000000000000000..553077d0f5dcea3276b090162992f95f650cae1c Binary files /dev/null and b/host/ide/src/figures/command.jpg differ diff --git a/host/ide/src/figures/cpu.jpg b/host/ide/src/figures/cpu.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f21a80d736774623f24a8f6a1472d5d7b4a2ad30 Binary files /dev/null and b/host/ide/src/figures/cpu.jpg differ diff --git a/host/ide/src/figures/cpu_frequency.png b/host/ide/src/figures/cpu_frequency.png new file mode 100644 index 0000000000000000000000000000000000000000..a18715fc696b3231b94425e4acd6aaf319bf399f Binary files /dev/null and b/host/ide/src/figures/cpu_frequency.png differ diff --git a/host/ide/src/figures/cpubyprocess.jpg b/host/ide/src/figures/cpubyprocess.jpg new file mode 100644 index 0000000000000000000000000000000000000000..180597dcbe73e1dba3ce58f348ca5b71da9077bd Binary files /dev/null and b/host/ide/src/figures/cpubyprocess.jpg differ diff --git a/host/ide/src/figures/cpubythread.jpg b/host/ide/src/figures/cpubythread.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0ada58ba849f9b2c5dcfa83c44fdda94ab696879 Binary files /dev/null and b/host/ide/src/figures/cpubythread.jpg differ diff --git a/host/ide/src/figures/cpuclick.jpg b/host/ide/src/figures/cpuclick.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f1a3c6d358474a1c649993cd673b66fade9871d6 Binary files /dev/null and b/host/ide/src/figures/cpuclick.jpg differ diff --git a/host/ide/src/figures/cpusage.jpg b/host/ide/src/figures/cpusage.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0aba4c0ee62c02bc846ab17d3f2cdb244dbe66d2 Binary files /dev/null and b/host/ide/src/figures/cpusage.jpg differ diff --git a/host/ide/src/figures/cpusummary.jpg b/host/ide/src/figures/cpusummary.jpg new file mode 100644 index 0000000000000000000000000000000000000000..83b2fcac39d8e119c502275efed6a40af9c7f2c4 Binary files /dev/null and b/host/ide/src/figures/cpusummary.jpg differ diff --git a/host/ide/src/figures/datamining.jpg b/host/ide/src/figures/datamining.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f8967408ff899f96f86492bbc1ba81c0a169ae5a Binary files /dev/null and b/host/ide/src/figures/datamining.jpg differ diff --git a/host/ide/src/figures/disktab.jpg b/host/ide/src/figures/disktab.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4eaa9d89a260542ae24354db834b695b7b47971c Binary files /dev/null and b/host/ide/src/figures/disktab.jpg differ diff --git a/host/ide/src/figures/dump_and_mem.png b/host/ide/src/figures/dump_and_mem.png new file mode 100644 index 0000000000000000000000000000000000000000..b7e3cc26ca286702c9ca9869fc203aff34a8da39 Binary files /dev/null and b/host/ide/src/figures/dump_and_mem.png differ diff --git a/host/ide/src/figures/excutecommand.jpg b/host/ide/src/figures/excutecommand.jpg new file mode 100644 index 0000000000000000000000000000000000000000..08335f77d94cb19252bb4cee92944339b8bab64c Binary files /dev/null and b/host/ide/src/figures/excutecommand.jpg differ diff --git a/host/ide/src/figures/filters.png b/host/ide/src/figures/filters.png new file mode 100644 index 0000000000000000000000000000000000000000..a02d9416f08382ff7a03e176e37e6479f5922c08 Binary files /dev/null and b/host/ide/src/figures/filters.png differ diff --git a/host/ide/src/figures/fps.jpg b/host/ide/src/figures/fps.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bfc18dfe881b738f6e9b100e4e32d5ab04dcb383 Binary files /dev/null and b/host/ide/src/figures/fps.jpg differ diff --git a/host/ide/src/figures/fpsselect.jpg b/host/ide/src/figures/fpsselect.jpg new file mode 100644 index 0000000000000000000000000000000000000000..14300f78ce384f8ad0366657e3b0eed2177e7505 Binary files /dev/null and b/host/ide/src/figures/fpsselect.jpg differ diff --git a/host/ide/src/figures/gray.jpg b/host/ide/src/figures/gray.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9bdb38037a286ea531485e6445553ea61f6d2e04 Binary files /dev/null and b/host/ide/src/figures/gray.jpg differ diff --git a/host/ide/src/figures/heaviesttrace1.jpg b/host/ide/src/figures/heaviesttrace1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6fdcf73b541fc60c8d66cbad04e16218a8c395db Binary files /dev/null and b/host/ide/src/figures/heaviesttrace1.jpg differ diff --git a/host/ide/src/figures/highlit.jpg b/host/ide/src/figures/highlit.jpg new file mode 100644 index 0000000000000000000000000000000000000000..24278fdc9e13fa79efcac8b8355f5d94919a01a7 Binary files /dev/null and b/host/ide/src/figures/highlit.jpg differ diff --git a/host/ide/src/figures/htrace.jpg b/host/ide/src/figures/htrace.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0c3999d31b19b03d6c2471ff80cbcd4d2e7e2177 Binary files /dev/null and b/host/ide/src/figures/htrace.jpg differ diff --git a/host/ide/src/figures/liveprocess.jpg b/host/ide/src/figures/liveprocess.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2088ba7ab29c07f105ed62df4a6226244326f34d Binary files /dev/null and b/host/ide/src/figures/liveprocess.jpg differ diff --git a/host/ide/src/figures/log.png b/host/ide/src/figures/log.png new file mode 100644 index 0000000000000000000000000000000000000000..dbe3780eb647493dec252d69f23e71cf66ac15a8 Binary files /dev/null and b/host/ide/src/figures/log.png differ diff --git a/host/ide/src/figures/main.jpg b/host/ide/src/figures/main.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5209395cb5c65c857a192b7e0ec768cd2170181e Binary files /dev/null and b/host/ide/src/figures/main.jpg differ diff --git a/host/ide/src/figures/mem_usage.png b/host/ide/src/figures/mem_usage.png new file mode 100644 index 0000000000000000000000000000000000000000..f4ebd6e272c424d6861e2e8150c72c1f4de9802a Binary files /dev/null and b/host/ide/src/figures/mem_usage.png differ diff --git a/host/ide/src/figures/memorytab.jpg b/host/ide/src/figures/memorytab.jpg new file mode 100644 index 0000000000000000000000000000000000000000..76849b0b19d38d67efb563ac7fb04c5fc6e8b487 Binary files /dev/null and b/host/ide/src/figures/memorytab.jpg differ diff --git a/host/ide/src/figures/network.jpg b/host/ide/src/figures/network.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a928cf3ad96b3d0701dbe79013d48792b360f172 Binary files /dev/null and b/host/ide/src/figures/network.jpg differ diff --git a/host/ide/src/figures/opentrace.jpg b/host/ide/src/figures/opentrace.jpg new file mode 100644 index 0000000000000000000000000000000000000000..c2fcf84c6dea67205d5cd5b6041dad1834631d33 Binary files /dev/null and b/host/ide/src/figures/opentrace.jpg differ diff --git a/host/ide/src/figures/perfsetting.jpg b/host/ide/src/figures/perfsetting.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1499dd93d248892d9d47b04d9a3daceadb9c9f71 Binary files /dev/null and b/host/ide/src/figures/perfsetting.jpg differ diff --git a/host/ide/src/figures/process.jpg b/host/ide/src/figures/process.jpg new file mode 100644 index 0000000000000000000000000000000000000000..62cad6b1f899e3be5abc1e17764a7aba6fca4a39 Binary files /dev/null and b/host/ide/src/figures/process.jpg differ diff --git a/host/ide/src/figures/process_thread.png b/host/ide/src/figures/process_thread.png new file mode 100644 index 0000000000000000000000000000000000000000..abc3867130c10413197482d0156ce0ee00aca255 Binary files /dev/null and b/host/ide/src/figures/process_thread.png differ diff --git a/host/ide/src/figures/samplecounter.jpg b/host/ide/src/figures/samplecounter.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2c84e9ebd15dd6f88c2c919fadca2391575188c9 Binary files /dev/null and b/host/ide/src/figures/samplecounter.jpg differ diff --git a/host/ide/src/figures/smartperf_framework.png b/host/ide/src/figures/smartperf_framework.png new file mode 100644 index 0000000000000000000000000000000000000000..62c1bc6cd61e07ba3014141f70941e6134d75681 Binary files /dev/null and b/host/ide/src/figures/smartperf_framework.png differ diff --git a/host/ide/src/figures/summary.jpg b/host/ide/src/figures/summary.jpg new file mode 100644 index 0000000000000000000000000000000000000000..de1cb2d6b2065cce706b0c6f810a3fec1ba629dd Binary files /dev/null and b/host/ide/src/figures/summary.jpg differ diff --git a/host/ide/src/figures/systraceconfig.jpg b/host/ide/src/figures/systraceconfig.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5436850abf26aaea585049af1908c85d1ce67178 Binary files /dev/null and b/host/ide/src/figures/systraceconfig.jpg differ diff --git a/host/ide/src/figures/thread_state.png b/host/ide/src/figures/thread_state.png new file mode 100644 index 0000000000000000000000000000000000000000..186ffb16905c7cfa0178f7c14a0189223f6c9e22 Binary files /dev/null and b/host/ide/src/figures/thread_state.png differ diff --git a/host/ide/src/figures/threadclick.jpg b/host/ide/src/figures/threadclick.jpg new file mode 100644 index 0000000000000000000000000000000000000000..65811e9317fd845bb5b2d3df752ffb742ad743e8 Binary files /dev/null and b/host/ide/src/figures/threadclick.jpg differ diff --git a/host/ide/src/figures/threadinfo.jpg b/host/ide/src/figures/threadinfo.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d2b6be2acf86bcc2612ff4ab1a6b820e6551b9b6 Binary files /dev/null and b/host/ide/src/figures/threadinfo.jpg differ diff --git a/host/ide/src/figures/threadselect.jpg b/host/ide/src/figures/threadselect.jpg new file mode 100644 index 0000000000000000000000000000000000000000..38fda253bd3bab6d3388b1e19cd39d488386d2ba Binary files /dev/null and b/host/ide/src/figures/threadselect.jpg differ diff --git a/host/ide/src/figures/time.jpg b/host/ide/src/figures/time.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a0221cb47e5874a05280a7315831fd61ec13cdd0 Binary files /dev/null and b/host/ide/src/figures/time.jpg differ diff --git a/host/ide/src/figures/trace.jpg b/host/ide/src/figures/trace.jpg new file mode 100644 index 0000000000000000000000000000000000000000..378dba3e866095c0b1155175d09eeb615b3dbf9a Binary files /dev/null and b/host/ide/src/figures/trace.jpg differ diff --git a/host/ide/src/figures/trace2.jpg b/host/ide/src/figures/trace2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6e324c54473450441105300db941db200b3da778 Binary files /dev/null and b/host/ide/src/figures/trace2.jpg differ diff --git a/host/ide/src/figures/trace_streamer_stream.png b/host/ide/src/figures/trace_streamer_stream.png new file mode 100644 index 0000000000000000000000000000000000000000..d36687d164a32bcb07f8f8bd699f0fb0b37e63bd Binary files /dev/null and b/host/ide/src/figures/trace_streamer_stream.png differ diff --git a/host/ide/src/icon.svg b/host/ide/src/icon.svg index 168c113b584dbbbfb6a69687e65adf634768dd8b..1cce633830ef2e9caf112ee0fe44e07f6bed4e53 100644 --- a/host/ide/src/icon.svg +++ b/host/ide/src/icon.svg @@ -1 +1,2173 @@ - + diff --git a/host/ide/src/img/help.png b/host/ide/src/img/help.png new file mode 100644 index 0000000000000000000000000000000000000000..05cc5d13cb1d94025ac8c6381c0d1ef1cc7c7443 Binary files /dev/null and b/host/ide/src/img/help.png differ diff --git a/host/ide/src/img/normal_off.png b/host/ide/src/img/normal_off.png new file mode 100644 index 0000000000000000000000000000000000000000..5f6aa75d2bed70f851cf7269f86fa8d6432dbd08 Binary files /dev/null and b/host/ide/src/img/normal_off.png differ diff --git a/host/ide/src/img/normal_on.png b/host/ide/src/img/normal_on.png new file mode 100644 index 0000000000000000000000000000000000000000..90e57e33025b81e539f0f289a4d3866db0e21d71 Binary files /dev/null and b/host/ide/src/img/normal_on.png differ diff --git a/host/ide/src/img/screening.png b/host/ide/src/img/screening.png new file mode 100644 index 0000000000000000000000000000000000000000..ee7259c851aa4656d6896eac17ac2894ed300ac3 Binary files /dev/null and b/host/ide/src/img/screening.png differ diff --git a/host/ide/src/index.html b/host/ide/src/index.html index dc1753f754d8fbc46869cf0a633dc885ebf78b4f..b1f4cd9ca2343a6a30a15094efef649f751c41d7 100644 --- a/host/ide/src/index.html +++ b/host/ide/src/index.html @@ -39,9 +39,9 @@ let req = new XMLHttpRequest(); req.open('GET', document.location, false); req.send(null); - window.version = req.getResponseHeader('data-version')||"" + window.version = req.getResponseHeader('data-version') || "" - + diff --git a/host/ide/src/trace/SpApplication.ts b/host/ide/src/trace/SpApplication.ts index b5e8eff0a96fc1f0ff8594b3c807c19199257654..5b736a15dd92ac122f093d478244e05e2c91d5b5 100644 --- a/host/ide/src/trace/SpApplication.ts +++ b/host/ide/src/trace/SpApplication.ts @@ -17,6 +17,8 @@ import {BaseElement, element} from "../base-ui/BaseElement.js"; import "../base-ui/menu/LitMainMenu.js"; import "../base-ui/icon/LitIcon.js"; import {SpMetrics} from "./component/SpMetrics.js"; +import {SpHelp} from "./component/SpHelp.js"; +import "./component/SpHelp.js"; import {SpQuerySQL} from "./component/SpQuerySQL.js"; import "./component/SpQuerySQL.js"; import {SpSystemTrace} from "./component/SpSystemTrace.js"; @@ -32,7 +34,9 @@ import "./component/trace/search/Search.js"; import "./component/SpWelcomePage.js"; import "./component/SpSystemTrace.js"; import "./component/SpRecordTrace.js"; -import {TraceRow} from "./component/trace/base/TraceRow.js"; +import "./component/SpMetrics.js"; +import "./component/SpInfoAndStas.js"; +import "./component/trace/base/TraceRow.js"; @element('sp-application') export class SpApplication extends BaseElement { @@ -41,6 +45,15 @@ export class SpApplication extends BaseElement { skinChangeArray: Array = []; private icon: HTMLDivElement | undefined | null private rootEL: HTMLDivElement | undefined | null + private spHelp: SpHelp | undefined | null + private keyCodeMap = { + 61: true, + 107: true, + 109: true, + 173: true, + 187: true, + 189: true, + }; static get observedAttributes() { return ["server", "sqlite", "wasm", "dark", "vs", "query-sql"] @@ -67,6 +80,10 @@ export class SpApplication extends BaseElement { if (SpApplication.skinChange2) { SpApplication.skinChange2(value); } + + if (this.spHelp) { + this.spHelp.dark = value + } } get vs(): boolean { @@ -91,10 +108,6 @@ export class SpApplication extends BaseElement { return this.hasAttribute("server") } - get querySql(): boolean { - return this.hasAttribute("query-sql") - } - set server(s: boolean) { if (s) { this.setAttribute('server', '') @@ -103,6 +116,10 @@ export class SpApplication extends BaseElement { } } + get querySql(): boolean { + return this.hasAttribute("query-sql") + } + set search(search: boolean) { if (search) { this.setAttribute('search', '') @@ -121,190 +138,200 @@ export class SpApplication extends BaseElement { initHtml(): string { return ` - -
- -
- `; } @@ -312,17 +339,19 @@ export class SpApplication extends BaseElement { let that = this; this.rootEL = this.shadowRoot!.querySelector(".root") let spWelcomePage = this.shadowRoot!.querySelector("#sp-welcome") as SpWelcomePage - let spMetrics = new SpMetrics(); + let spMetrics = this.shadowRoot!.querySelector("#sp-metrics") as SpMetrics // new SpMetrics(); + let spQuerySQL = this.shadowRoot!.querySelector("#sp-query-sql") as SpQuerySQL // new SpQuerySQL(); + let spInfoAndStats = this.shadowRoot!.querySelector("#sp-info-and-stats") as SpInfoAndStats // new SpInfoAndStats(); + let spSystemTrace = this.shadowRoot!.querySelector("#sp-system-trace") - let spInfoAndStats = new SpInfoAndStats(); + this.spHelp = this.shadowRoot!.querySelector("#sp-help") let spRecordTrace = this.shadowRoot!.querySelector("#sp-record-trace") - let spQuerySQL = this.shadowRoot!.querySelector("#sp-query-sql") let appContent = this.shadowRoot?.querySelector('#app-content') as HTMLDivElement; let mainMenu = this.shadowRoot?.querySelector('#main-menu') as LitMainMenu let progressEL = this.shadowRoot?.querySelector('.progress') as LitProgressBar let litSearch = this.shadowRoot?.querySelector('#lit-search') as LitSearch let sidebarButton: HTMLDivElement | undefined | null = this.shadowRoot?.querySelector('.sidebar-button') - let childNodes = [spSystemTrace, spRecordTrace, spWelcomePage, spQuerySQL] + let childNodes = [spSystemTrace, spRecordTrace, spWelcomePage, spMetrics, spQuerySQL, spInfoAndStats, this.spHelp] litSearch.addEventListener("focus", () => { spSystemTrace!.keyboardEnable = false }) @@ -330,17 +359,19 @@ export class SpApplication extends BaseElement { spSystemTrace!.keyboardEnable = true }) litSearch.addEventListener("previous-data", (ev: any) => { - litSearch.index = spSystemTrace!.showPreCpuStruct(litSearch.index,litSearch.list); + litSearch.index = spSystemTrace!.showStruct(true,litSearch.index, litSearch.list); litSearch.blur(); }) litSearch.addEventListener("next-data", (ev: any) => { - litSearch.index = spSystemTrace!.showNextCpuStruct(litSearch.index,litSearch.list); + litSearch.index = spSystemTrace!.showStruct(false,litSearch.index, litSearch.list); litSearch.blur(); - // spSystemTrace!.search(e.detail.value) }) litSearch.valueChangeHandler = (value: string) => { if (value.length > 0) { - litSearch.list = spSystemTrace!.searchCPU(value); + let list = spSystemTrace!.searchCPU(value); + spSystemTrace!.searchFunction(list,value).then((mixedResults)=>{ + litSearch.list = mixedResults + }) } else { litSearch.list = []; spSystemTrace?.visibleRows.forEach(it => { @@ -351,10 +382,10 @@ export class SpApplication extends BaseElement { } } spSystemTrace?.addEventListener("previous-data", (ev: any) => { - litSearch.index = spSystemTrace!.showPreCpuStruct(litSearch.index, litSearch.list); + litSearch.index = spSystemTrace!.showStruct(true,litSearch.index, litSearch.list); }) spSystemTrace?.addEventListener("next-data", (ev: any) => { - litSearch.index = spSystemTrace!.showNextCpuStruct(litSearch.index, litSearch.list); + litSearch.index = spSystemTrace!.showStruct(false,litSearch.index, litSearch.list); }) //打开侧边栏 sidebarButton!.onclick = (e) => { @@ -395,6 +426,21 @@ export class SpApplication extends BaseElement { }) } + function postLog(filename: string, fileSize: string) { + fetch(`https://${window.location.host.split(':')[0]}:9000/logger`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + fileName: filename, + fileSize: fileSize + }), + }).then(response => response.json()).then(data => { + }).catch((error) => { + }); + } + function openTraceFile(ev: any) { litSearch.clear(); showContent(spSystemTrace!) @@ -402,6 +448,7 @@ export class SpApplication extends BaseElement { progressEL.loading = true let fileName = (ev as any).name let fileSize = ((ev as any).size / 1000000).toFixed(1) + postLog(fileName, fileSize) document.title = `${fileName.substring(0, fileName.lastIndexOf('.'))} (${fileSize}M)` if (that.server) { threadPool.init("server").then(() => { @@ -410,7 +457,7 @@ export class SpApplication extends BaseElement { const fd = new FormData() that.freshMenuDisable(true) fd.append('file', ev as any) - let uploadPath = `https://${window.location.host.split(':')[0]}:9001/upload` + let uploadPath = `https://${window.location.host.split(':')[0]}:9000/upload` if (that.vs) { uploadPath = `http://${window.location.host.split(':')[0]}:${window.location.port}/upload` } @@ -430,13 +477,7 @@ export class SpApplication extends BaseElement { } } ]; - if (that.querySql) { - menus.push({ - title: "Query (SQL)", icon: "file", clickHandler: () => { - showContent(spQuerySQL!) - } - }); - } + mainMenu.menus!.splice(1, 1, { collapsed: false, title: "Current Trace", @@ -456,7 +497,7 @@ export class SpApplication extends BaseElement { } }).then(res => { if (res != undefined) { - let loadPath = `https://${window.location.host.split(':')[0]}:9001` + let loadPath = `https://${window.location.host.split(':')[0]}:9000` if (that.vs) { loadPath = `http://${window.location.host.split(':')[0]}:${window.location.port}` } @@ -512,13 +553,7 @@ export class SpApplication extends BaseElement { } } ]; - if (that.querySql) { - menus.push({ - title: "Query (SQL)", icon: "file", clickHandler: () => { - showContent(spQuerySQL!) - } - }); - } + mainMenu.menus!.splice(1, 1, { collapsed: false, title: "Current Trace", @@ -608,6 +643,27 @@ export class SpApplication extends BaseElement { } } }, false); + document.addEventListener("keydown",(event)=> { + const e = event || window.event; + const ctrlKey = e.ctrlKey || e.metaKey; + if (ctrlKey && (this.keyCodeMap as any)[e.keyCode]) { + e.preventDefault(); + } else if (e.detail) { // Firefox + event.returnValue = false; + } + }) + document.body.addEventListener('wheel', (e) => { + if (e.ctrlKey) { + if (e.deltaY < 0) { + e.preventDefault(); + return false; + } + if (e.deltaY > 0) { + e.preventDefault(); + return false; + } + } + }, { passive: false }); } freshMenuDisable(disable: boolean) { diff --git a/host/ide/src/trace/bean/AbilityMonitor.ts b/host/ide/src/trace/bean/AbilityMonitor.ts new file mode 100644 index 0000000000000000000000000000000000000000..b58e23856ac5a30232ff36191fa8db16a453ae02 --- /dev/null +++ b/host/ide/src/trace/bean/AbilityMonitor.ts @@ -0,0 +1,128 @@ +/* + * 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. + */ + +export class SystemCpuSummary { + startTime: number = -1 + startTimeStr: string = ""; + duration: number = -1 + durationStr: string = "" + totalLoad: number = -1 + totalLoadStr: string = "" + userLoad: number = -1 + userLoadStr: string = "" + systemLoad: number = -1 + systemLoadStr: string = "" + threads: number = -1 + threadsStr: string = "" +} + +export class SystemDiskIOSummary { + startTime: number = -1 + startTimeStr: string = "" + duration: number = -1 + durationStr: string = "" + dataRead: number = -1 + dataReadStr: string = "" + dataReadSec: number = -1 + dataReadSecStr: string = "" + dataWrite: number = -1 + dataWriteStr: string = "" + dataWriteSec: number = -1 + dataWriteSecStr: string = "" + readsIn: number = -1 + readsInStr: string = "" + readsInSec: number = -1 + readsInSecStr: string = "" + writeOut: number = -1 + writeOutStr: string = "" + writeOutSec: number = -1 + writeOutSecStr: string = "" + +} + +export class ProcessHistory { + processId: number = -1 + alive: string = '' // 0 alive and 1 dead + firstSeen: string = '' + lastSeen: string = '' + processName: string = "" + responsibleProcess: string = "" + userName: string = "" + cpuTime: string = '' + pss: number = -1 +} + +export class LiveProcess { + processId: number = -1 + processName: string = "" + responsibleProcess: string = "" + userName: string = "" + cpu: string = '' + threads: number = -1 + memory: string = '' + diskWrite: number = -1 + diskReads: number = -1 + cpuTime: string = "" + cpuTimeNumber: number = -1; +} + +export class SystemNetworkSummary { + startTime: number = -1 + startTimeStr: string = "" + duration: number = -1 + durationStr: string = "" + dataReceived: number = -1 + dataReceivedStr: string = "" + dataReceivedSec: number = -1 + dataReceivedSecStr: string = "" + dataSend: number = -1 + dataSendStr: string = "" + dataSendSec: number = -1 + dataSendSecStr: string = "" + packetsIn: number = -1 + packetsInStr: string = "" + packetsInSec: number = -1 + packetsInSecStr: string = "" + packetsOut: number = -1 + packetsOutStr: string = "" + packetsOutSec: number = -1 + packetsOutSecStr: string = "" +} + +export class SystemMemorySummary { + startTimeStr: string = "0" + durationStr: string = "0" + memoryTotal: string = "0"; + memFree: string = "0"; + buffers: string = "0"; + cached: string = "0"; + shmem: string = "0"; + slab: string = "0"; + swapTotal: string = "0"; + swapFree: string = "0"; + mapped: string = "0"; + vmallocUsed: string = "0"; + pageTables: string = "0"; + kernelStack: string = "0"; + active: string = "0"; + inactive: string = "0"; + unevictable: string = "0"; + vmallocTotal: string = "0"; + sUnreclaim: string = "0"; + kReclaimable: string = "0"; + cmaTotal: string = "0"; + cmaFree: string = "0"; + zram: string = "0"; +} \ No newline at end of file diff --git a/host/ide/src/trace/bean/BoxSelection.ts b/host/ide/src/trace/bean/BoxSelection.ts index 788e3c1c035ae492fc446c81462967b02bcac4c2..9ac5b955de6756492929cca50c59366b33c3c074 100644 --- a/host/ide/src/trace/bean/BoxSelection.ts +++ b/host/ide/src/trace/bean/BoxSelection.ts @@ -19,11 +19,20 @@ export class SelectionParam { trackIds: Array = []; funTids: Array = []; heapIds: Array = []; - nativeMemory:Array = []; + nativeMemory: Array = []; + cpuAbilityIds: Array = [] + memoryAbilityIds: Array = [] + diskAbilityIds: Array = [] + networkAbilityIds: Array = [] leftNs: number = 0; rightNs: number = 0; hasFps: boolean = false; - statisticsSelectData:any = undefined + statisticsSelectData: any = undefined + perfSampleIds: Array = []; + perfCpus: Array = []; + perfProcess: Array = []; + perfThread: Array = []; + perfAll: boolean = false; } export class BoxJumpParam { diff --git a/host/ide/src/trace/bean/CpuAbilityMonitorStruct.ts b/host/ide/src/trace/bean/CpuAbilityMonitorStruct.ts new file mode 100644 index 0000000000000000000000000000000000000000..05b56c2c4978459bebab81681c7bc7bb83c267b5 --- /dev/null +++ b/host/ide/src/trace/bean/CpuAbilityMonitorStruct.ts @@ -0,0 +1,28 @@ +/* + * 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. + */ + +import {BaseStruct} from "./BaseStruct.js"; + +export class CpuAbilityMonitorStruct extends BaseStruct { + static maxCpuUtilization: number = 0 + static maxCpuUtilizationName: string = "0 %" + static hoverCpuAbilityStruct: CpuAbilityMonitorStruct | undefined; + static selectCpuAbilityStruct: CpuAbilityMonitorStruct | undefined; + + type: number | undefined + value: number | undefined + startNS: number | undefined + dur: number | undefined +} diff --git a/host/ide/src/trace/bean/DiskAbilityMonitorStruct.ts b/host/ide/src/trace/bean/DiskAbilityMonitorStruct.ts new file mode 100644 index 0000000000000000000000000000000000000000..27118131d2c232982597a3026ffe316912c62d45 --- /dev/null +++ b/host/ide/src/trace/bean/DiskAbilityMonitorStruct.ts @@ -0,0 +1,61 @@ +/* + * 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. + */ + +import {BaseStruct} from "./BaseStruct.js"; +import {ColorUtils} from "../database/ProcedureWorkerCommon.js"; + +export class DiskAbilityMonitorStruct extends BaseStruct { + static maxDiskRate: number = 0 + static maxDiskRateName: string = "0 KB/S" + static hoverDiskAbilityStruct: DiskAbilityMonitorStruct | undefined; + static selectDiskAbilityStruct: DiskAbilityMonitorStruct | undefined; + cpu: number | undefined + value: number | undefined + startNS: number | undefined + dur: number | undefined + + static draw(context2D: any, data: DiskAbilityMonitorStruct) { + if (data.frame) { + let width = data.frame.width || 0; + let index = data.cpu || 0 + index += 2 + context2D.fillStyle = ColorUtils.colorForTid(index) + context2D.strokeStyle = ColorUtils.colorForTid(index) + if (data.startNS === DiskAbilityMonitorStruct.hoverDiskAbilityStruct?.startNS) { + context2D.lineWidth = 1; + context2D.globalAlpha = 0.6; + let drawHeight: number = Math.floor(((data.value || 0) * (data.frame.height || 0) * 1.0) / DiskAbilityMonitorStruct.maxDiskRate); + context2D.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight, width, drawHeight) + context2D.beginPath() + context2D.arc(data.frame.x, data.frame.y + data.frame.height - drawHeight, 3, 0, 2 * Math.PI, true) + context2D.fill() + context2D.globalAlpha = 1.0; + context2D.stroke(); + context2D.beginPath() + context2D.moveTo(data.frame.x + 3, data.frame.y + data.frame.height - drawHeight); + context2D.lineWidth = 3; + context2D.lineTo(data.frame.x + width, data.frame.y + data.frame.height - drawHeight) + context2D.stroke(); + } else { + context2D.globalAlpha = 0.6; + context2D.lineWidth = 1; + let drawHeight: number = Math.floor(((data.value || 0) * (data.frame.height || 0)) / DiskAbilityMonitorStruct.maxDiskRate); + context2D.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight, width, drawHeight) + } + } + context2D.globalAlpha = 1.0; + context2D.lineWidth = 1; + } +} diff --git a/host/ide/src/trace/bean/HeapBean.ts b/host/ide/src/trace/bean/HeapBean.ts index ec7541f0fec433d4d134b3c515edc51642117279..b001dfdfcd468e68afd620a0ff60474f36883421 100644 --- a/host/ide/src/trace/bean/HeapBean.ts +++ b/host/ide/src/trace/bean/HeapBean.ts @@ -13,15 +13,15 @@ * limitations under the License. */ -export class HeapBean{ - MoudleName:string|undefined - AllocationFunction:string|undefined - Allocations:number|string = 0 - Deallocations:number|string= 0 - AllocationSize:number|string= 0 - DeAllocationSize:number|string= 0 - Total:number|string= 0 - RemainingSize:number|string= 0 - children:HeapBean[] = [] - depth:number = 0 +export class HeapBean { + MoudleName: string | undefined + AllocationFunction: string | undefined + Allocations: number | string = 0 + Deallocations: number | string = 0 + AllocationSize: number | string = 0 + DeAllocationSize: number | string = 0 + Total: number | string = 0 + RemainingSize: number | string = 0 + children: HeapBean[] = [] + depth: number = 0 } \ No newline at end of file diff --git a/host/ide/src/trace/bean/HeapStruct.ts b/host/ide/src/trace/bean/HeapStruct.ts index 123ed31c6ab43f75a7e2f2afa679ea8ece08fb25..667dfb4cf3cda8b0f1a7bd585be738d77d68dabf 100644 --- a/host/ide/src/trace/bean/HeapStruct.ts +++ b/host/ide/src/trace/bean/HeapStruct.ts @@ -22,7 +22,7 @@ export class HeapStruct extends BaseStruct { startTime: number | undefined endTime: number | undefined dur: number | undefined - eventType:string | undefined + eventType: string | undefined heapsize: number | undefined maxHeapSize: number = 0 minHeapSize: number = 0 diff --git a/host/ide/src/trace/bean/HeapTreeDataBean.ts b/host/ide/src/trace/bean/HeapTreeDataBean.ts index a155a5865f7b112c7b9a4e52ed0b4d2cf5a07ae7..a2a07025d902949df67e0e304876d915b6fd64d3 100644 --- a/host/ide/src/trace/bean/HeapTreeDataBean.ts +++ b/host/ide/src/trace/bean/HeapTreeDataBean.ts @@ -13,13 +13,13 @@ * limitations under the License. */ -export class HeapTreeDataBean{ - MoudleName:string|undefined - AllocationFunction:string|undefined - startTs:number = 0 - endTs:number = 0 - eventType:string|undefined - depth:number = 0 - heapSize:number = 0 - eventId:string="" +export class HeapTreeDataBean { + MoudleName: string | undefined + AllocationFunction: string | undefined + startTs: number = 0 + endTs: number = 0 + eventType: string | undefined + depth: number = 0 + heapSize: number = 0 + eventId: string = "" } \ No newline at end of file diff --git a/host/ide/src/trace/bean/MemoryAbilityMonitorStruct.ts b/host/ide/src/trace/bean/MemoryAbilityMonitorStruct.ts new file mode 100644 index 0000000000000000000000000000000000000000..ff2c1a438c16b5a94a79f6bd4f9c88fc672dc969 --- /dev/null +++ b/host/ide/src/trace/bean/MemoryAbilityMonitorStruct.ts @@ -0,0 +1,61 @@ +/* + * 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. + */ + +import {BaseStruct} from "./BaseStruct.js"; +import {ColorUtils} from "../database/ProcedureWorkerCommon.js"; + +export class MemoryAbilityMonitorStruct extends BaseStruct { + static maxMemoryByte: number = 0 + static maxMemoryByteName: string = "0 MB" + static hoverMemoryAbilityStruct: MemoryAbilityMonitorStruct | undefined; + static selectMemoryAbilityStruct: MemoryAbilityMonitorStruct | undefined; + cpu: number | undefined + value: number | undefined + startNS: number | undefined + dur: number | undefined + + static draw(context2D: any, data: MemoryAbilityMonitorStruct) { + if (data.frame) { + let width = data.frame.width || 0; + let index = data.cpu || 0 + index += 2 + context2D.fillStyle = ColorUtils.colorForTid(index) + context2D.strokeStyle = ColorUtils.colorForTid(index) + if (data.startNS === MemoryAbilityMonitorStruct.hoverMemoryAbilityStruct?.startNS) { + context2D.lineWidth = 1; + context2D.globalAlpha = 0.6; + let drawHeight: number = Math.floor(((data.value || 0) * (data.frame.height || 0) * 1.0) / MemoryAbilityMonitorStruct.maxMemoryByte); + context2D.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight, width, drawHeight) + context2D.beginPath() + context2D.arc(data.frame.x, data.frame.y + data.frame.height - drawHeight, 3, 0, 2 * Math.PI, true) + context2D.fill() + context2D.globalAlpha = 1.0; + context2D.stroke(); + context2D.beginPath() + context2D.moveTo(data.frame.x + 3, data.frame.y + data.frame.height - drawHeight); + context2D.lineWidth = 3; + context2D.lineTo(data.frame.x + width, data.frame.y + data.frame.height - drawHeight) + context2D.stroke(); + } else { + context2D.globalAlpha = 0.6; + context2D.lineWidth = 1; + let drawHeight: number = Math.floor(((data.value || 0) * (data.frame.height || 0)) / MemoryAbilityMonitorStruct.maxMemoryByte); + context2D.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight, width, drawHeight) + } + } + context2D.globalAlpha = 1.0; + context2D.lineWidth = 1; + } +} diff --git a/host/ide/src/trace/bean/NativeHook.ts b/host/ide/src/trace/bean/NativeHook.ts index 99168e0009843c259d8ab533fbc0ec995c41ecd4..81d1b20dfcef00d316e2696de6d1826c71bb29f9 100644 --- a/host/ide/src/trace/bean/NativeHook.ts +++ b/host/ide/src/trace/bean/NativeHook.ts @@ -14,103 +14,90 @@ */ import {Utils} from "../component/trace/base/Utils.js"; +import {ChartStruct} from "../database/ProcedureWorkerCommon.js"; -export class NativeHookStatistics{ - eventId:number = 0; - eventType:string = ""; - subType:string = ""; - heapSize:number = 0; - addr:string = ""; - startTs:number = 0; - endTs:number = 0; - sumHeapSize:number = 0; - max:number = 0; - count:number = 0; - tid:number = 0; - isSelected:boolean = false; +export class NativeHookStatistics { + eventId: number = 0; + eventType: string = ""; + subType: string = ""; + heapSize: number = 0; + addr: string = ""; + startTs: number = 0; + endTs: number = 0; + sumHeapSize: number = 0; + max: number = 0; + count: number = 0; + tid: number = 0; + isSelected: boolean = false; } -export class NativeHookMalloc{ - eventType:string = ""; - subType:string = ""; - heapSize:number = 0; - allocByte:number = 0; - allocCount:number = 0; - freeByte:number = 0; - freeCount:number = 0; +export class NativeHookMalloc { + eventType: string = ""; + subType: string = ""; + heapSize: number = 0; + allocByte: number = 0; + allocCount: number = 0; + freeByte: number = 0; + freeCount: number = 0; } -export class NativeEventHeap{ - eventType:string = ""; - sumHeapSize:number = 0 +export class NativeEventHeap { + eventType: string = ""; + sumHeapSize: number = 0 } -export class NativeHookProcess{ - ipid:number = 0; - pid:number = 0; - name:String = "" +export class NativeHookProcess { + ipid: number = 0; + pid: number = 0; + name: String = "" } -export class NativeHookStatisticsTableData{ - memoryTap:string = ""; - existing:number = 0; - existingString:string = ""; - allocCount:number = 0; - freeCount:number = 0; - totalBytes:number = 0 - totalBytesString:string = ""; - maxStr:string = ""; - max:number = 0 - totalCount:number = 0; - existingValue:Array = []; +export class NativeHookStatisticsTableData { + memoryTap: string = ""; + existing: number = 0; + existingString: string = ""; + allocCount: number = 0; + freeCount: number = 0; + totalBytes: number = 0 + totalBytesString: string = ""; + maxStr: string = ""; + max: number = 0 + totalCount: number = 0; + existingValue: Array = []; } -export class NativeMemory{ - index:number = 0; - eventId:number = 0; - eventType:string = ""; - subType:string = ""; - addr:string = ""; - startTs:number = 0; - timestamp:string = "" - heapSize:number = 0; - heapSizeUnit:string = ""; - symbol:string = ""; - library:string = ""; -} - -export class NativeHookCallInfo{ - id:string = ""; - pid:string | undefined; - threadId:number = 0; - symbol:string = ""; - library:string = ""; - title:string = ""; - count:number = 0; - type:number = 0; - heapSize:number = 0; - heapSizeStr:string = ""; - eventId:number = 0 - depth:number = 0; - children:Array = []; +export class NativeMemory { + index: number = 0; + eventId: number = 0; + eventType: string = ""; + subType: string = ""; + addr: string = ""; + startTs: number = 0; + timestamp: string = "" + heapSize: number = 0; + heapSizeUnit: string = ""; + symbol: string = ""; + library: string = ""; + isSelected: boolean = false; } export class NativeHookSamplerInfo { - current:string = "" - currentSize:number = 0 - startTs:number = 0; - heapSize:number = 0; - snapshot:string = ""; - growth:string = ""; - total:number = 0; - totalGrowth:string = "" - existing:number = 0; - children:Array = []; - tempList:Array = []; - timestamp:string = "" - eventId:number = -1 - merageObj(merageObj:NativeHookSamplerInfo){ - this.currentSize+=merageObj.currentSize + current: string = "" + currentSize: number = 0 + startTs: number = 0; + heapSize: number = 0; + snapshot: string = ""; + growth: string = ""; + total: number = 0; + totalGrowth: string = "" + existing: number = 0; + children: Array = []; + tempList: Array = []; + timestamp: string = "" + eventId: number = -1 + + merageObj(merageObj: NativeHookSamplerInfo) { + this.currentSize += merageObj.currentSize this.heapSize += merageObj.heapSize this.existing += merageObj.existing this.total += merageObj.total @@ -121,15 +108,29 @@ export class NativeHookSamplerInfo { } export class NativeHookSampleQueryInfo { - eventId:number = -1 - current:number = 0 - eventType:string = ""; - subType:string = ""; - growth:number = 0; - existing:number = 0; - addr:string = ""; - startTs:number = 0; - endTs:number = 0; - total:number = 0; - children:Array = []; + eventId: number = -1 + current: number = 0 + eventType: string = ""; + subType: string = ""; + growth: number = 0; + existing: number = 0; + addr: string = ""; + startTs: number = 0; + endTs: number = 0; + total: number = 0; + children: Array = []; +} + +export class NativeHookCallInfo extends ChartStruct { + id: string = ""; + pid: string | undefined; + library: string = ""; + title: string = ""; + count: number = 0; + type: number = 0; + heapSize: number = 0; + heapSizeStr: string = ""; + eventId: number = 0; + threadId: number = 0; + isSelected: boolean = false; } \ No newline at end of file diff --git a/host/ide/src/trace/bean/NetworkAbilityMonitorStruct.ts b/host/ide/src/trace/bean/NetworkAbilityMonitorStruct.ts new file mode 100644 index 0000000000000000000000000000000000000000..52490fdfa0b126214b34d49ceb27ca8001e1882c --- /dev/null +++ b/host/ide/src/trace/bean/NetworkAbilityMonitorStruct.ts @@ -0,0 +1,60 @@ +/* + * 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. + */ + +import {BaseStruct} from "./BaseStruct.js"; +import {ColorUtils} from "../database/ProcedureWorkerCommon.js"; + +export class NetworkAbilityMonitorStruct extends BaseStruct { + static maxNetworkRate: number = 0 + static maxNetworkRateName: string = "0 KB/S" + static hoverNetworkAbilityStruct: NetworkAbilityMonitorStruct | undefined; + static selectNetworkAbilityStruct: NetworkAbilityMonitorStruct | undefined; + value: number | undefined + startNS: number | undefined + dur: number | undefined + + static draw(context2D: any, data: NetworkAbilityMonitorStruct) { + if (data.frame) { + let width = data.frame.width || 0; + let index = 0 + index += 2 + context2D.fillStyle = ColorUtils.colorForTid(index) + context2D.strokeStyle = ColorUtils.colorForTid(index) + if (data.startNS === NetworkAbilityMonitorStruct.hoverNetworkAbilityStruct?.startNS) { + context2D.lineWidth = 1; + context2D.globalAlpha = 0.6; + let drawHeight: number = Math.floor(((data.value || 0) * (data.frame.height || 0) * 1.0) / NetworkAbilityMonitorStruct.maxNetworkRate); + context2D.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight, width, drawHeight) + context2D.beginPath() + context2D.arc(data.frame.x, data.frame.y + data.frame.height - drawHeight, 3, 0, 2 * Math.PI, true) + context2D.fill() + context2D.globalAlpha = 1.0; + context2D.stroke(); + context2D.beginPath() + context2D.moveTo(data.frame.x + 3, data.frame.y + data.frame.height - drawHeight); + context2D.lineWidth = 3; + context2D.lineTo(data.frame.x + width, data.frame.y + data.frame.height - drawHeight) + context2D.stroke(); + } else { + context2D.globalAlpha = 0.6; + context2D.lineWidth = 1; + let drawHeight: number = Math.floor(((data.value || 0) * (data.frame.height || 0)) / NetworkAbilityMonitorStruct.maxNetworkRate); + context2D.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight, width, drawHeight) + } + } + context2D.globalAlpha = 1.0; + context2D.lineWidth = 1; + } +} diff --git a/host/ide/src/trace/bean/PerfProfile.ts b/host/ide/src/trace/bean/PerfProfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..6b514ef7990d665252e81c31d8888433f2f3d5fa --- /dev/null +++ b/host/ide/src/trace/bean/PerfProfile.ts @@ -0,0 +1,194 @@ +/* + * 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. + */ + +import {Utils} from "../component/trace/base/Utils.js"; +import {ChartStruct} from "../database/ProcedureWorkerCommon.js"; +import {SpHiPerf} from "../component/hiperf/SpHiPerf.js"; + +export class PerfFile { + fileId: number = 0; + symbol: string = "" + path: string = "" + fileName: string = "" + + static setFileName(data: PerfFile) { + if (data.path) { + let number = data.path.lastIndexOf("/"); + if (number > 0) { + data.fileName = data.path.substring(number + 1) + return + } + } + data.fileName = data.path + } + + setFileName() { + if (this.path) { + let number = this.path.lastIndexOf("/"); + if (number > 0) { + this.fileName = this.path.substring(number + 1) + return + } + } + this.fileName = this.path + } +} + +export class PerfThread { + tid: number = 0; + pid: number = 0; + threadName: string = ""; + processName: string = ""; +} + +export class PerfCallChain { + tid: number = 0; + pid: number = 0; + name: string = "" + fileName: string = ""; + threadState: string = ""; + startNS: number = 0; + dur: number = 0; + sampleId: number = 0; + callChainId: number = 0; + vaddrInFile: number = 0; + fileId: number = 0; + symbolId: number = 0; + path: string = ""; + parentId: string = ""//合并之后区分的id + id: string = "" + topDownMerageId: string = ""//top down合并使用的id + topDownMerageParentId: string = ""//top down合并使用的id + bottomUpMerageId: string = ""//bottom up合并使用的id + bottomUpMerageParentId: string = ""//bottom up合并使用的id + depth: number = 0; + canCharge:boolean = true + previousNode: PerfCallChain | undefined = undefined;//将list转换为一个链表结构 + nextNode: PerfCallChain | undefined = undefined; + + static setNextNode(currentNode: PerfCallChain, nextNode: PerfCallChain) { + currentNode.nextNode = nextNode + nextNode.previousNode = currentNode + } + + static setPreviousNode(currentNode: PerfCallChain, prevNode: PerfCallChain) { + currentNode.previousNode = prevNode + prevNode.nextNode = currentNode + } + + static merageCallChain(currentNode: PerfCallChain, callChain: PerfCallChain) { + currentNode.startNS = callChain.startNS + currentNode.tid = callChain.tid + currentNode.pid = callChain.pid + currentNode.sampleId = callChain.sampleId + currentNode.dur = callChain.dur + } + +} + +export class PerfCallChainMerageData extends ChartStruct { + #parentNode: PerfCallChainMerageData | undefined = undefined + #total = 0 + id: string = ""; + parentId: string = ""; + currentTreeParentNode: PerfCallChainMerageData | undefined = undefined; + symbolName: string = ""; + symbol: string = "" + libName: string = "" + path: string = "" + self: string = "0s" + weight: string = "" + selfDur: number = 0; + dur: number = 0; + tid: number = 0; + pid: number = 0; + isStore = 0; + canCharge:boolean = true + children: PerfCallChainMerageData[] = [] + initChildren: PerfCallChainMerageData[] = [] + type: number = 0; + vaddrInFile: number = 0; + isSelected: boolean = false; + searchShow: boolean = true; + + set parentNode(data: PerfCallChainMerageData | undefined) { + this.currentTreeParentNode = data; + this.#parentNode = data; + } + + get parentNode() { + return this.#parentNode + } + + set total(data: number) { + this.#total = data; + this.weight = `${Utils.timeMsFormat2p(this.dur * (SpHiPerf.stringResult?.fValue || 1))} ${(this.dur / data * 100).toFixed(1)}%` + } + + get total() { + return this.#total; + } + + static merageCallChain(currentNode: PerfCallChainMerageData, callChain: PerfCallChain, isTopDown: boolean) { + if (currentNode.symbolName == "") { + currentNode.symbol = `${callChain.name} ${callChain.fileName ? `(${callChain.fileName})` : ""}` + currentNode.symbolName = callChain.name + currentNode.pid = callChain.pid + currentNode.tid = callChain.tid + currentNode.libName = callChain.fileName + currentNode.vaddrInFile = callChain.vaddrInFile; + currentNode.canCharge = callChain.canCharge + if (callChain.path) { + currentNode.path = callChain.path + } + } + if (callChain[isTopDown ? "nextNode" : "previousNode"] == undefined) { + currentNode.selfDur++; + currentNode.self = Utils.timeMsFormat2p(currentNode.selfDur) + } + currentNode.dur++; + currentNode.count++; + } +} + +export class PerfSample { + sampleId: number = 0; + time: number = 0; + timeString: string = ""; + core: number = 0; + coreName: string = ""; + state: string = ""; + pid: number = 0; + processName: string = ""; + tid: number = 0; + threadName: string = ""; + depth: number = 0; + addr: string = ""; + fileId: number = 0; + symbolId: number = 0; + backtrace: Array = []; +} + +export class PerfStack { + symbol: string = ""; + path: string = ""; + fileId: number = 0; + type: number = 0; + vaddrInFile: number = 0; +} + +export class PerfCmdLine { + report_value: string = ""; +} \ No newline at end of file diff --git a/host/ide/src/trace/bean/SearchFuncBean.ts b/host/ide/src/trace/bean/SearchFuncBean.ts new file mode 100644 index 0000000000000000000000000000000000000000..e5cc893134c3ac2dc9bcc939b593b569bad4753f --- /dev/null +++ b/host/ide/src/trace/bean/SearchFuncBean.ts @@ -0,0 +1,33 @@ +/* + * 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. + */ + +export class SearchFuncBean { + depth: number | undefined // 0 + dur: number | undefined // 570000 + funName: string | undefined //"binder transaction" + id: number | undefined // 92749 + startTime: number | undefined // 9729867000 + tid: number | undefined // + pid: number | undefined // 2785 + type: string | undefined +} + +export class SearchThreadProcessBean { + type: string | undefined + rowId:string | undefined | null + name:string | undefined + rowType:string | undefined | null + rowParentId:string | undefined | null +} diff --git a/host/ide/src/trace/bean/StateProcessThread.ts b/host/ide/src/trace/bean/StateProcessThread.ts index 642d399ef9d84abbf1cb5511ae45e05e4cf1abde..e333c492d21996846ee6f7088162389e9fd8585c 100644 --- a/host/ide/src/trace/bean/StateProcessThread.ts +++ b/host/ide/src/trace/bean/StateProcessThread.ts @@ -61,4 +61,28 @@ export class SPT { cpu: number = 0; priority: string = "-" note: string = "-" +} + +export class ThreadState{ + itid:number = 0 + state:string = "" + dur:number = 0 + ts:number = 0 + end_ts:number = 0 + start_ts:number = 0 + cpu:number = 0 +} + +export class ThreadProcess{ + id:number = 0 + threadId :number = 0 + thread :string = "" + processId : number = 0 + process : string = "" +} + +export class SptSlice{ + itid :number = 0 + ts : number = 0 + priority : number = 0 } \ No newline at end of file diff --git a/host/ide/src/trace/bean/WakeupBean.ts b/host/ide/src/trace/bean/WakeupBean.ts index f8d6fbc30562f034ca1c864976725a2b255dc25a..f5c23003132af085c1248a8b9ca0950f6cfa4acc 100644 --- a/host/ide/src/trace/bean/WakeupBean.ts +++ b/host/ide/src/trace/bean/WakeupBean.ts @@ -22,4 +22,5 @@ export class WakeupBean { tid: number | undefined schedulingLatency: number | undefined schedulingDesc: string | undefined + ts: number | undefined } \ No newline at end of file diff --git a/host/ide/src/trace/component/DisassemblingWindow.ts b/host/ide/src/trace/component/DisassemblingWindow.ts new file mode 100644 index 0000000000000000000000000000000000000000..2c3ff8bf2dc7add3fe1e9d1b03e589ac0082d3b1 --- /dev/null +++ b/host/ide/src/trace/component/DisassemblingWindow.ts @@ -0,0 +1,205 @@ +/* + * 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. + */ + +import { BaseElement, element } from "../../base-ui/BaseElement.js"; + +@element('tab-native-data-modal') +export class DisassemblingWindow extends BaseElement { + private canvas: HTMLCanvasElement | undefined | null; + private window: HTMLElement | undefined | null; + private loading: HTMLElement | undefined | null; + private ctx: CanvasRenderingContext2D | null | undefined; + private hintLine = 0; + private addrArray = new Array(); + private maxBinSize = 0; + + private getMap(content: string, hintAttr: string) { + let lines = content.split('\n'); + this.addrArray = new Array(); + let lineMap = new Map(); + let effectLint = 0; + this.maxBinSize = 0; + for (let line of lines) { + let lineContents = line.split(':'); + if (lineContents.length === 2) { + let addrHex = lineContents[0].trim(); + let addr = '0x' + addrHex; + let value = lineContents[1].split('\t'); + try { + let binary = value[0]; + let lineStruct = new Disassembling(); + if (binary === '') { + if (line.includes('Disassembly') || line.includes('file format')) { + continue + } else { + if (addr.includes(' ')) { + let funcs = addr.split(' '); + lineStruct.addr = funcs[0]; + lineStruct.binary = funcs[1]; + } + } + } else { + lineStruct.addr = addr; + lineStruct.binary = value[0].trim(); + lineStruct.type = value.length > 1 ? value[1] : ''; + lineStruct.code = value.length > 2 ? value[2] : ''; + } + lineMap.set(addrHex, lineStruct); + this.maxBinSize = Math.max(this.ctx!.measureText(lineStruct.addr + lineStruct.binary).width, this.maxBinSize); + this.addrArray.push(addrHex); + if (addrHex === hintAttr) this.hintLine = effectLint; + effectLint++; + } catch (e) { + console.log(e); + } + } + } + return lineMap; + } + + public showContent(content: string, hintAddr: string): void { + this.loading!.style.display = "none"; + this.window!.style.display = "block"; + if (content.startsWith('error')) { + this.window!.innerHTML = `${content}`; + return; + } + let lineMap = this.getMap(content, hintAddr); + this.maxBinSize = this.maxBinSize * 1.7; + this.window!.innerHTML = ''; + for (let addr of this.addrArray) { + if (!lineMap.has(addr)) continue; + let struct = lineMap.get(addr); + if (this.addrArray[this.hintLine] == addr) { + this.window!.innerHTML += `
+ ${struct!.addr} : ${struct!.binary} + ${struct!.type} + ${struct!.code}
`; + (this.window!.querySelector("#emphasis") as HTMLElement)!.style.width = this.window!.scrollWidth + 'px'; + (this.window!.querySelector("#emphasis") as HTMLElement)!.style.background = '#0A59F7'; + } else { + this.window!.innerHTML += `
+ ${struct!.addr} : ${struct!.binary} + ${struct!.type} + ${struct!.code}
`; + } + } + this.window!.scrollTo(0, (this.hintLine - 1) * (this.shadowRoot!.querySelector("#window>.line")!.clientHeight) - this.window!.clientHeight / 2); + } + + private resetCanvas(styleWidth: number, styleHeight: number, width: number, height: number): void { + this.canvas!.style.width = styleWidth + "px"; + this.canvas!.style.height = styleHeight + "px"; + this.canvas!.width = width; + this.canvas!.height = height; + } + + public showLoading(): void { + this.loading!.style.display = 'block'; + this.window!.style.display = 'none'; + this.style.display = 'block'; + this.style.position = 'absolute'; + this.style.left = '0px'; + this.style.width = "64%"; + this.style.height = (this.parentElement!.querySelector("#left_table") as HTMLElement)!.clientHeight + 'px'; + this.style.border = '1px solid #d8d8d8'; + } + + initElements(): void { + this.canvas = this.shadowRoot?.querySelector("#canvas"); + let close = this.shadowRoot?.querySelector("#close"); + this.window = this.shadowRoot?.querySelector("#window"); + this.loading = this.shadowRoot?.querySelector("#loading"); + this.ctx = this.canvas!.getContext('2d'); + this.resetCanvas(0, 0, 0, 0); + close!.addEventListener("click", () => { + this.style.display = 'none'; + (this.parentElement!.querySelector("#left_table") as HTMLElement)!.style.visibility = 'visible'; + if (this.parentElement!.parentElement && this.parentElement!.parentElement!.nextElementSibling) { + (this.parentElement!.parentElement!.nextElementSibling as HTMLElement)!.style.display = 'flex'; + } + return true; + }); + } + + initHtml(): string { + return ` + + + `; + } +} + +class Disassembling { + addr = ''; + binary = ''; + type = ''; + code = ''; +} \ No newline at end of file diff --git a/host/ide/src/trace/component/FrameChart.ts b/host/ide/src/trace/component/FrameChart.ts new file mode 100644 index 0000000000000000000000000000000000000000..ae3d684f580c760a852917245a2d8f23ed57bd2f --- /dev/null +++ b/host/ide/src/trace/component/FrameChart.ts @@ -0,0 +1,552 @@ +/* + * 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. + */ + +import { BaseElement, element } from "../../base-ui/BaseElement.js"; +import { NativeHookCallInfo } from "../bean/NativeHook.js"; +import { ChartMode, ChartStruct, Rect } from "../database/ProcedureWorkerCommon.js"; +import { SpApplication } from "../SpApplication.js"; +import { Utils } from "./trace/base/Utils.js"; + +const TAG: string = "FrameChart"; +const scaleHeight = 30; +const depthHeight = 20; + +@element('tab-framechart') +export class FrameChart extends BaseElement { + private canvas: HTMLCanvasElement | undefined | null; + private cavasContext: CanvasRenderingContext2D | undefined | null; + private floatHint: HTMLDivElement | undefined | null; + + private rect: Rect = new Rect(0, 0, 0, 0); + private _mode = ChartMode.Call; + private startX = 0; // canvas start x coord + private startY = 0; // canvas start y coord + private canvasX = -1; // canvas current x + private canvasY = -1; // canvas current y + private lastCanvasXInScale = 0; + private lastCanvasX = 0; + private hintContent = ""; // float hoint inner html content + + private historyList: Array> = []; + private currentSize = 0; + private currentCount = 0; + private currentData: Array = []; + private xPoint = 0; // x in rect + private isFocusing = false; + private canvasScrollTop = 0; + private _maxDepth = 0; + + static get observedAttributes() { + return [] + } + + set data(val: Array | any) { + this.currentData = val; + this.resetTrans(); + this.caldrawArgs(); + } + + set tabPaneScrollTop(scrollTop: number) { + this.canvasScrollTop = scrollTop; + } + + /** + * cal total count size and max Depth + */ + private caldrawArgs(): void { + this.currentCount = 0; + this.currentSize = 0; + for (let rootNode of this.currentData!) { + this.currentCount += rootNode.count; + this.currentSize += rootNode.size; + let depth = 0; + this.calMaxDepth(rootNode, depth); + } + this.rect.height = this._maxDepth * 20 + scaleHeight; // 20px/depth and 30 is scale height + } + + /** + * cal max Depth + * @param node every child node + * @param depth current depth + */ + private calMaxDepth(node: ChartStruct, depth: number): void { + depth++; + if (node.children && node.children.length > 0) { + for (let children of node.children) { + this.calMaxDepth(children, depth); + } + } else { + this._maxDepth = Math.max(depth, this._maxDepth); + } + } + + /** + * set chart mode + * @param mode chart format for data mode + */ + set mode(mode: ChartMode) { + this._mode = mode; + } + + /** + * calculate Data and draw chart + */ + async calculateChartData() { + this.clearCanvas(); + this.cavasContext?.beginPath(); + this.drawScale(); + let x = this.xPoint; + switch (this._mode) { + case ChartMode.Byte: + for (let node of this.currentData!) { + let width = Math.ceil(node.size / this.currentSize * this.rect!.width); + let height = depthHeight; // 20px / depth + // ensure the data for first depth frame + if (!node.frame) { + node.frame = new Rect(x, scaleHeight, width, height) + } else { + node.frame!.x = x; + node.frame!.y = scaleHeight; + node.frame!.width = width; + node.frame!.height = height; + } + // not draw when rect not in canvas + if (x + width >= 0 && x < this.canvas!.width) { + NativeHookCallInfo.draw(this.cavasContext!, node, node.size / this.currentSize); + this.drawFrameChart(node); + } + x += width; + } + break; + case ChartMode.Count: + for (let node of this.currentData!) { + let width = Math.ceil(node.count / this.currentCount * this.rect!.width); + let height = depthHeight; // 20px / depth + // ensure the data for first depth frame + if (!node.frame) { + node.frame = new Rect(x, scaleHeight, width, height) + } else { + node.frame!.x = x; + node.frame!.y = scaleHeight; + node.frame!.width = width; + node.frame!.height = height; + } + // not draw when rect not in canvas + if (x + width >= 0 && x < this.canvas!.width) { + NativeHookCallInfo.draw(this.cavasContext!, node, node.count / this.currentCount); + this.drawFrameChart(node); + } + x += width; + } + break; + } + this.cavasContext?.closePath(); + } + + /** + * clear canvas all data + */ + public clearCanvas() { + this.cavasContext?.clearRect(0, 0, this.canvas!.width, this.canvas!.height); + } + + /** + * update canvas size + */ + public updateCanvas(updateWidth: boolean, newWidth?: number): void { + if (this.canvas instanceof HTMLCanvasElement) { + this.canvas.style.width = 100 + "%"; + this.canvas.style.height = this.rect!.height + "px"; + this.canvas.width = this.canvas!.clientWidth; + this.canvas.height = Math.ceil(this.rect!.height); + if (this.canvas.getBoundingClientRect()) { + let box = this.canvas.getBoundingClientRect(); + let D = document.documentElement; + this.startX = box.left + Math.max(D.scrollLeft, document.body.scrollLeft) - D.clientLeft; + this.startY = box.top + Math.max(D.scrollTop, document.body.scrollTop) - D.clientTop + this.canvasScrollTop; + } + } + if (this.rect.width == 0 || updateWidth || + Math.round(newWidth!) != this.canvas!.width + 40 || newWidth! > this.rect.width){ + this.rect.width = this.canvas!.clientWidth; + } + } + + /** + * draw top Scale Into 100 pieces + */ + private drawScale(): void { + let spApplication = document.getElementsByTagName("sp-application")[0]; + // line + this.cavasContext!.lineWidth = 0.5; + this.cavasContext?.moveTo(0, 0); + this.cavasContext?.lineTo(this.canvas!.width, 0); + + for (let i = 0; i <= 10; i++) { + let startX = Math.floor(this.canvas!.width / 10 * i); + for (let j = 0; j < 10; j++) { + // children scale + this.cavasContext!.lineWidth = 0.5; + let startItemX = startX + Math.floor(this.canvas!.width / 100 * j); + this.cavasContext?.moveTo(startItemX, 0); + this.cavasContext?.lineTo(startItemX, 10); + } + if (i == 0) continue; // skip first Size is 0 + // long line every 10 count + this.cavasContext!.lineWidth = 1; + let sizeRatio = this.canvas!.width / this.rect.width; // scale ratio + if (spApplication.dark) { + this.cavasContext!.strokeStyle = "#888"; + } else { + this.cavasContext!.strokeStyle = "#ddd"; + } + this.cavasContext?.moveTo(startX, 0); + this.cavasContext?.lineTo(startX, this.canvas!.height); + if (spApplication.dark) { + this.cavasContext!.fillStyle = "#fff"; + } else { + this.cavasContext!.fillStyle = "#000"; + } + let scale = ''; + if (this._mode == ChartMode.Byte) { + scale = Utils.getByteWithUnit(this.currentSize * sizeRatio / 10 * i); + } else { + scale = (this.currentCount * sizeRatio / 10 * i).toFixed(0) + ''; + } + this.cavasContext?.fillText(scale, startX + 5, depthHeight, 50); // 50 is Text max Size + this.cavasContext?.stroke(); + } + } + + /** + * draw chart + * @param node draw chart by every piece + */ + drawFrameChart(node: ChartStruct) { + if (node.children && node.children.length > 0) { + for (let children of node.children) { + children.parent = node; + let percent = 0; + if (this._mode == ChartMode.Byte) { + NativeHookCallInfo.setFuncFrame(children, this.rect, this.currentSize, this._mode); + percent = children.size / this.currentSize; + } else { + NativeHookCallInfo.setFuncFrame(children, this.rect, this.currentCount, this._mode); + percent = children.count / this.currentCount; + } + // not draw when rect not in canvas + if (children.frame!.x + children.frame!.width >= 0 && + children.frame!.x < this.canvas!.width && children.frame!.width > 2) { + NativeHookCallInfo.draw(this.cavasContext!, children, percent); + this.drawFrameChart(children); + } + } + } + } + + /** + * find target node from tree by mouse position + * + * @param nodes tree nodes + * @param canvasX x coord of canvas + * @param canvasY y coord of canvas + * @returns target node + */ + private searchData(nodes: Array, canvasX: number, canvasY: number): any { + for (let node of nodes) { + if (node.frame?.contains(canvasX, canvasY)) { + return node; + } else { + let result = this.searchData(node.children, canvasX, canvasY); + if (!result) continue; // if not found in this branch;search another branch + return result; + } + } + return null; + } + + /** + * show float hint and update position + */ + private updateFloatHint(): void { + this.floatHint!.innerHTML = this.hintContent; + this.floatHint!.style.display = 'flex'; + let x = this.canvasX; + let y = this.canvasY - this.canvasScrollTop; + //right rect hint show left + if (this.canvasX + this.floatHint!.clientWidth > (this.canvas?.clientWidth || 0)) { + x -= this.floatHint!.clientWidth - 1; + } else { + x += 30; + } + //bottom rect hint show top + if (this.canvasY + this.floatHint!.clientHeight > (this.canvas?.clientHeight || 0)) { + y -= this.floatHint!?.clientHeight - 1; + y += 30; + } else { + y -= 10; + } + this.floatHint!.style.transform = `translate(${x}px,${y}px)`; + } + + /** + * redraw Chart while click to scale chart + * @param selectData select Rect data as array + */ + private redrawChart(selectData: Array): void { + this.currentData = selectData; + if (selectData.length == 0) return; + this.caldrawArgs(); + this.calculateChartData(); + } + + /** + * press w to zoom in, s to zoom out + * @param index < 0 zoom out , > 0 zoom in + */ + private scale(index: number): void { + let newWidth = 0; + // zoom in + let deltaWidth = this.rect!.width * 0.2; + if (index > 0) { + newWidth = this.rect!.width + deltaWidth; + // max scale + let sizeRatio = this.canvas!.width / this.rect.width; + if (this._mode == ChartMode.Byte) { + if (Math.round(this.currentSize * sizeRatio) <= 10) { + newWidth = this.canvas!.width / (10 / this.currentSize); + } + } else { + if (Math.round(this.currentCount * sizeRatio) <= 10) { + if (this.lastCanvasXInScale == 0){ + return; + } + newWidth = this.canvas!.width / (10 / this.currentCount); + } + } + } else { // zoom out + newWidth = this.rect!.width - deltaWidth; + // min scale + if (newWidth < this.canvas!.width) { + newWidth = this.canvas!.width; + this.resetTrans() + } + } + // width not change + if (newWidth == this.rect.width) return; + this.translationByScale(index, deltaWidth, newWidth); + } + + private resetTrans() { + this.xPoint = 0; + this.lastCanvasXInScale = 0; + this.lastCanvasX = 0; + } + + /** + * translation after scale + * @param index is zoom in + * @param deltaWidth scale delta width + * @param newWidth rect width after scale + */ + private translationByScale(index: number, deltaWidth: number, newWidth: number): void { + if (this.lastCanvasX != this.canvasX && this.lastCanvasX != 0){ + this.lastCanvasXInScale = this.lastCanvasX; + } + if (this.lastCanvasXInScale == 0) { + this.lastCanvasXInScale = this.canvasX; + } + let deltaWidthPerent = (this.canvasX - this.lastCanvasXInScale) / this.canvas!.width; + let translationValue = deltaWidth * this.canvasX / this.canvas!.width * (1 - deltaWidthPerent) + if (index > 0) { + this.xPoint -= translationValue; + } else { + this.xPoint += translationValue; + } + this.lastCanvasX = this.canvasX; + this.rect!.width = newWidth; + this.translationDraw(); + } + + /** + * press a/d to translate rect + * @param index left or right + */ + private translation(index: number): void { + // let width = this.rect!.width; + let offset = this.canvas!.width / 10; + for (let i = 0; i < Math.abs(index); i++) { + if (index < 0) { + this.xPoint += offset; + } else { + this.xPoint -= offset; + } + } + this.translationDraw(); + } + + /** + * judge position ro fit canvas and draw + */ + private translationDraw(): void { + // rightad trans limit + if (this.xPoint > 0) { + this.xPoint = 0; + } + // left trans limit + if (this.rect.width + this.xPoint < this.canvas!.width) { + this.xPoint = this.canvas!.width - this.rect.width; + } + this.calculateChartData(); + } + + /** + * canvas click + * @param e MouseEvent + */ + private onMouseClick(e: MouseEvent): void { + if (e.button == 0) { // mouse left button + if (ChartStruct.hoverFuncStruct && ChartStruct.hoverFuncStruct != ChartStruct.selectFuncStruct) { + ChartStruct.selectFuncStruct = ChartStruct.hoverFuncStruct; + this.historyList.push(this.currentData!); + let selectData = new Array(); + selectData.push(ChartStruct.selectFuncStruct!); + // reset scale and translation + this.rect.width = this.canvas!.clientWidth; + this.resetTrans(); + this.redrawChart(selectData); + } + } else if (e.button == 2) { // mouse right button + ChartStruct.selectFuncStruct = undefined; + if (this.historyList.length > 0) { + // reset scale and translation + this.rect.width = this.canvas!.clientWidth; + this.resetTrans(); + this.redrawChart(this.historyList.pop()!); + } + } + } + + /** + * mouse on canvas move event + */ + private onMouseMove(): void { + let lastNode = ChartStruct.hoverFuncStruct; + let searchResult = this.searchData(this.currentData!, this.canvasX, this.canvasY); + if (searchResult) { + ChartStruct.hoverFuncStruct = searchResult; + // judge current node is hover redraw chart + if (searchResult != lastNode) { + let name = ChartStruct.hoverFuncStruct?.symbol; + if (this._mode == ChartMode.Byte) { + let size = Utils.getByteWithUnit(ChartStruct.hoverFuncStruct!.size); + this.hintContent = `Name: ${name} Size: ${size}`; + } else { + let count = ChartStruct.hoverFuncStruct!.count; + this.hintContent = `Name: ${name} Count: ${count}`; + } + this.calculateChartData(); + } + // pervent float hint trigger onmousemove event + this.updateFloatHint(); + } else { + if (this.floatHint) { + this.floatHint.style.display = 'none'; + } + } + } + + initElements(): void { + this.canvas = this.shadowRoot?.querySelector("#canvas"); + this.cavasContext = this.canvas?.getContext("2d"); + this.floatHint = this.shadowRoot?.querySelector('#float_hint'); + + this.canvas!.oncontextmenu = () => { + return false; + }; + this.canvas!.onmouseup = (e) => { + this.onMouseClick(e); + } + + this.canvas!.onmousemove = (e) => { + this.canvasX = e.clientX - this.startX; + this.canvasY = e.clientY - this.startY + this.canvasScrollTop; + this.isFocusing = true; + this.onMouseMove(); + }; + + this.canvas!.onmouseleave = () => { + ChartStruct.selectFuncStruct = undefined; + this.isFocusing = false; + if (this.floatHint) { + this.floatHint.style.display = 'none'; + } + }; + + document.addEventListener('keydown', (e) => { + if (!this.isFocusing) return; + switch (e.key.toLocaleLowerCase()) { + case 'w': + this.scale(1); + break; + case 's': + this.scale(-1); + break; + case 'a': + this.translation(-1); + break; + case 'd': + this.translation(1); + break; + } + }); + new ResizeObserver((entries) => { + if (this.canvas!.getBoundingClientRect()) { + let box = this.canvas!.getBoundingClientRect(); + let D = document.documentElement; + this.startX = box.left + Math.max(D.scrollLeft, document.body.scrollLeft) - D.clientLeft; + this.startY = box.top + Math.max(D.scrollTop, document.body.scrollTop) - D.clientTop + this.canvasScrollTop; + } + }).observe(document.documentElement); + } + + initHtml(): string { + return ` + + +
`; + } +} \ No newline at end of file diff --git a/host/ide/src/trace/component/SpFilter.ts b/host/ide/src/trace/component/SpFilter.ts new file mode 100644 index 0000000000000000000000000000000000000000..985fbdb76579b32c7e7f592bdd276fcb3fbdc2f1 --- /dev/null +++ b/host/ide/src/trace/component/SpFilter.ts @@ -0,0 +1,84 @@ +/* + * 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. + */ + +import {BaseElement, element} from "../../base-ui/BaseElement.js"; + +@element('sp-filter') +export class SpFilter extends BaseElement { + initElements(): void { + } + + initHtml(): string { + return ` + +
+ Input Filter + +
+ `; + } +} \ No newline at end of file diff --git a/host/ide/src/trace/component/SpHelp.ts b/host/ide/src/trace/component/SpHelp.ts new file mode 100644 index 0000000000000000000000000000000000000000..cfa84b7b3c2b058a4df25589d56f3eaceafbe4bb --- /dev/null +++ b/host/ide/src/trace/component/SpHelp.ts @@ -0,0 +1,227 @@ +/* + * 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. + */ + +import {BaseElement, element} from "../../base-ui/BaseElement.js"; +import {LitMainMenuGroup} from "../../base-ui/menu/LitMainMenuGroup.js"; +import {LitMainMenu, MenuItem} from "../../base-ui/menu/LitMainMenu.js"; +import {LitMainMenuItem} from "../../base-ui/menu/LitMainMenuItem"; + +@element('sp-help') +export class SpHelp extends BaseElement { + private appContent: HTMLElement | undefined | null + + get dark() { + return this.hasAttribute("dark"); + } + + set dark(dark: boolean) { + if (dark) { + this.setAttribute("dark", '' + dark); + } + this.appContent!.innerHTML = "" + } + + initElements(): void { + let that = this + let parentElement = this.parentNode as HTMLElement; + parentElement.style.overflow = 'hidden' + this.appContent = this.shadowRoot?.querySelector('#app-content') as HTMLElement + let mainMenu = this.shadowRoot?.querySelector('#main-menu') as LitMainMenu + let header = mainMenu.shadowRoot?.querySelector('.header') as HTMLDivElement + let version = mainMenu.shadowRoot?.querySelector('.version') as HTMLDivElement + header.style.display = 'none' + version.style.display = 'none' + mainMenu.menus = [ + { + collapsed: false, + title: 'QuickStart', + describe: '', + children: [ + { + title: "快速启动hiprofiler_cmd", icon: "", clickHandler: function (item: MenuItem) { + that.appContent!.innerHTML = + "" + } + }, + { + title: "网页加载trace 使用说明", icon: "", clickHandler: function (item: MenuItem) { + that.appContent!.innerHTML = + "" + } + }, + { + title: "Ability Monitor使用说明", icon: "", clickHandler: function (item: MenuItem) { + that.appContent!.innerHTML = + "" + } + }, + { + title: "Perf使用说明", icon: "", clickHandler: function (item: MenuItem) { + that.appContent!.innerHTML = + "" + } + } + ] + }, + { + collapsed: false, + title: 'TraceStreamer', + describe: '', + children: [ + { + title: "编译Trace_streamer", + icon: "", + clickHandler: function (item: MenuItem) { + that.appContent!.innerHTML = "" + } + }, + { + title: "TraceStreamer 解析数据状态表", + icon: "", + clickHandler: function (item: MenuItem) { + that.appContent!.innerHTML = "" + } + }, + { + title: "概述TraceStreamer生成的数据库", + icon: "", + clickHandler: function (item: MenuItem) { + that.appContent!.innerHTML = "" + } + }, + { + title: "TraceStreamer支持解析事件列表", + icon: "", + clickHandler: function (item: MenuItem) { + that.appContent!.innerHTML = "" + } + }, + { + title: "trace_streamer工具说明", + icon: "", + clickHandler: function (item: MenuItem) { + that.appContent!.innerHTML = "" + } + }, + ] + }, + { + collapsed: false, + title: 'SmartPerf', + describe: '', + children: [ + { + title: "SmartPerf 编译指导", + icon: "", + clickHandler: function (item: MenuItem) { + that.appContent!.innerHTML = "" + } + }, + ] + }, + ] + mainMenu.style.width = '290px' + let body = mainMenu.shadowRoot?.querySelector('.menu-body') as HTMLDivElement + let groups = body.querySelectorAll('lit-main-menu-group') + groups.forEach(value => { + let items = value.querySelectorAll('lit-main-menu-item') + items.forEach(item => { + item.style.width = '290px' + }) + }) + } + + initHtml(): string { + return ` + +
+
+ +
+
+
+
+ `; + } +} \ No newline at end of file diff --git a/host/ide/src/trace/component/SpInfoAndStas.ts b/host/ide/src/trace/component/SpInfoAndStas.ts index a450ef9e5a21674e81df606200b19bc826e87482..11552001adab508e17c0e7ee04376d21edcaca0c 100644 --- a/host/ide/src/trace/component/SpInfoAndStas.ts +++ b/host/ide/src/trace/component/SpInfoAndStas.ts @@ -14,15 +14,239 @@ */ import {BaseElement, element} from "../../base-ui/BaseElement.js"; +import {querySelectTraceStats, queryTraceMetaData,} from "../database/SqlLite.js"; +import {LitTable} from "../../base-ui/table/lit-table.js"; +import "../../base-ui/table/lit-table.js"; @element('sp-info-and-stats') export class SpInfoAndStats extends BaseElement { + private metaData: Array = []; + private infoData: Array = []; + private metaTableEl: LitTable | undefined; + private infoTableEl: LitTable | undefined; + private th: HTMLElement | undefined; + private backgroundMetaTable: HTMLDivElement | undefined; + private backgroundInfoTable: HTMLDivElement | undefined; + + static get observedAttributes() { + return [] + } + initElements(): void { + this.metaTableEl = this.shadowRoot!.querySelector('#metaData-table') as LitTable; + this.infoTableEl = this.shadowRoot!.querySelector('#stats-table') as LitTable; + + this.infoTableEl.style.overflow = 'visible' + this.metaTableEl.style.overflow = 'visible' + this.infoTableEl.style.width = 'auto' + this.metaTableEl.style.width = 'auto' + this.th = this.shadowRoot!.querySelector('.th') as HTMLElement; + } + + initInfoAndStatsData() { + this.initMetricItemData().then(() => { + this.metaTableEl!.dataSource = this.metaData; + this.infoTableEl!.dataSource = this.infoData; + let metaDataStyle: HTMLDivElement | undefined | null = this.shadowRoot?.querySelector('#metaData-table')?.shadowRoot?.querySelector('div.body') as HTMLDivElement + let metaDataHeadStyle: HTMLDivElement | undefined | null = this.shadowRoot?.querySelector('#metaData-table')?.shadowRoot?.querySelector('div.thead') as HTMLDivElement + let statsStyle: HTMLDivElement | undefined | null = this.shadowRoot?.querySelector('#stats-table')?.shadowRoot?.querySelector('div.body') as HTMLDivElement + let statsHeadStyle: HTMLDivElement | undefined | null = this.shadowRoot?.querySelector('#stats-table')?.shadowRoot?.querySelector('div.thead') as HTMLDivElement + metaDataHeadStyle.style.backgroundColor = 'var(--dark-background5,#F6F6F6)' + statsHeadStyle.style.backgroundColor = 'var(--dark-background5,#F6F6F6)' + this.initDataTableStyle(metaDataStyle); + this.initDataTableStyle(statsStyle); + }); + } + + initDataTableStyle(styleTable: HTMLDivElement): void { + for (let index = 0; index < styleTable.children.length; index++) { + // @ts-ignore + styleTable.children[index].style.backgroundColor = 'var(--dark-background5,#F6F6F6)' + } + this.metaTableEl!.style.height = 'auto' + this.metaTableEl!.style.minHeight = '80%' + this.metaTableEl!.style.borderRadius = '16' + this.infoTableEl!.style.height = 'auto' + this.infoTableEl!.style.minHeight = '80%' + this.infoTableEl!.style.borderRadius = '16' + } + + async initMetricItemData() { + this.metaData = [] + this.infoData = [] + let mete = await queryTraceMetaData(); + if (mete) { + for (let index = 0; index < mete.length; index++) { + this.metaData.push({name: mete[index].name, value: mete[index].valueText}) + } + } + let info = await querySelectTraceStats(); + if (info) { + for (let index = 0; index < info.length; index++) { + this.infoData.push({ + event_name: info[index].event_name, + stat_type: info[index].stat_type, + count: info[index].count + }) + } + } + } + + connectedCallback() { + } + + disconnectedCallback() { + } + + attributeChangedCallback(name: string, oldValue: string, newValue: string) { } initHtml(): string { return ` -
System info and metadata
+ + +
+ + +
`; } } + +export class MetaDataTable { + name: string | undefined; + value: string | undefined; + type?: string | undefined; +} + +export class InfoDataTable { + event_name: string | undefined; + stat_type: string | undefined; + count: number | undefined; + source?: string | undefined; + serverity?: string | undefined; +} diff --git a/host/ide/src/trace/component/SpMetrics.ts b/host/ide/src/trace/component/SpMetrics.ts index 3e06d04c8d084a51f7eb3e9349518d2e64fd896c..530e935fb9eaf3ee92e47d0e4419234e00cec1c9 100644 --- a/host/ide/src/trace/component/SpMetrics.ts +++ b/host/ide/src/trace/component/SpMetrics.ts @@ -15,41 +15,335 @@ import {BaseElement, element} from "../../base-ui/BaseElement.js"; +import { + queryDistributedTerm, + querySelectTraceStats, + querySystemCalls, + querySystemCallsTop, + queryTraceCpu, + queryTraceCpuTop, + queryTraceMemory, + queryTraceMemoryTop, + queryTraceMemoryUnAgg, + queryTraceMetaData, + queryTraceTaskName +} from "../database/SqlLite.js"; + +import "../../base-ui/table/lit-table.js"; +import {initCpuStrategyData, initTest} from "./metrics/CpuStrategy.js"; +import {initDistributedTermData} from "./metrics/DistributeTermStrategy.js"; +import {initMemoryAggStrategy} from "./metrics/MemAggStrategy.js"; +import {initMemoryStrategy} from "./metrics/MemStrategy.js"; +import {initSysCallsStrategy} from "./metrics/SysCallsStrategy.js"; +import {initSysCallsTopStrategy} from "./metrics/SysCallsTopStrategy.js"; +import {initTraceStateStrategy} from "./metrics/TraceStatsStrategy.js"; +import {initTraceTaskStrategy} from "./metrics/TraceTaskStrategy.js"; +import {initMetaDataStrategy} from "./metrics/MetaDataStrategy.js"; +import {PluginConvertUtils} from "./setting/utils/PluginConvertUtils.js"; + @element('sp-metrics') export class SpMetrics extends BaseElement { + private _metric?: string; + private _metricResult?: string; + private selectMetricEl: HTMLSelectElement | undefined; + private runButtonEl: HTMLButtonElement | undefined | null; + private responseJson: HTMLPreElement | undefined | null; + private metricOptionalSelects: Array | undefined; + + static get observedAttributes() { + return ["metric", "metricResult"] + } + + get metric(): string { + return this.getAttribute("metric") || ""; + } + + set metric(value: string) { + this._metric = value; + } + + get metricResult(): string { + return this.getAttribute("metricResult") || ""; + } + + set metricResult(value: string) { + this._metricResult = value; + this.setAttribute("metricResult", value); + } + initElements(): void { + this.selectMetricEl = this.shadowRoot?.querySelector(".sql-select") as HTMLSelectElement; + this.runButtonEl = this.shadowRoot?.querySelector(".sql-select-button") as HTMLButtonElement; + this.responseJson = this.shadowRoot?.querySelector(".response-json") as HTMLPreElement; + if (this.selectMetricEl) { + this.selectMetricEl.addEventListener("selectionchange", () => { + if (this.selectMetricEl) this.selectMetricEl.textContent = ""; + }) + } + this.initMetricDataHandle(); + this.initMetricSelectOption(); + } + + initMetric(queryItem: MetricQueryItem) { + this.initMetricData(queryItem).then(item => { + }) + } + + async initMetricData(queryItem: MetricQueryItem) { + let metricQuery = queryItem.metricQuery; + let queryList = await metricQuery(); + let metric = queryItem.metricResultHandle; + let resultData = metric(queryList); + let jsonText = PluginConvertUtils.BeanToCmdTxtWithObjName(resultData, true, queryItem.metricName, 4); + this.responseJson!.textContent = jsonText; + } + + attributeChangedCallback(name: string, oldValue: string, newValue: string) { + switch (name) { + case "metric": + if (this.selectMetricEl) this.selectMetricEl.textContent = newValue + break; + case "metricResult": + if (this.selectMetricEl) this.selectMetricEl.textContent = newValue + break; + } + } + + runClickListener = (event: any) => { + let selectedIndex = this.selectMetricEl!.selectedIndex; + let value = this.selectMetricEl!.options[selectedIndex].value; + let resultQuery = this.metricOptionalSelects?.filter((item) => { + return item.metricName == value + }) + if (!resultQuery || resultQuery.length < 1) return + this.initMetric(resultQuery[0]); + } + + + connectedCallback() { + // Run metric button to add listener + this.runButtonEl?.addEventListener('click', this.runClickListener); + } + + disconnectedCallback() { + this.runButtonEl?.removeEventListener('click', this.runClickListener); + } + + initMetricSelectOption() { + for (let index = 0; index < this.metricOptionalSelects!.length; index++) { + let htmlElement = document.createElement('option'); + if (this.metricOptionalSelects) { + htmlElement.textContent = this.metricOptionalSelects[index].metricName; + this.selectMetricEl?.appendChild(htmlElement); + } + } + } + + initMetricDataHandle() { + this.metricOptionalSelects = [ + { + metricName: 'distributed_term', + metricQuery: queryDistributedTerm, + metricResultHandle: initDistributedTermData + }, + { + metricName: 'trace_name', + metricQuery: querySelectTraceStats, + metricResultHandle: initTest, + }, + { + metricName: 'trace_cpu', + metricQuery: queryTraceCpu, + metricResultHandle: initCpuStrategyData + }, + { + metricName: 'trace_cpu_top10', + metricQuery: queryTraceCpuTop, + metricResultHandle: initCpuStrategyData, + }, + { + metricName: 'trace_mem', + metricQuery: queryTraceMemory, + metricResultHandle: initMemoryStrategy + }, + { + metricName: 'trace_mem_top10', + metricQuery: queryTraceMemoryTop, + metricResultHandle: initMemoryStrategy + }, + { + metricName: 'trace_mem_unagg', + metricQuery: queryTraceMemoryUnAgg, + metricResultHandle: initMemoryAggStrategy + }, + { + metricName: 'trace_task_names', + metricQuery: queryTraceTaskName, + metricResultHandle: initTraceTaskStrategy + }, + { + metricName: 'trace_stats', + metricQuery: querySelectTraceStats, + metricResultHandle: initTraceStateStrategy + }, + { + metricName: 'trace_metadata', + metricQuery: queryTraceMetaData, + metricResultHandle: initMetaDataStrategy + }, + { + metricName: 'sys_calls', + metricQuery: querySystemCalls, + metricResultHandle: initSysCallsStrategy + }, + { + metricName: 'sys_calls_top10', + metricQuery: querySystemCallsTop, + metricResultHandle: initSysCallsTopStrategy + }, + ] } initHtml(): string { return ` - + +
+
+

Select a metric

+ + +
+
+ +
+
+ `; + } } -xmp{ - color: #121212; - background-color: #eeeeee; - padding: 30px; - margin: 30px; - overflow: auto; - border-radius: 20px; + +export interface MetricQueryItem { + metricName: string + metricQuery: Function + metricResultHandle: Function } - -
- - trace_metadata: { - trace_duration_ns: 14726175738 - trace_uuid: "00000000-0000-0000-c0bd-eb5c5728bf40" - statsd_triggering_subscription_id: 0 - unique_session_name: "" - trace_size_bytes: 57202082 - trace_config_pbtxt: "buffers: { size_kb: 63488\\n fill_policy: DISCARD\\n}\\nbuffers: {\\n size_kb: 2048\\n fill_policy: DISCARD\\n}\\ndata_sources: {\\n config: {\\n name: \\"linux.process_stats\\"\\n target_buffer: 1\\n trace_duration_ms: 0\\n tracing_session_id: 0\\n enable_extra_guardrails: false\\n ftrace_config: {\\n buffer_size_kb: 0\\n drain_period_ms: 0\\n }\\n chrome_config: {\\n trace_config: \\"\\"\\n privacy_filtering_enabled: false\\n }\\n inode_file_config: {\\n scan_interval_ms: 0\\n scan_delay_ms: 0\\n scan_batch_size: 0\\n do_not_scan: false\\n }\\n process_stats_config: {\\n scan_all_processes_on_start: true\\n record_thread_names: false\\n proc_stats_poll_ms: 1000\\n proc_stats_cache_ttl_ms: 0\\n }\\n sys_stats_config: {\\n meminfo_period_ms: 0\\n vmstat_period_ms: 0\\n stat_period_ms: 0\\n }\\n heapprofd_config: {\\n sampling_interval_bytes: 0\\n all: false\\n continuous_dump_config: {\\n dump_phase_ms: 0\\n dump_interval_ms: 0\\n }\\n shmem_size_bytes: 0\\n block_client: false\\n }\\n android_power_config: {\\n battery_poll_ms: 0\\n collect_power_rails: false\\n }\\n android_log_config: {\\n min_prio: PRIO_UNSPECIFIED\\n }\\n packages_list_config: {\\n }\\n legacy_config: \\"\\"\\n }\\n}\\ndata_sources: {\\n config: {\\n name: \\"linux.ftrace\\"\\n target_buffer: 0\\n trace_duration_ms: 0\\n tracing_session_id: 0\\n enable_extra_guardrails: false\\n ftrace_config: {\\n ftrace_events: \\"sched/sched_switch\\"\\n ftrace_events: \\"power/suspend_resume\\"\\n ftrace_events: \\"sched/sched_wakeup\\"\\n ftrace_events: \\"sched/sched_wakeup_new\\"\\n ftrace_events: \\"sched/sched_waking\\"\\n ftrace_events: \\"power/cpu_frequency\\"\\n ftrace_events: \\"power/cpu_idle\\"\\n ftrace_events: \\"sched/sched_process_exit\\"\\n ftrace_events: \\"sched/sched_process_free\\"\\n ftrace_events: \\"task/task_newtask\\"\\n ftrace_events: \\"task/task_rename\\"\\n ftrace_events: \\"lowmemorykiller/lowmemory_kill\\"\\n ftrace_events: \\"oom/oom_score_adj_update\\"\\n ftrace_events: \\"ftrace/print\\"\\n atrace_categories: \\"gfx\\"\\n atrace_apps: \\"lmkd\\"\\n buffer_size_kb: 0\\n drain_period_ms: 0\\n }\\n chrome_config: {\\n trace_config: \\"\\"\\n privacy_filtering_enabled: false\\n }\\n inode_file_config: {\\n scan_interval_ms: 0\\n scan_delay_ms: 0\\n scan_batch_size: 0\\n do_not_scan: false\\n }\\n process_stats_config: {\\n scan_all_processes_on_start: false\\n record_thread_names: false\\n proc_stats_poll_ms: 0\\n proc_stats_cache_ttl_ms: 0\\n }\\n sys_stats_config: {\\n meminfo_period_ms: 0\\n vmstat_period_ms: 0\\n stat_period_ms: 0\\n }\\n heapprofd_config: {\\n sampling_interval_bytes: 0\\n all: false\\n continuous_dump_config: {\\n dump_phase_ms: 0\\n dump_interval_ms: 0\\n }\\n shmem_size_bytes: 0\\n block_client: false\\n }\\n android_power_config: {\\n battery_poll_ms: 0\\n collect_power_rails: false\\n }\\n android_log_config: {\\n min_prio: PRIO_UNSPECIFIED\\n }\\n packages_list_config: {\\n }\\n legacy_config: \\"\\"\\n }\\n}\\nduration_ms: 15000\\nenable_extra_guardrails: false\\nlockdown_mode: LOCKDOWN_UNCHANGED\\nstatsd_metadata: {\\n triggering_alert_id: 0\\n triggering_config_uid: 0\\n triggering_config_id: 0\\n triggering_subscription_id: 0\\n}\\nwrite_into_file: false\\nfile_write_period_ms: 0\\nmax_file_size_bytes: 0\\nguardrail_overrides: {\\n max_upload_per_day_bytes: 0\\n}\\ndeferred_start: false\\nflush_period_ms: 0\\nflush_timeout_ms: 0\\nnotify_traceur: false\\ntrigger_config: {\\n trigger_mode: UNSPECIFIED\\n trigger_timeout_ms: 0\\n}\\nallow_user_build_tracing: false\\nbuiltin_data_sources: {\\n disable_clock_snapshotting: false\\n disable_trace_config: false\\n disable_system_info: false\\n}\\nincremental_state_config: {\\n clear_period_ms: 0\\n}\\nunique_session_name: \\"\\"\\ncompression_type: COMPRESSION_TYPE_UNSPECIFIED\\nincident_report_config: {\\n destination_package: \\"\\"\\n destination_class: \\"\\"\\n privacy_level: 0\\n skip_dropbox: false\\n}" - sched_duration_ns: 14726119124 + +export class SpMetricsItem { + itemTip: string | undefined + itemValue: any[] | undefined } - -
- `; - } -} \ No newline at end of file diff --git a/host/ide/src/trace/component/SpQuerySQL.ts b/host/ide/src/trace/component/SpQuerySQL.ts index 291793d293b1daf8b70c4b5afcb69743302504df..2942f33aef0bfb76b388f33436abe2cc7fcaf022 100644 --- a/host/ide/src/trace/component/SpQuerySQL.ts +++ b/host/ide/src/trace/component/SpQuerySQL.ts @@ -14,55 +14,370 @@ */ import {BaseElement, element} from "../../base-ui/BaseElement.js"; -import {querySql, queryThreadsByPid} from "../database/SqlLite.js"; +import {queryCustomizeSelect, querySelectTraceStats} from "../database/SqlLite.js"; +import {LitTable} from "../../base-ui/table/lit-table.js"; +import "../../base-ui/table/lit-table.js"; +import {LitTableColumn} from "../../base-ui/table/lit-table-column.js"; @element('sp-query-sql') export class SpQuerySQL extends BaseElement { + private queryTableEl: LitTable | undefined; + private queryText: string | undefined; + private resultText: string | undefined; + private notSupportList: Array | undefined; + private querySize: HTMLElement | undefined; + private keyList: Array | undefined; + private selector: HTMLInputElement | undefined; + private isSupportSql: boolean = true; + private querySelectTables: string = ''; + private response: HTMLDivElement | undefined; + private statDataArray: any = [] + private querySqlErrorText: string = '' + private _queryStr?: string; + + static get observedAttributes() { + return ["queryStr"] + } + + get queryStr(): string { + return this.queryStr; + } + + set queryStr(value: string) { + this._queryStr = value; + } + initElements(): void { - let sqlInput: HTMLInputElement | undefined | null = this.shadowRoot?.querySelector('#sql-input'); - let contentEL: HTMLPreElement | undefined | null = this.shadowRoot?.querySelector('#content'); - if (sqlInput) { - sqlInput.addEventListener('change', e => { - let dateA = new Date().getTime(); - if(sqlInput&&sqlInput.value) { - querySql(sqlInput.value).then(res=>{ - let dur = new Date().getTime() - dateA; - contentEL!.innerHTML = `耗时:${dur}ms 记录:${res.length}条\n${JSON.stringify(res,null,4)}` - }) + this.selector = this.shadowRoot?.querySelector('.sql-select') as HTMLInputElement; + this.queryTableEl = new LitTable() + this.querySize = this.shadowRoot?.querySelector('.query_size') as HTMLElement; + this.response = this.shadowRoot?.querySelector('#dataResult') as HTMLDivElement; + this.notSupportList?.push('insert', 'delete', 'update', 'drop', 'alter', 'truncate'); + } + + selectEventListener = async (event: any) => { + if (event.ctrlKey && event.keyCode == 13) { + this.queryTableEl!.innerHTML = '' + this.queryText = this.selector!.value; + this.initDataElement(); + + this.response!.appendChild(this.queryTableEl!); + setTimeout(() => { + this.queryTableEl!.dataSource = this.statDataArray; + this.initData() + }, 20) + } + } + + initDataTableStyle(styleTable: HTMLDivElement): void { + for (let index = 0; index < styleTable.children.length; index++) { + // @ts-ignore + styleTable.children[index].style.backgroundColor = 'var(--dark-background5,#F6F6F6)' + } + } + + async initMetricData(): Promise { + if (!this.selector || this.selector.value == null) { + return []; + } + if (this.queryText == '' || this.queryText == null) { + let statList = await querySelectTraceStats(); + for (let index = 0; index < statList.length; index++) { + const statsResult = statList[index]; + let indexArray = { + event_name: statsResult.event_name, + start_type: statsResult.stat_type, + count: statsResult.count, + serverity: statsResult.serverity, + source: statsResult.source, + }; + } + if (this.querySize) { + this.querySize!.textContent = 'Query result - ' + statList.length + ' counts: select * from stat'; + } + this.resultText = 'Query result - ' + statList.length + ' counts: select * from stat'; + } else { + return this.statDataArray + } + } + + checkSupportSqlAbility(): boolean { + let noSupportChart = ['insert', 'delete', 'update', 'drop', 'alter', 'truncate'] + let result = noSupportChart.filter(item => { + return this.selector!.value.indexOf(item) > -1; + }); + return result.length > 0; + } + + checkSafetySelectSql(): boolean { + let split = this.selector?.value.trim().split(' '); + // if (!this.selector?.value.match('^\\s*?[sS]+$')) return + return !(split && split[0] == 'select'); + + } + + getSelectSqlField(): string { + if (this.selector!.value.indexOf('from') < 0) { + return ''; + } + let splitSql = this.selector?.value.split('from'); + if (splitSql) { + if (splitSql[0].indexOf('*') > -1) { + return '*' + } else { + let fields = splitSql[0].split(',') + return fields[0]; + } + } + return ''; + } + + getSelectSqlTableName(str: string): Array { + if (this.selector!.value.indexOf(str) < 0) { + return []; + } + let tableNameList = []; + let splitSql = this.selector?.value.split(str); + if (splitSql) { + for (let index = 1; index < splitSql?.length; index++) { + let splitSqlItem = splitSql[index].trim(); + let tableItem = splitSqlItem.split(' '); + let tableName = tableItem[0].trim(); + tableNameList.push(tableName); + if (tableName.indexOf('(') >= 0) { + tableNameList.pop(); + } else if (tableName.indexOf(')') >= 0) { + tableNameList.pop(); + let unitTableName = tableName.split(')'); + let tableNewName = unitTableName[0]; + tableNameList.push(tableNewName); } + } + } + return tableNameList + } + + initDataElement() { + if (this.keyList) { + this.keyList.forEach((item) => { + let htmlElement = document.createElement('lit-table-column') as LitTableColumn; + htmlElement.setAttribute('title', item); + htmlElement.setAttribute('data-index', item); + htmlElement.setAttribute('key', item); + htmlElement.setAttribute('align', 'flex-start'); + htmlElement.setAttribute('height', '32px'); + this.queryTableEl!.appendChild(htmlElement); }) } } connectedCallback() { + let selectQuery = this.shadowRoot?.querySelector('.query_select'); + if (selectQuery) { + let querySql = selectQuery.textContent; + } + // Listen to the sql execution of the query + this.addEventListener("keydown", this.selectEventListener); + this.selector!.addEventListener('input', this.inputSqlListener) + this.selector!.addEventListener('change', this.inputSqlListener) + } + + inputSqlListener = async (event: any) => { + let startData = new Date().getTime(); + if (!this.selector || this.selector!.value == null) { + this.querySqlErrorText = 'Query result - ' + ' 0 counts'; + return; + } + if (this.selector!.value.length < 15) { + this.isSupportSql = false; + this.querySqlErrorText = 'Query result - ' + ' 0 counts: ' + this.selector!.value; + if (this.checkSafetySelectSql() || this.checkSupportSqlAbility()) { + this.querySqlErrorText = 'Error: Statement contains a change action keyword,The change operation is not supported.'; + return; + } + return; + } + if (this.checkSafetySelectSql() || this.checkSupportSqlAbility()) { + this.isSupportSql = false; + return; + } + this.querySelectTables = this.getSelectSqlTableName('from').concat(this.getSelectSqlTableName('join')).toLocaleString(); + this.isSupportSql = true; + + this.getInputSqlResult(this.selector!.value).then(resultList => { + let dur = new Date().getTime() - startData; + this.statDataArray = [] + this.keyList = []; + for (let index = 0; index < resultList.length; index++) { + const dataResult = resultList[index]; + let keys = Object.keys(dataResult); + let values = Object.values(dataResult); + let jsonText = '{'; + for (let keyIndex = 0; keyIndex < keys.length; keyIndex++) { + let key = keys[keyIndex]; + if (this.keyList.indexOf(key) <= -1) { + this.keyList.push(key) + } + let value = values[keyIndex]; + jsonText += '"' + key + '"' + ': ' + '"' + value + '"'; + if (keyIndex != keys.length - 1) { + jsonText += ',' + } else { + jsonText += '}'; + } + } + this.statDataArray.push(JSON.parse(jsonText)) + } + }) + } + + async getInputSqlResult(sql: string): Promise { + return await queryCustomizeSelect(sql); + } + + disconnectedCallback() { + this.removeEventListener("keydown", this.selectEventListener); + this.selector!.removeEventListener('input', this.inputSqlListener) + this.selector!.removeEventListener('change', this.inputSqlListener) + } + + initData() { + if (this.statDataArray.length > 0) { + this.querySize!.textContent = 'Error: ' + this.selector?.value; + } + if (this.isSupportSql) { + let sqlField = this.keyList?.length == 0 ? '*' : this.keyList?.toLocaleString(); + this.querySize!.textContent = 'Query result - ' + this.statDataArray.length + ' counts: select ' + sqlField + ' from ' + this.querySelectTables; + } else { + this.querySize!.textContent = this.querySqlErrorText; + } + } + + attributeChangedCallback(name: string, oldValue: string, newValue: string) { + let queryDataSty: HTMLDivElement | undefined | null = this.queryTableEl?.shadowRoot?.querySelector('div.tbody') as HTMLDivElement + if (queryDataSty && queryDataSty.hasChildNodes()) { + for (let index = 0; index < queryDataSty.children.length; index++) { + // @ts-ignore + queryDataSty.children[index].style.backgroundColor = 'var(--dark-background5,#F6F6F6)' + } + } } initHtml(): string { return ` - -
- -

-
+ +
+
+

Enter query and press cmd/ctrl + Enter

+ +
+
+

Query result - 0 counts

+
+
+
`; } - -} \ No newline at end of file +} diff --git a/host/ide/src/trace/component/SpRecordTrace.ts b/host/ide/src/trace/component/SpRecordTrace.ts index 2e7674f29cb55bc413555cf7415ec06e3d34e778..00b9a26c42e0b2604ebc96dda5eb8dd00256f91a 100644 --- a/host/ide/src/trace/component/SpRecordTrace.ts +++ b/host/ide/src/trace/component/SpRecordTrace.ts @@ -22,12 +22,17 @@ import {MenuItem} from "../../base-ui/menu/LitMainMenu.js"; import {SpProbesConfig} from "./setting/SpProbesConfig.js"; import {SpTraceCommand} from "./setting/SpTraceCommand.js"; import { + CpuConfig, CreateSessionRequest, + DiskioConfig, FpsConfig, HilogConfig, + HiperfPluginConfig, levelFromJSON, MemoryConfig, NativeHookConfig, + NetworkConfig, + ProcessConfig, ProfilerPluginConfig, ProfilerSessionConfig, ProfilerSessionConfigBufferConfig, @@ -40,6 +45,7 @@ import { } from "./setting/bean/ProfilerServiceTypes.js"; import {PluginConvertUtils} from "./setting/utils/PluginConvertUtils.js"; import {SpAllocations} from "./setting/SpAllocations.js"; +import {SpRecordPerf} from "./setting/SpRecordPerf.js"; @element('sp-record-trace') export class SpRecordTrace extends BaseElement { @@ -50,7 +56,7 @@ export class SpRecordTrace extends BaseElement { "MEMINFO_MLOCKED", "MEMINFO_PAGE_TABLES", "MEMINFO_SHMEM", "MEMINFO_SLAB", "MEMINFO_SLAB_RECLAIMABLE", "MEMINFO_SLAB_UNRECLAIMABLE", "MEMINFO_SWAP_CACHED", "MEMINFO_SWAP_FREE", "MEMINFO_SWAP_TOTAL", "MEMINFO_UNEVICTABLE", "MEMINFO_VMALLOC_CHUNK", "MEMINFO_VMALLOC_TOTAL", "MEMINFO_VMALLOC_USED", - "MEMINFO_WRITEBACK"] + "MEMINFO_WRITEBACK", "MEMINFO_KERNEL_RECLAIMABLE"] static VMEM_INFO = ["VMEMINFO_UNSPECIFIED", "VMEMINFO_NR_FREE_PAGES", "VMEMINFO_NR_ALLOC_BATCH", "VMEMINFO_NR_INACTIVE_ANON", "VMEMINFO_NR_ACTIVE_ANON", "VMEMINFO_NR_INACTIVE_FILE", "VMEMINFO_NR_ACTIVE_FILE", "VMEMINFO_NR_UNEVICTABLE", "VMEMINFO_NR_MLOCK", "VMEMINFO_NR_ANON_PAGES", @@ -93,6 +99,16 @@ export class SpRecordTrace extends BaseElement { "VMEMINFO_PGSKIP_NORMAL", "VMEMINFO_PGSTEAL_DIRECT", "VMEMINFO_PGSTEAL_KSWAPD", "VMEMINFO_SWAP_RA", "VMEMINFO_SWAP_RA_HIT", "VMEMINFO_WORKINGSET_RESTORE" ] + // sys.mem.total sys.mem.free sys.mem.buffers sys.mem.cached sys.mem.shmem sys.mem.slab sys.mem.swap.total + // sys.mem.swap.free sys.mem.mapped sys.mem.vmalloc.used sys.mem.page.tables sys.mem.kernel.stack + // sys.mem.active sys.mem.inactive sys.mem.unevictable sys.mem.vmalloc.total sys.mem.slab.unreclaimable + // sys.mem.cma.total sys.mem.cma.free + static ABALITY_MEM_INFO = ["MEMINFO_MEM_TOTAL", "MEMINFO_MEM_FREE", "MEMINFO_BUFFERS", "MEMINFO_CACHED", + "MEMINFO_SHMEM", "MEMINFO_SLAB", "MEMINFO_SWAP_TOTAL", "MEMINFO_SWAP_FREE", "MEMINFO_MAPPED", + "MEMINFO_VMALLOC_USED", "MEMINFO_PAGE_TABLES", "MEMINFO_KERNEL_STACK", "MEMINFO_ACTIVE", "MEMINFO_INACTIVE", + "MEMINFO_UNEVICTABLE", "MEMINFO_VMALLOC_TOTAL", "MEMINFO_SLAB_UNRECLAIMABLE", "MEMINFO_CMA_TOTAL", + "MEMINFO_CMA_FREE", "MEMINFO_KERNEL_RECLAIMABLE"] + schedulingEvents = [ "sched/sched_switch", "power/suspend_resume", @@ -172,6 +188,7 @@ export class SpRecordTrace extends BaseElement { let probesConfig = new SpProbesConfig(); let traceCommand = new SpTraceCommand(); let spAllocations = new SpAllocations(); + let spRecordPerf = new SpRecordPerf(); let menuGroup = this.shadowRoot?.querySelector('#menu-group') as LitMainMenuGroup let appContent = this.shadowRoot?.querySelector('#app-content') as HTMLElement appContent.append(recordSetting) @@ -209,11 +226,59 @@ export class SpRecordTrace extends BaseElement { sessionConfig: sessionConfig, pluginConfigs: [] } + let hasMonitorMemory = false; if (probesConfig.traceConfig.length > 0) { - request.pluginConfigs.push(that.createHtracePluginConfig(that, probesConfig, recordSetting)) + if (probesConfig.traceConfig.find(value => { + return value != "FPS" && value != "AbilityMonitor" + })) { + request.pluginConfigs.push(that.createHtracePluginConfig(that, probesConfig, recordSetting)) + } if (probesConfig.traceConfig.indexOf("FPS") != -1) { request.pluginConfigs.push(that.createFpsPluginConfig()) } + if (probesConfig.traceConfig.indexOf("AbilityMonitor") != -1) { + hasMonitorMemory = true; + let processConfig: ProcessConfig = { + report_process_tree: true, + report_cpu: true, + report_diskio: true, + report_pss: true, + } + let processPlugin: ProfilerPluginConfig = { + pluginName: "process-plugin", + sampleInterval: 1000, + configData: processConfig + } + request.pluginConfigs.push(processPlugin) + let cpuConfig: CpuConfig = { + pid: 0, + reportProcessInfo: true + } + let cpuPlugin: ProfilerPluginConfig = { + pluginName: "cpu-plugin", + sampleInterval: 1000, + configData: cpuConfig + } + request.pluginConfigs.push(cpuPlugin) + let diskIoConfig: DiskioConfig = { + reportIoStats: "IO_REPORT" + } + let diskIoPlugin: ProfilerPluginConfig = { + pluginName: "diskio-plugin", + sampleInterval: 1000, + configData: diskIoConfig + } + request.pluginConfigs.push(diskIoPlugin) + let netWorkConfig: NetworkConfig = { + testFile: "/data/local/tmp/" + } + let netWorkPlugin: ProfilerPluginConfig = { + pluginName: "network-plugin", + sampleInterval: 1000, + configData: netWorkConfig + } + request.pluginConfigs.push(netWorkPlugin) + } } let reportingFrequency: number; if (maxDur > 20) { @@ -221,12 +286,15 @@ export class SpRecordTrace extends BaseElement { } else { reportingFrequency = 2 } - if (probesConfig.memoryConfig.length > 0) { - request.pluginConfigs.push(that.createMemoryPluginConfig(probesConfig, that, reportingFrequency)) + if (probesConfig.memoryConfig.length > 0 || hasMonitorMemory) { + request.pluginConfigs.push(that.createMemoryPluginConfig(probesConfig, reportingFrequency, hasMonitorMemory)) } if (spAllocations.appProcess != "") { request.pluginConfigs.push(that.createNativePluginConfig(spAllocations, reportingFrequency)) } + if (spRecordPerf.startSamp) { + request.pluginConfigs.push(that.createHiperConfig(spRecordPerf, reportingFrequency)) + } appContent!.innerHTML = "" appContent.append(traceCommand) traceCommand.hdcCommon = @@ -242,13 +310,20 @@ export class SpRecordTrace extends BaseElement { } }, { - title: "Allocations", + title: "Native Memory", icon: "externaltools", fileChoose: false, clickHandler: function (ev: InputEvent) { appContent!.innerHTML = "" appContent.append(spAllocations) } + }, + { + title: "Hiperf", icon: "realIntentionBulb", fileChoose: false, + clickHandler: function (ev: InputEvent) { + appContent!.innerHTML = "" + appContent.append(spRecordPerf) + } } ] this._menuItems?.forEach(item => { @@ -317,141 +392,141 @@ export class SpRecordTrace extends BaseElement { initHtml(): string { return ` - -
- -
- -
-
-
-
-`; + .menugroup{ + height: 100%; + background: var(--dark-background3,#FFFFFF); + } + .menuitem{ + background: var(--dark-background3,#FFFFFF); + } + .content{ + background: var(--dark-background3,#FFFFFF); + border-style: none none none solid; + border-width: 1px; + border-color: rgba(166,164,164,0.2); + border-radius: 0px 16px 16px 0px; + } + +
+ +
+ +
+
+
+
+ `; } private createHilogConfig(probesConfig: SpProbesConfig, reportingFrequency: number) { @@ -468,6 +543,61 @@ export class SpRecordTrace extends BaseElement { return hilogConfigProfilerPluginConfig; } + private createHiperConfig(spRecordPerf: SpRecordPerf, reportingFrequency: number) { + let perfConfig = spRecordPerf.getPerfConfig(); + let recordArgs = ""; + recordArgs = recordArgs + "-f " + perfConfig?.frequency; + if (perfConfig?.process && !perfConfig?.process.includes("ALL") && perfConfig?.process.length > 0) { + recordArgs = recordArgs + " -p " + perfConfig?.process; + } else { + recordArgs = recordArgs + " -a "; + } + if (perfConfig?.cpu && !perfConfig?.cpu.includes("ALL") && perfConfig?.cpu.length > 0) { + recordArgs = recordArgs + " -c " + perfConfig?.cpu; + } + if (perfConfig?.cpuPercent != 0) { + recordArgs = recordArgs + " --cpu-limit " + perfConfig?.cpuPercent; + } + if (perfConfig?.eventList && !perfConfig?.eventList.includes("NONE") && perfConfig?.eventList.length > 0) { + recordArgs = recordArgs + " -e " + perfConfig?.eventList; + } + if (perfConfig?.callStack != "none") { + recordArgs = recordArgs + " --call-stack " + perfConfig?.callStack + } + + if (perfConfig?.branch != "none") { + recordArgs = recordArgs + " -j " + perfConfig?.branch + } + + if (perfConfig?.clockType) { + recordArgs = recordArgs + " --clockid " + perfConfig?.clockType + } + + if (perfConfig?.isOffCpu) { + recordArgs = recordArgs + " --offcpu" + } + + if (perfConfig?.noInherit) { + recordArgs = recordArgs + " --no-inherit" + } + + if (perfConfig?.mmap) { + recordArgs = recordArgs + " -m " + perfConfig.mmap; + } + + let hiPerf: HiperfPluginConfig = { + isRoot: false, + outfileName: "/data/local/tmp/perf.data", + recordArgs: recordArgs + } + let hiPerfPluginConfig: ProfilerPluginConfig = { + pluginName: "hiperf-plugin", + sampleInterval: reportingFrequency * 1000, + configData: hiPerf, + } + return hiPerfPluginConfig; + } + private createNativePluginConfig(spAllocations: SpAllocations, reportingFrequency: number) { let appProcess = spAllocations.appProcess; let re = /^[0-9]+.?[0-9]*/; @@ -495,7 +625,7 @@ export class SpRecordTrace extends BaseElement { return nativePluginConfig; } - private createMemoryPluginConfig(probesConfig: SpProbesConfig, that: this, reportingFrequency: number) { + private createMemoryPluginConfig(probesConfig: SpProbesConfig, reportingFrequency: number, hasMonitorMemory: boolean) { let memoryconfig: MemoryConfig = { reportProcessTree: true, reportSysmemMemInfo: true, @@ -507,8 +637,16 @@ export class SpRecordTrace extends BaseElement { reportAppMemByMemoryService: false, pid: [] } + if (hasMonitorMemory) { + SpRecordTrace.ABALITY_MEM_INFO.forEach(va => { + memoryconfig.sysMeminfoCounters.push(sysMeminfoTypeFromJSON(va)); + }) + } probesConfig.memoryConfig.forEach(value => { if (value.indexOf("Kernel meminfo") != -1) { + if (hasMonitorMemory) { + memoryconfig.sysMeminfoCounters = []; + } SpRecordTrace.MEM_INFO.forEach(va => { memoryconfig.sysMeminfoCounters.push(sysMeminfoTypeFromJSON(va)); }) diff --git a/host/ide/src/trace/component/SpRecyclerSystemTrace.ts b/host/ide/src/trace/component/SpRecyclerSystemTrace.ts index a0a4ed179770527b4804ca2c8c72391e4c2839af..5dba6737201e03d0392682bc82dbdda5bc79cfd7 100644 --- a/host/ide/src/trace/component/SpRecyclerSystemTrace.ts +++ b/host/ide/src/trace/component/SpRecyclerSystemTrace.ts @@ -765,40 +765,43 @@ export class SpRecyclerSystemTrace extends BaseElement { initHtml(): string { return ` - -
- - - -
+ +
+ + + + + + +
`; } diff --git a/host/ide/src/trace/component/SpSystemTrace.ts b/host/ide/src/trace/component/SpSystemTrace.ts index 9b8d6294092fddb4e9e23a9cfb71a2e1758d0437..5f63dc40ec8a09d83a0daad502d6207ee483a721 100644 --- a/host/ide/src/trace/component/SpSystemTrace.ts +++ b/host/ide/src/trace/component/SpSystemTrace.ts @@ -20,28 +20,47 @@ import { getAsyncEvents, getCpuUtilizationRate, getFps, - getFunDataByTid, + getFunDataByTid, getSliceData, getSliceDataCount, getStatesProcessThreadData, - getStatesProcessThreadDataCount, + getStatesProcessThreadDataCount, getThreadProcessData, getThreadStateData, getThreadStateDataCount, + queryAbilityExits, + queryBytesInAbilityData, + queryBytesOutAbilityData, + queryBytesReadAbilityData, + queryBytesWrittenAbilityData, + queryCachedFilesAbilityData, + queryCompressedAbilityData, + queryCpuAbilityData, + queryCPuAbilityMaxData, + queryCpuAbilitySystemData, + queryCpuAbilityUserData, queryCpuData, queryCpuFreq, queryCpuFreqData, queryCpuMax, queryCpuMaxFreq, + queryDiskIoMaxData, queryHeapAllTable, queryHeapByEventType, - queryHeapByPid, queryHeapFrameCount, queryHeapGroupByEvent, queryHeapPid, + queryMemoryMaxData, + queryMemoryUsedAbilityData, queryNativeHookProcess, + queryNetWorkMaxData, + queryPacketsInAbilityData, + queryPacketsOutAbilityData, queryProcess, queryProcessData, queryProcessMem, queryProcessMemData, queryProcessThreads, + queryReadAbilityData, queryThreadData, queryTotalTime, + queryWrittenAbilityData, + querySearchFunc, threadPool } from "../database/SqlLite.js"; import {TraceRow} from "./trace/base/TraceRow.js"; @@ -62,11 +81,19 @@ import {HeapStruct} from "../bean/HeapStruct.js"; import {procedurePool} from "../database/Procedure.js"; import {Utils} from "./trace/base/Utils.js"; import {SpApplication} from "../SpApplication.js"; -import {SPT} from "../bean/StateProcessThread.js"; +import {SPT, SptSlice, ThreadProcess, ThreadState} from "../bean/StateProcessThread.js"; import {HeapTreeDataBean} from "../bean/HeapTreeDataBean.js"; import {Flag} from "./trace/timer-shaft/Flag.js"; import {SportRuler} from "./trace/timer-shaft/SportRuler.js"; import {NativeEventHeap} from "../bean/NativeHook.js"; +import {CpuAbilityMonitorStruct} from "../bean/CpuAbilityMonitorStruct.js"; +import {MemoryAbilityMonitorStruct} from "../bean/MemoryAbilityMonitorStruct.js"; +import {DiskAbilityMonitorStruct} from "../bean/DiskAbilityMonitorStruct.js"; +import {NetworkAbilityMonitorStruct} from "../bean/NetworkAbilityMonitorStruct.js"; +import {SpHiPerf} from "./hiperf/SpHiPerf.js"; +import {perfDataQuery} from "./hiperf/PerfDataQuery.js"; +import {SearchThreadProcessBean} from "../bean/SearchFuncBean.js"; +import {info} from "../../log/Log.js"; @element('sp-system-trace') export class SpSystemTrace extends BaseElement { @@ -97,6 +124,8 @@ export class SpSystemTrace extends BaseElement { private processThreads: Array = [] private processAsyncEvent: Array = [] private processMem: Array = [] + private expansionProcessIDS:Array = []; + private spHiPerf: SpHiPerf | undefined | null; initElements(): void { this.rowsEL = this.shadowRoot?.querySelector('.rows'); @@ -106,7 +135,8 @@ export class SpSystemTrace extends BaseElement { this.rangeSelect = new RangeSelect(this.timerShaftEL); this.rangeSelect.rowsEL = this.rowsEL; document?.addEventListener("triangle-flag", (event: any) => { - this.timerShaftEL?.drawTriangle(event.detail.time, event.detail.type); + let temporaryTime = this.timerShaftEL?.drawTriangle(event.detail.time, event.detail.type); + if (event.detail.timeCallback && temporaryTime) event.detail.timeCallback(temporaryTime); }) document?.addEventListener("flag-change", (event: any) => { @@ -162,7 +192,7 @@ export class SpSystemTrace extends BaseElement { th.checkType = "2" selection.nativeMemory.push(th.rowId!); }) - }else if (it.rowType == TraceRow.ROW_TYPE_THREAD) { + } else if (it.rowType == TraceRow.ROW_TYPE_THREAD) { selection.threadIds.push(parseInt(it.rowId!)) } else if (it.rowType == TraceRow.ROW_TYPE_FUNC) { selection.funTids.push(parseInt(it.rowId!)) @@ -176,6 +206,44 @@ export class SpSystemTrace extends BaseElement { } else { selection.heapIds.push(parseInt(it.rowId!)) } + } else if (it.rowType == TraceRow.ROW_TYPE_CPU_ABILITY) { + selection.cpuAbilityIds.push(it.rowId!) + } else if (it.rowType == TraceRow.ROW_TYPE_MEMORY_ABILITY) { + selection.memoryAbilityIds.push(it.rowId!) + } else if (it.rowType == TraceRow.ROW_TYPE_DISK_ABILITY) { + selection.diskAbilityIds.push(it.rowId!) + } else if (it.rowType == TraceRow.ROW_TYPE_NETWORK_ABILITY) { + selection.networkAbilityIds.push(it.rowId!) + } else if (it.rowType?.startsWith("hiperf")) { + it.dataList?.forEach((item) => { + if (item.startNS > (TraceRow.rangeSelectObject?.endNS || 0) || item.startNS < (TraceRow.rangeSelectObject?.startNS || 0)) { + return + } + if (perfDataQuery.threadData[item.thread_id] == undefined) { + return + } + if (selection.perfSampleIds.indexOf(item.sample_id) == -1) { + selection.perfSampleIds.push(item.sample_id) + } + }) + if (it.rowType == TraceRow.ROW_TYPE_HIPERF_PROCESS) { + this.rowsEL?.querySelectorAll>(`trace-row[row-parent-id='${it.rowId}']`).forEach(th => { + th.rangeSelect = true; + th.checkType = "2" + }) + } + if (it.rowType == TraceRow.ROW_TYPE_HIPERF || it.rowId == "HiPerf-cpu-merge") { + selection.perfAll = true; + } + if (it.rowType == TraceRow.ROW_TYPE_HIPERF_CPU) { + selection.perfCpus.push(it.index); + } + if (it.rowType == TraceRow.ROW_TYPE_HIPERF_PROCESS) { + selection.perfProcess.push(parseInt(it.rowId!.split("-")[0])); + } + if (it.rowType == TraceRow.ROW_TYPE_HIPERF_THREAD) { + selection.perfThread.push(parseInt(it.rowId!.split("-")[0])); + } } }) selection.leftNs = TraceRow.rangeSelectObject?.startNS || 0; @@ -199,6 +267,7 @@ export class SpSystemTrace extends BaseElement { this.timerShaftEL?.removeTriangle("triangle") } }).observe(this.rowsEL!); + this.spHiPerf = new SpHiPerf(this); } getScrollWidth() { @@ -264,22 +333,34 @@ export class SpSystemTrace extends BaseElement { } documentOnMouseDown = (ev: MouseEvent) => { + TraceRow.isUserInteraction = true; if (this.isMouseInSheet(ev)) return; this.observerScrollHeightEnable = false; if (ev.offsetX > this.timerShaftEL!.canvas!.offsetLeft) { - this.rangeSelect.mouseDown(ev) - this.timerShaftEL?.documentOnMouseDown(ev) - this.visibleRows.forEach(it => { - it.draw(); - }) + let x = ev.offsetX - this.timerShaftEL!.canvas!.offsetLeft; + let y = ev.offsetY; + this.timerShaftEL?.documentOnMouseDown(ev); + if (this.timerShaftEL!.sportRuler!.frame.contains(x, y) && x > (TraceRow.rangeSelectObject?.startX || 0) && x < (TraceRow.rangeSelectObject?.endX || 0)) { + let time = TraceRow.range?.totalNS! * x / this.timerShaftEL!.canvas!.offsetWidth; + this.timerShaftEL!.sportRuler!.drawTriangle(time, "triangle") + } else { + this.rangeSelect.mouseDown(ev) + } + this.visibleRows.forEach(it => it.draw()); } } documentOnMouseUp = (ev: MouseEvent) => { + TraceRow.isUserInteraction = false; this.rangeSelect.isMouseDown = false; if (this.isMouseInSheet(ev)) return; + let x = ev.offsetX - this.timerShaftEL!.canvas!.offsetLeft; + let y = ev.offsetY; + if (this.timerShaftEL!.sportRuler!.frame.contains(x, y) && x > (TraceRow.rangeSelectObject?.startX || 0) && x < (TraceRow.rangeSelectObject?.endX || 0)) { + } else { this.rangeSelect.mouseUp(ev); this.timerShaftEL?.documentOnMouseUp(ev) + } } documentOnMouseOut = (ev: MouseEvent) => { @@ -290,6 +371,18 @@ export class SpSystemTrace extends BaseElement { } documentOnKeyPress = (ev: KeyboardEvent) => { + TraceRow.isUserInteraction = true; + if (ev.key.toLocaleLowerCase() == "m") { + if (CpuStruct.selectCpuStruct) { + this.timerShaftEL?.setSlicesMark((CpuStruct.selectCpuStruct.startTime || 0), (CpuStruct.selectCpuStruct.startTime || 0) + (CpuStruct.selectCpuStruct.dur || 0)); + } else if (ThreadStruct.selectThreadStruct) { + this.timerShaftEL?.setSlicesMark((ThreadStruct.selectThreadStruct.startTime || 0), (ThreadStruct.selectThreadStruct.startTime || 0) + (ThreadStruct.selectThreadStruct.dur || 0)); + } else if (FuncStruct.selectFuncStruct) { + this.timerShaftEL?.setSlicesMark((FuncStruct.selectFuncStruct.startTs || 0), (FuncStruct.selectFuncStruct.startTs || 0) + (FuncStruct.selectFuncStruct.dur || 0)); + } else { + this.timerShaftEL?.setSlicesMark(); + } + } if (this.isMousePointInSheet) { return; } @@ -298,6 +391,7 @@ export class SpSystemTrace extends BaseElement { } documentOnKeyUp = (ev: KeyboardEvent) => { + TraceRow.isUserInteraction = false; if (this.isMousePointInSheet) { return; } @@ -306,11 +400,13 @@ export class SpSystemTrace extends BaseElement { if (ev.code == "Enter") { if (ev.shiftKey) { this.dispatchEvent(new CustomEvent("previous-data", { - detail: {} + detail: {}, + composed:false })); } else { this.dispatchEvent(new CustomEvent("next-data", { - detail: {} + detail: {}, + composed:false })); } } @@ -322,6 +418,7 @@ export class SpSystemTrace extends BaseElement { } favoriteChangeHandler = (row: TraceRow) => { + info("favoriteChangeHandler", row.frame, row.offsetTop, row.offsetHeight); this.getVisibleRows(); } @@ -331,7 +428,10 @@ export class SpSystemTrace extends BaseElement { } documentOnMouseMove = (ev: MouseEvent) => { - if (this.isMouseInSheet(ev)) return; + if (this.isMouseInSheet(ev)) { + this.hoverStructNull(); + return; + } let rows = this.visibleRows; if (this.timerShaftEL?.isScaling()) { return; @@ -363,6 +463,7 @@ export class SpSystemTrace extends BaseElement { } else if (tr.rowType === TraceRow.ROW_TYPE_CPU_FREQ) { this.currentRowType = TraceRow.ROW_TYPE_CPU_FREQ; if (CpuFreqStruct.hoverCpuFreqStruct) { + CpuStruct.hoverCpuStruct = undefined; tr.tip = `${ColorUtils.formatNumberComma(CpuFreqStruct.hoverCpuFreqStruct.value!)} kHz` } tr.setTipLeft(x, CpuFreqStruct.hoverCpuFreqStruct) @@ -380,6 +481,75 @@ export class SpSystemTrace extends BaseElement { } } tr.setTipLeft(x, HeapStruct.hoverHeapStruct) + } else if (tr.rowType === TraceRow.ROW_TYPE_CPU_ABILITY) { + this.currentRowType = TraceRow.ROW_TYPE_CPU_ABILITY; + if (!SpSystemTrace.isCanvasOffScreen) CpuAbilityMonitorStruct.hoverCpuAbilityStruct = tr.onMouseHover(x, y); + if (CpuAbilityMonitorStruct.hoverCpuAbilityStruct) { + let monitorCpuTip = (CpuAbilityMonitorStruct.hoverCpuAbilityStruct.value!).toFixed(2) + "%" + tr.tip = `${monitorCpuTip}` + } + tr.setTipLeft(x, CpuAbilityMonitorStruct.hoverCpuAbilityStruct) + } else if (tr.rowType === TraceRow.ROW_TYPE_MEMORY_ABILITY) { + this.currentRowType = TraceRow.ROW_TYPE_MEMORY_ABILITY; + if (!SpSystemTrace.isCanvasOffScreen) MemoryAbilityMonitorStruct.hoverMemoryAbilityStruct = tr.onMouseHover(x, y); + if (MemoryAbilityMonitorStruct.hoverMemoryAbilityStruct) { + tr.tip = `${Utils.getBinaryByteWithUnit(MemoryAbilityMonitorStruct.hoverMemoryAbilityStruct.value!)}` + } + tr.setTipLeft(x, MemoryAbilityMonitorStruct.hoverMemoryAbilityStruct) + } else if (tr.rowType === TraceRow.ROW_TYPE_DISK_ABILITY) { + this.currentRowType = TraceRow.ROW_TYPE_DISK_ABILITY; + if (!SpSystemTrace.isCanvasOffScreen) DiskAbilityMonitorStruct.hoverDiskAbilityStruct = tr.onMouseHover(x, y); + if (DiskAbilityMonitorStruct.hoverDiskAbilityStruct) { + tr.tip = `${DiskAbilityMonitorStruct.hoverDiskAbilityStruct.value!} KB/S` + } + tr.setTipLeft(x, DiskAbilityMonitorStruct.hoverDiskAbilityStruct) + } else if (tr.rowType === TraceRow.ROW_TYPE_NETWORK_ABILITY) { + this.currentRowType = TraceRow.ROW_TYPE_NETWORK_ABILITY; + if (!SpSystemTrace.isCanvasOffScreen) NetworkAbilityMonitorStruct.hoverNetworkAbilityStruct = tr.onMouseHover(x, y); + if (NetworkAbilityMonitorStruct.hoverNetworkAbilityStruct) { + tr.tip = `${Utils.getBinaryByteWithUnit(NetworkAbilityMonitorStruct.hoverNetworkAbilityStruct.value!)}` + } + tr.setTipLeft(x, NetworkAbilityMonitorStruct.hoverNetworkAbilityStruct) + } else if (tr.rowType === TraceRow.ROW_TYPE_HIPERF_CPU) { + this.currentRowType = TraceRow.ROW_TYPE_HIPERF_CPU; + if (SpHiPerf.hoverCpuStruct) { + let num = Math.trunc((SpHiPerf.hoverCpuStruct.height || 0) / 40 * 100); + if (num > 0) { + if (tr.rowId == "HiPerf-cpu-merge") { + tr.tip = `${num * (this.spHiPerf!.maxCpuId + 1)}% (10.00ms)` + } else { + tr.tip = `${num}% (10.00ms)` + } + } else { + let datum = perfDataQuery.callChainData[`${SpHiPerf.hoverCpuStruct.sample_id}`] || []; + tr.tip = `${datum.length > 2 ? datum[datum.length - 3].name : ''} (${datum.length} other frames)` + } + } + tr.setTipLeft(x, SpHiPerf.hoverCpuStruct) + } else if (tr.rowType === TraceRow.ROW_TYPE_HIPERF_PROCESS) { + this.currentRowType = TraceRow.ROW_TYPE_HIPERF_PROCESS; + if (SpHiPerf.hoverProcessStruct) { + let num = Math.trunc((SpHiPerf.hoverProcessStruct.height || 0) / 40 * 100); + if (num > 0) { + tr.tip = `${num}% (10.00ms)` + } else { + let datum = perfDataQuery.callChainData[`${SpHiPerf.hoverProcessStruct.sample_id}`] || []; + tr.tip = `${datum.length > 2 ? datum[datum.length - 3].name : ''} (${datum.length} other frames)` + } + } + tr.setTipLeft(x, SpHiPerf.hoverProcessStruct) + } else if (tr.rowType === TraceRow.ROW_TYPE_HIPERF_THREAD) { + this.currentRowType = TraceRow.ROW_TYPE_HIPERF_THREAD; + if (SpHiPerf.hoverThreadStruct) { + let num = Math.trunc((SpHiPerf.hoverThreadStruct.height || 0) / 40 * 100); + if (num > 0) { + tr.tip = `${num}% (10.00ms)` + } else { + let datum = perfDataQuery.callChainData[`${SpHiPerf.hoverThreadStruct.sample_id}`] || []; + tr.tip = `${datum.length > 2 ? datum[datum.length - 3].name : ''} (${datum.length} other frames)` + } + } + tr.setTipLeft(x, SpHiPerf.hoverThreadStruct) } else { this.hoverStructNull(); } @@ -413,6 +583,7 @@ export class SpSystemTrace extends BaseElement { CpuFreqStruct.hoverCpuFreqStruct = undefined; ThreadStruct.hoverThreadStruct = undefined; FuncStruct.hoverFuncStruct = undefined; + SpHiPerf.hoverCpuStruct = undefined; } selectStructNull() { @@ -421,6 +592,7 @@ export class SpSystemTrace extends BaseElement { CpuFreqStruct.selectCpuFreqStruct = undefined; ThreadStruct.selectThreadStruct = undefined; FuncStruct.selectFuncStruct = undefined; + SpHiPerf.selectCpuStruct = undefined; } documentOnClick = (ev: MouseEvent) => { @@ -428,11 +600,16 @@ export class SpSystemTrace extends BaseElement { if (this.rangeSelect.isDrag()) { return; } - this.onClickHandler(); - this.documentOnMouseMove(ev) + let x = ev.offsetX - this.timerShaftEL!.canvas!.offsetLeft; + let y = ev.offsetY; + if (this.timerShaftEL!.sportRuler!.frame.contains(x, y) && x > (TraceRow.rangeSelectObject?.startX || 0) && x < (TraceRow.rangeSelectObject?.endX || 0)) { + } else { + this.onClickHandler(); + this.documentOnMouseMove(ev) + } } - onClickHandler(){ + onClickHandler() { this.rowsEL?.querySelectorAll>("trace-row").forEach(it => it.rangeSelect = false) this.selectStructNull(); let threadClickHandler: any; @@ -446,50 +623,72 @@ export class SpSystemTrace extends BaseElement { } let cpuRow = this.rowsEL?.querySelectorAll>(`trace-row[row-id='${d.cpu}'][row-type='cpu']`)[0]; let findEntry = cpuRow!.dataList!.find(it => it.startTime === d.startTime); + if (findEntry!.startTime! + findEntry!.dur! < TraceRow.range!.startNS || findEntry!.startTime! > TraceRow.range!.endNS) { + this.timerShaftEL?.setRangeNS(findEntry!.startTime! - findEntry!.dur! * 2, findEntry!.startTime! + findEntry!.dur! + findEntry!.dur! * 2); + } this.hoverStructNull(); this.selectStructNull(); CpuStruct.hoverCpuStruct = findEntry; CpuStruct.selectCpuStruct = findEntry; + this.timerShaftEL?.drawTriangle(findEntry!.startTime || 0, "inverted"); cpuRow!.draw(); this.traceSheetEL?.displayCpuData(CpuStruct.selectCpuStruct!, (wakeUpBean) => { CpuStruct.wakeupBean = wakeUpBean; this.visibleRows.forEach(it => it.draw()); }, cpuClickHandler); } - let scrollTimer: any; + cpuClickHandler = (d: CpuStruct) => { + this.expansionProcessIDS.forEach(it =>{ + this.shadowRoot!.querySelectorAll>(`trace-row[row-id='${it}'][row-type='process'][folder]`).forEach(it => it.expansion = false); + }) + this.expansionProcessIDS.length = 0; this.observerScrollHeightEnable = true; let threadRow = this.rowsEL?.querySelectorAll>(`trace-row[row-id='${d.tid}'][row-type='thread']`)[0]; - this.goProcess(`${d.tid}`, `${d.processId}`, "thread", true) this.observerScrollHeightCallback = () => { + info("scroll height changed", this.rowsEL?.scrollHeight); if (threadRow!.isComplete) { let findEntry = threadRow!.dataList!.find((dat) => dat.startTime === d.startTime); + if (findEntry!.startTime! + findEntry!.dur! < TraceRow.range!.startNS || findEntry!.startTime! > TraceRow.range!.endNS) { + this.timerShaftEL?.setRangeNS(findEntry!.startTime! - findEntry!.dur! * 2, findEntry!.startTime! + findEntry!.dur! + findEntry!.dur! * 2); + } this.hoverStructNull(); this.selectStructNull(); ThreadStruct.hoverThreadStruct = findEntry; ThreadStruct.selectThreadStruct = findEntry; + this.timerShaftEL?.drawTriangle(findEntry!.startTime || 0, "inverted"); threadRow!.draw(); - this.traceSheetEL?.displayThreadData(ThreadStruct.selectThreadStruct!, threadClickHandler); - // clearTimeout(scrollTimer); + this.traceSheetEL?.displayThreadData(ThreadStruct.selectThreadStruct!, threadClickHandler, cpuClickHandler); + if(d.processId){ + this.expansionProcessIDS.push(d.processId); + } this.goProcess(`${d.tid}`, `${d.processId}`, "thread", true) } else { threadRow!.onComplete = () => { let findEntry = threadRow!.dataList!.find((dat) => dat.startTime === d.startTime); + if (findEntry!.startTime! + findEntry!.dur! < TraceRow.range!.startNS || findEntry!.startTime! > TraceRow.range!.endNS) { + this.timerShaftEL?.setRangeNS(findEntry!.startTime! - findEntry!.dur! * 2, findEntry!.startTime! + findEntry!.dur! + findEntry!.dur! * 2); + } this.hoverStructNull(); this.selectStructNull(); ThreadStruct.hoverThreadStruct = findEntry; ThreadStruct.selectThreadStruct = findEntry; + this.timerShaftEL?.drawTriangle(findEntry!.startTime || 0, "inverted"); threadRow!.draw(); - this.traceSheetEL?.displayThreadData(ThreadStruct.selectThreadStruct!, threadClickHandler); - clearTimeout(scrollTimer); - scrollTimer = setTimeout(() => this.goProcess(`${d.tid}`, `${d.processId}`, "thread", false), 100) + this.traceSheetEL?.displayThreadData(ThreadStruct.selectThreadStruct!, threadClickHandler, cpuClickHandler); + if(d.processId){ + this.expansionProcessIDS.push(d.processId); + } + this.goProcess(`${d.tid}`, `${d.processId}`, "thread", false); } } } + this.goProcess(`${d.tid}`, `${d.processId}`, "thread", true); } if (CpuStruct.hoverCpuStruct) { CpuStruct.selectCpuStruct = CpuStruct.hoverCpuStruct + this.timerShaftEL?.drawTriangle(CpuStruct.selectCpuStruct!.startTime || 0, "inverted"); this.traceSheetEL?.displayCpuData(CpuStruct.selectCpuStruct, (wakeUpBean) => { CpuStruct.wakeupBean = wakeUpBean; this.visibleRows.forEach(it => it.draw()); @@ -497,15 +696,18 @@ export class SpSystemTrace extends BaseElement { this.timerShaftEL?.modifyFlagList(undefined); } else if (ThreadStruct.hoverThreadStruct) { ThreadStruct.selectThreadStruct = ThreadStruct.hoverThreadStruct; - this.traceSheetEL?.displayThreadData(ThreadStruct.selectThreadStruct, threadClickHandler); + this.timerShaftEL?.drawTriangle(ThreadStruct.selectThreadStruct!.startTime || 0, "inverted"); + this.traceSheetEL?.displayThreadData(ThreadStruct.selectThreadStruct, threadClickHandler, cpuClickHandler); this.timerShaftEL?.modifyFlagList(undefined); } else if (FuncStruct.hoverFuncStruct) { FuncStruct.selectFuncStruct = FuncStruct.hoverFuncStruct; + this.timerShaftEL?.drawTriangle(FuncStruct.selectFuncStruct!.startTs || 0, "inverted"); this.traceSheetEL?.displayFuncData(FuncStruct.hoverFuncStruct) this.timerShaftEL?.modifyFlagList(undefined); } else { this.observerScrollHeightEnable = false; this.selectFlag = null; + this.timerShaftEL?.removeTriangle("inverted"); if (!SportRuler.isMouseInSportRuler) { this.traceSheetEL?.setAttribute("mode", 'hidden'); this.getVisibleRows().forEach(it => it.draw(true)); @@ -556,6 +758,34 @@ export class SpSystemTrace extends BaseElement { }) } + goFunction(rowId: string, rowParentId: string, rowType: string, smooth: boolean = true, afterScroll: any) { + let row = this.shadowRoot!.querySelector>(`trace-row[row-id='${rowParentId}'][folder]`); + if (row) { + row.expansion = true + } + let funcRow = this.shadowRoot!.querySelector>(`trace-row[row-id='${rowId}'][row-type='${rowType}']`); + if (funcRow == null) { + let threadRow = this.shadowRoot!.querySelector>(`trace-row[row-id='${rowId}'][row-type='thread']`); + this.rowsEL!.scroll({ + top: threadRow!.offsetTop - this.rowsEL!.offsetTop - this.rowsEL!.offsetHeight + threadRow!.offsetHeight + threadRow!.offsetHeight, + left: 0, + behavior: smooth ? "smooth" : undefined + }) + if(threadRow!=null){ + if(threadRow.isComplete){ + afterScroll() + }else{ + threadRow.onComplete = ()=>{ + funcRow = this.shadowRoot!.querySelector>(`trace-row[row-id='${rowId}'][row-type='${rowType}']`); + afterScroll() + } + } + } + } else { + afterScroll() + } + } + rowScrollTo(offset: number, callback: Function) { const fixedOffset = offset; const onScroll = () => { @@ -586,6 +816,7 @@ export class SpSystemTrace extends BaseElement { } loadDatabaseUrl(url: string, progress: Function, complete?: ((res: { status: boolean, msg: string }) => void) | undefined) { + this.observerScrollHeightEnable = false; this.init({url: url}, progress).then((res) => { if (complete) { complete(res); @@ -594,6 +825,7 @@ export class SpSystemTrace extends BaseElement { } loadDatabaseArrayBuffer(buf: ArrayBuffer, progress: ((name: string, percent: number) => void), complete?: ((res: { status: boolean, msg: string }) => void) | undefined) { + this.observerScrollHeightEnable = false; this.init({buf}, progress).then((res) => { let scrollTop = this.rowsEL?.scrollTop || 0 let scrollHeight = this.rowsEL?.clientHeight || 0 @@ -613,7 +845,11 @@ export class SpSystemTrace extends BaseElement { item.rowType == TraceRow.ROW_TYPE_CPU_FREQ || item.rowType == TraceRow.ROW_TYPE_NATIVE_MEMORY || item.rowType == TraceRow.ROW_TYPE_FPS || - item.rowType == TraceRow.ROW_TYPE_PROCESS) { + item.rowType == TraceRow.ROW_TYPE_PROCESS || + item.rowType == TraceRow.ROW_TYPE_CPU_ABILITY || + item.rowType == TraceRow.ROW_TYPE_MEMORY_ABILITY || + item.rowType == TraceRow.ROW_TYPE_DISK_ABILITY || + item.rowType == TraceRow.ROW_TYPE_NETWORK_ABILITY) { item.expansion = false; item.rowHidden = false; } else { @@ -643,6 +879,163 @@ export class SpSystemTrace extends BaseElement { return searchResults; } + async searchFunction(cpuList: Array, query: string): Promise> { + let list = await querySearchFunc(query) + cpuList = cpuList.concat(list) + cpuList.sort((a, b) => (a.startTime || 0) - (b.startTime || 0)); + return cpuList + } + + searchThreadsAndProcesses(query: string): Array { + let searchResults: Array = [] + this.rowsEL!.querySelectorAll>(`trace-row[row-type='thread'][row-type='process']`).forEach(item => { + if (item!.name.search(query) >= 0) { + let searchBean = new SearchThreadProcessBean() + searchBean.name = item.name + searchBean.rowId = item.rowId + searchBean.type = "thread||process" + searchBean.rowType = item.rowType + searchBean.rowParentId = item.rowParentId + searchResults.push(searchBean) + } + }) + return searchResults + } + + showStruct(previous: boolean, currentIndex: number, structs: Array) { + if (structs.length == 0) { + return 0; + } + let findIndex = -1; + if (previous) { + for (let i = structs.length - 1; i >= 0; i--) { + let it = structs[i]; + if (i < currentIndex && (it.startTime!) >= (TraceRow.range!.startNS) && (it.startTime!) + (it.dur!) <= (TraceRow.range!.endNS)) { + findIndex = i; + break; + } + } + } else { + findIndex = structs.findIndex((it, idx) => { + return idx > currentIndex && (it.startTime!) >= (TraceRow.range!.startNS) && (it.startTime!) + (it.dur!) <= (TraceRow.range!.endNS) + }) + } + let findEntry: any + if (findIndex >= 0) { + findEntry = structs[findIndex]; + } else { + if (previous) { + for (let i = structs.length - 1; i >= 0; i--) { + let it = structs[i]; + if ((it.startTime! + it.dur!) < (TraceRow.range!.startNS)) { + findIndex = i; + break; + } + } + if (findIndex == -1) { + findIndex = structs.length - 1; + } + } else { + findIndex = structs.findIndex((it) => (it.startTime!) > (TraceRow.range!.endNS)) + if (findIndex == -1) { + findIndex = 0; + } + } + findEntry = structs[findIndex]; + this.moveRangeToCenter(findEntry.startTime!, findEntry.dur!) + } + this.rowsEL!.querySelectorAll>(`trace-row`).forEach(item => { + item.highlight = false; + if (!item.sleeping) { + item.draw(true) + } + }) + if (findEntry.type == 'thread') { + CpuStruct.selectCpuStruct = findEntry; + CpuStruct.hoverCpuStruct = CpuStruct.selectCpuStruct; + this.rowsEL!.querySelectorAll>(`trace-row[row-type='cpu']`).forEach(item => { + item.highlight = item.rowId == `${findEntry.cpu}`; + item.draw(true) + }) + this.goProcess(`${findEntry.cpu}`, "", "cpu", true) + this.onClickHandler(); + } else if (findEntry.type == "func") { + this.observerScrollHeightEnable = true; + this.goFunction(`${findEntry.tid}`, `${findEntry.pid}`, findEntry.type, true, () => { + let funcRow = this.rowsEL?.querySelector>(`trace-row[row-id='${findEntry.tid}'][row-type='func']`); + if (funcRow == null)return + this.goProcess(`${findEntry.tid}`, `${findEntry.pid}`, "func", true) + funcRow!.highlight = true + let completeEntry = () => { + if (funcRow == null) return + let searchEntry = funcRow!.dataList!.find((dat) => dat.startTs === findEntry.startTime); + this.hoverStructNull(); + this.selectStructNull(); + FuncStruct.hoverFuncStruct = searchEntry; + FuncStruct.selectFuncStruct = searchEntry; + this.visibleRows.forEach(it => it.draw()); + } + let scrollTimer: any; + this.observerScrollHeightCallback = () => { + funcRow = this.rowsEL?.querySelector>(`trace-row[row-id='${findEntry.tid}'][row-type='func']`); + if(funcRow == null){return} + if (funcRow!.isComplete) { + completeEntry() + this.onClickHandler(); + this.goProcess(`${findEntry.tid}`, `${findEntry.pid}`, "func", false) + } else { + funcRow!.onComplete = () => { + completeEntry() + this.onClickHandler(); + clearTimeout(scrollTimer); + scrollTimer = setTimeout(() => this.goProcess(`${findEntry.tid}`, `${findEntry.pid}`, "func", false), 100) + } + } + } + if (funcRow?.isComplete) { + completeEntry() + this.onClickHandler(); + this.goProcess(`${findEntry.tid}`, `${findEntry.pid}`, "func", true) + } + }); + } else if (findEntry.type == "thread||process") { + let threadProcessRow = this.rowsEL?.querySelectorAll>(`trace-row[row-id='${findEntry.rowId}'][row-type='${findEntry.rowType}']`)[0]; + threadProcessRow!.highlight = true + this.goProcess(`${findEntry.rowId}`, `${findEntry.rowParentId}`, findEntry.rowType, true); + let completeEntry = () => { + let searchEntry = threadProcessRow!.dataList!.find((dat) => dat.startTime === findEntry.startTime); + this.hoverStructNull(); + this.selectStructNull(); + + ThreadStruct.hoverThreadStruct = searchEntry; + ThreadStruct.selectThreadStruct = searchEntry; + threadProcessRow!.draw(); + } + let scrollTimer: any; + this.observerScrollHeightCallback = () => { + if (threadProcessRow!.isComplete) { + completeEntry() + this.goProcess(`${findEntry.rowId}`, `${findEntry.rowParentId}`, findEntry.rowType, true) + } else { + threadProcessRow!.onComplete = () => { + completeEntry() + clearTimeout(scrollTimer); + scrollTimer = setTimeout(() => this.goProcess(`${findEntry.rowId}`, `${findEntry.rowParentId}`, findEntry.rowType, false), 100) + } + } + } + } + this.timerShaftEL?.drawTriangle(findEntry.startTime || 0, "inverted"); + return findIndex; + } + + moveRangeToCenter(startTime: number, dur: number) { + let startNS = this.timerShaftEL?.getRange()?.startNS || 0; + let endNS = this.timerShaftEL?.getRange()?.endNS || 0; + let harfDur = Math.trunc((endNS - startNS) / 2 - dur / 2); + this.timerShaftEL?.setRangeNS(startTime - harfDur, startTime + dur + harfDur); + } + showPreCpuStruct(currentIndex: number, cpuStructs: Array): number { if (cpuStructs.length == 0) { return 0; @@ -658,11 +1051,11 @@ export class SpSystemTrace extends BaseElement { if (findIndex >= 0) { let findEntry = cpuStructs[findIndex]; CpuStruct.selectCpuStruct = findEntry; - this.rowsEL!.querySelectorAll>(`trace-row[row-type='cpu']`).forEach(item =>{ + this.rowsEL!.querySelectorAll>(`trace-row[row-type='cpu']`).forEach(item => { item.highlight = item.rowId == `${findEntry.cpu}`; item.draw(true); }) - this.timerShaftEL?.drawTriangle(findEntry.startTime||0, "inverted"); + this.timerShaftEL?.drawTriangle(findEntry.startTime || 0, "inverted"); } else { for (let i = cpuStructs.length - 1; i >= 0; i--) { let it = cpuStructs[i]; @@ -685,7 +1078,7 @@ export class SpSystemTrace extends BaseElement { item.highlight = item.rowId == `${findEntry.cpu}`; item.draw(true) }) - this.timerShaftEL?.drawTriangle(findEntry.startTime||0, "inverted"); + this.timerShaftEL?.drawTriangle(findEntry.startTime || 0, "inverted"); } CpuStruct.hoverCpuStruct = CpuStruct.selectCpuStruct; this.onClickHandler(); @@ -702,11 +1095,11 @@ export class SpSystemTrace extends BaseElement { if (findIndex >= 0) { let findEntry = cpuStructs[findIndex]; CpuStruct.selectCpuStruct = findEntry; - this.rowsEL!.querySelectorAll>(`trace-row[row-type='cpu']`).forEach(item =>{ + this.rowsEL!.querySelectorAll>(`trace-row[row-type='cpu']`).forEach(item => { item.highlight = item.rowId == `${findEntry.cpu}`; item.draw(true); }) - this.timerShaftEL?.drawTriangle(findEntry.startTime||0, "inverted"); + this.timerShaftEL?.drawTriangle(findEntry.startTime || 0, "inverted"); } else { findIndex = cpuStructs.findIndex((it) => (it.startTime!) > (TraceRow.range!.endNS)) let findEntry: CpuStruct; @@ -723,7 +1116,7 @@ export class SpSystemTrace extends BaseElement { item.highlight = item.rowId == `${findEntry.cpu}`; item.draw(true); }) - this.timerShaftEL?.drawTriangle(findEntry.startTime||0, "inverted"); + this.timerShaftEL?.drawTriangle(findEntry.startTime || 0, "inverted"); } CpuStruct.hoverCpuStruct = CpuStruct.selectCpuStruct; this.onClickHandler(); @@ -778,10 +1171,15 @@ export class SpSystemTrace extends BaseElement { await this.initFPS(); progress("native memory", 87); await this.initNativeMemory(); + progress("ability monitor", 88); + await this.initAbilityMonitor(); + await perfDataQuery.initPerfFiles() + await this.spHiPerf!.init(); progress("process", 90); await this.initProcess(); progress("process", 93); - await this.initProcessThreadStateData(progress); + // await this.initProcessThreadStateData(progress); + await this.initProcessThreadStateData2(progress); await this.initHeapStateData(progress) progress("display", 95); this.getVisibleRows().forEach(it => { @@ -832,11 +1230,20 @@ export class SpSystemTrace extends BaseElement { traceRow.name = `Cpu ${cpuId}` traceRow.favoriteChangeHandler = this.favoriteChangeHandler; traceRow.selectChangeHandler = this.selectChangeHandler; - traceRow.supplier = () => queryCpuData(cpuId, 0, this.timerShaftEL?.totalNS || 0) - traceRow.onThreadHandler = ((useCache: boolean) => { + traceRow.supplier = () => queryCpuData(cpuId, TraceRow.range?.startNS || 0, TraceRow.range?.endNS || 0) + traceRow.onThreadHandler = ((useCache: boolean, buf: ArrayBuffer | undefined | null) => { + let transfer = []; + if (!traceRow.isTransferCanvas) { + transfer.push(traceRow.offscreen[0]); + } + if (buf) { + transfer.push(buf); + } procedurePool.submitWithName(`cpu${cpuId % procedurePool.cpusLen.length}`, `cpu${cpuId}`, { + online: traceRow.online, + buf: buf, list: traceRow.must ? traceRow.dataList : undefined, - offscreen: traceRow.must ? traceRow.offscreen[0] : undefined,//是否离屏 + offscreen: !traceRow.isTransferCanvas ? traceRow.offscreen[0] : undefined,//是否离屏 dpr: traceRow.dpr,//屏幕dpr值 xs: TraceRow.range?.xs,//线条坐标信息 isHover: traceRow.isHover, @@ -856,17 +1263,16 @@ export class SpSystemTrace extends BaseElement { startNS: TraceRow.range?.startNS || 0, endNS: TraceRow.range?.endNS || 0, totalNS: TraceRow.range?.totalNS || 0, + slicesTime:TraceRow.range?.slicesTime, frame: traceRow.frame - }, traceRow.must && traceRow.args.isOffScreen ? traceRow.offscreen[0] : undefined, (res: any, hover: any) => { + }, transfer, (res: any, hover: any) => { traceRow.must = false; - if (traceRow.args.isOffScreen == true) { if (traceRow.isHover) { CpuStruct.hoverCpuStruct = hover; this.visibleRows.filter(it => it.rowType === TraceRow.ROW_TYPE_CPU && it.name !== traceRow.name).forEach(it => it.draw(true)); } - return; - } }) + traceRow.isTransferCanvas = true; }) this.rowsEL?.appendChild(traceRow) } @@ -911,7 +1317,7 @@ export class SpSystemTrace extends BaseElement { traceRow.onThreadHandler = (useCache) => { procedurePool.submitWithName(`freq${it.cpu % procedurePool.freqLen.length}`, `freq${it.cpu}`, { list: traceRow.must ? traceRow.dataList : undefined, - offscreen: traceRow.must ? traceRow.offscreen[0] : undefined, + offscreen: !traceRow.isTransferCanvas ? traceRow.offscreen[0] : undefined, xs: TraceRow.range?.xs, dpr: traceRow.dpr, isHover: traceRow.isHover, @@ -933,8 +1339,9 @@ export class SpSystemTrace extends BaseElement { startNS: TraceRow.range?.startNS || 0, endNS: TraceRow.range?.endNS || 0, totalNS: TraceRow.range?.totalNS || 0, + slicesTime:TraceRow.range?.slicesTime, frame: traceRow.frame - }, traceRow.must && traceRow.args.isOffScreen ? traceRow.offscreen[0] : undefined, (res: any, hover: any) => { + }, !traceRow.isTransferCanvas ? traceRow.offscreen[0] : undefined, (res: any, hover: any) => { traceRow.must = false; if (traceRow.args.isOffScreen == true) { if (traceRow.isHover) { @@ -944,7 +1351,7 @@ export class SpSystemTrace extends BaseElement { return; } }) - + traceRow.isTransferCanvas = true; } this.rowsEL?.appendChild(traceRow) } @@ -964,7 +1371,7 @@ export class SpSystemTrace extends BaseElement { fpsRow.onThreadHandler = (useCache) => { procedurePool.submitWithName(`process0`, `fps0`, { list: fpsRow.must ? fpsRow.dataList : undefined, - offscreen: fpsRow.must ? fpsRow.offscreen[0] : undefined, + offscreen: !fpsRow.isTransferCanvas ? fpsRow.offscreen[0] : undefined, xs: TraceRow.range?.xs, dpr: fpsRow.dpr, isHover: fpsRow.isHover, @@ -982,10 +1389,12 @@ export class SpSystemTrace extends BaseElement { startNS: TraceRow.range?.startNS || 0, endNS: TraceRow.range?.endNS || 0, totalNS: TraceRow.range?.totalNS || 0, + slicesTime:TraceRow.range?.slicesTime, frame: fpsRow.frame - }, fpsRow.must && fpsRow.args.isOffScreen ? fpsRow.offscreen[0] : undefined, (res: any, hover: any) => { + }, !fpsRow.isTransferCanvas ? fpsRow.offscreen[0] : undefined, (res: any, hover: any) => { fpsRow.must = false; - }) + }); + fpsRow.isTransferCanvas = true; } this.rowsEL?.appendChild(fpsRow) } @@ -1026,7 +1435,7 @@ export class SpSystemTrace extends BaseElement { nativeRow.onThreadHandler = (useCache) => { procedurePool.submitWithName(`process${nativeRow.index}`, `native-memory`, { list: nativeRow.must ? nativeRow.dataList : undefined, - offscreen: nativeRow.must ? nativeRow.offscreen[0] : undefined, + offscreen: !nativeRow.isTransferCanvas ? nativeRow.offscreen[0] : undefined, xs: TraceRow.range?.xs, dpr: nativeRow.dpr, isHover: nativeRow.isHover, @@ -1043,10 +1452,12 @@ export class SpSystemTrace extends BaseElement { startNS: TraceRow.range?.startNS || 0, endNS: TraceRow.range?.endNS || 0, totalNS: TraceRow.range?.totalNS || 0, + slicesTime:TraceRow.range?.slicesTime, frame: nativeRow.frame - }, nativeRow.must && nativeRow.args.isOffScreen ? nativeRow.offscreen[0] : undefined, (res: any) => { + }, !nativeRow.isTransferCanvas ? nativeRow.offscreen[0] : undefined, (res: any) => { nativeRow.must = false; - }) + }); + nativeRow.isTransferCanvas = true; } this.rowsEL?.appendChild(nativeRow) @@ -1157,14 +1568,15 @@ export class SpSystemTrace extends BaseElement { startNS: TraceRow.range?.startNS || 0, endNS: TraceRow.range?.endNS || 0, totalNS: TraceRow.range?.totalNS || 0, + slicesTime:TraceRow.range?.slicesTime, frame: allHeapRow.frame }, !allHeapRow.isTransferCanvas ? allHeapRow.offscreen[0] : undefined, (res: any, hover: any) => { allHeapRow.must = false; - allHeapRow.isTransferCanvas = true; if (allHeapRow.isHover) { HeapStruct.hoverHeapStruct = hover; } - }) + }); + allHeapRow.isTransferCanvas = true; } this.rowsEL?.appendChild(allHeapRow) } @@ -1184,6 +1596,63 @@ export class SpSystemTrace extends BaseElement { } } + initProcessThreadStateData2 = async (progress: Function) => { + SpSystemTrace.SPT_DATA = []; + let pageSize = 500000; + let percent = 93; + let threadStateRes = await getThreadStateDataCount(); + let count: number = (threadStateRes[0] as any).count; + let pages = Math.ceil(count / pageSize); + let arrTs :Array = []; + let ps = 0; + for (let i = 0; i < pages; i++) { + ps += 1; + progress("StateProcessThread", percent + (ps / 100)); + let arr = await getThreadStateData(pageSize, i * pageSize); + arrTs = arrTs.concat(arr); + } + ps += 1; + progress("StateProcessThread", percent + (ps / 100)); + let arrTp:Array = await getThreadProcessData(); + let mapTp:Map = new Map(); + for (let tp of arrTp) { + mapTp.set(tp.id,tp); + } + let threadSliceRes = await getSliceDataCount(); + let sliceCount: number = (threadSliceRes[0] as any).count; + let slicePages = Math.ceil(sliceCount / pageSize); + let arrSlice :Array = []; + for (let i = 0; i < slicePages; i++) { + ps += 1; + progress("StateProcessThread", percent + (ps / 100)); + let arr = await getSliceData(pageSize, i * pageSize); + arrSlice = arrSlice.concat(arr); + } + let mapSlice:Map = new Map(); + for (let slice of arrSlice) { + mapSlice.set(`${slice.itid}-${slice.ts}`,slice); + } + for (let tr of arrTs) { + if(mapTp.has(tr.itid)){ + let tp = mapTp.get(tr.itid); + let spt = new SPT(); + spt.processId = tp!.processId + spt.process = tp!.process + spt.thread = tp!.thread + spt.threadId = tp!.threadId + spt.state = tr.state; + spt.dur= tr.dur; + spt.end_ts = tr.end_ts; + spt.start_ts = tr.start_ts; + spt.cpu = tr.cpu; + let slice = mapSlice.get(`${tr.itid}-${tr.ts}`); + spt.priority = (slice != undefined && slice != null) ? slice!.priority.toString() : ""; + spt.note = "-"; + SpSystemTrace.SPT_DATA.push(spt); + } + } + } + initHeapStateData = async (progress: Function) => { SpSystemTrace.HEAP_FRAME_DATA = []; let res = await queryHeapFrameCount(); @@ -1229,7 +1698,7 @@ export class SpSystemTrace extends BaseElement { processRow.onThreadHandler = (useCache) => { procedurePool.submitWithName(`process${(processRow.index) % procedurePool.processLen.length}`, `process ${processRow.index} ${it.processName}`, { list: processRow.must ? processRow.dataList : undefined, - offscreen: processRow.must ? processRow.offscreen[0] : undefined, + offscreen: !processRow.isTransferCanvas ? processRow.offscreen[0] : undefined, xs: TraceRow.range?.xs, dpr: processRow.dpr, isHover: processRow.isHover, @@ -1248,10 +1717,12 @@ export class SpSystemTrace extends BaseElement { startNS: TraceRow.range?.startNS || 0, endNS: TraceRow.range?.endNS || 0, totalNS: TraceRow.range?.totalNS || 0, + slicesTime:TraceRow.range?.slicesTime, frame: processRow.frame - }, processRow.must && processRow.args.isOffScreen ? processRow.offscreen[0] : undefined, (res: any) => { + }, !processRow.isTransferCanvas ? processRow.offscreen[0] : undefined, (res: any) => { processRow.must = false; }) + processRow.isTransferCanvas = true; } this.rowsEL?.appendChild(processRow) /** @@ -1295,7 +1766,7 @@ export class SpSystemTrace extends BaseElement { row.onThreadHandler = (useCache) => { procedurePool.submitWithName(`cpu${mem.trackId % procedurePool.cpusLen.length}`, `mem ${mem.trackId} ${mem.trackName}`, { list: row.must ? row.dataList : undefined, - offscreen: row.must ? row.offscreen[0] : undefined,//是否离屏 + offscreen: !row.isTransferCanvas ? row.offscreen[0] : undefined,//是否离屏 dpr: row.dpr,//屏幕dpr值 xs: TraceRow.range?.xs,//线条坐标信息 isHover: row.isHover, @@ -1313,10 +1784,12 @@ export class SpSystemTrace extends BaseElement { startNS: TraceRow.range?.startNS || 0, endNS: TraceRow.range?.endNS || 0, totalNS: TraceRow.range?.totalNS || 0, + slicesTime:TraceRow.range?.slicesTime, frame: row.frame - }, row.must && row.args.isOffScreen ? row.offscreen[0] : undefined, (res: any) => { + }, !row.isTransferCanvas ? row.offscreen[0] : undefined, (res: any) => { row.must = false; - }) + }); + row.isTransferCanvas = true; } this.rowsEL?.appendChild(row) }); @@ -1379,7 +1852,7 @@ export class SpSystemTrace extends BaseElement { for (let k = 0; k < groupedBy.length; k++) { procedurePool.submitWithName(`cpu${k % procedurePool.cpusLen.length}`, `func${thread.tid}${k}${thread.threadName}`, { list: funcRow.must ? groupedBy[k] : undefined, - offscreen: funcRow.must ? funcRow.offscreen[k] : undefined,//是否离屏 + offscreen: !funcRow.isTransferCanvas ? funcRow.offscreen[k] : undefined,//是否离屏 dpr: funcRow.dpr,//屏幕dpr值 xs: TraceRow.range?.xs,//线条坐标信息 isHover: funcRow.isHover, @@ -1401,8 +1874,9 @@ export class SpSystemTrace extends BaseElement { startNS: TraceRow.range?.startNS || 0, endNS: TraceRow.range?.endNS || 0, totalNS: TraceRow.range?.totalNS || 0, + slicesTime:TraceRow.range?.slicesTime, frame: funcRow.frame - }, funcRow.must && funcRow.args.isOffScreen ? funcRow.offscreen[k] : undefined, (res: any, hover: any) => { + }, !funcRow.isTransferCanvas ? funcRow.offscreen[k] : undefined, (res: any, hover: any) => { funcRow.must = false; if (funcRow.args.isOffScreen == true) { if (funcRow.isHover && hover) { @@ -1413,10 +1887,14 @@ export class SpSystemTrace extends BaseElement { } }) } + funcRow.isTransferCanvas = true; } this.insertAfter(funcRow, threadRow) this.observer.observe(funcRow) funcRow.draw(); + if(threadRow.onComplete){ + threadRow.onComplete() + } this.getVisibleRows();//function 由于后插入dom,所以需要重新获取可见行 } }) @@ -1425,7 +1903,7 @@ export class SpSystemTrace extends BaseElement { threadRow.onThreadHandler = (useCache) => { procedurePool.submitWithName(`process${(threadRow.index) % procedurePool.processLen.length}`, `thread ${thread.tid} ${thread.threadName}`, { list: threadRow.must ? threadRow.dataList : undefined, - offscreen: threadRow.must ? threadRow.offscreen[0] : undefined,//是否离屏 + offscreen: !threadRow.isTransferCanvas ? threadRow.offscreen[0] : undefined,//是否离屏 dpr: threadRow.dpr,//屏幕dpr值 xs: TraceRow.range?.xs,//线条坐标信息 isHover: threadRow.isHover, @@ -1445,8 +1923,9 @@ export class SpSystemTrace extends BaseElement { startNS: TraceRow.range?.startNS || 0, endNS: TraceRow.range?.endNS || 0, totalNS: TraceRow.range?.totalNS || 0, + slicesTime:TraceRow.range?.slicesTime, frame: threadRow.frame - }, threadRow.must && threadRow.args.isOffScreen ? threadRow.offscreen[0] : undefined, (res: any, hover: any) => { + }, !threadRow.isTransferCanvas ? threadRow.offscreen[0] : undefined, (res: any, hover: any) => { threadRow.must = false; if (threadRow.args.isOffScreen == true) { if (threadRow.isHover) { @@ -1456,9 +1935,11 @@ export class SpSystemTrace extends BaseElement { return; } }) + threadRow.isTransferCanvas = true; } this.rowsEL?.appendChild(threadRow) - }; + } + } } @@ -1471,47 +1952,1033 @@ export class SpSystemTrace extends BaseElement { } } + initAbilityMonitor = async () => { + let result = await queryAbilityExits(); + if (result.length <= 0) return; + let processRow = this.initAbilityRow(); + if (this.hasTable(result, "trace_cpu_usage")) { + await this.initCpuAbility(processRow); + } + if (this.hasTable(result, "sys_memory")) { + await this.initMemoryAbility(processRow); + } + if (this.hasTable(result, "trace_diskio")) { + await this.initDiskAbility(processRow); + } + if (this.hasTable(result, "trace_network")) { + await this.initNetworkAbility(processRow); + } + } + + memoryMath = (maxByte: number) => { + let maxByteName = "" + if (maxByte > 0) { + maxByteName = Utils.getBinaryByteWithUnit(maxByte) + } + return maxByteName; + } + + diskIOMath = (maxByte: number) => { + let maxByteName = "" + if (maxByte > 0) { + maxByteName = maxByte + "KB/S" + } + return maxByteName; + } + + networkMath = (maxValue: number) => { + let maxByteName = "" + if (maxValue > 0) { + maxByteName = Utils.getBinaryByteWithUnit(maxValue) + } + return maxByteName; + } + initHtml(): string { return ` - -
- -
-
- -
+ +
+ + +
+
+ + +
`; } + + private hasTable(result: Array, tableName: string) { + return result.find((o) => { + return o.event_name === tableName + }) + } + + private initAbilityRow = () => { + let processRow = new TraceRow({ + canvasNumber: 1, + alpha: false, + contextId: '2d', + isOffScreen: SpSystemTrace.isCanvasOffScreen + }); + processRow.rowId = `abilityMonitor` + processRow.rowType = TraceRow.ROW_TYPE_MONITOR + processRow.rowParentId = ''; + processRow.folder = true; + processRow.name = 'Ability Monitor'; + processRow.favoriteChangeHandler = this.favoriteChangeHandler; + processRow.selectChangeHandler = this.selectChangeHandler; + processRow.supplier = () => new Promise>((resolve) => resolve([])); + processRow.onThreadHandler = (useCache) => { + procedurePool.submitWithName(`ability0`, `monitorGroup`, { + list: processRow.must ? processRow.dataList : undefined, + offscreen: processRow.must ? processRow.offscreen[0] : undefined, + xs: TraceRow.range?.xs, + dpr: processRow.dpr, + isHover: processRow.isHover, + hoverX: processRow.hoverX, + hoverY: processRow.hoverY, + flagMoveInfo: this.hoverFlag, + flagSelectedInfo: this.selectFlag, + canvasWidth: processRow.canvasWidth, + canvasHeight: processRow.canvasHeight, + isRangeSelect: processRow.rangeSelect, + rangeSelectObject: TraceRow.rangeSelectObject, + useCache: useCache, + lineColor: processRow.getLineColor(), + startNS: TraceRow.range?.startNS || 0, + endNS: TraceRow.range?.endNS || 0, + totalNS: TraceRow.range?.totalNS || 0, + slicesTime:TraceRow.range?.slicesTime, + frame: processRow.frame, + }, processRow.must && processRow.args.isOffScreen ? processRow.offscreen[0] : undefined, (res: any, hover: any) => { + processRow.must = false; + } + ) + } + this.rowsEL?.appendChild(processRow) + return processRow; + } + + private initCpuAbility = async (processRow: TraceRow) => { + let cpuMaxData = await queryCPuAbilityMaxData(); + let hasTotal = false; + let hasUserLoad = false; + let hasSystemLoad = false; + let userLoad = cpuMaxData[0].userLoad; + if (userLoad > 0) { + hasUserLoad = true; + } + let systemLoad = cpuMaxData[0].systemLoad; + if (systemLoad > 0) { + hasSystemLoad = true; + } + let totalLoad = cpuMaxData[0].totalLoad; + if (totalLoad > 0) { + hasTotal = true; + } + let cpuNameList: Array = ['Total', 'User', 'System'] + let traceRow = new TraceRow({ + canvasNumber: 1, + alpha: false, + contextId: '2d', + isOffScreen: SpSystemTrace.isCanvasOffScreen + }); + traceRow.rowParentId = `abilityMonitor` + traceRow.rowHidden = !processRow.expansion + traceRow.rowId = cpuNameList[0] + traceRow.rowType = TraceRow.ROW_TYPE_CPU_ABILITY + traceRow.favoriteChangeHandler = this.favoriteChangeHandler; + traceRow.selectChangeHandler = this.selectChangeHandler; + traceRow.style.height = '40px' + traceRow.style.width = `100%`; + traceRow.setAttribute('children', ''); + traceRow.name = `CPU ${cpuNameList[0]} Load`; + traceRow.supplier = () => queryCpuAbilityData() + traceRow.onThreadHandler = (useCache) => { + procedurePool.submitWithName(`ability0`, `monitorCpu0`, { + list: traceRow.must ? traceRow.dataList : undefined, + offscreen: traceRow.must ? traceRow.offscreen[0] : undefined, + xs: TraceRow.range?.xs, + dpr: traceRow.dpr, + isHover: traceRow.isHover, + hoverX: traceRow.hoverX, + hoverY: traceRow.hoverY, + flagMoveInfo: this.hoverFlag, + flagSelectedInfo: this.selectFlag, + canvasWidth: traceRow.canvasWidth, + canvasHeight: traceRow.canvasHeight, + hoverCpuAbilityStruct: CpuAbilityMonitorStruct.hoverCpuAbilityStruct, + selectCpuAbilityStruct: CpuAbilityMonitorStruct.selectCpuAbilityStruct, + isRangeSelect: traceRow.rangeSelect, + rangeSelectObject: TraceRow.rangeSelectObject, + maxCpuUtilization: 100, + maxCpuUtilizationName: hasTotal ? "100%" : '0%', + useCache: useCache, + lineColor: traceRow.getLineColor(), + startNS: TraceRow.range?.startNS || 0, + endNS: TraceRow.range?.endNS || 0, + totalNS: TraceRow.range?.totalNS || 0, + slicesTime:TraceRow.range?.slicesTime, + frame: traceRow.frame, + }, traceRow.must && traceRow.args.isOffScreen ? traceRow.offscreen[0] : undefined, (res: any, hover: any) => { + traceRow.must = false; + if (traceRow.args.isOffScreen == true) { + if (traceRow.isHover) { + CpuAbilityMonitorStruct.hoverCpuAbilityStruct = hover; + this.visibleRows.filter(it => it.rowType === TraceRow.ROW_TYPE_CPU_ABILITY && it.name !== traceRow.name).forEach(it => it.draw(true)); + } + return; + } + } + ) + } + this.rowsEL?.appendChild(traceRow) + + let userTraceRow = new TraceRow({ + canvasNumber: 1, + alpha: false, + contextId: '2d', + isOffScreen: SpSystemTrace.isCanvasOffScreen + }); + userTraceRow.rowParentId = `abilityMonitor` + userTraceRow.rowHidden = !processRow.expansion + userTraceRow.rowId = cpuNameList[1] + userTraceRow.rowType = TraceRow.ROW_TYPE_CPU_ABILITY + userTraceRow.style.height = '40px' + userTraceRow.style.width = `100%`; + userTraceRow.favoriteChangeHandler = this.favoriteChangeHandler; + userTraceRow.selectChangeHandler = this.selectChangeHandler; + userTraceRow.setAttribute('children', ''); + userTraceRow.name = `CPU ${cpuNameList[1]} Load`; + userTraceRow.supplier = () => queryCpuAbilityUserData() + userTraceRow.onThreadHandler = (useCache) => { + procedurePool.submitWithName(`ability1`, `monitorCpu1`, { + list: userTraceRow.must ? userTraceRow.dataList : undefined, + offscreen: userTraceRow.must ? userTraceRow.offscreen[0] : undefined, + xs: TraceRow.range?.xs, + dpr: userTraceRow.dpr, + isHover: userTraceRow.isHover, + hoverX: userTraceRow.hoverX, + hoverY: userTraceRow.hoverY, + flagMoveInfo: this.hoverFlag, + flagSelectedInfo: this.selectFlag, + canvasWidth: userTraceRow.canvasWidth, + canvasHeight: userTraceRow.canvasHeight, + hoverCpuAbilityStruct: CpuAbilityMonitorStruct.hoverCpuAbilityStruct, + selectCpuAbilityStruct: CpuAbilityMonitorStruct.selectCpuAbilityStruct, + wakeupBean: CpuStruct.wakeupBean, + isRangeSelect: userTraceRow.rangeSelect, + rangeSelectObject: TraceRow.rangeSelectObject, + maxCpuUtilization: 100, + maxCpuUtilizationName: hasUserLoad ? "100%" : '0%', + useCache: useCache, + lineColor: userTraceRow.getLineColor(), + startNS: TraceRow.range?.startNS || 0, + endNS: TraceRow.range?.endNS || 0, + totalNS: TraceRow.range?.totalNS || 0, + slicesTime:TraceRow.range?.slicesTime, + frame: userTraceRow.frame, + isAbilityRow: true, + isStartAbilityRow: true, + isEndAbilityRow: false, + }, userTraceRow.must && userTraceRow.args.isOffScreen ? userTraceRow.offscreen[0] : undefined, (res: any, hover: any) => { + userTraceRow.must = false; + if (userTraceRow.args.isOffScreen == true) { + if (userTraceRow.isHover) { + CpuAbilityMonitorStruct.hoverCpuAbilityStruct = hover; + this.visibleRows.filter(it => it.rowType === TraceRow.ROW_TYPE_CPU_ABILITY && it.name !== userTraceRow.name).forEach(it => it.draw(true)); + } + if (userTraceRow.dataList) userTraceRow.dataList.length = 0; + return; + } + } + ) + } + this.rowsEL?.appendChild(userTraceRow) + + let sysTraceRow = new TraceRow({ + canvasNumber: 1, + alpha: false, + contextId: '2d', + isOffScreen: SpSystemTrace.isCanvasOffScreen + }); + sysTraceRow.rowParentId = `abilityMonitor` + sysTraceRow.rowHidden = !processRow.expansion + sysTraceRow.rowId = cpuNameList[2] + sysTraceRow.rowType = TraceRow.ROW_TYPE_CPU_ABILITY + sysTraceRow.style.height = '40px' + sysTraceRow.style.width = `100%`; + sysTraceRow.favoriteChangeHandler = this.favoriteChangeHandler; + sysTraceRow.selectChangeHandler = this.selectChangeHandler; + sysTraceRow.setAttribute('children', ''); + sysTraceRow.name = `CPU ${cpuNameList[2]} Load`; + sysTraceRow.supplier = () => queryCpuAbilitySystemData() + sysTraceRow.onThreadHandler = (useCache) => { + procedurePool.submitWithName(`ability2`, `monitorCpu2`, { + list: sysTraceRow.must ? sysTraceRow.dataList : undefined, + offscreen: sysTraceRow.must ? sysTraceRow.offscreen[0] : undefined, + xs: TraceRow.range?.xs, + dpr: sysTraceRow.dpr, + isHover: sysTraceRow.isHover, + hoverX: sysTraceRow.hoverX, + hoverY: sysTraceRow.hoverY, + flagMoveInfo: this.hoverFlag, + flagSelectedInfo: this.selectFlag, + canvasWidth: sysTraceRow.canvasWidth, + canvasHeight: sysTraceRow.canvasHeight, + hoverCpuAbilityStruct: CpuAbilityMonitorStruct.hoverCpuAbilityStruct, + selectCpuAbilityStruct: CpuAbilityMonitorStruct.selectCpuAbilityStruct, + wakeupBean: CpuStruct.wakeupBean, + isRangeSelect: sysTraceRow.rangeSelect, + rangeSelectObject: TraceRow.rangeSelectObject, + maxCpuUtilization: 100, + maxCpuUtilizationName: hasSystemLoad ? "100%" : '0%', + useCache: useCache, + lineColor: sysTraceRow.getLineColor(), + startNS: TraceRow.range?.startNS || 0, + endNS: TraceRow.range?.endNS || 0, + totalNS: TraceRow.range?.totalNS || 0, + slicesTime:TraceRow.range?.slicesTime, + frame: sysTraceRow.frame, + isAbilityRow: true, + isStartAbilityRow: true, + isEndAbilityRow: false, + }, sysTraceRow.must && sysTraceRow.args.isOffScreen ? sysTraceRow.offscreen[0] : undefined, (res: any, hover: any) => { + sysTraceRow.must = false; + if (sysTraceRow.args.isOffScreen == true) { + if (sysTraceRow.isHover) { + CpuAbilityMonitorStruct.hoverCpuAbilityStruct = hover; + this.visibleRows.filter(it => it.rowType === TraceRow.ROW_TYPE_CPU_ABILITY && it.name !== sysTraceRow.name).forEach(it => it.draw(true)); + } + if (sysTraceRow.dataList) sysTraceRow.dataList.length = 0; + return; + } + } + ) + } + this.rowsEL?.appendChild(sysTraceRow) + } + + private initMemoryAbility = async (processRow: TraceRow) => { + // sys.mem.total sys.mem.cached sys.mem.swap.total + let memoryNameList: Array = ['MemoryTotal', 'Cached', 'SwapTotal'] + let memoryTotal = await queryMemoryMaxData("sys.mem.total"); + let memoryTotalValue = memoryTotal[0].maxValue + let memoryTotalId = memoryTotal[0].filter_id + + let memoryTotalValueName = this.memoryMath(memoryTotalValue); + let memoryUsedTraceRow = new TraceRow({ + canvasNumber: 1, + alpha: false, + contextId: '2d', + isOffScreen: SpSystemTrace.isCanvasOffScreen + }); + memoryUsedTraceRow.rowParentId = `abilityMonitor` + memoryUsedTraceRow.rowHidden = !processRow.expansion + memoryUsedTraceRow.rowId = memoryNameList[0] + memoryUsedTraceRow.rowType = TraceRow.ROW_TYPE_MEMORY_ABILITY + memoryUsedTraceRow.favoriteChangeHandler = this.favoriteChangeHandler; + memoryUsedTraceRow.selectChangeHandler = this.selectChangeHandler; + memoryUsedTraceRow.style.height = '40px' + memoryUsedTraceRow.style.width = `100%`; + memoryUsedTraceRow.setAttribute('children', ''); + memoryUsedTraceRow.name = memoryNameList[0]; + memoryUsedTraceRow.supplier = () => queryMemoryUsedAbilityData(memoryTotalId) + memoryUsedTraceRow.onThreadHandler = (useCache) => { + procedurePool.submitWithName(`ability0`, `monitorMemory0`, { + list: memoryUsedTraceRow.must ? memoryUsedTraceRow.dataList : undefined, + offscreen: memoryUsedTraceRow.must ? memoryUsedTraceRow.offscreen[0] : undefined, + xs: TraceRow.range?.xs, + dpr: memoryUsedTraceRow.dpr, + isHover: memoryUsedTraceRow.isHover, + hoverX: memoryUsedTraceRow.hoverX, + hoverY: memoryUsedTraceRow.hoverY, + flagMoveInfo: this.hoverFlag, + flagSelectedInfo: this.selectFlag, + canvasWidth: memoryUsedTraceRow.canvasWidth, + canvasHeight: memoryUsedTraceRow.canvasHeight, + hoverMemoryAbilityStruct: MemoryAbilityMonitorStruct.hoverMemoryAbilityStruct, + selectMemoryAbilityStruct: MemoryAbilityMonitorStruct.selectMemoryAbilityStruct, + isRangeSelect: memoryUsedTraceRow.rangeSelect, + rangeSelectObject: TraceRow.rangeSelectObject, + maxMemoryByte: memoryTotalValue, + maxMemoryByteName: memoryTotalValueName, + useCache: useCache, + lineColor: memoryUsedTraceRow.getLineColor(), + startNS: TraceRow.range?.startNS || 0, + endNS: TraceRow.range?.endNS || 0, + totalNS: TraceRow.range?.totalNS || 0, + slicesTime:TraceRow.range?.slicesTime, + frame: memoryUsedTraceRow.frame, + }, memoryUsedTraceRow.must && memoryUsedTraceRow.args.isOffScreen ? memoryUsedTraceRow.offscreen[0] : undefined, (res: any, hover: any) => { + memoryUsedTraceRow.must = false; + if (memoryUsedTraceRow.args.isOffScreen == true) { + if (memoryUsedTraceRow.isHover) { + MemoryAbilityMonitorStruct.hoverMemoryAbilityStruct = hover; + this.visibleRows.filter(it => it.rowType === TraceRow.ROW_TYPE_MEMORY_ABILITY && it.name !== memoryUsedTraceRow.name).forEach(it => it.draw(true)); + } + if (memoryUsedTraceRow.dataList) memoryUsedTraceRow.dataList.length = 0; + return; + } + } + ) + } + this.rowsEL?.appendChild(memoryUsedTraceRow) + + let cached = await queryMemoryMaxData("sys.mem.cached"); + let cachedValue = cached[0].maxValue + let cachedValueName = this.memoryMath(cachedValue); + let cachedId = cached[0].filter_id + + let cachedFilesTraceRow = new TraceRow({ + canvasNumber: 1, + alpha: false, + contextId: '2d', + isOffScreen: SpSystemTrace.isCanvasOffScreen + }); + cachedFilesTraceRow.rowParentId = `abilityMonitor` + cachedFilesTraceRow.rowHidden = !processRow.expansion + cachedFilesTraceRow.rowId = memoryNameList[1] + cachedFilesTraceRow.rowType = TraceRow.ROW_TYPE_MEMORY_ABILITY + cachedFilesTraceRow.favoriteChangeHandler = this.favoriteChangeHandler; + cachedFilesTraceRow.selectChangeHandler = this.selectChangeHandler; + cachedFilesTraceRow.style.height = '40px' + cachedFilesTraceRow.style.width = `100%`; + cachedFilesTraceRow.setAttribute('children', ''); + cachedFilesTraceRow.name = memoryNameList[1]; + cachedFilesTraceRow.supplier = () => queryCachedFilesAbilityData(cachedId) + cachedFilesTraceRow.onThreadHandler = (useCache) => { + procedurePool.submitWithName(`ability1`, `monitorMemory1`, { + list: cachedFilesTraceRow.must ? cachedFilesTraceRow.dataList : undefined, + offscreen: cachedFilesTraceRow.must ? cachedFilesTraceRow.offscreen[0] : undefined, + xs: TraceRow.range?.xs, + dpr: cachedFilesTraceRow.dpr, + isHover: cachedFilesTraceRow.isHover, + hoverX: cachedFilesTraceRow.hoverX, + hoverY: cachedFilesTraceRow.hoverY, + flagMoveInfo: this.hoverFlag, + flagSelectedInfo: this.selectFlag, + canvasWidth: cachedFilesTraceRow.canvasWidth, + canvasHeight: cachedFilesTraceRow.canvasHeight, + hoverMemoryAbilityStruct: MemoryAbilityMonitorStruct.hoverMemoryAbilityStruct, + selectMemoryAbilityStruct: MemoryAbilityMonitorStruct.selectMemoryAbilityStruct, + isRangeSelect: cachedFilesTraceRow.rangeSelect, + rangeSelectObject: TraceRow.rangeSelectObject, + maxMemoryByte: cachedValue, + maxMemoryByteName: cachedValueName, + useCache: useCache, + lineColor: cachedFilesTraceRow.getLineColor(), + startNS: TraceRow.range?.startNS || 0, + endNS: TraceRow.range?.endNS || 0, + totalNS: TraceRow.range?.totalNS || 0, + slicesTime:TraceRow.range?.slicesTime, + frame: cachedFilesTraceRow.frame, + }, cachedFilesTraceRow.must && cachedFilesTraceRow.args.isOffScreen ? cachedFilesTraceRow.offscreen[0] : undefined, (res: any, hover: any) => { + cachedFilesTraceRow.must = false; + if (cachedFilesTraceRow.args.isOffScreen == true) { + if (cachedFilesTraceRow.isHover) { + MemoryAbilityMonitorStruct.hoverMemoryAbilityStruct = hover; + this.visibleRows.filter(it => it.rowType === TraceRow.ROW_TYPE_MEMORY_ABILITY && it.name !== cachedFilesTraceRow.name).forEach(it => it.draw(true)); + } + if (cachedFilesTraceRow.dataList) cachedFilesTraceRow.dataList.length = 0; + return; + } + } + ) + } + this.rowsEL?.appendChild(cachedFilesTraceRow) + + + let swap = await queryMemoryMaxData("sys.mem.swap.total"); + let swapValue = swap[0].maxValue + let swapValueName = this.memoryMath(swapValue); + let swapId = swap[0].filter_id + + let compressedTraceRow = new TraceRow({ + canvasNumber: 1, + alpha: false, + contextId: '2d', + isOffScreen: SpSystemTrace.isCanvasOffScreen + }); + compressedTraceRow.rowParentId = `abilityMonitor` + compressedTraceRow.rowHidden = !processRow.expansion + compressedTraceRow.rowId = memoryNameList[2] + compressedTraceRow.rowType = TraceRow.ROW_TYPE_MEMORY_ABILITY + compressedTraceRow.favoriteChangeHandler = this.favoriteChangeHandler; + compressedTraceRow.selectChangeHandler = this.selectChangeHandler; + compressedTraceRow.style.height = '40px' + compressedTraceRow.style.width = `100%`; + compressedTraceRow.setAttribute('children', ''); + compressedTraceRow.name = memoryNameList[2]; + compressedTraceRow.supplier = () => queryCompressedAbilityData(swapId) + compressedTraceRow.onThreadHandler = (useCache) => { + procedurePool.submitWithName(`ability2`, `monitorMemory2`, { + list: compressedTraceRow.must ? compressedTraceRow.dataList : undefined, + offscreen: compressedTraceRow.must ? compressedTraceRow.offscreen[0] : undefined, + xs: TraceRow.range?.xs, + dpr: compressedTraceRow.dpr, + isHover: compressedTraceRow.isHover, + hoverX: compressedTraceRow.hoverX, + hoverY: compressedTraceRow.hoverY, + flagMoveInfo: this.hoverFlag, + flagSelectedInfo: this.selectFlag, + canvasWidth: compressedTraceRow.canvasWidth, + canvasHeight: compressedTraceRow.canvasHeight, + hoverMemoryAbilityStruct: MemoryAbilityMonitorStruct.hoverMemoryAbilityStruct, + selectMemoryAbilityStruct: MemoryAbilityMonitorStruct.selectMemoryAbilityStruct, + wakeupBean: CpuStruct.wakeupBean, + isRangeSelect: compressedTraceRow.rangeSelect, + rangeSelectObject: TraceRow.rangeSelectObject, + maxMemoryByte: swapValue, + maxMemoryByteName: swapValueName, + useCache: useCache, + lineColor: compressedTraceRow.getLineColor(), + startNS: TraceRow.range?.startNS || 0, + endNS: TraceRow.range?.endNS || 0, + totalNS: TraceRow.range?.totalNS || 0, + slicesTime:TraceRow.range?.slicesTime, + frame: compressedTraceRow.frame, + }, compressedTraceRow.must && compressedTraceRow.args.isOffScreen ? compressedTraceRow.offscreen[0] : undefined, (res: any, hover: any) => { + compressedTraceRow.must = false; + if (compressedTraceRow.args.isOffScreen == true) { + if (compressedTraceRow.isHover) { + MemoryAbilityMonitorStruct.hoverMemoryAbilityStruct = hover; + this.visibleRows.filter(it => it.rowType === TraceRow.ROW_TYPE_MEMORY_ABILITY && it.name !== compressedTraceRow.name).forEach(it => it.draw(true)); + } + if (compressedTraceRow.dataList) compressedTraceRow.dataList.length = 0; + return; + } + } + ) + } + this.rowsEL?.appendChild(compressedTraceRow) + } + + private initDiskAbility = async (processRow: TraceRow) => { + let maxList = await queryDiskIoMaxData(); + let maxBytesRead = maxList[0].bytesRead; + let maxBytesReadName = this.diskIOMath(maxBytesRead); + let diskIONameList: Array = ['Bytes Read/Sec', 'Bytes Written/Sec', 'Read Ops/Sec', 'Written Ops/Sec'] + let bytesReadTraceRow = new TraceRow({ + canvasNumber: 1, + alpha: false, + contextId: '2d', + isOffScreen: SpSystemTrace.isCanvasOffScreen + }); + bytesReadTraceRow.rowParentId = `abilityMonitor` + bytesReadTraceRow.rowHidden = !processRow.expansion + bytesReadTraceRow.rowId = diskIONameList[0] + bytesReadTraceRow.rowType = TraceRow.ROW_TYPE_DISK_ABILITY + bytesReadTraceRow.favoriteChangeHandler = this.favoriteChangeHandler; + bytesReadTraceRow.selectChangeHandler = this.selectChangeHandler; + bytesReadTraceRow.style.height = '40px' + bytesReadTraceRow.style.width = `100%`; + bytesReadTraceRow.setAttribute('children', ''); + bytesReadTraceRow.name = 'Disk ' + diskIONameList[0]; + bytesReadTraceRow.supplier = () => queryBytesReadAbilityData() + bytesReadTraceRow.onThreadHandler = (useCache) => { + procedurePool.submitWithName(`ability0`, `monitorDiskIo0`, { + list: bytesReadTraceRow.must ? bytesReadTraceRow.dataList : undefined, + offscreen: bytesReadTraceRow.must ? bytesReadTraceRow.offscreen[0] : undefined, + xs: TraceRow.range?.xs, + dpr: bytesReadTraceRow.dpr, + isHover: bytesReadTraceRow.isHover, + hoverX: bytesReadTraceRow.hoverX, + hoverY: bytesReadTraceRow.hoverY, + flagMoveInfo: this.hoverFlag, + flagSelectedInfo: this.selectFlag, + canvasWidth: bytesReadTraceRow.canvasWidth, + canvasHeight: bytesReadTraceRow.canvasHeight, + hoverDiskAbilityStruct: DiskAbilityMonitorStruct.hoverDiskAbilityStruct, + selectDiskAbilityStruct: DiskAbilityMonitorStruct.selectDiskAbilityStruct, + wakeupBean: CpuStruct.wakeupBean, + isRangeSelect: bytesReadTraceRow.rangeSelect, + rangeSelectObject: TraceRow.rangeSelectObject, + maxDiskRate: maxBytesRead, + maxDiskRateName: maxBytesReadName, + useCache: useCache, + lineColor: bytesReadTraceRow.getLineColor(), + startNS: TraceRow.range?.startNS || 0, + endNS: TraceRow.range?.endNS || 0, + totalNS: TraceRow.range?.totalNS || 0, + slicesTime:TraceRow.range?.slicesTime, + frame: bytesReadTraceRow.frame, + }, bytesReadTraceRow.must && bytesReadTraceRow.args.isOffScreen ? bytesReadTraceRow.offscreen[0] : undefined, (res: any, hover: any) => { + bytesReadTraceRow.must = false; + if (bytesReadTraceRow.args.isOffScreen == true) { + if (bytesReadTraceRow.isHover) { + DiskAbilityMonitorStruct.hoverDiskAbilityStruct = hover; + this.visibleRows.filter(it => it.rowType === TraceRow.ROW_TYPE_DISK_ABILITY && it.name !== bytesReadTraceRow.name).forEach(it => it.draw(true)); + } + if (bytesReadTraceRow.dataList) bytesReadTraceRow.dataList.length = 0; + return; + } + } + ) + } + this.rowsEL?.appendChild(bytesReadTraceRow) + + let maxBytesWrite = maxList[0].bytesWrite; + let maxBytesWriteName = this.diskIOMath(maxBytesWrite); + let bytesWrittenTraceRow = new TraceRow({ + canvasNumber: 1, + alpha: false, + contextId: '2d', + isOffScreen: SpSystemTrace.isCanvasOffScreen + }); + bytesWrittenTraceRow.rowParentId = `abilityMonitor` + bytesWrittenTraceRow.rowHidden = !processRow.expansion + bytesWrittenTraceRow.rowId = diskIONameList[1] + bytesWrittenTraceRow.rowType = TraceRow.ROW_TYPE_DISK_ABILITY + bytesWrittenTraceRow.favoriteChangeHandler = this.favoriteChangeHandler; + bytesWrittenTraceRow.selectChangeHandler = this.selectChangeHandler; + bytesWrittenTraceRow.style.height = '40px' + bytesWrittenTraceRow.style.width = `100%`; + bytesWrittenTraceRow.setAttribute('children', ''); + bytesWrittenTraceRow.name = 'Disk ' + diskIONameList[1]; + bytesWrittenTraceRow.supplier = () => queryBytesWrittenAbilityData() + bytesWrittenTraceRow.onThreadHandler = (useCache) => { + procedurePool.submitWithName(`ability1`, `monitorDiskIo1`, { + list: bytesWrittenTraceRow.must ? bytesWrittenTraceRow.dataList : undefined, + offscreen: bytesWrittenTraceRow.must ? bytesWrittenTraceRow.offscreen[0] : undefined, + xs: TraceRow.range?.xs, + dpr: bytesWrittenTraceRow.dpr, + isHover: bytesWrittenTraceRow.isHover, + hoverX: bytesWrittenTraceRow.hoverX, + hoverY: bytesWrittenTraceRow.hoverY, + flagMoveInfo: this.hoverFlag, + flagSelectedInfo: this.selectFlag, + canvasWidth: bytesWrittenTraceRow.canvasWidth, + canvasHeight: bytesWrittenTraceRow.canvasHeight, + hoverDiskAbilityStruct: DiskAbilityMonitorStruct.hoverDiskAbilityStruct, + selectDiskAbilityStruct: DiskAbilityMonitorStruct.selectDiskAbilityStruct, + wakeupBean: CpuStruct.wakeupBean, + isRangeSelect: bytesWrittenTraceRow.rangeSelect, + rangeSelectObject: TraceRow.rangeSelectObject, + maxDiskRate: maxBytesWrite, + maxDiskRateName: maxBytesWriteName, + useCache: useCache, + lineColor: bytesWrittenTraceRow.getLineColor(), + startNS: TraceRow.range?.startNS || 0, + endNS: TraceRow.range?.endNS || 0, + totalNS: TraceRow.range?.totalNS || 0, + slicesTime:TraceRow.range?.slicesTime, + frame: bytesWrittenTraceRow.frame, + }, bytesWrittenTraceRow.must && bytesWrittenTraceRow.args.isOffScreen ? bytesWrittenTraceRow.offscreen[0] : undefined, (res: any, hover: any) => { + bytesWrittenTraceRow.must = false; + if (bytesWrittenTraceRow.args.isOffScreen == true) { + if (bytesWrittenTraceRow.isHover) { + DiskAbilityMonitorStruct.hoverDiskAbilityStruct = hover; + this.visibleRows.filter(it => it.rowType === TraceRow.ROW_TYPE_DISK_ABILITY && it.name !== bytesWrittenTraceRow.name).forEach(it => it.draw(true)); + } + if (bytesWrittenTraceRow.dataList) bytesWrittenTraceRow.dataList.length = 0; + return; + } + } + ) + } + this.rowsEL?.appendChild(bytesWrittenTraceRow) + + + let maxReadOps = maxList[0].readOps; + let maxReadOpsName = this.diskIOMath(maxReadOps); + let readOpsTraceRow = new TraceRow({ + canvasNumber: 1, + alpha: false, + contextId: '2d', + isOffScreen: SpSystemTrace.isCanvasOffScreen + }); + readOpsTraceRow.rowParentId = `abilityMonitor` + readOpsTraceRow.rowHidden = !processRow.expansion + readOpsTraceRow.rowId = diskIONameList[2] + readOpsTraceRow.rowType = TraceRow.ROW_TYPE_DISK_ABILITY + readOpsTraceRow.favoriteChangeHandler = this.favoriteChangeHandler; + readOpsTraceRow.selectChangeHandler = this.selectChangeHandler; + readOpsTraceRow.style.height = '40px' + readOpsTraceRow.style.width = `100%`; + readOpsTraceRow.setAttribute('children', ''); + readOpsTraceRow.name = 'Disk ' + diskIONameList[2]; + readOpsTraceRow.supplier = () => queryReadAbilityData() + readOpsTraceRow.onThreadHandler = (useCache) => { + procedurePool.submitWithName(`ability2`, `monitorDiskIo2`, { + list: readOpsTraceRow.must ? readOpsTraceRow.dataList : undefined, + offscreen: readOpsTraceRow.must ? readOpsTraceRow.offscreen[0] : undefined, + xs: TraceRow.range?.xs, + dpr: readOpsTraceRow.dpr, + isHover: readOpsTraceRow.isHover, + hoverX: readOpsTraceRow.hoverX, + hoverY: readOpsTraceRow.hoverY, + flagMoveInfo: this.hoverFlag, + flagSelectedInfo: this.selectFlag, + canvasWidth: readOpsTraceRow.canvasWidth, + canvasHeight: readOpsTraceRow.canvasHeight, + hoverDiskAbilityStruct: DiskAbilityMonitorStruct.hoverDiskAbilityStruct, + selectDiskAbilityStruct: DiskAbilityMonitorStruct.selectDiskAbilityStruct, + wakeupBean: CpuStruct.wakeupBean, + isRangeSelect: readOpsTraceRow.rangeSelect, + rangeSelectObject: TraceRow.rangeSelectObject, + maxDiskRate: maxReadOps, + maxDiskRateName: maxReadOpsName, + useCache: useCache, + lineColor: readOpsTraceRow.getLineColor(), + startNS: TraceRow.range?.startNS || 0, + endNS: TraceRow.range?.endNS || 0, + totalNS: TraceRow.range?.totalNS || 0, + slicesTime:TraceRow.range?.slicesTime, + frame: readOpsTraceRow.frame, + }, readOpsTraceRow.must && readOpsTraceRow.args.isOffScreen ? readOpsTraceRow.offscreen[0] : undefined, (res: any, hover: any) => { + readOpsTraceRow.must = false; + if (readOpsTraceRow.args.isOffScreen == true) { + if (readOpsTraceRow.isHover) { + DiskAbilityMonitorStruct.hoverDiskAbilityStruct = hover; + this.visibleRows.filter(it => it.rowType === TraceRow.ROW_TYPE_DISK_ABILITY && it.name !== readOpsTraceRow.name).forEach(it => it.draw(true)); + } + if (readOpsTraceRow.dataList) readOpsTraceRow.dataList.length = 0; + return; + } + } + ) + } + this.rowsEL?.appendChild(readOpsTraceRow) + + let maxWriteOps = maxList[0].writeOps; + let maxWriteOpsName = this.diskIOMath(maxWriteOps); + let writtenOpsTraceRow = new TraceRow({ + canvasNumber: 1, + alpha: false, + contextId: '2d', + isOffScreen: SpSystemTrace.isCanvasOffScreen + }); + writtenOpsTraceRow.rowParentId = `abilityMonitor` + writtenOpsTraceRow.rowHidden = !processRow.expansion + writtenOpsTraceRow.rowId = diskIONameList[3] + writtenOpsTraceRow.rowType = TraceRow.ROW_TYPE_DISK_ABILITY + writtenOpsTraceRow.favoriteChangeHandler = this.favoriteChangeHandler; + writtenOpsTraceRow.selectChangeHandler = this.selectChangeHandler; + writtenOpsTraceRow.style.height = '40px' + writtenOpsTraceRow.style.width = `100%`; + writtenOpsTraceRow.setAttribute('children', ''); + writtenOpsTraceRow.name = 'Disk ' + diskIONameList[3]; + writtenOpsTraceRow.supplier = () => queryWrittenAbilityData() + writtenOpsTraceRow.onThreadHandler = (useCache) => { + procedurePool.submitWithName(`ability3`, `monitorDiskIo3`, { + list: writtenOpsTraceRow.must ? writtenOpsTraceRow.dataList : undefined, + offscreen: writtenOpsTraceRow.must ? writtenOpsTraceRow.offscreen[0] : undefined, + xs: TraceRow.range?.xs, + dpr: writtenOpsTraceRow.dpr, + isHover: writtenOpsTraceRow.isHover, + hoverX: writtenOpsTraceRow.hoverX, + hoverY: writtenOpsTraceRow.hoverY, + flagMoveInfo: this.hoverFlag, + flagSelectedInfo: this.selectFlag, + canvasWidth: writtenOpsTraceRow.canvasWidth, + canvasHeight: writtenOpsTraceRow.canvasHeight, + hoverDiskAbilityStruct: DiskAbilityMonitorStruct.hoverDiskAbilityStruct, + selectDiskAbilityStruct: DiskAbilityMonitorStruct.selectDiskAbilityStruct, + wakeupBean: CpuStruct.wakeupBean, + isRangeSelect: writtenOpsTraceRow.rangeSelect, + rangeSelectObject: TraceRow.rangeSelectObject, + maxDiskRate: maxWriteOps, + maxDiskRateName: maxWriteOpsName, + useCache: useCache, + lineColor: writtenOpsTraceRow.getLineColor(), + startNS: TraceRow.range?.startNS || 0, + endNS: TraceRow.range?.endNS || 0, + totalNS: TraceRow.range?.totalNS || 0, + slicesTime:TraceRow.range?.slicesTime, + frame: writtenOpsTraceRow.frame, + }, writtenOpsTraceRow.must && writtenOpsTraceRow.args.isOffScreen ? writtenOpsTraceRow.offscreen[0] : undefined, (res: any, hover: any) => { + writtenOpsTraceRow.must = false; + if (writtenOpsTraceRow.args.isOffScreen == true) { + if (writtenOpsTraceRow.isHover) { + DiskAbilityMonitorStruct.hoverDiskAbilityStruct = hover; + this.visibleRows.filter(it => it.rowType === TraceRow.ROW_TYPE_DISK_ABILITY && it.name !== writtenOpsTraceRow.name).forEach(it => it.draw(true)); + } + if (writtenOpsTraceRow.dataList) writtenOpsTraceRow.dataList.length = 0; + return; + } + } + ) + } + this.rowsEL?.appendChild(writtenOpsTraceRow) + } + + private initNetworkAbility = async (processRow: TraceRow) => { + let maxList = await queryNetWorkMaxData(); + let maxBytesIn = maxList[0].maxIn; + let maxInByteName = this.networkMath(maxBytesIn); + let networkNameList: Array = ['Bytes In/Sec', 'Bytes Out/Sec', 'Packets In/Sec', 'Packets Out/Sec'] + let bytesInTraceRow = new TraceRow({ + canvasNumber: 1, + alpha: false, + contextId: '2d', + isOffScreen: SpSystemTrace.isCanvasOffScreen + }); + bytesInTraceRow.rowParentId = `abilityMonitor` + bytesInTraceRow.rowHidden = !processRow.expansion + bytesInTraceRow.rowId = networkNameList[0] + bytesInTraceRow.rowType = TraceRow.ROW_TYPE_NETWORK_ABILITY + bytesInTraceRow.favoriteChangeHandler = this.favoriteChangeHandler; + bytesInTraceRow.selectChangeHandler = this.selectChangeHandler; + bytesInTraceRow.style.height = '40px' + bytesInTraceRow.style.width = `100%`; + bytesInTraceRow.setAttribute('children', ''); + bytesInTraceRow.name = 'Network ' + networkNameList[0]; + bytesInTraceRow.supplier = () => queryBytesInAbilityData() + bytesInTraceRow.onThreadHandler = (useCache) => { + procedurePool.submitWithName(`ability0`, `monitorNetwork0`, { + list: bytesInTraceRow.must ? bytesInTraceRow.dataList : undefined, + offscreen: bytesInTraceRow.must ? bytesInTraceRow.offscreen[0] : undefined, + xs: TraceRow.range?.xs, + dpr: bytesInTraceRow.dpr, + isHover: bytesInTraceRow.isHover, + hoverX: bytesInTraceRow.hoverX, + hoverY: bytesInTraceRow.hoverY, + flagMoveInfo: this.hoverFlag, + flagSelectedInfo: this.selectFlag, + canvasWidth: bytesInTraceRow.canvasWidth, + canvasHeight: bytesInTraceRow.canvasHeight, + hoverNetworkAbilityStruct: NetworkAbilityMonitorStruct.hoverNetworkAbilityStruct, + selectNetworkAbilityStruct: NetworkAbilityMonitorStruct.selectNetworkAbilityStruct, + isRangeSelect: bytesInTraceRow.rangeSelect, + rangeSelectObject: TraceRow.rangeSelectObject, + maxNetworkRate: maxBytesIn, + maxNetworkRateName: maxInByteName, + useCache: useCache, + lineColor: bytesInTraceRow.getLineColor(), + startNS: TraceRow.range?.startNS || 0, + endNS: TraceRow.range?.endNS || 0, + totalNS: TraceRow.range?.totalNS || 0, + slicesTime:TraceRow.range?.slicesTime, + frame: bytesInTraceRow.frame, + }, bytesInTraceRow.must && bytesInTraceRow.args.isOffScreen ? bytesInTraceRow.offscreen[0] : undefined, (res: any, hover: any) => { + bytesInTraceRow.must = false; + if (bytesInTraceRow.args.isOffScreen == true) { + if (bytesInTraceRow.isHover) { + NetworkAbilityMonitorStruct.hoverNetworkAbilityStruct = hover; + this.visibleRows.filter(it => it.rowType === TraceRow.ROW_TYPE_NETWORK_ABILITY && it.name !== bytesInTraceRow.name).forEach(it => it.draw(true)); + } + if (bytesInTraceRow.dataList) bytesInTraceRow.dataList.length = 0; + return; + } + } + ) + } + this.rowsEL?.appendChild(bytesInTraceRow) + + let bytesOutTraceRow = new TraceRow({ + canvasNumber: 1, + alpha: false, + contextId: '2d', + isOffScreen: SpSystemTrace.isCanvasOffScreen + }); + let maxBytesOut = maxList[0].maxOut; + let maxOutByteName = this.networkMath(maxBytesOut); + bytesOutTraceRow.rowParentId = `abilityMonitor` + bytesOutTraceRow.rowHidden = !processRow.expansion + bytesOutTraceRow.rowId = networkNameList[1] + bytesOutTraceRow.rowType = TraceRow.ROW_TYPE_NETWORK_ABILITY + bytesOutTraceRow.favoriteChangeHandler = this.favoriteChangeHandler; + bytesOutTraceRow.selectChangeHandler = this.selectChangeHandler; + bytesOutTraceRow.style.height = '40px' + bytesOutTraceRow.style.width = `100%`; + bytesOutTraceRow.setAttribute('children', ''); + bytesOutTraceRow.name = 'Network ' + networkNameList[1]; + bytesOutTraceRow.supplier = () => queryBytesOutAbilityData(); + bytesOutTraceRow.onThreadHandler = (useCache) => { + procedurePool.submitWithName(`ability1`, `monitorNetwork1`, { + list: bytesOutTraceRow.must ? bytesOutTraceRow.dataList : undefined, + offscreen: bytesOutTraceRow.must ? bytesOutTraceRow.offscreen[0] : undefined, + xs: TraceRow.range?.xs, + dpr: bytesOutTraceRow.dpr, + isHover: bytesOutTraceRow.isHover, + hoverX: bytesOutTraceRow.hoverX, + hoverY: bytesOutTraceRow.hoverY, + flagMoveInfo: this.hoverFlag, + flagSelectedInfo: this.selectFlag, + canvasWidth: bytesOutTraceRow.canvasWidth, + canvasHeight: bytesOutTraceRow.canvasHeight, + hoverNetworkAbilityStruct: NetworkAbilityMonitorStruct.hoverNetworkAbilityStruct, + selectNetworkAbilityStruct: NetworkAbilityMonitorStruct.selectNetworkAbilityStruct, + isRangeSelect: bytesOutTraceRow.rangeSelect, + rangeSelectObject: TraceRow.rangeSelectObject, + maxNetworkRate: maxBytesOut, + maxNetworkRateName: maxOutByteName, + useCache: useCache, + lineColor: bytesOutTraceRow.getLineColor(), + startNS: TraceRow.range?.startNS || 0, + endNS: TraceRow.range?.endNS || 0, + totalNS: TraceRow.range?.totalNS || 0, + slicesTime:TraceRow.range?.slicesTime, + frame: bytesOutTraceRow.frame, + }, bytesOutTraceRow.must && bytesOutTraceRow.args.isOffScreen ? bytesOutTraceRow.offscreen[0] : undefined, (res: any, hover: any) => { + bytesOutTraceRow.must = false; + if (bytesOutTraceRow.args.isOffScreen == true) { + if (bytesOutTraceRow.isHover) { + NetworkAbilityMonitorStruct.hoverNetworkAbilityStruct = hover; + this.visibleRows.filter(it => it.rowType === TraceRow.ROW_TYPE_NETWORK_ABILITY && it.name !== bytesOutTraceRow.name).forEach(it => it.draw(true)); + } + if (bytesOutTraceRow.dataList) bytesOutTraceRow.dataList.length = 0; + return; + } + } + ) + } + this.rowsEL?.appendChild(bytesOutTraceRow) + + + let packetInTraceRow = new TraceRow({ + canvasNumber: 1, + alpha: false, + contextId: '2d', + isOffScreen: SpSystemTrace.isCanvasOffScreen + }); + let maxPacketIn = maxList[0].maxPacketIn; + let maxInPacketName = this.networkMath(maxPacketIn); + packetInTraceRow.rowParentId = `abilityMonitor` + packetInTraceRow.rowHidden = !processRow.expansion + packetInTraceRow.rowId = networkNameList[2] + packetInTraceRow.rowType = TraceRow.ROW_TYPE_NETWORK_ABILITY + packetInTraceRow.favoriteChangeHandler = this.favoriteChangeHandler; + packetInTraceRow.selectChangeHandler = this.selectChangeHandler; + packetInTraceRow.style.height = '40px' + packetInTraceRow.style.width = `100%`; + packetInTraceRow.setAttribute('children', ''); + packetInTraceRow.name = 'Network ' + networkNameList[2]; + packetInTraceRow.supplier = () => queryPacketsInAbilityData(); + packetInTraceRow.onThreadHandler = (useCache) => { + procedurePool.submitWithName(`ability2`, `monitorNetwork-Packet2`, { + list: packetInTraceRow.must ? packetInTraceRow.dataList : undefined, + offscreen: packetInTraceRow.must ? packetInTraceRow.offscreen[0] : undefined, + xs: TraceRow.range?.xs, + dpr: packetInTraceRow.dpr, + isHover: packetInTraceRow.isHover, + hoverX: packetInTraceRow.hoverX, + hoverY: packetInTraceRow.hoverY, + flagMoveInfo: this.hoverFlag, + flagSelectedInfo: this.selectFlag, + canvasWidth: packetInTraceRow.canvasWidth, + canvasHeight: packetInTraceRow.canvasHeight, + hoverNetworkAbilityStruct: NetworkAbilityMonitorStruct.hoverNetworkAbilityStruct, + selectNetworkAbilityStruct: NetworkAbilityMonitorStruct.selectNetworkAbilityStruct, + isRangeSelect: packetInTraceRow.rangeSelect, + rangeSelectObject: TraceRow.rangeSelectObject, + maxNetworkRate: maxPacketIn, + maxNetworkRateName: maxInPacketName, + useCache: useCache, + lineColor: packetInTraceRow.getLineColor(), + startNS: TraceRow.range?.startNS || 0, + endNS: TraceRow.range?.endNS || 0, + totalNS: TraceRow.range?.totalNS || 0, + slicesTime:TraceRow.range?.slicesTime, + frame: packetInTraceRow.frame, + }, packetInTraceRow.must && packetInTraceRow.args.isOffScreen ? packetInTraceRow.offscreen[0] : undefined, (res: any, hover: any) => { + packetInTraceRow.must = false; + if (packetInTraceRow.args.isOffScreen == true) { + if (packetInTraceRow.isHover) { + NetworkAbilityMonitorStruct.hoverNetworkAbilityStruct = hover; + this.visibleRows.filter(it => it.rowType === TraceRow.ROW_TYPE_NETWORK_ABILITY && it.name !== packetInTraceRow.name).forEach(it => it.draw(true)); + } + if (packetInTraceRow.dataList) packetInTraceRow.dataList.length = 0; + return; + } + } + ) + } + this.rowsEL?.appendChild(packetInTraceRow) + + + let packetOutTraceRow = new TraceRow({ + canvasNumber: 1, + alpha: false, + contextId: '2d', + isOffScreen: SpSystemTrace.isCanvasOffScreen + }); + let maxPacketOut = maxList[0].maxPacketOut; + let maxOutPacketName = this.networkMath(maxPacketOut); + packetOutTraceRow.rowParentId = `abilityMonitor` + packetOutTraceRow.rowHidden = !processRow.expansion + packetOutTraceRow.rowId = networkNameList[3] + packetOutTraceRow.rowType = TraceRow.ROW_TYPE_NETWORK_ABILITY + packetOutTraceRow.favoriteChangeHandler = this.favoriteChangeHandler; + packetOutTraceRow.selectChangeHandler = this.selectChangeHandler; + packetOutTraceRow.style.height = '40px' + packetOutTraceRow.style.width = `100%`; + packetOutTraceRow.setAttribute('children', ''); + packetOutTraceRow.name = 'Network ' + networkNameList[3]; + packetOutTraceRow.supplier = () => queryPacketsOutAbilityData(); + packetOutTraceRow.onThreadHandler = (useCache) => { + procedurePool.submitWithName(`ability3`, `monitorNetwork3`, { + list: packetOutTraceRow.must ? packetOutTraceRow.dataList : undefined, + offscreen: packetOutTraceRow.must ? packetOutTraceRow.offscreen[0] : undefined, + xs: TraceRow.range?.xs, + dpr: packetOutTraceRow.dpr, + isHover: packetOutTraceRow.isHover, + hoverX: packetOutTraceRow.hoverX, + hoverY: packetOutTraceRow.hoverY, + flagMoveInfo: this.hoverFlag, + flagSelectedInfo: this.selectFlag, + canvasWidth: packetOutTraceRow.canvasWidth, + canvasHeight: packetOutTraceRow.canvasHeight, + hoverNetworkAbilityStruct: NetworkAbilityMonitorStruct.hoverNetworkAbilityStruct, + selectNetworkAbilityStruct: NetworkAbilityMonitorStruct.selectNetworkAbilityStruct, + isRangeSelect: packetOutTraceRow.rangeSelect, + rangeSelectObject: TraceRow.rangeSelectObject, + maxNetworkRate: maxPacketOut, + maxNetworkRateName: maxOutPacketName, + useCache: useCache, + lineColor: packetOutTraceRow.getLineColor(), + startNS: TraceRow.range?.startNS || 0, + endNS: TraceRow.range?.endNS || 0, + totalNS: TraceRow.range?.totalNS || 0, + slicesTime:TraceRow.range?.slicesTime, + frame: packetOutTraceRow.frame, + }, packetOutTraceRow.must && packetOutTraceRow.args.isOffScreen ? packetOutTraceRow.offscreen[0] : undefined, (res: any, hover: any) => { + packetOutTraceRow.must = false; + if (packetOutTraceRow.args.isOffScreen == true) { + if (packetOutTraceRow.isHover) { + NetworkAbilityMonitorStruct.hoverNetworkAbilityStruct = hover; + this.visibleRows.filter(it => it.rowType === TraceRow.ROW_TYPE_NETWORK_ABILITY && it.name !== packetOutTraceRow.name).forEach(it => it.draw(true)); + } + if (packetOutTraceRow.dataList) packetOutTraceRow.dataList.length = 0; + return; + } + } + ) + } + this.rowsEL?.appendChild(packetOutTraceRow) + } } diff --git a/host/ide/src/trace/component/SpWelcomePage.ts b/host/ide/src/trace/component/SpWelcomePage.ts index 8da17c7e03409b23b747aab944f013461c0baba9..5b6e57a8908479dae808212a985209a07703cc5b 100644 --- a/host/ide/src/trace/component/SpWelcomePage.ts +++ b/host/ide/src/trace/component/SpWelcomePage.ts @@ -22,23 +22,22 @@ export class SpWelcomePage extends BaseElement { initHtml(): string { return ` - -
- -
+ +
+ +
`; } - } diff --git a/host/ide/src/trace/component/Sptext.ts b/host/ide/src/trace/component/Sptext.ts index f0b089aa105f695adff15cbac60f151f6fc6004c..93dc08ae8468a939283d29a6cbd71580f2dc61b4 100644 --- a/host/ide/src/trace/component/Sptext.ts +++ b/host/ide/src/trace/component/Sptext.ts @@ -29,31 +29,31 @@ export class Sptext extends BaseElement { initHtml(): string { return ` - -
-
- - - - -
-
`; + +
+
+ + + + +
+
+ `; } - } \ No newline at end of file diff --git a/host/ide/src/trace/component/StackBar.ts b/host/ide/src/trace/component/StackBar.ts index 9c9a0b259bdad2aa04f54ba8b2a1e6a38838472d..26700c1c0280f28501053f293e4610525caffe5f 100644 --- a/host/ide/src/trace/component/StackBar.ts +++ b/host/ide/src/trace/component/StackBar.ts @@ -62,20 +62,21 @@ export class StackBar extends BaseElement { initHtml(): string { return ` - -
-
`; + +
+
+ `; } getStateWidth(state: string): number { diff --git a/host/ide/src/trace/component/hiperf/PerfDataQuery.ts b/host/ide/src/trace/component/hiperf/PerfDataQuery.ts new file mode 100644 index 0000000000000000000000000000000000000000..ba90636a18b18df9c5cc88cf5fbf178d2aaf5482 --- /dev/null +++ b/host/ide/src/trace/component/hiperf/PerfDataQuery.ts @@ -0,0 +1,361 @@ +/* + * 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. + */ + +import { + queryPerfCallchains, + queryPerfCallchainsCount, + queryPerfFiles, + queryPerfThread +} from "../../database/SqlLite.js"; +import {PerfCallChain, PerfCallChainMerageData, PerfFile} from "../../bean/PerfProfile.js"; +import {Utils} from "../trace/base/Utils.js"; + +export class PerfDataQuery { + + filesData: any = {} + samplesData: any = {} + threadData: any = {} + callChainData: any = {} + splitMapData: any = {} + currentTreeMapData: any = {} + currentTreeList: any[] = [] + searchValue: string = "" + + async initPerfFiles() { + let files = await queryPerfFiles() + files.forEach((file) => { + this.filesData[file.fileId] = this.filesData[file.fileId] || [] + PerfFile.setFileName(file) + this.filesData[file.fileId].push(file) + }) + let threads = await queryPerfThread() + threads.forEach((thread) => { + this.threadData[thread.tid] = thread + }) + let countRes = await queryPerfCallchainsCount() + if (countRes.length != 0) { + let count: number = (countRes[0] as any).count; + let pageSize = 500000; + let pages = Math.ceil(count / pageSize); + let callChains: any[] = [] + for (let i = 0; i < pages; i++) { + let arr = await queryPerfCallchains(pageSize, i * pageSize); + callChains = callChains.concat(arr) + } + this.initCallChainBottomUp(callChains) + } + } + + initCallChainBottomUp(callChains: PerfCallChain[]) { + callChains.forEach((callChain, index) => { + if (this.threadData[callChain.tid] == undefined) { + return + } + callChain.name = this.setCallChainName(callChain) + this.addGroupData(callChain) + if (index + 1 < callChains.length && callChains[index + 1].callChainId != 0) { + PerfCallChain.setPreviousNode(callChain, callChains[index + 1]) + } + if (callChains.length == index + 1 || callChains[index + 1].callChainId == 0) { + this.addProcessThreadStateData(callChain) + } + }) + } + + setCallChainName(callChain: PerfCallChain): string {//设置调用栈的名称 + callChain.canCharge = true + if (callChain.symbolId == -1) { + if (this.filesData[callChain.fileId] && this.filesData[callChain.fileId].length > 0) { + callChain.fileName = this.filesData[callChain.fileId][0].fileName + callChain.path = this.filesData[callChain.fileId][0].path + return this.filesData[callChain.fileId][0].fileName + "+0x" + callChain.vaddrInFile + } else { + callChain.fileName = "unkown" + return "+0x" + callChain.vaddrInFile + } + } else { + if (this.filesData[callChain.fileId] && this.filesData[callChain.fileId].length > callChain.symbolId) { + callChain.fileName = this.filesData[callChain.fileId][callChain.symbolId].fileName + callChain.path = this.filesData[callChain.fileId][callChain.symbolId].path + return this.filesData[callChain.fileId][callChain.symbolId].symbol + } else { + callChain.fileName = "unkown" + return "+0x" + callChain.vaddrInFile + } + } + } + + addProcessThreadStateData(callChain: PerfCallChain) {//当调用栈为调用的根节点时 + let threadCallChain = new PerfCallChain()//新增的线程数据 + threadCallChain.depth = 0 + PerfCallChain.merageCallChain(threadCallChain, callChain) + threadCallChain.canCharge = false + threadCallChain.name = this.threadData[callChain.tid].threadName + "(" + callChain.tid + ")" + let threadStateCallChain = new PerfCallChain()//新增的线程状态数据 + PerfCallChain.merageCallChain(threadStateCallChain, callChain) + threadStateCallChain.name = callChain.threadState || "Unkown State" + threadStateCallChain.fileName = threadStateCallChain.name == "-" ? "Unkown Thead State" : "" + threadStateCallChain.canCharge = false + this.addGroupData(threadStateCallChain) + this.addGroupData(threadCallChain) + PerfCallChain.setNextNode(threadCallChain, threadStateCallChain) + PerfCallChain.setNextNode(threadStateCallChain, callChain) + } + + addGroupData(callChain: PerfCallChain) { + this.callChainData[callChain.sampleId] = this.callChainData[callChain.sampleId] || [] + this.callChainData[callChain.sampleId].push(callChain) + } + + getCallChainsBySampleIds(sampleIds: string[], isTopDown: boolean) { + return this.groupNewTreeNoId(sampleIds, isTopDown) + } + + + groupNewTreeNoId(sampleIds: string[], isTopDown: boolean) { + this.currentTreeMapData = {} + this.currentTreeList = [] + for (let i = 0; i < sampleIds.length; i++) { + let callChains = this.callChainData[sampleIds[i]] + let topIndex = isTopDown ? (callChains.length - 1) : 0; + if (callChains.length > 0) { + let root = this.currentTreeMapData[callChains[topIndex].name + callChains[topIndex].pid]; + if (root == undefined) { + root = new PerfCallChainMerageData(); + root.id = Utils.uuid() + this.currentTreeMapData[callChains[topIndex].name + callChains[topIndex].pid] = root; + this.currentTreeList.push(root) + } + PerfCallChainMerageData.merageCallChain(root, callChains[topIndex], isTopDown); + this.merageChildren(root, callChains[topIndex], isTopDown); + } + } + let rootMerageMap: any = {} + Object.values(this.currentTreeMapData).forEach((merageData: any) => { + if (rootMerageMap[merageData.pid] == undefined) { + let processMerageData = new PerfCallChainMerageData()//新增进程的节点数据 + processMerageData.canCharge = false + processMerageData.symbolName = this.threadData[merageData.tid].processName + processMerageData.symbol = processMerageData.symbolName + processMerageData.tid = merageData.tid + processMerageData.children.push(merageData) + processMerageData.initChildren.push(merageData) + processMerageData.dur = merageData.dur; + processMerageData.count = merageData.dur; + processMerageData.total = sampleIds.length; + processMerageData.id = Utils.uuid() + rootMerageMap[merageData.pid] = processMerageData + } else { + merageData.parentId = rootMerageMap[merageData.pid].id + rootMerageMap[merageData.pid].children.push(merageData) + rootMerageMap[merageData.pid].initChildren.push(merageData) + rootMerageMap[merageData.pid].dur += merageData.dur; + rootMerageMap[merageData.pid].count += merageData.dur; + rootMerageMap[merageData.pid].total = sampleIds.length; + } + merageData.parentNode = rootMerageMap[merageData.pid]//子节点添加父节点的引用 + }) + this.currentTreeList.forEach((node) => { + node.total = sampleIds.length; + }) + return Object.values(rootMerageMap) + } + + merageChildren(currentNode: PerfCallChainMerageData, callChain: any, isTopDown: boolean) { + let nextNodeKey = isTopDown ? "nextNode" : "previousNode" + if (callChain[nextNodeKey] == undefined) return + let node; + if (currentNode.initChildren.filter((child: PerfCallChainMerageData) => { + if (child.symbolName == callChain[nextNodeKey]?.name) { + node = child; + PerfCallChainMerageData.merageCallChain(child, callChain[nextNodeKey], isTopDown) + return true; + } + return false; + }).length == 0) { + node = new PerfCallChainMerageData() + PerfCallChainMerageData.merageCallChain(node, callChain[nextNodeKey], isTopDown) + node.id = Utils.uuid() + node.parentId = currentNode.id + currentNode.children.push(node) + currentNode.initChildren.push(node) + this.currentTreeList.push(node) + node.parentNode = currentNode + } + if (node) this.merageChildren(node, callChain[nextNodeKey], isTopDown) + } + + //所有的操作都是针对整个树结构的 不区分特定的数据 + splitTree(data: PerfCallChainMerageData[], name: string, isCharge: boolean, isSymbol: boolean) { + data.forEach((process) => { + process.children = [] + if (isCharge) { + this.recursionChargeInitTree(process, name, isSymbol) + } else { + this.recursionPruneInitTree(process, name, isSymbol) + } + }) + this.resetAllNode(data) + } + + recursionChargeInitTree(node: PerfCallChainMerageData, symbolName: string, isSymbol: boolean) { + if ((isSymbol && node.symbolName == symbolName) || (!isSymbol && node.libName == symbolName)) { + (this.splitMapData[symbolName] = this.splitMapData[symbolName] || []).push(node) + node.isStore++; + } + if (node.initChildren.length > 0) { + node.initChildren.forEach((child) => { + this.recursionChargeInitTree(child, symbolName, isSymbol) + }) + } + } + + //symbol lib charge + recursionChargeTree(node: PerfCallChainMerageData, symbolName: string, isSymbol: boolean) { + if ((isSymbol && node.symbolName == symbolName) || (!isSymbol && node.libName == symbolName)) { + node.currentTreeParentNode && node.currentTreeParentNode.children.splice(node.currentTreeParentNode.children.indexOf(node), 1, ...node.children); + node.children.forEach((child) => { + child.currentTreeParentNode = node.currentTreeParentNode + }) + } + if (node.children.length > 0) { + node.children.forEach((child) => { + this.recursionChargeTree(child, symbolName, isSymbol) + }) + } + } + + recursionPruneInitTree(node: PerfCallChainMerageData, symbolName: string, isSymbol: boolean) { + if (isSymbol && node.symbolName == symbolName || (!isSymbol && node.libName == symbolName)) { + (this.splitMapData[symbolName] = this.splitMapData[symbolName] || []).push(node) + node.isStore++; + this.pruneChildren(node, symbolName) + } else if (node.initChildren.length > 0) { + node.initChildren.forEach((child) => { + this.recursionPruneInitTree(child, symbolName, isSymbol) + }) + } + } + + //symbol lib prune + recursionPruneTree(node: PerfCallChainMerageData, symbolName: string, isSymbol: boolean) { + if (isSymbol && node.symbolName == symbolName || (!isSymbol && node.libName == symbolName)) { + node.currentTreeParentNode && node.currentTreeParentNode.children.splice(node.currentTreeParentNode.children.indexOf(node), 1); + } else { + node.children.forEach((child) => { + this.recursionPruneTree(child, symbolName, isSymbol) + }) + } + } + + recursionChargeByRule(node: PerfCallChainMerageData, ruleName: string, rule: (node: PerfCallChainMerageData) => boolean) { + if (node.initChildren.length > 0) { + node.initChildren.forEach((child) => { + if (rule(child)) { + (this.splitMapData[ruleName] = this.splitMapData[ruleName] || []).push(child) + child.isStore++; + } + this.recursionChargeByRule(child, ruleName, rule) + }) + } + } + + pruneChildren(node: PerfCallChainMerageData, symbolName: string) { + if (node.initChildren.length > 0) { + node.initChildren.forEach((child) => { + child.isStore++; + (this.splitMapData[symbolName] = this.splitMapData[symbolName] || []).push(child); + this.pruneChildren(child, symbolName) + }) + } + } + + clearSplitMapData(symbolName: string) { + delete this.splitMapData[symbolName] + } + + resotreAllNode(symbols: string[]) { + symbols.forEach((symbol) => { + let list = this.splitMapData[symbol]; + if (list != undefined) { + list.forEach((item: any) => { + item.isStore-- + }) + } + }) + } + + resetAllNode(data: PerfCallChainMerageData[]) { + this.clearSearchNode() + data.forEach((process)=>{ + process.searchShow = true + }) + this.resetNewAllNode(data) + if (this.searchValue != "") { + this.findSearchNode(data, this.searchValue, false) + this.resetNewAllNode(data) + } + } + + resetNewAllNode(data: PerfCallChainMerageData[]) { + data.forEach((process) => { + process.children = [] + }) + let values = this.currentTreeList.map((item: any) => { + item.children = [] + return item + }) + values.forEach((item: any) => { + if (item.parentNode != undefined) { + if (item.isStore == 0 && item.searchShow) { + let parentNode = item.parentNode + while (parentNode != undefined && !(parentNode.isStore == 0 && parentNode.searchShow)) { + parentNode = parentNode.parentNode + } + if (parentNode) { + item.currentTreeParentNode = parentNode + parentNode.children.push(item) + } + } + } + }) + } + + findSearchNode(data: PerfCallChainMerageData[], search: string, parentSearch: boolean) { + data.forEach((node) => { + if (node.symbol.includes(search) || parentSearch) { + node.searchShow = true + let parentNode = node.currentTreeParentNode + while (parentNode != undefined && !parentNode.searchShow) { + parentNode.searchShow = true + parentNode = parentNode.currentTreeParentNode + } + } else { + node.searchShow = false + } + if (node.children.length > 0) { + this.findSearchNode(node.children, search, node.searchShow) + } + }) + } + + clearSearchNode() { + this.currentTreeList.forEach((node) => { + node.searchShow = true + }) + } +} + +export const perfDataQuery = new PerfDataQuery() diff --git a/host/ide/src/trace/component/hiperf/SpHiPerf.ts b/host/ide/src/trace/component/hiperf/SpHiPerf.ts new file mode 100644 index 0000000000000000000000000000000000000000..8c3e0ed2e1de1791496ebc33f5f8c01142d048bf --- /dev/null +++ b/host/ide/src/trace/component/hiperf/SpHiPerf.ts @@ -0,0 +1,389 @@ +/* + * 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. + */ + +import {SpSystemTrace} from "../SpSystemTrace.js"; +import {TraceRow} from "../trace/base/TraceRow.js"; +import {procedurePool} from "../../database/Procedure.js"; +import { + queryHiPerfCpuData, + queryHiPerfCpuMergeData, + queryHiPerfProcessData, + queryHiPerfThreadData, + queryPerfCmdline, + queryPerfThread +} from "../../database/SqlLite.js"; +import {Utils} from "../trace/base/Utils.js"; +import {PerfThread} from "../../bean/PerfProfile.js"; +import {HiPerfCpuStruct} from "../../database/ProcedureWorkerHiPerfCPU.js"; +import {HiPerfThreadStruct} from "../../database/ProcedureWorkerHiPerfThread.js"; +import {HiPerfProcessStruct} from "../../database/ProcedureWorkerHiPerfProcess.js"; +import {PerfDataQuery} from "./PerfDataQuery.js"; + +export interface ResultData { + existA: boolean | null | undefined, + existF: boolean | null | undefined, + fValue: number + +} + +export class SpHiPerf { + static hoverCpuStruct: HiPerfCpuStruct | undefined; + static selectCpuStruct: HiPerfCpuStruct | undefined; + static hoverProcessStruct: HiPerfProcessStruct | undefined; + static selectProcessStruct: HiPerfProcessStruct | undefined; + static hoverThreadStruct: HiPerfThreadStruct | undefined; + static selectThreadStruct: HiPerfThreadStruct | undefined; + static stringResult: ResultData | undefined; + + private cpuData: Array | undefined + public maxCpuId: number = 0 + private rowFolder!: TraceRow; + private perfThreads: Array | undefined; + private trace: SpSystemTrace; + private group: any; + + constructor(trace: SpSystemTrace) { + this.trace = trace; + } + + async init() { + await this.initCmdLine() + this.perfThreads = await queryPerfThread(); + this.group = Utils.groupBy(this.perfThreads || [], "pid"); + this.cpuData = await queryHiPerfCpuMergeData(); + this.maxCpuId = this.cpuData.length > 0 ? this.cpuData.reduce((max, v) => max.cpu_id >= v.cpu_id ? max : v).cpu_id : -Infinity; + if (this.cpuData.length > 0) { + await this.initFolder(); + await this.initCpuMerge(); + await this.initCpu(); + await this.initProcess(); + } + } + + getStringResult(s:string = ""){ + let list = s.split(" ").filter((e) => e); + let sA = list.findIndex((item) => item == "-a"); + let sF = list.findIndex((item) => item == "-f"); + SpHiPerf.stringResult = { + existA: sA!==-1, + existF: sF!==-1, + fValue: Number((1000/(sF!==-1?parseInt(list[sF + 1]):1000)).toFixed(1)), + } + } + + async initCmdLine(){ + let perfCmdLines = await queryPerfCmdline(); + if(perfCmdLines.length > 0){ + this.getStringResult(perfCmdLines[0].report_value) + }else { + SpHiPerf.stringResult = { + existA: true, + existF: false, + fValue: 1, + } + } + } + + async initFolder() { + let row = new TraceRow({ + canvasNumber: 1, + alpha: false, + contextId: '2d', + isOffScreen: SpSystemTrace.isCanvasOffScreen + }); + row.setAttribute('disabled-check', '') + row.rowId = `HiPerf`; + row.index = 0; + row.rowType = TraceRow.ROW_TYPE_HIPERF + row.rowParentId = ''; + row.folder = true; + if (SpHiPerf.stringResult?.existA === true) { + row.name = `HiPerf (All)`; + } else { + let names = Reflect.ownKeys(this.group).map((pid: any) => { + let array = this.group[pid] as Array; + let process = array.filter(th => th.pid === th.tid)[0]; + return process.processName; + }).join(','); + row.name = `HiPerf (${names})`; + } + row.supplier = () => new Promise>((resolve) => resolve([])); + row.onThreadHandler = (useCache) => { + procedurePool.submitWithName(`process${row.index}`, `HiPerf-Group`, { + list: row.must ? row.dataList : undefined, + offscreen: !row.isTransferCanvas ? row.offscreen[0] : undefined, + xs: TraceRow.range?.xs, + dpr: row.dpr, + isHover: row.isHover, + flagMoveInfo: this.trace.hoverFlag, + flagSelectedInfo: this.trace.selectFlag, + hoverX: row.hoverX, + hoverY: row.hoverY, + canvasWidth: row.canvasWidth, + canvasHeight: row.canvasHeight, + isRangeSelect: row.rangeSelect, + rangeSelectObject: TraceRow.rangeSelectObject, + useCache: useCache, + lineColor: row.getLineColor(), + startNS: TraceRow.range?.startNS || 0, + endNS: TraceRow.range?.endNS || 0, + totalNS: TraceRow.range?.totalNS || 0, + slicesTime: TraceRow.range?.slicesTime, + scale: TraceRow.range?.scale || 50, + intervalPerf:SpHiPerf.stringResult?.fValue||1, + frame: row.frame + }, !row.isTransferCanvas ? row.offscreen[0] : undefined, (res: any) => { + row.must = false; + }) + row.isTransferCanvas =true; + } + this.rowFolder = row; + this.trace.rowsEL?.appendChild(row) + } + + async initCpuMerge() { + let row = new TraceRow({ + canvasNumber: 1, + alpha: false, + contextId: '2d', + isOffScreen: SpSystemTrace.isCanvasOffScreen + }); + row.rowId = `HiPerf-cpu-merge`; + row.index = 0; + row.rowType = TraceRow.ROW_TYPE_HIPERF_CPU + row.rowParentId = 'HiPerf'; + row.rowHidden = !this.rowFolder.expansion + row.folder = false; + row.name = `HiPerf`; + row.setAttribute('children', '') + row.favoriteChangeHandler = this.trace.favoriteChangeHandler; + row.selectChangeHandler = this.trace.selectChangeHandler; + let that = this; + row.supplier = () => queryHiPerfCpuMergeData(); + row.onThreadHandler = (useCache) => { + procedurePool.submitWithName(`freq${row.index}`, `HiPerf-Cpu-Merge`, { + list: row.must ? row.dataList : undefined, + offscreen: !row.isTransferCanvas ? row.offscreen[0] : undefined, + xs: TraceRow.range?.xs, + dpr: row.dpr, + isHover: row.isHover, + flagMoveInfo: this.trace.hoverFlag, + flagSelectedInfo: this.trace.selectFlag, + hoverX: row.hoverX, + hoverY: row.hoverY, + canvasWidth: row.canvasWidth, + canvasHeight: row.canvasHeight, + hoverStruct: SpHiPerf.hoverCpuStruct, + selectStruct: SpHiPerf.selectCpuStruct, + isRangeSelect: row.rangeSelect, + rangeSelectObject: TraceRow.rangeSelectObject, + useCache: useCache, + lineColor: row.getLineColor(), + startNS: TraceRow.range?.startNS || 0, + endNS: TraceRow.range?.endNS || 0, + totalNS: TraceRow.range?.totalNS || 0, + slicesTime: TraceRow.range?.slicesTime, + scale: TraceRow.range?.scale || 50, + intervalPerf:SpHiPerf.stringResult?.fValue||1, + frame: row.frame, + maxCpu: (this.maxCpuId + 1) + }, !row.isTransferCanvas ? row.offscreen[0] : undefined, (res: any, hover: any) => { + row.must = false; + if (row.isHover) { + SpHiPerf.hoverCpuStruct = hover; + } + }) + row.isTransferCanvas = true; + } + this.trace.rowsEL?.appendChild(row) + } + + async initCpu() { + for (let i = 0; i <= this.maxCpuId; i++) { + let row = new TraceRow({ + canvasNumber: 1, + alpha: false, + contextId: '2d', + isOffScreen: SpSystemTrace.isCanvasOffScreen + }); + row.rowId = `HiPerf-cpu-${i}`; + row.index = i; + row.rowType = TraceRow.ROW_TYPE_HIPERF_CPU + row.rowParentId = 'HiPerf'; + row.rowHidden = !this.rowFolder.expansion + row.folder = false; + row.name = `Cpu ${i}`; + row.setAttribute('children', '') + row.favoriteChangeHandler = this.trace.favoriteChangeHandler; + row.selectChangeHandler = this.trace.selectChangeHandler; + let that = this; + row.supplier = () => queryHiPerfCpuData(i); + row.onThreadHandler = (useCache) => { + procedurePool.submitWithName(`cpu${row.index}`, `HiPerf-Cpu-${i}`, { + list: row.must ? row.dataList : undefined, + offscreen: !row.isTransferCanvas ? row.offscreen[0] : undefined, + xs: TraceRow.range?.xs, + dpr: row.dpr, + isHover: row.isHover, + flagMoveInfo: this.trace.hoverFlag, + flagSelectedInfo: this.trace.selectFlag, + hoverX: row.hoverX, + hoverY: row.hoverY, + canvasWidth: row.canvasWidth, + canvasHeight: row.canvasHeight, + hoverStruct: SpHiPerf.hoverCpuStruct, + selectStruct: SpHiPerf.selectCpuStruct, + isRangeSelect: row.rangeSelect, + rangeSelectObject: TraceRow.rangeSelectObject, + useCache: useCache, + lineColor: row.getLineColor(), + startNS: TraceRow.range?.startNS || 0, + endNS: TraceRow.range?.endNS || 0, + totalNS: TraceRow.range?.totalNS || 0, + slicesTime: TraceRow.range?.slicesTime, + scale: TraceRow.range?.scale || 50, + intervalPerf:SpHiPerf.stringResult?.fValue||1, + frame: row.frame, + maxCpu: undefined + }, !row.isTransferCanvas ? row.offscreen[0] : undefined, (res: any, hover: any) => { + row.must = false; + if (row.isHover) { + SpHiPerf.hoverCpuStruct = hover; + } + }) + row.isTransferCanvas = true; + } + this.trace.rowsEL?.appendChild(row) + } + } + + async initProcess() { + Reflect.ownKeys(this.group).forEach((key, index) => { + let array = this.group[key] as Array; + let process = array.filter(th => th.pid === th.tid)[0]; + let row = new TraceRow({ + canvasNumber: 1, + alpha: false, + contextId: '2d', + isOffScreen: SpSystemTrace.isCanvasOffScreen + }); + row.rowId = `${process.pid}-Perf-Process`; + row.index = index; + row.rowType = TraceRow.ROW_TYPE_HIPERF_PROCESS + row.rowParentId = 'HiPerf'; + row.rowHidden = !this.rowFolder.expansion + row.folder = true; + row.name = `${process.processName} [${process.pid}]`; + row.folderPaddingLeft = 30; + row.favoriteChangeHandler = this.trace.favoriteChangeHandler; + row.selectChangeHandler = this.trace.selectChangeHandler; + let that = this; + row.supplier = () => queryHiPerfProcessData(process.pid); + row.onThreadHandler = (useCache) => { + procedurePool.submitWithName(`process${(row.index) % procedurePool.processLen.length}`, `HiPerf-Process-${row.index}`, { + list: row.must ? row.dataList : undefined, + offscreen: !row.isTransferCanvas ? row.offscreen[0] : undefined, + xs: TraceRow.range?.xs, + dpr: row.dpr, + isHover: row.isHover, + flagMoveInfo: this.trace.hoverFlag, + flagSelectedInfo: this.trace.selectFlag, + hoverX: row.hoverX, + hoverY: row.hoverY, + canvasWidth: row.canvasWidth, + canvasHeight: row.canvasHeight, + hoverStruct: SpHiPerf.hoverProcessStruct, + selectStruct: SpHiPerf.selectProcessStruct, + isRangeSelect: row.rangeSelect, + rangeSelectObject: TraceRow.rangeSelectObject, + useCache: useCache, + lineColor: row.getLineColor(), + startNS: TraceRow.range?.startNS || 0, + endNS: TraceRow.range?.endNS || 0, + totalNS: TraceRow.range?.totalNS || 0, + slicesTime: TraceRow.range?.slicesTime, + scale: TraceRow.range?.scale || 50, + intervalPerf:SpHiPerf.stringResult?.fValue||1, + frame: row.frame + }, !row.isTransferCanvas ? row.offscreen[0] : undefined, (res: any, hover: any) => { + row.must = false; + if (row.isHover) { + SpHiPerf.hoverProcessStruct = hover; + // this.trace.visibleRows.filter(it => it.rowType === TraceRow.ROW_TYPE_HIPERF_PROCESS && it.name !== row.name).forEach(it => it.draw(true)); + } + }) + row.isTransferCanvas=true; + } + this.trace.rowsEL?.appendChild(row) + + array.forEach((thObj, thIdx) => { + let thread = new TraceRow({ + canvasNumber: 1, + alpha: false, + contextId: '2d', + isOffScreen: SpSystemTrace.isCanvasOffScreen + }); + thread.rowId = `${thObj.tid}-Perf-Thread`; + thread.index = thIdx; + thread.rowType = TraceRow.ROW_TYPE_HIPERF_THREAD + thread.rowParentId = row.rowId; + thread.rowHidden = !row.expansion + thread.folder = false; + thread.name = `${thObj.threadName} [${thObj.tid}]`; + thread.setAttribute('children', '') + thread.folderPaddingLeft = 30; + thread.favoriteChangeHandler = this.trace.favoriteChangeHandler; + thread.selectChangeHandler = this.trace.selectChangeHandler; + let that = this; + thread.supplier = () => queryHiPerfThreadData(thObj.tid); + thread.onThreadHandler = (useCache) => { + procedurePool.submitWithName(`process${(thread.index) % procedurePool.processLen.length}`, `HiPerf-Thread-${row.index}-${thread.index}`, { + list: thread.must ? thread.dataList : undefined, + offscreen: !thread.isTransferCanvas ? thread.offscreen[0] : undefined, + xs: TraceRow.range?.xs, + dpr: thread.dpr, + isHover: thread.isHover, + flagMoveInfo: this.trace.hoverFlag, + flagSelectedInfo: this.trace.selectFlag, + hoverX: thread.hoverX, + hoverY: thread.hoverY, + canvasWidth: thread.canvasWidth, + canvasHeight: thread.canvasHeight, + hoverStruct: SpHiPerf.hoverThreadStruct, + selectStruct: SpHiPerf.selectThreadStruct, + isRangeSelect: thread.rangeSelect, + rangeSelectObject: TraceRow.rangeSelectObject, + useCache: useCache, + lineColor: thread.getLineColor(), + startNS: TraceRow.range?.startNS || 0, + endNS: TraceRow.range?.endNS || 0, + totalNS: TraceRow.range?.totalNS || 0, + slicesTime: TraceRow.range?.slicesTime, + scale: TraceRow.range?.scale || 50, + intervalPerf:SpHiPerf.stringResult?.fValue||1, + frame: thread.frame + }, !thread.isTransferCanvas ? thread.offscreen[0] : undefined, (res: any, hover: any) => { + thread.must = false; + if (thread.isHover) { + SpHiPerf.hoverThreadStruct = hover; + } + }) + thread.isTransferCanvas=true; + } + this.trace.rowsEL?.appendChild(thread) + }); + }) + } +} \ No newline at end of file diff --git a/host/ide/src/trace/component/metrics/CpuStrategy.ts b/host/ide/src/trace/component/metrics/CpuStrategy.ts new file mode 100644 index 0000000000000000000000000000000000000000..1c5b9ce3a76ffb7e805b784b63eaaa655d784af7 --- /dev/null +++ b/host/ide/src/trace/component/metrics/CpuStrategy.ts @@ -0,0 +1,113 @@ +/* + * 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. + */ + +import {info} from "../../../log/Log.js"; + +export const initTest = (metricData: Array): ProcessInfoListItem => { + let processInfoListItems: Array = []; + for (let index = 0; index < metricData.length; index++) { + let eventName = metricData[index].event_name; + let stat_type = metricData[index].stat_type; + let count = metricData[index].count; + let source = metricData[index].source; + let serverity = metricData[index].serverity; + + let processInfoSource: ProcessInfoItem = { + // @ts-ignore + processName: eventName, + threads: { + // @ts-ignore + threadName: stat_type, + cpu: [{ + cpu: eventName, + minFreq: stat_type, + maxFreq: count, + avgFrequency: source, + duration: serverity, + }], + } + } + processInfoListItems?.push(processInfoSource) + } + return { + processInfo: processInfoListItems + } +} + +export const initCpuStrategyData = (metricData: Array): ProcessInfoListItem => { + info("Cpu Strategy data length is:", metricData.length) + let processInfoListItems: Array = []; + if (metricData.length == 10) { + + } else { + + } + const splitChar: string = ',' + for (let sqlIndex = 0; sqlIndex < metricData.length; sqlIndex++) { + if (metricData[sqlIndex].avg_frequency == null) { + continue + } + let cpus = metricData[sqlIndex].cpu.split(splitChar); + let minFrequencies = metricData[sqlIndex].min_freq.split(splitChar); + let maxFrequencies = metricData[sqlIndex].max_freq.split(splitChar); + let avgFrequencies = metricData[sqlIndex].avg_frequency.split(splitChar); + let durations = metricData[sqlIndex].duration.split(splitChar); + + let arrayCpu = []; + for (let index = 0; index < cpus.length; index++) { + let cpuIndex: CpuItem = { + cpu: cpus[index], + minFreq: minFrequencies[index], + maxFreq: maxFrequencies[index], + avgFrequency: avgFrequencies[index], + duration: durations[index], + } + arrayCpu.push(cpuIndex); + } + let processInfoSource: ProcessInfoItem = { + processName: metricData[sqlIndex].process_name, + threads: { + threadName: metricData[sqlIndex].thread_name, + cpu: arrayCpu, + } + } + processInfoListItems?.push(processInfoSource) + } + return { + processInfo: processInfoListItems + }; +} + +export interface ProcessInfoListItem { + processInfo: Array +} + +export interface ProcessInfoItem { + processName: string; + threads: ThreadsItem; +} + +export interface ThreadsItem { + threadName: string; + cpu: Array; +} + +export interface CpuItem { + cpu: string; + minFreq: string; + maxFreq: string; + avgFrequency: string; + duration: string; +} diff --git a/host/ide/src/trace/component/metrics/DistributeTermStrategy.ts b/host/ide/src/trace/component/metrics/DistributeTermStrategy.ts new file mode 100644 index 0000000000000000000000000000000000000000..1d6cf851e9b45c843f0fbbc570498063a4019287 --- /dev/null +++ b/host/ide/src/trace/component/metrics/DistributeTermStrategy.ts @@ -0,0 +1,118 @@ +/* + * 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. + */ + +import {info} from "../../../log/Log.js"; + +export const initDistributedTermData = (metricData: Array): DistributedTermListItem => { + info("Distributed Term data length is:", metricData.length) + let distributedTermListItems: Array = [] + const splitChar = ',' + for (let sqlIndex = 0; sqlIndex < metricData.length; sqlIndex++) { + let threadIdsList = metricData[sqlIndex].threadId.split(splitChar); + let threadNamesList = metricData[sqlIndex].threadName.split(splitChar); + let processIdList = metricData[sqlIndex].processId.split(splitChar); + let processNameList = metricData[sqlIndex].processName === null ? threadIdsList.length + '' : metricData[sqlIndex].processName.split(splitChar); + + let funNameList = metricData[sqlIndex].funName.split(splitChar); + let timeList = metricData[sqlIndex].ts.split(splitChar); + let durList = metricData[sqlIndex].dur.split(splitChar); + let flag = metricData[sqlIndex].flag; + let flagList = flag.split(splitChar); + let traceNameList = metricData[sqlIndex].trace_name; + let chainIdList = metricData[sqlIndex].chainId; + let spanIdList = metricData[sqlIndex].spanId; + let parentSpanIdList = metricData[sqlIndex].parentSpanId; + + let distributedTermListItem: DistributedTermItem = {} + for (let index = 0; index < flagList.length; index++) { + let across: boolean = true; + let receiverTime: number = 0; + let senderTime: number = 0; + let delay: number = 0; + if (flag.indexOf('S,C') > -1 || flag.indexOf('C,S') > -1) { + across = false; + if (flagList[index] == 'S') receiverTime = timeList[index] + if (flagList[index] == 'C') senderTime = timeList[index] + delay = receiverTime - senderTime; + } + + let type = { + acrossTheDevice: across, + traceName: traceNameList, + traceId: { + chainID: chainIdList, + spanID: spanIdList, + parentSpanID: parentSpanIdList, + }, + functionName: funNameList[index], + processInfo: { + processId: processIdList[index], + processName: processNameList[index], + }, + threadInfoItem: { + threadId: threadIdsList[index], + threadName: threadNamesList[index], + }, + dur: durList[index], + delay: delay, + } + if ("C" == flagList[index]) { + distributedTermListItem.sender = type + } else { + distributedTermListItem.receiver = type + } + } + distributedTermListItems?.push(distributedTermListItem) + } + return { + distributedTermItem: distributedTermListItems + } +} + +export interface DistributedTermListItem { + distributedTermItem: Array +} + +export interface DistributedTermItem { + sender?: SenderOrReceiverItem; + receiver?: SenderOrReceiverItem; +} + +export interface SenderOrReceiverItem { + acrossTheDevice?: boolean + traceName: string + traceId: TraceIdItem + functionName: string + processInfo: ProcessInfoItem + threadInfoItem: ThreadInfoItem + dur: string + delay: number +} + +export interface TraceIdItem { + chainID: string + spanID: string + parentSpanID: string +} + +export interface ProcessInfoItem { + processId: string + processName: string +} + +export interface ThreadInfoItem { + threadId: string + threadName: string +} diff --git a/host/ide/src/trace/component/metrics/MemAggStrategy.ts b/host/ide/src/trace/component/metrics/MemAggStrategy.ts new file mode 100644 index 0000000000000000000000000000000000000000..85e7246765dcc9228eea752a9f39f57b2253ad54 --- /dev/null +++ b/host/ide/src/trace/component/metrics/MemAggStrategy.ts @@ -0,0 +1,81 @@ +/* + * 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. + */ + +import {info} from "../../../log/Log.js"; + +export const initMemoryAggStrategy = (metricData: Array): ProcessValuesListItem => { + info("Memory Agg Strategy data length is:", metricData.length) + let processValuesListItems: Array = [] + const splitChar: string = ',' + for (let sqlIndex = 0; sqlIndex < metricData.length; sqlIndex++) { + let processNames = metricData[sqlIndex].processName; + let names = metricData[sqlIndex].name.split(splitChar); + let values = metricData[sqlIndex].value.split(splitChar); + let times = metricData[sqlIndex].ts.split(splitChar); + let arrayMem = []; + let oomScoreValue = 0; + for (let indexScore = 0; indexScore < names.length; indexScore++) { + if ("oom_score_adj" === names[indexScore]) { + oomScoreValue = values[indexScore]; + break; + } + } + let processInfoSource: ProcessValuesItem = { + processName: processNames, + } + for (let index = 0; index < names.length; index++) { + let typeItem: TypeItem = { + ts: times[index], + oom_score: oomScoreValue, + value: values[index], + } + if (!processInfoSource) continue + if ("mem.rss.anon" === names[index]) { + processInfoSource.anonRss = typeItem + } + if ("mem.swap" === names[index]) { + processInfoSource.swap = typeItem + } + if ("mem.rss.file" === names[index]) { + processInfoSource.fileRss = typeItem + } + if ("oom_score_adj" === names[index]) { + processInfoSource.anonAndSwap = typeItem + } + } + processValuesListItems?.push(processInfoSource) + } + return { + processValues: processValuesListItems + } +} + +export interface ProcessValuesListItem { + processValues: Array +} + +export interface ProcessValuesItem { + processName: string; + anonRss?: TypeItem; + swap?: TypeItem; + fileRss?: TypeItem; + anonAndSwap?: TypeItem; +} + +export interface TypeItem { + ts: number; + oom_score: number; + value: number; +} diff --git a/host/ide/src/trace/component/metrics/MemStrategy.ts b/host/ide/src/trace/component/metrics/MemStrategy.ts new file mode 100644 index 0000000000000000000000000000000000000000..143a43e317286ac7f11bc054b9019635b67cb245 --- /dev/null +++ b/host/ide/src/trace/component/metrics/MemStrategy.ts @@ -0,0 +1,60 @@ +/* + * 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. + */ + +import {info} from "../../../log/Log.js"; + +export const initMemoryStrategy = (metricData: Array): ProcessMetricsListItems => { + info("Memory Strategy data length is:", metricData.length) + let processMetricsListItems: Array = [] + for (let sqlIndex = 0; sqlIndex < metricData.length; sqlIndex++) { + let processName = metricData[sqlIndex].processName; + let minNum = metricData[sqlIndex].minNum; + let maxNum = metricData[sqlIndex].maxNum; + let avgNum = metricData[sqlIndex].avgNum; + let processInfoSource: ProcessMetricsItems = { + processName: processName, + overallCounters: { + anonRss: { + min: minNum, + max: maxNum, + avg: avgNum, + } + } + } + processMetricsListItems?.push(processInfoSource); + } + return { + processMetrics: processMetricsListItems + } +} + +export interface ProcessMetricsListItems { + processMetrics: Array +} + +export interface ProcessMetricsItems { + processName: string + overallCounters: AnonRssItem +} + +export interface AnonRssItem { + anonRss: TypeItem +} + +export interface TypeItem { + min: number + max: number + avg: number +} diff --git a/host/ide/src/trace/component/metrics/MetaDataStrategy.ts b/host/ide/src/trace/component/metrics/MetaDataStrategy.ts new file mode 100644 index 0000000000000000000000000000000000000000..f3ff8cb37777d253f8d7ea449ebfd7e35fd58d6c --- /dev/null +++ b/host/ide/src/trace/component/metrics/MetaDataStrategy.ts @@ -0,0 +1,60 @@ +/* + * 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. + */ + +import {info} from "../../../log/Log.js"; + +export const initMetaDataStrategy = (metricData: Array): TraceMetadata => { + info("Meta Strategy data length is:", metricData.length) + let traceMetaDataList: Array = [] + let statDataArray = []; + let jsonText = `{`; + for (let index = 0; index < metricData.length; index++) { + let name = metricData[index].name; + let value = metricData[index].valueText; + if (!value.match('^-?\\d+$')) { + value = "\"" + value.replace('\r|\n', '') + '\"' + } + jsonText += `'` + name + `'` + `: ` + `'` + value.toString() + `'` + `,`; + if (index >= metricData.length - 1) { + jsonText += `}`; + } + } + + for (let sqlIndex = 0; sqlIndex < metricData.length; sqlIndex++) { + let name = metricData[sqlIndex].name; + let value = metricData[sqlIndex].valueText; + if (!value.match('^-?\\d+$')) { + value = "\"" + value.replace('\r|\n', '') + '\"' + } + let traceMetaData = { + name: name, + value: value + } + traceMetaDataList?.push(traceMetaData); + } + return { + traceMetadata: traceMetaDataList + } +} + +export interface TraceMetadata { + traceMetadata: Array +} + +export interface TraceMetadataItem { + name: string + value: string +} + diff --git a/host/ide/src/trace/component/metrics/SysCallsStrategy.ts b/host/ide/src/trace/component/metrics/SysCallsStrategy.ts new file mode 100644 index 0000000000000000000000000000000000000000..de68c58596673acf05e4a009dc347bfc234b01cf --- /dev/null +++ b/host/ide/src/trace/component/metrics/SysCallsStrategy.ts @@ -0,0 +1,48 @@ +/* + * 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. + */ + +import {info} from "../../../log/Log.js"; + +export const initSysCallsStrategy = (metricData: Array): FunctionListItem => { + info("System Calls Strategy data length is:", metricData.length) + let functionListItems: Array = [] + for (let sqlIndex = 0; sqlIndex < metricData.length; sqlIndex++) { + let functionNames = metricData[sqlIndex].funName; + let durMaxes = metricData[sqlIndex].maxDur; + let durMines = metricData[sqlIndex].minDur; + let durAvgs = metricData[sqlIndex].avgDur; + let functionItem: FunctionItem = { + functionName: functionNames, + durMax: durMaxes, + durMin: durMines, + durAvg: durAvgs, + } + functionListItems?.push(functionItem) + } + return { + function: functionListItems + } +} + +export interface FunctionListItem { + function: Array +} + +export interface FunctionItem { + functionName: string + durMax: string + durMin: string + durAvg: string +} diff --git a/host/ide/src/trace/component/metrics/SysCallsTopStrategy.ts b/host/ide/src/trace/component/metrics/SysCallsTopStrategy.ts new file mode 100644 index 0000000000000000000000000000000000000000..c9fe6a259c0edd7be7f0ac268e851bef4d2881d8 --- /dev/null +++ b/host/ide/src/trace/component/metrics/SysCallsTopStrategy.ts @@ -0,0 +1,75 @@ +/* + * 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. + */ + +import {info} from "../../../log/Log.js"; + +export const initSysCallsTopStrategy = (metricData: Array): ProcessInfoListItem => { + info("System Calls Strategy data length is:", metricData.length) + let ProcessInfoListItems: Array = [] + + for (let sqlIndex = 0; sqlIndex < metricData.length; sqlIndex++) { + let processNameList = metricData[sqlIndex].process_name; + let pidList = metricData[sqlIndex].pid; + let threadNameList = metricData[sqlIndex].ThreadName; + let tidList = metricData[sqlIndex].tid; + let functionNames = metricData[sqlIndex].funName; + let durMaxes = metricData[sqlIndex].maxDur; + let durMines = metricData[sqlIndex].minDur; + let durAvgs = metricData[sqlIndex].avgDur; + + let processInfoItem: ProcessInfoItem = { + name: processNameList, + pid: pidList, + threads: { + name: threadNameList, + tid: tidList, + function: { + functionName: functionNames, + durMax: durMaxes, + durMin: durMines, + durAvg: durAvgs, + }, + }, + } + ProcessInfoListItems?.push(processInfoItem) + } + return { + processInfo: ProcessInfoListItems + } +} + +export interface ProcessInfoListItem { + processInfo: Array +} + +export interface ProcessInfoItem { + name: string + pid: string + threads: ThreadsItem +} + + +export interface ThreadsItem { + name: string + tid: string + function: FunctionItem +} + +export interface FunctionItem { + functionName: string + durMax: string + durMin: string + durAvg: string +} diff --git a/host/ide/src/trace/component/metrics/TraceStatsStrategy.ts b/host/ide/src/trace/component/metrics/TraceStatsStrategy.ts new file mode 100644 index 0000000000000000000000000000000000000000..20b4bacb56dd892992d717cb18b1ad218ceb3568 --- /dev/null +++ b/host/ide/src/trace/component/metrics/TraceStatsStrategy.ts @@ -0,0 +1,48 @@ +/* + * 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. + */ + +import {info} from "../../../log/Log.js"; + +export const initTraceStateStrategy = (metricData: Array): StatListItem => { + info("Trace State Strategy data length is:", metricData.length) + let statListItems: Array = [] + for (let sqlIndex = 0; sqlIndex < metricData.length; sqlIndex++) { + let names = metricData[sqlIndex].event_name; + let counts = metricData[sqlIndex].count; + let sources = metricData[sqlIndex].source; + let severities = metricData[sqlIndex].serverity; + let statListItem: StatItem = { + name: names, + count: counts, + source: sources, + severity: severities + } + statListItems?.push(statListItem) + } + return { + stat: statListItems + } +} + +export interface StatListItem { + stat: Array +} + +export interface StatItem { + name: string + count: string + source: string + severity: string +} diff --git a/host/ide/src/trace/component/metrics/TraceTaskStrategy.ts b/host/ide/src/trace/component/metrics/TraceTaskStrategy.ts new file mode 100644 index 0000000000000000000000000000000000000000..a81214cc03875b0175a8343ca841d3c85670f208 --- /dev/null +++ b/host/ide/src/trace/component/metrics/TraceTaskStrategy.ts @@ -0,0 +1,52 @@ +/* + * 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. + */ + +import {info} from "../../../log/Log.js"; + +export const initTraceTaskStrategy = (metricData: Array): ProcessListItem => { + info("Trace Task Strategy data length is:", metricData.length) + let statListItems: Array = [] + for (let sqlIndex = 0; sqlIndex < metricData.length; sqlIndex++) { + let pidList = metricData[sqlIndex].pid; + let processNameList = metricData[sqlIndex].process_name; + let threadNameList = metricData[sqlIndex].thread_name; + let value = '' + if (threadNameList !== null) { + let threadNames = threadNameList.split(',') + for (const valueKey in threadNames) { + value = '\"' + valueKey + '\"' + } + } + let statListItem: ProcessItem = { + pid: pidList, + processName: processNameList, + threadName: value + } + statListItems?.push(statListItem) + } + return { + process: statListItems + } +} + +export interface ProcessListItem { + process: Array +} + +export interface ProcessItem { + pid: string + processName: string + threadName: string +} diff --git a/host/ide/src/trace/component/setting/SpAllocations.ts b/host/ide/src/trace/component/setting/SpAllocations.ts index 9763ea000f6fc7338230c6f67e5828a0a02edfb1..2a7e1ca038b310cb72e09f974c102f8443db6f02 100644 --- a/host/ide/src/trace/component/setting/SpAllocations.ts +++ b/host/ide/src/trace/component/setting/SpAllocations.ts @@ -60,131 +60,132 @@ export class SpAllocations extends BaseElement { initHtml(): string { return ` - -
-
- Allocations -
-
- ProcessId or ProcessName : - -
-
- Max unwind level : - -
-
- Shared Memory Size (Must be a multiple of 4 KB) : -
- - -
-
-
- Filter Memory Size : -
- - -
-
-
`; + .font-style{ + font-family: Helvetica-Bold; + font-size: 1em; + color: var(--dark-color1,#000000); + line-height: 28px; + font-weight: 700; + } + .inner-font-style { + font-family: Helvetica,serif; + font-size: 1em; + color: var(--dark-color1,#000000); + text-align: left; + line-height: 20px; + font-weight: 400; + } + input { + width: 72%; + height: 25px; + border:0; + outline:none; + border-radius: 16px; + text-indent:2% + } + input::-webkit-input-placeholder{ + color:var(--bark-prompt,#999999); + } + .select { + height: 30px; + border:0; + border-radius: 3px; + outline:none; + border: 1px solid var(--dark-border,#B3B3B3); + width: 60px; + background-color:var(--dark-background5, #FFFFFF) + font-family: Helvetica; + font-size: 14px; + color:var(--dark-color,#212121) + text-align: center; + line-height: 16px; + font-weight: 400; + border-radius: 16px; + } + .application{ + display: flex; + flex-direction: column; + grid-gap: 15px; + margin-top: 40px; + } + .inputstyle{ + background: var(--dark-background5,#FFFFFF); + border: 1px solid var(--dark-background5,#999999); + font-family: Helvetica; + font-size: 14px; + color: var(--dark-color1,#212121); + text-align: left; + line-height: 16px; + font-weight: 400; + } + .inputstyle::-webkit-input-placeholder { + background: var(--dark-background5,#FFFFFF); + } + #one_mb{ + background-color:var(--dark-background5, #FFFFFF) + } + #one_kb{ + background-color:var(--dark-background5, #FFFFFF) + } + #two_mb{ + background-color:var(--dark-background5, #FFFFFF) + } + #two_kb{ + background-color:var(--dark-background5, #FFFFFF) + } + +
+
+ Native Memory +
+
+ ProcessId or ProcessName : + +
+
+ Max unwind level : + +
+
+ Shared Memory Size (Must be a multiple of 4 KB) : +
+ + +
+
+
+ Filter Memory Size : +
+ + +
+
+
+ `; } private convertToValue(input: string, unit: string): number { @@ -205,4 +206,4 @@ input::-webkit-input-placeholder{ } return parseInt(String(number)); } -} +} \ No newline at end of file diff --git a/host/ide/src/trace/component/setting/SpProbesConfig.ts b/host/ide/src/trace/component/setting/SpProbesConfig.ts index a2af05c5580c7c489e9612bb8f5f68039e030214..2d9f51d2546f28a9be45a15a44a7398e539c84a6 100644 --- a/host/ide/src/trace/component/setting/SpProbesConfig.ts +++ b/host/ide/src/trace/component/setting/SpProbesConfig.ts @@ -95,7 +95,11 @@ export class SpProbesConfig extends BaseElement { + " enabled by other probes." } , {value: "Syscalls", isSelect: false, des: "Tracks the enter and exit of all syscalls"} - , {value: "FPS", isSelect: false, des: "Tracks the FPS"}] + , {value: "FPS", isSelect: false, des: "Tracks the FPS"}, { + value: "AbilityMonitor", + isSelect: false, + des: "Tracks the AbilityMonitor" + }] this._traceConfig = this.shadowRoot?.querySelector(".trace-config") as HTMLElement this.traceConfigList.forEach(configBean => { let checkDesBox = new SpCheckDesBox(); @@ -155,96 +159,98 @@ export class SpProbesConfig extends BaseElement { initHtml(): string { return ` - -
-
Record mode
-
-
-
-
- -
- -
-
-
-
-
- Memory Config + #hitrace-cat{ + display: grid; + grid-template-columns: 1fr 1fr; + } + .user-events{ + display: grid; + grid-template-columns: repeat(4, 1fr); + grid-template-rows: repeat(2, 1fr); + gap: 10px; + margin-left: 15px;; + } + +
+
Record mode
+
+
+
+
+ + +
+ +
+
+
+
+
+ Memory Config +
+
-
-
`; + `; } //当 custom element首次被插入文档DOM时,被调用。 diff --git a/host/ide/src/trace/component/setting/SpRecordPerf.ts b/host/ide/src/trace/component/setting/SpRecordPerf.ts new file mode 100644 index 0000000000000000000000000000000000000000..0abdadd9e0fbb9081be1aee2b5a2724fdb3100b0 --- /dev/null +++ b/host/ide/src/trace/component/setting/SpRecordPerf.ts @@ -0,0 +1,589 @@ +/* + * 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. + */ + +import {BaseElement, element} from "../../../base-ui/BaseElement.js"; +import {LitSelect} from "../../../base-ui/select/LitSelect.js"; +import {LitSlider} from "../../../base-ui/slider/LitSlider.js"; +import LitSwitch from "../../../base-ui/switch/lit-switch.js"; +import "../../../base-ui/switch/lit-switch.js"; + +@element("sp-record-perf") +export class SpRecordPerf extends BaseElement { + private addOptionButton: HTMLButtonElement | undefined | null; + private processSelect: LitSelect | undefined | null; + private frequencySetInput: HTMLInputElement | undefined | null; + private offCPUSwitch: LitSwitch | undefined | null; + private callSelect: LitSelect | undefined | null; + private configList: Array = []; + + get show(): boolean { + return this.hasAttribute("show"); + } + + set show(show: boolean) { + if (show) { + this.setAttribute("show", ""); + } else { + this.removeAttribute("show") + } + } + + set startSamp(start: boolean) { + if (start) { + this.setAttribute("startSamp", ""); + } else { + this.removeAttribute("startSamp") + } + } + + get startSamp(): boolean { + return this.hasAttribute("startSamp"); + } + + getPerfConfig(): PerfConfig | undefined { + let configVal = this.shadowRoot?.querySelectorAll(".config"); + let perfConfig: PerfConfig = { + process:"ALL", + cpu: "select ALL", + eventList: "NONE", + cpuPercent: 100, + frequency: 1000, + period: 1, + isOffCpu: false, + noInherit: false, + callStack: "none", + branch: "none", + mmap: 256, + clockType: "monotonic" + } + configVal!.forEach(value => { + switch (value.title) { + case "Process": + let processSelect = value as LitSelect; + if (processSelect.value.length > 0) { + perfConfig.process = processSelect.value + } + break; + case "CPU": + let selectV = value as LitSelect; + if (selectV.value.length > 0) { + perfConfig.cpu = selectV.value + } + break; + case "Event List": + let selectList = value as LitSelect; + if (selectList.value.length > 0) { + perfConfig.eventList = selectList.value; + } + break; + case "CPU Percent": + let selectSlider = value as LitSlider; + let parEle = value.parentElement; + if (parEle!.hasAttribute("percent")) { + let percent = parEle!.getAttribute("percent"); + perfConfig.cpuPercent = Number(percent); + } + break; + case "Frequency": + let input = value as HTMLInputElement; + if (input.value != "") { + perfConfig.frequency = Number(input.value); + } + break; + case "Period": + let periodInput = value as HTMLInputElement; + if (periodInput.value != "") { + perfConfig.period = Number(periodInput.value); + } + break; + case "Is Off CPU": + let cpuImage = value as LitSwitch; + perfConfig.isOffCpu = cpuImage.checked; + break; + case "No Inherit": + let InheritImage = value as LitSwitch; + perfConfig.noInherit = InheritImage.checked; + break; + case "Call Stack": + let callStack = value as LitSelect; + if (callStack.value != "") { + perfConfig.callStack = callStack.value; + } + break; + case "Branch": + let branch = value as LitSelect; + if (branch.value != "") { + perfConfig.branch = branch.value; + } + break; + case "Mmap Pages": + let pages = value as LitSlider; + let parent = value.parentElement; + if (parent!.hasAttribute("percent")) { + let pagesPercent = parent!.getAttribute("percent"); + perfConfig.mmap = Math.pow(2, Number(pagesPercent)); + } + break; + case "Clock Type": + let clock = value as LitSelect; + if (clock.value != "") { + perfConfig.clockType = clock.value; + } + break; + } + }) + return perfConfig; + } + + initElements(): void { + this.initConfigList(); + let configList = this.shadowRoot?.querySelector(".configList"); + this.addOptionButton = this.shadowRoot?.querySelector("#addOptions"); + this.configList.forEach(config => { + let div = document.createElement("div") + if (config.hidden) { + div.className = "config-div hidden"; + } else { + div.className = "config-div"; + } + let headDiv = document.createElement("div") + div.appendChild(headDiv); + let title = document.createElement("span") + title.className = "title" + title.textContent = config.title + headDiv.appendChild(title) + let des = document.createElement("span") + des.textContent = config.des + des.className = "des" + headDiv.appendChild(des); + switch (config.type) { + case "select-multiple": + let html = ''; + html += `` + config.selectArray.forEach((value: string) => { + html += `${value}` + }) + html += `` + div.innerHTML = div.innerHTML + html; + break; + case "lit-slider": + let silder = `
+ +
` + div.innerHTML = div.innerHTML + silder; + let litSlider = div.querySelector(".silderclass"); + litSlider!.percent = config.litSliderStyle.defaultValue + let sliderBody = div.querySelector(".sliderBody"); + let bufferInput = div?.querySelector('.sliderInput') as HTMLInputElement; + litSlider!.addEventListener('input', evt => { + bufferInput.value = sliderBody!.getAttribute("percent") + config.litSliderStyle.resultUnit; + }) + litSlider!.sliderStyle = config.litSliderStyle; + break; + case "Mmap-lit-slider": + let defaultValue = Math.pow(2,config.litSliderStyle.defaultValue); + let mapsilder = `
+ +
` + div.innerHTML = div.innerHTML + mapsilder; + let maplitSlider = div.querySelector(".silderclass"); + maplitSlider!.percent = config.litSliderStyle.defaultValue + let mapsliderBody = div.querySelector(".sliderBody"); + let mapbufferInput = div?.querySelector('.sliderInput') as HTMLInputElement; + maplitSlider!.addEventListener('input', evt => { + let percnet = mapsliderBody!.getAttribute("percent") ; + if(percnet != null) { + mapbufferInput.value = Math.pow(2,Number(percnet)) + config.litSliderStyle.resultUnit; + } + }) + maplitSlider!.sliderStyle = config.litSliderStyle; + break; + case "input": + let input = document.createElement("input"); + input.className = "input config"; + input.textContent = config.value; + input.value = config.value; + input.title = config.title; + div.appendChild(input); + break; + case "select": + let html1 = ''; + html1 += `` + config.selectArray.forEach((value: string) => { + html1 += `${value}` + }) + html1 += `` + div.innerHTML = div.innerHTML + html1; + break; + case "switch": + let switch1 = document.createElement("lit-switch") as LitSwitch; + switch1.className = "config" + switch1.title = config.title; + if (config.value) { + switch1.checked = true; + } else { + switch1.checked = false; + } + if (config.title == "Is Start Hiperf Sampling") { + switch1.addEventListener("change", (event: any) => { + let detail = event.detail; + if (detail.checked) { + this.startSamp = true; + this.unDisable(); + } else { + this.startSamp = false; + this.addOptionButton!.style.display = "unset"; + this.disable(); + this.show = false; + } + }) + } + headDiv.appendChild(switch1); + break; + default: + break; + } + configList!.appendChild(div); + }) + this.processSelect = this.shadowRoot?.querySelector("lit-select[title='Process']"); + this.frequencySetInput = this.shadowRoot?.querySelector("input[title='Frequency']"); + this.offCPUSwitch = this.shadowRoot?.querySelector("lit-switch[title='Is Off CPU']"); + this.callSelect = this.shadowRoot?.querySelector("lit-select[title='Call Stack']"); + this.addOptionButton!.addEventListener("click", (event) => { + if (!this.startSamp) { + return; + } + this.addOptionButton!.style.display = "none"; + this.show = true; + }); + this.disable(); + } + + private unDisable() { + if (this.processSelect) { + this.processSelect.removeAttribute("disabled"); + } + if (this.frequencySetInput) { + this.frequencySetInput!.disabled = false; + } + if (this.offCPUSwitch) { + this.offCPUSwitch!.disabled = false; + } + if (this.callSelect) { + this.callSelect!.removeAttribute("disabled"); + } + if (this.addOptionButton) { + this.addOptionButton.disabled = false; + } + } + + private disable() { + if (this.processSelect) { + this.processSelect.setAttribute("disabled", ''); + } + if (this.frequencySetInput) { + this.frequencySetInput!.disabled = true; + } + if (this.offCPUSwitch) { + this.offCPUSwitch!.disabled = true; + } + if (this.callSelect) { + this.callSelect!.setAttribute("disabled", ''); + } + if (this.addOptionButton) { + this.addOptionButton.disabled = true; + } + } + + initConfigList(): void { + this.configList = [ + { + title: "Is Start Hiperf Sampling", + des: "", + hidden: false, + type: "switch", + value: false + }, + { + title: "Process", + des: "Record process", + hidden: false, + type: "select-multiple", + selectArray: [ + "ALL-Process" + ] + }, + { + title: "CPU", + des: "Record assign cpu num such as 0,1,2", + hidden: true, + type: "select-multiple", + selectArray: [ + "ALL-CPU" + ] + }, { + title: "Event List", + des: "Event type Default is cpu cycles", + hidden: true, + type: "select-multiple", + selectArray: [ + "NONE" + ] + }, { + title: "CPU Percent", + des: "Set the max percent of cpu time used for recording", + hidden: true, + type: "lit-slider", + litSliderStyle: { + minRange: 0, + maxRange: 100, + defaultValue: '100', + resultUnit: "%", + stepSize: 1, + lineColor: "var(--dark-color3,#a88888)", + buttonColor: "#a88888" + } + }, + { + title: "Frequency", + des: "Set event sampling frequency", + hidden: false, + type: "input", + value: "1000" + }, + { + title: "Period", + des: "Set event sampling period for trace point events2", + hidden: true, + type: "input", + value: "1" + }, + { + title: "Is Off CPU", + des: "Trace when threads are scheduled off cpu", + hidden: false, + type: "switch", + value: false + }, + { + title: "No Inherit", + des: "Don't trace child processes", + hidden: true, + type: "switch", + value: false + }, + { + title: "Call Stack", + des: "Setup and enable call stack recording", + hidden: false, + type: "select", + selectArray: ["none", "fp", "dwarf"] + }, + { + title: "Branch", + des: "Taken branch stack sampling", + hidden: true, + type: "select", + selectArray: ["none", "any", "any_call", "any_ret", "ind_call", "call", "user", "kernel"] + }, + { + title: "Mmap Pages", + des: "Used to receiving record data from kernel", + hidden: true, + type: "Mmap-lit-slider", + litSliderStyle: { + minRange: 1, + maxRange: 10, + defaultValue: "8", + resultUnit: "MB", + stepSize: 1, + lineColor: "var(--dark-color3,#46B1E3)", + buttonColor: "#999999" + } + }, + { + title: "Clock Type", + des: "Set the clock id to use for the various time fields in the perf_event_type records", + hidden: true, + type: "select", + selectArray: ["monotonic", "monotonic_raw", "realtime", "boottime", "perf"] + }, + ] + } + + initHtml(): string { + return ` + +
+
+
+ +
+ `; + } +} + +export interface PerfConfig { + process:string; + cpu: string; + eventList: string; + cpuPercent: number; + frequency: number; + period: number; + isOffCpu: boolean; + noInherit: boolean; + callStack: string; + branch: string; + mmap: number; + clockType: string; +} diff --git a/host/ide/src/trace/component/setting/SpRecordSetting.ts b/host/ide/src/trace/component/setting/SpRecordSetting.ts index 9db5328af629b8ba41a39402b9bedbaf4b7d7436..63fc5fe6ea825cc8e31176e526674d20f7e22a1f 100644 --- a/host/ide/src/trace/component/setting/SpRecordSetting.ts +++ b/host/ide/src/trace/component/setting/SpRecordSetting.ts @@ -18,12 +18,15 @@ import "../../../base-ui/radiobox/LitRadioBox.js"; import {LitRadioBox} from "../../../base-ui/radiobox/LitRadioBox.js"; import "../../../base-ui/slider/LitSlider.js"; import {LitSlider} from "../../../base-ui/slider/LitSlider.js"; +import "../../../base-ui/popover/LitPopover.js" @element('record-setting') export class SpRecordSetting extends BaseElement { private memoryBufferSlider: LitSlider | undefined; private maxDurationSliders: LitSlider | undefined; private radioBox: LitRadioBox | undefined + private bufferNumber: HTMLElement | undefined + private durationNumber: HTMLElement | undefined get recordMod(): boolean { if (this.radioBox) { @@ -33,91 +36,191 @@ export class SpRecordSetting extends BaseElement { } get bufferSize(): number { - let bufferSize = this.shadowRoot?.querySelector(".buffer-size") as HTMLElement - return Number(bufferSize.getAttribute("percent")); + if (this.bufferNumber?.hasAttribute('percent')) { + return Number(this.bufferNumber!.getAttribute("percent")); + } + return 64 } get maxDur(): number { - let bufferSize = this.shadowRoot?.querySelector(".max-duration") as HTMLElement - return Number(bufferSize.getAttribute("percent")); + if (this.durationNumber?.hasAttribute('percent')) { + return Number(this.durationNumber!.getAttribute("percent")); + } + return 50 } initElements(): void { + this.bufferNumber = this.shadowRoot?.querySelector(".buffer-size") as HTMLElement + this.durationNumber = this.shadowRoot?.querySelector(".max-duration") as HTMLElement + let bu = this.shadowRoot?.querySelector('.record') as HTMLDivElement + this.shadowRoot?.querySelectorAll('.MenuButton').forEach(button => { + + button!.addEventListener('mouseenter', e => { + button.style.backgroundColor = '#EFEFEF' + }) + + button!.addEventListener('mouseout', e => { + button.style.backgroundColor = '#E4E3E9' + }) + }) + this.radioBox = this.shadowRoot?.querySelector("#litradio") as LitRadioBox + this.initLitSlider() + } + + initLitSlider() { this.memoryBufferSlider = this.shadowRoot?.querySelector('#memory-buffer') as LitSlider; - let sliderSize1 = this.memoryBufferSlider.sliderSize; + this.memoryBufferSlider.sliderStyle = { + minRange: 4, + maxRange: 512, + defaultValue: "64", + resultUnit: "MB", + stepSize: 2, + lineColor: "var(--dark-color3,#46B1E3)", + buttonColor: "#999999" + }; + let bufferInput = this.shadowRoot?.querySelector('.memory_buffer_result') as HTMLInputElement; + bufferInput.value = ' ' + this.memoryBufferSlider.sliderStyle.defaultValue + ' MB' + this.memoryBufferSlider.addEventListener('input', evt => { + bufferInput.value = ' ' + this.bufferSize + ' MB' + }) + this.maxDurationSliders = this.shadowRoot?.querySelector('#max-duration') as LitSlider; - let sliderSize2 = this.maxDurationSliders.sliderSize; + this.maxDurationSliders.sliderStyle = { + minRange: 10, + maxRange: 600, + defaultValue: '00:00:50', + resultUnit: "h:m:s", + stepSize: 1, + lineColor: "var(--dark-color4,#61CFBE)", + buttonColor: "#999999" + } + + let durationInput = this.shadowRoot?.querySelector('.max_duration_result') as HTMLInputElement; + durationInput.value = ' ' + this.maxDurationSliders.sliderStyle.defaultValue + ' h:m:s' + this.maxDurationSliders.addEventListener('input', evt => { + durationInput.value = ' ' + this.maxDurationSliders!.formatSeconds(this.maxDur.toString()) + ' h:m:s' + }) } initHtml(): string { return ` - -
-
- Record mode - Stop when full -
-
- In-memory buffer size - -
-
- Max duration - -
-
`; + +
+
+ Record mode + Stop when full +
+
+ In-memory buffer size + + + +
+
+ Max duration + + + +
+
+ `; } -} +} \ No newline at end of file diff --git a/host/ide/src/trace/component/setting/SpTraceCommand.ts b/host/ide/src/trace/component/setting/SpTraceCommand.ts index b3f2a542c08dd2e18081e2c665c6020ad30fef09..7426675620d95c39b6511028bff519e385580b19 100644 --- a/host/ide/src/trace/component/setting/SpTraceCommand.ts +++ b/host/ide/src/trace/component/setting/SpTraceCommand.ts @@ -14,6 +14,7 @@ */ import {BaseElement, element} from "../../../base-ui/BaseElement.js"; +import {info} from "../../../log/Log.js"; @element('trace-command') export class SpTraceCommand extends BaseElement { @@ -26,6 +27,7 @@ export class SpTraceCommand extends BaseElement { } set hdcCommon(value: string) { + info("hdc Common is:", value) this.codeHl!.textContent = value; } @@ -56,91 +58,92 @@ export class SpTraceCommand extends BaseElement { initHtml(): string { return ` - -
- - -
`; + +
+ + +
+ `; } -} +} \ No newline at end of file diff --git a/host/ide/src/trace/component/setting/bean/ProfilerServiceTypes.ts b/host/ide/src/trace/component/setting/bean/ProfilerServiceTypes.ts index 88464f8e900e24126542ee29ea9d5abaa83ed58c..41d652c011090058aa3e7a61b6638e8172281d29 100644 --- a/host/ide/src/trace/component/setting/bean/ProfilerServiceTypes.ts +++ b/host/ide/src/trace/component/setting/bean/ProfilerServiceTypes.ts @@ -675,6 +675,7 @@ export enum SysMeminfoType { MEMINFO_VMALLOC_CHUNK = "PMEM_VMALLOC_CHUNK", MEMINFO_CMA_TOTAL = "PMEM_CMA_TOTAL", MEMINFO_CMA_FREE = "PMEM_CMA_FREE", + MEMINFO_KERNEL_RECLAIMABLE = "PMEM_KERNEL_RECLAIMABLE", UNRECOGNIZED = "UNRECOGNIZED", } @@ -782,6 +783,9 @@ export function sysMeminfoTypeFromJSON(object: any): SysMeminfoType { case 33: case "MEMINFO_CMA_FREE": return SysMeminfoType.MEMINFO_CMA_FREE; + case 34: + case "MEMINFO_KERNEL_RECLAIMABLE": + return SysMeminfoType.MEMINFO_KERNEL_RECLAIMABLE; case -1: case "UNRECOGNIZED": default: @@ -848,3 +852,36 @@ export interface NativeHookConfig { export interface FpsConfig { reportFps: boolean; } + +export interface ProcessConfig { + report_process_tree: boolean; + report_cpu: boolean; + report_diskio: boolean; + report_pss: boolean; +} + +export interface CpuConfig { + pid: number; + reportProcessInfo: boolean; +} + +enum IoReportType { + UNSPECIFIED = "UNSPECIFIED", + IO_REPORT = "IO_REPORT", + IO_REPORT_EX = "IO_REPORT_EX" +} + +export interface DiskioConfig { + reportIoStats: string; +} + +export interface NetworkConfig { + testFile: string; +} + + +export interface HiperfPluginConfig { + isRoot: boolean; + outfileName: string; + recordArgs: string; +} \ No newline at end of file diff --git a/host/ide/src/trace/component/setting/utils/PluginConvertUtils.ts b/host/ide/src/trace/component/setting/utils/PluginConvertUtils.ts index 895520db8b4c4564b71681162f2ee8662e7bf0c9..8d1c4728c42946fb953665b37462cd133add7ecc 100644 --- a/host/ide/src/trace/component/setting/utils/PluginConvertUtils.ts +++ b/host/ide/src/trace/component/setting/utils/PluginConvertUtils.ts @@ -32,7 +32,8 @@ export class PluginConvertUtils { return this.handleObj(bean, 0, needColon, 1); } - public static BeanToCmdTxtWithObjName(bean: any, needColon: boolean, objName: string, spacesNumber: number): string { + public static BeanToCmdTxtWithObjName(bean: any, needColon: boolean, objName: string, + spacesNumber: number): string { return objName + ": {" + this.handleObj(bean, 0, needColon, spacesNumber) + "}"; } @@ -50,33 +51,70 @@ export class PluginConvertUtils { } else { switch (typeof value) { case "bigint": - prefixText = prefixText + ' '.repeat(spacesNumber).repeat(indentation + 1) + this.humpToSnake(key) + ": " + value.toString() + this.crlf + prefixText = prefixText + + ' '.repeat(spacesNumber).repeat(indentation + 1) + + this.humpToSnake(key) + + ": " + + value.toString() + + this.crlf break case "boolean": - prefixText = prefixText + ' '.repeat(spacesNumber).repeat(indentation + 1) + this.humpToSnake(key) + ": " + value.toString() + this.crlf + prefixText = prefixText + + ' '.repeat(spacesNumber).repeat(indentation + 1) + + this.humpToSnake(key) + + ": " + + value.toString() + + this.crlf break case "number": if (value == 0 && !needColon) { break; } - prefixText = prefixText + ' '.repeat(spacesNumber).repeat(indentation + 1) + this.humpToSnake(key) + ": " + value.toString() + this.crlf + prefixText = prefixText + + ' '.repeat(spacesNumber).repeat(indentation + 1) + + this.humpToSnake(key) + + ": " + + value.toString() + + this.crlf break case "string": if (value == '') { break } - if (value.startsWith("LOG_")) { - prefixText = prefixText + ' '.repeat(spacesNumber).repeat(indentation + 1) + this.humpToSnake(key) + ": " + value.toString() + this.crlf + if (value.startsWith("LOG_") || value.startsWith("IO_REPORT")) { + prefixText = prefixText + + ' '.repeat(spacesNumber).repeat(indentation + 1) + + this.humpToSnake(key) + + ": " + + value.toString() + + this.crlf } else { - prefixText = prefixText + ' '.repeat(spacesNumber).repeat(indentation + 1) + this.humpToSnake(key) + ": \"" + value.toString() + "\"" + this.crlf + prefixText = prefixText + + ' '.repeat(spacesNumber).repeat(indentation + 1) + + this.humpToSnake(key) + + ": \"" + + value.toString() + + "\"" + + this.crlf } break case "object": default: if (needColon) { - prefixText = prefixText + ' '.repeat(spacesNumber).repeat(indentation + 1) + this.humpToSnake(key) + ": " + this.handleObj(value, indentation + 1, needColon, spacesNumber) + "" + this.crlf + prefixText = prefixText + + ' '.repeat(spacesNumber).repeat(indentation + 1) + + this.humpToSnake(key) + + ": " + + this.handleObj(value, indentation + 1, needColon, spacesNumber) + + "" + + this.crlf } else { - prefixText = prefixText + ' '.repeat(spacesNumber).repeat(indentation + 1) + this.humpToSnake(key) + this.handleObj(value, indentation + 1, needColon, spacesNumber) + "" + this.crlf + prefixText = prefixText + + ' '.repeat(spacesNumber).repeat(indentation + 1) + + this.humpToSnake(key) + + this.handleObj(value, indentation + 1, needColon, spacesNumber) + + "" + + this.crlf } } } @@ -88,35 +126,73 @@ export class PluginConvertUtils { } } - private static handleArray(key: string, arr: Array, indentation: number, needColon: boolean, spacesNumber: number): string { + private static handleArray(key: string, arr: Array, indentation: number, + needColon: boolean, spacesNumber: number): string { let text = ""; arr.forEach(arrValue => { switch (typeof arrValue) { case "bigint": - text = text + ' '.repeat(spacesNumber).repeat(indentation + 1) + this.humpToSnake(key) + ": " + arrValue.toString() + this.crlf + text = text + + ' '.repeat(spacesNumber).repeat(indentation + 1) + + this.humpToSnake(key) + + ": " + + arrValue.toString() + + this.crlf break case "boolean": - text = text + ' '.repeat(spacesNumber).repeat(indentation + 1) + this.humpToSnake(key) + ": " + arrValue.toString() + this.crlf + text = text + + ' '.repeat(spacesNumber).repeat(indentation + 1) + + this.humpToSnake(key) + + ": " + + arrValue.toString() + + this.crlf break case "number": - text = text + ' '.repeat(spacesNumber).repeat(indentation + 1) + this.humpToSnake(key) + ": " + arrValue.toString() + this.crlf + text = text + + ' '.repeat(spacesNumber).repeat(indentation + 1) + + this.humpToSnake(key) + + ": " + + arrValue.toString() + + this.crlf break case "string": if (arrValue == '') { break } if (arrValue.startsWith("VMEMINFO") || arrValue.startsWith("PMEM")) { - text = text + ' '.repeat(spacesNumber).repeat(indentation + 1) + this.humpToSnake(key) + ": " + arrValue.toString() + this.crlf + text = text + + ' '.repeat(spacesNumber).repeat(indentation + 1) + + this.humpToSnake(key) + + ": " + + arrValue.toString() + + this.crlf } else { - text = text + ' '.repeat(spacesNumber).repeat(indentation + 1) + this.humpToSnake(key) + ": \"" + arrValue.toString() + "\"" + this.crlf + text = text + + ' '.repeat(spacesNumber).repeat(indentation + 1) + + this.humpToSnake(key) + + ": \"" + + arrValue.toString() + + "\"" + + this.crlf } break case "object": default: if (needColon) { - text = text + ' '.repeat(spacesNumber).repeat(indentation + 1) + this.humpToSnake(key) + ": " + this.handleObj(arrValue, indentation + 1, needColon, spacesNumber) + "" + this.crlf + text = text + + ' '.repeat(spacesNumber).repeat(indentation + 1) + + this.humpToSnake(key) + + ": " + + this.handleObj(arrValue, indentation + 1, needColon, spacesNumber) + + "" + + this.crlf } else { - text = text + ' '.repeat(spacesNumber).repeat(indentation + 1) + this.humpToSnake(key) + this.handleObj(arrValue, indentation + 1, needColon, spacesNumber) + "" + this.crlf + text = text + + ' '.repeat(spacesNumber).repeat(indentation + 1) + + this.humpToSnake(key) + + this.handleObj(arrValue, indentation + 1, needColon, spacesNumber) + + "" + + this.crlf } } }) @@ -127,6 +203,5 @@ export class PluginConvertUtils { private static humpToSnake(humpString: string): string { return humpString.replace(/[A-Z]/g, (value) => '_' + value.toLowerCase()); } - } diff --git a/host/ide/src/trace/component/trace/TimerShaftElement.ts b/host/ide/src/trace/component/trace/TimerShaftElement.ts index 04bb21e77cd9f1cafd4770788cc0d76c0fd90062..a07661875669dc389697a19810ca555e226e5553 100644 --- a/host/ide/src/trace/component/trace/TimerShaftElement.ts +++ b/host/ide/src/trace/component/trace/TimerShaftElement.ts @@ -149,6 +149,7 @@ export class TimerShaftElement extends BaseElement { this.rangeRuler.cpuUsage = [] this.sportRuler!.flagList.length = 0 this.sportRuler!.isRangeSelect = false + this.setSlicesMark(); } this.removeTriangle("inverted"); this.totalNS = 10_000_000_000; @@ -192,6 +193,12 @@ export class TimerShaftElement extends BaseElement { } if (!this.rangeRuler) { this.rangeRuler = new RangeRuler(this, new Rect(0, 25, width, 75), { + slicesTime:{ + startTime:null, + endTime:null, + color:null, + }, + scale: 0, startX: 0, endX: this.canvas?.clientWidth || 0, startNS: 0, @@ -225,14 +232,6 @@ export class TimerShaftElement extends BaseElement { } updateWidth(width: number) { - if (this.isOffScreen) { - this.frame.width = width - (this.totalEL?.clientWidth || 0); - this.frame.height = this.shadowRoot!.host.clientHeight || 0; - this.canvasWidth = Math.round((this.frame.width) * this.dpr); - this.canvasHeight = Math.round((this.frame.height) * this.dpr); - this.render(); - return; - } this.canvas!.width = width - (this.totalEL?.clientWidth || 0); this.canvas!.height = this.shadowRoot!.host.clientHeight || 0; let oldWidth = this.canvas!.width; @@ -251,167 +250,29 @@ export class TimerShaftElement extends BaseElement { } documentOnMouseDown = (ev: MouseEvent) => { - if (this.isOffScreen) { - procedurePool.submitWithName(`timeline`, `timeline`, { - offscreen: this.must ? this.offscreen : undefined,//是否离屏 - dpr: this.dpr,//屏幕dpr值 - hoverX: this.hoverX, - hoverY: this.hoverY, - canvasWidth: this.canvasWidth, - canvasHeight: this.canvasHeight, - offsetLeft: this.canvas?.offsetLeft || 0, - offsetTop: this.canvas?.offsetTop || 0, - mouseDown: {offsetX: ev.offsetX, offsetY: ev.offsetY}, - mouseUp: null, - mouseMove: null, - mouseOut: null, - keyPressCode: null, - keyUpCode: null, - lineColor: "#dadada", - startNS: this.startNS, - endNS: this.endNS, - totalNS: this.totalNS, - frame: this.frame, - }, this.must ? this.offscreen : undefined, (res: any) => { - this.must = false; - }) - } else { - this.rangeRuler?.mouseDown(ev); - } + this.rangeRuler?.mouseDown(ev); } documentOnMouseUp = (ev: MouseEvent) => { - if (this.isOffScreen) { - procedurePool.submitWithName(`timeline`, `timeline`, { - offscreen: this.must ? this.offscreen : undefined,//是否离屏 - dpr: this.dpr,//屏幕dpr值 - hoverX: this.hoverX, - hoverY: this.hoverY, - canvasWidth: this.canvasWidth, - canvasHeight: this.canvasHeight, - offsetLeft: this.canvas?.offsetLeft || 0, - offsetTop: this.canvas?.offsetTop || 0, - mouseUp: {offsetX: ev.offsetX, offsetY: ev.offsetY}, - mouseMove: null, - mouseOut: null, - keyPressCode: null, - keyUpCode: null, - lineColor: "#dadada", - startNS: this.startNS, - endNS: this.endNS, - totalNS: this.totalNS, - frame: this.frame, - }, this.must ? this.offscreen : undefined, (res: any) => { - this.must = false; - }) - } else { - this.rangeRuler?.mouseUp(ev); - this._sportRuler?.mouseUp(ev); - } + this.rangeRuler?.mouseUp(ev); + this.sportRuler?.mouseUp(ev); } documentOnMouseMove = (ev: MouseEvent) => { - if (this.isOffScreen) { - procedurePool.submitWithName(`timeline`, `timeline`, { - offscreen: this.must ? this.offscreen : undefined,//是否离屏 - dpr: this.dpr,//屏幕dpr值 - hoverX: this.hoverX, - hoverY: this.hoverY, - canvasWidth: this.canvasWidth, - canvasHeight: this.canvasHeight, - offsetLeft: this.canvas?.offsetLeft || 0, - offsetTop: this.canvas?.offsetTop || 0, - mouseMove: {offsetX: ev.offsetX, offsetY: ev.offsetY}, - mouseOut: null, - keyPressCode: null, - keyUpCode: null, - lineColor: "#dadada", - startNS: this.startNS, - endNS: this.endNS, - totalNS: this.totalNS, - frame: this.frame, - }, this.must ? this.offscreen : undefined, (res: any) => { - this.must = false; - }) - } else { - this.rangeRuler?.mouseMove(ev); - this._sportRuler?.mouseMove(ev); - } + this.rangeRuler?.mouseMove(ev); + this.sportRuler?.mouseMove(ev); } documentOnMouseOut = (ev: MouseEvent) => { - if (this.isOffScreen) { - procedurePool.submitWithName(`timeline`, `timeline`, { - offscreen: this.must ? this.offscreen : undefined,//是否离屏 - dpr: this.dpr,//屏幕dpr值 - hoverX: this.hoverX, - hoverY: this.hoverY, - canvasWidth: this.canvasWidth, - canvasHeight: this.canvasHeight, - offsetLeft: this.canvas?.offsetLeft || 0, - offsetTop: this.canvas?.offsetTop || 0, - mouseOut: {offsetX: ev.offsetX, offsetY: ev.offsetY}, - keyPressCode: null, - keyUpCode: null, - lineColor: "#dadada", - startNS: this.startNS, - endNS: this.endNS, - totalNS: this.totalNS, - frame: this.frame, - }, this.must ? this.offscreen : undefined, (res: any) => { - this.must = false; - }) - } else { - this.rangeRuler?.mouseOut(ev); - } + this.rangeRuler?.mouseOut(ev); } documentOnKeyPress = (ev: KeyboardEvent) => { - if (this.isOffScreen) { - procedurePool.submitWithName(`timeline`, `timeline`, { - offscreen: this.must ? this.offscreen : undefined,//是否离屏 - dpr: this.dpr,//屏幕dpr值 - hoverX: this.hoverX, - hoverY: this.hoverY, - canvasWidth: this.canvasWidth, - canvasHeight: this.canvasHeight, - keyPressCode: {key: ev.key}, - keyUpCode: null, - lineColor: "#dadada", - startNS: this.startNS, - endNS: this.endNS, - totalNS: this.totalNS, - frame: this.frame, - }, this.must ? this.offscreen : undefined, (res: any) => { - this.must = false; - }) - } else { - this.rangeRuler?.keyPress(ev); - } + this.rangeRuler?.keyPress(ev); } documentOnKeyUp = (ev: KeyboardEvent) => { - if (this.isOffScreen) { - procedurePool.submitWithName(`timeline`, `timeline`, { - offscreen: this.must ? this.offscreen : undefined,//是否离屏 - dpr: this.dpr,//屏幕dpr值 - hoverX: this.hoverX, - hoverY: this.hoverY, - canvasWidth: this.canvasWidth, - canvasHeight: this.canvasHeight, - keyPressCode: null, - keyUpCode: {key: ev.key}, - lineColor: "#dadada", - startNS: this.startNS, - endNS: this.endNS, - totalNS: this.totalNS, - frame: this.frame, - }, this.must ? this.offscreen : undefined, (res: any) => { - this.must = false; - }) - } else { - this.rangeRuler?.keyUp(ev); - } + this.rangeRuler?.keyUp(ev); } disconnectedCallback() { @@ -450,72 +311,76 @@ export class TimerShaftElement extends BaseElement { } drawTriangle(time: number, type: string) { - this._sportRuler?.drawTriangle(time, type); + return this._sportRuler?.drawTriangle(time, type); } - removeTriangle(type:string){ + removeTriangle(type: string) { this._sportRuler?.removeTriangle(type) } + setSlicesMark(startTime: null | number = null,endTime: null | number = null) { + this._sportRuler?.setSlicesMark(startTime,endTime) + } + initHtml(): string { return ` - -
-
-
-
- 10 - 0 + +
+
+
+
+ 10 + 0 +
+
+
-
- -
`; } } diff --git a/host/ide/src/trace/component/trace/base/ColorUtils.ts b/host/ide/src/trace/component/trace/base/ColorUtils.ts index e5798ef2ee798b9c6dc93218fc0947fb819f46ff..103e405a73bd4145aa5f0899cccad95080f0aad9 100644 --- a/host/ide/src/trace/component/trace/base/ColorUtils.ts +++ b/host/ide/src/trace/component/trace/base/ColorUtils.ts @@ -83,4 +83,4 @@ export class ColorUtils { } return t.split("").reverse().join("") } -} +} \ No newline at end of file diff --git a/host/ide/src/trace/component/trace/base/RangeSelect.ts b/host/ide/src/trace/component/trace/base/RangeSelect.ts index 3e2e8f5b3f9d8f1dab7d6e4a42f97a39f43cdb03..55df72dc0ac2c6aeada8c2ae9d55551c55a89be1 100644 --- a/host/ide/src/trace/component/trace/base/RangeSelect.ts +++ b/host/ide/src/trace/component/trace/base/RangeSelect.ts @@ -65,6 +65,7 @@ export class RangeSelect { if (this.isInRowsEl(ev)) { this.rangeTraceRow = []; this.isMouseDown = true; + TraceRow.rangeSelectObject = undefined; this.startX = ev.offsetX - this.rowsEL!.offsetLeft!; if (this.isInSpacerEL(ev)) { this.startY = 0; @@ -138,6 +139,8 @@ export class RangeSelect { let markB = this.movingMark == "markB" ? mouseX : this.mark.endMark; let startX = markA < markB ? markA : markB let endX = markB < markA ? markA : markB + rangeSelect.startX = startX; + rangeSelect.endX = endX; rangeSelect.startNS = Math.floor((TraceRow.range!.endNS - TraceRow.range!.startNS) * startX / it.frame.width + TraceRow.range!.startNS!); rangeSelect.endNS = Math.floor((TraceRow.range!.endNS - TraceRow.range!.startNS) * endX / it.frame.width + TraceRow.range!.startNS!); if (rangeSelect.startNS <= TraceRow.range!.startNS) { @@ -188,6 +191,8 @@ export class RangeSelect { rangeSelect = new RangeSelectStruct(); let startX = Math.floor(rt.x <= 0 ? 0 : rt.x); let endX = Math.floor((rt.x + rt.width) > it.frame.width ? it.frame.width : (rt.x + rt.width)); + rangeSelect.startX = startX; + rangeSelect.endX = endX; rangeSelect.startNS = Math.floor((TraceRow.range!.endNS - TraceRow.range!.startNS) * startX / it.frame.width + TraceRow.range!.startNS!); rangeSelect.endNS = Math.floor((TraceRow.range!.endNS - TraceRow.range!.startNS) * endX / it.frame.width + TraceRow.range!.startNS!); } diff --git a/host/ide/src/trace/component/trace/base/TraceRow.ts b/host/ide/src/trace/component/trace/base/TraceRow.ts index dc54efbbd5b7119d649fb579d795c6ba0b3ecf8b..ebd7f4833a285cf5bbaf64d05a5ac93f4bca70cd 100644 --- a/host/ide/src/trace/component/trace/base/TraceRow.ts +++ b/host/ide/src/trace/component/trace/base/TraceRow.ts @@ -39,11 +39,20 @@ export class TraceRow extends HTMLElement { static ROW_TYPE_CPU_FREQ = "cpu-freq" static ROW_TYPE_FPS = "fps" static ROW_TYPE_NATIVE_MEMORY = "native-memory" + static ROW_TYPE_HIPERF = "hiperf" + static ROW_TYPE_HIPERF_CPU = "hiperf-cpu" + static ROW_TYPE_HIPERF_PROCESS = "hiperf-process" + static ROW_TYPE_HIPERF_THREAD = "hiperf-thread" static ROW_TYPE_PROCESS = "process" static ROW_TYPE_THREAD = "thread" static ROW_TYPE_MEM = "mem" static ROW_TYPE_HEAP = "heap" static ROW_TYPE_FUNC = "func" + static ROW_TYPE_MONITOR = "ability-monitor" + static ROW_TYPE_CPU_ABILITY = "cpu-ability" + static ROW_TYPE_MEMORY_ABILITY = "memory-ability" + static ROW_TYPE_DISK_ABILITY = "disk-ability" + static ROW_TYPE_NETWORK_ABILITY = "network-ability" static range: TimeRange | undefined | null; static rangeSelectObject: RangeSelectStruct | undefined public obj: TraceRowObject | undefined | null; @@ -62,8 +71,7 @@ export class TraceRow extends HTMLElement { public tipEL: HTMLDivElement | null | undefined; public checkBoxEL: LitCheckBox | null | undefined; public collectEL: LitIcon | null | undefined; - public onDrawHandler: ((ctx: CanvasRenderingContext2D) => void) | undefined | null - public onThreadHandler: ((useCache: boolean) => void) | undefined | null + public onThreadHandler: ((useCache: boolean, buf: ArrayBuffer | undefined | null) => void) | undefined | null public onDrawTypeChangeHandler: ((type: number) => void) | undefined | null public supplier: (() => Promise>) | undefined | null public favoriteChangeHandler: ((fav: TraceRow) => void) | undefined | null @@ -74,12 +82,15 @@ export class TraceRow extends HTMLElement { canvasWidth = 0 canvasHeight = 0 public _frame: Rect | undefined; + public isLoading: boolean = false + public readonly args: any; private rootEL: HTMLDivElement | null | undefined; private nameEL: HTMLLabelElement | null | undefined; - public isLoading: boolean = false private _rangeSelect: boolean = false; - public readonly args: any; private _drawType: number = 0 + private folderIconEL: LitIcon | null | undefined; + online: boolean = false; + static isUserInteraction: boolean; constructor(args: { canvasNumber: number, alpha: boolean, contextId: string, isOffScreen: boolean }) { super(); @@ -91,7 +102,8 @@ export class TraceRow extends HTMLElement { static get observedAttributes() { return ["folder", "name", "expansion", "children", "height", "row-type", "row-id", "row-parent-id", "sleeping", "check-type", - "collect-type" + "collect-type", + "disabled-check" ]; } @@ -194,6 +206,9 @@ export class TraceRow extends HTMLElement { if (!it.collect) { it.rowHidden = !this.expansion; } + if (it.folder && !value && it.expansion) { + it.expansion = value; + } }) this.dispatchEvent(new CustomEvent("expansion-change", { detail: { @@ -230,12 +245,34 @@ export class TraceRow extends HTMLElement { this._frame = f; } + get disabledCheck(): boolean { + return this.hasAttribute("disabled-check"); + } + + set disabledCheck(value: boolean) { + if (value) { + this.setAttribute("disabled-check", '') + this.checkBoxEL!.style.display = "none"; + } else { + this.removeAttribute('disabled-check') + this.checkBoxEL!.style.display = "flex"; + } + } + get checkType(): string { return this.getAttribute("check-type") || ""; } set checkType(value: string) { + if (!value || value.length == 0) { + this.removeAttribute("check-type"); + return; + } this.setAttribute("check-type", value); + if (this.hasAttribute("disabled-check")) { + this.checkBoxEL!.style.display = "none"; + return; + } switch (value) { case "-1": this.checkBoxEL!.style.display = "none"; @@ -286,11 +323,16 @@ export class TraceRow extends HTMLElement { } } + set folderPaddingLeft(value: number) { + this.folderIconEL!.style.marginLeft = value + "px"; + } + initElements(): void { this.rootEL = this.shadowRoot?.querySelector('.root') this.checkBoxEL = this.shadowRoot?.querySelector('.lit-check-box') this.collectEL = this.shadowRoot?.querySelector('.collect') this.describeEl = this.shadowRoot?.querySelector('.describe') + this.folderIconEL = this.shadowRoot?.querySelector('.icon') this.nameEL = this.shadowRoot?.querySelector('.name') this.canvasContainer = this.shadowRoot?.querySelector('.panel-container') this.tipEL = this.shadowRoot?.querySelector('.tip') @@ -310,12 +352,12 @@ export class TraceRow extends HTMLElement { initCanvas(list: Array): void { let timerShaftCanvas = this.parentElement!.parentElement!.querySelector("timer-shaft-element")!.shadowRoot!.querySelector("canvas"); - let tempHeight:number = 0; - if(this.rowType==TraceRow.ROW_TYPE_FUNC ){ + let tempHeight: number = 0; + if (this.rowType == TraceRow.ROW_TYPE_FUNC) { tempHeight = 20; - }else if(this.rowType==TraceRow.ROW_TYPE_THREAD ){ + } else if (this.rowType == TraceRow.ROW_TYPE_THREAD) { tempHeight = 30; - }else{ + } else { tempHeight = 40; } list.forEach((canvas, i) => { @@ -335,7 +377,14 @@ export class TraceRow extends HTMLElement { updateWidth(width: number) { let dpr = window.devicePixelRatio || 1; - let tempHeight = 40; + let tempHeight: number = 0; + if (this.rowType == TraceRow.ROW_TYPE_FUNC) { + tempHeight = 20; + } else if (this.rowType == TraceRow.ROW_TYPE_THREAD) { + tempHeight = 30; + } else { + tempHeight = 40; + } let tempTop = 0; if (this.canvas.length > 1) { tempHeight = 20; @@ -497,6 +546,15 @@ export class TraceRow extends HTMLElement { if (this.sleeping) { return; } + if (this.online) { + if (!useCache && !TraceRow.isUserInteraction) { + this.supplier?.().then(res => { + this.onThreadHandler?.(useCache, res as any); + }); + } + this.onThreadHandler?.(useCache, null); + return; + } if (!this.isComplete) { if (this.supplier && !this.isLoading) { this.isLoading = true; @@ -521,7 +579,7 @@ export class TraceRow extends HTMLElement { } } else { if (this.onThreadHandler && this.dataList) { - this.onThreadHandler!(useCache) + this.onThreadHandler!(useCache, null); } } } @@ -593,231 +651,232 @@ export class TraceRow extends HTMLElement { initHtml(): string { return ` - -
-
- - - - -
-
Current Bytes
-
Native Memory Density
+ } + #setting{ + color: var(--dark-color1,#606060); + } + :host([expansion]) #setting{ + color: #FFFFFF; + } + :host([highlight]) .flash{ + background-color: #ffe263; + } + + +
+
+ + + + +
+
+ Current Bytes
+
+ Native Memory Density
+
+ +
+ +
+
+
+ P:process [1573]
+ T:Thread [675] +
- - - -
-
-
- P:process [1573]
- T:Thread [675]
-
-
`; } - } diff --git a/host/ide/src/trace/component/trace/base/TraceRowRecyclerView.ts b/host/ide/src/trace/component/trace/base/TraceRowRecyclerView.ts index f5ce8484b72dfae6b9e4a74d0b4d23296bef5dfb..4da1ed420e83833069c6db49151b4d3785071aa6 100644 --- a/host/ide/src/trace/component/trace/base/TraceRowRecyclerView.ts +++ b/host/ide/src/trace/component/trace/base/TraceRowRecyclerView.ts @@ -118,7 +118,7 @@ export class TraceRowRecyclerView extends BaseElement { } if (!this.recycler) this.visibleRowsCount = this.dataSource.length; for (let i = 0; i <= this.visibleRowsCount; i++) { - let el = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); + let el = new TraceRow({canvasNumber: 1, alpha: true, contextId: '2d', isOffScreen: true}); el.className = "recycler-cell" this.container?.appendChild(el); el.addEventListener('expansion-change', (ev: any) => { @@ -149,42 +149,42 @@ export class TraceRowRecyclerView extends BaseElement { initHtml(): string { return ` - -
-
-
+ +
+
+
-`; + `; } } diff --git a/host/ide/src/trace/component/trace/base/TraceSheet.ts b/host/ide/src/trace/component/trace/base/TraceSheet.ts index 0ede469f0d6d9fe0302cb43c0f8a077e1887145e..6c6cbb31f51e430e9997af3854089d418affa3a2 100644 --- a/host/ide/src/trace/component/trace/base/TraceSheet.ts +++ b/host/ide/src/trace/component/trace/base/TraceSheet.ts @@ -37,6 +37,8 @@ import "../sheet/TabPaneNMStatstics.js"; import "../sheet/TabPaneNMCallInfo.js"; import "../sheet/TabPaneNMemory.js"; import "../sheet/TabPaneNMSampleList.js"; +import "../sheet/TabPerfProfile.js"; +import "../sheet/TabPerfSampleList.js"; import {BoxJumpParam, SelectionParam} from "../../../bean/BoxSelection.js"; import {TabPaneThreadStates} from "../sheet/TabPaneThreadStates.js"; import {TabPaneCpuByProcess} from "../sheet/TabPaneCpuByProcess.js"; @@ -65,6 +67,20 @@ import {TabPaneNMemory} from "../sheet/TabPaneNMemory.js"; import {TabPaneNMSampleList} from "../sheet/TabPaneNMSampleList.js"; import {WakeupBean} from "../../../bean/WakeupBean.js"; import {LitIcon} from "../../../../base-ui/icon/LitIcon.js"; +import {TabPaneCpuAbility} from "../sheet/TabPaneCpuAbility.js"; +import "../sheet/TabPaneCpuAbility.js"; +import {TabPaneDiskAbility} from "../sheet/TabPaneDiskAbility.js"; +import "../sheet/TabPaneDiskAbility.js"; +import {TabPaneMemoryAbility} from "../sheet/TabPaneMemoryAbility.js"; +import "../sheet/TabPaneMemoryAbility.js"; +import {TabPaneNetworkAbility} from "../sheet/TabPaneNetworkAbility.js"; +import "../sheet/TabPaneNetworkAbility.js"; +import {TabPaneHistoryProcesses} from "../sheet/TabPaneHistoryProcesses.js"; +import "../sheet/TabPaneHistoryProcesses.js"; +import {TabPaneLiveProcesses} from "../sheet/TabPaneLiveProcesses.js"; +import "../sheet/TabPaneLiveProcesses.js"; +import {TabpanePerfProfile} from "../sheet/TabPerfProfile.js"; +import {TabPanePerfSample} from "../sheet/TabPerfSampleList.js"; @element("trace-sheet") export class TraceSheet extends BaseElement { @@ -89,6 +105,8 @@ export class TraceSheet extends BaseElement { private tabBoxNMCallInfo: LitTabpane | undefined | null private tabBoxNMemory: LitTabpane | undefined | null private tabBoxNMSample: LitTabpane | undefined | null + private tabBoxPerfProfile: LitTabpane | undefined | null + private tabBoxPerfSample: LitTabpane | undefined | null private tabSPT: TabPaneSPT | undefined | null private tabPTS: TabPanePTS | undefined | null private tabCs: TabPaneContextSwitch | undefined | null @@ -98,9 +116,25 @@ export class TraceSheet extends BaseElement { private tabNativeMemory: TabPaneNMemory | undefined | null private tabNativeCallInfo: TabPaneNMCallInfo | undefined | null private tabNativeSample: TabPaneNMSampleList | undefined | null + private tabPerfProfile: TabpanePerfProfile | undefined | null + private tabPerfSample: TabPanePerfSample | undefined | null private currentKey: string = "1"; private selection: SelectionParam | undefined | null; + private tabBoxLiveProcesses: LitTabpane | undefined | null + private tabBoxHistoryProcesses: LitTabpane | undefined | null + private tabBoxSystemCpu: LitTabpane | undefined | null + private tabBoxSystemMemory: LitTabpane | undefined | null + private tabBoxSystemDiskIo: LitTabpane | undefined | null + private tabBoxSystemNetwork: LitTabpane | undefined | null + + private tabLiveProcesses: TabPaneLiveProcesses | undefined | null + private tabHistoryProcesses: TabPaneHistoryProcesses | undefined | null + private tabSystemCpu: TabPaneCpuAbility | undefined | null + private tabSystemMemory: TabPaneMemoryAbility | undefined | null + private tabSystemDiskIo: TabPaneDiskAbility | undefined | null + private tabSystemNetwork: TabPaneNetworkAbility | undefined | null + static get observedAttributes() { return ['mode']; } @@ -128,6 +162,16 @@ export class TraceSheet extends BaseElement { this.tabBoxNMemory = this.shadowRoot?.querySelector("#box-native-memory"); this.tabBoxNMSample = this.shadowRoot?.querySelector("#box-native-sample"); + this.tabBoxLiveProcesses = this.shadowRoot?.querySelector("#box-live-processes-child"); + this.tabBoxHistoryProcesses = this.shadowRoot?.querySelector("#box-history-processes-child"); + this.tabBoxSystemCpu = this.shadowRoot?.querySelector("#box-system-cpu-child"); + this.tabBoxSystemMemory = this.shadowRoot?.querySelector("#box-system-memory-child"); + this.tabBoxSystemDiskIo = this.shadowRoot?.querySelector("#box-system-diskIo-child"); + this.tabBoxSystemNetwork = this.shadowRoot?.querySelector("#box-system-network-child"); + + this.tabBoxPerfProfile = this.shadowRoot?.querySelector("#box-perf-profile"); + this.tabBoxPerfSample = this.shadowRoot?.querySelector("#box-perf-sample"); + this.tabSPT = this.shadowRoot!.querySelector('#tab-spt'); this.tabPTS = this.shadowRoot!.querySelector('#tab-pts'); this.tabCs = this.shadowRoot!.querySelector('#tab-cs'); @@ -139,6 +183,15 @@ export class TraceSheet extends BaseElement { this.tabNativeMemory = this.shadowRoot!.querySelector('#tab-box-native-memory'); this.tabNativeSample = this.shadowRoot!.querySelector('#tab-box-native-sample'); + this.tabLiveProcesses = this.shadowRoot?.querySelector("#tab-live-processes-child"); + this.tabHistoryProcesses = this.shadowRoot?.querySelector("#tab-history-processes-child"); + this.tabSystemCpu = this.shadowRoot?.querySelector("#tab-system-cpu-child"); + this.tabSystemMemory = this.shadowRoot?.querySelector("#tab-system-memory-child"); + this.tabSystemDiskIo = this.shadowRoot?.querySelector("#tab-system-diskIo-child"); + this.tabSystemNetwork = this.shadowRoot?.querySelector("#tab-system-network-child"); + + this.tabPerfProfile = this.shadowRoot!.querySelector('#tab-box-perf-profile'); + this.tabPerfSample = this.shadowRoot!.querySelector('#tab-box-perf-sample'); let minBtn = this.shadowRoot?.querySelector("#min-btn"); minBtn?.addEventListener('click', (e) => { }) @@ -162,7 +215,7 @@ export class TraceSheet extends BaseElement { this.tabTs!.addEventListener("row-click", (e) => { this.jumpBoxChild("14", e) }) - this.tabNativeStatistics!.addEventListener("row-click",(e)=>{ + this.tabNativeStatistics!.addEventListener("row-click", (e) => { // @ts-ignore this.selection!.statisticsSelectData = e.detail this.tabNativeMemory?.fromStastics(this.selection) @@ -253,100 +306,152 @@ export class TraceSheet extends BaseElement { initHtml(): string { return ` - -
- -
- - -
- - - - - - - - - - - - - - - - - - - - -
-
`; + +
+ +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ `; } clear() { this.shadowRoot?.querySelectorAll("lit-tabpane").forEach(it => this.litTabs?.removeChild(it)) } - displayThreadData(data: ThreadStruct, scrollCallback: ((e: ThreadStruct) => void) | undefined) { + displayThreadData(data: ThreadStruct, scrollCallback: ((e: ThreadStruct) => void) | undefined,scrollWakeUp:(d:any) => void | undefined) { this.setAttribute("mode", "max") this.tabCurrentSelection!.hidden = false; this.hideBoxTab(); this.litTabs?.activeByKey("1") let tabCpu = this.shadowRoot!.querySelector('#tabpane-cpu'); - tabCpu!.setThreadData(data, scrollCallback); + tabCpu!.setThreadData(data, scrollCallback,scrollWakeUp); } displayMemData(data: ProcessMemStruct) { @@ -388,12 +493,13 @@ export class TraceSheet extends BaseElement { tabFlag!.setFlagObj(flagObj) } - boxSelection(selection: SelectionParam):boolean { + boxSelection(selection: SelectionParam): boolean { this.tabBoxChild!.hidden = true; this.selection = selection; if (selection.hasFps || selection.cpus.length > 0 || selection.threadIds.length > 0 || selection.funTids.length > 0 || selection.trackIds.length > 0 || selection.heapIds.length > 0 - || selection.nativeMemory.length > 0) { + || selection.nativeMemory.length > 0 || selection.cpuAbilityIds.length > 0 || selection.memoryAbilityIds.length > 0 || selection.diskAbilityIds.length > 0 || selection.networkAbilityIds.length > 0 + || selection.perfSampleIds.length > 0) { this.setAttribute("mode", "max") this.tabCurrentSelection!.hidden = true; this.tabBoxFlag!.hidden = true; @@ -413,6 +519,15 @@ export class TraceSheet extends BaseElement { this.tabBoxNMCallInfo!.hidden = selection.nativeMemory.length == 0 this.tabBoxNMemory!.hidden = selection.nativeMemory.length == 0 this.tabBoxNMSample!.hidden = selection.nativeMemory.length == 0 + + this.tabBoxLiveProcesses!.hidden = selection.cpuAbilityIds.length == 0 && selection.memoryAbilityIds.length == 0 && selection.diskAbilityIds.length == 0 && selection.networkAbilityIds.length == 0 + this.tabBoxHistoryProcesses!.hidden = selection.cpuAbilityIds.length == 0 && selection.memoryAbilityIds.length == 0 && selection.diskAbilityIds.length == 0 && selection.networkAbilityIds.length == 0 + this.tabBoxSystemCpu!.hidden = selection.cpuAbilityIds.length == 0 + this.tabBoxSystemMemory!.hidden = selection.memoryAbilityIds.length == 0 + this.tabBoxSystemDiskIo!.hidden = selection.diskAbilityIds.length == 0 + this.tabBoxSystemNetwork!.hidden = selection.networkAbilityIds.length == 0 + this.tabBoxPerfProfile!.hidden = selection.perfSampleIds.length == 0 + this.tabBoxPerfSample!.hidden = selection.perfSampleIds.length == 0 this.setBoxActiveKey(selection); return true; } else { @@ -439,6 +554,8 @@ export class TraceSheet extends BaseElement { this.tabBoxNMCallInfo!.hidden = !(this.selection!.nativeMemory.length > 0) this.tabBoxNMemory!.hidden = !(this.selection!.nativeMemory.length > 0) this.tabBoxNMSample!.hidden = !(this.selection!.nativeMemory.length > 0) + this.tabBoxPerfProfile!.hidden = !(this.selection!.perfSampleIds.length > 0) + this.tabBoxPerfSample!.hidden = !(this.selection!.perfSampleIds.length > 0) } setBoxActiveKey(val: SelectionParam) { @@ -460,10 +577,25 @@ export class TraceSheet extends BaseElement { } else if (val.heapIds.length > 0) { this.litTabs?.activeByKey("9") this.loadTabPaneData("9") - } else if(val.nativeMemory.length > 0) { + } else if (val.nativeMemory.length > 0) { this.litTabs?.activeByKey("16") this.loadTabPaneData("16") - }else{ + } else if (val.cpuAbilityIds.length > 0) { + this.litTabs?.activeByKey("32") + this.loadTabPaneData("32") + } else if (val.memoryAbilityIds.length > 0) { + this.litTabs?.activeByKey("33") + this.loadTabPaneData("33") + } else if (val.diskAbilityIds.length > 0) { + this.litTabs?.activeByKey("34") + this.loadTabPaneData("34") + } else if (val.networkAbilityIds.length > 0) { + this.litTabs?.activeByKey("35") + this.loadTabPaneData("35") + } else if (val.perfSampleIds.length > 0) { + this.litTabs?.activeByKey("20") + this.loadTabPaneData("20") + } else { this.litTabs?.activeByKey("1") this.loadTabPaneData("1") } @@ -512,6 +644,22 @@ export class TraceSheet extends BaseElement { this.tabNativeMemory!.data = this.selection; } else if (key == "19") { this.tabNativeSample!.data = this.selection; + } else if (key == "20") { + this.tabPerfProfile!.data = this.selection; + } else if (key == "21") { + this.tabPerfSample!.data = this.selection; + } else if (key == "30") { + this.tabLiveProcesses!.data = this.selection; + } else if (key == "31") { + this.tabHistoryProcesses!.data = this.selection; + } else if (key == "32") { + this.tabSystemCpu!.data = this.selection; + } else if (key == "33") { + this.tabSystemMemory!.data = this.selection; + } else if (key == "34") { + this.tabSystemDiskIo!.data = this.selection; + } else if (key == "35") { + this.tabSystemNetwork!.data = this.selection; } } @@ -534,6 +682,8 @@ export class TraceSheet extends BaseElement { this.tabBoxNMCallInfo!.hidden = true; this.tabBoxNMemory!.hidden = true; this.tabBoxNMSample!.hidden = true; + this.tabBoxPerfProfile!.hidden = true; + this.tabBoxPerfSample!.hidden = true; } hideOtherBoxTab(key: string) { @@ -549,6 +699,8 @@ export class TraceSheet extends BaseElement { this.tabBoxNMCallInfo!.hidden = true; this.tabBoxNMemory!.hidden = true; this.tabBoxNMSample!.hidden = true; + this.tabBoxPerfProfile!.hidden = true; + this.tabBoxPerfSample!.hidden = true; if (key == "11") { this.tabBoxPTS!.hidden = true; this.tabBoxContextSwitch!.hidden = true; diff --git a/host/ide/src/trace/component/trace/base/Utils.ts b/host/ide/src/trace/component/trace/base/Utils.ts index cb7e6dad238611e49ff712b5c3dc88695d98dd94..3a8d60fd09961dc34f4fceb317d7179f8971692d 100644 --- a/host/ide/src/trace/component/trace/base/Utils.ts +++ b/host/ide/src/trace/component/trace/base/Utils.ts @@ -148,23 +148,359 @@ export class Utils { return "-" + this.getByteWithUnit(Math.abs(bytes)) } let currentBytes = bytes - let kb1 = 1024 - let mb1 = 1048576 - let gb1 = 1073741824; // 1 gb + let kb1 = 1 << 10; + let mb1 = 1 << 10 << 10; + let gb1 = 1 << 10 << 10 << 10; // 1 gb let res = "" if (currentBytes > gb1) { res += (currentBytes / gb1).toFixed(2) + " Gb"; } else if (currentBytes > mb1) { res += (currentBytes / mb1).toFixed(2) + " Mb"; } else if (currentBytes > kb1) { - res += (currentBytes / kb1).toFixed(2) + " kb"; + res += (currentBytes / kb1).toFixed(2) + " Kb"; } else { - res += currentBytes + " byte"; + res += Math.round(currentBytes) + " byte"; } return res } + public static groupByMap(array: Array, key: string) { + let result = new Map(); + array.forEach(item => { + let value = item[key]; + if (!result.has(value)) { + result.set(value, []) + } + result.get(value).push(item); + }) + return result; + } + + public static groupBy(array: Array, key: string) { + return array.reduce((pre, current, index, arr) => { + (pre[current[key]] = pre[current[key]] || []).push(current); + return pre; + }, {}); + } + + public static timeMsFormat2p(ns: number) { + let currentNs = ns + let hour1 = 3600_000 + let minute1 = 60_000 + let second1 = 1_000; // 1 second + let res = "" + if (currentNs >= hour1) { + res += Math.floor(currentNs / hour1).toFixed(2) + "h" + return res + } + if (currentNs >= minute1) { + res += Math.floor(currentNs / minute1).toFixed(2) + "min" + return res + } + if (currentNs >= second1) { + res += Math.floor(currentNs / second1).toFixed(2) + "s" + return res + } + if (currentNs > 0) { + res += currentNs.toFixed(2) + "ms"; + return res + } + if (res == "") { + res = "0s"; + } + return res + } + + public static uuid(): string { + // @ts-ignore + return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c => (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)); + } + + public static MD5(uint8Array: any) { + function md5cycle(x: any, k: any) { + let a = x[0], b = x[1], c = x[2], d = x[3]; + + a = ff(a, b, c, d, k[0], 7, -680876936); + d = ff(d, a, b, c, k[1], 12, -389564586); + c = ff(c, d, a, b, k[2], 17, 606105819); + b = ff(b, c, d, a, k[3], 22, -1044525330); + a = ff(a, b, c, d, k[4], 7, -176418897); + d = ff(d, a, b, c, k[5], 12, 1200080426); + c = ff(c, d, a, b, k[6], 17, -1473231341); + b = ff(b, c, d, a, k[7], 22, -45705983); + a = ff(a, b, c, d, k[8], 7, 1770035416); + d = ff(d, a, b, c, k[9], 12, -1958414417); + c = ff(c, d, a, b, k[10], 17, -42063); + b = ff(b, c, d, a, k[11], 22, -1990404162); + a = ff(a, b, c, d, k[12], 7, 1804603682); + d = ff(d, a, b, c, k[13], 12, -40341101); + c = ff(c, d, a, b, k[14], 17, -1502002290); + b = ff(b, c, d, a, k[15], 22, 1236535329); + + a = gg(a, b, c, d, k[1], 5, -165796510); + d = gg(d, a, b, c, k[6], 9, -1069501632); + c = gg(c, d, a, b, k[11], 14, 643717713); + b = gg(b, c, d, a, k[0], 20, -373897302); + a = gg(a, b, c, d, k[5], 5, -701558691); + d = gg(d, a, b, c, k[10], 9, 38016083); + c = gg(c, d, a, b, k[15], 14, -660478335); + b = gg(b, c, d, a, k[4], 20, -405537848); + a = gg(a, b, c, d, k[9], 5, 568446438); + d = gg(d, a, b, c, k[14], 9, -1019803690); + c = gg(c, d, a, b, k[3], 14, -187363961); + b = gg(b, c, d, a, k[8], 20, 1163531501); + a = gg(a, b, c, d, k[13], 5, -1444681467); + d = gg(d, a, b, c, k[2], 9, -51403784); + c = gg(c, d, a, b, k[7], 14, 1735328473); + b = gg(b, c, d, a, k[12], 20, -1926607734); + + a = hh(a, b, c, d, k[5], 4, -378558); + d = hh(d, a, b, c, k[8], 11, -2022574463); + c = hh(c, d, a, b, k[11], 16, 1839030562); + b = hh(b, c, d, a, k[14], 23, -35309556); + a = hh(a, b, c, d, k[1], 4, -1530992060); + d = hh(d, a, b, c, k[4], 11, 1272893353); + c = hh(c, d, a, b, k[7], 16, -155497632); + b = hh(b, c, d, a, k[10], 23, -1094730640); + a = hh(a, b, c, d, k[13], 4, 681279174); + d = hh(d, a, b, c, k[0], 11, -358537222); + c = hh(c, d, a, b, k[3], 16, -722521979); + b = hh(b, c, d, a, k[6], 23, 76029189); + a = hh(a, b, c, d, k[9], 4, -640364487); + d = hh(d, a, b, c, k[12], 11, -421815835); + c = hh(c, d, a, b, k[15], 16, 530742520); + b = hh(b, c, d, a, k[2], 23, -995338651); + + a = ii(a, b, c, d, k[0], 6, -198630844); + d = ii(d, a, b, c, k[7], 10, 1126891415); + c = ii(c, d, a, b, k[14], 15, -1416354905); + b = ii(b, c, d, a, k[5], 21, -57434055); + a = ii(a, b, c, d, k[12], 6, 1700485571); + d = ii(d, a, b, c, k[3], 10, -1894986606); + c = ii(c, d, a, b, k[10], 15, -1051523); + b = ii(b, c, d, a, k[1], 21, -2054922799); + a = ii(a, b, c, d, k[8], 6, 1873313359); + d = ii(d, a, b, c, k[15], 10, -30611744); + c = ii(c, d, a, b, k[6], 15, -1560198380); + b = ii(b, c, d, a, k[13], 21, 1309151649); + a = ii(a, b, c, d, k[4], 6, -145523070); + d = ii(d, a, b, c, k[11], 10, -1120210379); + c = ii(c, d, a, b, k[2], 15, 718787259); + b = ii(b, c, d, a, k[9], 21, -343485551); + + x[0] = add32(a, x[0]); + x[1] = add32(b, x[1]); + x[2] = add32(c, x[2]); + x[3] = add32(d, x[3]); + + } + + function cmn(q: any, a: any, b: any, x: any, s: any, t: any) { + a = add32(add32(a, q), add32(x, t)); + return add32((a << s) | (a >>> (32 - s)), b); + } + + function ff(a: any, b: any, c: any, d: any, x: any, s: any, t: any) { + return cmn((b & c) | ((~b) & d), a, b, x, s, t); + } + + function gg(a: any, b: any, c: any, d: any, x: any, s: any, t: any) { + return cmn((b & d) | (c & (~d)), a, b, x, s, t); + } + + function hh(a: any, b: any, c: any, d: any, x: any, s: any, t: any) { + return cmn(b ^ c ^ d, a, b, x, s, t); + } + + function ii(a: any, b: any, c: any, d: any, x: any, s: any, t: any) { + return cmn(c ^ (b | (~d)), a, b, x, s, t); + } + + function md51(s: any) { + let n = s.length, + state = [1732584193, -271733879, -1732584194, 271733878], i; + for (i = 64; i <= s.length; i += 64) { + md5cycle(state, md5blk(s.subarray(i - 64, i))); + } + s = s.subarray(i - 64); + let tail = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + for (i = 0; i < s.length; i++) + tail[i >> 2] |= s[i] << ((i % 4) << 3); + tail[i >> 2] |= 0x80 << ((i % 4) << 3); + if (i > 55) { + md5cycle(state, tail); + for (i = 0; i < 16; i++) tail[i] = 0; + } + tail[14] = n * 8; + md5cycle(state, tail); + return state; + } + + /* there needs to be support for Unicode here, + * unless we pretend that we can redefine the MD-5 + * algorithm for multi-byte characters (perhaps + * by adding every four 16-bit characters and + * shortening the sum to 32 bits). Otherwise + * I suggest performing MD-5 as if every character + * was two bytes--e.g., 0040 0025 = @%--but then + * how will an ordinary MD-5 sum be matched? + * There is no way to standardize text to something + * like UTF-8 before transformation; speed cost is + * utterly prohibitive. The JavaScript standard + * itself needs to look at this: it should start + * providing access to strings as preformed UTF-8 + * 8-bit unsigned value arrays. + */ + function md5blk(s: any) { /* I figured global was faster. */ + let md5blks = [], i; /* Andy King said do it this way. */ + for (i = 0; i < 64; i += 4) { + md5blks[i >> 2] = s[i] + + (s[i + 1] << 8) + + (s[i + 2] << 16) + + (s[i + 3] << 24); + } + return md5blks; + } + + let hex_chr = '0123456789abcdef'.split(''); + + function rhex(n: any) { + let s = '', j = 0; + for (; j < 4; j++) + s += hex_chr[(n >> (j * 8 + 4)) & 0x0F] + + hex_chr[(n >> (j * 8)) & 0x0F]; + return s; + } + + function hex(x: any) { + for (let i = 0; i < x.length; i++) + x[i] = rhex(x[i]); + return x.join(''); + } + + function md5(s: any) { + return hex(md51(s)); + } + + function add32(a: any, b: any) { + return (a + b) & 0xFFFFFFFF; + } + + return md5(uint8Array); + }; + + public static getBinaryByteWithUnit(bytes: number): string { + if (bytes == 0) { + return "0Bytes" + } + let currentBytes = bytes + let kib1 = 1024 + let mib1 = 1024 * 1024 + let gib1 = 1024 * 1024 * 1024; + let res = "" + if (currentBytes > gib1) { + res += (currentBytes / gib1).toFixed(2) + "Gib"; + } else if (currentBytes > mib1) { + res += (currentBytes / mib1).toFixed(2) + "Mib"; + } else if (currentBytes > kib1) { + res += (currentBytes / kib1).toFixed(2) + "kib"; + } else { + res += currentBytes.toFixed(2) + "Bytes"; + } + return res + } + + public static getTimeStampHMS(ns: number): string { + let currentNs = ns + let hour1 = 3600_000_000_000 + let minute1 = 60_000_000_000 + let second1 = 1_000_000_000; // 1 second + let millisecond1 = 1_000_000; // 1 millisecond + let microsecond1 = 1_000; // 1 microsecond + let res = ""; + if (currentNs >= hour1) { + res += this.getCompletionTime(Math.floor(currentNs / hour1), 2) + ":"; + currentNs = currentNs - Math.floor(currentNs / hour1) * hour1 + } + if (currentNs >= minute1) { + res += this.getCompletionTime(Math.floor(currentNs / minute1), 2) + ":"; + currentNs = currentNs - Math.floor(ns / minute1) * minute1 + } + if (currentNs >= second1) { + res += this.getCompletionTime(Math.floor(currentNs / second1), 2) + ":"; + currentNs = currentNs - Math.floor(currentNs / second1) * second1 + } else { + res += '00:' + } + if (currentNs >= millisecond1) { + res += this.getCompletionTime(Math.floor(currentNs / millisecond1), 3) + "."; + currentNs = currentNs - Math.floor(currentNs / millisecond1) * millisecond1 + } else { + res += "000." + } + if (currentNs >= microsecond1) { + res += this.getCompletionTime(Math.floor(currentNs / microsecond1), 3) + "."; + currentNs = currentNs - Math.floor(currentNs / microsecond1) * microsecond1 + } else { + res += "000" + } + if (currentNs > 0) { + res += this.getCompletionTime(currentNs, 3); + } + if (res == "") { + res = ns + ""; + } + return res + } + + public static getDurString(ns: number): string { + let currentNs = ns + let minute1 = 60_000_000_000 + let second1 = 1_000_000_000; + let millisecond1 = 1_000_000; + let res = ""; + if (currentNs >= minute1) { + res += Math.floor(currentNs / minute1) + ":"; + currentNs = currentNs - Math.floor(ns / minute1) * minute1 + } + if (currentNs >= second1) { + res += Math.floor(currentNs / second1) + "."; + currentNs = currentNs - Math.floor(currentNs / second1) * second1; + res += Math.floor(currentNs / millisecond1) + "s "; + return res; + } + if (currentNs >= millisecond1) { + res += Math.floor(currentNs / millisecond1) + "ms "; + return res; + } + if (res == "") { + res = ns + ""; + } + return res + } + + private static getCompletionTime(time: number, maxLength: number): string { + if (maxLength == 2) { + if (time.toString().length == 2) { + return '' + time; + } else { + return '0' + time; + } + } else if (maxLength == 3) { + if (time.toString().length == 3) { + return time.toString(); + } else if (time.toString().length == 2) { + return '0' + time; + } else { + return '00' + time; + } + } else { + return '0' + } + } + public getStatusMap(): Map { return Utils.statusMap; } + } diff --git a/host/ide/src/trace/component/trace/search/Search.ts b/host/ide/src/trace/component/trace/search/Search.ts index 23ff8f918a5925be94ed571142ac4d903073f40c..1e9607df9c8a3929263a6efad8e97576471c12f1 100644 --- a/host/ide/src/trace/component/trace/search/Search.ts +++ b/host/ide/src/trace/component/trace/search/Search.ts @@ -40,7 +40,7 @@ export class LitSearch extends BaseElement { set index(value: number) { this._index = value; - this.indexEL!.textContent = `${value+1}`; + this.indexEL!.textContent = `${value + 1}`; } get total(): number { @@ -89,9 +89,10 @@ export class LitSearch extends BaseElement { this.list = []; } - blur(){ + blur() { this.search?.blur(); } + initElements(): void { this.search = this.shadowRoot!.querySelector("input"); this.totalEL = this.shadowRoot!.querySelector("#total"); @@ -116,18 +117,21 @@ export class LitSearch extends BaseElement { this.dispatchEvent(new CustomEvent("previous-data", { detail: { value: this.search!.value - } + }, + composed:false })); } else { this.dispatchEvent(new CustomEvent("next-data", { detail: { value: this.search!.value - } + }, + composed:false })); } } else { this.valueChangeHandler?.(this.search!.value); } + e.stopPropagation(); }); this.shadowRoot?.querySelector("#arrow-left")?.addEventListener("click", (e) => { this.dispatchEvent(new CustomEvent("previous-data", { @@ -147,70 +151,73 @@ export class LitSearch extends BaseElement { initHtml(): string { return ` - - + + `; } - } diff --git a/host/ide/src/trace/component/trace/sheet/TabPaneBoxChild.ts b/host/ide/src/trace/component/trace/sheet/TabPaneBoxChild.ts index c37351bf74ec91f3ef5d077f474657fda33ffda8..7b0f2c3470e086e2c7676f4fcb0c604fa2b1beef 100644 --- a/host/ide/src/trace/component/trace/sheet/TabPaneBoxChild.ts +++ b/host/ide/src/trace/component/trace/sheet/TabPaneBoxChild.ts @@ -30,7 +30,7 @@ export class TabPaneBoxChild extends BaseElement { set data(val: BoxJumpParam) { // @ts-ignore - this.tbl?.shadowRoot?.querySelector(".table")?.style?.height = (this.parentElement!.clientHeight - 45)+"px"; + this.tbl?.shadowRoot?.querySelector(".table")?.style?.height = (this.parentElement!.clientHeight - 45) + "px"; this.range!.textContent = "Selected range: " + parseFloat(((val.rightNs - val.leftNs) / 1000000.0).toFixed(5)) + " ms" if (this.loadDataInCache) { this.getDataByCache(val).then((arr) => { @@ -53,7 +53,7 @@ export class TabPaneBoxChild extends BaseElement { new ResizeObserver((entries) => { if (this.parentElement?.clientHeight != 0) { // @ts-ignore - this.tbl?.shadowRoot.querySelector(".table").style.height = (this.parentElement.clientHeight - 45)+"px" + this.tbl?.shadowRoot.querySelector(".table").style.height = (this.parentElement.clientHeight - 45) + "px" this.tbl?.reMeauseHeight() } }).observe(this.parentElement!) @@ -83,13 +83,12 @@ export class TabPaneBoxChild extends BaseElement { getDataByCache(val: BoxJumpParam): Promise> { return new Promise>((resolve, reject) => { - let time = Date.now(); let arr: Array = []; SpSystemTrace.SPT_DATA.map((spt) => { let b1 = (val.state != undefined && val.state != '') ? spt.state == val.state : true let b2 = (val.processId != undefined && val.processId != -1) ? spt.processId == val.processId : true let b3 = (val.threadId != undefined && val.threadId != -1) ? spt.threadId == val.threadId : true - if(!(spt.end_ts < val.leftNs || spt.start_ts > val.rightNs) && b1 && b2 && b3){ + if (!(spt.end_ts < val.leftNs || spt.start_ts > val.rightNs) && b1 && b2 && b3) { let sptChild = new SPTChild(); sptChild.startTime = Utils.getTimeString(spt.start_ts) sptChild.state = Utils.getEndState(spt.state)! @@ -107,23 +106,30 @@ export class TabPaneBoxChild extends BaseElement { initHtml(): string { return ` - - - - - - - - - - - + + + + + + + + + + + + + + + + + + `; } diff --git a/host/ide/src/trace/component/trace/sheet/TabPaneContextSwitch.ts b/host/ide/src/trace/component/trace/sheet/TabPaneContextSwitch.ts index 0098d18d90f375868153e0469ce679acee218153..309ddb3a8b19a941ef9cdd36871cac6e358bfad2 100644 --- a/host/ide/src/trace/component/trace/sheet/TabPaneContextSwitch.ts +++ b/host/ide/src/trace/component/trace/sheet/TabPaneContextSwitch.ts @@ -33,7 +33,7 @@ export class TabPaneContextSwitch extends BaseElement { set data(val: SelectionParam | any) { // @ts-ignore - this.tbl?.shadowRoot.querySelector(".table").style.height = (this.parentElement.clientHeight - 45)+"px" + this.tbl?.shadowRoot.querySelector(".table").style.height = (this.parentElement.clientHeight - 45) + "px" this.range!.textContent = "Selected range: " + parseFloat(((val.rightNs - val.leftNs) / 1000000.0).toFixed(5)) + " ms" if (this.loadDataInCache) { this.queryDataInCacheData(val).then((arr) => { @@ -50,7 +50,7 @@ export class TabPaneContextSwitch extends BaseElement { new ResizeObserver((entries) => { if (this.parentElement?.clientHeight != 0) { // @ts-ignore - this.tbl?.shadowRoot.querySelector(".table").style.height = (this.parentElement.clientHeight - 45)+"px" + this.tbl?.shadowRoot.querySelector(".table").style.height = (this.parentElement.clientHeight - 45) + "px" this.tbl?.reMeauseHeight() } }).observe(this.parentElement!) @@ -61,8 +61,8 @@ export class TabPaneContextSwitch extends BaseElement { let pMap: Map = new Map(); let ptMap: Map = new Map(); let ptsMap: Map = new Map(); - SpSystemTrace.SPT_DATA.map((d)=>{ - if(!(d.end_ts < val.leftNs || d.start_ts > val.rightNs)){ + SpSystemTrace.SPT_DATA.map((d) => { + if (!(d.end_ts < val.leftNs || d.start_ts > val.rightNs)) { if (pMap.has(d.processId + "")) { let obj1 = pMap.get(d.processId + ""); obj1!.count++; @@ -244,19 +244,20 @@ export class TabPaneContextSwitch extends BaseElement { initHtml(): string { return ` - - - - - - + + + + + + + + `; } - } \ No newline at end of file diff --git a/host/ide/src/trace/component/trace/sheet/TabPaneCounter.ts b/host/ide/src/trace/component/trace/sheet/TabPaneCounter.ts index 582811f47cd5d8fe5010859197fb228720f38110..e4d646769c6aae50f9c6fc69cbe18c97aeb954cc 100644 --- a/host/ide/src/trace/component/trace/sheet/TabPaneCounter.ts +++ b/host/ide/src/trace/component/trace/sheet/TabPaneCounter.ts @@ -33,7 +33,7 @@ export class TabPaneCounter extends BaseElement { let sumCount = 0; for (let key of collect.keys()) { let counters = collect.get(key); - let list:Array = []; + let list: Array = []; let index = counters!.findIndex((item) => item.startTime >= val.leftNs); if (index != -1) { list = counters!.splice(index > 0 ? index - 1 : index) @@ -68,25 +68,34 @@ export class TabPaneCounter extends BaseElement { initHtml(): string { return ` - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + `; } diff --git a/host/ide/src/trace/component/trace/sheet/TabPaneCpu.ts b/host/ide/src/trace/component/trace/sheet/TabPaneCpu.ts index cb5a3a769f90dbb9e4eb9bc55edb379707067ed8..6010d75ab9b91ec34bfa1e93e9d5ce00a4463ccf 100644 --- a/host/ide/src/trace/component/trace/sheet/TabPaneCpu.ts +++ b/host/ide/src/trace/component/trace/sheet/TabPaneCpu.ts @@ -40,19 +40,20 @@ export class TabPaneCpu extends BaseElement { initHtml(): string { return ` - - - - - - + + + + + + + + `; } - } \ No newline at end of file diff --git a/host/ide/src/trace/component/trace/sheet/TabPaneCpuAbility.ts b/host/ide/src/trace/component/trace/sheet/TabPaneCpuAbility.ts new file mode 100644 index 0000000000000000000000000000000000000000..4ce6a98bbe18770357b1544965f679a3842a410b --- /dev/null +++ b/host/ide/src/trace/component/trace/sheet/TabPaneCpuAbility.ts @@ -0,0 +1,165 @@ +/* + * 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. + */ + +import {BaseElement, element} from "../../../../base-ui/BaseElement.js"; +import {LitTable} from "../../../../base-ui/table/lit-table.js"; +import {SelectionParam} from "../../../bean/BoxSelection.js"; +import {getTabCpuAbilityData,} from "../../../database/SqlLite.js"; +import {SystemCpuSummary} from "../../../bean/AbilityMonitor.js"; +import {Utils} from "../base/Utils.js"; +import {ColorUtils} from "../base/ColorUtils.js"; +import "../../../component/SpFilter.js"; + +@element('tabpane-cpu-ability') +export class TabPaneCpuAbility extends BaseElement { + private tbl: LitTable | null | undefined; + private source: Array = []; + private queryResult: Array = [] + private float: HTMLDivElement | null | undefined; + private search: HTMLInputElement | undefined | null + + set data(val: SelectionParam | any) { + // @ts-ignore + this.tbl?.shadowRoot.querySelector(".table").style.height = (this.parentElement.clientHeight - 45) + "px" + this.queryDataByDB(val) + } + + initElements(): void { + this.tbl = this.shadowRoot?.querySelector('#tb-cpu-ability'); + new ResizeObserver((entries) => { + if (this.parentElement?.clientHeight != 0) { + // @ts-ignore + this.tbl?.shadowRoot.querySelector(".table").style.height = (this.parentElement.clientHeight - 45) + "px" + this.tbl?.reMeauseHeight() + } + }).observe(this.parentElement!) + this.tbl!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortByColumn(evt.detail) + }); + } + + filterData() { + if (this.queryResult.length > 0) { + let filter = this.queryResult.filter((item) => { + let array = this.toCpuAbilityArray(item) + let isInclude = array.filter(value => value.indexOf(this.search!.value) > -1); + return isInclude.length > 0 + }); + if (filter.length > 0) { + this.source = filter; + this.tbl!.recycleDataSource = this.source; + } else { + this.source = [] + this.tbl!.recycleDataSource = []; + } + } + } + + toCpuAbilityArray(systemCpuSummary: SystemCpuSummary): any[] { + let array: Array = [] + array.push(systemCpuSummary.startTimeStr) + array.push(systemCpuSummary.durationStr) + array.push(systemCpuSummary.totalLoadStr) + array.push(systemCpuSummary.userLoadStr) + array.push(systemCpuSummary.systemLoadStr) + array.push(systemCpuSummary.threadsStr) + return array + } + + queryDataByDB(val: SelectionParam | any) { + getTabCpuAbilityData(val.leftNs, val.rightNs).then(result => { + if (result.length != null && result.length > 0) { + for (const systemCpuSummary of result) { + if (systemCpuSummary.startTime == 0) { + systemCpuSummary.startTimeStr = '0:000.000.000'; + } else { + systemCpuSummary.startTimeStr = Utils.getTimeStampHMS(systemCpuSummary.startTime); + } + systemCpuSummary.durationStr = Utils.getDurString(systemCpuSummary.duration); + systemCpuSummary.totalLoadStr = (systemCpuSummary.totalLoad).toFixed(2) + "%" + systemCpuSummary.userLoadStr = (systemCpuSummary.userLoad).toFixed(2) + "%" + systemCpuSummary.systemLoadStr = (systemCpuSummary.systemLoad).toFixed(2) + "%" + systemCpuSummary.threadsStr = ColorUtils.formatNumberComma(systemCpuSummary.threads); + } + this.source = result + this.queryResult = result; + this.tbl!.recycleDataSource = this.source + } else { + this.source = [] + this.queryResult = [] + this.tbl!.recycleDataSource = [] + } + }) + } + + initHtml(): string { + return ` + + + + + + + + + + + + + + + + `; + } + + sortByColumn(detail: any) { + // @ts-ignore + function compare(property, sort, type) { + return function (a: SystemCpuSummary, b: SystemCpuSummary) { + if (type === 'number') { + // @ts-ignore + return sort === 2 ? parseFloat(b[property]) - parseFloat(a[property]) : parseFloat(a[property]) - parseFloat(b[property]); + } else { + // @ts-ignore + if (b[property] > a[property]) { + return sort === 2 ? 1 : -1; + } else { // @ts-ignore + if (b[property] == a[property]) { + return 0; + } else { + return sort === 2 ? -1 : 1; + } + } + } + } + } + + if (detail.key === 'startTime') { + this.source.sort(compare(detail.key, detail.sort, 'string')) + } else { + this.source.sort(compare(detail.key, detail.sort, 'number')) + } + this.tbl!.dataSource = this.source; + } + +} \ No newline at end of file diff --git a/host/ide/src/trace/component/trace/sheet/TabPaneCpuByProcess.ts b/host/ide/src/trace/component/trace/sheet/TabPaneCpuByProcess.ts index 5537ba596159ba28b00eada557613f78b5e82969..21d381c4175e560c750ab2a8473e854b2442af8e 100644 --- a/host/ide/src/trace/component/trace/sheet/TabPaneCpuByProcess.ts +++ b/host/ide/src/trace/component/trace/sheet/TabPaneCpuByProcess.ts @@ -62,21 +62,26 @@ export class TabPaneCpuByProcess extends BaseElement { initHtml(): string { return ` - - - - - - - - - + + + + + + + + + + + + + + `; } diff --git a/host/ide/src/trace/component/trace/sheet/TabPaneCpuByThread.ts b/host/ide/src/trace/component/trace/sheet/TabPaneCpuByThread.ts index 69192ddcf5a4bfe3c422a1d3b242806ae7ed23e2..8248c2a3bad74f0699e9617abc2c76cbbe2ea1d4 100644 --- a/host/ide/src/trace/component/trace/sheet/TabPaneCpuByThread.ts +++ b/host/ide/src/trace/component/trace/sheet/TabPaneCpuByThread.ts @@ -64,23 +64,30 @@ export class TabPaneCpuByThread extends BaseElement { initHtml(): string { return ` - - - - - - - - - - - + + + + + + + + + + + + + + + + + + `; } diff --git a/host/ide/src/trace/component/trace/sheet/TabPaneCpuUsage.ts b/host/ide/src/trace/component/trace/sheet/TabPaneCpuUsage.ts index e66a633683079dc4fe57679590b0db39d30e8ca5..8d3b9b1378290201b2a1d4b136ea04c78ba13a1d 100644 --- a/host/ide/src/trace/component/trace/sheet/TabPaneCpuUsage.ts +++ b/host/ide/src/trace/component/trace/sheet/TabPaneCpuUsage.ts @@ -152,24 +152,32 @@ export class TabPaneCpuUsage extends BaseElement { initHtml(): string { return ` - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + `; } } \ No newline at end of file diff --git a/host/ide/src/trace/component/trace/sheet/TabPaneCurrentSelection.ts b/host/ide/src/trace/component/trace/sheet/TabPaneCurrentSelection.ts index 6ffdaf1669a00a2177962e936eebcb94253ec909..5757273a204b651e79ab602a082c2cf28cf78071 100644 --- a/host/ide/src/trace/component/trace/sheet/TabPaneCurrentSelection.ts +++ b/host/ide/src/trace/component/trace/sheet/TabPaneCurrentSelection.ts @@ -20,8 +20,10 @@ import "../../../../base-ui/table/lit-table-column.js"; import { queryBinderArgsByArgset, - queryWakeUpThread_WakeThread, - queryWakeUpThread_WakeTime + queryThreadWakeUp, + queryThreadWakeUpFrom, + queryWakeUpFromThread_WakeThread, + queryWakeUpFromThread_WakeTime, } from "../../../database/SqlLite.js"; import {WakeupBean} from "../../../bean/WakeupBean.js"; import {ThreadStruct} from "../../../bean/ThreadStruct.js"; @@ -127,7 +129,7 @@ export class TabPaneCurrentSelection extends BaseElement { list.push({name: 'Duration', value: getTimeString(data.dur || 0)}) list.push({name: 'Prio', value: data.priority || 0}) list.push({name: 'End State', value: state}) - this.queryWakeUpData(data).then((bean) => { + this.queryCPUWakeUpFromData(data).then((bean) => { if (callback) { callback(bean) } @@ -209,7 +211,7 @@ export class TabPaneCurrentSelection extends BaseElement { } - setThreadData(data: ThreadStruct, scrollCallback: ((d: any) => void) | undefined) {//线程信息 + setThreadData(data: ThreadStruct, scrollCallback: ((d: any) => void) | undefined,scrollWakeUp:(d:any) => void | undefined) {//线程信息 this.initCanvas() let leftTitle: HTMLElement | null | undefined = this?.shadowRoot?.querySelector("#leftTitle"); let rightTitle: HTMLElement | null | undefined = this?.shadowRoot?.querySelector("#rightTitle"); @@ -217,7 +219,7 @@ export class TabPaneCurrentSelection extends BaseElement { rightTitle.style.visibility = "hidden" } if (leftTitle) { - leftTitle.innerText = "Counter Details" + leftTitle.innerText = "Thread State" } let list: any[] = [] list.push({name: 'StartTime', value: getTimeString(data.startTime || 0)}) @@ -248,21 +250,76 @@ export class TabPaneCurrentSelection extends BaseElement { processName = data.name; } list.push({name: 'Process', value: processName + " [" + data.pid + "] "}) - this.tbl!.dataSource = list - this.tbl?.shadowRoot?.querySelector("#state-click")?.addEventListener("click", () => { - //线程点击 - if (scrollCallback) { - scrollCallback(data) + let cpu = new CpuStruct(); + cpu.id = data.id; + cpu.startTime = data.startTime; + Promise.all([this.queryThreadWakeUpFromData(data.id!,data.startTime!,data.dur!),this.queryThreadWakeUpData(data.id!,data.startTime!,data.dur!)]).then((result)=>{ + let fromBean = result[0] + let wakeUps = result[1]; + if(fromBean != null && fromBean != undefined && fromBean.pid != 0 && fromBean.tid != 0){ + list.push({ + name: 'wakeup from tid', value: `
+
${fromBean.tid}
+ +
` + }) + } + if(wakeUps != null){ + for (let key in wakeUps) { + list.push({ + name: 'wakeup tid', value: `
+
${wakeUps[key].tid}
+ +
` + }) + } + } + this.tbl!.dataSource = list + this.tbl?.shadowRoot?.querySelector("#state-click")?.addEventListener("click", () => { + //线程点击 + if (scrollCallback) { + scrollCallback(data) + } + }) + this.tbl?.shadowRoot?.querySelector("#wakeup-from")?.addEventListener("click", (e) => { + //点击跳转,唤醒和被唤醒的 线程 + if(fromBean && scrollWakeUp){ + scrollWakeUp({ + processId: fromBean.pid, + tid: fromBean.tid, + startTime: fromBean.ts, + }) + } + }) + if(wakeUps){ + for (let key in wakeUps) { + this.tbl?.shadowRoot?.querySelector(`#wakeup-${key}`)?.addEventListener("click", (e) => { + //点击跳转,唤醒和被唤醒的 线程 + let up = wakeUps[key]; + if(up && scrollWakeUp != undefined){ + scrollWakeUp({ + tid: up.tid, + startTime: up.ts, + processId:up.pid, + }) + } + }) + } } }) } - async queryWakeUpData(data: CpuStruct) { + /** + * 查询出 线程被唤醒的 线程信息 + * @param data + */ + async queryCPUWakeUpFromData(data: CpuStruct) { + // console.log(data); let wb: WakeupBean | null = null if (data.id == undefined || data.startTime == undefined) { return null } - let wakeupTimes = await queryWakeUpThread_WakeTime(data.id, data.startTime)// 3,4835380000 + let wakeupTimes = await queryWakeUpFromThread_WakeTime(data.id, data.startTime)// 3,4835380000 if (wakeupTimes != undefined && wakeupTimes.length > 0) { let wakeupTime = wakeupTimes[0] if (wakeupTime.wakeTs != undefined && wakeupTime.preRow != undefined && wakeupTime.wakeTs < wakeupTime.preRow) { @@ -271,7 +328,7 @@ export class TabPaneCurrentSelection extends BaseElement { if (wakeupTime.wakeTs == undefined) { return null } - let wakeupBeans = await queryWakeUpThread_WakeThread(wakeupTime.wakeTs) + let wakeupBeans = await queryWakeUpFromThread_WakeThread(wakeupTime.wakeTs) if (wakeupBeans != undefined && wakeupBeans.length > 0) { wb = wakeupBeans[0] if (wb != null) { @@ -292,6 +349,32 @@ export class TabPaneCurrentSelection extends BaseElement { return wb } + /** + * 查询出 线程唤醒了哪些线程信息 + * @param data + */ + async queryThreadWakeUpFromData(itid: number, startTime: number,dur:number) : Promise { + let wakeUps = await queryThreadWakeUpFrom(itid, startTime,dur)// 3,4835380000 + if (wakeUps != undefined && wakeUps.length > 0) { + return wakeUps[0]; + } + } + /** + * 查询出 线程唤醒了哪些线程信息 + * @param data + */ + async queryThreadWakeUpData(itid: number, startTime: number,dur:number) : Promise> { + let list :Array = []; + if (itid == undefined || startTime == undefined) { + return list + } + let wakeUps = await queryThreadWakeUp(itid, startTime,dur)// 3,4835380000 + if (wakeUps != undefined && wakeUps.length > 0) { + list.push(...wakeUps) + } + return list + } + initCanvas(): HTMLCanvasElement | null { let canvas = this.shadowRoot!.querySelector("#rightDraw") let width = getComputedStyle(this.tbl!).getPropertyValue("width") @@ -342,7 +425,7 @@ export class TabPaneCurrentSelection extends BaseElement { let strList = [] strList.push("wakeup @ " + getTimeString(wakeupBean?.wakeupTime || 0) + " on CPU " + wakeupBean?.cpu + " by") strList.push("P:" + wakeupBean?.process + " [ " + wakeupBean?.pid + " ]") - strList.push("F:" + wakeupBean?.thread + " [ " + wakeupBean?.tid + " ]") + strList.push("T:" + wakeupBean?.thread + " [ " + wakeupBean?.tid + " ]") strList.forEach((str, index) => { if (context != null) { context.fillText(str, 40, 40 + 16 * index) @@ -446,5 +529,4 @@ export class TabPaneCurrentSelection extends BaseElement {
`; } - } diff --git a/host/ide/src/trace/component/trace/sheet/TabPaneDiskAbility.ts b/host/ide/src/trace/component/trace/sheet/TabPaneDiskAbility.ts new file mode 100644 index 0000000000000000000000000000000000000000..646988804cd5a17829c3460facb3fb24572d6c7c --- /dev/null +++ b/host/ide/src/trace/component/trace/sheet/TabPaneDiskAbility.ts @@ -0,0 +1,178 @@ +/* + * 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. + */ + +import {BaseElement, element} from "../../../../base-ui/BaseElement.js"; +import {LitTable} from "../../../../base-ui/table/lit-table.js"; +import {SelectionParam} from "../../../bean/BoxSelection.js"; +import {getTabDiskAbilityData} from "../../../database/SqlLite.js"; +import {SystemDiskIOSummary} from "../../../bean/AbilityMonitor.js"; +import {Utils} from "../base/Utils.js"; +import {ColorUtils} from "../base/ColorUtils.js"; +import "../../../component/SpFilter.js"; + +@element('tabpane-disk-ability') +export class TabPaneDiskAbility extends BaseElement { + private tbl: LitTable | null | undefined; + private source: Array = []; + private queryResult: Array = [] + private search: HTMLInputElement | undefined | null + + set data(val: SelectionParam | any) { + // @ts-ignore + this.tbl?.shadowRoot.querySelector(".table").style.height = (this.parentElement.clientHeight - 45) + "px" + this.queryDataByDB(val) + } + + initElements(): void { + this.tbl = this.shadowRoot?.querySelector('#tb-disk-ability'); + new ResizeObserver((entries) => { + if (this.parentElement?.clientHeight != 0) { + // @ts-ignore + this.tbl!.shadowRoot.querySelector(".table").style.height = (this.parentElement.clientHeight - 45) + "px" + this.tbl!.reMeauseHeight() + } + }).observe(this.parentElement!) + this.tbl!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortByColumn(evt.detail) + }); + } + + filterData() { + if (this.queryResult.length > 0) { + let filter = this.queryResult.filter((item) => { + let array = this.toDiskAbilityArray(item) + let isInclude = array.filter(value => value.indexOf(this.search!.value) > -1); + return isInclude.length > 0 + }); + if (filter.length > 0) { + this.source = filter; + this.tbl!.recycleDataSource = this.source; + } else { + this.source = [] + this.tbl!.recycleDataSource = []; + } + } + } + + toDiskAbilityArray(systemDiskIOSummary: SystemDiskIOSummary): any[] { + let array: Array = [] + array.push(systemDiskIOSummary.startTimeStr) + array.push(systemDiskIOSummary.durationStr) + array.push(systemDiskIOSummary.dataReadStr) + array.push(systemDiskIOSummary.dataReadSecStr) + array.push(systemDiskIOSummary.dataWriteStr) + array.push(systemDiskIOSummary.readsInStr) + array.push(systemDiskIOSummary.readsInSecStr) + array.push(systemDiskIOSummary.writeOutStr) + array.push(systemDiskIOSummary.writeOutSecStr) + return array + } + + queryDataByDB(val: SelectionParam | any) { + getTabDiskAbilityData(val.leftNs, val.rightNs).then((result) => { + if (result.length != null && result.length > 0) { + for (const systemDiskIOSummary of result) { + if (systemDiskIOSummary.startTime <= 0) { + systemDiskIOSummary.startTimeStr = '0:000.000.000'; + } else { + systemDiskIOSummary.startTimeStr = Utils.getTimeStampHMS(systemDiskIOSummary.startTime); + } + systemDiskIOSummary.durationStr = Utils.getDurString(systemDiskIOSummary.duration); + systemDiskIOSummary.dataReadStr = systemDiskIOSummary.dataRead + "KB"; + systemDiskIOSummary.dataReadSecStr = systemDiskIOSummary.dataReadSec + "KB/S"; + systemDiskIOSummary.dataWriteStr = systemDiskIOSummary.dataWrite + "KB"; + systemDiskIOSummary.dataWriteSecStr = systemDiskIOSummary.dataWriteSec + "KB/S"; + systemDiskIOSummary.readsInStr = ColorUtils.formatNumberComma(systemDiskIOSummary.readsIn); + systemDiskIOSummary.readsInSecStr = systemDiskIOSummary.readsInSec.toString(); + systemDiskIOSummary.writeOutStr = ColorUtils.formatNumberComma(systemDiskIOSummary.writeOut); + systemDiskIOSummary.writeOutSecStr = systemDiskIOSummary.writeOutSec.toString(); + } + this.source = result; + this.queryResult = result; + this.tbl!.recycleDataSource = result; + } else { + this.source = []; + this.queryResult = [] + this.tbl!.recycleDataSource = [] + } + }) + } + + initHtml(): string { + return ` + + + + + + + + + + + + + + + + + + + + + + + + `; + } + + sortByColumn(detail: any) { + // @ts-ignore + function compare(property, sort, type) { + return function (a: SystemDiskIOSummary, b: SystemDiskIOSummary) { + if (type === 'number') { + // @ts-ignore + return sort === 2 ? parseFloat(b[property]) - parseFloat(a[property]) : parseFloat(a[property]) - parseFloat(b[property]); + } else { + // @ts-ignore + if (b[property] > a[property]) { + return sort === 2 ? 1 : -1; + } else { // @ts-ignore + if (b[property] == a[property]) { + return 0; + } else { + return sort === 2 ? -1 : 1; + } + } + } + } + } + + if (detail.key === 'startTime') { + this.source.sort(compare(detail.key, detail.sort, 'string')) + } else { + this.source.sort(compare(detail.key, detail.sort, 'number')) + } + this.tbl!.dataSource = this.source; + } + +} \ No newline at end of file diff --git a/host/ide/src/trace/component/trace/sheet/TabPaneFilter.ts b/host/ide/src/trace/component/trace/sheet/TabPaneFilter.ts index 4ce88d324c97cdd4f4759eb2f36505c50010bb9f..60f4ec39982522c2d5bab3dff7c086c9c6aeeb34 100644 --- a/host/ide/src/trace/component/trace/sheet/TabPaneFilter.ts +++ b/host/ide/src/trace/component/trace/sheet/TabPaneFilter.ts @@ -18,347 +18,722 @@ import "../../../../base-ui/select/LitSelect.js"; import "../../../../base-ui/select/LitSelectOption.js"; import '../../../../base-ui/icon/LitIcon.js' import {LitIcon} from "../../../../base-ui/icon/LitIcon.js"; +import {LitSelect} from "../../../../base-ui/select/LitSelect.js"; +import "../../../../base-ui/popover/LitPopoverV.js" +import {LitCheckBox} from "../../../../base-ui/checkbox/LitCheckBox.js"; -export interface FilterData{ - inputValue:string, - firstSelect:string|null|undefined, - secondSelect:string|null|undefined, - mark:boolean|null|undefined, - icon:string|null, +export interface FilterData { + inputValue: string, + firstSelect: string | null | undefined, + secondSelect: string | null | undefined, + mark: boolean | null | undefined, + icon: string | null, +} + +export interface MiningData { + type: string, + item: any | null | undefined, + remove?: Array | null | undefined, } @element('tab-pane-filter') export class TabPaneFilter extends BaseElement { - private filterInputEL: HTMLInputElement | null | undefined; - private firstSelectEL: HTMLSelectElement | null | undefined; - private secondSelectEL: HTMLSelectElement | null | undefined; - private markButtonEL: HTMLButtonElement | null | undefined; - private iconEL: LitIcon | null | undefined; - private getFilter: ((e:FilterData)=>void) | undefined; - - initElements(): void { - // this.firstSelectEL = this.shadowRoot?.querySelector("#first-select") - // this.secondSelectEL = this.shadowRoot?.querySelector("#second-select") - this.filterInputEL = this.shadowRoot?.querySelector("#filter-input") - this.markButtonEL = this.shadowRoot?.querySelector("#mark") - this.iconEL = this.shadowRoot?.querySelector("#icon") - - this.iconEL!.onclick=(e)=>{ - if (this.iconEL!.name == "statistics") { - this.iconEL!.name = "menu"; - this.iconEL!.size = 18; - if (this.getFilter) { - this.getFilter({ - inputValue:this.filterInputEL!.value, - firstSelect:this.firstSelectEL?.value, - secondSelect:this.secondSelectEL?.value, - mark:false, - icon:this.icon - }) - } - }else if (this.iconEL!.name == "menu") { - this.iconEL!.name = "statistics"; - this.iconEL!.size = 16; - if (this.getFilter) { - this.getFilter({ - inputValue:this.filterInputEL!.value, - firstSelect:this.firstSelectEL?.value, - secondSelect:this.secondSelectEL?.value, - mark:false, - icon:this.icon - }) - } - } - } - - this.markButtonEL!.onclick=(e)=>{ - if (this.getFilter) { - this.getFilter({ - inputValue:this.filterInputEL!.value, - firstSelect:this.firstSelectEL?.value, - secondSelect:this.secondSelectEL?.value, - mark:true, - icon:this.icon - }) - } - } - - this.filterInputEL?.addEventListener("keydown", (event:any) => { - if (event.keyCode == 13) { - this.iconEL!.name="menu" - if (this.getFilter) { - this.getFilter({ - inputValue:event.target.value, - firstSelect:this.firstSelectEL?.value, - secondSelect:this.secondSelectEL?.value, - mark:false, - icon:this.icon - }) - } - } - }); - - // this.firstSelectEL!.onchange = (e)=>{ - // if (this.getFilter) { - // this.getFilter({ - // inputValue:this.filterInputEL!.value, - // firstSelect:this.firstSelectEL?.value, - // secondSelect:this.secondSelectEL?.value, - // mark:false - // }) - // } - // } - // this.secondSelectEL!.onchange = (e)=>{ - // if (this.getFilter) { - // this.getFilter({ - // inputValue:this.filterInputEL!.value, - // firstSelect:this.firstSelectEL?.value, - // secondSelect:this.secondSelectEL?.value, - // mark:false - // }) - // } - // } - this.setSelectList() - } - - set firstSelect(value:string){ - this.firstSelectEL!.value = value; - } - - get firstSelect(){ - return this.firstSelectEL?.value||"" - } - - set secondSelect(value:string){ - this.secondSelectEL!.value = value; - } - - get secondSelect(){ - return this.secondSelectEL?.value||"" - } - - set filterValue(value:string){ - this.filterInputEL!.value = value; - } - get filterValue(){ - return this.filterInputEL!.value - } - - get inputPlaceholder(){ - return this.getAttribute("inputPlaceholder") || "Detail Filter"; - } - - get icon(){ - if (this.getAttribute("icon") != "false") { - if (this.iconEL!.name == "statistics") { - return "tree" - }else if (this.iconEL!.name == "menu") { - return "block" - }else { - return "" - } - } else { - return ""; - } - } - - set icon(value:string){ - if (value == "block") { - this.iconEL!.name = "menu"; - this.iconEL!.size = 18; - }else if (value == "tree") { - this.iconEL!.name = "statistics"; - this.iconEL!.size = 16; - } - } - - - getFilterData(getFilter:(v:FilterData)=>void){ - this.getFilter = getFilter - } - - setSelectList(firstList :Array|null|undefined = [ "All Allocations" ,"Created & Existing" ,"Created & Destroyed" ], - secondList :Array|null|undefined = ["All Heap & Anonymous VM", "All Heap", "All Anonymous VM"]){ - if (!firstList && !secondList) return; - let sLE = this.shadowRoot?.querySelector("#load") - let html = ``; - if (firstList) { - html += ` - Allocation Lifespan` - firstList!.forEach((a,b)=>{ - html+=`${a}` - }) - html+=`` - } - if (secondList) { - html+=` - Allocation Type` - secondList!.forEach((a,b)=>{ - html+=`${a}` - }) - html+=`` - } - if (!firstList) { - this.secondSelectEL!.outerHTML = html; - } else if (!secondList) { - this.firstSelectEL!.outerHTML = html; - }else { - sLE!.innerHTML=html; - } - - this.firstSelectEL = this.shadowRoot?.querySelector("#first-select") - this.secondSelectEL = this.shadowRoot?.querySelector("#second-select") - - this.firstSelectEL!.onchange = (e)=>{ - if (this.getFilter) { - this.getFilter({ - inputValue:this.filterInputEL!.value, - firstSelect:this.firstSelectEL?.value, - secondSelect:this.secondSelectEL?.value, - mark:false, - icon:this.icon - }) - } - } - this.secondSelectEL!.onchange = (e)=>{ - if (this.getFilter) { - this.getFilter({ - inputValue:this.filterInputEL!.value, - firstSelect:this.firstSelectEL?.value, - secondSelect:this.secondSelectEL?.value, - mark:false, - icon:this.icon - }) - } - } - - } - - initHtml(): string { - return ` - - -Input Filter - - -
- -
- - - - - - - - - - - - - Call Tree - Call Tree Constraints - Data Mining + + Input Filter + + +
+ +
+ +
+
Invert
+
Hide System so
+
+ Options +
+ +
+ + + +
+
Constraints:Only enabled with data and while stopped;
+
filters data to thresholds.
+
+ +
+
+ Sample Count Filter +
+ +
+
+ +
+
+
Reset
+
+
+ Symbol Filter +
+ +
+
+ +
+
+
Reset
+
+
+ Library Filter +
`; - } + } } diff --git a/host/ide/src/trace/component/trace/sheet/TabPaneFps.ts b/host/ide/src/trace/component/trace/sheet/TabPaneFps.ts index c98bab228108ded48609e6dc37e0f80771b2db85..3114835f8dd15a3f9654bbb3abae8603fbfb8306 100644 --- a/host/ide/src/trace/component/trace/sheet/TabPaneFps.ts +++ b/host/ide/src/trace/component/trace/sheet/TabPaneFps.ts @@ -51,19 +51,20 @@ export class TabPaneFps extends BaseElement { initHtml(): string { return ` - - - - - - + + + + + + + + `; } - } \ No newline at end of file diff --git a/host/ide/src/trace/component/trace/sheet/TabPaneHeap.ts b/host/ide/src/trace/component/trace/sheet/TabPaneHeap.ts index ae9da25baf3b17b0b9aec65a3cff110ecd1dd59f..3fea46ac0c1cd71a63182edda32c2577caf86b03 100644 --- a/host/ide/src/trace/component/trace/sheet/TabPaneHeap.ts +++ b/host/ide/src/trace/component/trace/sheet/TabPaneHeap.ts @@ -12,11 +12,12 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import "../../../../base-ui/table/lit-table-column.js"; + +import "../../../../base-ui/table/lit-table-column.js"; import {BaseElement, element} from "../../../../base-ui/BaseElement.js"; import {LitTable} from "../../../../base-ui/table/lit-table.js"; import {SelectionParam} from "../../../bean/BoxSelection.js"; -import {queryHeapAllData, queryHeapAllTable, queryHeapTable, queryHeapTreeTable} from "../../../database/SqlLite.js"; +import {queryHeapAllData} from "../../../database/SqlLite.js"; import {Utils} from "../base/Utils.js"; import {HeapBean} from "../../../bean/HeapBean.js"; import {HeapTreeDataBean} from "../../../bean/HeapTreeDataBean.js"; @@ -27,145 +28,142 @@ export class TabPaneHeap extends BaseElement { private tbl: LitTable | null | undefined; private range: HTMLLabelElement | null | undefined; - initElements(): void { - this.tbl = this.shadowRoot?.querySelector('#tb-heap'); - this.range = this.shadowRoot?.querySelector('#time-range') - new ResizeObserver((entries) => { - if (this.parentElement?.clientHeight != 0) { - // @ts-ignore - this.tbl?.shadowRoot.querySelector(".table").style.height = (this.parentElement.clientHeight - 20)+"px" - this.tbl?.reMeauseHeight() - } - }).observe(this.parentElement!) - } - - - - set data(val: SelectionParam|any) { + set data(val: SelectionParam | any) { // @ts-ignore - this.tbl?.shadowRoot.querySelector(".table").style.height = (this.parentElement.clientHeight - 20)+"px" - queryHeapAllData(val.leftNs,val.rightNs,val.heapIds).then((allHeap)=>{ - if(allHeap.length>0){ - let groups:any = {}; - let treeGroup:any = {} - let treeData:HeapBean[] = [] - allHeap.forEach((heapData)=>{ + this.tbl?.shadowRoot.querySelector(".table").style.height = (this.parentElement.clientHeight - 20) + "px" + queryHeapAllData(val.leftNs, val.rightNs, val.heapIds).then((allHeap) => { + if (allHeap.length > 0) { + let groups: any = {}; + let treeGroup: any = {} + let treeData: HeapBean[] = [] + allHeap.forEach((heapData) => { groups[heapData.eventId] = heapData }) - SpSystemTrace.HEAP_FRAME_DATA.map((frame)=>{ - if(groups[frame.eventId]){ - treeGroup[frame.eventId] = treeGroup[frame.eventId]||[] + SpSystemTrace.HEAP_FRAME_DATA.map((frame) => { + if (groups[frame.eventId]) { + treeGroup[frame.eventId] = treeGroup[frame.eventId] || [] frame.heapSize = groups[frame.eventId].heapSize - frame.startTs = groups[frame.eventId].startTs + frame.startTs = groups[frame.eventId].startTs frame.endTs = groups[frame.eventId].endTs frame.eventType = groups[frame.eventId].eventType treeGroup[frame.eventId].push(frame) } }) - Object.keys(treeGroup).forEach((key)=>{ + Object.keys(treeGroup).forEach((key) => { if (treeGroup[key].length > 0) { - if(treeData.length>0){ - this.merageTree(0,treeData,treeGroup[key],val) - }else { + if (treeData.length > 0) { + this.merageTree(0, treeData, treeGroup[key], val) + } else { let currentData = new HeapBean() - let firstData = treeGroup[key][0] + let firstData = treeGroup[key][0] currentData.AllocationFunction = firstData.AllocationFunction currentData.depth = firstData.depth currentData.MoudleName = firstData.MoudleName treeData.push(currentData) - this.merageTree(0,treeData,treeGroup[key],val) + this.merageTree(0, treeData, treeGroup[key], val) } } }) this.setTreeDataSize(treeData) this.tbl!.recycleDataSource = treeData - }else { + } else { this.tbl!.recycleDataSource = [] } }) } - setTreeDataSize(list:HeapBean[]){ - list.forEach((item)=>{ + initElements(): void { + this.tbl = this.shadowRoot?.querySelector('#tb-heap'); + this.range = this.shadowRoot?.querySelector('#time-range') + new ResizeObserver((entries) => { + if (this.parentElement?.clientHeight != 0) { + // @ts-ignore + this.tbl?.shadowRoot.querySelector(".table").style.height = (this.parentElement.clientHeight - 20) + "px" + this.tbl?.reMeauseHeight() + } + }).observe(this.parentElement!) + } + + setTreeDataSize(list: HeapBean[]) { + list.forEach((item) => { item.AllocationSize = Utils.getByteWithUnit(Number(item.AllocationSize)) item.DeAllocationSize = Utils.getByteWithUnit(Number(item.DeAllocationSize)) item.RemainingSize = Utils.getByteWithUnit(Number(item.RemainingSize)) - if(item.children.length>0){ + if (item.children.length > 0) { this.setTreeDataSize(item.children) } }) } - merageTree(depth: number,beanList:HeapBean[],list:HeapTreeDataBean[],selection: SelectionParam|any){ - if(beanList.length>0){ - if(depth < list.length){ - let treeData = list[depth] - let currentData = beanList.find((item)=>{ + merageTree(depth: number, beanList: HeapBean[], list: HeapTreeDataBean[], selection: SelectionParam | any) { + if (beanList.length > 0) { + if (depth < list.length) { + let treeData = list[depth] + let currentData = beanList.find((item) => { return treeData.MoudleName == item.MoudleName && treeData.AllocationFunction == item.AllocationFunction }) - if(currentData!=undefined){ - (currentData.Allocations as number) += selection.leftNstreeData.endTs?1:0; - (currentData.AllocationSize as number) += selection.leftNstreeData.endTs?treeData.heapSize:0; - ( currentData.Total as number) = (currentData.Allocations as number) - (currentData.Deallocations as number); + if (currentData != undefined) { + (currentData.Allocations as number) += selection.leftNs < treeData.startTs ? 1 : 0; + (currentData.Deallocations as number) += selection.rightNs > treeData.endTs ? 1 : 0; + (currentData.AllocationSize as number) += selection.leftNs < treeData.startTs ? treeData.heapSize : 0; + (currentData.DeAllocationSize as number) += selection.rightNs > treeData.endTs ? treeData.heapSize : 0; + (currentData.Total as number) = (currentData.Allocations as number) - (currentData.Deallocations as number); currentData.RemainingSize = (currentData.AllocationSize as number) - (currentData.DeAllocationSize as number) - }else { + } else { currentData = new HeapBean() currentData.AllocationFunction = treeData.AllocationFunction currentData.depth = treeData.depth currentData.MoudleName = (treeData.MoudleName as string); - (currentData.Allocations as number) += selection.leftNstreeData.endTs?1:0; - (currentData.AllocationSize as number) += selection.leftNstreeData.endTs?treeData.heapSize:0; + (currentData.Allocations as number) += selection.leftNs < treeData.startTs ? 1 : 0; + (currentData.Deallocations as number) += selection.rightNs > treeData.endTs ? 1 : 0; + (currentData.AllocationSize as number) += selection.leftNs < treeData.startTs ? treeData.heapSize : 0; + (currentData.DeAllocationSize as number) += selection.rightNs > treeData.endTs ? treeData.heapSize : 0; currentData.Total = (currentData.Allocations as number) - (currentData.Deallocations as number); currentData.RemainingSize = (currentData.AllocationSize as number) - (currentData.DeAllocationSize as number); beanList.push(currentData) } - if(depth+1 -:host{ - display: flex; - flex-direction: column; - padding: 10px 10px; -} - + - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + `; } - } \ No newline at end of file diff --git a/host/ide/src/trace/component/trace/sheet/TabPaneHistoryProcesses.ts b/host/ide/src/trace/component/trace/sheet/TabPaneHistoryProcesses.ts new file mode 100644 index 0000000000000000000000000000000000000000..3f7c8c7b9ac79c4ee1ed3576c8a3a7b79218c5fa --- /dev/null +++ b/host/ide/src/trace/component/trace/sheet/TabPaneHistoryProcesses.ts @@ -0,0 +1,200 @@ +/* + * 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. + */ + + +import {BaseElement, element} from "../../../../base-ui/BaseElement.js"; +import {LitTable} from "../../../../base-ui/table/lit-table.js"; +import {SelectionParam} from "../../../bean/BoxSelection.js"; +import {getTabProcessHistoryData} from "../../../database/SqlLite.js"; +import {Utils} from "../base/Utils.js"; +import {ProcessHistory} from "../../../bean/AbilityMonitor.js"; +import "../../../component/SpFilter.js"; + +@element('tabpane-history-processes') +export class TabPaneHistoryProcesses extends BaseElement { + private tbl: LitTable | null | undefined; + private source: Array = []; + private queryResult: Array = [] + private float: HTMLDivElement | null | undefined; + private search: HTMLInputElement | undefined | null + + set data(val: SelectionParam | any) { + // @ts-ignore + this.tbl?.shadowRoot.querySelector(".table").style.height = (this.parentElement.clientHeight - 45) + "px" + this.queryDataByDB(val) + } + + initElements(): void { + this.tbl = this.shadowRoot?.querySelector('#tb-history-processes'); + new ResizeObserver((entries) => { + if (this.parentElement?.clientHeight != 0) { + // @ts-ignore + this.tbl?.shadowRoot.querySelector(".table").style.height = (this.parentElement.clientHeight - 45) + "px" + this.tbl?.reMeauseHeight() + } + }).observe(this.parentElement!) + this.tbl!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortByColumn(evt.detail) + }); + } + + filterData() { + if (this.queryResult.length > 0) { + let filter = this.queryResult.filter((item) => { + let array = this.toProcessHistoryArray(item) + let isInclude = array.filter(value => value.indexOf(this.search!.value) > -1); + return isInclude.length > 0 + }); + if (filter.length > 0) { + this.source = filter; + this.tbl!.recycleDataSource = this.source; + } else { + this.source = [] + this.tbl!.recycleDataSource = []; + } + } + } + + toProcessHistoryArray(process: ProcessHistory): any[] { + let array: Array = [] + array.push(process.processId.toString()) + array.push(process.processName) + array.push(process.alive) + array.push(process.firstSeen) + array.push(process.lastSeen) + array.push(process.responsibleProcess) + array.push(process.userName) + array.push(process.cpuTime) + return array + } + + queryDataByDB(val: SelectionParam | any) { + getTabProcessHistoryData(val.leftNs, val.rightNs, val.processId, val.threadId).then(item => { + if (item.length != null && item.length > 0) { + for (const processHistory of item) { + processHistory.alive = processHistory.alive == '0' ? 'No' : 'Yes' + if (Number(processHistory.firstSeen) <= 0) { + processHistory.firstSeen = '0:000.000.000'; + } else { + processHistory.firstSeen = Utils.getTimeStampHMS(Number(processHistory.firstSeen)) + } + processHistory.lastSeen = Utils.getTimeStampHMS(Number(processHistory.lastSeen)) + processHistory.processName = processHistory.processName + '(' + processHistory.processId + ')' + processHistory.cpuTime = this.timeFormat(Number(processHistory.cpuTime)) + } + this.source = item + this.queryResult = item; + this.tbl!.recycleDataSource = this.source; + } else { + this.source = [] + this.queryResult = [] + this.tbl!.recycleDataSource = []; + } + }) + } + + timeFormat(ms: number) : string { + let currentNs = ms + let minute1 = 60000 + let second1 = 1000; + let millisecond1 = 1; + let res = ""; + if (currentNs >= minute1) { + res += Math.floor(currentNs / minute1) + ":"; + currentNs = currentNs - Math.floor(ms / minute1) * minute1 + } + if (currentNs >= second1) { + res += Math.floor(currentNs / second1) + "."; + currentNs = currentNs - Math.floor(currentNs / second1) * second1; + res += Math.floor(currentNs / millisecond1) + "s "; + return res; + } + if (res == "") { + res = ms + "ms"; + } + return res + } + + initHtml(): string { + return ` + + + + + + + + + + + + `; + } + + sortByColumn(detail: any) { + // @ts-ignore + function compare(property, sort, type) { + return function (a: ProcessHistory, b: ProcessHistory) { + if (type === 'number') { + // @ts-ignore + return sort === 2 ? parseFloat(b[property]) - parseFloat(a[property]) : parseFloat(a[property]) - parseFloat(b[property]); + } else if (type === 'alive') { + let aaaa = 0; + let bbbb = 0; + // @ts-ignore + if (b[property] == "Yes") { + bbbb = 1; + } + // @ts-ignore + if (a[property] == "Yes") { + aaaa = 1; + } + if (aaaa - bbbb == 0) { + return 0; + } + return aaaa - bbbb ? -1 : 1 + } else { + // @ts-ignore + if (b[property] > a[property]) { + return sort === 2 ? 1 : -1; + } else { // @ts-ignore + if (b[property] == a[property]) { + return 0; + } else { + return sort === 2 ? -1 : 1; + } + } + } + } + } + + if (detail.key === 'startTime') { + this.source.sort(compare(detail.key, detail.sort, 'string')) + } else if (detail.key === 'alive') { + this.source.sort(compare(detail.key, detail.sort, 'alive')) + } else { + this.source.sort(compare(detail.key, detail.sort, 'number')) + } + this.tbl!.dataSource = this.source; + } + +} \ No newline at end of file diff --git a/host/ide/src/trace/component/trace/sheet/TabPaneLiveProcesses.ts b/host/ide/src/trace/component/trace/sheet/TabPaneLiveProcesses.ts new file mode 100644 index 0000000000000000000000000000000000000000..cf19902000a1f010aada3d4e7d6a567fa0bf8ce2 --- /dev/null +++ b/host/ide/src/trace/component/trace/sheet/TabPaneLiveProcesses.ts @@ -0,0 +1,188 @@ +/* + * 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. + */ + +import {BaseElement, element} from "../../../../base-ui/BaseElement.js"; +import {LitTable} from "../../../../base-ui/table/lit-table.js"; +import {SelectionParam} from "../../../bean/BoxSelection.js"; +import {getTabLiveProcessData} from "../../../database/SqlLite.js"; +import {LiveProcess} from "../../../bean/AbilityMonitor.js"; +import "../../../component/SpFilter.js"; +import {Utils} from "../base/Utils.js"; + +@element('tabpane-live-processes') +export class TabPaneLiveProcesses extends BaseElement { + private tbl: LitTable | null | undefined; + private source: Array = []; + private queryResult: Array = [] + private float: HTMLDivElement | null | undefined; + private search: HTMLInputElement | undefined | null + + set data(val: SelectionParam | any) { + // @ts-ignore + this.tbl?.shadowRoot.querySelector(".table").style.height = (this.parentElement.clientHeight - 45) + "px" + this.queryDataByDB(val) + } + + initElements(): void { + this.tbl = this.shadowRoot?.querySelector('#tb-live-processes'); + new ResizeObserver((entries) => { + if (this.parentElement?.clientHeight != 0) { + // @ts-ignore + this.tbl?.shadowRoot.querySelector(".table").style.height = (this.parentElement.clientHeight - 45) + "px" + this.tbl?.reMeauseHeight() + } + }).observe(this.parentElement!) + this.tbl!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortByColumn(evt.detail) + }); + } + + filterData() { + if (this.queryResult.length > 0) { + let filter = this.queryResult.filter((item) => { + let array = this.toLiveProcessArray(item) + let isInclude = array.filter(value => value.indexOf(this.search!.value) > -1); + return isInclude.length > 0 + }); + if (filter.length > 0) { + this.source = filter; + this.tbl!.recycleDataSource = this.source; + } else { + this.source = [] + this.tbl!.recycleDataSource = []; + } + } + } + + toLiveProcessArray(liveProcess: LiveProcess): any[] { + let array: Array = [] + array.push(liveProcess.processId.toString()) + array.push(liveProcess.processName) + array.push(liveProcess.responsibleProcess) + array.push(liveProcess.userName) + array.push(liveProcess.threads.toString()) + array.push(liveProcess.cpu) + array.push(liveProcess.memory) + array.push(liveProcess.diskReads.toString()) + array.push(liveProcess.diskWrite.toString()) + return array + } + + queryDataByDB(val: SelectionParam | any) { + getTabLiveProcessData(val.leftNs, val.rightNs).then(item => { + if (item.length != null && item.length > 0) { + for (const liveProcess of item) { + liveProcess.processName = liveProcess.processName + '(' + liveProcess.processId + ')' + liveProcess.memory = Utils.getBinaryByteWithUnit(Number(liveProcess.memory)) + if (Number(liveProcess.cpu) > 0) { + liveProcess.cpu = Number(Number(liveProcess.cpu).toFixed(3)) + "%" + } else { + liveProcess.cpu = "0%"; + } + liveProcess.cpuTimeNumber = Number(liveProcess.cpuTime); + liveProcess.cpuTime = this.timeFormat(Number(liveProcess.cpuTime)) + } + this.source = item + this.queryResult = item; + this.tbl!.recycleDataSource = this.source; + } else { + this.source = [] + this.queryResult = [] + this.tbl!.recycleDataSource = []; + } + }) + } + + + timeFormat(ms: number): string { + let currentNs = ms + let minute1 = 60000 + let second1 = 1000; + let millisecond1 = 1; + let res = ""; + if (currentNs >= minute1) { + res += Math.floor(currentNs / minute1) + ":"; + currentNs = currentNs - Math.floor(ms / minute1) * minute1 + } + if (currentNs >= second1) { + res += Math.floor(currentNs / second1) + "."; + currentNs = currentNs - Math.floor(currentNs / second1) * second1; + res += Math.floor(currentNs / millisecond1) + "s "; + return res; + } + if (res == "") { + res = ms + "ms"; + } + return res + } + initHtml(): string { + return ` + + + + + + + + + + + + + + `; + } + + sortByColumn(detail: any) { + // @ts-ignore + function compare(property, sort, type) { + return function (a: LiveProcess, b: LiveProcess) { + if (type === 'number') { + // @ts-ignore + return sort === 2 ? parseFloat(b[property]) - parseFloat(a[property]) : parseFloat(a[property]) - parseFloat(b[property]); + } else if (type === 'cpuTime') { + return sort === 2 ? b.cpuTimeNumber - a.cpuTimeNumber : a.cpuTimeNumber - b.cpuTimeNumber; + } else { + // @ts-ignore + if (b[property] > a[property]) { + return sort === 2 ? 1 : -1; + } else { // @ts-ignore + if (b[property] == a[property]) { + return 0; + } else { + return sort === 2 ? -1 : 1; + } + } + } + } + } + + if (detail.key == 'startTime') { + this.source.sort(compare(detail.key, detail.sort, 'string')) + } else if (detail.key == 'cpuTime') { + this.source.sort(compare(detail.key, detail.sort, 'cpuTime')) + } else { + this.source.sort(compare(detail.key, detail.sort, 'number')) + } + this.tbl!.dataSource = this.source; + } +} \ No newline at end of file diff --git a/host/ide/src/trace/component/trace/sheet/TabPaneMemoryAbility.ts b/host/ide/src/trace/component/trace/sheet/TabPaneMemoryAbility.ts new file mode 100644 index 0000000000000000000000000000000000000000..faadcd1198ed6a1fca2a8a146b2ccfb2982dde64 --- /dev/null +++ b/host/ide/src/trace/component/trace/sheet/TabPaneMemoryAbility.ts @@ -0,0 +1,256 @@ +/* + * 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. + */ + +import {BaseElement, element} from "../../../../base-ui/BaseElement.js"; +import {LitTable} from "../../../../base-ui/table/lit-table.js"; +import {SelectionParam} from "../../../bean/BoxSelection.js"; +import {getTabMemoryAbilityData, queryStartTime} from "../../../database/SqlLite.js"; +import {SystemMemorySummary} from "../../../bean/AbilityMonitor.js"; +import {Utils} from "../base/Utils.js"; +import "../../../component/SpFilter.js"; + +@element('tabpane-memory-ability') +export class TabPaneMemoryAbility extends BaseElement { + private tbl: LitTable | null | undefined; + private source: Array = []; + private float: HTMLDivElement | null | undefined; + private queryResult: Array = [] + private search: HTMLInputElement | undefined | null + + set data(val: SelectionParam | any) { + // @ts-ignore + this.tbl?.shadowRoot.querySelector(".table").style.height = (this.parentElement.clientHeight - 45) + "px" + this.queryDataByDB(val) + } + + initElements(): void { + this.tbl = this.shadowRoot?.querySelector('#tb-memory-ability'); + new ResizeObserver((entries) => { + if (this.parentElement?.clientHeight != 0) { + // @ts-ignore + this.tbl?.shadowRoot.querySelector(".table").style.height = (this.parentElement.clientHeight - 45) + "px" + this.tbl?.reMeauseHeight() + } + }).observe(this.parentElement!) + this.tbl!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortByColumn(evt.detail) + }); + } + + filterData() { + if (this.queryResult.length > 0) { + let filter = this.queryResult.filter((item) => { + let array = this.toMemoryAbilityArray(item) + let isInclude = array.filter(value => value.indexOf(this.search!.value) > -1); + return isInclude.length > 0 + }); + if (filter.length > 0) { + this.source = filter; + this.tbl!.recycleDataSource = this.source; + } else { + this.source = [] + this.tbl!.recycleDataSource = []; + } + } + } + + toMemoryAbilityArray(systemMemorySummary: SystemMemorySummary): any[] { + let array: Array = [] + array.push(systemMemorySummary.startTimeStr) + array.push(systemMemorySummary.durationStr) + array.push(systemMemorySummary.memoryTotal) + array.push(systemMemorySummary.cached) + array.push(systemMemorySummary.swapTotal) + return array + } + + queryDataByDB(val: SelectionParam | any) { + queryStartTime().then(res => { + let startTime = res[0].start_ts; + getTabMemoryAbilityData(val.leftNs + startTime, val.rightNs + startTime).then(items => { + this.source = [] + this.queryResult = []; + if (items.length != null && items.length > 0) { + let lastTime = 0; + for (const item of items) { + let systemMemorySummary = new SystemMemorySummary() + if (item.startTime - startTime <= 0) { + systemMemorySummary.startTimeStr = '0:000.000.000'; + } else { + systemMemorySummary.startTimeStr = Utils.getTimeStampHMS(item.startTime - startTime); + } + if (lastTime !== 0) { + systemMemorySummary.durationStr = Utils.getDurString(item.startTime - lastTime); + } else { + systemMemorySummary.durationStr = '-'; + } + lastTime = item.startTime; + let memorys = item.value.split(","); + let names = item.name.split(","); + if (memorys.length != names.length) { + continue; + } + for (let i = 0; i < names.length; i++) { + switch (names[i]) { + case "sys.mem.total": + systemMemorySummary.memoryTotal = Utils.getBinaryByteWithUnit(Number(memorys[i])) + break; + case "sys.mem.free": + systemMemorySummary.memFree = Utils.getBinaryByteWithUnit(Number(memorys[i])) + break; + case "sys.mem.buffers": + systemMemorySummary.buffers = Utils.getBinaryByteWithUnit(Number(memorys[i])) + break; + case "sys.mem.cached": + systemMemorySummary.cached = Utils.getBinaryByteWithUnit(Number(memorys[i])) + break; + case "sys.mem.shmem": + systemMemorySummary.shmem = Utils.getBinaryByteWithUnit(Number(memorys[i])) + break; + case "sys.mem.slab": + systemMemorySummary.slab = Utils.getBinaryByteWithUnit(Number(memorys[i])) + break; + case "sys.mem.swap.total": + systemMemorySummary.swapTotal = Utils.getBinaryByteWithUnit(Number(memorys[i])) + break; + case "sys.mem.swap.free": + systemMemorySummary.swapFree = Utils.getBinaryByteWithUnit(Number(memorys[i])) + break; + case "sys.mem.mapped": + systemMemorySummary.mapped = Utils.getBinaryByteWithUnit(Number(memorys[i])) + break; + case "sys.mem.vmalloc.used": + systemMemorySummary.vmallocUsed = Utils.getBinaryByteWithUnit(Number(memorys[i])) + break; + case "sys.mem.page.tables": + systemMemorySummary.pageTables = Utils.getBinaryByteWithUnit(Number(memorys[i])) + break; + case "sys.mem.kernel.stack": + systemMemorySummary.kernelStack = Utils.getBinaryByteWithUnit(Number(memorys[i])) + break; + case "sys.mem.active": + systemMemorySummary.active = Utils.getBinaryByteWithUnit(Number(memorys[i])) + break; + case "sys.mem.inactive": + systemMemorySummary.inactive = Utils.getBinaryByteWithUnit(Number(memorys[i])) + break; + case "sys.mem.unevictable": + systemMemorySummary.unevictable = Utils.getBinaryByteWithUnit(Number(memorys[i])) + break; + case "sys.mem.vmalloc.total": + systemMemorySummary.vmallocTotal = Utils.getBinaryByteWithUnit(Number(memorys[i])) + break; + case "sys.mem.slab.unreclaimable": + systemMemorySummary.sUnreclaim = Utils.getBinaryByteWithUnit(Number(memorys[i])) + break; + case "sys.mem.cma.total": + systemMemorySummary.cmaTotal = Utils.getBinaryByteWithUnit(Number(memorys[i])) + break; + case "sys.mem.cma.free": + systemMemorySummary.cmaFree = Utils.getBinaryByteWithUnit(Number(memorys[i])) + break; + case "sys.mem.kernel.reclaimable": + systemMemorySummary.kReclaimable = Utils.getBinaryByteWithUnit(Number(memorys[i])) + break; + case "sys.mem.zram": + systemMemorySummary.zram = Utils.getBinaryByteWithUnit(Number(memorys[i]) * 1000) + break; + } + } + this.source.push(systemMemorySummary); + } + this.tbl!.recycleDataSource = this.source; + } else { + this.source = [] + this.tbl!.recycleDataSource = []; + } + }) + + }); + } + + initHtml(): string { + return ` + + + + + + + + + + + + + + + + + + + + + + + + + + + `; + } + + sortByColumn(detail: any) { + // @ts-ignore + function compare(property, sort, type) { + return function (a: SystemMemorySummary, b: SystemMemorySummary) { + if (type === 'number') { + // @ts-ignore + return sort === 2 ? parseFloat(b[property]) - parseFloat(a[property]) : parseFloat(a[property]) - parseFloat(b[property]); + } else { + // @ts-ignore + if (b[property] > a[property]) { + return sort === 2 ? 1 : -1; + } else { // @ts-ignore + if (b[property] == a[property]) { + return 0; + } else { + return sort === 2 ? -1 : 1; + } + } + } + } + } + + if (detail.key === 'startTime') { + this.source.sort(compare(detail.key, detail.sort, 'string')) + } else { + this.source.sort(compare(detail.key, detail.sort, 'number')) + } + this.tbl!.dataSource = this.source; + } +} + + diff --git a/host/ide/src/trace/component/trace/sheet/TabPaneNMCallInfo.ts b/host/ide/src/trace/component/trace/sheet/TabPaneNMCallInfo.ts index 0ad18bf9d6c346e1443979afa0bc1de4b0a1340d..eb2ae0a870a55d141c219346526ac5366313e240 100644 --- a/host/ide/src/trace/component/trace/sheet/TabPaneNMCallInfo.ts +++ b/host/ide/src/trace/component/trace/sheet/TabPaneNMCallInfo.ts @@ -22,31 +22,40 @@ import {SpSystemTrace} from "../../SpSystemTrace.js"; import {Utils} from "../base/Utils.js"; import "./TabPaneFilter.js" import {FilterData, TabPaneFilter} from "./TabPaneFilter"; +import "../../FrameChart.js"; +import {FrameChart} from "../../FrameChart.js"; +import {ChartMode} from "../../../database/ProcedureWorkerCommon.js"; + @element('tabpane-native-callinfo') export class TabPaneNMCallInfo extends BaseElement { private tbl: LitTable | null | undefined; private tblData: LitTable | null | undefined; private source: Array = [] + private rightSource: Array = [] private queryResult: Array = [] - private native_type:Array = ["All Heap & Anonymous VM","All Heap","All Anonymous VM"]; - private filterAllocationType:string = "0" - private filterNativeType:string = "0" - private currentSelection:SelectionParam|undefined + private native_type: Array = ["All Heap & Anonymous VM", "All Heap", "All Anonymous VM"]; + private filterAllocationType: string = "0" + private filterNativeType: string = "0" + private currentSelection: SelectionParam | undefined + private frameChart: FrameChart | null | undefined; + private isChartShow: boolean = false; + private selectTotalSize = 0; + set data(val: SelectionParam | any) { - if(val!=this.currentSelection){ + if (val != this.currentSelection) { this.currentSelection = val this.initFilterTypes() } - let types:Array = [] - if(val.nativeMemory.indexOf(this.native_type[0]) != -1){ + let types: Array = [] + if (val.nativeMemory.indexOf(this.native_type[0]) != -1) { types.push("'AllocEvent'"); types.push("'MmapEvent'"); - }else{ - if(val.nativeMemory.indexOf(this.native_type[1]) != -1){ + } else { + if (val.nativeMemory.indexOf(this.native_type[1]) != -1) { types.push("'AllocEvent'"); } - if(val.nativeMemory.indexOf(this.native_type[2]) != -1){ + if (val.nativeMemory.indexOf(this.native_type[2]) != -1) { types.push("'MmapEvent'"); } } @@ -58,76 +67,79 @@ export class TabPaneNMCallInfo extends BaseElement { this.tblData?.recycleDataSource = []; // @ts-ignore this.tbl?.recycleDataSource = []; - queryNativeHookEventTid(val.leftNs,val.rightNs,types).then((result)=>{ - if(result.length > 0){ - this.queryResult = result + queryNativeHookEventTid(val.leftNs, val.rightNs, types).then((result) => { + if (result.length > 0) { + this.queryResult = result; this.source = this.handleQueryResult(result); - }else{ + } else { this.source = []; + this.frameChart!.data = []; + this.frameChart?.clearCanvas(); } this.filterQueryData() }) } - handleQueryResult(result:Array):Array{ - let resultMap = new Map(); - result.map((r)=>{ - resultMap.set(r.eventId,r); - }) - let map = new Map(); + handleQueryResult(result: Array): Array { + let resultMap = new Map(); + result.map((r) => { + resultMap.set(r.eventId, r); + }); + let map = new Map(); SpSystemTrace.HEAP_FRAME_DATA.map((frame) => { let frameEventId = parseInt(frame.eventId); - if(frameEventId >= result[0].eventId && frameEventId <= result[result.length - 1].eventId){ - if(resultMap.has(frameEventId)){ + if (frameEventId >= result[0].eventId && frameEventId <= result[result.length - 1].eventId) { + if (resultMap.has(frameEventId)) { let hook = resultMap.get(frameEventId); - if(hook != undefined){ + if (hook != undefined) { let target = new NativeHookCallInfo(); target.id = frame.eventId + "_" + frame.depth; target.eventId = frameEventId; target.depth = frame.depth; target.count = 1; - target.heapSize = hook.heapSize; + target.size = hook.heapSize; target.threadId = hook.tid; - target.heapSizeStr = Utils.getByteWithUnit(target.heapSize); + target.heapSizeStr = Utils.getByteWithUnit(target.size); let sym_arr = frame.AllocationFunction?.split("/"); let lib_arr = frame.MoudleName?.split("/"); target.symbol = sym_arr![sym_arr!.length - 1]; target.library = lib_arr![lib_arr!.length - 1]; target.title = `[ ${target.symbol} ] ${target.library}`; target.type = (target.library.endsWith(".so.1") || target.library.endsWith(".dll") || target.library.endsWith(".so")) ? 0 : 1; - if(map.has(frame.eventId)){ + if (map.has(frame.eventId)) { let src = map.get(frame.eventId); - this.listToTree(target,src!); - }else{ - map.set(frame.eventId,target); + this.listToTree(target, src!); + } else { + map.set(frame.eventId, target); } } } } - if(frameEventId > result[result.length -1].eventId){ + if (frameEventId > result[result.length - 1].eventId) { return false; } }); - let groupMap = new Map>(); + let groupMap = new Map>(); for (let value of map.values()) { - let key = value.threadId+ "_" + value.symbol; - if(groupMap.has(key)){ + let key = value.threadId + "_" + value.symbol; + if (groupMap.has(key)) { groupMap.get(key)!.push(value); - }else{ - let arr:Array = []; + } else { + let arr: Array = []; arr.push(value); - groupMap.set(key,arr); + groupMap.set(key, arr); } } - let data:Array = []; + let data: Array = []; for (let arr of groupMap.values()) { - if(arr.length > 1){ + if (arr.length > 1) { for (let i = 1; i < arr.length; i++) { - if(arr[i].children.length > 0){ - this.mergeTree(arr[i].children[0],arr[0]); - }else{ - arr[0].heapSize += arr[i].heapSize; - arr[0].heapSizeStr = Utils.getByteWithUnit(arr[0].heapSize); + if (arr[i].children.length > 0) { + this.mergeTree(arr[i].children[0], arr[0]); + } else { + arr[0].size += arr[i].size; + arr[0].heapSizeStr = Utils.getByteWithUnit(arr[0].size); + } } } @@ -137,109 +149,137 @@ export class TabPaneNMCallInfo extends BaseElement { return this.groupByWithTid(data) } - groupByWithTid(data:Array):Array{ - let tidMap = new Map(); + groupByWithTid(data: Array): Array { + let tidMap = new Map(); for (let call of data) { - call.pid = "tid_"+call.threadId; - if(tidMap.has(call.threadId)){ + call.pid = "tid_" + call.threadId; + if (tidMap.has(call.threadId)) { let tidCall = tidMap.get(call.threadId); - tidCall!.heapSize += call.heapSize; - tidCall!.heapSizeStr = Utils.getByteWithUnit(tidCall!.heapSize); + tidCall!.size += call.size; + tidCall!.heapSizeStr = Utils.getByteWithUnit(tidCall!.size); tidCall!.count += call.count; tidCall!.children.push(call); - }else{ + } else { let tidCall = new NativeHookCallInfo(); tidCall.id = "tid_" + call.threadId; tidCall.count = call.count; - tidCall.heapSize = call.heapSize; - tidCall.heapSizeStr = Utils.getByteWithUnit(call.heapSize); + tidCall.size = call.size; + tidCall.heapSizeStr = Utils.getByteWithUnit(call.size); tidCall.title = "Thread " + call.threadId; + tidCall.symbol = tidCall.title; tidCall.type = -1; tidCall.children.push(call); - tidMap.set(call.threadId,tidCall); + tidMap.set(call.threadId, tidCall); } } - return Array.from(tidMap.values()); + this.source = data; + let showData = Array.from(tidMap.values()) + this.frameChart!.mode = ChartMode.Byte; + this.frameChart!.data = showData; + this.frameChart?.updateCanvas(true); + this.frameChart?.calculateChartData(); + return showData; } - listToTree(target:NativeHookCallInfo,src:NativeHookCallInfo){ - if(target.depth == src.depth + 1){ + listToTree(target: NativeHookCallInfo, src: NativeHookCallInfo) { + if (target.depth == src.depth + 1) { target.pid = src.id; src.children.push(target) - }else{ - if(src.children.length > 0){ - this.listToTree(target,src.children[0]); + } else { + if (src.children.length > 0) { + this.listToTree(target, src.children[0]); } } } - mergeTree(target:NativeHookCallInfo,src:NativeHookCallInfo){ + mergeTree(target: NativeHookCallInfo, src: NativeHookCallInfo) { let len = src.children.length; - if(len == 0){ + if (len == 0) { target.pid = src.id; - src.heapSize += target.heapSize; - src.heapSizeStr = Utils.getByteWithUnit(src.heapSize); + src.size += target.size; + src.heapSizeStr = Utils.getByteWithUnit(src.size); src.children.push(target); - }else{ + } else { let index = src.children.findIndex((hook) => hook.symbol == target.symbol && hook.depth == target.depth); - src.heapSize += target.heapSize; - src.heapSizeStr = Utils.getByteWithUnit(src.heapSize); - if(index != -1){ - let srcChild = src.children[index]; + src.size += target.size; + src.heapSizeStr = Utils.getByteWithUnit(src.size); + if (index != -1) { + let srcChild = src.children[index]; srcChild.count += 1; - if(target.children.length > 0){ - this.mergeTree(target.children[0],srcChild) - }else{ - srcChild.heapSize += target.heapSize; - srcChild.heapSizeStr = Utils.getByteWithUnit(srcChild.heapSize) + if (target.children.length > 0) { + this.mergeTree(target.children[0], srcChild) + } else { + srcChild.size += target.size; + srcChild.heapSizeStr = Utils.getByteWithUnit(srcChild.size) + } - }else{ + } else { target.pid = src.id; src.children.push(target) } } } - setRightTableData(hook:NativeHookCallInfo){ - let arr:Array = []; + getParentTree(src: Array, target: NativeHookCallInfo, parents: Array): boolean { + for (let hook of src) { + if (hook.id == target.id) { + parents.push(hook) + return true + } else { + if (this.getParentTree(hook.children as Array, target, parents)) { + parents.push(hook); + return true; + } + } + } + return false; + } + + getChildTree(src: Array, eventId: number, children: Array): boolean { + for (let hook of src) { + if (hook.eventId == eventId && hook.children.length == 0) { + children.push(hook) + return true + } else { + if (this.getChildTree(hook.children as Array, eventId, children)) { + children.push(hook); + return true; + } + } + } + return false; + } + + setRightTableData(hook: NativeHookCallInfo) { + let parents: Array = []; + let children: Array = []; + this.getParentTree(this.source, hook, parents); let maxEventId = hook.eventId; let maxHeap = 0; - function findMaxStack(hook:NativeHookCallInfo){ - if(hook.children.length == 0){ - if(hook.heapSize > maxHeap){ - maxHeap = hook.heapSize; + + function findMaxStack(hook: NativeHookCallInfo) { + if (hook.children.length == 0) { + if (hook.size > maxHeap) { + maxHeap = hook.size; maxEventId = hook.eventId; } - }else{ - hook.children.map((hookChild)=>{ - findMaxStack(hookChild); + } else { + hook.children.map((hookChild) => { + findMaxStack(hookChild); }) } } + findMaxStack(hook); - SpSystemTrace.HEAP_FRAME_DATA.map((frame) => { - let eventId = parseInt(frame.eventId); - if(eventId == maxEventId){ - let target = new NativeHookCallInfo(); - target.eventId = eventId; - target.depth = frame.depth; - let sym_arr = frame.AllocationFunction?.split("/"); - let lib_arr = frame.MoudleName?.split("/"); - target.symbol = sym_arr![sym_arr!.length - 1]; - target.library = lib_arr![lib_arr!.length - 1]; - target.title = `[ ${target.symbol} ] ${target.library}`; - target.type = (target.library.endsWith(".so.1") || target.library.endsWith(".dll") || target.library.endsWith(".so")) ? 0 : 1; - arr.push(target); - } - if(eventId > maxEventId){ - return false; - } - }); - // @ts-ignore - this.tblData?.recycleDataSource = arr; + this.getChildTree(hook.children as Array, maxEventId, children); + this.rightSource = parents.reverse().concat(children.reverse()); + let len = this.rightSource.length; + // @ts-ignore + this.tblData?.recycleDataSource = len == 0 ? [] : this.rightSource.slice(1, len); + } - initFilterTypes(){ + initFilterTypes() { let filter = this.shadowRoot?.querySelector("#filter") this.queryResult = [] filter!.firstSelect = "0" @@ -248,97 +288,211 @@ export class TabPaneNMCallInfo extends BaseElement { this.filterNativeType = "0" } + sortTreeByColumn(column: string, sort: number) { + this.tbl!.recycleDataSource = this.sortTree(this.source, column, sort) + } + + sortTree(arr: Array, column: string, sort: number): Array { + let sortArr = arr.sort((a, b) => { + if (column == 'size') { + if (sort == 0) { + return a.eventId - b.eventId; + } else if (sort == 1) { + return a.size - b.size; + } else { + return b.size - a.size; + } + } else { + if (sort == 0) { + return a.eventId - b.eventId; + } else if (sort == 1) { + return a.count - b.count; + } else { + return b.count - a.count; + } + } + }) + sortArr.map((call) => { + call.children = this.sortTree(call.children as Array, column, sort); + }) + return sortArr; + } + initElements(): void { this.tbl = this.shadowRoot?.querySelector('#tb-native-callinfo'); this.tblData = this.shadowRoot?.querySelector('#tb-native-data'); + this.frameChart = this.shadowRoot?.querySelector('#framechart'); + let pageTab = this.shadowRoot?.querySelector('#show_table'); + let pageChart = this.shadowRoot?.querySelector('#show_chart'); this.tbl!.addEventListener("row-click", (e) => { // @ts-ignore - let data = (e.detail as NativeHookCallInfo) + let data = (e.detail.data as NativeHookCallInfo); + (data as any).isSelected = true this.setRightTableData(data); + this.tblData?.clearAllSelection(data) + this.tblData?.setCurrentSelection(data) + // @ts-ignore + if ((e.detail as any).callBack) { + // @ts-ignore + (e.detail as any).callBack(true) + } + }) + this.tblData!.addEventListener("row-click", (e) => { + this.tbl!.expandList(this.rightSource) + // @ts-ignore + let detail = e.detail.data as NativeHookCallInfo; + this.tbl?.clearAllSelection(detail) + detail.isSelected = true + this.tbl!.scrollToData(this.rightSource[detail.depth + 1]) + // @ts-ignore + if ((e.detail as any).callBack) { + // @ts-ignore + (e.detail as any).callBack(true) + } }) + this.tbl!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortTreeByColumn(evt.detail.key == "count" ? 'count' : 'size', evt.detail.sort) + }); + let filterHeight = 0; new ResizeObserver((entries) => { + let tabPaneFilter = this.shadowRoot!.querySelector("#filter") as HTMLElement; + if (tabPaneFilter.clientHeight > 0) filterHeight = tabPaneFilter.clientHeight; + if (this.parentElement!.clientHeight > filterHeight) { + tabPaneFilter.style.display = "flex"; + } else { + tabPaneFilter.style.display = "none"; + } if (this.parentElement?.clientHeight != 0) { + if (!this.isChartShow) { + // @ts-ignore + this.tbl?.shadowRoot.querySelector(".table").style.height = (this.parentElement.clientHeight) + "px" + this.tbl?.reMeauseHeight() + } else { + // @ts-ignore + this.frameChart?.updateCanvas(false,entries[0].contentRect.width); + this.frameChart?.calculateChartData(); + } // @ts-ignore - this.tbl?.shadowRoot.querySelector(".table").style.height = (this.parentElement.clientHeight)-10-31+"px"; - this.tbl?.reMeauseHeight() + this.tbl?.shadowRoot.querySelector(".table").style.height = (this.parentElement.clientHeight) - 10 - 31 + "px"; + this.tbl?.reMeauseHeight(); // @ts-ignore - this.tblData?.shadowRoot.querySelector(".table").style.height = (this.parentElement.clientHeight) -10+"px" + this.tblData?.shadowRoot.querySelector(".table").style.height = (this.parentElement.clientHeight) - 10 - 31 + "px"; this.tblData?.reMeauseHeight() } }).observe(this.parentElement!); - this.shadowRoot?.querySelector("#filter")!.getFilterData((data:FilterData)=>{ - this.filterAllocationType = data.firstSelect||"0" - this.filterNativeType = data.secondSelect||"0" + this.shadowRoot?.querySelector("#filter")!.getFilterData((data: FilterData) => { + if (data.icon == 'block') { + pageChart?.setAttribute('class', 'show'); + pageTab?.setAttribute('class', ''); + this.isChartShow = true; + } else if (data.icon == 'tree') { + pageChart?.setAttribute('class', ''); + pageTab?.setAttribute('class', 'show'); + this.isChartShow = false; + } + this.filterAllocationType = data.firstSelect || "0" + this.filterNativeType = data.secondSelect || "0" this.filterQueryData() - }) + }); + + this.parentElement!.onscroll = () => { + this.frameChart!.tabPaneScrollTop = this.parentElement!.scrollTop; + }; this.initFilterTypes() } - filterQueryData(){ - if (this.queryResult.length > 0&&this.currentSelection) { - let filter = this.queryResult.filter((item)=>{ - let filterAllocation = true - let filterNative = true - if(this.filterAllocationType=="1"){ - filterAllocation = item.startTs>=this.currentSelection!.leftNs&&item.startTs<=this.currentSelection!.rightNs&&item.endTs>this.currentSelection!.rightNs - }else if(this.filterAllocationType=="2"){ - filterAllocation = item.startTs>=this.currentSelection!.leftNs&&item.startTs<=this.currentSelection!.rightNs&&item.endTs<=this.currentSelection!.rightNs + filterQueryData() { + if (this.queryResult.length > 0 && this.currentSelection) { + let filter = this.queryResult.filter((item) => { + let filterAllocation = true; + let filterNative = true; + if (this.filterAllocationType == "1") { + filterAllocation = item.startTs >= this.currentSelection!.leftNs && item.startTs <= this.currentSelection!.rightNs && item.endTs > this.currentSelection!.rightNs + } else if (this.filterAllocationType == "2") { + filterAllocation = item.startTs >= this.currentSelection!.leftNs && item.startTs <= this.currentSelection!.rightNs && item.endTs <= this.currentSelection!.rightNs } - if(this.filterNativeType=="1"){ + if (this.filterNativeType == "1") { filterNative = item.eventType == "AllocEvent" - }else if(this.filterNativeType=="2"){ + } else if (this.filterNativeType == "2") { filterNative = item.eventType == "MmapEvent" } - return filterAllocation&&filterNative - }) - if(filter.length>0){ + return filterAllocation && filterNative + }); + if (filter.length > 0) { this.source = this.handleQueryResult(filter); this.tbl!.recycleDataSource = this.source; - }else { + } else { this.source = [] this.tbl!.recycleDataSource = []; + this.frameChart!.data = []; + this.frameChart!.clearCanvas() } } } initHtml(): string { return ` - -
-
- - - - - - - - - -
-
- - - - - - -
-
- + +
+ +
+ + + + + + + + + + + +
+
+ + + + + + + +
+
+ + + + +
`; } } \ No newline at end of file diff --git a/host/ide/src/trace/component/trace/sheet/TabPaneNMSampleList.ts b/host/ide/src/trace/component/trace/sheet/TabPaneNMSampleList.ts index df7e7eb1fddf4b477df473ed2b30cf8f1a00fd88..c90fc5a67d40b4bfb76208e8195657c03f84f9df 100644 --- a/host/ide/src/trace/component/trace/sheet/TabPaneNMSampleList.ts +++ b/host/ide/src/trace/component/trace/sheet/TabPaneNMSampleList.ts @@ -13,16 +13,11 @@ * limitations under the License. */ -import "../../../../base-ui/table/lit-table-column.js"; +import "../../../../base-ui/table/lit-table-column.js"; import {BaseElement, element} from "../../../../base-ui/BaseElement.js"; import {LitTable} from "../../../../base-ui/table/lit-table.js"; -import {Counter, SelectionData, SelectionParam} from "../../../bean/BoxSelection.js"; -import { - getTabCounters, queryAllHookData, - queryNativeHookEventId, - queryNativeHookSnapshot, - queryNativeHookSnapshotTypes -} from "../../../database/SqlLite.js"; +import {SelectionData, SelectionParam} from "../../../bean/BoxSelection.js"; +import {queryAllHookData, queryNativeHookSnapshot, queryNativeHookSnapshotTypes} from "../../../database/SqlLite.js"; import {SpSystemTrace} from "../../SpSystemTrace.js"; import { NativeHookCallInfo, @@ -41,82 +36,83 @@ export class TabPaneNMSampleList extends BaseElement { static filter: any static filterSelect: string = "0" static source: Array = []; - static groups:any = undefined; - static types:Array = [] - static native_type:Array = ["All Heap & Anonymous VM","All Heap","All Anonymous VM"]; + static groups: any = undefined; + static types: Array = [] + static native_type: Array = ["All Heap & Anonymous VM", "All Heap", "All Anonymous VM"]; static tableMarkData: Array = [] - static selectionParam:SelectionParam|undefined = undefined - static sampleTypes:Array = [] - static sampleTypesList:any[] = [] + static selectionParam: SelectionParam | undefined = undefined + static sampleTypes: Array = [] + static sampleTypesList: any[] = [] + set data(val: SelectionParam | any) { TabPaneNMSampleList.serSelection(val) this.filterAllList() } - static serSelection(val: SelectionParam){ - if(this.selectionParam !== val){ + static serSelection(val: SelectionParam) { + if (this.selectionParam !== val) { this.clearData() this.selectionParam = val this.initTypes() } - if(val.nativeMemory.indexOf(this.native_type[0]) != -1){ + if (val.nativeMemory.indexOf(this.native_type[0]) != -1) { this.types.push("'AllocEvent'"); this.types.push("'MmapEvent'"); - }else{ - if(val.nativeMemory.indexOf(this.native_type[1]) != -1){ + } else { + if (val.nativeMemory.indexOf(this.native_type[1]) != -1) { this.types.push("'AllocEvent'"); } - if(val.nativeMemory.indexOf(this.native_type[2]) != -1){ + if (val.nativeMemory.indexOf(this.native_type[2]) != -1) { this.types.push("'MmapEvent'"); } } } - static initTypes(){ - queryNativeHookSnapshotTypes().then((result)=>{ - if(result.length>0){ + static initTypes() { + queryNativeHookSnapshotTypes().then((result) => { + if (result.length > 0) { this.sampleTypes = result } }) } - static addSampleData(data:any){ - if(TabPaneNMSampleList.tableMarkData.indexOf(data)!=-1){ + static addSampleData(data: any) { + if (TabPaneNMSampleList.tableMarkData.indexOf(data) != -1) { return } TabPaneNMSampleList.tableMarkData.push(data) this.initGroups() let rootSample = new NativeHookSamplerInfo() - rootSample.snapshot = "Snapshot"+this.numberToWord(this.source.length+1) + rootSample.snapshot = "Snapshot" + this.numberToWord(this.source.length + 1) rootSample.startTs = data.startTs rootSample.timestamp = Utils.getTimeString(data.startTs) rootSample.eventId = data.eventId - this.queryAllHookInfo(data,rootSample) + this.queryAllHookInfo(data, rootSample) } - static querySnapshot(data:any,rootSample:NativeHookSamplerInfo){ - let copyTypes = this.sampleTypes.map((type)=>{ + static querySnapshot(data: any, rootSample: NativeHookSamplerInfo) { + let copyTypes = this.sampleTypes.map((type) => { let copyType = new NativeHookSampleQueryInfo() copyType.eventType = type.eventType copyType.subType = type.subType return copyType }) - queryNativeHookSnapshot(data.startTs).then((result)=>{ - if(result.length>0){ - let nameGroup:any = {} - copyTypes.forEach((item)=> { + queryNativeHookSnapshot(data.startTs).then((result) => { + if (result.length > 0) { + let nameGroup: any = {} + copyTypes.forEach((item) => { nameGroup[item.eventType] = nameGroup[item.eventType] || [] nameGroup[item.eventType].push(item) }) - result.forEach((item)=>{ - if(nameGroup[item.eventType]!=undefined){ - if(item.subType == null){ + result.forEach((item) => { + if (nameGroup[item.eventType] != undefined) { + if (item.subType == null) { nameGroup[item.eventType][0].existing = item.existing nameGroup[item.eventType][0].growth = item.growth - }else{ - let filter = nameGroup[item.eventType].filter((type:any)=>{ - return type.subType == item.subType + } else { + let filter = nameGroup[item.eventType].filter((type: any) => { + return type.subType == item.subType }) if (filter.length > 0) { filter[0].existing = item.existing @@ -125,35 +121,35 @@ export class TabPaneNMSampleList extends BaseElement { } } }) - if(this.sampleTypesList.length>0){ - let sampleTypesListElement = this.sampleTypesList[this.sampleTypesList.length-1]; - sampleTypesListElement.forEach((item:any,index:number)=>{ + if (this.sampleTypesList.length > 0) { + let sampleTypesListElement = this.sampleTypesList[this.sampleTypesList.length - 1]; + sampleTypesListElement.forEach((item: any, index: number) => { copyTypes[index].current = copyTypes[index].growth - if(index{ + } else { + copyTypes.forEach((item: any, index: number) => { item.current = item.growth }) } this.sampleTypesList.push(copyTypes) - this.createTree(nameGroup,rootSample) + this.createTree(nameGroup, rootSample) rootSample.tempList = [...rootSample.children] this.source.push(rootSample) } }) } - static merageSampleData(leftTime:number,startNs:number,rootSample:NativeHookSampleQueryInfo,merageSample:NativeHookSampleQueryInfo){ - if(merageSample.endTs >= startNs){ + static merageSampleData(leftTime: number, startNs: number, rootSample: NativeHookSampleQueryInfo, merageSample: NativeHookSampleQueryInfo) { + if (merageSample.endTs >= startNs) { rootSample.growth += merageSample.growth } - if(merageSample.startTs > leftTime){ + if (merageSample.startTs > leftTime) { rootSample.existing++; let childSample = new NativeHookSamplerInfo()//新增最下层的叶子节点 - childSample.snapshot = "0x"+merageSample.addr + childSample.snapshot = "0x" + merageSample.addr childSample.eventId = merageSample.eventId; childSample.heapSize = merageSample.growth childSample.growth = Utils.getByteWithUnit(merageSample.growth) @@ -166,75 +162,75 @@ export class TabPaneNMSampleList extends BaseElement { rootSample.total += merageSample.growth } - static queryAllHookInfo(data:any,rootSample:NativeHookSamplerInfo){ - let copyTypes = this.sampleTypes.map((type)=>{ + static queryAllHookInfo(data: any, rootSample: NativeHookSamplerInfo) { + let copyTypes = this.sampleTypes.map((type) => { let copyType = new NativeHookSampleQueryInfo() copyType.eventType = type.eventType copyType.subType = type.subType return copyType }) - queryAllHookData(data.startTs).then((result)=>{ - if(result.length > 0){ - let nameGroup:any = {} - copyTypes.forEach((item)=> { + queryAllHookData(data.startTs).then((result) => { + if (result.length > 0) { + let nameGroup: any = {} + copyTypes.forEach((item) => { nameGroup[item.eventType] = nameGroup[item.eventType] || [] nameGroup[item.eventType].push(item) }) - let leftTime = TabPaneNMSampleList.tableMarkData.length == 1?0:TabPaneNMSampleList.tableMarkData[TabPaneNMSampleList.tableMarkData.length - 2].startTs - result.forEach((item)=>{ - if(nameGroup[item.eventType]!=undefined){ - if(item.subType == null){ - this.merageSampleData(leftTime,data.startTs,nameGroup[item.eventType][0],item) - }else{ - let filter = nameGroup[item.eventType].filter((type:any)=>{ + let leftTime = TabPaneNMSampleList.tableMarkData.length == 1 ? 0 : TabPaneNMSampleList.tableMarkData[TabPaneNMSampleList.tableMarkData.length - 2].startTs + result.forEach((item) => { + if (nameGroup[item.eventType] != undefined) { + if (item.subType == null) { + this.merageSampleData(leftTime, data.startTs, nameGroup[item.eventType][0], item) + } else { + let filter = nameGroup[item.eventType].filter((type: any) => { return type.subType == item.subType }) if (filter.length > 0) { - this.merageSampleData(leftTime,data.startTs,filter[0],item) + this.merageSampleData(leftTime, data.startTs, filter[0], item) } } } }) - if(this.sampleTypesList.length>0){ - let sampleTypesListElement = this.sampleTypesList[this.sampleTypesList.length-1]; - sampleTypesListElement.forEach((item:any,index:number)=>{ + if (this.sampleTypesList.length > 0) { + let sampleTypesListElement = this.sampleTypesList[this.sampleTypesList.length - 1]; + sampleTypesListElement.forEach((item: any, index: number) => { copyTypes[index].current = copyTypes[index].growth - if(index{ + } else { + copyTypes.forEach((item: any, index: number) => { item.current = item.growth }) } this.sampleTypesList.push(copyTypes) - this.createTree(nameGroup,rootSample) + this.createTree(nameGroup, rootSample) rootSample.tempList = [...rootSample.children] this.source.push(rootSample) } }) } - static initGroups(){ - if(this.groups==undefined){ + static initGroups() { + if (this.groups == undefined) { this.groups = {} - SpSystemTrace.HEAP_FRAME_DATA.map((frame)=>{ - this.groups[frame.eventId] = this.groups[frame.eventId]||[] + SpSystemTrace.HEAP_FRAME_DATA.map((frame) => { + this.groups[frame.eventId] = this.groups[frame.eventId] || [] this.groups[frame.eventId].push(frame) }) } } - static createTree(nameGroup:any,rootSample:NativeHookSamplerInfo){ - Object.keys(nameGroup).forEach((key)=>{ + static createTree(nameGroup: any, rootSample: NativeHookSamplerInfo) { + Object.keys(nameGroup).forEach((key) => { let parentSample = new NativeHookSamplerInfo() parentSample.snapshot = key if (nameGroup[key].length > 0) { - nameGroup[key].forEach((child:any)=>{ + nameGroup[key].forEach((child: any) => { let childSample = new NativeHookSamplerInfo() - childSample.snapshot = child.subType||child.eventType + childSample.snapshot = child.subType || child.eventType childSample.heapSize = child.growth childSample.growth = Utils.getByteWithUnit(child.growth) childSample.total = child.total @@ -243,10 +239,10 @@ export class TabPaneNMSampleList extends BaseElement { childSample.currentSize = child.current childSample.current = Utils.getByteWithUnit(child.current) parentSample.merageObj(childSample) - if(childSample.snapshot != parentSample.snapshot){//根据名称是否一致来判断是否需要添加子节点 + if (childSample.snapshot != parentSample.snapshot) {//根据名称是否一致来判断是否需要添加子节点 childSample.children.push(...child.children) parentSample.children.push(childSample) - }else { + } else { parentSample.children.push(...child.children) } }) @@ -256,25 +252,25 @@ export class TabPaneNMSampleList extends BaseElement { }) } - static prepChild(currentSample:NativeHookSamplerInfo,rootSample:NativeHookSamplerInfo){ + static prepChild(currentSample: NativeHookSamplerInfo, rootSample: NativeHookSamplerInfo) { currentSample.heapSize -= rootSample.heapSize currentSample.growth = Utils.getByteWithUnit(currentSample.heapSize) - let currentMap:any = {} - currentSample.children.forEach((currentChild)=>{ + let currentMap: any = {} + currentSample.children.forEach((currentChild) => { currentMap[currentChild.snapshot] = currentChild }) - rootSample.children.forEach((rootChild)=>{ + rootSample.children.forEach((rootChild) => { if (currentMap[rootChild.snapshot] == undefined) { let perpSample = new NativeHookSamplerInfo() - perpSample.snapshot =rootChild.snapshot + perpSample.snapshot = rootChild.snapshot currentMap[rootChild.snapshot] = perpSample currentSample.children.push(perpSample) } - this.prepChild(currentMap[rootChild.snapshot],rootChild) + this.prepChild(currentMap[rootChild.snapshot], rootChild) }) } - static clearData(){ + static clearData() { this.types = [] this.source = [] this.tblData!.dataSource = [] @@ -284,22 +280,22 @@ export class TabPaneNMSampleList extends BaseElement { TabPaneNMSampleList.filter!.firstSelect = "0" } - static numberToWord(num:number){ + static numberToWord(num: number) { let word = "" - while (num>0){ - let end = num%26 - end = end === 0?(end = 26):end; - word = String.fromCharCode(96 + end)+word - num = ( num - end ) / 26 + while (num > 0) { + let end = num % 26 + end = end === 0 ? (end = 26) : end; + word = String.fromCharCode(96 + end) + word + num = (num - end) / 26 } return word.toUpperCase() } - setRightTableData(eventId:number){ - let arr:Array = []; + setRightTableData(eventId: number) { + let arr: Array = []; let frameArr = TabPaneNMSampleList.groups[eventId]; - if(frameArr){ - frameArr.map((frame:any)=>{ + if (frameArr) { + frameArr.map((frame: any) => { let target = new NativeHookCallInfo(); target.eventId = parseInt(frame.eventId); target.depth = frame.depth; @@ -318,25 +314,25 @@ export class TabPaneNMSampleList extends BaseElement { initElements(): void { TabPaneNMSampleList.tbl = this.shadowRoot?.querySelector('#tb-native-sample'); - TabPaneNMSampleList.tbl!.addEventListener('row-click', (evt:any) => { + TabPaneNMSampleList.tbl!.addEventListener('row-click', (evt: any) => { // @ts-ignore - this.setRightTableData(evt.detail.eventId); + this.setRightTableData(evt.detail.data.eventId); }) TabPaneNMSampleList.tblData = this.shadowRoot?.querySelector('#tb-native-data'); new ResizeObserver((entries) => { if (this.parentElement?.clientHeight != 0) { // @ts-ignore - TabPaneNMSampleList.tbl?.shadowRoot.querySelector(".table").style.height = (this.parentElement.clientHeight - 10 - 31)+"px" + TabPaneNMSampleList.tbl?.shadowRoot.querySelector(".table").style.height = (this.parentElement.clientHeight - 10 - 31) + "px" TabPaneNMSampleList.tbl?.reMeauseHeight() // @ts-ignore - TabPaneNMSampleList.tblData?.shadowRoot.querySelector(".table").style.height = (this.parentElement.clientHeight - 10)+"px" + TabPaneNMSampleList.tblData?.shadowRoot.querySelector(".table").style.height = (this.parentElement.clientHeight - 10) + "px" TabPaneNMSampleList.tblData?.reMeauseHeight() } }).observe(this.parentElement!) TabPaneNMSampleList.filter = this.shadowRoot?.querySelector("#filter") - this.shadowRoot?.querySelector("#filter")!.setSelectList(TabPaneNMSampleList.native_type,null) - this.shadowRoot?.querySelector("#filter")!.getFilterData((data:FilterData)=>{ - if(data.firstSelect){ + this.shadowRoot?.querySelector("#filter")!.setSelectList(TabPaneNMSampleList.native_type, null) + this.shadowRoot?.querySelector("#filter")!.getFilterData((data: FilterData) => { + if (data.firstSelect) { TabPaneNMSampleList.filterSelect = data.firstSelect this.filterAllList() } @@ -345,42 +341,42 @@ export class TabPaneNMSampleList extends BaseElement { } - filterAllList(){ - TabPaneNMSampleList.source.forEach((rootSample)=>{ + filterAllList() { + TabPaneNMSampleList.source.forEach((rootSample) => { rootSample.heapSize = 0 rootSample.existing = 0 rootSample.total = 0 - if(TabPaneNMSampleList.filterSelect == "0"){ - rootSample.children = [...rootSample.tempList] - rootSample.tempList.forEach((parentSample)=>{ - rootSample.heapSize +=parentSample.heapSize - rootSample.existing +=parentSample.existing - rootSample.total +=parentSample.total + if (TabPaneNMSampleList.filterSelect == "0") { + rootSample.children = [...rootSample.tempList] + rootSample.tempList.forEach((parentSample) => { + rootSample.heapSize += parentSample.heapSize + rootSample.existing += parentSample.existing + rootSample.total += parentSample.total }) rootSample.growth = Utils.getByteWithUnit(rootSample.heapSize) - rootSample.totalGrowth =Utils.getByteWithUnit(rootSample.total) - }else if(TabPaneNMSampleList.filterSelect == "2"){ - if(rootSample.tempList.length>1){ + rootSample.totalGrowth = Utils.getByteWithUnit(rootSample.total) + } else if (TabPaneNMSampleList.filterSelect == "2") { + if (rootSample.tempList.length > 1) { rootSample.children = [rootSample.tempList[1]] - rootSample.heapSize +=rootSample.tempList[1].heapSize - rootSample.existing +=rootSample.tempList[1].existing + rootSample.heapSize += rootSample.tempList[1].heapSize + rootSample.existing += rootSample.tempList[1].existing rootSample.growth = Utils.getByteWithUnit(rootSample.heapSize) rootSample.total += rootSample.tempList[1].total rootSample.totalGrowth = Utils.getByteWithUnit(rootSample.total) - }else { + } else { rootSample.children = [] rootSample.growth = "" rootSample.totalGrowth = "" } - }else { - if(rootSample.tempList.length>0){ + } else { + if (rootSample.tempList.length > 0) { rootSample.children = [rootSample.tempList[0]] - rootSample.heapSize +=rootSample.tempList[0].heapSize - rootSample.existing +=rootSample.tempList[0].existing + rootSample.heapSize += rootSample.tempList[0].heapSize + rootSample.existing += rootSample.tempList[0].existing rootSample.growth = Utils.getByteWithUnit(rootSample.heapSize) rootSample.total += rootSample.tempList[0].total rootSample.totalGrowth = Utils.getByteWithUnit(rootSample.total) - }else { + } else { rootSample.children = [] rootSample.growth = "" rootSample.totalGrowth = "" @@ -392,36 +388,42 @@ export class TabPaneNMSampleList extends BaseElement { initHtml(): string { return ` - -
-
- - - - - - - - -
-
- - - - - - -
-
+ +
+
+ + + + + + + + + + + + + +
+
+ + + + + + + +
+
`; } @@ -453,4 +455,4 @@ export class TabPaneNMSampleList extends BaseElement { TabPaneNMSampleList.tbl!.recycleDataSource = TabPaneNMSampleList.source; } -} \ No newline at end of file +} diff --git a/host/ide/src/trace/component/trace/sheet/TabPaneNMStatstics.ts b/host/ide/src/trace/component/trace/sheet/TabPaneNMStatstics.ts index e022aaff55750b1ba630c1abf5646b0b58357e2f..4a1a4f0cee939ebe942a54b5135631b8ae9c4803 100644 --- a/host/ide/src/trace/component/trace/sheet/TabPaneNMStatstics.ts +++ b/host/ide/src/trace/component/trace/sheet/TabPaneNMStatstics.ts @@ -15,18 +15,13 @@ import {BaseElement, element} from "../../../../base-ui/BaseElement.js"; import {LitTable} from "../../../../base-ui/table/lit-table.js"; -import { SelectionParam} from "../../../bean/BoxSelection.js"; +import {SelectionParam} from "../../../bean/BoxSelection.js"; import { queryNativeHookStatistics, queryNativeHookStatisticsMalloc, queryNativeHookStatisticsSubType } from "../../../database/SqlLite.js"; -import { - NativeHookMalloc, - NativeHookStatistics, - NativeHookStatisticsTableData, - NativeMemory -} from "../../../bean/NativeHook.js"; +import {NativeHookMalloc, NativeHookStatistics, NativeHookStatisticsTableData} from "../../../bean/NativeHook.js"; import {Utils} from "../base/Utils.js"; import {SpSystemTrace} from "../../SpSystemTrace.js"; import "./TabProgressBar.js" @@ -35,39 +30,39 @@ import "./TabProgressBar.js" export class TabPaneNMStatstics extends BaseElement { private tbl: LitTable | null | undefined; private source: Array = [] - private native_type:Array = ["All Heap & Anonymous VM","All Heap","All Anonymous VM"]; - private allMax:number = 0; + private native_type: Array = ["All Heap & Anonymous VM", "All Heap", "All Anonymous VM"]; + private allMax: number = 0; set data(val: SelectionParam | any) { this.allMax = 0; - SpSystemTrace.EVENT_HEAP.map((heap)=>{ + SpSystemTrace.EVENT_HEAP.map((heap) => { this.allMax += heap.sumHeapSize; }); // @ts-ignore this.tbl?.shadowRoot.querySelector(".table").style.height = (this.parentElement.clientHeight - 20) + "px" // @ts-ignore this.tbl?.recycleDataSource = []; - Promise.all([queryNativeHookStatistics(val.leftNs,val.rightNs), - queryNativeHookStatisticsSubType(val.leftNs,val.rightNs), - queryNativeHookStatisticsMalloc(val.leftNs,val.rightNs) - ]).then((values)=>{ - let arr:Array = []; + Promise.all([queryNativeHookStatistics(val.leftNs, val.rightNs), + queryNativeHookStatisticsSubType(val.leftNs, val.rightNs), + queryNativeHookStatisticsMalloc(val.leftNs, val.rightNs) + ]).then((values) => { + let arr: Array = []; let index1 = val.nativeMemory.indexOf(this.native_type[0]) let index2 = val.nativeMemory.indexOf(this.native_type[1]) let index3 = val.nativeMemory.indexOf(this.native_type[2]) - this.setMemoryTypeData(val,values[0],arr); - if(index1 != -1 || index3 != -1){ - this.setSubTypeTableData(values[1],arr); + this.setMemoryTypeData(val, values[0], arr); + if (index1 != -1 || index3 != -1) { + this.setSubTypeTableData(values[1], arr); } - if(index1 != -1 || index2 != -1){ - this.setMallocTableData(values[2],arr); + if (index1 != -1 || index2 != -1) { + this.setMallocTableData(values[2], arr); } this.tbl!.recycleDataSource = arr; }) } - setMallocTableData(result:Array,arr:Array){ - result.map((malloc)=>{ + setMallocTableData(result: Array, arr: Array) { + result.map((malloc) => { let data = new NativeHookStatisticsTableData(); data.memoryTap = "Malloc " + Utils.getByteWithUnit(malloc.heapSize); data.existing = malloc.allocByte; @@ -79,111 +74,113 @@ export class TabPaneNMStatstics extends BaseElement { data.existingString = Utils.getByteWithUnit(data.existing); data.totalBytesString = Utils.getByteWithUnit(data.totalBytes); data.maxStr = Utils.getByteWithUnit(malloc.heapSize); - data.existingValue = [data.existing,data.totalBytes,this.allMax]; + data.existingValue = [data.existing, data.totalBytes, this.allMax]; arr.push(data); }) } - setSubTypeTableData(result:Array,arr:Array){ - result.map((sub)=>{ - let data = new NativeHookStatisticsTableData(); - data.memoryTap = sub.subType - data.existing = sub.allocByte - data.allocCount = sub.allocCount; - data.freeCount = sub.freeCount; - data.totalBytes = sub.allocByte + sub.freeByte; - data.totalCount = sub.allocCount + sub.freeCount; - data.max = sub.heapSize; - data.existingString = Utils.getByteWithUnit(data.existing); - data.totalBytesString = Utils.getByteWithUnit(data.totalBytes); - data.maxStr = Utils.getByteWithUnit(sub.heapSize); - data.existingValue = [data.existing,data.totalBytes,this.allMax]; - arr.push(data); + setSubTypeTableData(result: Array, arr: Array) { + result.map((sub) => { + if (sub.subType != null && sub.subType != "") { + let data = new NativeHookStatisticsTableData(); + data.memoryTap = sub.subType + data.existing = sub.allocByte + data.allocCount = sub.allocCount; + data.freeCount = sub.freeCount; + data.totalBytes = sub.allocByte + sub.freeByte; + data.totalCount = sub.allocCount + sub.freeCount; + data.max = sub.heapSize; + data.existingString = Utils.getByteWithUnit(data.existing); + data.totalBytesString = Utils.getByteWithUnit(data.totalBytes); + data.maxStr = Utils.getByteWithUnit(sub.heapSize); + data.existingValue = [data.existing, data.totalBytes, this.allMax]; + arr.push(data); + } }) } - setMemoryTypeData(val:SelectionParam,result:Array,arr:Array){ - let all:NativeHookStatisticsTableData | null = null - let heap:NativeHookStatisticsTableData | null = null - let anonymous:NativeHookStatisticsTableData | null = null - if(val.nativeMemory.indexOf(this.native_type[0]) != -1){ + setMemoryTypeData(val: SelectionParam, result: Array, arr: Array) { + let all: NativeHookStatisticsTableData | null = null + let heap: NativeHookStatisticsTableData | null = null + let anonymous: NativeHookStatisticsTableData | null = null + if (val.nativeMemory.indexOf(this.native_type[0]) != -1) { all = new NativeHookStatisticsTableData(); all.memoryTap = this.native_type[0]; } - if(val.nativeMemory.indexOf(this.native_type[1]) != -1){ + if (val.nativeMemory.indexOf(this.native_type[1]) != -1) { heap = new NativeHookStatisticsTableData(); heap.memoryTap = this.native_type[1]; } - if(val.nativeMemory.indexOf(this.native_type[2]) != -1){ + if (val.nativeMemory.indexOf(this.native_type[2]) != -1) { anonymous = new NativeHookStatisticsTableData(); anonymous.memoryTap = this.native_type[2]; } for (let hook of result) { - if(all != null){ - if(hook.eventType == "AllocEvent" || hook.eventType == "MmapEvent"){ + if (all != null) { + if (hook.eventType == "AllocEvent" || hook.eventType == "MmapEvent") { all.existing += hook.sumHeapSize; all.allocCount += hook.count; all.totalBytes += hook.sumHeapSize; all.totalCount += hook.count; - if(hook.max > all.max){ + if (hook.max > all.max) { all.max = hook.max; all.maxStr = Utils.getByteWithUnit(all.max); } - }else if(hook.eventType == "FreeEvent" || hook.eventType == "MunmapEvent"){ + } else if (hook.eventType == "FreeEvent" || hook.eventType == "MunmapEvent") { all.totalBytes += hook.sumHeapSize; all.freeCount += hook.count; all.totalCount += hook.count; } } - if(heap != null){ - if(hook.eventType == "AllocEvent" ){ + if (heap != null) { + if (hook.eventType == "AllocEvent") { heap.existing += hook.sumHeapSize; heap.allocCount += hook.count; heap.totalBytes += hook.sumHeapSize; heap.totalCount += hook.count; - if(hook.max > heap.max){ + if (hook.max > heap.max) { heap.max = hook.max; heap.maxStr = Utils.getByteWithUnit(heap.max); } - }else if(hook.eventType == "FreeEvent"){ + } else if (hook.eventType == "FreeEvent") { heap.totalBytes += hook.sumHeapSize; heap.totalCount += hook.count; heap.freeCount += hook.count; } } - if(anonymous != null){ - if(hook.eventType == "MmapEvent" ){ + if (anonymous != null) { + if (hook.eventType == "MmapEvent") { anonymous.existing += hook.sumHeapSize; anonymous.allocCount += hook.count; anonymous.totalBytes += hook.sumHeapSize; anonymous.totalCount += hook.count; - if(hook.max > anonymous.max){ + if (hook.max > anonymous.max) { anonymous.max = hook.max; anonymous.maxStr = Utils.getByteWithUnit(anonymous.max); } - }else if(hook.eventType == "MunmapEvent"){ + } else if (hook.eventType == "MunmapEvent") { anonymous.totalBytes += hook.sumHeapSize; anonymous.freeCount += hook.count; anonymous.totalCount += hook.count; } } } - if(all != null){ + if (all != null) { all.existingString = Utils.getByteWithUnit(all.existing) all.totalBytesString = Utils.getByteWithUnit(all.totalBytes) - all.existingValue = [all.existing,all.totalBytes,this.allMax] + all.existingValue = [all.existing, all.totalBytes, this.allMax] arr.push(all) } - if(heap != null){ + if (heap != null) { heap.existingString = Utils.getByteWithUnit(heap.existing) heap.totalBytesString = Utils.getByteWithUnit(heap.totalBytes) - heap.existingValue = [heap.existing,heap.totalBytes,this.allMax] + heap.existingValue = [heap.existing, heap.totalBytes, this.allMax] arr.push(heap) } - if(anonymous != null){ + if (anonymous != null) { anonymous.existingString = Utils.getByteWithUnit(anonymous.existing) anonymous.totalBytesString = Utils.getByteWithUnit(anonymous.totalBytes) - anonymous.existingValue = [anonymous.existing,anonymous.totalBytes,this.allMax] + anonymous.existingValue = [anonymous.existing, anonymous.totalBytes, this.allMax] arr.push(anonymous) } } @@ -193,7 +190,7 @@ export class TabPaneNMStatstics extends BaseElement { new ResizeObserver((entries) => { if (this.parentElement?.clientHeight != 0) { // @ts-ignore - this.tbl?.shadowRoot.querySelector(".table").style.height = (this.parentElement.clientHeight - 20)+"px" + this.tbl?.shadowRoot.querySelector(".table").style.height = (this.parentElement.clientHeight - 20) + "px" this.tbl?.reMeauseHeight() } }).observe(this.parentElement!) @@ -202,25 +199,35 @@ export class TabPaneNMStatstics extends BaseElement { initHtml(): string { return ` - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + `; } } diff --git a/host/ide/src/trace/component/trace/sheet/TabPaneNMemory.ts b/host/ide/src/trace/component/trace/sheet/TabPaneNMemory.ts index 43fde1a8ed02f124de021d53177c3312b4c0266d..6e0c365964126e3ddba382bfd393a024238edd9a 100644 --- a/host/ide/src/trace/component/trace/sheet/TabPaneNMemory.ts +++ b/host/ide/src/trace/component/trace/sheet/TabPaneNMemory.ts @@ -27,32 +27,37 @@ import {TabPaneNMSampleList} from "./TabPaneNMSampleList.js"; @element('tabpane-native-memory') export class TabPaneNMemory extends BaseElement { - private defaultNativeTypes = ["All Heap & Anonymous VM","All Heap","All Anonymous VM"]; + private defaultNativeTypes = ["All Heap & Anonymous VM", "All Heap", "All Anonymous VM"]; private tbl: LitTable | null | undefined; private tblData: LitTable | null | undefined; private source: Array = [] - private native_type:Array = [...this.defaultNativeTypes]; + private native_type: Array = [...this.defaultNativeTypes]; private statsticsSelection: Array = [] private queryResult: Array = [] - private filterAllocationType:string = "0" - private filterNativeType:string = "0" - private currentSelection:SelectionParam|undefined - private rowSelectData:any = undefined; + private filterAllocationType: string = "0" + private filterNativeType: string = "0" + private currentSelection: SelectionParam | undefined + private rowSelectData: any = undefined; + set data(val: SelectionParam | any) { - if(val==this.currentSelection){ + if (val == this.currentSelection) { return } this.currentSelection = val this.initFilterTypes() - let types:Array = [] - if(val.nativeMemory.indexOf(this.defaultNativeTypes[0]) != -1){ + this.queryData(val) + } + + queryData(val: SelectionParam | any) { + let types: Array = [] + if (val.nativeMemory.indexOf(this.defaultNativeTypes[0]) != -1) { types.push("'AllocEvent'"); types.push("'MmapEvent'"); - }else{ - if(val.nativeMemory.indexOf(this.defaultNativeTypes[1]) != -1){ + } else { + if (val.nativeMemory.indexOf(this.defaultNativeTypes[1]) != -1) { types.push("'AllocEvent'"); } - if(val.nativeMemory.indexOf(this.defaultNativeTypes[2]) != -1){ + if (val.nativeMemory.indexOf(this.defaultNativeTypes[2]) != -1) { types.push("'MmapEvent'"); } } @@ -60,97 +65,99 @@ export class TabPaneNMemory extends BaseElement { // @ts-ignore this.tbl?.shadowRoot.querySelector(".table").style.height = (this.parentElement.clientHeight - 20 - 31) + "px" // @ts-ignore - this.tblData?.shadowRoot.querySelector(".table").style.height = (this.parentElement.clientHeight -20)+"px" + this.tblData?.shadowRoot.querySelector(".table").style.height = (this.parentElement.clientHeight - 20) + "px" // @ts-ignore this.tblData?.recycleDataSource = []; // @ts-ignore this.tbl?.recycleDataSource = []; - queryNativeHookEventId(val.leftNs,val.rightNs,types).then((result)=>{ - if(result.length > 0){ + queryNativeHookEventId(val.leftNs, val.rightNs, types).then((result) => { + if (result.length > 0) { this.queryResult = result this.source = this.handleQueryResult(result); - }else{ + } else { this.source = []; } this.filterQueryData() }) } - fromStastics(val: SelectionParam | any){ + fromStastics(val: SelectionParam | any) { let filter = this.shadowRoot?.querySelector("#filter") + if (this.currentSelection != val) { + this.initFilterTypes() + } let typeIndexOf = this.native_type.indexOf(val.statisticsSelectData.memoryTap); - if(this.statsticsSelection.indexOf(val.statisticsSelectData) == -1&&typeIndexOf == -1){ + if (this.statsticsSelection.indexOf(val.statisticsSelectData) == -1 && typeIndexOf == -1) { this.statsticsSelection.push(val.statisticsSelectData) this.native_type.push(val.statisticsSelectData.memoryTap) typeIndexOf = this.native_type.length - 1 } - if(this.currentSelection != val){ - //设置选项后刷新当前的数据 - this.data = val - //todo 设置filter当前的选项和选中项 - filter!.setSelectList(null,this.native_type) - filter!.secondSelect = typeIndexOf+"" - this.filterNativeType = typeIndexOf+"" - }else{ + if (this.currentSelection != val) { + this.currentSelection = val + filter!.setSelectList(null, this.native_type) + filter!.secondSelect = typeIndexOf + "" + this.filterNativeType = typeIndexOf + "" + this.queryData(val) + } else { this.tblData!.recycleDataSource = []; this.rowSelectData = undefined - filter!.setSelectList(null,this.native_type) - filter!.secondSelect = typeIndexOf+"" - this.filterNativeType = typeIndexOf+"" + filter!.setSelectList(null, this.native_type) + filter!.secondSelect = typeIndexOf + "" + this.filterNativeType = typeIndexOf + "" //直接将当前数据过滤即可 this.filterQueryData() } } - getTypeFromIndex(indexOf:number,item:NativeHookStatistics):boolean{ - if(indexOf == -1){ + getTypeFromIndex(indexOf: number, item: NativeHookStatistics): boolean { + if (indexOf == -1) { return false; } - if(indexOf < 3){ - if(indexOf == 0){ + if (indexOf < 3) { + if (indexOf == 0) { return true - }else if(indexOf == 1){ + } else if (indexOf == 1) { return item.eventType == "AllocEvent" - }else if(indexOf == 2){ + } else if (indexOf == 2) { return item.eventType == "MmapEvent" } - }else if(indexOf-3 < this.statsticsSelection.length){ + } else if (indexOf - 3 < this.statsticsSelection.length) { let selectionElement = this.statsticsSelection[indexOf - 3]; - if(selectionElement.memoryTap!=undefined&&selectionElement.max!=undefined){ + if (selectionElement.memoryTap != undefined && selectionElement.max != undefined) { if (selectionElement.memoryTap.indexOf("Malloc") != -1) { - return item.eventType == "AllocEvent"&&item.heapSize == selectionElement.max - }else { - return item.subType == selectionElement.memoryTap&&item.heapSize == selectionElement.max + return item.eventType == "AllocEvent" && item.heapSize == selectionElement.max + } else { + return item.subType == selectionElement.memoryTap && item.heapSize == selectionElement.max } } } return false; } - handleQueryResult(result:Array):Array{ - let resultMap = new Map(); - result.map((r)=>{ - resultMap.set(r.eventId,r); + handleQueryResult(result: Array): Array { + let resultMap = new Map(); + result.map((r) => { + resultMap.set(r.eventId, r); }) - let data :Array = []; + let data: Array = []; let frameArr: Array = []; SpSystemTrace.HEAP_FRAME_DATA.map((frame) => { let frameEventId = parseInt(frame.eventId); - if(frameEventId >= result[0].eventId && frameEventId <= result[result.length - 1].eventId){ - if(resultMap.has(frameEventId) && frame.depth == 0){ + if (frameEventId >= result[0].eventId && frameEventId <= result[result.length - 1].eventId) { + if (resultMap.has(frameEventId) && frame.depth == 0) { frameArr.push(frame); } } - if(frameEventId > result[result.length -1].eventId){ + if (frameEventId > result[result.length - 1].eventId) { return false; } }); - let frameMap = new Map(); - frameArr.map((frame)=>{ - frameMap.set(parseInt(frame.eventId),frame); + let frameMap = new Map(); + frameArr.map((frame) => { + frameMap.set(parseInt(frame.eventId), frame); }) - for (let i = 0,len = result.length; i < len; i++) { + for (let i = 0, len = result.length; i < len; i++) { let hook = result[i]; let memory = new NativeMemory(); memory.index = i; @@ -159,12 +166,12 @@ export class TabPaneNMemory extends BaseElement { memory.subType = hook.subType; memory.heapSize = hook.heapSize; memory.heapSizeUnit = Utils.getByteWithUnit(hook.heapSize); - memory.addr = "0x"+hook.addr; + memory.addr = "0x" + hook.addr; memory.startTs = hook.startTs; memory.timestamp = Utils.getTimeString(hook.startTs); (memory as any).isSelected = hook.isSelected; let frame = frameMap.get(hook.eventId); - if(frame != null && frame != undefined){ + if (frame != null && frame != undefined) { let sym_arr = frame.AllocationFunction?.split("/"); let lib_arr = frame.MoudleName?.split("/"); memory.symbol = sym_arr![sym_arr!.length - 1]; @@ -175,10 +182,12 @@ export class TabPaneNMemory extends BaseElement { return data } - initFilterTypes(){ + initFilterTypes() { let filter = this.shadowRoot?.querySelector("#filter") this.queryResult = [] - filter!.setSelectList(null,this.defaultNativeTypes) + this.native_type = [...this.defaultNativeTypes] + this.statsticsSelection = [] + filter!.setSelectList(null, [...this.defaultNativeTypes]) filter!.firstSelect = "0" filter!.secondSelect = "0" this.filterAllocationType = "0" @@ -191,73 +200,93 @@ export class TabPaneNMemory extends BaseElement { this.tblData = this.shadowRoot?.querySelector('#tb-native-data'); this.tbl!.addEventListener("row-click", (e) => { // @ts-ignore - let data = (e.detail as NativeMemory); + let data = (e.detail.data as NativeMemory); this.rowSelectData = data this.setRightTableData(data); - document.dispatchEvent(new CustomEvent('triangle-flag', {detail: {time:data.startTs,type:"triangle"}})); + document.dispatchEvent(new CustomEvent('triangle-flag', {detail: {time: data.startTs, type: "triangle"}})); }) new ResizeObserver((entries) => { if (this.parentElement?.clientHeight != 0) { // @ts-ignore - this.tbl?.shadowRoot.querySelector(".table").style.height = (this.parentElement.clientHeight)-10-31+"px"; + this.tbl?.shadowRoot.querySelector(".table").style.height = (this.parentElement.clientHeight) - 10 - 31 + "px"; this.tbl?.reMeauseHeight(); // @ts-ignore - this.tblData?.shadowRoot.querySelector(".table").style.height = (this.parentElement.clientHeight)-10+"px" + this.tblData?.shadowRoot.querySelector(".table").style.height = (this.parentElement.clientHeight) - 10 + "px" this.tblData?.reMeauseHeight() } }).observe(this.parentElement!) let filter = this.shadowRoot?.querySelector("#filter") - this.shadowRoot?.querySelector("#filter")!.getFilterData((data:FilterData)=>{ + this.shadowRoot?.querySelector("#filter")!.getFilterData((data: FilterData) => { if (data.mark) { - if(this.rowSelectData!=undefined){ - let filterTemp = this.queryResult.filter((tempItem)=>{ - return tempItem.eventId == this.rowSelectData.eventId - }) - if(filterTemp.length>0){ - filterTemp[0].isSelected = true - } - TabPaneNMSampleList.addSampleData(this.rowSelectData) - if(this.rowSelectData.selectedCallback){ - this.rowSelectData.isSelected = true - this.rowSelectData.selectedCallback() + document.dispatchEvent(new CustomEvent('triangle-flag', { + detail: { + time: "", type: "square", timeCallback: (t: any) => { + let minTs = 0 + let minItem: any = undefined + let filterTemp = this.source.filter((tempItem) => { + if (minTs == 0 || (tempItem.startTs - t != 0 && Math.abs(tempItem.startTs - t) < minTs)) { + minTs = Math.abs(tempItem.startTs - t) + minItem = tempItem + } + return tempItem.startTs == t + }) + if (filterTemp.length > 0) { + filterTemp[0].isSelected = true + } else { + if (minItem) { + filterTemp.push(minItem) + minItem.isSelected = true + } + } + if (filterTemp.length > 0) { + this.rowSelectData = filterTemp[0] + let currentSelection = this.queryResult.filter((item) => { + return item.startTs == this.rowSelectData.startTs + }) + if (currentSelection.length > 0) { + currentSelection[0].isSelected = true + } + TabPaneNMSampleList.addSampleData(this.rowSelectData) + this.tbl!.scrollToData(this.rowSelectData) + } + } } - document.dispatchEvent(new CustomEvent('triangle-flag', {detail: {time:this.rowSelectData.startTs,type:"square"}})); - } - }else { - this.filterAllocationType = data.firstSelect||"0" - this.filterNativeType = data.secondSelect||"0" + })); + } else { + this.filterAllocationType = data.firstSelect || "0" + this.filterNativeType = data.secondSelect || "0" this.filterQueryData() } }) filter!.firstSelect = "1" } - filterQueryData(){ - if (this.queryResult.length > 0&&this.currentSelection) { - let filter = this.queryResult.filter((item)=>{ + filterQueryData() { + if (this.queryResult.length > 0 && this.currentSelection) { + let filter = this.queryResult.filter((item) => { let filterAllocation = true - if(this.filterAllocationType=="1"){ - filterAllocation = item.startTs>=this.currentSelection!.leftNs&&item.startTs<=this.currentSelection!.rightNs&&item.endTs>this.currentSelection!.rightNs - }else if(this.filterAllocationType=="2"){ - filterAllocation = item.startTs>=this.currentSelection!.leftNs&&item.startTs<=this.currentSelection!.rightNs&&item.endTs<=this.currentSelection!.rightNs + if (this.filterAllocationType == "1") { + filterAllocation = item.startTs >= this.currentSelection!.leftNs && item.startTs <= this.currentSelection!.rightNs && item.endTs > this.currentSelection!.rightNs + } else if (this.filterAllocationType == "2") { + filterAllocation = item.startTs >= this.currentSelection!.leftNs && item.startTs <= this.currentSelection!.rightNs && item.endTs <= this.currentSelection!.rightNs } - let filterNative = this.getTypeFromIndex(parseInt(this.filterNativeType),item) - return filterAllocation&&filterNative + let filterNative = this.getTypeFromIndex(parseInt(this.filterNativeType), item) + return filterAllocation && filterNative }) - if(filter.length>0){ + if (filter.length > 0) { this.source = this.handleQueryResult(filter); this.tbl!.recycleDataSource = this.source; - }else { + } else { this.source = [] this.tbl!.recycleDataSource = []; } } } - setRightTableData(hook:NativeMemory){ - let arr:Array = []; + setRightTableData(hook: NativeMemory) { + let arr: Array = []; let frameArr = SpSystemTrace.HEAP_FRAME_DATA.filter((frame) => parseInt(frame.eventId) == hook.eventId); - frameArr.map((frame)=>{ + frameArr.map((frame) => { let target = new NativeHookCallInfo(); target.eventId = parseInt(frame.eventId); target.depth = frame.depth; @@ -275,38 +304,46 @@ export class TabPaneNMemory extends BaseElement { initHtml(): string { return ` - -
-
- - - - - - - - - - -
-
- - - - - - -
-
+ +
+
+ + + + + + + + + + + + + + + + + +
+
+ + + + + + + +
+
`; } -} \ No newline at end of file +} diff --git a/host/ide/src/trace/component/trace/sheet/TabPaneNetworkAbility.ts b/host/ide/src/trace/component/trace/sheet/TabPaneNetworkAbility.ts new file mode 100644 index 0000000000000000000000000000000000000000..34df8066ba9bfe0aacd2a371d5cf49de5f13151e --- /dev/null +++ b/host/ide/src/trace/component/trace/sheet/TabPaneNetworkAbility.ts @@ -0,0 +1,168 @@ +/* + * 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. + */ + +import {BaseElement, element} from "../../../../base-ui/BaseElement.js"; +import {LitTable} from "../../../../base-ui/table/lit-table.js"; +import {SelectionParam} from "../../../bean/BoxSelection.js"; +import {getTabNetworkAbilityData} from "../../../database/SqlLite.js"; +import {SystemNetworkSummary} from "../../../bean/AbilityMonitor.js"; +import {Utils} from "../base/Utils.js"; +import "../../../component/SpFilter.js"; +import {ColorUtils} from "../base/ColorUtils.js"; + +@element('tabpane-network-ability') +export class TabPaneNetworkAbility extends BaseElement { + private tbl: LitTable | null | undefined; + private source: Array = []; + private float: HTMLDivElement | null | undefined; + private queryResult: Array = [] + private search: HTMLInputElement | undefined | null + + set data(val: SelectionParam | any) { + // @ts-ignore + this.tbl?.shadowRoot.querySelector(".table").style.height = (this.parentElement.clientHeight - 45) + "px" + this.queryDataByDB(val) + } + + initElements(): void { + this.tbl = this.shadowRoot?.querySelector('#tb-network-ability'); + new ResizeObserver((entries) => { + if (this.parentElement?.clientHeight != 0) { + // @ts-ignore + this.tbl?.shadowRoot.querySelector(".table").style.height = (this.parentElement.clientHeight - 45) + "px" + this.tbl?.reMeauseHeight() + } + }).observe(this.parentElement!) + this.tbl!.addEventListener('column-click', (evt) => { + // @ts-ignore + this.sortByColumn(evt.detail) + }); + } + + filterData() { + if (this.queryResult.length > 0) { + let filter = this.queryResult.filter((item) => { + let array = this.toNetWorkAbilityArray(item) + let isInclude = array.filter(value => value.indexOf(this.search!.value) > -1); + return isInclude.length > 0 + }); + if (filter.length > 0) { + this.source = filter; + this.tbl!.recycleDataSource = this.source; + } else { + this.source = [] + this.tbl!.recycleDataSource = []; + } + } + } + + toNetWorkAbilityArray(systemNetworkSummary: SystemNetworkSummary): any[] { + let array: Array = [] + array.push(systemNetworkSummary.startTimeStr) + array.push(systemNetworkSummary.durationStr) + array.push(systemNetworkSummary.dataReceivedStr) + array.push(systemNetworkSummary.dataReceivedSecStr) + array.push(systemNetworkSummary.dataSendSecStr) + array.push(systemNetworkSummary.dataSendStr) + array.push(systemNetworkSummary.packetsIn.toString()) + array.push(systemNetworkSummary.packetsOut.toString()) + array.push(systemNetworkSummary.packetsOutSec.toString()) + return array + } + + queryDataByDB(val: SelectionParam | any) { + getTabNetworkAbilityData(val.leftNs, val.rightNs).then(item => { + if (item.length != null && item.length > 0) { + for (const systemNetworkSummary of item) { + if (systemNetworkSummary.startTime == 0) { + systemNetworkSummary.startTimeStr = '0:000.000.000'; + } else { + systemNetworkSummary.startTimeStr = Utils.getTimeStampHMS(systemNetworkSummary.startTime); + } + systemNetworkSummary.durationStr = Utils.getDurString(systemNetworkSummary.duration); + systemNetworkSummary.dataReceivedStr = Utils.getBinaryByteWithUnit(systemNetworkSummary.dataReceived); + systemNetworkSummary.dataReceivedSecStr = Utils.getBinaryByteWithUnit(systemNetworkSummary.dataReceivedSec); + systemNetworkSummary.dataSendStr = Utils.getBinaryByteWithUnit(systemNetworkSummary.dataSend); + systemNetworkSummary.dataSendSecStr = Utils.getBinaryByteWithUnit(systemNetworkSummary.dataSendSec); + systemNetworkSummary.packetsInStr = ColorUtils.formatNumberComma(systemNetworkSummary.packetsIn); + systemNetworkSummary.packetsInSecStr = systemNetworkSummary.packetsInSec.toFixed(2); + systemNetworkSummary.packetsOutStr = ColorUtils.formatNumberComma(systemNetworkSummary.packetsOut); + systemNetworkSummary.packetsOutSecStr = systemNetworkSummary.packetsOutSec.toFixed(2); + } + this.source = item + this.queryResult = item; + this.tbl!.recycleDataSource = this.source; + } else { + this.source = [] + this.queryResult = [] + this.tbl!.recycleDataSource = []; + } + }) + } + + initHtml(): string { + return ` + + + + + + + + + + + + + + `; + } + + sortByColumn(detail: any) { + // @ts-ignore + function compare(property, sort, type) { + return function (a: SystemNetworkSummary, b: SystemNetworkSummary) { + if (type === 'number') { + // @ts-ignore + return sort === 2 ? parseFloat(b[property]) - parseFloat(a[property]) : parseFloat(a[property]) - parseFloat(b[property]); + } else { + // @ts-ignore + if (b[property] > a[property]) { + return sort === 2 ? 1 : -1; + } else { // @ts-ignore + if (b[property] == a[property]) { + return 0; + } else { + return sort === 2 ? -1 : 1; + } + } + } + } + } + + if (detail.key === 'startTime') { + this.source.sort(compare(detail.key, detail.sort, 'string')) + } else { + this.source.sort(compare(detail.key, detail.sort, 'number')) + } + this.tbl!.dataSource = this.source; + } +} \ No newline at end of file diff --git a/host/ide/src/trace/component/trace/sheet/TabPanePTS.ts b/host/ide/src/trace/component/trace/sheet/TabPanePTS.ts index 9b3bf4c8b4ac48cfd85f21891491d6dbf08c7111..719a8db6b16aebae91a082413d58dab869081042 100644 --- a/host/ide/src/trace/component/trace/sheet/TabPanePTS.ts +++ b/host/ide/src/trace/component/trace/sheet/TabPanePTS.ts @@ -50,7 +50,7 @@ export class TabPanePTS extends BaseElement { new ResizeObserver((entries) => { if (this.parentElement?.clientHeight != 0) { // @ts-ignore - this.tbl?.shadowRoot.querySelector(".table").style.height = (this.parentElement.clientHeight - 45)+"px" + this.tbl?.shadowRoot.querySelector(".table").style.height = (this.parentElement.clientHeight - 45) + "px" this.tbl?.reMeauseHeight() } }).observe(this.parentElement!) @@ -61,8 +61,8 @@ export class TabPanePTS extends BaseElement { let pMap: Map = new Map(); let ptMap: Map = new Map(); let ptsMap: Map = new Map(); - SpSystemTrace.SPT_DATA.map((d)=>{ - if(!(d.end_ts < val.leftNs || d.start_ts > val.rightNs)){ + SpSystemTrace.SPT_DATA.map((d) => { + if (!(d.end_ts < val.leftNs || d.start_ts > val.rightNs)) { if (pMap.has(d.processId + "")) { let obj1 = pMap.get(d.processId + ""); obj1!.count++; @@ -244,24 +244,28 @@ export class TabPanePTS extends BaseElement { initHtml(): string { return ` - - - - - - - - - - - + + + + + + + + + + + + + + + + `; } - } \ No newline at end of file diff --git a/host/ide/src/trace/component/trace/sheet/TabPaneSPT.ts b/host/ide/src/trace/component/trace/sheet/TabPaneSPT.ts index 2c068cdf95997c8cf1a15d7c4c73853633fc0509..a79788984b6410dcb28026241274b7eae433c21b 100644 --- a/host/ide/src/trace/component/trace/sheet/TabPaneSPT.ts +++ b/host/ide/src/trace/component/trace/sheet/TabPaneSPT.ts @@ -33,7 +33,7 @@ export class TabPaneSPT extends BaseElement { set data(val: SelectionParam | any) { // @ts-ignore - this.tbl?.shadowRoot?.querySelector(".table").style.height = (this.parentElement!.clientHeight - 45)+"px" + this.tbl?.shadowRoot?.querySelector(".table").style.height = (this.parentElement!.clientHeight - 45) + "px" this.range!.textContent = "Selected range: " + parseFloat(((val.rightNs - val.leftNs) / 1000000.0).toFixed(5)) + " ms" if (this.loadDataInCache) { this.queryDataByCacheData(val).then((result) => { @@ -50,7 +50,7 @@ export class TabPaneSPT extends BaseElement { new ResizeObserver((entries) => { if (this.parentElement?.clientHeight != 0) { // @ts-ignore - this.tbl?.shadowRoot?.querySelector(".table").style.height = (this.parentElement!.clientHeight - 45)+"px" + this.tbl?.shadowRoot?.querySelector(".table").style.height = (this.parentElement!.clientHeight - 45) + "px" this.tbl?.reMeauseHeight() } }).observe(this.parentElement!) @@ -64,7 +64,7 @@ export class TabPaneSPT extends BaseElement { let sptMap: Map = new Map(); // @ts-ignore SpSystemTrace.SPT_DATA.map((d) => { - if(!(d.end_ts < val.leftNs || d.start_ts > val.rightNs)){ + if (!(d.end_ts < val.leftNs || d.start_ts > val.rightNs)) { if (statesMap.has(d.state)) { let obj1 = statesMap.get(d.state); obj1!.count++; @@ -242,24 +242,28 @@ export class TabPaneSPT extends BaseElement { initHtml(): string { return ` - - - - - - - - - - - + + + + + + + + + + + + + + + + `; } - } \ No newline at end of file diff --git a/host/ide/src/trace/component/trace/sheet/TabPaneSlices.ts b/host/ide/src/trace/component/trace/sheet/TabPaneSlices.ts index 705749bde1c3f9c88721b02cb51372de1f4bb241..c5960655f68f0b734a2198e4a5de92de3d13b1bb 100644 --- a/host/ide/src/trace/component/trace/sheet/TabPaneSlices.ts +++ b/host/ide/src/trace/component/trace/sheet/TabPaneSlices.ts @@ -62,20 +62,24 @@ export class TabPaneSlices extends BaseElement { initHtml(): string { return ` - - - - - - - - + + + + + + + + + + + + `; } diff --git a/host/ide/src/trace/component/trace/sheet/TabPaneThreadStates.ts b/host/ide/src/trace/component/trace/sheet/TabPaneThreadStates.ts index a9ab4a43b2d40ff482493d0631ddca5e9c622c19..196cb912e048f0f162ffba78d0dccb7fea3bc76b 100644 --- a/host/ide/src/trace/component/trace/sheet/TabPaneThreadStates.ts +++ b/host/ide/src/trace/component/trace/sheet/TabPaneThreadStates.ts @@ -73,27 +73,35 @@ export class TabPaneThreadStates extends BaseElement { initHtml(): string { return ` - -
- - -
- - - - - - - - - - + +
+ + +
+ + + + + + + + + + + + + + + + + + `; } diff --git a/host/ide/src/trace/component/trace/sheet/TabPaneThreadSwitch.ts b/host/ide/src/trace/component/trace/sheet/TabPaneThreadSwitch.ts index 9af0690e12a460a5c9c331fd940b6ac01e7c5360..d833eac2a4e5fdb4ab6660401cbda327a0a10cc6 100644 --- a/host/ide/src/trace/component/trace/sheet/TabPaneThreadSwitch.ts +++ b/host/ide/src/trace/component/trace/sheet/TabPaneThreadSwitch.ts @@ -33,7 +33,7 @@ export class TabPaneThreadSwitch extends BaseElement { set data(val: SelectionParam | any) { //@ts-ignore - this.tbl?.shadowRoot?.querySelector(".table")?.style?.height = (this.parentElement!.clientHeight - 45)+"px"; + this.tbl?.shadowRoot?.querySelector(".table")?.style?.height = (this.parentElement!.clientHeight - 45) + "px"; this.range!.textContent = "Selected range: " + parseFloat(((val.rightNs - val.leftNs) / 1000000.0).toFixed(5)) + " ms"; if (this.loadDataInCache) { this.queryDataByCacheData(val).then((arr) => { @@ -50,7 +50,7 @@ export class TabPaneThreadSwitch extends BaseElement { new ResizeObserver((entries) => { if (this.parentElement?.clientHeight != 0) { // @ts-ignore - this.tbl?.shadowRoot?.querySelector(".table").style.height = (this.parentElement!.clientHeight - 45)+"px" + this.tbl?.shadowRoot?.querySelector(".table").style.height = (this.parentElement!.clientHeight - 45) + "px" this.tbl?.reMeauseHeight() } }).observe(this.parentElement!); @@ -63,7 +63,7 @@ export class TabPaneThreadSwitch extends BaseElement { let spMap: Map = new Map(); let sptMap: Map = new Map(); SpSystemTrace.SPT_DATA.map((d) => { - if(!(d.end_ts < val.leftNs || d.start_ts > val.rightNs)){ + if (!(d.end_ts < val.leftNs || d.start_ts > val.rightNs)) { if (statesMap.has(d.state)) { let obj1 = statesMap.get(d.state); obj1!.count++; @@ -241,18 +241,20 @@ export class TabPaneThreadSwitch extends BaseElement { initHtml(): string { return ` - - - - - - + + + + + + + + `; } } \ No newline at end of file diff --git a/host/ide/src/trace/component/trace/sheet/TabPerfProfile.ts b/host/ide/src/trace/component/trace/sheet/TabPerfProfile.ts new file mode 100644 index 0000000000000000000000000000000000000000..498f08631aa70ebfed44447ca689f652db2b568e --- /dev/null +++ b/host/ide/src/trace/component/trace/sheet/TabPerfProfile.ts @@ -0,0 +1,459 @@ +/* + * 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. + */ + +import {BaseElement, element} from "../../../../base-ui/BaseElement.js"; +import {LitTable} from "../../../../base-ui/table/lit-table.js"; +import "./TabPaneFilter.js"; +import {FilterData, TabPaneFilter} from "./TabPaneFilter.js"; +import {SelectionParam} from "../../../bean/BoxSelection.js"; +import {perfDataQuery} from "../../hiperf/PerfDataQuery.js"; +import {PerfCallChainMerageData} from "../../../bean/PerfProfile.js"; +import "../../FrameChart.js"; +import { FrameChart } from "../../FrameChart.js"; +import { ChartMode } from "../../../database/ProcedureWorkerCommon.js"; +import '../../DisassemblingWindow.js' +import {DisassemblingWindow} from "../../DisassemblingWindow.js"; +import {Cmd} from "../../../../command/cmd.js"; +import {SpApplication} from "../../../SpApplication.js"; + +@element('tabpane-perf-profile') +export class TabpanePerfProfile extends BaseElement { + private tbl: LitTable | null | undefined; + private tbr: LitTable | null | undefined; + private rightSource: Array = []; + private filter: any + private sampleIds:string[] = [] + private dataSource:any[] = [] + private currentSelectedData:any = undefined + private frameChart: FrameChart | null | undefined; + private isChartShow: boolean = false; + private systmeRuleName = "/system/" + private numRuleName = "/max/min/" + private modal: DisassemblingWindow | null | undefined; + + set data(val: SelectionParam | any) { + this.modal!.style.display = 'none'; + (this.shadowRoot?.querySelector('#show_table > #left_table') as HTMLElement)!.style.visibility = "visible"; + if (this.parentElement!.clientHeight > this.filter!.clientHeight) { + this.filter!.style.display = "flex"; + } else { + this.filter!.style.display = "none"; + } + this.filter!.initializeFilterTree(true,true,true) + this.filter!.filterValue = "" + perfDataQuery.searchValue = "" + this.sampleIds = val.perfSampleIds + this.dataSource = perfDataQuery.getCallChainsBySampleIds(val.perfSampleIds,true) + this.frameChart!.mode = ChartMode.Count; + this.frameChart!.data = this.dataSource; + this.frameChart?.updateCanvas(true); + this.frameChart?.calculateChartData(); + this.tbl!.recycleDataSource = this.dataSource; + this.tbr!.recycleDataSource = [] + } + + getParentTree(src: Array, target: PerfCallChainMerageData, parents: Array): boolean { + for (let call of src) { + if (call.id == target.id) { + parents.push(call) + return true + } else { + if (this.getParentTree(call.children as Array, target, parents)) { + parents.push(call); + return true; + } + } + } + return false; + } + + getChildTree(src: Array, id: string, children: Array): boolean { + for (let call of src) { + if (call.id == id && call.children.length == 0) { + children.push(call) + return true + } else { + if (this.getChildTree(call.children as Array, id, children)) { + children.push(call); + return true; + } + } + } + return false; + } + + setRightTableData(call: PerfCallChainMerageData) { + let parents: Array = []; + let children: Array = []; + this.getParentTree(this.dataSource, call, parents); + let maxId = call.id; + let maxDur = 0; + + function findMaxStack(call: PerfCallChainMerageData) { + if (call.children.length == 0) { + if (call.dur > maxDur) { + maxDur = call.dur; + maxId = call.id; + } + } else { + call.children.map((callChild) => { + findMaxStack(callChild); + }) + } + } + findMaxStack(call); + this.getChildTree(call.children as Array, maxId, children); + let arr = parents.reverse().concat(children.reverse()); + for (let data of arr) { + data.type = (data.libName.endsWith(".so.1") || data.libName.endsWith(".dll") || data.libName.endsWith(".so")) ? 0 : 1; + } + let len = arr.length; + this.rightSource = arr; + this.tbr!.recycleDataSource = len == 0 ? [] : this.rightSource.slice(3,len); + } + + initElements(): void { + this.tbl = this.shadowRoot?.querySelector('#tb-perf-profile'); + this.frameChart = this.shadowRoot?.querySelector('#framechart'); + let pageTab = this.shadowRoot?.querySelector('#show_table'); + let pageChart = this.shadowRoot?.querySelector('#show_chart'); + this.modal = this.shadowRoot?.querySelector('tab-native-data-modal'); + this.parentElement!.onscroll = () => { + this.frameChart!.tabPaneScrollTop = this.parentElement!.scrollTop; + }; + this.tbl!.rememberScrollTop = true; + this.filter = this.shadowRoot?.querySelector("#filter") + this.tbl!.addEventListener('row-click', (evt:any) => { + // @ts-ignore + let data = (evt.detail.data as PerfCallChainMerageData); + this.setRightTableData(data); + data.isSelected = true; + this.currentSelectedData = data; + this.tbr?.clearAllSelection(data); + this.tbr?.setCurrentSelection(data); + // @ts-ignore + if((evt.detail as any).callBack){ + // @ts-ignore + (evt.detail as any).callBack(true) + } + }) + this.tbr = this.shadowRoot?.querySelector('#tb-perf-list'); + let lastClikTime = 0; + this.tbr!.addEventListener('row-click', (evt:any) => { + // @ts-ignore + let data = (evt.detail.data as PerfCallChainMerageData); + this.tbl?.clearAllSelection(data); + (data as any).isSelected = true + this.tbl!.scrollToData(data) + // @ts-ignore + if ((evt.detail as any).callBack) { + // @ts-ignore + (evt.detail as any).callBack(true) + } + let spApplication = document.getElementsByTagName("sp-application")[0]; + if (Date.now() - lastClikTime < 200 && spApplication.vs){ + (this.shadowRoot?.querySelector('#show_table > #left_table') as HTMLElement)!.style.visibility = "hidden"; + this.filter.style.display = "none"; + this.modal!.showLoading(); + // @ts-ignore + let data = (evt.detail.data as PerfCallChainMerageData); + let path = data.path; + let addr = data.vaddrInFile; + let addrHex = addr.toString(16); + if (path.trim() === '[kernel.kallsyms]'){ + this.modal?.showContent(`error : Symbol ${data.symbol} lib is [kernel.kallsyms] ,not support `,addrHex); + } else if (path.trim() ===''){ + this.modal?.showContent(`error : Symbol ${data.symbol} lib is null `,addrHex); + }else if (addr < 0){ + this.modal?.showContent(`error : Symbol ${data.symbol} current addr is error ` + addrHex,addrHex); + } else { + const binDir = 'C:/binary_cache'; + let binPath = binDir + path; + let cmd = 'C:/binary_cache/llvm-objdump.exe -S ' + binPath; + Cmd.execObjDump(cmd,addrHex,(result : any) => { + this.modal?.showContent(result,addrHex); + }) + } + } + lastClikTime = Date.now(); + }) + this.tbr = this.shadowRoot?.querySelector('#tb-perf-list'); + let filterHeight = 0; + new ResizeObserver((entries) => { + let tabPaneFilter = this.shadowRoot!.querySelector("#filter") as HTMLElement; + if (tabPaneFilter.clientHeight > 0) filterHeight = tabPaneFilter.clientHeight; + if (this.parentElement!.clientHeight > filterHeight) { + tabPaneFilter.style.display = "flex"; + } else { + tabPaneFilter.style.display = "none"; + } + this.modal!.style.height = (this.shadowRoot?.querySelector('#show_table > #right_table') as HTMLElement)!.clientHeight - 2 + 'px'; //2 is borderWidth + if ((this.shadowRoot?.querySelector('#show_table > #left_table') as HTMLElement)!.style.visibility == "hidden") { + tabPaneFilter.style.display = "none"; + } + if (this.parentElement?.clientHeight != 0) { + if (this.isChartShow) { + this.frameChart?.updateCanvas(false,entries[0].contentRect.width); + this.frameChart?.calculateChartData(); + } + // @ts-ignore + this.tbl?.shadowRoot.querySelector(".table").style.height = (this.parentElement.clientHeight - 10 - 35)+"px" + this.tbl?.reMeauseHeight() + // @ts-ignore + this.tbr?.shadowRoot.querySelector(".table").style.height = (this.parentElement.clientHeight - 45 - 21) + "px" + this.tbr?.reMeauseHeight() + } + }).observe(this.parentElement!) + let filterFunc = (data:any)=>{ + if (data.type == "check") { + if(data.item.checked) { + perfDataQuery.splitTree(this.dataSource,data.item.name,data.item.select == "0",data.item.type=="symbol") + }else { + perfDataQuery.resotreAllNode([data.item.name]) + perfDataQuery.resetAllNode(this.dataSource) + perfDataQuery.clearSplitMapData(data.item.name) + } + }else if (data.type == "select") { + perfDataQuery.resotreAllNode([data.item.name]) + perfDataQuery.clearSplitMapData(data.item.name) + perfDataQuery.splitTree(this.dataSource,data.item.name,data.item.select == "0",data.item.type=="symbol") + }else if (data.type=="button") { + if (data.item == "symbol") { + if(this.currentSelectedData&&!this.currentSelectedData.canCharge){ + return + } + if (this.currentSelectedData != undefined) { + this.filter!.addDataMining({name:this.currentSelectedData.symbolName},data.item) + perfDataQuery.splitTree(this.dataSource,this.currentSelectedData.symbolName,false,true) + }else { + return + } + }else if (data.item == "library") { + if(this.currentSelectedData&&!this.currentSelectedData.canCharge){ + return + } + if (this.currentSelectedData != undefined && this.currentSelectedData.libName != "") { + this.filter!.addDataMining({name:this.currentSelectedData.libName},data.item) + perfDataQuery.splitTree(this.dataSource,this.currentSelectedData.libName,false,false) + }else { + return + } + }else if (data.item == "restore") { + if (data.remove != undefined&&data.remove.length > 0) { + let list = data.remove.map((item:any)=>{ + return item.name + }) + perfDataQuery.resotreAllNode(list) + perfDataQuery.resetAllNode(this.dataSource) + list.forEach((symbolName:string)=>{ + perfDataQuery.clearSplitMapData(symbolName) + }) + } + } + } + this.tbl!.recycleDataSource = this.dataSource + this.frameChart!.data = this.dataSource; + if (this.isChartShow) this.frameChart?.calculateChartData(); + this.tbl!.move1px() + if(this.currentSelectedData){ + this.currentSelectedData.isSelected = false; + this.tbl?.clearAllSelection(this.currentSelectedData) + this.tbr!.recycleDataSource = [] + this.currentSelectedData = undefined + } + } + this.filter!.getDataLibrary(filterFunc) + this.filter!.getDataMining(filterFunc) + this.filter!.getCallTreeData((data:any)=>{ + if(data.value == 0){ + this.refreshAllNode({...this.filter!.getFilterTreeData(),callTree:data.checks}) + }else { + if(data.checks[1]){ + this.hideSystemLibrary() + perfDataQuery.resetAllNode(this.dataSource) + }else { + perfDataQuery.resotreAllNode([this.systmeRuleName]) + perfDataQuery.resetAllNode(this.dataSource) + perfDataQuery.clearSplitMapData(this.systmeRuleName) + } + this.tbl!.recycleDataSource = this.dataSource + this.frameChart!.data = this.dataSource; + if (this.isChartShow) this.frameChart?.calculateChartData(); + } + }) + this.filter!.getCallTreeConstraintsData((data:any)=>{ + perfDataQuery.resotreAllNode([this.numRuleName]) + perfDataQuery.clearSplitMapData(this.numRuleName) + if(data.checked){ + this.hideNumMaxAndMin(parseInt(data.min),data.max) + } + perfDataQuery.resetAllNode(this.dataSource) + this.tbl!.recycleDataSource = this.dataSource + this.frameChart!.data = this.dataSource; + if (this.isChartShow) this.frameChart?.calculateChartData(); + }) + this.filter!.getFilterData((data:FilterData)=>{ + if(perfDataQuery.searchValue != this.filter!.filterValue){ + perfDataQuery.searchValue = this.filter!.filterValue + perfDataQuery.resetAllNode(this.dataSource) + this.tbl!.recycleDataSource = this.dataSource + } + if (data.icon == 'block'){ + pageChart?.setAttribute('class', 'show'); + pageTab?.setAttribute('class', ''); + this.isChartShow = true; + this.filter!.disabledMining = true; + this.frameChart?.calculateChartData(); + } else if (data.icon == 'tree') { + pageChart?.setAttribute('class', ''); + pageTab?.setAttribute('class', 'show'); + this.isChartShow = false; + this.filter!.disabledMining = false; + this.frameChart!.clearCanvas(); + } + }) + } + + filterSampleIds(checked:boolean,min:string,max:string):Array{ + let ids:Array = []; + if(checked){ + let minId = parseInt(min); + let maxId = max == "∞" ? -999 : parseInt(max); + if(minId != NaN && maxId != NaN){ + for (let sampleId of this.sampleIds) { + let id = parseInt(sampleId); + if(id != NaN){ + if(id >= minId) { + if (maxId == -999) { + ids.push(sampleId); + } else if (id <= maxId) { + ids.push(sampleId); + }else{ + continue; + } + } + } + } + } + }else{ + ids.push(...this.sampleIds) + } + return ids; + } + + hideSystemLibrary(){ + this.dataSource.forEach((item)=>{ + item.children = [] + perfDataQuery.recursionChargeByRule(item,this.systmeRuleName,(node)=>{ + return node.path.startsWith(this.systmeRuleName) + }) + }) + } + + hideNumMaxAndMin(startNum:number,endNum:string){ + let max = endNum == "∞"?Number.POSITIVE_INFINITY :parseInt(endNum) + this.dataSource.forEach((item)=>{ + item.children = [] + perfDataQuery.recursionChargeByRule(item,this.numRuleName,(node)=>{ + return node.dur < startNum || node.dur > max + }) + }) + } + + refreshAllNode(filterData:any){ + let isTopDown:boolean = !filterData.callTree[0]; + let isHideSystemLibrary = filterData.callTree[1]; + let list = filterData.dataMining.concat(filterData.dataLibrary); + this.dataSource = perfDataQuery.getCallChainsBySampleIds(this.sampleIds,isTopDown); + this.tbr!.recycleDataSource = [] + if(isHideSystemLibrary){ + this.hideSystemLibrary() + } + if(filterData.callTreeConstraints.checked){ + this.hideNumMaxAndMin(parseInt(filterData.callTreeConstraints.inputs[0]),filterData.callTreeConstraints.inputs[1]) + } + list.forEach((item:any)=>{ + this.dataSource.forEach((process)=>{ + if(item.select == "0"){ + perfDataQuery.recursionChargeInitTree(process, item.name, item.type == "symbol") + }else { + perfDataQuery.recursionPruneInitTree(process, item.name, item.type == "symbol") + } + }) + if(!item.checked){ + perfDataQuery.resotreAllNode([item.name]) + } + }) + perfDataQuery.resetAllNode(this.dataSource) + this.tbl!.recycleDataSource = this.dataSource + this.frameChart!.data = this.dataSource; + if (this.isChartShow) this.frameChart?.calculateChartData(); + } + + initHtml(): string { + return ` + +
+ + +
+ + + + + +
+
+
Heaviest Stack Trace
+ + + + + + +
+
+ + + + + +
`; + } +} diff --git a/host/ide/src/trace/component/trace/sheet/TabPerfSampleList.ts b/host/ide/src/trace/component/trace/sheet/TabPerfSampleList.ts new file mode 100644 index 0000000000000000000000000000000000000000..3befd1c768f8add4b1763d2ee4d6fd9fa0d3c253 --- /dev/null +++ b/host/ide/src/trace/component/trace/sheet/TabPerfSampleList.ts @@ -0,0 +1,200 @@ +/* + * 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. + */ + +import {BaseElement, element} from "../../../../base-ui/BaseElement.js"; +import {LitTable} from "../../../../base-ui/table/lit-table.js"; +import {SelectionParam} from "../../../bean/BoxSelection.js"; +import {perfDataQuery} from "../../hiperf/PerfDataQuery.js"; +import {queryPerfProcess, queryPerfSampleCallChain, queryPerfSampleListByTimeRange} from "../../../database/SqlLite.js"; +import {PerfCallChain, PerfFile, PerfSample, PerfStack, PerfThread} from "../../../bean/PerfProfile.js"; +import {Utils} from "../base/Utils.js"; +import '../../DisassemblingWindow.js' +import {DisassemblingWindow} from "../../DisassemblingWindow.js"; +import {Cmd} from "../../../../command/cmd.js"; +import {SpApplication} from "../../../SpApplication.js"; + +@element('tabpane-perf-sample') +export class TabPanePerfSample extends BaseElement { + private tbl: LitTable | null | undefined; + private tblData: LitTable | null | undefined; + private source: Array = []; + private processMap: Map = new Map(); + private modal: DisassemblingWindow | null | undefined; + + set data(val: SelectionParam | null | undefined) { + this.modal!.style.display = 'none'; + (this.shadowRoot?.querySelector('div > #left_table') as HTMLElement)!.style.visibility = "visible"; + // @ts-ignore + this.tbl?.shadowRoot?.querySelector(".table")?.style?.height = (this.parentElement!.clientHeight - 40) + "px"; + this.tbl!.recycleDataSource = []; + // @ts-ignore + this.tblData?.shadowRoot?.querySelector(".table")?.style?.height = (this.parentElement!.clientHeight - 25) + "px"; + this.tblData!.recycleDataSource = []; + if (val) { + Promise.all([queryPerfProcess(), + queryPerfSampleListByTimeRange(val.leftNs, val.rightNs, val.perfAll ? [] : val.perfCpus, val.perfAll ? [] : val.perfProcess, val.perfAll ? [] : val.perfThread) + ]).then((results) => { + let processes = results[0] as Array; + let samples = results[1] as Array; + this.processMap.clear(); + for (let process of processes) { + this.processMap.set(process.pid, process) + } + for (let sample of samples) { + let process = this.processMap.get(sample.pid); + sample.processName = process == null || process == undefined ? `Process(${sample.pid})` : `${process!.processName}(${sample.pid})`; + sample.threadName = sample.threadName == null || sample.threadName == undefined ? `Thread(${sample.tid})` : `${sample.threadName}(${sample.tid})`; + sample.coreName = `CPU ${sample.core}`; + sample.timeString = Utils.getTimeString(sample.time); + let arr = (perfDataQuery.callChainData[sample.sampleId] ?? []) as Array; + let calls = arr.slice(0, arr.length - 2) + let last = calls[calls.length - 1]; + sample.depth = calls.length; + sample.fileId = last.fileId; + sample.symbolId = last.symbolId; + sample.addr = last.vaddrInFile.toString(); + let files = (perfDataQuery.filesData[sample.fileId] ?? []) as Array; + sample.backtrace = []; + if (sample.symbolId == -1 || sample.symbolId > files.length - 1) { + sample.backtrace.push(`0x${sample.addr}`) + } else { + sample.backtrace.push(files[sample.symbolId].symbol) + } + sample.backtrace.push(`(${sample.depth} other frames)`); + } + this.source = samples; + this.tbl!.recycleDataSource = this.source; + }) + + } + + } + + setRightTableData(sample: PerfSample) { + queryPerfSampleCallChain(sample.sampleId).then((result) => { + let stackArr: Array = []; + for (let perfCallChain of result) { + let stack = new PerfStack(); + stack.fileId = perfCallChain.fileId; + let files = (perfDataQuery.filesData[stack.fileId] ?? []) as Array; + if (perfCallChain.symbolId == -1 || perfCallChain.symbolId > files.length - 1) { + stack.symbol = `0x${perfCallChain.vaddrInFile}` + stack.path = ""; + } else { + stack.symbol = files[perfCallChain.symbolId].symbol + stack.path = files[perfCallChain.symbolId].path + } + stack.vaddrInFile = perfCallChain.vaddrInFile; + stack.type = (stack.path.endsWith(".so.1") || stack.path.endsWith(".dll") || stack.path.endsWith(".so")) ? 0 : 1; + stackArr.push(stack) + } + this.tblData!.recycleDataSource = stackArr + }) + } + + initElements(): void { + this.tbl = this.shadowRoot?.querySelector('#tb-perf-sample'); + this.tblData = this.shadowRoot?.querySelector('#tb-stack-data'); + this.modal = this.shadowRoot?.querySelector('tab-native-data-modal'); + this.tbl!.addEventListener('row-click', (e) => { + // @ts-ignore + let data = (e.detail.data as PerfSample); + this.setRightTableData(data); + }); + let lastClikTime = 0; + let spApplication = document.getElementsByTagName("sp-application")[0]; + this.tblData!.addEventListener("row-click", (e) => { + if (Date.now() - lastClikTime < 200 && spApplication.vs){ + (this.shadowRoot?.querySelector('div > #left_table') as HTMLElement)!.style.visibility = "hidden"; + this.modal!.showLoading(); + // @ts-ignore + let data = (e.detail.data as PerfStack); + let path = data.path; + let addr = data.vaddrInFile; + let addrHex = addr.toString(16); + if (path.trim() === '[kernel.kallsyms]'){ + this.modal?.showContent(`error : Symbol ${data.symbol} lib is [kernel.kallsyms] ,not support `,addrHex); + } else if (path.trim() ===''){ + this.modal?.showContent(`error : Symbol ${data.symbol} lib is null `,addrHex); + }else if (addr < 0){ + this.modal?.showContent(`error : Symbol ${data.symbol} current addr is error ` + addrHex,addrHex); + } else { + const binDir = 'C:/binary_cache'; + let binPath = binDir + path; + let cmd = 'C:/binary_cache/llvm-objdump.exe -S ' + binPath; + Cmd.execObjDump(cmd,addrHex,(result : any) => { + this.modal?.showContent(result,addrHex); + }) + } + } + lastClikTime = Date.now(); + }); + new ResizeObserver((entries) => { + if (this.parentElement?.clientHeight != 0) { + // @ts-ignore + this.tbl?.shadowRoot.querySelector(".table").style.height = (this.parentElement.clientHeight - 40) + "px" + // @ts-ignore + this.tblData?.shadowRoot.querySelector(".table").style.height = (this.parentElement.clientHeight - 25) + "px" + this.tbl?.reMeauseHeight() + this.tblData?.reMeauseHeight(); + } + this.modal!.style.height = (this.shadowRoot?.querySelector('div > #right_table') as HTMLElement)!.clientHeight - 2 + 'px'; //2 is borderWidth + }).observe(this.parentElement!) + } + + initHtml(): string { + return ` + +
+ +
+ + + + + + + + + + + +
+
+ + + + + + +
+
`; + } +} diff --git a/host/ide/src/trace/component/trace/sheet/TabProgressBar.ts b/host/ide/src/trace/component/trace/sheet/TabProgressBar.ts index 74640f8beaf93160964e685a981084b507dbe700..2d55de7af035df4d9184021d9e20eedfc04bc5a8 100644 --- a/host/ide/src/trace/component/trace/sheet/TabProgressBar.ts +++ b/host/ide/src/trace/component/trace/sheet/TabProgressBar.ts @@ -19,38 +19,38 @@ import {BaseElement, element} from "../../../../base-ui/BaseElement.js"; @element('tab-progress-bar') export class TabProgressBar extends BaseElement { - initElements(): void { - let data:Array = this.getAttribute("data")!.split(",") - let first: HTMLDivElement | undefined | null =this.shadowRoot?.querySelector("#first") - let second: HTMLDivElement | undefined | null =this.shadowRoot?.querySelector("#second") - if (data!.length > 0 && data && data![2]!="0") { - if (parseInt(data[0])< 0) { - first!.style.width = (Number((Math.abs(parseInt(data[0]))/parseInt(data[2]))*100)).toFixed(2) + "%" - first!.style.background = "#FC74FF" - }else { - first!.style.width = (Number((parseInt(data[0])/parseInt(data[2]))*100)).toFixed(2) + "%" - } - if (parseInt(data[1])< 0) { - second!.style.width = (Number((Math.abs(parseInt(data[1])) / parseInt(data[2])) * 100)).toFixed(2) + "%" - first!.style.background = "#CC34CF" - }else { - second!.style.width = (Number((parseInt(data[1]) / parseInt(data[2])) * 100)).toFixed(2) + "%" - } - } - - } - - - - initHtml(): string { - return ` - -
-
+ initElements(): void { + let data: Array = this.getAttribute("data")!.split(",") + let first: HTMLDivElement | undefined | null = this.shadowRoot?.querySelector("#first") + let second: HTMLDivElement | undefined | null = this.shadowRoot?.querySelector("#second") + if (data!.length > 0 && data && data![2] != "0") { + if (parseInt(data[0]) < 0) { + first!.style.width = (Number((Math.abs(parseInt(data[0])) / parseInt(data[2])) * 100)).toFixed(2) + "%" + first!.style.background = "#FC74FF" + } else { + first!.style.width = (Number((parseInt(data[0]) / parseInt(data[2])) * 100)).toFixed(2) + "%" + } + if (parseInt(data[1]) < 0) { + second!.style.width = (Number((Math.abs(parseInt(data[1])) / parseInt(data[2])) * 100)).toFixed(2) + "%" + first!.style.background = "#CC34CF" + } else { + second!.style.width = (Number((parseInt(data[1]) / parseInt(data[2])) * 100)).toFixed(2) + "%" + } + } + + } + + initHtml(): string { + return ` + +
+
+
+
`; - } + } } diff --git a/host/ide/src/trace/component/trace/timer-shaft/Flag.ts b/host/ide/src/trace/component/trace/timer-shaft/Flag.ts index aaf2f2974001db4f43d11bbf1b23b48b87768fdc..36762b5d372008b841699eb2d616437bf8b9bf5d 100644 --- a/host/ide/src/trace/component/trace/timer-shaft/Flag.ts +++ b/host/ide/src/trace/component/trace/timer-shaft/Flag.ts @@ -23,8 +23,9 @@ export class Flag { selected: boolean = false text: string = "" hidden: boolean = false; - type:string = ""; - constructor(x: number, y: number, width: number, height: number, time: number, color: string = "#999999", selected = false, type:string="") { + type: string = ""; + + constructor(x: number, y: number, width: number, height: number, time: number, color: string = "#999999", selected = false, type: string = "") { this.x = x; this.y = y; this.width = width; diff --git a/host/ide/src/trace/component/trace/timer-shaft/RangeRuler.ts b/host/ide/src/trace/component/trace/timer-shaft/RangeRuler.ts index 3836cbf27b5cef43a9db005bf5763996dd52e5b5..a8bed7cb25f191b6b60d37163e94156688f486fe 100644 --- a/host/ide/src/trace/component/trace/timer-shaft/RangeRuler.ts +++ b/host/ide/src/trace/component/trace/timer-shaft/RangeRuler.ts @@ -62,6 +62,12 @@ export class Mark extends Graph { } export interface TimeRange { + slicesTime: { + color: string|null|undefined; + startTime: number | null | undefined; + endTime: number | null | undefined; + }; + scale: number; totalNS: number startX: number endX: number @@ -89,8 +95,8 @@ export class RangeRuler extends Graph { currentDuration: number = 0 centerXPercentage: number = 0; animaStartTime: number | undefined - animTime: number = 100; - p: number = 800; + animTime: number = 250; + p: number = 2000; private readonly notifyHandler: (r: TimeRange) => void; private scale: number = 0; //缩放级别 @@ -100,7 +106,7 @@ export class RangeRuler extends Graph { 100_000_000_000, 200_000_000_000, 500_000_000_000]; private _cpuUsage: Array<{ cpu: number, ro: number, rate: number }> = [] - constructor(timerShaftEL:TimerShaftElement, frame: Rect, range: TimeRange, notifyHandler: (r: TimeRange) => void) { + constructor(timerShaftEL: TimerShaftElement, frame: Rect, range: TimeRange, notifyHandler: (r: TimeRange) => void) { super(timerShaftEL.canvas, timerShaftEL.ctx!, frame) this.range = range; this.notifyHandler = notifyHandler; @@ -192,6 +198,7 @@ export class RangeRuler extends Graph { } else { this.range.xsTxt = [] } + this.range.scale = this.scale; if (yu != 0) { let firstNodeWidth = ((this.scale - yu) / this.scale * realW); startX += firstNodeWidth; @@ -329,13 +336,14 @@ export class RangeRuler extends Graph { this.markB.inspectionFrame.x = this.markB.frame.x - markPadding } - setRangeNS(startNS:number,endNS:number) { + setRangeNS(startNS: number, endNS: number) { this.range.startNS = startNS this.range.endNS = endNS this.fillX() this.draw(); } - getRange():TimeRange{ + + getRange(): TimeRange { return this.range; } @@ -345,7 +353,7 @@ export class RangeRuler extends Graph { } let startTime = new Date().getTime(); let duration = (startTime - this.animaStartTime); - if (duration < this.animTime) duration = this.animTime + if (duration < this.animTime * 2) duration = duration + this.animTime this.currentDuration = duration if (this.isPress) return this.isPress = true diff --git a/host/ide/src/trace/component/trace/timer-shaft/SportRuler.ts b/host/ide/src/trace/component/trace/timer-shaft/SportRuler.ts index ac43c903e494a2a8a152cae61103ba18ab84835a..7dc6cd1af056f79b83d2b8d25b166a7de6c59469 100644 --- a/host/ide/src/trace/component/trace/timer-shaft/SportRuler.ts +++ b/host/ide/src/trace/component/trace/timer-shaft/SportRuler.ts @@ -22,7 +22,9 @@ import {TraceRow} from "../base/TraceRow.js"; import {SpApplication} from "../../../SpApplication.js"; export class SportRuler extends Graph { + static isMouseInSportRuler = false; public flagList: Array = []; + isRangeSelect: boolean = false;//region selection private hoverFlag: Flag = new Flag(0, 0, 0, 0, 0); private lineColor: string | null = null; private rulerW = 0; @@ -30,11 +32,17 @@ export class SportRuler extends Graph { private readonly notifyHandler: ((hoverFlag: Flag | undefined | null, selectFlag: Flag | undefined | null) => void) | undefined; private readonly flagClickHandler: ((flag: Flag | undefined | null) => void) | undefined; private invertedTriangleTime: number | null | undefined = null; - isRangeSelect: boolean = false;//region selection + private slicesTime: { startTime: number | null | undefined, endTime: number | null | undefined, color: string | null } | null = { + startTime: null, + endTime: null, + color: null + }; + private timerShaftEL: TimerShaftElement|undefined|null; constructor(timerShaftEL: TimerShaftElement, frame: Rect, notifyHandler: (hoverFlag: Flag | undefined | null, selectFlag: Flag | undefined | null) => void, flagClickHandler: (flag: Flag | undefined | null) => void) { super(timerShaftEL.canvas, timerShaftEL.ctx!, frame) this.notifyHandler = notifyHandler; this.flagClickHandler = flagClickHandler; + this.timerShaftEL = timerShaftEL; } get range(): TimeRange { @@ -63,7 +71,7 @@ export class SportRuler extends Graph { draw(): void { this.rulerW = this.canvas!.offsetWidth - this.c.clearRect(this.frame.x, this.frame.y, this.frame.width, this.frame.height+1) + this.c.clearRect(this.frame.x, this.frame.y, this.frame.width, this.frame.height + 1) this.c.beginPath(); this.lineColor = window.getComputedStyle(this.canvas!, null).getPropertyValue("color"); this.c.strokeStyle = this.lineColor //"#dadada" @@ -134,8 +142,9 @@ export class SportRuler extends Graph { this.c.closePath(); } if (this.invertedTriangleTime != null && typeof (this.invertedTriangleTime) != undefined) { - this.drawInvertedTriangle(this.invertedTriangleTime,document.querySelector("sp-application")!.dark?"#FFFFFF":"#000000") + this.drawInvertedTriangle(this.invertedTriangleTime, document.querySelector("sp-application")!.dark ? "#FFFFFF" : "#000000") } + this.drawSlicesMark(this.slicesTime?.startTime, this.slicesTime?.endTime) } drawTriangle(time: number, type: string) { @@ -163,6 +172,17 @@ export class SportRuler extends Graph { } else if (type == "square") { if (i != -1) { this.flagList[i].type = ""; + } else { + let triangle = this.flagList.findIndex(it => it.type == "triangle"); + if (triangle !== -1) { + this.flagList[triangle].type = ""; + this.draw(); + this.notifyHandler && this.notifyHandler( + !this.hoverFlag.hidden ? this.hoverFlag : null, + this.flagList.find(it => it.selected) || null + ) + return this.flagList[triangle].time; + } } } else if (type == "inverted") { this.invertedTriangleTime = time @@ -175,10 +195,10 @@ export class SportRuler extends Graph { } } - removeTriangle(type:string){ + removeTriangle(type: string) { if (type == "inverted") { this.invertedTriangleTime = null; - }else { + } else { let i = this.flagList.findIndex(it => it.type == type) if (i !== -1) { this.flagList.splice(i, 1) @@ -189,16 +209,16 @@ export class SportRuler extends Graph { !this.hoverFlag.hidden ? this.hoverFlag : null, this.flagList.find(it => it.selected) || null ) - } + } - drawInvertedTriangle(time: number, color: string = "#000000"){ + drawInvertedTriangle(time: number, color: string = "#000000") { if (time != null && typeof (time) != undefined) { let x = Math.round(this.rulerW * (time - this.range.startNS) / (this.range.endNS - this.range.startNS)); this.c.beginPath(); this.c.fillStyle = color; this.c.strokeStyle = color; - this.c.moveTo(x-2, 142); - this.c.lineTo(x+2, 142); + this.c.moveTo(x - 2, 142); + this.c.lineTo(x + 2, 142); this.c.lineTo(x, 145); this.c.fill() this.c.closePath() @@ -206,6 +226,80 @@ export class SportRuler extends Graph { } } + setSlicesMark(startTime: number | null = null, endTime: number | null = null) { + if (startTime != null && typeof (startTime) != undefined && endTime != null && typeof (endTime) != undefined) { + this.slicesTime = { + startTime: startTime <= endTime ? startTime : endTime, + endTime: startTime <= endTime ? endTime : startTime, + color: null + }; + } else { + this.slicesTime = {startTime: null, endTime: null, color: null}; + } + this.range.slicesTime = this.slicesTime; + this.draw(); + this.timerShaftEL?.render(); + } + + drawSlicesMark(startTime: number | null = null, endTime: number | null = null) { + if (startTime != null && typeof (startTime) != undefined && endTime != null && typeof (endTime) != undefined) { + let startX = Math.round(this.rulerW * (startTime - this.range.startNS) / (this.range.endNS - this.range.startNS)); + let endX = Math.round(this.rulerW * (endTime - this.range.startNS) / (this.range.endNS - this.range.startNS)); + this.c.beginPath(); + if (document.querySelector("sp-application")!.dark) { + this.c.strokeStyle = "#FFF" + this.c.fillStyle = "#FFF" + this.range.slicesTime.color = "#FFF" + } else { + this.c.strokeStyle = "#344596" + this.c.fillStyle = "#344596" + this.range.slicesTime.color = "#344596" + } + this.c.moveTo(startX + 9, 132); + this.c.lineTo(startX, 141); + this.c.lineTo(startX, 132); + this.c.lineTo(startX + 9, 132); + + this.c.lineTo(endX - 9, 132); + this.c.lineTo(endX, 132); + this.c.lineTo(endX, 141); + this.c.lineTo(endX - 9, 132); + // this.c.fill() + this.c.closePath() + this.c.stroke(); + + + this.c.beginPath(); + if (document.querySelector("sp-application")!.dark) { + this.c.strokeStyle = "#FFF" + this.c.fillStyle = "#FFF" + } else { + this.c.strokeStyle = "#000" + this.c.fillStyle = "#000" + } + let lineWidth = endX - startX; + let txt = ns2s((endTime || 0) - (startTime || 0)); + this.c.moveTo(startX, this.frame.y + 22); + this.c.lineTo(endX, this.frame.y + 22); + this.c.moveTo(startX, this.frame.y + 22 - 5); + this.c.lineTo(startX, this.frame.y + 22 + 5); + this.c.moveTo(endX, this.frame.y + 22 - 5); + this.c.lineTo(endX, this.frame.y + 22 + 5); + let txtWidth = this.c.measureText(txt).width; + if (lineWidth > txtWidth) { + this.c.fillText(`${txt}`, startX + (lineWidth - txtWidth) / 2, this.frame.y + 20) + } else { + if (endX + txtWidth >= this.frame.width) { + this.c.fillText(`${txt}`, startX - 5 - txtWidth, this.frame.y + 20) + } else { + this.c.fillText(`${txt}`, endX + 5, this.frame.y + 20) + } + } + this.c.stroke(); + this.c.closePath(); + } + } + //绘制旗子 drawFlag(x: number, color: string = "#999999", isFill: boolean = false, text: string = "", type: string = "") { this.c.beginPath(); @@ -277,7 +371,6 @@ export class SportRuler extends Graph { ) } - static isMouseInSportRuler = false; edgeDetection(ev: MouseEvent): boolean { let x = ev.offsetX - (this.canvas?.offsetLeft || 0) diff --git a/host/ide/src/trace/component/trace/timer-shaft/TabPaneFlag.ts b/host/ide/src/trace/component/trace/timer-shaft/TabPaneFlag.ts index e397fbe1585bf9b62d7dc1b301f494d51d7eca01..037cabe47ba855e590f4aa02e04731c5d3ee222b 100644 --- a/host/ide/src/trace/component/trace/timer-shaft/TabPaneFlag.ts +++ b/host/ide/src/trace/component/trace/timer-shaft/TabPaneFlag.ts @@ -54,50 +54,50 @@ export class TabPaneFlag extends BaseElement { initHtml(): string { return ` - -
-
Annotation at
- - Change color: - -
+ +
+
Annotation at
+ + Change color: + +
`; } diff --git a/host/ide/src/trace/database/Procedure.ts b/host/ide/src/trace/database/Procedure.ts index 8793eafdc3fb95164ad9ec762b3e35ab9fc83de4..fcc4baf98b2e6bd3190ade2a6a5f51a8f9066b2a 100644 --- a/host/ide/src/trace/database/Procedure.ts +++ b/host/ide/src/trace/database/Procedure.ts @@ -36,7 +36,15 @@ class ProcedureThread extends Worker { } if (transfer) { try { + if (Array.isArray(transfer) ) { + if(transfer.length > 0){ + this.postMessage(pam, [...transfer]); + }else{ + this.postMessage(pam); + } + } else { this.postMessage(pam, [transfer]); + } } catch (e: any) { } } else { @@ -59,8 +67,10 @@ class ProcedurePool { cpusLen = ProcedurePool.build('cpu', 8); freqLen = ProcedurePool.build('freq', 2); processLen = ProcedurePool.build('process', 8); + ability = ProcedurePool.build('ability', 4); // names = [...this.cpusLen, ...this.freqLen, ...this.processLen, ...this.memLen, ...this.threadLen, ...this.funcLen]; - names = [...this.cpusLen, ...this.processLen, ...this.freqLen]; + names = [...this.cpusLen, ...this.processLen, ...this.freqLen, ...this.ability]; + onComplete: Function | undefined;//任务完成回调 constructor(threadBuild: (() => ProcedureThread) | undefined = undefined) { diff --git a/host/ide/src/trace/database/ProcedureWorker.ts b/host/ide/src/trace/database/ProcedureWorker.ts index 0adeae3816bf762cc8097be118c7f31ab7cdde7a..dbcb1e69edb9b06d9f7910a753715c310080331f 100644 --- a/host/ide/src/trace/database/ProcedureWorker.ts +++ b/host/ide/src/trace/database/ProcedureWorker.ts @@ -13,8 +13,8 @@ * limitations under the License. */ -import {cpu, CpuStruct, WakeupBean} from "./ProcedureWorkerCPU.js"; -import {drawFlagLine, drawLines, ns2s, ns2x, Rect} from "./ProcedureWorkerCommon.js"; +import {cpu, CpuStruct, rtCpu, WakeupBean} from "./ProcedureWorkerCPU.js"; +import {ColorUtils, drawFlagLine, drawLines, ns2s, ns2x, Rect} from "./ProcedureWorkerCommon.js"; import {CpuFreqStruct, freq} from "./ProcedureWorkerFreq.js"; import {proc, ProcessStruct} from "./ProcedureWorkerProcess.js"; import {mem, ProcessMemStruct} from "./ProcedureWorkerMem.js"; @@ -23,14 +23,23 @@ import {func, FuncStruct} from "./ProcedureWorkerFunc.js"; import {fps, FpsStruct} from "./ProcedureWorkerFPS.js"; import {heap, HeapStruct} from "./ProcedureWorkerHeap.js"; import {timeline} from "./ProcedureWorkerTimeline.js"; +import {cpuAbility, CpuAbilityMonitorStruct} from "./ProcedureWorkerCpuAbility.js"; +import {memoryAbility, MemoryAbilityMonitorStruct} from "./ProcedureWorkerMemoryAbility.js"; +import {DiskAbilityMonitorStruct, diskIoAbility} from "./ProcedureWorkerDiskIoAbility.js"; +import {networkAbility, NetworkAbilityMonitorStruct} from "./ProcedureWorkerNetworkAbility.js"; +import {hiPerfCpu, HiPerfCpuStruct} from "./ProcedureWorkerHiPerfCPU.js"; +import {hiPerfProcess, HiPerfProcessStruct} from "./ProcedureWorkerHiPerfProcess.js"; +import {hiPerfThread, HiPerfThreadStruct} from "./ProcedureWorkerHiPerfThread.js"; + let dataList: any = {} +let dataList2: any = {} let dataFilter: any = {} let canvasList: any = {} let contextList: any = {} function drawSelection(context: any, params: any) { - if (params.isRangeSelect) { + if (params.isRangeSelect && params.rangeSelectObject) { params.rangeSelectObject!.startX = Math.floor(ns2x(params.rangeSelectObject!.startNS!, params.startNS, params.endNS, params.totalNS, params.frame)); params.rangeSelectObject!.endX = Math.floor(ns2x(params.rangeSelectObject!.endNS!, params.startNS, params.endNS, params.totalNS, params.frame)); if (context) { @@ -101,6 +110,7 @@ function drawWakeUp(context: CanvasRenderingContext2D | any, wake: WakeupBean | self.onmessage = function (e: any) { if ((e.data.type as string).startsWith("clear")) { dataList = {}; + dataList2 = {}; dataFilter = {}; canvasList = {}; contextList = {}; @@ -122,13 +132,15 @@ self.onmessage = function (e: any) { contextList[e.data.type].scale(e.data.params.dpr, e.data.params.dpr); } } - if(!dataFilter[e.data.type]){ + if (!dataFilter[e.data.type]) { dataFilter[e.data.type] = new Set(); } let canvas = canvasList[e.data.type]; let context = contextList[e.data.type]; let type = e.data.type as string; let params = e.data.params; + let online = e.data.params.online; + let buf = e.data.params.buf; let isRangeSelect = e.data.params.isRangeSelect; let isHover = e.data.params.isHover; let xs = e.data.params.xs; @@ -140,11 +152,14 @@ self.onmessage = function (e: any) { let startNS = e.data.params.startNS; let endNS = e.data.params.endNS; let totalNS = e.data.params.totalNS; + let slicesTime: { startTime: number | null, endTime: number | null, color: string | null } = e.data.params.slicesTime; + let scale = e.data.params.scale; let canvasWidth = e.data.params.canvasWidth; let canvasHeight = e.data.params.canvasHeight; let useCache = e.data.params.useCache; let lineColor = e.data.params.lineColor; let wakeupBean: WakeupBean | null = e.data.params.wakeupBean; + let intervalPerf: number = e.data.params.intervalPerf; if (canvas) { if (canvas.width !== canvasWidth || canvas.height !== canvasHeight) { canvas.width = canvasWidth; @@ -175,7 +190,15 @@ self.onmessage = function (e: any) { }); } else if (type.startsWith("cpu")) { if (!useCache) { - cpu(dataList[type], dataFilter[type], startNS, endNS, totalNS, frame); + if (online) { + rtCpu(buf, dataFilter[type], startNS, endNS, totalNS, frame); + } else { + cpu(dataList[type], dataFilter[type], startNS, endNS, totalNS, frame); + } + }else{ + if (online) { + rtCpu(null, dataFilter[type], startNS, endNS, totalNS, frame); + } } if (canvas) { context.clearRect(0, 0, canvas.width, canvas.height); @@ -198,7 +221,7 @@ self.onmessage = function (e: any) { } drawSelection(context, params); context.closePath(); - drawFlagLine(context, flagMoveInfo, flagSelectedInfo, startNS, endNS, totalNS, frame); + drawFlagLine(context, flagMoveInfo, flagSelectedInfo, startNS, endNS, totalNS, frame, slicesTime); let currentCpu = parseInt(type.replace("cpu", "")); drawWakeUp(context, wakeupBean, startNS, endNS, totalNS, frame, type == `cpu${CpuStruct.selectCpuStruct?.cpu || 0}` ? CpuStruct.selectCpuStruct : undefined, currentCpu); } @@ -232,7 +255,7 @@ self.onmessage = function (e: any) { context.textBaseline = "middle" context.fillText(maxFps, 4, 5 + 9); drawWakeUp(context, wakeupBean, startNS, endNS, totalNS, frame); - drawFlagLine(context, flagMoveInfo, flagSelectedInfo, startNS, endNS, totalNS, frame); + drawFlagLine(context, flagMoveInfo, flagSelectedInfo, startNS, endNS, totalNS, frame, slicesTime); } // @ts-ignore self.postMessage({id: e.data.id, type: type, results: canvas ? undefined : dataFilter[type], hover: undefined}); @@ -273,7 +296,7 @@ self.onmessage = function (e: any) { context.textBaseline = "middle" context.fillText(s, 4, 5 + 9) drawWakeUp(context, wakeupBean, startNS, endNS, totalNS, frame); - drawFlagLine(context, flagMoveInfo, flagSelectedInfo, startNS, endNS, totalNS, frame); + drawFlagLine(context, flagMoveInfo, flagSelectedInfo, startNS, endNS, totalNS, frame, slicesTime); } // @ts-ignore self.postMessage({ @@ -291,13 +314,20 @@ self.onmessage = function (e: any) { context.beginPath(); CpuStruct.cpuCount = e.data.params.cpuCount; drawLines(context, xs, frame.height, lineColor) + let path = new Path2D(); + let miniHeight: number = 0; + miniHeight = Math.round(frame.height / CpuStruct.cpuCount) + if (dataFilter[type].size > 0) { + context.fillStyle = ColorUtils.colorForTid(dataFilter[type].values().next().value.pid || 0) + } for (let re of dataFilter[type]) { - ProcessStruct.draw(context, re) + ProcessStruct.draw(context, path, re, miniHeight); } + context.fill(path); drawSelection(context, params); drawWakeUp(context, wakeupBean, startNS, endNS, totalNS, frame); context.closePath(); - drawFlagLine(context, flagMoveInfo, flagSelectedInfo, startNS, endNS, totalNS, frame); + drawFlagLine(context, flagMoveInfo, flagSelectedInfo, startNS, endNS, totalNS, frame, slicesTime); } // @ts-ignore self.postMessage({id: e.data.id, type: type, results: canvas ? undefined : dataFilter[type], hover: undefined}); @@ -327,7 +357,7 @@ self.onmessage = function (e: any) { drawSelection(context, params); drawWakeUp(context, wakeupBean, startNS, endNS, totalNS, frame); context.closePath(); - drawFlagLine(context, flagMoveInfo, flagSelectedInfo, startNS, endNS, totalNS, frame); + drawFlagLine(context, flagMoveInfo, flagSelectedInfo, startNS, endNS, totalNS, frame, slicesTime); } // @ts-ignore self.postMessage({ @@ -350,7 +380,7 @@ self.onmessage = function (e: any) { drawSelection(context, params); drawWakeUp(context, wakeupBean, startNS, endNS, totalNS, frame); context.closePath(); - drawFlagLine(context, flagMoveInfo, flagSelectedInfo, startNS, endNS, totalNS, frame); + drawFlagLine(context, flagMoveInfo, flagSelectedInfo, startNS, endNS, totalNS, frame, slicesTime); } // @ts-ignore self.postMessage({id: e.data.id, type: type, results: canvas ? undefined : dataFilter[type], hover: undefined}); @@ -380,7 +410,7 @@ self.onmessage = function (e: any) { drawSelection(context, params); drawWakeUp(context, wakeupBean, startNS, endNS, totalNS, frame); context.closePath(); - drawFlagLine(context, flagMoveInfo, flagSelectedInfo, startNS, endNS, totalNS, frame); + drawFlagLine(context, flagMoveInfo, flagSelectedInfo, startNS, endNS, totalNS, frame, slicesTime); } // @ts-ignore self.postMessage({ @@ -422,7 +452,7 @@ self.onmessage = function (e: any) { drawSelection(context, params); drawWakeUp(context, wakeupBean, startNS, endNS, totalNS, frame); context.closePath(); - drawFlagLine(context, flagMoveInfo, flagSelectedInfo, startNS, endNS, totalNS, frame); + drawFlagLine(context, flagMoveInfo, flagSelectedInfo, startNS, endNS, totalNS, frame, slicesTime); } // @ts-ignore self.postMessage({ @@ -438,7 +468,23 @@ self.onmessage = function (e: any) { drawLines(context, xs, frame.height, lineColor) drawSelection(context, params); context.closePath(); - drawFlagLine(context, flagMoveInfo, flagSelectedInfo, startNS, endNS, totalNS, frame); + drawFlagLine(context, flagMoveInfo, flagSelectedInfo, startNS, endNS, totalNS, frame, slicesTime); + } + // @ts-ignore + self.postMessage({ + id: e.data.id, + type: type, + results: canvas ? undefined : dataFilter[type], + hover: ThreadStruct.hoverThreadStruct + }); + } else if (type.startsWith("HiPerf-Group") || type.startsWith("monitorGroup")) { + if (canvas) { + context.clearRect(0, 0, canvas.width, canvas.height); + context.beginPath(); + drawLines(context, xs, frame.height, lineColor) + drawSelection(context, params); + context.closePath(); + drawFlagLine(context, flagMoveInfo, flagSelectedInfo, startNS, endNS, totalNS, frame, slicesTime); } // @ts-ignore self.postMessage({ @@ -447,6 +493,310 @@ self.onmessage = function (e: any) { results: canvas ? undefined : dataFilter[type], hover: ThreadStruct.hoverThreadStruct }); + } else if (type.startsWith("HiPerf-Cpu")) { + let groupBy10MS = scale > 100_000_000; + if (!useCache) { + hiPerfCpu(dataList[type],dataList2,type, dataFilter[type], startNS, endNS, totalNS, frame, groupBy10MS, e.data.params.maxCpu, intervalPerf); + } + if (canvas) { + context.clearRect(0, 0, canvas.width, canvas.height); + drawLines(context, xs, frame.height, lineColor) + context.stroke(); + context.beginPath(); + HiPerfCpuStruct.hoverStruct = undefined; + if (isHover) { + let offset = groupBy10MS ? 0 : 3; + for (let re of dataFilter[e.data.type]) { + if (hoverX >= re.frame.x - offset && hoverX <= re.frame.x + re.frame.width + offset) {//&& hoverY >= re.frame.y && hoverY <= re.frame.y + re.frame.height + HiPerfCpuStruct.hoverStruct = re; + break; + } + } + } else { + HiPerfCpuStruct.hoverStruct = e.data.params.hoverStruct; + } + HiPerfCpuStruct.selectStruct = e.data.params.selectStruct; + context.fillStyle = ColorUtils.FUNC_COLOR[0]; + context.strokeStyle = ColorUtils.FUNC_COLOR[0]; + let path = new Path2D(); + for (let re of dataFilter[type]) { + HiPerfCpuStruct.draw(context, path, re, groupBy10MS); + } + if (groupBy10MS) { + context.fill(path); + } else { + context.stroke(path); + } + drawSelection(context, params); + context.closePath(); + drawFlagLine(context, flagMoveInfo, flagSelectedInfo, startNS, endNS, totalNS, frame, slicesTime); + } + // @ts-ignore + self.postMessage({ + id: e.data.id, + type: type, + results: canvas ? undefined : dataFilter[type], + hover: HiPerfCpuStruct.hoverStruct + }); + } else if (type.startsWith("HiPerf-Process")) { + let groupBy10MS = scale > 100_000_000; + if (!useCache) { + hiPerfProcess(dataList[type], dataFilter[type], startNS, endNS, totalNS, frame, groupBy10MS, intervalPerf); + } + if (canvas) { + context.clearRect(0, 0, canvas.width, canvas.height); + drawLines(context, xs, frame.height, lineColor) + context.stroke(); + context.beginPath(); + HiPerfProcessStruct.hoverStruct = undefined; + context.fillStyle = ColorUtils.FUNC_COLOR[0]; + context.strokeStyle = ColorUtils.FUNC_COLOR[0]; + if (isHover) { + let offset = groupBy10MS ? 0 : 3; + for (let re of dataFilter[e.data.type]) { + if (hoverX >= re.frame.x - offset && hoverX <= re.frame.x + re.frame.width + offset) {//&& hoverY >= re.frame.y && hoverY <= re.frame.y + re.frame.height + HiPerfProcessStruct.hoverStruct = re; + break; + } + } + } else { + HiPerfProcessStruct.hoverStruct = e.data.params.hoverStruct; + } + HiPerfProcessStruct.selectStruct = e.data.params.selectStruct; + let path = new Path2D(); + for (let re of dataFilter[type]) { + HiPerfProcessStruct.draw(context, path, re, groupBy10MS); + } + drawSelection(context, params); + groupBy10MS ? context.fill(path) : context.stroke(path); + context.closePath(); + drawFlagLine(context, flagMoveInfo, flagSelectedInfo, startNS, endNS, totalNS, frame, slicesTime); + } + // @ts-ignore + self.postMessage({ + id: e.data.id, + type: type, + results: canvas ? undefined : dataFilter[type], + hover: HiPerfProcessStruct.hoverStruct + }); + } else if (type.startsWith("HiPerf-Thread")) { + let groupBy10MS = scale > 100_000_000; + if (!useCache) { + hiPerfThread(dataList[type], dataFilter[type], startNS, endNS, totalNS, frame, groupBy10MS,intervalPerf); + } + if (canvas) { + context.clearRect(0, 0, canvas.width, canvas.height); + drawLines(context, xs, frame.height, lineColor) + context.stroke(); + context.beginPath(); + HiPerfThreadStruct.hoverStruct = undefined; + context.fillStyle = ColorUtils.FUNC_COLOR[0]; + context.strokeStyle = ColorUtils.FUNC_COLOR[0]; + if (isHover) { + let offset = groupBy10MS ? 0 : 3; + for (let re of dataFilter[e.data.type]) { + if (hoverX >= re.frame.x - offset && hoverX <= re.frame.x + re.frame.width + offset) {//&& hoverY >= re.frame.y && hoverY <= re.frame.y + re.frame.height + HiPerfThreadStruct.hoverStruct = re; + break; + } + } + } else { + HiPerfThreadStruct.hoverStruct = e.data.params.hoverStruct; + } + HiPerfThreadStruct.selectStruct = e.data.params.selectStruct; + let path = new Path2D(); + for (let re of dataFilter[type]) { + HiPerfThreadStruct.draw(context, path, re, groupBy10MS); + } + groupBy10MS ? context.fill(path) : context.stroke(path); + drawSelection(context, params); + context.stroke(); + context.closePath(); + drawFlagLine(context, flagMoveInfo, flagSelectedInfo, startNS, endNS, totalNS, frame, slicesTime); + } + // @ts-ignore + self.postMessage({ + id: e.data.id, + type: type, + results: canvas ? undefined : dataFilter[type], + hover: HiPerfThreadStruct.hoverStruct + }); + } else if (type.startsWith("monitorCpu")) { + if (!useCache) { + cpuAbility(dataList[type], dataFilter[type], startNS, endNS, totalNS, frame) + } + if (canvas) { + context.clearRect(0, 0, canvas.width, canvas.height); + context.beginPath(); + CpuAbilityMonitorStruct.maxCpuUtilization = e.data.params.maxCpuUtilization; + CpuAbilityMonitorStruct.maxCpuUtilizationName = e.data.params.maxCpuUtilizationName; + drawLines(context, xs, frame.height, lineColor) + CpuAbilityMonitorStruct.hoverCpuAbilityStruct = undefined; + if (isHover) { + for (let re of dataFilter[type]) { + if (hoverX >= re.frame.x && hoverX <= re.frame.x + re.frame.width && hoverY >= re.frame.y && hoverY <= re.frame.y + re.frame.height) { + CpuAbilityMonitorStruct.hoverCpuAbilityStruct = re; + break; + } + } + } + CpuAbilityMonitorStruct.selectCpuAbilityStruct = e.data.params.selectCpuAbilityStruct; + for (let re of dataFilter[type]) { + CpuAbilityMonitorStruct.draw(context, re) + } + drawSelection(context, params); + context.closePath(); + let s = CpuAbilityMonitorStruct.maxCpuUtilizationName + let textMetrics = context.measureText(s); + context.globalAlpha = 0.8 + context.fillStyle = "#f0f0f0" + context.fillRect(0, 5, textMetrics.width + 8, 18) + context.globalAlpha = 1 + context.fillStyle = "#333" + context.textBaseline = "middle" + context.fillText(s, 4, 5 + 9) + drawWakeUp(context, wakeupBean, startNS, endNS, totalNS, frame); + drawFlagLine(context, flagMoveInfo, flagSelectedInfo, startNS, endNS, totalNS, frame, slicesTime); + } + // @ts-ignore + self.postMessage({ + id: e.data.id, + type: type, + results: canvas ? undefined : dataFilter[type], + hover: CpuAbilityMonitorStruct.hoverCpuAbilityStruct + }); + } else if (type.startsWith("monitorMemory")) { + if (!useCache) { + memoryAbility(dataList[type], dataFilter[type], startNS, endNS, totalNS, frame) + } + if (canvas) { + context.clearRect(0, 0, canvas.width, canvas.height); + context.beginPath(); + MemoryAbilityMonitorStruct.maxMemoryByte = e.data.params.maxMemoryByte; + MemoryAbilityMonitorStruct.maxMemoryByteName = e.data.params.maxMemoryByteName; + drawLines(context, xs, frame.height, lineColor) + MemoryAbilityMonitorStruct.hoverMemoryAbilityStruct = undefined; + if (isHover) { + for (let re of dataFilter[type]) { + if (hoverX >= re.frame.x && hoverX <= re.frame.x + re.frame.width && hoverY >= re.frame.y && hoverY <= re.frame.y + re.frame.height) { + MemoryAbilityMonitorStruct.hoverMemoryAbilityStruct = re; + break; + } + } + } + MemoryAbilityMonitorStruct.selectMemoryAbilityStruct = e.data.params.selectMemoryAbilityStruct; + for (let re of dataFilter[type]) { + MemoryAbilityMonitorStruct.draw(context, re) + } + drawSelection(context, params); + context.closePath(); + let s = MemoryAbilityMonitorStruct.maxMemoryByteName + let textMetrics = context.measureText(s); + context.globalAlpha = 0.8 + context.fillStyle = "#f0f0f0" + context.fillRect(0, 5, textMetrics.width + 8, 18) + context.globalAlpha = 1 + context.fillStyle = "#333" + context.textBaseline = "middle" + context.fillText(s, 4, 5 + 9) + drawWakeUp(context, wakeupBean, startNS, endNS, totalNS, frame); + drawFlagLine(context, flagMoveInfo, flagSelectedInfo, startNS, endNS, totalNS, frame, slicesTime); + } + // @ts-ignore + self.postMessage({ + id: e.data.id, + type: type, + results: canvas ? undefined : dataFilter[type], + hover: MemoryAbilityMonitorStruct.hoverMemoryAbilityStruct + }); + + } else if (type.startsWith("monitorDiskIo")) { + if (!useCache) { + diskIoAbility(dataList[type], dataFilter[type], startNS, endNS, totalNS, frame) + } + if (canvas) { + context.clearRect(0, 0, canvas.width, canvas.height); + context.beginPath(); + let maxDiskRate = e.data.params.maxDiskRate; + let maxDiskRateName = e.data.params.maxDiskRateName; + drawLines(context, xs, frame.height, lineColor) + DiskAbilityMonitorStruct.hoverDiskAbilityStruct = undefined; + if (isHover) { + for (let re of dataFilter[type]) { + if (hoverX >= re.frame.x && hoverX <= re.frame.x + re.frame.width && hoverY >= re.frame.y && hoverY <= re.frame.y + re.frame.height) { + DiskAbilityMonitorStruct.hoverDiskAbilityStruct = re; + break; + } + } + } + DiskAbilityMonitorStruct.selectDiskAbilityStruct = e.data.params.selectDiskAbilityStruct; + for (let re of dataFilter[type]) { + DiskAbilityMonitorStruct.draw(context, re, maxDiskRate) + } + drawSelection(context, params); + context.closePath(); + let textMetrics = context.measureText(maxDiskRateName); + context.globalAlpha = 0.8 + context.fillStyle = "#f0f0f0" + context.fillRect(0, 5, textMetrics.width + 8, 18) + context.globalAlpha = 1 + context.fillStyle = "#333" + context.textBaseline = "middle" + context.fillText(maxDiskRateName, 4, 5 + 9) + drawWakeUp(context, wakeupBean, startNS, endNS, totalNS, frame); + drawFlagLine(context, flagMoveInfo, flagSelectedInfo, startNS, endNS, totalNS, frame, slicesTime); + } + // @ts-ignore + self.postMessage({ + id: e.data.id, + type: type, + results: canvas ? undefined : dataFilter[type], + hover: DiskAbilityMonitorStruct.hoverDiskAbilityStruct + }); + } else if (type.startsWith("monitorNetwork")) { + if (!useCache) { + networkAbility(dataList[type], dataFilter[type], startNS, endNS, totalNS, frame) + } + if (canvas) { + context.clearRect(0, 0, canvas.width, canvas.height); + context.beginPath(); + let maxNetworkRate = e.data.params.maxNetworkRate; + let maxNetworkRateName = e.data.params.maxNetworkRateName; + drawLines(context, xs, frame.height, lineColor) + NetworkAbilityMonitorStruct.hoverNetworkAbilityStruct = undefined; + if (isHover) { + for (let re of dataFilter[type]) { + if (hoverX >= re.frame.x && hoverX <= re.frame.x + re.frame.width && hoverY >= re.frame.y && hoverY <= re.frame.y + re.frame.height) { + NetworkAbilityMonitorStruct.hoverNetworkAbilityStruct = re; + break; + } + } + } + NetworkAbilityMonitorStruct.selectNetworkAbilityStruct = e.data.params.selectNetworkAbilityStruct; + for (let re of dataFilter[type]) { + NetworkAbilityMonitorStruct.draw(context, re, maxNetworkRate) + } + drawSelection(context, params); + context.closePath(); + let textMetrics = context.measureText(maxNetworkRateName); + context.globalAlpha = 0.8 + context.fillStyle = "#f0f0f0" + context.fillRect(0, 5, textMetrics.width + 8, 18) + context.globalAlpha = 1 + context.fillStyle = "#333" + context.textBaseline = "middle" + context.fillText(maxNetworkRateName, 4, 5 + 9) + drawWakeUp(context, wakeupBean, startNS, endNS, totalNS, frame); + drawFlagLine(context, flagMoveInfo, flagSelectedInfo, startNS, endNS, totalNS, frame, slicesTime); + } + // @ts-ignore + self.postMessage({ + id: e.data.id, + type: type, + results: canvas ? undefined : dataFilter[type], + hover: NetworkAbilityMonitorStruct.hoverNetworkAbilityStruct + }); + } }; self.onmessageerror = function (e: any) { diff --git a/host/ide/src/trace/database/ProcedureWorkerCPU.ts b/host/ide/src/trace/database/ProcedureWorkerCPU.ts index a0f22b246d0b4efc6767bcd1d2414c6f6e0a26ca..8f616a5f7f1724e38c2904e2627d1c3ce093f960 100644 --- a/host/ide/src/trace/database/ProcedureWorkerCPU.ts +++ b/host/ide/src/trace/database/ProcedureWorkerCPU.ts @@ -15,6 +15,41 @@ import {BaseStruct, ColorUtils} from "./ProcedureWorkerCommon.js"; +let dec = new TextDecoder(); +export function rtCpu(buf: ArrayBuffer | null | undefined, res: Set, startNS: number, endNS: number, totalNS: number, frame: any) { + if (buf) { + res.clear(); + let pns = (endNS - startNS) / frame.width; + let y = frame.y + 5; + let height = frame.height - 10; + + let str = dec.decode(buf); + str = str.substring(str.indexOf("\n") + 1); + let parse = JSON.parse(str); + let columns = parse.columns; + let values = parse.values; + for (let i = 0; i < values.length; i++) { + let obj: any = {} + for (let j = 0; j < columns.length; j++) { + obj[columns[j]] = values[i][j] + } + obj.frame = { + // x: obj.x1, + y: frame.y + 5, + // width: obj.x2 - obj.x1 > 0 ? obj.x2 - obj.x1 : 1, + height: frame.height - 10, + } + CpuStruct.setCpuFrame(obj, pns, startNS, endNS, frame) + res.add(obj); + } + }else{ + let pns = (endNS - startNS) / frame.width; + res.forEach(it=>{ + CpuStruct.setCpuFrame(it, pns, startNS, endNS, frame) + }) + } +} + export function cpu(list: Array, res: Set, startNS: number, endNS: number, totalNS: number, frame: any) { res.clear(); if (list) { @@ -59,25 +94,6 @@ export class CpuStruct extends BaseStruct { tid: number | undefined type: string | undefined - // static setFrame(node: CpuStruct, padding: number, startNS: number, endNS: number, totalNS: number, frame: Rect) { - // let x1: number; - // let x2: number; - // if ((node.startTime || 0) < startNS) { - // x1 = 0; - // } else { - // x1 = ns2x((node.startTime || 0), startNS, endNS, totalNS, frame); - // } - // if ((node.startTime || 0) + (node.dur || 0) > endNS) { - // x2 = frame.width; - // } else { - // x2 = ns2x((node.startTime || 0) + (node.dur || 0), startNS, endNS, totalNS, frame); - // } - // let getV: number = x2 - x1 <= 1 ? 1 : x2 - x1; - // let rectangle: Rect = new Rect(Math.floor(x1), frame.y + padding, Math.ceil(getV), frame.height - padding * 2); - // node.frame = rectangle; - // node.isHover = false; - // } - static draw(ctx: CanvasRenderingContext2D, data: CpuStruct) { if (data.frame) { let width = data.frame.width || 0; @@ -95,6 +111,7 @@ export class CpuStruct extends BaseStruct { let processCharWidth = Math.round(processMeasure.width / process.length) let threadCharWidth = Math.round(threadMeasure.width / thread.length) ctx.fillStyle = "#ffffff" + ctx.font = "11px sans-serif"; let y = data.frame.height / 2 + data.frame.y; if (processMeasure.width < width - textPadding * 2) { let x1 = Math.floor(width / 2 - processMeasure.width / 2 + data.frame.x + textPadding) @@ -106,6 +123,8 @@ export class CpuStruct extends BaseStruct { ctx.textBaseline = "bottom"; ctx.fillText(process.substring(0, chatNum - 4) + '...', x1, y, width - textPadding * 2) } + ctx.fillStyle = "#ffffff" + ctx.font = "9px sans-serif"; if (threadMeasure.width < width - textPadding * 2) { ctx.textBaseline = "top"; let x2 = Math.floor(width / 2 - threadMeasure.width / 2 + data.frame.x + textPadding) diff --git a/host/ide/src/trace/database/ProcedureWorkerCommon.ts b/host/ide/src/trace/database/ProcedureWorkerCommon.ts index 2672f456510da3415e74d4ebdd4dc8e61d7e84d9..afff67695bfc44aa1ee645f8b2b9d44543e42577 100644 --- a/host/ide/src/trace/database/ProcedureWorkerCommon.ts +++ b/host/ide/src/trace/database/ProcedureWorkerCommon.ts @@ -13,6 +13,8 @@ * limitations under the License. */ +import {SpApplication} from "../SpApplication"; + export function ns2s(ns: number): string { let second1 = 1_000_000_000; // 1 second let millisecond1 = 1_000_000; // 1 millisecond @@ -176,7 +178,26 @@ export class ColorUtils { "#535da6", // indigo "#008078", // blue "#ff9201", - "#38428c"]; + "#38428c", + "#3391ff",// red + "#0076ff",// pink + "#66adff",// purple + "#2db3aa",// deep purple + "#008078",// indigo + "#73e6de",// blue + "#535da6",// light blue + "#38428c", // cyan + "#7a84cc",// teal + "#ff9201",// green + "#ff7500",// light green + "#ffab40",// lime + "#2db4e2",// amber 0xffc105 + "#0094c6", // orange + "#7cdeff",// deep orange + "#ffd44a", // brown + "#fbbf00",// blue gray + "#ffe593",// yellow 0xffec3d + ]; /** * Get the color value according to the length of the string @@ -220,10 +241,9 @@ export class ColorUtils { } } -export function drawLines(ctx: any, xs: Array, height: number, lineColor: string) { +export function drawLines(ctx: CanvasRenderingContext2D, xs: Array, height: number, lineColor: string) { if (ctx) { ctx.lineWidth = 1; - // ctx.strokeStyle = window.getComputedStyle(this.rootEL!, null).getPropertyValue("border-bottom-color");//"#dadada" "#474e59";// ctx.strokeStyle = lineColor || "#dadada"; xs?.forEach(it => { ctx.moveTo(Math.floor(it), 0) @@ -233,7 +253,7 @@ export function drawLines(ctx: any, xs: Array, height: number, lineColor: s } } -export function drawFlagLine(ctx: any, hoverFlag: any, selectFlag: any, startNS: number, endNS: number, totalNS: number, frame: any) { +export function drawFlagLine(ctx: any, hoverFlag: any, selectFlag: any, startNS: number, endNS: number, totalNS: number, frame: any, slicesTime: { startTime: number | null, endTime: number | null ,color:string|null}) { if (ctx) { if (hoverFlag) { ctx.beginPath(); @@ -254,6 +274,159 @@ export function drawFlagLine(ctx: any, hoverFlag: any, selectFlag: any, startNS: ctx.stroke(); ctx.closePath(); } + if (slicesTime && slicesTime.startTime && slicesTime.endTime) { + ctx.beginPath(); + ctx.lineWidth = 1; + ctx.strokeStyle = slicesTime.color||"#dadada"; + let x1 = ns2x(slicesTime.startTime, startNS, endNS, totalNS, frame); + let x2 = ns2x(slicesTime.endTime, startNS, endNS, totalNS, frame); + ctx.moveTo(Math.floor(x1), 0) + ctx.lineTo(Math.floor(x1), frame.height) + ctx.moveTo(Math.floor(x2), 0) + ctx.lineTo(Math.floor(x2), frame.height) + ctx.stroke(); + ctx.closePath(); + } } } +/** + * get framechart color by percent + * @param widthPercentage proportion of function + * @returns rbg + */ +export function getHeatColor(widthPercentage: number) { + return { + r: Math.floor(245 + 10 * (1 - widthPercentage)), + g: Math.floor(110 + 105 * (1 - widthPercentage)), + b: 100, + }; +} + +export enum ChartMode { + Call, + Byte, + Count, +} + +export class ChartStruct extends BaseStruct { + static hoverFuncStruct: ChartStruct | undefined; + static selectFuncStruct: ChartStruct | undefined; + static padding: number = 1; + depth: number = 0; + symbol: string = ''; + size: number = 0; + count: number = 0; + type: ChartMode = ChartMode.Call; + parent: ChartStruct | undefined; + children: Array = []; + + /** + * set function position + * @param node current function struct + * @param canvas_frame canvas + * @param total all rect size + */ + static setFuncFrame(node: ChartStruct, canvas_frame: Rect, total: number, mode: ChartMode) { + if (!node.frame) { + node.frame = new Rect(0, 0, 0, 0); + } + // filter depth is 0 + if (node.parent instanceof ChartStruct) { + let idx = node.parent.children.indexOf(node); + if (idx == 0) { + node.frame!.x = node.parent.frame!.x; + } else { + // set x by left frame. left frame is parent.children[idx - 1] + node.frame.x = node.parent.children[idx - 1].frame!.x + node.parent.children[idx - 1].frame!.width + } + let width = 0; + if (mode == ChartMode.Byte) { + width = node.size / total * canvas_frame.width; + } else { + width = node.count / total * canvas_frame.width; + } + // ensure every rect at least draw 1px + width = (width < 1) ? Math.ceil(width) : Math.floor(width); + node.frame!.width = width; + node.frame!.y = node.parent.frame!.y + 20; + node.frame!.height = 20; + } + } + + /** + * draw rect + * @param ctx CanvasRenderingContext2D + * @param data rect which is need draw + * @param percent function size or count / total size or count + */ + static draw(ctx: CanvasRenderingContext2D, data: ChartStruct, percent: number) { + let spApplication = document.getElementsByTagName("sp-application")[0] + if (data.frame) { + // draw rect + let color = getHeatColor(percent); + let miniHeight = 20; + ctx.fillStyle = `rgba(${color.r}, ${color.g}, ${color.b}, 0.9)`; + ctx.fillRect(data.frame.x, data.frame.y, data.frame.width, miniHeight - ChartStruct.padding * 2); + + //draw border + if (ChartStruct.isHover(data)) { + if (spApplication.dark) { + ctx.strokeStyle = "#fff"; + } else { + ctx.strokeStyle = "#000"; + } + } else { + if (spApplication.dark) { + ctx.strokeStyle = "#000"; + } else { + ctx.strokeStyle = "#fff"; + } + } + ctx.lineWidth = 0.4; + ctx.strokeRect(data.frame.x, data.frame.y, data.frame.width, miniHeight - ChartStruct.padding * 2); + + //draw symbol name + if (data.frame.width > 10) { + if (percent > 0.6) { + ctx.fillStyle = "#fff"; + } else { + ctx.fillStyle = "#000"; + } + ChartStruct.drawString(ctx, data.symbol || '', 5, data.frame); + } + + } + } + + /** + * draw function string in rect + * @param ctx CanvasRenderingContext2D + * @param str function Name + * @param textPadding textPadding + * @param frame canvas area + * @returns is draw + */ + static drawString(ctx: CanvasRenderingContext2D, str: string, textPadding: number, frame: Rect): boolean { + let textMetrics = ctx.measureText(str); + let charWidth = Math.round(textMetrics.width / str.length) + if (textMetrics.width < frame.width - textPadding * 2) { + let x2 = Math.floor(frame.width / 2 - textMetrics.width / 2 + frame.x + textPadding) + ctx.fillText(str, x2, Math.floor(frame.y + frame.height / 2 + 2), frame.width - textPadding * 2) + return true; + } + if (frame.width - textPadding * 2 > charWidth * 4) { + let chatNum = (frame.width - textPadding * 2) / charWidth; + let x1 = frame.x + textPadding + ctx.fillText(str.substring(0, chatNum - 4) + '...', x1, Math.floor(frame.y + frame.height / 2 + 2), frame.width - textPadding * 2) + return true; + } + return false; + } + + static isHover(data: ChartStruct): boolean { + return ChartStruct.hoverFuncStruct == data; + } + + +} diff --git a/host/ide/src/trace/database/ProcedureWorkerCpuAbility.ts b/host/ide/src/trace/database/ProcedureWorkerCpuAbility.ts new file mode 100644 index 0000000000000000000000000000000000000000..dcf87ec95811b6c98b9bafa9d95600e751b04805 --- /dev/null +++ b/host/ide/src/trace/database/ProcedureWorkerCpuAbility.ts @@ -0,0 +1,110 @@ +/* + * 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. + */ + +import {BaseStruct, ColorUtils, ns2x} from "./ProcedureWorkerCommon.js"; + +export function cpuAbility(list: Array, res: Set, startNS: number, endNS: number, totalNS: number, frame: any) { + res.clear() + if (list) { + for (let index = 0; index < list.length; index++) { + let item = list[index]; + if (index === list.length - 1) { + item.dur = (endNS || 0) - (item.startNS || 0) + } else { + item.dur = (list[index + 1].startNS || 0) - (item.startNS || 0) + } + if ((item.startNS || 0) + (item.dur || 0) > (startNS || 0) && (item.startNS || 0) < (endNS || 0)) { + CpuAbilityMonitorStruct.setCpuAbilityFrame(list[index], 5, startNS || 0, endNS || 0, totalNS || 0, frame) + if (index > 0 && ((list[index - 1].frame?.x || 0) == (list[index].frame?.x || 0) && (list[index - 1].frame?.width || 0) == (list[index].frame?.width || 0))) { + + } else { + res.add(item) + } + } + } + } +} + +export class CpuAbilityMonitorStruct extends BaseStruct { + static maxCpuUtilization: number = 0 + static maxCpuUtilizationName: string = "0 %" + static hoverCpuAbilityStruct: CpuAbilityMonitorStruct | undefined; + static selectCpuAbilityStruct: CpuAbilityMonitorStruct | undefined; + + type: number | undefined + value: number | undefined + startNS: number | undefined + dur: number | undefined //自补充,数据库没有返回 + + static draw(context2D: CanvasRenderingContext2D, data: CpuAbilityMonitorStruct) { + if (data.frame) { + let width = data.frame.width || 0; + let index = 2; + context2D.fillStyle = ColorUtils.colorForTid(index) + context2D.strokeStyle = ColorUtils.colorForTid(index) + if (data.startNS === CpuAbilityMonitorStruct.hoverCpuAbilityStruct?.startNS) { + context2D.lineWidth = 1; + context2D.globalAlpha = 0.6; + let drawHeight: number = Math.floor(((data.value || 0) * (data.frame.height || 0) * 1.0) / CpuAbilityMonitorStruct.maxCpuUtilization); + context2D.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight + 4, width, drawHeight) + context2D.beginPath() + context2D.arc(data.frame.x, data.frame.y + data.frame.height - drawHeight + 4, 3, 0, 2 * Math.PI, true) + context2D.fill() + context2D.globalAlpha = 1.0; + context2D.stroke(); + context2D.beginPath() + context2D.moveTo(data.frame.x + 3, data.frame.y + data.frame.height - drawHeight + 4); + context2D.lineWidth = 3; + context2D.lineTo(data.frame.x + width, data.frame.y + data.frame.height - drawHeight + 4) + context2D.stroke(); + } else { + context2D.globalAlpha = 0.6; + context2D.lineWidth = 1; + let drawHeight: number = Math.floor(((data.value || 0) * (data.frame.height || 0)) / CpuAbilityMonitorStruct.maxCpuUtilization); + context2D.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight + 4, width, drawHeight) + } + } + context2D.globalAlpha = 1.0; + context2D.lineWidth = 1; + } + + static setCpuAbilityFrame(node: any, padding: number, startNS: number, endNS: number, totalNS: number, frame: any) { + let startPointX: number, endPointX: number + + if ((node.startNS || 0) < startNS) { + startPointX = 0 + } else { + startPointX = ns2x((node.startNS || 0), startNS, endNS, totalNS, frame); + } + if ((node.startNS || 0) + (node.dur || 0) > endNS) { + endPointX = frame.width; + } else { + endPointX = ns2x((node.startNS || 0) + (node.dur || 0), startNS, endNS, totalNS, frame); + } + let frameWidth: number = endPointX - startPointX <= 1 ? 1 : endPointX - startPointX; + if (!node.frame) { + node.frame = {}; + } + node.frame.x = Math.floor(startPointX); + node.frame.y = frame.y + padding; + node.frame.width = Math.ceil(frameWidth); + node.frame.height = Math.floor(frame.height - padding * 2); + } +} + +export class CpuAbility { + context: any + params: any +} \ No newline at end of file diff --git a/host/ide/src/trace/database/ProcedureWorkerDiskIoAbility.ts b/host/ide/src/trace/database/ProcedureWorkerDiskIoAbility.ts new file mode 100644 index 0000000000000000000000000000000000000000..c7305ffd132ddee0ee5499ed0f5241cb02c0cba7 --- /dev/null +++ b/host/ide/src/trace/database/ProcedureWorkerDiskIoAbility.ts @@ -0,0 +1,104 @@ +/* + * 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. + */ + +import {BaseStruct, ColorUtils, ns2x} from "./ProcedureWorkerCommon.js"; + +export function diskIoAbility(list: Array, res: Set, startNS: number, endNS: number, totalNS: number, frame: any) { + res.clear(); + if (list) { + for (let index = 0; index < list.length; index++) { + let item = list[index]; + if (index === list.length - 1) { + item.dur = (endNS || 0) - (item.startNS || 0) + } else { + item.dur = (list[index + 1].startNS || 0) - (item.startNS || 0) + } + if ((item.startNS || 0) + (item.dur || 0) > (startNS || 0) && (item.startNS || 0) < (endNS || 0)) { + DiskAbilityMonitorStruct.setDiskIOFrame(list[index], 5, startNS || 0, endNS || 0, totalNS || 0, frame) + if (index > 0 && ((list[index - 1].frame?.x || 0) == (list[index].frame?.x || 0) && (list[index - 1].frame?.width || 0) == (list[index].frame?.width || 0))) { + + } else { + res.add(item) + } + } + } + } + +} + +export class DiskAbilityMonitorStruct extends BaseStruct { + static maxDiskRate: number = 0 + static maxDiskRateName: string = "0 KB/S" + static hoverDiskAbilityStruct: DiskAbilityMonitorStruct | undefined; + static selectDiskAbilityStruct: DiskAbilityMonitorStruct | undefined; + value: number | undefined + startNS: number | undefined + dur: number | undefined //自补充,数据库没有返回 + + static draw(context2D: CanvasRenderingContext2D, data: DiskAbilityMonitorStruct, maxDiskRate: number) { + if (data.frame) { + let width = data.frame.width || 0; + let index = 2; + context2D.fillStyle = ColorUtils.colorForTid(index) + context2D.strokeStyle = ColorUtils.colorForTid(index) + if (data.startNS === DiskAbilityMonitorStruct.hoverDiskAbilityStruct?.startNS) { + context2D.lineWidth = 1; + context2D.globalAlpha = 0.6; + let drawHeight: number = Math.floor(((data.value || 0) * (data.frame.height || 0) * 1.0) / maxDiskRate); + context2D.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight + 4, width, drawHeight) + context2D.beginPath() + context2D.arc(data.frame.x, data.frame.y + data.frame.height - drawHeight + 4, 3, 0, 2 * Math.PI, true) + context2D.fill() + context2D.globalAlpha = 1.0; + context2D.stroke(); + context2D.beginPath() + context2D.moveTo(data.frame.x + 3, data.frame.y + data.frame.height - drawHeight + 4); + context2D.lineWidth = 3; + context2D.lineTo(data.frame.x + width, data.frame.y + data.frame.height - drawHeight + 4) + context2D.stroke(); + } else { + context2D.globalAlpha = 0.6; + context2D.lineWidth = 1; + let drawHeight: number = Math.floor(((data.value || 0) * (data.frame.height || 0)) / maxDiskRate); + context2D.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight + 4, width, drawHeight) + } + } + context2D.globalAlpha = 1.0; + context2D.lineWidth = 1; + } + + static setDiskIOFrame(node: any, padding: number, startNS: number, endNS: number, totalNS: number, frame: any) { + let startPointX: number, endPointX: number + + if ((node.startNS || 0) < startNS) { + startPointX = 0 + } else { + startPointX = ns2x((node.startNS || 0), startNS, endNS, totalNS, frame); + } + if ((node.startNS || 0) + (node.dur || 0) > endNS) { + endPointX = frame.width; + } else { + endPointX = ns2x((node.startNS || 0) + (node.dur || 0), startNS, endNS, totalNS, frame); + } + let frameWidth: number = endPointX - startPointX <= 1 ? 1 : endPointX - startPointX; + if (!node.frame) { + node.frame = {}; + } + node.frame.x = Math.floor(startPointX); + node.frame.y = frame.y + padding; + node.frame.width = Math.ceil(frameWidth); + node.frame.height = Math.floor(frame.height - padding * 2); + } +} diff --git a/host/ide/src/trace/database/ProcedureWorkerFunc.ts b/host/ide/src/trace/database/ProcedureWorkerFunc.ts index 773ff7bc0d00c16508f92be40ae1ff42543501b5..f08f27d353da435cf8924879857648a67c7f4193 100644 --- a/host/ide/src/trace/database/ProcedureWorkerFunc.ts +++ b/host/ide/src/trace/database/ProcedureWorkerFunc.ts @@ -69,12 +69,20 @@ export class FuncStruct extends BaseStruct { node.frame.height = 20; } + static getInt(data:FuncStruct):number{ + let str = data.funName || ""; + let sum = 0; + for (let i = 0; i < str.length; i++) { + sum+=str.charCodeAt(i) + } + return (sum+(data?.depth||0)) % ColorUtils.FUNC_COLOR.length; + } static draw(ctx: CanvasRenderingContext2D, data: FuncStruct) { if (data.frame) { let isBinder = FuncStruct.isBinder(data); if (data.dur == undefined || data.dur == null || data.dur == 0) { } else { - ctx.fillStyle = ColorUtils.FUNC_COLOR[(data.funName?.length || 0) % ColorUtils.FUNC_COLOR.length] + ctx.fillStyle = ColorUtils.FUNC_COLOR[FuncStruct.getInt(data)]; let miniHeight = 20 ctx.fillRect(data.frame.x, data.frame.y, data.frame.width, miniHeight - padding * 2) if (data.frame.width > 10) { diff --git a/host/ide/src/trace/database/ProcedureWorkerHeap.ts b/host/ide/src/trace/database/ProcedureWorkerHeap.ts index 9a11b403c1df8dc3d9c4537310cda9a312d28ff9..dcb963c2b80d422c04f697386612b1e83f83f6b8 100644 --- a/host/ide/src/trace/database/ProcedureWorkerHeap.ts +++ b/host/ide/src/trace/database/ProcedureWorkerHeap.ts @@ -23,7 +23,7 @@ export function heap(list: Array, res: Set, startNS: number, endNS: nu if ((it.startTime || 0) + (it.dur || 0) > (startNS || 0) && (it.startTime || 0) < (endNS || 0)) { HeapStruct.setFrame(list[i], 5, startNS || 0, endNS || 0, totalNS || 0, frame) if (i > 0 && ((list[i - 1].frame?.x || 0) == (list[i].frame?.x || 0) && (list[i - 1].frame?.width || 0) == (list[i].frame?.width || 0))) { - continue; + } else { res.add(list[i]) } @@ -67,10 +67,10 @@ export class HeapStruct extends BaseStruct { if (data.startTime === HeapStruct.hoverHeapStruct?.startTime) { ctx.lineWidth = 1; ctx.globalAlpha = 0.6; - let drawHeight:number = 0; - if(data.minHeapSize < 0 ){ + let drawHeight: number = 0; + if (data.minHeapSize < 0) { drawHeight = Math.ceil((((data.heapsize || 0) - data.minHeapSize) * (data.frame.height || 0)) / (data.maxHeapSize - data.minHeapSize)); - }else{ + } else { drawHeight = Math.ceil(((data.heapsize || 0) * (data.frame.height || 0)) / data.maxHeapSize); } ctx.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight, width, drawHeight) diff --git a/host/ide/src/trace/database/ProcedureWorkerHiPerfCPU.ts b/host/ide/src/trace/database/ProcedureWorkerHiPerfCPU.ts new file mode 100644 index 0000000000000000000000000000000000000000..030f6e9bd2634610062471b314ffd68539f45ffe --- /dev/null +++ b/host/ide/src/trace/database/ProcedureWorkerHiPerfCPU.ts @@ -0,0 +1,143 @@ +/* + * 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. + */ + +import {BaseStruct} from "./ProcedureWorkerCommon.js"; + +export function hiPerfCpu(arr: Array, arr2: any ,type: string, res: Set, startNS: number, endNS: number, totalNS: number, frame: any, groupBy10MS: boolean, maxCpu: number | undefined, intervalPerf: number) { + res.clear(); + if (arr) { + let list: Array; + if (groupBy10MS) { + if (arr2[type] && arr2[type].length > 0) { + list = arr2[type]; + } else { + list = HiPerfCpuStruct.groupBy10MS(arr, maxCpu, intervalPerf); + arr2[type] = list; + } + } else { + list = arr; + } + let pns = (endNS - startNS) / frame.width; + let y = frame.y; + + let groups = list.filter(it => (it.startNS || 0) + (it.dur || 0) > startNS && (it.startNS || 0) < endNS).map(it => { + if (!it.frame) { + it.frame = {}; + it.frame.y = y; + } + it.frame.height = it.height; + HiPerfCpuStruct.setFrame(it, pns, startNS, endNS, frame); + return it; + }).reduce((pre, current, index, arr) => { + if(!pre[`${current.frame.x}`]){ + pre[`${current.frame.x}`]=[]; + pre[`${current.frame.x}`].push(current); + res.add(current); + } + return pre; + }, {}); + } +} + +export class HiPerfCpuStruct extends BaseStruct { + static hoverStruct: HiPerfCpuStruct | undefined; + static selectStruct: HiPerfCpuStruct | undefined; + static path = new Path2D('M 100,100 h 50 v 50 h 50'); + id: number | undefined; + sample_id: number | undefined; + timestamp: number | undefined; + thread_id: number | undefined; + event_count: number | undefined; + event_type_id: number | undefined; + cpu_id: number | undefined; + thread_state: string | undefined; + //------------------------------------------------------ + startNS: number | undefined; + endNS: number | undefined; + dur: number | undefined; + height: number | undefined; + cpu: number | undefined; + + static draw(ctx: CanvasRenderingContext2D,path:Path2D, data: HiPerfCpuStruct, groupBy10MS: boolean) { + if (data.frame) { + if (groupBy10MS) { + let width = data.frame.width; + path.rect(data.frame.x, 40 - (data.height || 0), width, data.height || 0) + } else { + path.moveTo(data.frame.x + 7, 20); + HiPerfCpuStruct.drawRoundRectPath(path,data.frame.x-7,20-7,14,14,3) + path.moveTo(data.frame.x, 27); + path.lineTo(data.frame.x, 33); + } + } + } + + static drawRoundRectPath(cxt: Path2D,x:number,y:number, width:number, height:number, radius:number) { + cxt.arc(x+width - radius, y+height - radius, radius, 0, Math.PI / 2); + cxt.lineTo(x+radius, y+height); + cxt.arc(x+radius, y+height - radius, radius, Math.PI / 2, Math.PI); + cxt.lineTo(x+0, y+radius); + cxt.arc(x+radius, y+radius, radius, Math.PI, Math.PI * 3 / 2); + cxt.lineTo(x+width - radius, y+0); + cxt.arc(x+width - radius, y+radius, radius, Math.PI * 3 / 2, Math.PI * 2); + cxt.lineTo(x+width, y+height - radius); + cxt.moveTo(x+width/3,y+height/5); + cxt.lineTo(x+width/3,y+height/5*4); + cxt.moveTo(x+width/3,y+height/5); + cxt.bezierCurveTo(x+width/3+7,y+height/5-2,x+width/3+7,y+height/5+6,x+width/3,y+height/5+4); + } + + static setFrame(node: any, pns: number, startNS: number, endNS: number, frame: any) { + if ((node.startNS || 0) < startNS) { + node.frame.x = 0; + } else { + node.frame.x = Math.floor(((node.startNS || 0) - startNS) / pns); + } + if ((node.startNS || 0) + (node.dur || 0) > endNS) { + node.frame.width = frame.width - node.frame.x; + } else { + node.frame.width = Math.ceil(((node.startNS || 0) + (node.dur || 0) - startNS) / pns - node.frame.x); + } + if (node.frame.width < 1) { + node.frame.width = 1; + } + } + + static groupBy10MS(array: Array, maxCpu: number | undefined, intervalPerf: number): Array { + let obj = array.map(it => { + it.timestamp_group = Math.trunc(it.startNS / 1_000_000_0) * 1_000_000_0; + return it; + }).reduce((pre, current) => { + (pre[current["timestamp_group"]] = pre[current["timestamp_group"]] || []).push(current); + return pre; + }, {}); + let arr: any[] = []; + for (let aKey in obj) { + let ns = parseInt(aKey); + let height: number = 0; + if(maxCpu!=undefined){ + height = Math.floor(obj[aKey].length / (10 / intervalPerf) / maxCpu * 40); + }else{ + height = Math.floor(obj[aKey].length / (10 / intervalPerf) * 40); + } + arr.push({ + startNS: ns, + dur: 1_000_000_0, + height: height, + }) + } + return arr; + } +} \ No newline at end of file diff --git a/host/ide/src/trace/database/ProcedureWorkerHiPerfProcess.ts b/host/ide/src/trace/database/ProcedureWorkerHiPerfProcess.ts new file mode 100644 index 0000000000000000000000000000000000000000..4c37adcc8945d0404d3214d777f82fdb28c6cdda --- /dev/null +++ b/host/ide/src/trace/database/ProcedureWorkerHiPerfProcess.ts @@ -0,0 +1,124 @@ +/* + * 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. + */ + +import {BaseStruct} from "./ProcedureWorkerCommon.js"; +import {HiPerfCpuStruct} from "./ProcedureWorkerHiPerfCPU.js"; + +export function hiPerfProcess(arr: Array, res: Set, startNS: number, endNS: number, totalNS: number, frame: any, groupBy10MS: boolean,intervalPerf:number) { + res.clear(); + if (arr) { + let list = groupBy10MS ? HiPerfProcessStruct.groupBy10MS(arr,intervalPerf) : arr; + let pns = (endNS - startNS) / frame.width; + let y = frame.y; + for (let i = 0, len = list.length; i < len; i++) { + let it = list[i]; + if ((it.startNS || 0) + (it.dur || 0) > startNS && (it.startNS || 0) < endNS) { + if (!list[i].frame) { + list[i].frame = {}; + list[i].frame.y = y; + } + list[i].frame.height = it.height; + HiPerfProcessStruct.setFrame(list[i], pns, startNS, endNS, frame) + if (groupBy10MS) { + if (i > 0 && ((list[i - 1].frame?.x || 0) == (list[i].frame?.x || 0) + && ((list[i - 1].frame?.width || 0) == (list[i].frame?.width || 0)) + && ((list[i - 1].frame?.height || 0) == (list[i].frame?.height || 0)) + )) { + } else { + res.add(list[i]) + } + } else { + if (i > 0 && (Math.abs((list[i - 1].frame?.x || 0) - (list[i].frame?.x || 0)) < 3)) { + } else { + res.add(list[i]) + } + } + + } + } + } +} + +export class HiPerfProcessStruct extends BaseStruct { + static hoverStruct: HiPerfProcessStruct | undefined; + static selectStruct: HiPerfProcessStruct | undefined; + id: number | undefined; + sample_id: number | undefined; + timestamp: number | undefined; + thread_id: number | undefined; + event_count: number | undefined; + event_type_id: number | undefined; + cpu_id: number | undefined; + thread_state: string | undefined; + //------------------------------------------------------ + startNS: number | undefined; + endNS: number | undefined; + dur: number | undefined; + height: number | undefined; + cpu: number | undefined; + group: number | undefined; + + static draw(ctx: CanvasRenderingContext2D,path:Path2D, data: HiPerfProcessStruct, groupBy10MS: boolean) { + if (data.frame) { + if (groupBy10MS) { + let width = data.frame.width; + path.rect(data.frame.x, 40 - (data.height || 0), width, data.height || 0) + } else { + path.moveTo(data.frame.x + 7, 20); + HiPerfCpuStruct.drawRoundRectPath(path,data.frame.x-7,20-7,14,14,3) + path.moveTo(data.frame.x, 27); + path.lineTo(data.frame.x, 33); + } + } + } + + static setFrame(node: any, pns: number, startNS: number, endNS: number, frame: any) { + if ((node.startNS || 0) < startNS) { + node.frame.x = 0; + } else { + node.frame.x = Math.floor(((node.startNS || 0) - startNS) / pns); + } + if ((node.startNS || 0) + (node.dur || 0) > endNS) { + node.frame.width = frame.width - node.frame.x; + } else { + node.frame.width = Math.ceil(((node.startNS || 0) + (node.dur || 0) - startNS) / pns - node.frame.x); + } + if (node.frame.width < 1) { + node.frame.width = 1; + } + } + + static groupBy10MS(array: Array,intervalPerf:number): Array { + let obj = array.map(it => { + it.timestamp_group = Math.trunc(it.startNS / 1_000_000_0) * 1_000_000_0; + return it; + }).reduce((pre, current) => { + (pre[current["timestamp_group"]] = pre[current["timestamp_group"]] || []).push(current); + return pre; + }, {}); + let arr: any[] = []; + for (let aKey in obj) { + let ns = parseInt(aKey); + let height: number = 0; + height = Math.floor(obj[aKey].length / (10/intervalPerf) * 40); + arr.push({ + startNS: ns, + height: height, + dur: 1_000_000_0, + }) + } + return arr; + } +} diff --git a/host/ide/src/trace/database/ProcedureWorkerHiPerfThread.ts b/host/ide/src/trace/database/ProcedureWorkerHiPerfThread.ts new file mode 100644 index 0000000000000000000000000000000000000000..547d9870a2ed46d8934338a840d69da39692c048 --- /dev/null +++ b/host/ide/src/trace/database/ProcedureWorkerHiPerfThread.ts @@ -0,0 +1,123 @@ +/* + * 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. + */ + +import {BaseStruct} from "./ProcedureWorkerCommon.js"; +import {HiPerfCpuStruct} from "./ProcedureWorkerHiPerfCPU.js"; + +export function hiPerfThread(arr: Array, res: Set, startNS: number, endNS: number, totalNS: number, frame: any, groupBy10MS: boolean, intervalPerf: number) { + res.clear(); + if (arr) { + let list = groupBy10MS ? HiPerfThreadStruct.groupBy10MS(arr, intervalPerf) : arr; + let pns = (endNS - startNS) / frame.width; + let y = frame.y; + for (let i = 0, len = list.length; i < len; i++) { + let it = list[i]; + if ((it.startNS || 0) + (it.dur || 0) > startNS && (it.startNS || 0) < endNS) { + if (!list[i].frame) { + list[i].frame = {}; + list[i].frame.y = y; + } + list[i].frame.height = it.height; + HiPerfThreadStruct.setFrame(list[i], pns, startNS, endNS, frame) + if (groupBy10MS) { + if (i > 0 && ((list[i - 1].frame?.x || 0) == (list[i].frame?.x || 0) + && ((list[i - 1].frame?.width || 0) == (list[i].frame?.width || 0)) + && ((list[i - 1].frame?.height || 0) == (list[i].frame?.height || 0)) + )) { + + } else { + res.add(list[i]) + } + } else { + if (i > 0 && (Math.abs((list[i - 1].frame?.x || 0) - (list[i].frame?.x || 0)) < 3)) { + } else { + res.add(list[i]) + } + } + } + } + } +} + +export class HiPerfThreadStruct extends BaseStruct { + static hoverStruct: HiPerfThreadStruct | undefined; + static selectStruct: HiPerfThreadStruct | undefined; + id: number | undefined; + sample_id: number | undefined; + timestamp: number | undefined; + thread_id: number | undefined; + event_count: number | undefined; + event_type_id: number | undefined; + cpu_id: number | undefined; + thread_state: string | undefined; + //------------------------------------------------------ + startNS: number | undefined; + endNS: number | undefined; + dur: number | undefined; + height: number | undefined; + cpu: number | undefined; + + static draw(ctx: CanvasRenderingContext2D, path: Path2D, data: HiPerfThreadStruct, groupBy10MS: boolean) { + if (data.frame) { + if (groupBy10MS) { + let width = data.frame.width; + path.rect(data.frame.x, 40 - (data.height || 0), width, data.height || 0) + } else { + path.moveTo(data.frame.x + 7, 20); + HiPerfCpuStruct.drawRoundRectPath(path,data.frame.x-7,20-7,14,14,3) + path.moveTo(data.frame.x, 27); + path.lineTo(data.frame.x, 33); + } + } + } + + static setFrame(node: any, pns: number, startNS: number, endNS: number, frame: any) { + if ((node.startNS || 0) < startNS) { + node.frame.x = 0; + } else { + node.frame.x = Math.floor(((node.startNS || 0) - startNS) / pns); + } + if ((node.startNS || 0) + (node.dur || 0) > endNS) { + node.frame.width = frame.width - node.frame.x; + } else { + node.frame.width = Math.ceil(((node.startNS || 0) + (node.dur || 0) - startNS) / pns - node.frame.x); + } + if (node.frame.width < 1) { + node.frame.width = 1; + } + } + + static groupBy10MS(array: Array, intervalPerf: number): Array { + let obj = array.map(it => { + it.timestamp_group = Math.trunc(it.startNS / 1_000_000_0) * 1_000_000_0; + return it; + }).reduce((pre, current) => { + (pre[current["timestamp_group"]] = pre[current["timestamp_group"]] || []).push(current); + return pre; + }, {}); + let arr: any[] = []; + for (let aKey in obj) { + let ns = parseInt(aKey); + let height: number = 0; + height = Math.floor(obj[aKey].length / (10 / intervalPerf) * 40); + arr.push({ + startNS: ns, + height: height, + dur: 1_000_000_0, + }) + } + return arr; + } +} diff --git a/host/ide/src/trace/database/ProcedureWorkerMemoryAbility.ts b/host/ide/src/trace/database/ProcedureWorkerMemoryAbility.ts new file mode 100644 index 0000000000000000000000000000000000000000..8c5857dfd4d06b33cef899a966c12513709765c3 --- /dev/null +++ b/host/ide/src/trace/database/ProcedureWorkerMemoryAbility.ts @@ -0,0 +1,106 @@ +/* + * 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. + */ + +import {BaseStruct, ColorUtils, ns2x} from "./ProcedureWorkerCommon.js"; + +export function memoryAbility(list: Array, res: Set, startNS: number, endNS: number, totalNS: number, frame: any) { + res.clear(); + if (list) { + for (let index = 0; index < list.length; index++) { + let item = list[index]; + if (index === list.length - 1) { + item.dur = (endNS || 0) - (item.startNS || 0) + } else { + item.dur = (list[index + 1].startNS || 0) - (item.startNS || 0) + } + if ((item.startNS || 0) + (item.dur || 0) > (startNS || 0) && (item.startNS || 0) < (endNS || 0)) { + MemoryAbilityMonitorStruct.setMemoryFrame(list[index], 5, startNS || 0, endNS || 0, totalNS || 0, frame) + if (index > 0 && ((list[index - 1].frame?.x || 0) == (list[index].frame?.x || 0) && (list[index - 1].frame?.width || 0) == (list[index].frame?.width || 0))) { + + } else { + res.add(item) + } + } + } + } +} + +export class MemoryAbilityMonitorStruct extends BaseStruct { + static maxMemoryByte: number = 0 + static maxMemoryByteName: string = "0 MB" + static hoverMemoryAbilityStruct: MemoryAbilityMonitorStruct | undefined; + static selectMemoryAbilityStruct: MemoryAbilityMonitorStruct | undefined; + cpu: number | undefined + value: number | undefined + startNS: number | undefined + dur: number | undefined + + static draw(context2D: CanvasRenderingContext2D, data: MemoryAbilityMonitorStruct) { + if (data.frame) { + let width = data.frame.width || 0; + let index = 2; + context2D.fillStyle = ColorUtils.colorForTid(index) + context2D.strokeStyle = ColorUtils.colorForTid(index) + if (data.startNS === MemoryAbilityMonitorStruct.hoverMemoryAbilityStruct?.startNS) { + context2D.lineWidth = 1; + context2D.globalAlpha = 0.6; + let drawHeight: number = Math.floor(((data.value || 0) * (data.frame.height || 0) * 1.0) / MemoryAbilityMonitorStruct.maxMemoryByte); + context2D.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight + 4, width, drawHeight) + context2D.beginPath() + context2D.arc(data.frame.x, data.frame.y + data.frame.height - drawHeight + 4, 3, 0, 2 * Math.PI, true) + context2D.fill() + context2D.globalAlpha = 1.0; + context2D.stroke(); + context2D.beginPath() + context2D.moveTo(data.frame.x + 3, data.frame.y + data.frame.height - drawHeight + 4); + context2D.lineWidth = 3; + context2D.lineTo(data.frame.x + width, data.frame.y + data.frame.height - drawHeight + 4) + context2D.stroke(); + } else { + context2D.globalAlpha = 0.6; + context2D.lineWidth = 1; + let drawHeight: number = Math.floor(((data.value || 0) * (data.frame.height || 0)) / MemoryAbilityMonitorStruct.maxMemoryByte); + context2D.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight + 4, width, drawHeight) + } + } + context2D.globalAlpha = 1.0; + context2D.lineWidth = 1; + } + + static setMemoryFrame(node: any, padding: number, startNS: number, endNS: number, totalNS: number, frame: any) { + let startPointX: number, endPointX: number + + if ((node.startNS || 0) < startNS) { + startPointX = 0 + } else { + startPointX = ns2x((node.startNS || 0), startNS, endNS, totalNS, frame); + } + if ((node.startNS || 0) + (node.dur || 0) > endNS) { + endPointX = frame.width; + } else { + endPointX = ns2x((node.startNS || 0) + (node.dur || 0), startNS, endNS, totalNS, frame); + } + let frameWidth: number = endPointX - startPointX <= 1 ? 1 : endPointX - startPointX; + if (!node.frame) { + node.frame = {}; + } + node.frame.x = Math.floor(startPointX); + node.frame.y = frame.y + padding; + node.frame.width = Math.ceil(frameWidth); + node.frame.height = Math.floor(frame.height - padding * 2); + } +} + +const textPadding = 2; diff --git a/host/ide/src/trace/database/ProcedureWorkerNetworkAbility.ts b/host/ide/src/trace/database/ProcedureWorkerNetworkAbility.ts new file mode 100644 index 0000000000000000000000000000000000000000..5a5e322883366e44058919b23369dd6e63c3fc60 --- /dev/null +++ b/host/ide/src/trace/database/ProcedureWorkerNetworkAbility.ts @@ -0,0 +1,102 @@ +/* + * 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. + */ + +import {BaseStruct, ColorUtils, ns2x} from "./ProcedureWorkerCommon.js"; + +export function networkAbility(list: Array, res: Set, startNS: number, endNS: number, totalNS: number, frame: any) { + res.clear(); + if (list) { + for (let index = 0; index < list.length; index++) { + let item = list[index]; + if (index === list.length - 1) { + item.dur = (endNS || 0) - (item.startNS || 0) + } else { + item.dur = (list[index + 1].startNS || 0) - (item.startNS || 0) + } + if ((item.startNS || 0) + (item.dur || 0) > (startNS || 0) && (item.startNS || 0) < (endNS || 0)) { + NetworkAbilityMonitorStruct.setNetworkFrame(list[index], 5, startNS || 0, endNS || 0, totalNS || 0, frame) + if (index > 0 && ((list[index - 1].frame?.x || 0) == (list[index].frame?.x || 0) && (list[index - 1].frame?.width || 0) == (list[index].frame?.width || 0))) { + + } else { + res.add(item) + } + } + } + } +} + +export class NetworkAbilityMonitorStruct extends BaseStruct { + static maxNetworkRate: number = 0 + static maxNetworkRateName: string = "0 KB/S" + static hoverNetworkAbilityStruct: NetworkAbilityMonitorStruct | undefined; + static selectNetworkAbilityStruct: NetworkAbilityMonitorStruct | undefined; + value: number | undefined + startNS: number | undefined + + static draw(context2D: CanvasRenderingContext2D, data: NetworkAbilityMonitorStruct, maxNetworkRate: number) { + if (data.frame) { + let width = data.frame.width || 0; + let index = 2; + context2D.fillStyle = ColorUtils.colorForTid(index) + context2D.strokeStyle = ColorUtils.colorForTid(index) + if (data.startNS === NetworkAbilityMonitorStruct.hoverNetworkAbilityStruct?.startNS) { + context2D.lineWidth = 1; + context2D.globalAlpha = 0.6; + let drawHeight: number = Math.floor(((data.value || 0) * (data.frame.height || 0) * 1.0) / maxNetworkRate); + context2D.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight + 4, width, drawHeight) + context2D.beginPath() + context2D.arc(data.frame.x, data.frame.y + data.frame.height - drawHeight + 4, 3, 0, 2 * Math.PI, true) + context2D.fill() + context2D.globalAlpha = 1.0; + context2D.stroke(); + context2D.beginPath() + context2D.moveTo(data.frame.x + 3, data.frame.y + data.frame.height - drawHeight + 4); + context2D.lineWidth = 3; + context2D.lineTo(data.frame.x + width, data.frame.y + data.frame.height - drawHeight + 4) + context2D.stroke(); + } else { + context2D.globalAlpha = 0.6; + context2D.lineWidth = 1; + let drawHeight: number = Math.floor(((data.value || 0) * (data.frame.height || 0)) / maxNetworkRate); + context2D.fillRect(data.frame.x, data.frame.y + data.frame.height - drawHeight + 4, width, drawHeight) + } + } + context2D.globalAlpha = 1.0; + context2D.lineWidth = 1; + } + + static setNetworkFrame(node: any, padding: number, startNS: number, endNS: number, totalNS: number, frame: any) { + let startPointX: number, endPointX: number + + if ((node.startNS || 0) < startNS) { + startPointX = 0 + } else { + startPointX = ns2x((node.startNS || 0), startNS, endNS, totalNS, frame); + } + if ((node.startNS || 0) + (node.dur || 0) > endNS) { + endPointX = frame.width; + } else { + endPointX = ns2x((node.startNS || 0) + (node.dur || 0), startNS, endNS, totalNS, frame); + } + let frameWidth: number = endPointX - startPointX <= 1 ? 1 : endPointX - startPointX; + if (!node.frame) { + node.frame = {}; + } + node.frame.x = Math.floor(startPointX); + node.frame.y = frame.y + padding; + node.frame.width = Math.ceil(frameWidth); + node.frame.height = Math.floor(frame.height - padding * 2); + } +} diff --git a/host/ide/src/trace/database/ProcedureWorkerProcess.ts b/host/ide/src/trace/database/ProcedureWorkerProcess.ts index 01669edf0aadec9ff2143c76bf87dce618035b36..f314edfafc419cc816ed7353448a803d09acdf16 100644 --- a/host/ide/src/trace/database/ProcedureWorkerProcess.ts +++ b/host/ide/src/trace/database/ProcedureWorkerProcess.ts @@ -49,12 +49,9 @@ export class ProcessStruct extends BaseStruct { type: string | undefined utid: number | undefined - static draw(ctx: CanvasRenderingContext2D, data: ProcessStruct) { + static draw(ctx: CanvasRenderingContext2D,path:Path2D, data: ProcessStruct,miniHeight:number) { if (data.frame) { - let width = data.frame.width || 0; - ctx.fillStyle = ColorUtils.colorForTid(data.pid || 0) - let miniHeight = Math.round(data.frame.height / CpuStruct.cpuCount) - ctx.fillRect(data.frame.x, data.frame.y + (data.cpu || 0) * miniHeight + padding, data.frame.width, miniHeight - padding * 2) + path.rect(data.frame.x, data.frame.y + (data.cpu || 0) * miniHeight + padding, data.frame.width, miniHeight - padding * 2) } } diff --git a/host/ide/src/trace/database/ProcedureWorkerThread.ts b/host/ide/src/trace/database/ProcedureWorkerThread.ts index a285e7982af4cc05018df8adf1d568b3e25980b9..9b7b1d2d076e146d6268fd9e5e49e1f8c437cb94 100644 --- a/host/ide/src/trace/database/ProcedureWorkerThread.ts +++ b/host/ide/src/trace/database/ProcedureWorkerThread.ts @@ -18,17 +18,26 @@ import {BaseStruct, ns2x, Rect} from "./ProcedureWorkerCommon.js"; export function thread(list: Array, res: Set, startNS: number, endNS: number, totalNS: number, frame: any) { res.clear(); if (list) { - for (let i = 0, len = list.length; i < len; i++) { - let it = list[i]; - if ((it.startTime || 0) + (it.dur || 0) > startNS && (it.startTime || 0) < endNS) { - ThreadStruct.setThreadFrame(list[i], 5, startNS, endNS, totalNS, frame) - if (i > 0 && ((list[i - 1].frame?.x || 0) == (list[i].frame?.x || 0) && (list[i - 1].frame?.width || 0) == (list[i].frame?.width || 0))) { - + let groups = list.filter(it => (it.startTime || 0) + (it.dur || 0) > startNS && (it.startTime || 0) < endNS).map(it => { + ThreadStruct.setThreadFrame(it, 5, startNS, endNS, totalNS, frame) + return it; + }).reduce((pre, current, index, arr) => { + (pre[`${current.frame.x}`] = pre[`${current.frame.x}`] || []).push(current); + return pre; + }, {}); + Reflect.ownKeys(groups).map((kv => { + let arr = (groups[kv].sort((a: any, b: any) => b.frame.width - a.frame.width)); + if (arr.length > 1) { + let idx = arr.findIndex((it: any) => it.state != "S") + if (idx != -1) { + res.add(arr[idx]); } else { - res.add(list[i]) + res.add(arr[0]); } + } else { + res.add(arr[0]); } - } + })); } } @@ -125,7 +134,7 @@ export class ThreadStruct extends BaseStruct { ctx.fillRect(data.frame.x, data.frame.y + padding, data.frame.width, data.frame.height - padding * 2) ctx.fillStyle = "#fff"; data.frame.width > 4 && ThreadStruct.drawString(ctx, ThreadStruct.getEndState(data.state || ''), 2, data.frame); - } else if("T" == data.state || "t" == data.state) { + } else if ("T" == data.state || "t" == data.state) { ctx.fillStyle = ThreadStruct.traceColor; ctx.fillRect(data.frame.x, data.frame.y + padding, data.frame.width, data.frame.height - padding * 2) ctx.fillStyle = "#fff"; diff --git a/host/ide/src/trace/database/SqlLite.ts b/host/ide/src/trace/database/SqlLite.ts index 3e49266ed2312ad5ec66644a424bc3683a278de2..2f722ccdd34fef13ccc3d2bb2176be96311afe48 100644 --- a/host/ide/src/trace/database/SqlLite.ts +++ b/host/ide/src/trace/database/SqlLite.ts @@ -25,16 +25,31 @@ import {WakeupBean} from "../bean/WakeupBean.js"; import {BinderArgBean} from "../bean/BinderArgBean.js"; import {FpsStruct} from "../bean/FpsStruct.js"; import {HeapBean} from "../bean/HeapBean.js"; -import {SPT, SPTChild, StateProcessThread} from "../bean/StateProcessThread.js"; +import {SPT, SPTChild, SptSlice, StateProcessThread, ThreadProcess, ThreadState} from "../bean/StateProcessThread.js"; import {CpuUsage, Freq} from "../bean/CpuUsage.js"; import {HeapStruct} from "../bean/HeapStruct.js"; import {HeapTreeDataBean} from "../bean/HeapTreeDataBean.js"; import { - NativeEventHeap, NativeHookMalloc, + NativeEventHeap, + NativeHookMalloc, NativeHookProcess, NativeHookSampleQueryInfo, NativeHookStatistics } from "../bean/NativeHook.js"; +import { + LiveProcess, + ProcessHistory, + SystemCpuSummary, + SystemDiskIOSummary, + SystemNetworkSummary +} from "../bean/AbilityMonitor.js"; +import {NetworkAbilityMonitorStruct} from "../bean/NetworkAbilityMonitorStruct.js"; +import {DiskAbilityMonitorStruct} from "../bean/DiskAbilityMonitorStruct.js"; +import {MemoryAbilityMonitorStruct} from "../bean/MemoryAbilityMonitorStruct.js"; +import {CpuAbilityMonitorStruct} from "../bean/CpuAbilityMonitorStruct.js"; +import {PerfCallChain, PerfCmdLine, PerfFile, PerfSample, PerfThread} from "../bean/PerfProfile.js"; +import {SearchFuncBean} from "../bean/SearchFuncBean.js"; +import {info} from "../../log/Log.js"; class DbThread extends Worker { busy: boolean = false; @@ -45,20 +60,22 @@ class DbThread extends Worker { uuid(): string { // @ts-ignore - return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c => (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)); + return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11) + .replace(/[018]/g, (c: any) => (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)); } - queryFunc(name: string, sql: string, args: any, handler: Function) { + queryFunc(name: string, sql: string, args: any, handler: Function, action: string | null) { this.busy = true; let id = this.uuid(); this.taskMap[id] = handler - this.postMessage({ + let msg = { id: id, name: name, - action: "exec", + action: action || "exec", sql: sql, params: args, - }) + } + this.postMessage(msg); } dbOpen = async (): Promise<{ status: boolean, msg: string }> => { @@ -186,497 +203,1094 @@ export class DbPool { this.works.length = 0; } - submit(name: string, sql: string, args: any, handler: Function) { + submit(name: string, sql: string, args: any, handler: Function, action: string | null) { let noBusyThreads = this.works.filter(it => !it.busy); let thread: DbThread if (noBusyThreads.length > 0) { //取第一个空闲的线程进行任务 thread = noBusyThreads[0]; - thread.queryFunc(name, sql, args, handler) + thread.queryFunc(name, sql, args, handler, action) } else { // 随机插入一个线程中 thread = this.works[Math.floor(Math.random() * this.works.length)] - thread.queryFunc(name, sql, args, handler) + thread.queryFunc(name, sql, args, handler, action) } } } export const threadPool = new DbPool() -function query(name: string, sql: string, args: any = null): Promise> { +export function query(name: string, sql: string, args: any = null, action: string | null = null): Promise> { + let a = new Date().getTime(); return new Promise>((resolve, reject) => { threadPool.submit(name, sql, args, (res: any) => { + info("查询耗时", name, new Date().getTime() - a) resolve(res) - }) + }, action); }) } export const querySql = (sql: string): Promise> => query("queryProcess", sql) -/*-------------------------------------------------------------------------------------*/ + export const queryProcess = (): Promise> => - query("queryProcess", `SELECT pid,processName FROM temp_query_process`) -/*-------------------------------------------------------------------------------------*/ + query("queryProcess", ` + SELECT + pid, processName + FROM + temp_query_process`) + export const queryTotalTime = (): Promise> => - query("queryTotalTime", `select end_ts-start_ts as total from trace_section;`) -/*-------------------------------------------------------------------------------------*/ + query("queryTotalTime", ` + select + end_ts-start_ts as total + from + trace_section;`) + export const queryCpu = async (): Promise> => - query("queryCpu", `select cpu from cpu_measure_filter where name='cpu_idle' order by cpu;`) -/*-------------------------------------------------------------------------------------*/ + query("queryCpu", ` + select + cpu + from + cpu_measure_filter + where + name='cpu_idle' + order by cpu;`) + export const getAsyncEvents = (): Promise> => - query("getAsyncEvents", `select *,p.pid as pid,c.ts - t.start_ts as "startTime" from callstack c,trace_section t -left join process p on c.callid = p.id where cookie is not null;`) + query("getAsyncEvents", ` + select + *, + p.pid as pid, + c.ts - t.start_ts as "startTime" + from + callstack c,trace_section t + left join + process p + on + c.callid = p.id + where + cookie is not null;`) export const getCpuUtilizationRate = (startNS: number, endNS: number): Promise> => - query("getCpuUtilizationRate", `select * from temp_get_cpu_rate;`, {}) -/*-------------------------------------------------------------------------------------*/ + query("getCpuUtilizationRate", ` + select + * + from + temp_get_cpu_rate;`, {}) + export const getFps = () => - query("getFps", `select distinct(ts-tb.start_ts) as startNS,fps -from hidump c ,trace_section tb -where startNS >= 0 -order by startNS;`, {}) + query("getFps", ` + select + distinct(ts-tb.start_ts) as startNS, fps + from + hidump c ,trace_section tb + where + startNS >= 0 + order by + startNS;`, {}) -/*-------------------------------------------------------------------------------------*/ export const getFunDataByTid = (tid: number): Promise> => - query("getFunDataByTid", `select * from temp_query_thread_function where tid = $tid`, {$tid: tid}) -/*-------------------------------------------------------------------------------------*/ + query("getFunDataByTid", ` + select + * + from + temp_query_thread_function + where + tid = $tid`, {$tid: tid}) + + +export const getThreadStateDataCount = (): Promise> => + query("getThreadStateDataCount", ` + select count(1) as count from thread_state,trace_range where dur > 0 and (ts - start_ts) >= 0; +`, {}); + +export const getThreadStateData = (limit: number, offset: number): Promise> => + query("getThreadStateData", ` + select itid, + state, + dur, + ts, + (ts - start_ts + dur) as end_ts, + (ts - start_ts) as start_ts, + cpu +from thread_state,trace_range where dur > 0 and (ts - start_ts) >= 0 +limit $limit +offset $offset; +`, {$limit: limit, $offset: offset}); + +export const getThreadProcessData = (): Promise> => + query("getThreadProcessData", ` + select A.id, + A.tid as threadId, + A.name as thread, + IP.pid as processId, + IP.name as process +from thread as A left join process as IP on A.ipid = IP.id +where IP.pid not null; +`, {}); + +export const getSliceDataCount = (): Promise> => + query("getSliceDataCount", ` + select count(1) as count from sched_slice; +`, {}); + +export const getSliceData = (limit: number, offset: number): Promise> => + query("getSliceData", ` + select itid,ts,priority + from sched_slice +limit $limit +offset $offset; +`, {$limit: limit, $offset: offset}); + export const getStatesProcessThreadDataCount = (): Promise> => - query("getStatesProcessThreadData", `select count(1) as count from (select IP.name as process, - IP.pid as processId, - A.name as thread, - B.state as state, - A.tid as threadId, - B.dur, - (B.ts - TR.start_ts + B.dur) as end_ts, - (B.ts - TR.start_ts) as start_ts, - B.cpu, - C.priority, - '-' as note -from thread_state as B - left join thread as A on B.itid = A.id - left join process as IP on A.ipid = IP.id - left join trace_section as TR - left join sched_slice as C on B.itid = C.itid and C.ts = B.ts -where - B.dur > 0 and IP.pid not null and (B.ts - TR.start_ts) >= 0); + query("getStatesProcessThreadData", ` + select + count(1) as count + from + (select + IP.name as process, + IP.pid as processId, + A.name as thread, + B.state as state, + A.tid as threadId, + B.dur, + (B.ts - TR.start_ts + B.dur) as end_ts, + (B.ts - TR.start_ts) as start_ts, + B.cpu, + C.priority, + '-' as note + from + thread_state as B + left join + thread as A + on + B.itid = A.id + left join + process as IP + on + A.ipid = IP.id + left join + trace_section as TR + left join + sched_slice as C + on + B.itid = C.itid + and + C.ts = B.ts + where + B.dur > 0 + and + IP.pid not null + and + (B.ts - TR.start_ts) >= 0); `, {}); -export const getStatesProcessThreadData = (limit:number,offset:number): Promise> => - query("getStatesProcessThreadData", `select IP.name as process, - IP.pid as processId, - A.name as thread, - B.state as state, - A.tid as threadId, - B.dur, - (B.ts - TR.start_ts + B.dur) as end_ts, - (B.ts - TR.start_ts) as start_ts, - B.cpu, - C.priority, - '-' as note -from thread_state as B - left join thread as A on B.itid = A.id - left join process as IP on A.ipid = IP.id - left join trace_section as TR - left join sched_slice as C on B.itid = C.itid and C.ts = B.ts -where - B.dur > 0 and IP.pid not null and (B.ts - TR.start_ts) >= 0 limit $limit offset $offset; +export const getStatesProcessThreadData = (limit: number, offset: number): Promise> => + query("getStatesProcessThreadData", ` + select + IP.name as process, + IP.pid as processId, + A.name as thread, + B.state as state, + A.tid as threadId, + B.dur, + (B.ts - TR.start_ts + B.dur) as end_ts, + (B.ts - TR.start_ts) as start_ts, + B.cpu, + C.priority, + '-' as note + from + thread_state as B + left join + thread as A + on + B.itid = A.id + left join + process as IP + on + A.ipid = IP.id + left join + trace_section as TR + left join + sched_slice as C + on + B.itid = C.itid + and + C.ts = B.ts + where + B.dur > 0 + and + IP.pid not null + and (B.ts - TR.start_ts) >= 0 + limit $limit + offset $offset; `, {$limit: limit, $offset: offset}); export const getTabStatesGroupByProcessThread = (leftNs: number, rightNs: number): Promise> => - query("getTabStatesGroupByProcessThread", `select process, - processId, - thread, - threadId, - sum(dur) as wallDuration, - round(avg(dur),2) as avgDuration, - min(dur) as minDuration, - max(dur) as maxDuration, - count(threadId) as count -from temp_get_process_thread_state_data -where not (end_ts < $leftNS or start_ts > $rightNS) -group by process, processId,thread,threadId`, {$leftNS: leftNs, $rightNS: rightNs}); + query("getTabStatesGroupByProcessThread", ` + select + process, + processId, + thread, + threadId, + sum(dur) as wallDuration, + round(avg(dur),2) as avgDuration, + min(dur) as minDuration, + max(dur) as maxDuration, + count(threadId) as count + from + temp_get_process_thread_state_data + where + not (end_ts < $leftNS or start_ts > $rightNS) + group by + process, + processId, + thread, + threadId`, {$leftNS: leftNs, $rightNS: rightNs}); export const getTabStatesGroupByProcess = (leftNs: number, rightNs: number): Promise> => - query("getTabStatesGroupByProcess", `select process, processId, - sum(dur) as wallDuration, - round(avg(dur),2) as avgDuration, - min(dur) as minDuration, - max(dur) as maxDuration, - count(processId) as count -from temp_get_process_thread_state_data -where not (end_ts < $leftNS or start_ts > $rightNS) -group by process,processId`, {$leftNS: leftNs, $rightNS: rightNs}); - -// todo wasm模式报错 + query("getTabStatesGroupByProcess", ` + select + process, + processId, + sum(dur) as wallDuration, + round(avg(dur),2) as avgDuration, + min(dur) as minDuration, + max(dur) as maxDuration, + count(processId) as count + from + temp_get_process_thread_state_data + where + not (end_ts < $leftNS or start_ts > $rightNS) + group by + process,processId`, {$leftNS: leftNs, $rightNS: rightNs}); + export const getTabStatesGroupByState = (leftNs: number, rightNs: number): Promise> => - query("getTabStatesGroupByState", `select state, - sum(dur) as wallDuration, - round(avg(dur),2) as avgDuration, - min(dur) as minDuration, - max(dur) as maxDuration, - count(state) as count -from temp_get_process_thread_state_data -where not (end_ts < $leftNS or start_ts > $rightNS) -group by state`, {$leftNS: leftNs, $rightNS: rightNs}); + query("getTabStatesGroupByState", ` + select + state, + sum(dur) as wallDuration, + round(avg(dur),2) as avgDuration, + min(dur) as minDuration, + max(dur) as maxDuration, + count(state) as count + from + temp_get_process_thread_state_data + where + not (end_ts < $leftNS or start_ts > $rightNS) + group by + state`, {$leftNS: leftNs, $rightNS: rightNs}); export const getTabStatesGroupByStatePid = (leftNs: number, rightNs: number): Promise> => - query("getTabStatesGroupByStatePid", `select process, - processId, - state, - sum(dur) as wallDuration, - round(avg(dur),2) as avgDuration, - min(dur) as minDuration, - max(dur) as maxDuration, - count(processId) as count -from temp_get_process_thread_state_data -where not (end_ts < $leftNS or start_ts > $rightNS) -group by process,processId,state`, {$leftNS: leftNs, $rightNS: rightNs}); + query("getTabStatesGroupByStatePid", ` + select + process, + processId, + state, + sum(dur) as wallDuration, + round(avg(dur),2) as avgDuration, + min(dur) as minDuration, + max(dur) as maxDuration, + count(processId) as count + from + temp_get_process_thread_state_data + where + not (end_ts < $leftNS or start_ts > $rightNS) + group by + process, + processId, + state`, {$leftNS: leftNs, $rightNS: rightNs}); export const getTabStatesGroupByStatePidTid = (leftNs: number, rightNs: number): Promise> => - query("getTabStatesGroupByStatePidTid", `select process, - processId, - thread, - state, - threadId, - sum(dur) as wallDuration, - round(avg(dur),2) as avgDuration, - min(dur) as minDuration, - max(dur) as maxDuration, - count(threadId) as count -from temp_get_process_thread_state_data -where not (end_ts < $leftNS or start_ts > $rightNS) -group by process, processId, thread, threadId,state`, {$leftNS: leftNs, $rightNS: rightNs}); - -export const getTabBoxChildData = (leftNs: number, rightNs: number, state: string | undefined, processId: number | undefined, threadId: number | undefined): Promise> => - query("getTabBoxChildData", `select IP.name as process, - IP.pid as processId, - A.name as thread, - B.state as state, - A.tid as threadId, - B.dur as duration, - B.ts - TR.start_ts as startNs, - B.cpu, - C.priority, - '-' as note -from thread_state AS B - left join thread as A on B.itid = A.id - left join process AS IP on A.ipid = IP.id - left join trace_section AS TR - left join sched_slice as C on B.itid = C.itid and C.ts = B.ts -where - B.dur > 0 and IP.pid not null - and not ((B.ts - TR.start_ts + B.dur < $leftNS) or (B.ts - TR.start_ts > $rightNS)) - ${state != undefined && state != '' ? 'and B.state = $state' : ''} - ${processId != undefined && processId != -1 ? 'and IP.pid = $processID' : ''} - ${threadId != undefined && threadId != -1 ? 'and A.tid = $threadID' : ''} + query("getTabStatesGroupByStatePidTid", ` + select + process, + processId, + thread, + state, + threadId, + sum(dur) as wallDuration, + round(avg(dur),2) as avgDuration, + min(dur) as minDuration, + max(dur) as maxDuration, + count(threadId) as count + from + temp_get_process_thread_state_data + where + not (end_ts < $leftNS or start_ts > $rightNS) + group by + process, + processId, + thread, + threadId, + state`, {$leftNS: leftNs, $rightNS: rightNs}); + +export const getTabBoxChildData = (leftNs: number, rightNs: number, state: string | undefined, + processId: number | undefined, threadId: number | undefined): Promise> => + query("getTabBoxChildData", ` + select + IP.name as process, + IP.pid as processId, + A.name as thread, + B.state as state, + A.tid as threadId, + B.dur as duration, + B.ts - TR.start_ts as startNs, + B.cpu, + C.priority, + '-' as note + from + thread_state AS B + left join + thread as A + on + B.itid = A.id + left join + process AS IP + on + A.ipid = IP.id + left join + trace_section AS TR + left join + sched_slice as C + on + B.itid = C.itid + and + C.ts = B.ts + where + B.dur > 0 + and + IP.pid not null + and + not ((B.ts - TR.start_ts + B.dur < $leftNS) or (B.ts - TR.start_ts > $rightNS)) + ${state != undefined && state != '' ? 'and B.state = $state' : ''} + ${processId != undefined && processId != -1 ? 'and IP.pid = $processID' : ''} + ${threadId != undefined && threadId != -1 ? 'and A.tid = $threadID' : ''} `, {$leftNS: leftNs, $rightNS: rightNs, $state: state, $processID: processId, $threadID: threadId}) -/*-------------------------------------------------------------------------------------*/ export const getTabCpuUsage = (cpus: Array, leftNs: number, rightNs: number): Promise> => - query("getTabCpuUsage", `select cpu, - sum(case - when (A.ts - B.start_ts) < $leftNS then (A.ts - B.start_ts + A.dur - $leftNS) - when (A.ts - B.start_ts) >= $leftNS and (A.ts - B.start_ts + A.dur) <= $rightNS then A.dur - when (A.ts - B.start_ts + A.dur) > $rightNS then ($rightNS - (A.ts - B.start_ts)) end) / cast($rightNS - $leftNS as float) as usage -from thread_state A ,trace_section B -where (A.ts - B.start_ts) > 0 and A.dur > 0 - and cpu in (${cpus.join(",")}) - and (A.ts - B.start_ts + A.dur) > $leftNS and (A.ts - B.start_ts) < $rightNS -group by cpu`, {$leftNS: leftNs, $rightNS: rightNs}) + query("getTabCpuUsage", ` + select + cpu, + sum(case + when (A.ts - B.start_ts) < $leftNS + then (A.ts - B.start_ts + A.dur - $leftNS) + when (A.ts - B.start_ts) >= $leftNS + and (A.ts - B.start_ts + A.dur) <= $rightNS + then A.dur + when (A.ts - B.start_ts + A.dur) > $rightNS + then ($rightNS - (A.ts - B.start_ts)) end) / cast($rightNS - $leftNS as float) as usage + from + thread_state A, + trace_section B + where + (A.ts - B.start_ts) > 0 and A.dur > 0 + and + cpu in (${cpus.join(",")}) + and + (A.ts - B.start_ts + A.dur) > $leftNS + and + (A.ts - B.start_ts) < $rightNS + group by + cpu`, {$leftNS: leftNs, $rightNS: rightNs}) export const getTabCpuFreq = (cpus: Array, leftNs: number, rightNs: number): Promise> => - query("getTabCpuFreq", `select cpu,value,(ts - tb.start_ts) as startNs -from measure c ,trace_section tb -inner join cpu_measure_filter t on c.filter_id = t.id -where (name = 'cpufreq' or name='cpu_frequency') - and cpu in (${cpus.join(",")}) - and startNs > 0 - and startNs < $rightNS - order by startNs`, {$leftNS: leftNs, $rightNS: rightNs}) -/*-------------------------------------------------------------------------------------*/ + query("getTabCpuFreq", ` + select + cpu, + value, + (ts - tb.start_ts) as startNs + from + measure c, + trace_section tb + inner join + cpu_measure_filter t + on + c.filter_id = t.id + where + (name = 'cpufreq' or name='cpu_frequency') + and + cpu in (${cpus.join(",")}) + and + startNs > 0 + and + startNs < $rightNS + order by + startNs`, {$leftNS: leftNs, $rightNS: rightNs}) + export const getTabFps = (leftNs: number, rightNs: number): Promise> => - query("getTabFps", `select distinct(ts-tb.start_ts) as startNS,fps -from hidump c ,trace_section tb -where startNS <= $rightNS and startNS >= 0 -order by startNS;`, {$leftNS: leftNs, $rightNS: rightNs}) -/*-------------------------------------------------------------------------------------*/ + query("getTabFps", ` + select + distinct(ts-tb.start_ts) as startNS, + fps + from + hidump c, + trace_section tb + where + startNS <= $rightNS + and + startNS >= 0 + order by + startNS;`, {$leftNS: leftNs, $rightNS: rightNs}) + export const getTabCounters = (filterIds: Array, startTime: number) => - query("getTabCounters", `select t1.filter_id as trackId,t2.name,value, t1.ts - t3.start_ts as startTime -from measure t1 -left join process_measure_filter t2 on t1.filter_id = t2.id -left join trace_section t3 where filter_id in (${filterIds.join(",")}) -and startTime <= $startTime -order by startTime asc;`, {$startTime: startTime}) -/*-------------------------------------------------------------------------------------*/ + query("getTabCounters", ` + select + t1.filter_id as trackId, + t2.name, + value, + t1.ts - t3.start_ts as startTime + from + measure t1 + left join + process_measure_filter t2 + on + t1.filter_id = t2.id + left join + trace_section t3 + where + filter_id in (${filterIds.join(",")}) + and + startTime <= $startTime + order by + startTime asc;`, {$startTime: startTime}) + export const getTabCpuByProcess = (cpus: Array, leftNS: number, rightNS: number) => - query("getTabCpuByProcess", `select IP.name as process, - IP.pid as pid, - sum(B.dur) as wallDuration, - avg(B.dur) as avgDuration, - count(A.tid) as occurrences -from thread_state AS B - left join thread as A on B.itid = A.id - left join trace_section AS TR - left join process AS IP on A.ipid = IP.id -where B.cpu in (${cpus.join(",")}) - and not ((B.ts - TR.start_ts + B.dur < $leftNS) or (B.ts - TR.start_ts > $rightNS )) -group by IP.name, IP.pid -order by wallDuration desc;`, {$rightNS: rightNS, $leftNS: leftNS}) -/*-------------------------------------------------------------------------------------*/ + query("getTabCpuByProcess", ` + select + IP.name as process, + IP.pid as pid, + sum(B.dur) as wallDuration, + avg(B.dur) as avgDuration, + count(A.tid) as occurrences + from + thread_state AS B + left join + thread as A + on + B.itid = A.id + left join + trace_section AS TR + left join + process AS IP + on + A.ipid = IP.id + where + B.cpu in (${cpus.join(",")}) + and + not ((B.ts - TR.start_ts + B.dur < $leftNS) or (B.ts - TR.start_ts > $rightNS )) + group by + IP.name, + IP.pid + order by + wallDuration desc;`, {$rightNS: rightNS, $leftNS: leftNS}) + export const getTabCpuByThread = (cpus: Array, leftNS: number, rightNS: number) => - query("getTabCpuByThread", `select IP.name as process, - IP.pid as pid, - A.name as thread, - A.tid as tid, - sum(B.dur) as wallDuration, - avg(B.dur) as avgDuration, - count(A.tid) as occurrences -from thread_state AS B - left join thread as A on B.itid = A.id - left join trace_section AS TR - left join process AS IP on A.ipid = IP.id -where B.cpu in (${cpus.join(",")}) - and not ((B.ts - TR.start_ts + B.dur < $leftNS) or (B.ts - TR.start_ts > $rightNS)) -group by IP.name, IP.pid, A.name, A.tid -order by wallDuration desc;`, {$rightNS: rightNS, $leftNS: leftNS}) -/*-------------------------------------------------------------------------------------*/ + query("getTabCpuByThread", ` + select + IP.name as process, + IP.pid as pid, + A.name as thread, + A.tid as tid, + sum(B.dur) as wallDuration, + avg(B.dur) as avgDuration, + count(A.tid) as occurrences + from + thread_state AS B + left join + thread as A + on + B.itid = A.id + left join + trace_section AS TR + left join + process AS IP + on + A.ipid = IP.id + where + B.cpu in (${cpus.join(",")}) + and + not ((B.ts - TR.start_ts + B.dur < $leftNS) or (B.ts - TR.start_ts > $rightNS)) + group by + IP.name, + IP.pid, + A.name, + A.tid + order by + wallDuration desc;`, {$rightNS: rightNS, $leftNS: leftNS}) + export const getTabSlices = (funTids: Array, leftNS: number, rightNS: number): Promise> => - query("getTabSlices", `select + query("getTabSlices", ` + select c.name as name, sum(c.dur) as wallDuration, avg(c.dur) as avgDuration, count(c.name) as occurrences -from thread A,trace_section D -left join callstack C on A.id = C.callid -where C.ts not null - and c.dur >= 0 - and A.tid in (${funTids.join(",")}) - and c.name not like 'binder%' - and not ((C.ts - D.start_ts + C.dur < $leftNS) or (C.ts - D.start_ts > $rightNS)) -group by c.name -order by wallDuration desc;`, {$leftNS: leftNS, $rightNS: rightNS}) -/*-------------------------------------------------------------------------------------*/ + from + thread A, trace_section D + left join + callstack C + on + A.id = C.callid + where + C.ts not null + and + c.dur >= 0 + and + A.tid in (${funTids.join(",")}) + and + c.name not like 'binder%' + and + not ((C.ts - D.start_ts + C.dur < $leftNS) or (C.ts - D.start_ts > $rightNS)) + group by + c.name + order by + wallDuration desc;`, {$leftNS: leftNS, $rightNS: rightNS}) + export const getTabThreadStates = (tIds: Array, leftNS: number, rightNS: number): Promise> => - query("getTabThreadStates", `select - IP.name as process, - IP.pid, - A.name as thread, - A.tid, - B.state, - sum(B.dur) as wallDuration, - avg(ifnull(B.dur,0)) as avgDuration, - count(A.tid) as occurrences -from thread_state AS B -left join thread as A on A.id = B.itid -left join trace_section AS TR -left join process AS IP on IP.id=ipid -where A.tid in (${tIds.join(",")}) -and not ((B.ts - TR.start_ts + ifnull(B.dur,0) < $leftNS) or (B.ts - TR.start_ts > $rightNS)) -group by IP.name, IP.pid, A.name, A.tid, B.state -order by wallDuration desc;`, {$leftNS: leftNS, $rightNS: rightNS}) -/*-------------------------------------------------------------------------------------*/ + query("getTabThreadStates", ` + select + IP.name as process, + IP.pid, + A.name as thread, + A.tid, + B.state, + sum(B.dur) as wallDuration, + avg(ifnull(B.dur,0)) as avgDuration, + count(A.tid) as occurrences + from + thread_state AS B + left join + thread as A + on + A.id = B.itid + left join + trace_section AS TR + left join + process AS IP + on + IP.id=ipid + where + A.tid in (${tIds.join(",")}) + and + not ((B.ts - TR.start_ts + ifnull(B.dur,0) < $leftNS) or (B.ts - TR.start_ts > $rightNS)) + group by + IP.name, IP.pid, A.name, A.tid, B.state + order by + wallDuration desc;`, {$leftNS: leftNS, $rightNS: rightNS}) + export const getThreadFuncData = (tId: number): Promise> => - query("getThreadFuncData", `select tid, - A.start_ts, - A.end_ts, - A.name as threadName, - is_main_thread, - c.callid as track_id, - c.ts-D.start_ts as startTs, - c.ts + c.dur as endTs, - c.dur, - c.name as funName, - c.depth, - c.parent_id, - c.id -from thread A,trace_section D -left join callstack C on A.id = C.callid -where startTs not null and A.tid = $tid;`, {$tid: tId}) -/*-------------------------------------------------------------------------------------*/ + query("getThreadFuncData", ` + select + tid, + A.start_ts, + A.end_ts, + A.name as threadName, + is_main_thread, + c.callid as track_id, + c.ts-D.start_ts as startTs, + c.ts + c.dur as endTs, + c.dur, + c.name as funName, + c.depth, + c.parent_id, + c.id + from + thread A, + trace_section D + left join + callstack C + on + A.id = C.callid + where + startTs not null + and + A.tid = $tid;`, {$tid: tId}) + export const queryBinderArgsByArgset = (argset: number): Promise> => - query("queryBinderArgsByArgset", `select * from args_view where argset = $argset;`, {$argset: argset}) -/*-------------------------------------------------------------------------------------*/ + query("queryBinderArgsByArgset", ` + select + * + from + args_view + where + argset = $argset;`, {$argset: argset}) + export const queryClockFrequency = (): Promise> => - query("queryClockFrequency", `with freq as ( select measure.filter_id, measure.ts, measure.type, measure.value from clock_event_filter -left join measure -where clock_event_filter.name = '%s' and clock_event_filter.type = 'clock_set_rate' and clock_event_filter.id = measure.filter_id -order by measure.ts) -select freq.filter_id,freq.ts - r.start_ts as ts,freq.type,freq.value from freq,trace_section r;`, {}) -/*-------------------------------------------------------------------------------------*/ + query("queryClockFrequency", ` + with freq as ( + select + measure.filter_id, + measure.ts, + measure.type, + measure.value + from + clock_event_filter + left join + measure + where + clock_event_filter.name = '%s' + and + clock_event_filter.type = 'clock_set_rate' + and + clock_event_filter.id = measure.filter_id + order by + measure.ts) + select + freq.filter_id, + freq.ts - r.start_ts as ts, + freq.type, + freq.value + from + freq, + trace_section r;`, {}) + export const queryClockList = (): Promise> => - query("queryClockList", `with list as ( - select distinct name from clock_event_filter - where clock_event_filter.type = 'clock_set_rate' order by name -),freq as( - select measure.filter_id, measure.ts, measure.type, measure.value , clock_event_filter.name from clock_event_filter - left join measure - where clock_event_filter.type = 'clock_set_rate' and clock_event_filter.id = measure.filter_id - order by measure.ts -),state as ( - select filter_id, ts, endts, endts-ts as dur, type, value,name from - (select measure.filter_id, measure.ts, lead(ts, 1, null) over( order by measure.ts) endts, measure.type, measure.value,clock_event_filter.name from clock_event_filter,trace_section - left join measure - where clock_event_filter.type != 'clock_set_rate' and clock_event_filter.id = measure.filter_id - order by measure.ts) -),count_freq as ( - select COUNT(*) num,name srcname from freq group by name -),count_state as ( - select COUNT(*) num,name srcname from state group by name -) -select count_freq.srcname||' Frequency' as name,* from count_freq union select count_state.srcname||' State' as name,* from count_state order by name;`) -/*-------------------------------------------------------------------------------------*/ + query("queryClockList", ` + with list as ( + select + distinct name + from + clock_event_filter + where + clock_event_filter.type = 'clock_set_rate' + order by + name), + freq as( + select + measure.filter_id, + measure.ts, + measure.type, + measure.value, + clock_event_filter.name + from + clock_event_filter + left join + measure + where + clock_event_filter.type = 'clock_set_rate' + and + clock_event_filter.id = measure.filter_id + order by + measure.ts + ),state as ( + select + filter_id, + ts, + endts, + endts-ts as dur, + type, + value, + name + from + (select + measure.filter_id, + measure.ts, + lead(ts, 1, null) over( order by measure.ts) endts, + measure.type, + measure.value, + clock_event_filter.name + from + clock_event_filter, + trace_section + left join + measure + where + clock_event_filter.type != 'clock_set_rate' + and + clock_event_filter.id = measure.filter_id + order by + measure.ts) + ),count_freq as ( + select + COUNT(*) num, + name srcname + from + freq + group by + name + ),count_state as ( + select + COUNT(*) num, + name srcname + from + state + group by + name + ) + select + count_freq.srcname||' Frequency' as name, + * + from + count_freq union select count_state.srcname||' State' as name,* from count_state order by name;`) + export const queryClockState = (): Promise> => - query("queryClockState", `with state as ( -select filter_id, ts, endts, endts-ts as dur, type, value from -(select measure.filter_id, measure.ts, lead(ts, 1, null) over( order by measure.ts) endts, measure.type, measure.value from clock_event_filter,trace_section -left join measure -where clock_event_filter.name = '%s' and clock_event_filter.type != 'clock_set_rate' and clock_event_filter.id = measure.filter_id -order by measure.ts)) + query("queryClockState", ` + with state as ( + select + filter_id, + ts, + endts, + endts-ts as dur, + type, + value + from + (select + measure.filter_id, + measure.ts, + lead(ts, 1, null) over( order by measure.ts) endts, + measure.type, + measure.value + from + clock_event_filter, + trace_section + left join + measure + where + clock_event_filter.name = '%s' + and + clock_event_filter.type != 'clock_set_rate' + and + clock_event_filter.id = measure.filter_id + order by + measure.ts)) -- select * from state; select s.filter_id,s.ts-r.start_ts as ts,s.type,s.value,s.dur from state s,trace_section r;`) -/*-------------------------------------------------------------------------------------*/ + export const queryCpuData = (cpu: number, startNS: number, endNS: number): Promise> => - query("queryCpuData", `select * from temp_query_cpu_data where cpu = $cpu and startTime between $startNS and $endNS;`, { + query("queryCpuData", ` + select + * + from + temp_query_cpu_data + where + cpu = $cpu + and + startTime between $startNS and $endNS;`, { $cpu: cpu, $startNS: startNS, $endNS: endNS }) -/*-------------------------------------------------------------------------------------*/ + export const queryCpuFreq = (): Promise> => -query("queryCpuFreq", `select cpu from cpu_measure_filter where (name='cpufreq' or name='cpu_frequency') order by cpu;`) -/*-------------------------------------------------------------------------------------*/ + query("queryCpuFreq", ` + select + cpu + from + cpu_measure_filter + where + (name='cpufreq' or name='cpu_frequency') + order by cpu;`) + export const queryCpuFreqData = (cpu: number): Promise> => - query("queryCpuFreqData", `select cpu,value,ts-tb.start_ts as startNS -from measure c ,trace_section tb -inner join cpu_measure_filter t on c.filter_id = t.id -where (name = 'cpufreq' or name='cpu_frequency') and cpu= $cpu -order by ts;`, {$cpu: cpu}); -/*-------------------------------------------------------------------------------------*/ + query("queryCpuFreqData", ` + select + cpu, + value, + ts-tb.start_ts as startNS + from + measure c, + trace_section tb + inner join + cpu_measure_filter t + on + c.filter_id = t.id + where + (name = 'cpufreq' or name='cpu_frequency') + and + cpu= $cpu + order by + ts;`, {$cpu: cpu}); + export const queryCpuMax = (): Promise> => - query("queryCpuMax", `select cpu from sched_slice order by cpu desc limit 1;`) -/*-------------------------------------------------------------------------------------*/ + query("queryCpuMax", ` + select + cpu + from + sched_slice + order by + cpu + desc limit 1;`) + export const queryCpuMaxFreq = (): Promise> => -query("queryCpuMaxFreq", `select max(value) as maxFreq -from measure c -inner join cpu_measure_filter t on c.filter_id = t.id -where (name = 'cpufreq' or name='cpu_frequency');`) -// /*-------------------------------------------------------------------------------------*/ + query("queryCpuMaxFreq", ` + select + max(value) as maxFreq + from + measure c + inner join + cpu_measure_filter t + on + c.filter_id = t.id + where + (name = 'cpufreq' or name='cpu_frequency');`) + export const queryLogs = (): Promise> => - query("queryLogs", `select l.*,l.ts-t.start_ts as "startTime" from log as l left join trace_section AS t - where "startTime" between %s and %s order by "startTime" - limit %s offset %s;`) -/*-------------------------------------------------------------------------------------*/ + query("queryLogs", ` + select + l.*, + l.ts-t.start_ts as "startTime" + from + log as l + left join + trace_section AS t + where + "startTime" between %s and %s + order by + "startTime" + limit %s offset %s;`) + export const queryLogsCount = (): Promise> => - query("queryLogsCount", `select l.*,l.ts-t.start_ts as "startTime" from log as l left join trace_section AS t - where "startTime" between %s and %s;`) -/*-------------------------------------------------------------------------------------*/ + query("queryLogsCount", ` + select + l.*, + l.ts-t.start_ts as "startTime" + from + log as l + left join + trace_section AS t + where + "startTime" + between %s and %s;`) + export const queryProcessData = (pid: number, startNS: number, endNS: number): Promise> => - query("queryProcessData", `select * from temp_query_process_data where tid != 0 and pid = $pid and startTime between $startNS and $endNS;`, { + query("queryProcessData", ` + select + * + from + temp_query_process_data + where + tid != 0 + and + pid = $pid + and + startTime between $startNS and $endNS;`, { $pid: pid, $startNS: startNS, $endNS: endNS }) -/*-------------------------------------------------------------------------------------*/ + export const queryProcessDataCount = (): Promise> => - query("queryProcessDataCount", `select ta.id,type, ts, dur, ta.cpu, itid as utid, state - ,ts-tb.start_ts as startTime,tc.tid,tc.pid,tc.process,tc.thread -from thread_state ta,trace_section tb -left join ( - select it.id,tid,pid,ip.name as process,it.name as thread from thread as it left join process ip on it.ipid = ip.id - ) tc on ta.itid = tc.id -where tc.pid = %d - and startTime between %s and %s -and ta.cpu is not null -order by startTime;`) -/*-------------------------------------------------------------------------------------*/ + query("queryProcessDataCount", ` + select + ta.id, + type, + ts, + dur, + ta.cpu, + itid as utid, + state, + ts-tb.start_ts as startTime, + tc.tid, + tc.pid, + tc.process, + tc.thread + from + thread_state ta, + trace_section tb + left join ( + select + it.id, + tid, + pid, + ip.name as process, + it.name as thread + from + thread as it + left join + process ip + on + it.ipid = ip.id + ) tc + on + ta.itid = tc.id + where + tc.pid = %d + and + startTime between %s and %s + and + ta.cpu is not null + order by startTime;`) + export const queryProcessDataLimit = (pid: number, startNS: number, endNS: number, limit: number): Promise> => - query("queryProcessDataLimit", `with list as (select ta.id,type, ts, dur, ta.cpu, itid as utid, state - ,ts-tb.start_ts as startTime,tc.tid,tc.pid,tc.process,tc.thread -from thread_state ta,trace_section tb -left join ( - select it.id,tid,pid,ip.name as process,it.name as thread from thread as it left join process ip on it.ipid = ip.id - ) tc on ta.itid = tc.id -where tc.pid = $pid - and startTime between $startNS and $endNS -and ta.cpu is not null -order by startTime ) + query("queryProcessDataLimit", ` + with list as ( + select + ta.id,type, + ts, dur, + ta.cpu, + itid as utid, + state, + ts-tb.start_ts as startTime, + tc.tid, + tc.pid, + tc.process, + tc.thread + from + thread_state ta, + trace_section tb + left join ( + select + it.id, + tid,pid, + ip.name as process, + it.name as thread + from + thread as it + left join + process ip + on + it.ipid = ip.id + ) tc on ta.itid = tc.id + where + tc.pid = $pid + and + startTime between $startNS and $endNS + and + ta.cpu is not null + order by startTime ) select * from list order by random() limit $limit;`, {$pid: pid, $startNS: startNS, $endNS: endNS, $limit: limit}) -/*-------------------------------------------------------------------------------------*/ + export const queryProcessMem = (): Promise> => - query("queryProcessMem", `select process_measure_filter.id as trackId, - process_measure_filter.name as trackName, - ipid as upid, - process_view.pid, - process_view.name as processName -from process_measure_filter join process_view using (ipid) -order by trackName;`) -/*-------------------------------------------------------------------------------------*/ + query("queryProcessMem", ` + select + process_measure_filter.id as trackId, + process_measure_filter.name as trackName, + ipid as upid, + process_view.pid, + process_view.name as processName + from + process_measure_filter + join + process_view using (ipid) + order by trackName;`) + export const queryProcessMemData = (trackId: number): Promise> => - query("queryProcessMemData", `select c.type, - ts, value, - filter_id as track_id, - c.ts-tb.start_ts startTime -from measure c,trace_section tb where filter_id = $id;`, {$id: trackId}) -/*-------------------------------------------------------------------------------------*/ + query("queryProcessMemData", ` + select + c.type, + ts, + value, + filter_id as track_id, + c.ts-tb.start_ts startTime + from + measure c, + trace_section tb + where + filter_id = $id;`, {$id: trackId}) + export const queryProcessNOrder = (): Promise> => - query("queryProcessNOrder", `select pid,name as processName from process;`) -/*-------------------------------------------------------------------------------------*/ + query("queryProcessNOrder", ` + select + pid, + name as processName + from + process;`) + export const queryProcessThreads = (): Promise> => - query("queryProcessThreads", `select - the_tracks.ipid as upid, - the_tracks.itid as utid, - total_dur as hasSched, - process_view.pid as pid, - thread_view.tid as tid, - process_view.name as processName, - thread_view.name as threadName -from ( - select ipid, itid from sched_view join thread_view using(itid) group by itid -) the_tracks -left join (select ipid, sum(dur) as total_dur - from sched_view join thread_view using(itid) - group by ipid -) using(ipid) -left join thread_view using(itid) -left join process_view using(ipid) -order by - total_dur desc, - the_tracks.ipid, - the_tracks.itid;`, {}) -/*-------------------------------------------------------------------------------------*/ + query("queryProcessThreads", ` + select + the_tracks.ipid as upid, + the_tracks.itid as utid, + total_dur as hasSched, + process_view.pid as pid, + thread_view.tid as tid, + process_view.name as processName, + thread_view.name as threadName + from ( + select + ipid, + itid + from + sched_view + join + thread_view using(itid) + group by + itid + ) the_tracks + left join ( + select + ipid, + sum(dur) as total_dur + from + sched_view join thread_view using(itid) + group by + ipid + ) using(ipid) + left join + thread_view using(itid) + left join + process_view using(ipid) + order by + total_dur desc, + the_tracks.ipid, + the_tracks.itid;`, {}) + export const queryProcessThreadsNOrder = (): Promise> => - query("queryProcessThreadsNOrder", `select p.id as upid, - t.id as utid, - p.pid, - t.tid, - p.name as processName, - t.name as threadName - from thread t left join process p on t.ipid = p.id;`) -/*-------------------------------------------------------------------------------------*/ + query("queryProcessThreadsNOrder", ` + select + p.id as upid, + t.id as utid, + p.pid, + t.tid, + p.name as processName, + t.name as threadName + from + thread t + left join + process p + on + t.ipid = p.id;`) + export const queryScreenState = (): Promise> => - query("queryScreenState", `select m.type, m.ts-r.start_ts as ts, value, filter_id from measure m,trace_section r where filter_id in (select id from process_measure_filter where name = 'ScreenState');`) -/*-------------------------------------------------------------------------------------*/ + query("queryScreenState", ` + select + m.type, + m.ts-r.start_ts as ts, + value, + filter_id + from + measure m, + trace_section r + where + filter_id in ( + select + id + from + process_measure_filter + where + name = 'ScreenState');`) + export const queryThreadData = (tid: number): Promise> => - query("queryThreadData", `select * from temp_query_thread_data where tid = $tid;`, {$tid: tid}) -/*-------------------------------------------------------------------------------------*/ + query("queryThreadData", ` + select + * + from + temp_query_thread_data + where + tid = $tid;`, {$tid: tid}) + export const queryWakeUpThread_Desc = (): Promise> => query("queryWakeUpThread_Desc", `This is the interval from when the task became eligible to run (e.g.because of notifying a wait queue it was a suspended on) to when it started running.`) + /*-------------------------------------------------------------------------------------*/ -export const queryWakeUpThread_WakeThread = (wakets: number): Promise> => - query("queryWakeUpThread_WakeThread", `select TB.tid,TB.name as thread,TA.cpu,TC.pid,TC.name as process +export const queryWakeUpFromThread_WakeThread = (wakets: number): Promise> => + query("queryWakeUpFromThread_WakeThread", `select TB.tid,TB.name as thread,TA.cpu,(TA.ts - TR.start_ts) as ts,TC.pid,TC.name as process from sched_view TA left join thread TB on TA.itid = TB.id left join process TC on TB.ipid = TC.id +left join trace_range TR where itid = (select itid from raw where name = 'sched_waking' and ts = $wakets ) and TA.ts < $wakets and Ta.ts + Ta.dur >= $wakets`, {$wakets: wakets}) /*-------------------------------------------------------------------------------------*/ -export const queryWakeUpThread_WakeTime = (tid: number, startTime: number): Promise> => - query("queryWakeUpThread_WakeTime", `select * from +export const queryWakeUpFromThread_WakeTime = (tid: number, startTime: number): Promise> => + query("queryWakeUpFromThread_WakeTime", `select * from ( select ts as wakeTs,start_ts as startTs from instants_view,trace_section where name = 'sched_waking' and ref = $tid @@ -688,187 +1302,1315 @@ export const queryWakeUpThread_WakeTime = (tid: number, startTime: number): Prom and ts < start_ts + $startTime order by ts desc limit 1) TB`, {$tid: tid, $startTime: startTime}) /*-------------------------------------------------------------------------------------*/ -export const queryThreadsByPid = (pid: number): Promise> => - query("queryThreadsByPid", `select - the_tracks.ipid as upid, - the_tracks.itid as utid, - total_dur as hasSched, - process_view.pid as pid, - thread_view.tid as tid, - process_view.name as processName, - thread_view.name as threadName - from ( - select ipid, itid from sched_view join thread_view using(itid) group by itid - ) the_tracks - left join (select ipid, sum(dur) as total_dur - from sched_view join thread_view using(itid) - group by ipid - ) using(ipid) - left join thread_view using(itid) - left join process_view using(ipid) - where pid = $pid - order by - total_dur desc, - the_tracks.ipid, - the_tracks.itid`, {$pid: pid}) +export const queryThreadWakeUp = (itid: number, startTime: number,dur:number): Promise> => + query("queryThreadWakeUp", ` +select TB.tid,TB.name as thread,min(TA.ts - TR.start_ts) as ts,TC.pid,TC.name as process +from + (select min(ts) as wakeTs,ref as itid from instant,trace_range + where name = 'sched_wakeup' + and wakeup_from = $tid + and ts > start_ts + $startTime + and ts < start_ts + $startTime + $dur + group by ref + ) TW +left join sched_slice TA on TW.itid = TA.itid and TA.ts > TW.wakeTs +left join thread TB on TA.itid = TB.id +left join process TC on TB.ipid = TC.id +left join trace_range TR +where TB.ipid not null +group by TB.tid, TB.name,TC.pid, TC.name; + `, {$tid: itid, $startTime: startTime,$dur:dur}) + +export const queryThreadWakeUpFrom = (itid: number, startTime: number,dur:number): Promise> => + query("queryThreadWakeUpFrom", ` +select TB.tid,TB.name as thread,TA.cpu,(TA.ts - TR.start_ts) as ts,TC.pid,TC.name as process +from + (select ts as wakeTs,wakeup_from as wakeupFromTid from instant,trace_range + where name = 'sched_wakeup' + and ref = $tid + and ts > start_ts + $startTime + and ts < start_ts + $startTime + $dur + order by ts) TW +left join sched_slice TA on TW.wakeupFromTid = TA.itid and TA.ts < TW.wakeTs and TA.ts + TA.dur >= TW.wakeTs +left join thread TB on TA.itid = TB.id +left join process TC on TB.ipid = TC.id +left join trace_range TR +where TB.ipid not null +limit 1; + `, {$tid: itid, $startTime: startTime,$dur:dur}) /*-------------------------------------------------------------------------------------*/ +export const queryThreadsByPid = (pid: number): Promise> => + query("queryThreadsByPid", ` + select + the_tracks.ipid as upid, + the_tracks.itid as utid, + total_dur as hasSched, + process_view.pid as pid, + thread_view.tid as tid, + process_view.name as processName, + thread_view.name as threadName + from ( + select + ipid, + itid + from + sched_view + join + thread_view using(itid) + group by + itid + ) the_tracks + left join ( + select + ipid, + sum(dur) as total_dur + from + sched_view + join + thread_view using(itid) + group by + ipid + ) using(ipid) + left join + thread_view using(itid) + left join + process_view using(ipid) + where + pid = $pid + order by + total_dur desc, + the_tracks.ipid, + the_tracks.itid`, {$pid: pid}) + export const queryHeapByPid = (startTs: number, endTs: number, ipid: number): Promise> => - query("queryHeapByPid", `select a.maxheap maxHeapSize,current_size_dur as dur,h.all_heap_size heapsize,h.start_ts - t.start_ts as startTime,h.end_ts - t.start_ts as endTime -from native_hook h left join trace_section t left join (select max(all_heap_size) maxheap from native_hook) a where ipid = ${ipid} and startTime between ${startTs} and ${endTs}; + query("queryHeapByPid", ` + select + a.maxheap maxHeapSize, + current_size_dur as dur, + h.all_heap_size heapsize, + h.start_ts - t.start_ts as startTime, + h.end_ts - t.start_ts as endTime + from + native_hook h + left join + trace_section t + left join ( + select + max(all_heap_size) maxheap + from + native_hook) a + where + ipid = ${ipid} + and + startTime + between ${startTs} and ${endTs}; `, {$ipid: ipid, $startTs: startTs, $endTs: endTs}) export const queryHeapGroupByEvent = (): Promise> => - query("queryHeapGroupByEvent", `select event_type as eventType,sum(heap_size) as sumHeapSize from native_hook group by event_type`, {}) - -export const queryHeapByEventType = (startTs: number, endTs: number, arg1: string,arg2: string): Promise> => - query("queryHeapByEventType", ` -select a.maxHeap maxHeapSize, - current_size_dur as dur, - h.all_heap_size heapsize, - h.start_ts - t.start_ts as startTime, - h.end_ts - t.start_ts as endTime, - h.event_type as eventType -from native_hook h -left join trace_section t -left join ( -select max(all_heap_size) maxHeap -from native_hook ${arg1}) a -where startTime between ${startTs} and ${endTs} ${arg2} -`, {$startTs: startTs, $endTs: endTs,$arg1:arg1,$arg2:arg2}) -/*-------------------------------------------------------------------------------------*/ + query("queryHeapGroupByEvent", ` + select + event_type as eventType, + sum(heap_size) as sumHeapSize + from + native_hook + group by event_type`, {}) + +export const queryHeapByEventType = + (startTs: number, endTs: number, arg1: string, arg2: string): Promise> => + query("queryHeapByEventType", ` + select + a.maxHeap maxHeapSize, + current_size_dur as dur, + h.all_heap_size heapsize, + h.start_ts - t.start_ts as startTime, + h.end_ts - t.start_ts as endTime, + h.event_type as eventType + from + native_hook h + left join + trace_section t + left join ( + select + max(all_heap_size) maxHeap + from + native_hook ${arg1}) a + where + startTime + between ${startTs} and ${endTs} ${arg2} +`, {$startTs: startTs, $endTs: endTs, $arg1: arg1, $arg2: arg2}) + export const queryHeapPid = (): Promise> => - query("queryHeapPid", `select ipid,pid from native_hook h left join process p on h.ipid = p.id group by ipid,pid`, {}) -/*-------------------------------------------------------------------------------------*/ + query("queryHeapPid", ` + select + ipid, + pid + from + native_hook h + left join + process p + on + h.ipid = p.id + group by ipid,pid`, {}) + export const queryHeapTable = (startTs: number, endTs: number, ipids: Array): Promise> => - query("queryHeapTable", `select *,Allocations - Deallocations Total,AllocationSize - DeAllocationSize RemainingSize from (select f.file_path MoudleName, - sum(case when h.event_type = 'AllocEvent' then 1 else 0 end) Allocations, - sum(case when h.event_type = 'FreeEvent' then 1 else 0 end) Deallocations, - sum(case when h.event_type = 'AllocEvent' then heap_size else 0 end) AllocationSize, - sum(case when h.event_type = 'FreeEvent' then heap_size else 0 end) DeAllocationSize, + query("queryHeapTable", ` + select + *, + Allocations - Deallocations Total, + AllocationSize - DeAllocationSize RemainingSize + from ( + select + f.file_path MoudleName, + sum(case when h.event_type = 'AllocEvent' then 1 else 0 end) Allocations, + sum(case when h.event_type = 'FreeEvent' then 1 else 0 end) Deallocations, + sum(case when h.event_type = 'AllocEvent' then heap_size else 0 end) AllocationSize, + sum(case when h.event_type = 'FreeEvent' then heap_size else 0 end) DeAllocationSize, f.symbol_name AllocationFunction - from (select native_hook.start_ts - t.start_ts as startTime,* from native_hook - left join trace_range t where ipid in (${ipids.join(",")}) and startTime between ${startTs} and ${endTs}) h - left join (select * from native_hook_frame where depth = 0) f - on f.eventId = h.eventId group by f.file_path)`, + from ( + select + native_hook.start_ts - t.start_ts as startTime, + * + from + native_hook + left join + trace_range t \ + where + ipid in (${ipids.join(",")}) + and + startTime + between + ${startTs} and ${endTs}) h + left join ( + select + * + from + native_hook_frame + where + depth = 0) f + on + f.eventId = h.eventId + group by + f.file_path)`, {ipids: ipids, $startTs: startTs, $endTs: endTs}) + export const queryHeapTreeTable = (startTs: number, endTs: number, ipids: Array): Promise> => query("queryHeapTable", ` - select h.start_ts - t.start_ts as startTs, - h.end_ts - t.start_ts as endTs, - h.heap_size as heapSize, - h.event_type as eventType, - f.symbol_name as AllocationFunction, - f.file_path as MoudleName, - f.depth, - f.eventId - from native_hook h - inner join trace_range t - inner join native_hook_frame f on h.eventId = f.eventId where event_type = 'AllocEvent' - and ipid in (${ipids.join(",")}) - and (h.start_ts - t.start_ts between ${startTs} and ${endTs} or h.end_ts - t.start_ts between ${startTs} and ${endTs})`, + select + h.start_ts - t.start_ts as startTs, + h.end_ts - t.start_ts as endTs, + h.heap_size as heapSize, + h.event_type as eventType, + f.symbol_name as AllocationFunction, + f.file_path as MoudleName, + f.depth, + f.eventId + from + native_hook h + inner join + trace_range t + inner join + native_hook_frame f + on + h.eventId = f.eventId + where + event_type = 'AllocEvent' + and + ipid in (${ipids.join(",")}) + and + (h.start_ts - t.start_ts between ${startTs} + and ${endTs} or h.end_ts - t.start_ts + between ${startTs} and ${endTs})`, {ipids: ipids, $startTs: startTs, $endTs: endTs}) + export const queryHeapAllTable = (limit: number, offset: number): Promise> => query("queryHeapAllTable", ` select - h.symbol_name as AllocationFunction, - h.file_path as MoudleName, - h.depth, - h.eventId - from native_hook_frame h limit $limit offset $offset`, - { $limit: limit, $offset: offset}) + h.symbol_name as AllocationFunction, + h.file_path as MoudleName, + h.depth, + h.eventId + from + native_hook_frame h + limit $limit offset $offset`, + {$limit: limit, $offset: offset}) + export const queryHeapAllData = (startTs: number, endTs: number, ipids: Array): Promise> => query("queryHeapAllData", ` - select h.start_ts - t.start_ts as startTs, - h.end_ts - t.start_ts as endTs, - h.heap_size as heapSize, - h.event_type as eventType, - h.eventId - from native_hook h - inner join trace_range t - where event_type = 'AllocEvent' - and ipid in (${ipids.join(",")}) - and (h.start_ts - t.start_ts between ${startTs} and ${endTs} or h.end_ts - t.start_ts between ${startTs} and ${endTs})`, + select + h.start_ts - t.start_ts as startTs, + h.end_ts - t.start_ts as endTs, + h.heap_size as heapSize, + h.event_type as eventType, + h.eventId + from + native_hook h + inner join + trace_range t + where + event_type = 'AllocEvent' + and + ipid in (${ipids.join(",")}) + and + (h.start_ts - t.start_ts between ${startTs} and ${endTs} or h.end_ts - t.start_ts between ${startTs} and ${endTs})`, {ipids: ipids, $startTs: startTs, $endTs: endTs}) + export const queryHeapFrameCount = (): Promise> => query("queryHeapAllTable", ` select count(*) as count - from native_hook_frame `, + from + native_hook_frame `, {}) -export const queryNativeHookStatistics = (leftNs:number,rightNs:number): Promise> => - query("queryNativeHookStatistics",` - select event_type as eventType,sub_type as subType,max(all_heap_size) as max,sum(heap_size) as sumHeapSize,count(event_type) as count -from native_hook A,trace_range B -where (A.start_ts - B.start_ts) between ${leftNs} and ${rightNs} ---not ((A.start_ts - B.start_ts + ifnull(A.dur,0)) < ${leftNs} or (A.start_ts - B.start_ts) > ${rightNs}) -group by event_type, sub_type`,{$leftNs:leftNs,$rightNs:rightNs}) - -export const queryNativeHookStatisticsMalloc = (leftNs:number,rightNs:number):Promise> => - query('queryNativeHookStatisticsMalloc', - `select event_type as eventType, - heap_size as heapSize, - sum(case when ((A.start_ts - B.start_ts) between ${leftNs} and ${rightNs}) then heap_size else 0 end) as allocByte, - sum(case when ((A.start_ts - B.start_ts) between ${leftNs} and ${rightNs}) then 1 else 0 end) as allocCount, - sum(case when ((A.end_ts - B.start_ts) between ${leftNs} and ${rightNs} ) then heap_size else 0 end) as freeByte, - sum(case when ((A.end_ts - B.start_ts) between ${leftNs} and ${rightNs} ) then 1 else 0 end) as freeCount -from native_hook A,trace_range B -where ((A.start_ts - B.start_ts) between ${leftNs} and ${rightNs} - or (A.end_ts - B.start_ts) between ${leftNs} and ${rightNs} ) - and (event_type = 'AllocEvent') -group by event_type,heap_size; - `,{$leftNs:leftNs,$rightNs:rightNs}) - -export const queryNativeHookStatisticsSubType = (leftNs:number,rightNs:number):Promise> => - query('queryNativeHookStatisticsSubType', - `select event_type as eventType, - sub_type as subType, - max(heap_size) as heapSize, - sum(case when ((A.start_ts - B.start_ts) between ${leftNs} and ${rightNs}) then heap_size else 0 end) as allocByte, - sum(case when ((A.start_ts - B.start_ts) between ${leftNs} and ${rightNs}) then 1 else 0 end) as allocCount, - sum(case when ((A.end_ts - B.start_ts) between ${leftNs} and ${rightNs} ) then heap_size else 0 end) as freeByte, - sum(case when ((A.end_ts - B.start_ts) between ${leftNs} and ${rightNs} ) then 1 else 0 end) as freeCount -from native_hook A,trace_range B -where ((A.start_ts - B.start_ts) between ${leftNs} and ${rightNs} - or (A.end_ts - B.start_ts) between ${leftNs} and ${rightNs} ) - and (event_type = 'MmapEvent') -group by event_type,sub_type; - `,{$leftNs:leftNs,$rightNs:rightNs}) - -export const queryNativeHookEventId = (leftNs:number,rightNs:number,types:Array): Promise> => - query("queryNativeHookEventId",` - select eventId,event_type as eventType,sub_type as subType,heap_size as heapSize,addr,(A.start_ts - B.start_ts) as startTs,(A.end_ts - B.start_ts) as endTs -from native_hook A, trace_range B -where A.start_ts - B.start_ts between ${leftNs} and ${rightNs} and A.event_type in (${types.join(",")})`,{$leftNs:leftNs,$rightNs:rightNs,$types:types}) - -export const queryNativeHookEventTid = (leftNs:number,rightNs:number,types:Array): Promise> => - query("queryNativeHookEventTid",` - select eventId, - event_type as eventType, - sub_type as subType, - heap_size as heapSize, - addr, - (A.start_ts - B.start_ts) as startTs, - (A.end_ts - B.start_ts) as endTs, - tid -from native_hook A, trace_range B -left join thread t on A.itid = t.id -where A.start_ts - B.start_ts between ${leftNs} and ${rightNs} and A.event_type in (${types.join(",")})`,{$leftNs:leftNs,$rightNs:rightNs,$types:types}) - -export const queryNativeHookProcess = ():Promise> => - query("queryNativeHookProcess",`select distinct ipid,pid,name from native_hook left join process p on native_hook.ipid = p.id`,{}) - -export const queryNativeHookSnapshot = (rightNs:number):Promise> => - query("queryNativeHookSnapshot",`select event_type as eventType,sub_type as subType,sum(heap_size) as growth,count(*) as existing from native_hook n, trace_range t -where (event_type = 'AllocEvent' or event_type = 'MmapEvent') - and n.start_ts between 0 and ${rightNs} + t.start_ts - and n.end_ts > ${rightNs} + t.start_ts -group by event_type,sub_type`,{$rightNs:rightNs}) - -export const queryNativeHookSnapshotTypes = ():Promise> => - query("queryNativeHookSnapshotTypes",`select event_type as eventType,sub_type as subType from native_hook where (event_type = 'AllocEvent' or event_type = 'MmapEvent') group by event_type,sub_type;`,{}) - -export const queryAllHookData = (rightNs:number):Promise> => - query("queryAllHookData",`select eventId,event_type as eventType,sub_type as subType,addr,heap_size as growth,(n.start_ts - t.start_ts) as startTs,(n.end_ts - t.start_ts) as endTs from native_hook n, trace_range t -where (event_type = 'AllocEvent' or event_type = 'MmapEvent') - and n.start_ts between t.start_ts and ${rightNs} + t.start_ts`,{$rightNs:rightNs}) \ No newline at end of file +export const queryNativeHookStatistics = (leftNs: number, rightNs: number): Promise> => + query("queryNativeHookStatistics", ` + select + event_type as eventType, + sub_type as subType, + max(all_heap_size) as max, + sum(heap_size) as sumHeapSize, + count(event_type) as count + from + native_hook A, + trace_range B + where + (A.start_ts - B.start_ts) between ${leftNs} and ${rightNs} + --not ((A.start_ts - B.start_ts + ifnull(A.dur,0)) < ${leftNs} or (A.start_ts - B.start_ts) > ${rightNs}) + group by event_type, sub_type`, {$leftNs: leftNs, $rightNs: rightNs}) + +export const queryNativeHookStatisticsMalloc = (leftNs: number, rightNs: number): Promise> => + query('queryNativeHookStatisticsMalloc', ` + select + event_type as eventType, + heap_size as heapSize, + sum(case when ((A.start_ts - B.start_ts) between ${leftNs} and ${rightNs}) then heap_size else 0 end) as allocByte, + sum(case when ((A.start_ts - B.start_ts) between ${leftNs} and ${rightNs}) then 1 else 0 end) as allocCount, + sum(case when ((A.end_ts - B.start_ts) between ${leftNs} and ${rightNs} ) then heap_size else 0 end) as freeByte, + sum(case when ((A.end_ts - B.start_ts) between ${leftNs} and ${rightNs} ) then 1 else 0 end) as freeCount + from + native_hook A, + trace_range B + where + ((A.start_ts - B.start_ts) between ${leftNs} and ${rightNs} + or + (A.end_ts - B.start_ts) between ${leftNs} and ${rightNs} ) + and + (event_type = 'AllocEvent') + group by + event_type, + heap_size; + `, {$leftNs: leftNs, $rightNs: rightNs}) + +export const queryNativeHookStatisticsSubType = (leftNs: number, rightNs: number): Promise> => + query('queryNativeHookStatisticsSubType', ` + select + event_type as eventType, + sub_type as subType, + max(heap_size) as heapSize, + sum(case when ((A.start_ts - B.start_ts) between ${leftNs} and ${rightNs}) then heap_size else 0 end) as allocByte, + sum(case when ((A.start_ts - B.start_ts) between ${leftNs} and ${rightNs}) then 1 else 0 end) as allocCount, + sum(case when ((A.end_ts - B.start_ts) between ${leftNs} and ${rightNs} ) then heap_size else 0 end) as freeByte, + sum(case when ((A.end_ts - B.start_ts) between ${leftNs} and ${rightNs} ) then 1 else 0 end) as freeCount + from + native_hook A, + trace_range B + where + ((A.start_ts - B.start_ts) between ${leftNs} and ${rightNs} + or + (A.end_ts - B.start_ts) between ${leftNs} and ${rightNs} ) + and + (event_type = 'MmapEvent') + group by + event_type,sub_type; + `, {$leftNs: leftNs, $rightNs: rightNs}) + +export const queryNativeHookEventId = (leftNs: number, rightNs: number, types: Array): Promise> => + query("queryNativeHookEventId", ` + select + eventId, + event_type as eventType, + sub_type as subType, + heap_size as heapSize, + addr, + (A.start_ts - B.start_ts) as startTs, + (A.end_ts - B.start_ts) as endTs + from + native_hook A, + trace_range B + where + A.start_ts - B.start_ts between ${leftNs} and ${rightNs} and A.event_type in (${types.join(",")})` + , {$leftNs: leftNs, $rightNs: rightNs, $types: types}) + +export const queryNativeHookEventTid = (leftNs: number, rightNs: number, types: Array): Promise> => + query("queryNativeHookEventTid", ` + select + eventId, + event_type as eventType, + sub_type as subType, + heap_size as heapSize, + addr, + (A.start_ts - B.start_ts) as startTs, + (A.end_ts - B.start_ts) as endTs, + tid + from + native_hook A, + trace_range B + left join + thread t + on + A.itid = t.id + where + A.start_ts - B.start_ts + between ${leftNs} and ${rightNs} and A.event_type in (${types.join(",")})` + , {$leftNs: leftNs, $rightNs: rightNs, $types: types}) + +export const queryNativeHookProcess = (): Promise> => + query("queryNativeHookProcess", ` + select + distinct ipid, + pid, + name + from + native_hook + left join + process p + on + native_hook.ipid = p.id`, {}) + +export const queryNativeHookSnapshot = (rightNs: number): Promise> => + query("queryNativeHookSnapshot", ` + select + event_type as eventType, + sub_type as subType, + sum(heap_size) as growth, + count(*) as existing + from + native_hook n, + trace_range t + where + (event_type = 'AllocEvent' or event_type = 'MmapEvent') + and n.start_ts between 0 and ${rightNs} + t.start_ts + and n.end_ts > ${rightNs} + t.start_ts + group by event_type,sub_type`, {$rightNs: rightNs}) + +export const queryNativeHookSnapshotTypes = (): Promise> => + query("queryNativeHookSnapshotTypes", ` + select + event_type as eventType, + sub_type as subType + from + native_hook + where + (event_type = 'AllocEvent' or event_type = 'MmapEvent') + group by + event_type,sub_type;`, {}) + +export const queryAllHookData = (rightNs: number): Promise> => + query("queryAllHookData", ` + select + eventId, + event_type as eventType, + sub_type as subType, + addr, + heap_size as growth, + (n.start_ts - t.start_ts) as startTs, + (n.end_ts - t.start_ts) as endTs + from + native_hook n, + trace_range t + where + (event_type = 'AllocEvent' or event_type = 'MmapEvent') + and + n.start_ts between t.start_ts and ${rightNs} + t.start_ts`, {$rightNs: rightNs}) + + +/** + * HiPerf + */ +export const queryHiPerfCpuData = (cpu: number): Promise> => + query("queryHiPerfCpuData", `select s.*,(s.timestamp_trace-t.start_ts) startNS from perf_sample s,trace_range t where cpu_id=${cpu} and s.thread_id != 0;`, {$cpu: cpu}) +export const queryHiPerfCpuMergeData = (): Promise> => + query("queryHiPerfCpuData", `select s.*,(s.timestamp_trace-t.start_ts) startNS from perf_sample s,trace_range t where s.thread_id != 0;`, {}) + +export const queryHiPerfProcessData = (pid: number): Promise> => query("queryHiPerfProcessData", `SELECT sp.*, + th.thread_name, + th.thread_id tid, + th.process_id pid, + sp.timestamp_trace - tr.start_ts startNS +from perf_sample sp, + trace_range tr + left join perf_thread th on th.thread_id = sp.thread_id +where pid = ${pid} and sp.thread_id != 0;;`, {$pid: pid}) + +export const queryHiPerfThreadData = (tid: number): Promise> => query("queryHiPerfThreadData", `SELECT sp.*, + th.thread_name, + th.thread_id tid, + th.process_id pid, + sp.timestamp_trace - tr.start_ts startNS +from perf_sample sp, + trace_range tr + left join perf_thread th on th.thread_id = sp.thread_id +where tid = ${tid} and sp.thread_id != 0;`, {$tid: tid}) + +export const querySelectTraceStats = (): Promise> => + query('querySelectTraceStats', 'select event_name,stat_type,count,source,serverity from stat'); + +export const queryCustomizeSelect = (sql: string): Promise> => + query('queryCustomizeSelect', sql); + +export const queryMetricTraceStats = (): Promise> => + query('queryMetricTraceStats', `select 'stat {' || char(13) || ' name: ' || + event_name || '_' || stat_type || char(13) || ' count: ' || + count || char(13) || ' source: ' || + source || char(13) || ' severity: ' || + serverity || char(13) || ' }' || char(13) as traceStatsResult from stat`); + +export const querySysCalls = (): Promise> => + query('querySysCalls', `SELECT ' function {' || CHAR ( 13 ) || ' function_name: ' || + name || char(13) || ' durMax: ' || + max( dur ) || char(13) || ' durMin: ' || + min( dur ) || char(13) ||' durAvg: ' || + floor(avg( dur )) || char(13) || ' }' || char(13) as sysCallsResult + FROM callstack GROUP BY name ORDER BY count(*) DESC LIMIT 100`); + +export const querySysCallsTop10 = (): Promise> => + query('querySysCallsTop10', `select + ' process_info {' || char(13) || + ' name: ' || cpu.process_name || char(13) || + ' pid: ' || cpu.pid || char(13) || + ' threads {' || char(13) || + ' name: ' || cpu.thread_name || char(13) || + ' tid: ' || cpu.tid || char(13) || + ' function {' || char(13) || + ' function_name: ' || cpu.thread_name || char(13) || + ' durMax: ' || max(callstack.dur) || char(13) || + ' durMin: ' || min(callstack.dur) || char(13) || + ' durAvg: ' || floor(avg(callstack.dur)) || char(13) || + ' }' || char(13) || + ' }' || char(13) || + ' }' as name + from callstack inner join + ( select + itid as tid, + ipid as pid, + group_concat(cpu,',') as cpu, + group_concat(duration,',') as duration, + group_concat(min_freq,',') as min_freq, + group_concat(max_freq,',') as max_freq, + group_concat(avg_frequency,',') as avg_frequency, + sum(duration*avg_frequency) as sumNum, + process_name, + thread_name + from + ( + SELECT itid, + ipid, + cpu, + CAST(SUM(duration) AS INT) AS duration, + CAST(MIN(freq) AS INT) AS min_freq, + CAST(MAX(freq) AS INT) AS max_freq, + CAST((SUM(duration * freq) / SUM(duration)) AS INT) AS avg_frequency, + process_name, + thread_name + FROM (SELECT (MIN(cpu_frequency_view.end_ts, cpu_thread_view.end_ts) - MAX(cpu_frequency_view.start_ts, cpu_thread_view.ts)) AS duration, + freq, + cpu_thread_view.cpu as cpu, + itid, + ipid, + process_name, + thread_name + FROM cpu_frequency_view JOIN cpu_thread_view ON(cpu_frequency_view.cpu = cpu_thread_view.cpu) + WHERE cpu_frequency_view.start_ts < cpu_thread_view.end_ts AND cpu_frequency_view.end_ts > cpu_thread_view.ts + ) GROUP BY itid, cpu) GROUP BY ipid, itid order by sumNum desc limit 10 + ) + as cpu on + callstack.callid = cpu.tid + group by callstack.name order by count(callstack.name) desc limit 10`); + +export const queryMetricTraceTask = (): Promise> => + query('queryMetricTraceTask', `select + ttt.name || + REPLACE(ttt.thread_name,',',CHAR (13)) || char(13) || ' }' || CHAR (13) as nameStr + from + (SELECT ' process{' || CHAR (13) || ' pid: ' || + P.pid || char(13) || ' process_name: ' || + P.name || char(13) as name, + group_concat(' thread_name: ', T.name || ',') as thread_name + from process as P left join thread as T where P.id = T.ipid + group by pid) ttt`); + +export const queryMetricData = (): Promise> => + query('queryMetricData', ` + select + cast(name as varchar) as name, + cast(value as varchar) as value + from meta + UNION + select + 'start_ts', + cast(start_ts as varchar) + from trace_range + UNION + select + 'end_ts', + cast(end_ts as varchar) + from + trace_range`); + +export const queryDistributedTerm = (): Promise> => + query('queryDistributedTerm', ` + select + group_concat(thread.id,',') as threadId, + group_concat(thread.name,',') as threadName, + group_concat(process.id,',') as processId, + group_concat(process.name,',') as processName, + group_concat(callstack.name,',') as funName, + group_concat(callstack.dur,',') as dur, + group_concat(callstack.ts,',') as ts, + cast(callstack.chainId as varchar) as chainId, + callstack.spanId as spanId, + callstack.parentSpanId as parentSpanId, + group_concat(callstack.flag,',') as flag, + (select + value + from + meta + where + name='source_name') as trace_name + from + callstack + inner join thread on callstack.callid = thread.id + inner join process on process.id = thread.ipid + where (callstack.flag='S' or callstack.flag='C') + group by callstack.chainId,callstack.spanId,callstack.parentSpanId`); + +export const queryTraceCpu = (): Promise> => + query('queryTraceCpu', ` + select + itid as tid, + ipid as pid, + group_concat(cpu,',') as cpu, + group_concat(duration,',') as duration, + group_concat(min_freq,',') as min_freq, + group_concat(max_freq,',') as max_freq, + group_concat(avg_frequency,',') as avg_frequency, + process_name as process_name, + thread_name as thread_name + from + ( + SELECT itid, + ipid, + cpu, + CAST(SUM(duration) AS INT) AS duration, + CAST(MIN(freq) AS INT) AS min_freq, + CAST(MAX(freq) AS INT) AS max_freq, + CAST((SUM(duration * freq) / SUM(duration)) AS INT) AS avg_frequency, + process_name, + thread_name + FROM (SELECT (MIN(cpu_frequency_view.end_ts, cpu_thread_view.end_ts) - MAX(cpu_frequency_view.start_ts, cpu_thread_view.ts)) AS duration, + freq, + cpu_thread_view.cpu as cpu, + itid, + ipid, + process_name, + thread_name + FROM cpu_frequency_view JOIN cpu_thread_view ON(cpu_frequency_view.cpu = cpu_thread_view.cpu) + WHERE cpu_frequency_view.start_ts < cpu_thread_view.end_ts AND cpu_frequency_view.end_ts > cpu_thread_view.ts + ) GROUP BY itid, cpu + ) + GROUP BY ipid, itid order by ipid`); + +export const queryTraceCpuTop = (): Promise> => + query('queryTraceCpuTop', ` + select + itid as tid, + ipid as pid, + group_concat(cpu,',') as cpu, + group_concat(duration,',') as duration, + group_concat(min_freq,',') as min_freq, + group_concat(max_freq,',') as max_freq, + group_concat(avg_frequency,',') as avg_frequency, + sum(duration*avg_frequency) as sumNum, + process_name as process_name, + thread_name as thread_name + from + ( + SELECT itid, + ipid, + cpu, + CAST(SUM(duration) AS INT) AS duration, + CAST(MIN(freq) AS INT) AS min_freq, + CAST(MAX(freq) AS INT) AS max_freq, + CAST((SUM(duration * freq) / SUM(duration)) AS INT) AS avg_frequency, + process_name, + thread_name + FROM (SELECT (MIN(cpu_frequency_view.end_ts, cpu_thread_view.end_ts) - MAX(cpu_frequency_view.start_ts, cpu_thread_view.ts)) AS duration, + freq, + cpu_thread_view.cpu as cpu, + itid, + ipid, + process_name, + thread_name + FROM cpu_frequency_view JOIN cpu_thread_view ON(cpu_frequency_view.cpu = cpu_thread_view.cpu) + WHERE cpu_frequency_view.start_ts < cpu_thread_view.end_ts AND cpu_frequency_view.end_ts > cpu_thread_view.ts + ) GROUP BY itid, cpu + ) + GROUP BY ipid, itid order by sumNum desc limit 10`); + +export const queryTraceMemory = (): Promise> => + query('queryTraceMemory', ` + select + max(value) as maxNum, + min(value) as minNum, + avg(value) as avgNum, + result.name as name, + result.processName as processName + from measure inner join + ( + select filter.id,filter.name,p.name as processName from process_measure_filter as filter + left join process as p + on filter.ipid=p.id where filter.name = 'mem.rss.anon' + ) as result on result.id = filter_id + where filter_id > 0 group by filter_id order by avgNum desc`); + +export const queryTraceMemoryTop = (): Promise> => + query('queryTraceMemoryTop', ` + select + max(value) as maxNum, + min(value) as minNum, + avg(value) as avgNum, + result.name as name, + result.processName as processName + from measure inner join + ( + select filter.id,filter.name,p.name as processName from process_measure_filter as filter + left join process as p + on filter.ipid=p.id where filter.name = 'mem.rss.anon' + ) as result on result.id = filter_id + where filter_id > 0 group by filter_id order by avgNum desc limit 10`); + +export const queryTraceMemoryUnAgg = (): Promise> => + query('queryTraceMemoryUnAgg', `d + select + processName as processName, + group_concat(name) as name, + cast(group_concat(value) as varchar) as value, + cast(group_concat(ts) as varchar) as ts + from measure inner join + ( + select filter.ipid,filter.id,filter.name,p.name as processName from process_measure_filter as filter + left join process as p + on filter.ipid=p.id where filter.name = 'mem.rss.anon' or filter.name = 'mem.rss.file' or filter.name = 'mem.swap' or filter.name = 'oom_score_adj' + ) as result + on result.id = filter_id + group by processName,ipid order by ipid`); + +export const queryTraceTaskName = (): Promise> => + query('queryTraceTaskName', ` + select + P.id as id, + P.pid as pid, + P.name as process_name, + group_concat(T.name,',') as thread_name + from process as P left join thread as T where P.id = T.ipid + group by pid`); + +export const queryTraceMetaData = (): Promise> => + query('queryTraceMetaData', ` + select + cast(name as varchar) as name, + cast(value as varchar) as valueText + from meta + UNION + select 'start_ts',cast(start_ts as varchar) from trace_range + UNION + select 'end_ts',cast(end_ts as varchar) from trace_range`); + +export const querySystemCalls = (): Promise> => + query('querySystemCalls', ` + select + count(*) as frequency, + min(dur) as minDur, + max(dur) as maxDur, + floor(avg(dur)) as avgDur, + name as funName + from + callstack + group by name + order by + frequency desc limit 100`); + +export const querySystemCallsTop = (): Promise> => + query('querySystemCallsTop', `select + cpu.tid as tid, + cpu.pid as pid, + cpu.process_name as process_name, + cpu.thread_name as thread_name, + callstack.name as funName, + count(callstack.name) as frequency, + min(callstack.dur) as minDur, + max(callstack.dur) as maxDur, + floor(avg(callstack.dur)) as avgDur + from callstack inner join + ( select + itid as tid, + ipid as pid, + group_concat(cpu,',') as cpu, + group_concat(duration,',') as duration, + group_concat(min_freq,',') as min_freq, + group_concat(max_freq,',') as max_freq, + group_concat(avg_frequency,',') as avg_frequency, + sum(duration*avg_frequency) as sumNum, + process_name, + thread_name + from + ( + SELECT itid, + ipid, + cpu, + CAST(SUM(duration) AS INT) AS duration, + CAST(MIN(freq) AS INT) AS min_freq, + CAST(MAX(freq) AS INT) AS max_freq, + CAST((SUM(duration * freq) / SUM(duration)) AS INT) AS avg_frequency, + process_name, + thread_name + FROM (SELECT (MIN(cpu_frequency_view.end_ts, cpu_thread_view.end_ts) - MAX(cpu_frequency_view.start_ts, cpu_thread_view.ts)) AS duration, + freq, + cpu_thread_view.cpu as cpu, + itid, + ipid, + process_name, + thread_name + FROM cpu_frequency_view JOIN cpu_thread_view ON(cpu_frequency_view.cpu = cpu_thread_view.cpu) + WHERE cpu_frequency_view.start_ts < cpu_thread_view.end_ts AND cpu_frequency_view.end_ts > cpu_thread_view.ts + ) GROUP BY itid, cpu) GROUP BY ipid, itid order by sumNum desc limit 10 + ) + as cpu on + callstack.callid = cpu.tid + group by callstack.name order by frequency desc limit 10`); + +export const getTabLiveProcessData = (leftNs: number, rightNs: number): Promise> => + query("getTabLiveProcessData", `SELECT + process.id as processId, + process.name as processName, + process.ppid as responsibleProcess, + process.uud as userName, + process.usag as cpu, + process.threadN as threads, + process.pss as memory, + process.cpu_time as cpuTime, + process.disk_reads as diskReads, + process.disk_writes as diskWrite + FROM + ( + SELECT + tt.process_id AS id, + tt.process_name AS name, + tt.parent_process_id AS ppid, + tt.uid as uud, + tt.cpu_usage as usag, + tt.thread_num AS threadN, + mt.maxTT - TR.start_ts as endTs, + tt.pss_info as pss, + tt.cpu_time, + tt.disk_reads, + tt.disk_writes + FROM + live_process tt + LEFT JOIN trace_range AS TR + LEFT JOIN (select re.process_id as idd, max(re.ts) as maxTT, min(re.ts) as minTT + from live_process re GROUP BY re.process_name, re.process_id ) mt + on mt.idd = tt.process_id where endTs >= $rightNS + GROUP BY + tt.process_name, + tt.process_id + ) process ;`, {$leftNS: leftNs, $rightNS: rightNs}) + +export const getTabProcessHistoryData = (leftNs: number, rightNs: number, + processId: number | undefined, threadId: number | undefined): Promise> => + query("getTabProcessHistoryData", `SELECT + process.id as processId, + process.isD as alive, + process.startTS as firstSeen, + process.endTs as lastSeen, + process.name as processName, + process.ppid as responsibleProcess, + process.uuid as userName, + process.cpu_time as cpuTime, + 0 as pss + FROM + ( + SELECT + tt.process_id AS id, + tt.process_name AS name, + tt.parent_process_id AS ppid, + tt.uid AS uuid, + tt.cpu_time, + (mt.minTT - TR.start_ts ) AS startTS, + mt.maxTT - TR.start_ts as endTs, + (mt.maxTT - TR.start_ts - $rightNS) > 0 as isD + FROM + live_process tt + LEFT JOIN trace_range AS TR + LEFT JOIN (select re.process_id as idd, max(re.ts) as maxTT, min(re.ts) as minTT + from live_process re GROUP BY re.process_name, re.process_id ) mt + on mt.idd = tt.process_id + GROUP BY + tt.process_name, + tt.process_id + ) process;` + , {$leftNS: leftNs, $rightNS: rightNs, $processID: processId, $threadID: threadId}) + +export const getTabCpuAbilityData = (leftNs: number, rightNs: number): Promise> => + query("getTabCpuAbilityData", `SELECT + ( n.ts - TR.start_ts ) AS startTime, + n.dur AS duration, + n.total_load AS totalLoad, + n.user_load AS userLoad, + n.system_load AS systemLoad, + n.process_num AS threads + FROM + cpu_usage AS n, + trace_range AS TR + WHERE + ( n.ts - TR.start_ts ) >= ifnull(( + SELECT + ( usage.ts - TR.start_ts ) + FROM + cpu_usage usage, + trace_range TR + WHERE + ( usage.ts - TR.start_ts ) <= $leftNS + ORDER BY + usage.ts DESC + LIMIT 1 + ),0) + AND ( n.ts - TR.start_ts ) <= $rightNS + ORDER BY + startTime ASC; + `, {$leftNS: leftNs, $rightNS: rightNs}) + +export const getTabMemoryAbilityData = (leftNs: number, rightNs: number): Promise> => + query("getTabMemoryAbilityData", `SELECT + m.ts AS startTime, + GROUP_CONCAT( IFNULL( m.value, 0 ) ) AS value, + GROUP_CONCAT( f.name ) AS name + FROM + measure AS m + INNER JOIN sys_event_filter AS f ON m.filter_id = f.id + AND (f.name = 'sys.mem.total' + or f.name = 'sys.mem.free' + or f.name = 'sys.mem.buffers' + or f.name = 'sys.mem.cached' + or f.name = 'sys.mem.shmem' + or f.name = 'sys.mem.slab' + or f.name = 'sys.mem.swap.total' + or f.name = 'sys.mem.swap.free' + or f.name = 'sys.mem.mapped' + or f.name = 'sys.mem.vmalloc.used' + or f.name = 'sys.mem.page.tables' + or f.name = 'sys.mem.kernel.stack' + or f.name = 'sys.mem.active' + or f.name = 'sys.mem.inactive' + or f.name = 'sys.mem.unevictable' + or f.name = 'sys.mem.vmalloc.total' + or f.name = 'sys.mem.slab.unreclaimable' + or f.name = 'sys.mem.cma.total' + or f.name = 'sys.mem.cma.free' + or f.name = 'sys.mem.kernel.reclaimable' + or f.name = 'sys.mem.zram' + ) + AND m.ts >= ifnull(( + SELECT + m.ts AS startTime + FROM + measure AS m + INNER JOIN sys_event_filter AS f ON m.filter_id = f.id + AND m.ts <= $leftNS + AND (f.name = 'sys.mem.total' + or f.name = 'sys.mem.free' + or f.name = 'sys.mem.buffers' + or f.name = 'sys.mem.cached' + or f.name = 'sys.mem.shmem' + or f.name = 'sys.mem.slab' + or f.name = 'sys.mem.swap.total' + or f.name = 'sys.mem.swap.free' + or f.name = 'sys.mem.mapped' + or f.name = 'sys.mem.vmalloc.used' + or f.name = 'sys.mem.page.tables' + or f.name = 'sys.mem.kernel.stack' + or f.name = 'sys.mem.active' + or f.name = 'sys.mem.inactive' + or f.name = 'sys.mem.unevictable' + or f.name = 'sys.mem.vmalloc.total' + or f.name = 'sys.mem.slab.unreclaimable' + or f.name = 'sys.mem.cma.total' + or f.name = 'sys.mem.cma.free' + or f.name = 'sys.mem.kernel.reclaimable' + or f.name = 'sys.mem.zram' + ) + ORDER BY + m.ts DESC + LIMIT 1 + ),0) + AND m.ts <= $rightNS GROUP BY m.ts;`, {$leftNS: leftNs, $rightNS: rightNs}) + +export const getTabNetworkAbilityData = (leftNs: number, rightNs: number): Promise> => + query("getTabNetworkAbilityData", `SELECT + ( n.ts - TR.start_ts ) AS startTime, + n.dur AS duration, + n.rx AS dataReceived, + n.tx_speed AS dataReceivedSec, + n.tx AS dataSend, + n.rx_speed AS dataSendSec, + n.packet_in AS packetsIn, + n.packet_in_sec AS packetsInSec, + n.packet_out AS packetsOut, + n.packet_out_sec AS packetsOutSec + FROM + network AS n, + trace_range AS TR + WHERE + ( n.ts - TR.start_ts ) >= ifnull(( + SELECT + ( nn.ts - T.start_ts ) AS startTime + FROM + network nn, + trace_range T + WHERE + ( nn.ts - T.start_ts ) <= $leftNS + ORDER BY + nn.ts DESC + LIMIT 1 + ),0) + AND ( n.ts - TR.start_ts ) <= $rightNS + ORDER BY + startTime ASC`, {$leftNS: leftNs, $rightNS: rightNs}) + +/*-------------------------------------------------------------------------------------*/ +export const getTabDiskAbilityData = (leftNs: number, rightNs: number): Promise> => + query("getTabDiskAbilityData", `SELECT + ( n.ts - TR.start_ts ) AS startTime, + n.dur AS duration, + n.rd AS dataRead, + n.rd_speed AS dataReadSec, + n.wr AS dataWrite, + n.wr_speed AS dataWriteSec, + n.rd_count AS readsIn, + n.rd_count_speed AS readsInSec, + n.wr_count AS writeOut, + n.wr_count_speed AS writeOutSec + FROM + diskio AS n, + trace_range AS TR + WHERE + ( n.ts - TR.start_ts ) >= ifnull(( + SELECT + ( nn.ts - T.start_ts ) AS startTime + FROM + diskio AS nn, + trace_range AS T + WHERE + ( nn.ts - T.start_ts ) <= $leftNS + ORDER BY + nn.ts DESC + LIMIT 1 + ),0) + AND ( n.ts - TR.start_ts ) <= $rightNS + ORDER BY + startTime ASC; + `, {$leftNS: leftNs, $rightNS: rightNs}) + +export const queryCpuAbilityData = (): Promise> => + query("queryCpuAbilityData", `select + (t.total_load) as value, + (t.ts - TR.start_ts) as startNS + from cpu_usage t, trace_section AS TR;`) + +export const queryCpuAbilityUserData = (): Promise> => + query("queryCpuAbilityUserData", `select + t.user_load as value, + (t.ts - TR.start_ts) as startNS + from cpu_usage t, trace_section AS TR;`) + +export const queryCpuAbilitySystemData = (): Promise> => + query("queryCpuAbilitySystemData", `select + t.system_load as value, + (t.ts - TR.start_ts) as startNS + from cpu_usage t, trace_section AS TR;`) + +export const queryMemoryUsedAbilityData = (id: string): Promise> => + query("queryMemoryUsedAbilityData", `select + t.value as value, + (t.ts - TR.start_ts) as startNS + from measure t, trace_section AS TR where t.filter_id = $id;`, {$id: id}) + +export const queryCachedFilesAbilityData = (id: string): Promise> => + query("queryCachedFilesAbilityData", `select + t.value as value, + (t.ts - TR.start_ts) as startNS + from measure t, trace_section AS TR where t.filter_id = $id;`, {$id: id}) + +export const queryCompressedAbilityData = (id: string): Promise> => + query("queryCompressedAbilityData", `select + t.value as value, + (t.ts - TR.start_ts) as startNS + from measure t, trace_section AS TR where t.filter_id = $id;`, {$id: id}) + +export const querySwapUsedAbilityData = (id: string): Promise> => + query("querySwapUsedAbilityData", `select + t.value as value, + (t.ts - TR.start_ts) as startNS + from measure t, trace_section AS TR where t.filter_id = $id;`, {$id: id}) + +export const queryBytesReadAbilityData = (): Promise> => + query("queryBytesReadAbilityData", `select + t.rd_speed as value, + (t.ts - TR.start_ts) as startNS + from diskio t, trace_section AS TR;`) + +export const queryBytesWrittenAbilityData = (): Promise> => + query("queryBytesWrittenAbilityData", `select + t.wr_speed as value, + (t.ts - TR.start_ts) as startNS + from diskio t, trace_section AS TR;`) + +export const queryReadAbilityData = (): Promise> => + query("queryReadAbilityData", `select + t.rd_count_speed as value, + (t.ts - TR.start_ts) as startNS + from diskio t, trace_section AS TR;`) + + +export const queryWrittenAbilityData = (): Promise> => + query("queryWrittenAbilityData", `select + t.wr_count_speed as value, + (t.ts - TR.start_ts) as startNS + from diskio t, trace_section AS TR;`) + +export const queryBytesInAbilityData = (): Promise> => + query("queryBytesInAbilityData", `select + t.tx_speed as value, + (t.ts - TR.start_ts) as startNS + from network t, trace_section AS TR;`) + +export const queryBytesOutAbilityData = (): Promise> => + query("queryBytesOutAbilityData", `select + t.rx_speed as value, + (t.ts - TR.start_ts) as startNS + from network t, trace_section AS TR;`,) + +export const queryPacketsInAbilityData = (): Promise> => + query("queryPacketsInAbilityData", `select + t.packet_in_sec as value, + (t.ts - TR.start_ts) as startNS + from network t, trace_section AS TR;`,) + +export const queryPacketsOutAbilityData = (): Promise> => + query("queryPacketsOutAbilityData", `select + t.packet_out_sec as value, + (t.ts - TR.start_ts) as startNS + from network t, trace_section AS TR;`) + +export const queryNetWorkMaxData = (): Promise> => + query("queryNetWorkMaxData", `select + ifnull(max(tx_speed),0) as maxIn, + ifnull(max(rx_speed),0) as maxOut, + ifnull(max(packet_in_sec),0) as maxPacketIn, + ifnull(max(packet_in_sec),0) as maxPacketOut + from network`) + +export const queryMemoryMaxData = (memoryName: string): Promise> => + query("queryMemoryMaxData", + `SELECT ifnull(max(m.value),0) as maxValue, + filter_id + from measure m + WHERE m.filter_id = + (SELECT id FROM sys_event_filter WHERE name = $memoryName) +`, {$memoryName: memoryName}) + +export const queryDiskIoMaxData = (): Promise> => + query("queryDiskIoMaxData", `select + ifnull(max(rd_speed),0) as bytesRead, + ifnull(max(wr_speed),0) as bytesWrite, + ifnull(max(rd_count_speed),0) as readOps, + ifnull(max(wr_count_speed),0) as writeOps + from diskio`) + +export const queryAbilityExits = (): Promise> => + query("queryAbilityExits", `select + event_name + from stat s + where s.event_name in ('trace_diskio','trace_network', 'trace_cpu_usage','sys_memory') + and s.stat_type ='received' and s.count > 0`) + +export const queryStartTime = (): Promise> => + query("queryStartTime", `SELECT start_ts FROM trace_range`) + +export const queryPerfFiles = (): Promise> => + query("queryPerfFiles", `select file_id as fileId,symbol,path from perf_files`, {}) + +export const queryPerfCallchains = (limit:number,offset:number):Promise> => + query("queryPerfCallchains",`select c.sample_id as sampleId,c.callchain_id as callChainId,c.vaddr_in_file as vaddrInFile,c.file_id as fileId,c.symbol_id as symbolId, + s.thread_id as tid,t.process_id as pid,s.thread_state as threadState,s.timestamp as startNS from perf_callchain c left join perf_sample s on c.sample_id = s.sample_id left join perf_thread t on t.thread_id = s.thread_id limit $limit offset $offset`, + {$limit: limit, $offset: offset}) + +export const queryPerfCallchainsCount = ():Promise> => + query("queryPerfCallchainsCount",`select count(*) as count from perf_callchain`,{}) + +export const queryPerfProcess = (): Promise> => + query("queryPerfThread", `select process_id as pid,thread_name as processName from perf_thread where process_id = thread_id`, {}) + + +export const queryPerfThread = (): Promise> => + query("queryPerfThread", `select a.thread_id as tid,a.thread_name as threadName,a.process_id as pid,b.thread_name as processName from perf_thread a left join (select * from perf_thread where thread_id = process_id) b on a.process_id = b.thread_id`, {}) + +export const queryPerfSampleListByTimeRange = (leftNs: number, rightNs: number, cpus: Array, processes: Array, threads: Array): Promise> => { + let sql = ` +select A.sample_id as sampleId, + A.thread_id as tid, + C.thread_name as threadName, + A.thread_state as state, + C.process_id as pid, + (timestamp_trace - R.start_ts) as time, + cpu_id as core +from perf_sample A,trace_range R +left join perf_thread C on A.thread_id = C.thread_id +where time >= $leftNs and time <= $rightNs and A.thread_id != 0 + ` + if (cpus.length != 0 || processes.length != 0 || threads.length != 0) { + let arg1 = cpus.length > 0 ? `or core in (${cpus.join(",")}) ` : ''; + let arg2 = processes.length > 0 ? `or pid in (${processes.join(",")}) ` : ''; + let arg3 = threads.length > 0 ? `or tid in (${threads.join(",")})` : ''; + let arg = `${arg1}${arg2}${arg3}`.substring(3); + sql = `${sql} and (${arg})` + } + return query("queryPerfSampleListByTimeRange", sql, {$leftNs: leftNs, $rightNs: rightNs}); +} + +export const queryPerfSampleCallChain = (sampleId: number): Promise> => + query("queryPerfSampleCallChain", ` + select + callchain_id as callChainId, + sample_id as sampleId, + vaddr_in_file as vaddrInFile, + file_id as fileId, + symbol_id as symbolId +from perf_callchain where sample_id = $sampleId order by id desc; + `, {$sampleId: sampleId}) + +export const queryPerfCmdline = ():Promise> => + query("queryPerfCmdline",` + select report_value from perf_report where report_type = 'cmdline' + `,{}) + +export const queryCPuAbilityMaxData = (): Promise> => + query("queryCPuAbilityMaxData", + `select ifnull(max(total_load),0) as totalLoad, + ifnull(max(user_load),0) as userLoad, + ifnull(max(system_load),0) as systemLoad + from cpu_usage`) + +export const querySearchFunc = (search:string):Promise> => + query("querySearchFunc",` + select c.id,c.name as funName,c.ts - r.start_ts as startTime,c.dur,c.depth,t.tid,t.name as threadName + ,p.pid ,'func' as type from callstack c left join thread t on c.callid = t.id left join process p on t.ipid = p.id + left join trace_range r + where c.name like '%${search}%' and startTime > 0; + `,{$search:search}) \ No newline at end of file diff --git a/host/ide/src/trace/database/TempSql.ts b/host/ide/src/trace/database/TempSql.ts index a04efb3e417a807ccc651392d55c947ccf305923..7282e15eca707fc1c8e6fe1e38f3857fa5e271a2 100644 --- a/host/ide/src/trace/database/TempSql.ts +++ b/host/ide/src/trace/database/TempSql.ts @@ -14,22 +14,30 @@ */ let temp_query_process = `create table temp_query_process as select - distinct process_view.pid as pid, - process_view.name as processName -from ( - select ipid, itid from sched_slice join thread_view using(itid) group by itid -) the_tracks -left join (select ipid, sum(dur) as total_dur - from sched_view join thread_view using(itid) - group by ipid -) using(ipid) -left join process_view using(ipid) -where pid is not null -order by - total_dur desc, - the_tracks.ipid, - processName, - the_tracks.itid; + distinct process_view.pid as pid, + process_view.name as processName + from ( + select + ipid, + itid + from + sched_slice join thread_view using(itid) + group by itid + ) the_tracks + left join + (select ipid, sum(dur) as total_dur + from sched_view join thread_view using(itid) + group by ipid + ) using(ipid) + left join + process_view using(ipid) + where + pid is not null + order by + total_dur desc, + the_tracks.ipid, + processName, + the_tracks.itid; ` let temp_query_cpu_data = `create table temp_query_cpu_data as with list as (SELECT IP.name as processName, @@ -195,63 +203,99 @@ select state, create index temp_get_tab_states_group_by_state_idx1 on temp_get_tab_states_group_by_state(start_ts,end_ts); ` let temp_get_tab_states_group_by_process_thread = `create table temp_get_tab_states_group_by_process_thread as -select IP.name as process, - IP.pid as processId, - A.name as thread, - a.tid as threadId, - B.dur as dur, - A.tid as tid, - (ts - TR.start_ts + dur) as end_ts, - (ts - TR.start_ts) as start_ts - from thread_state AS B - left join thread as A on B.itid = A.id - left join process AS IP on A.ipid = IP.id - left join trace_section AS TR - where pid not null and - B.dur > 0 and (ts - TR.start_ts)>0; + select + IP.name as process, + IP.pid as processId, + A.name as thread, + a.tid as threadId, + B.dur as dur, + A.tid as tid, + (ts - TR.start_ts + dur) as end_ts, + (ts - TR.start_ts) as start_ts + from + thread_state AS B + left join + thread as A on B.itid = A.id + left join + process AS IP on A.ipid = IP.id + left join + trace_section AS TR + where + pid not null + and + B.dur > 0 + and + (ts - TR.start_ts)>0; create index temp_get_tab_states_group_by_process_thread_idx0 on temp_get_tab_states_group_by_process_thread(process,processId,thread,threadId); create index temp_get_tab_states_group_by_process_thread_idx1 on temp_get_tab_states_group_by_process_thread(start_ts,end_ts); ` let temp_get_cpu_rate = `create table temp_get_cpu_rate as with cpu as ( - select cpu,ts,dur,(case when ro < 99 then ro else 99 end) as ro , - (case when ro < 99 then stime+ro*cell else stime + 99 * cell end) as st, - (case when ro < 99 then stime + (ro+1)*cell else etime end) as et + select + cpu, + ts, + dur, + (case when ro < 99 then ro else 99 end) as ro , + (case when ro < 99 then stime+ro*cell else stime + 99 * cell end) as st, + (case when ro < 99 then stime + (ro+1)*cell else etime end) as et from ( - select cpu,ts,A.dur,((ts+A.dur)-D.start_ts)/((D.end_ts-D.start_ts)/100) as ro,D.start_ts as stime,D.end_ts etime,(D.end_ts-D.start_ts)/100 as cell - from sched_slice A - left join trace_section D - left join thread B on A.itid = B.id - left join process C on B.ipid = C.id - where tid != 0 and (A.ts) between D.start_ts and D.end_ts)) -select cpu,ro, + select + cpu, + ts, + A.dur, + ((ts+A.dur)-D.start_ts)/((D.end_ts-D.start_ts)/100) as ro, + D.start_ts as stime, + D.end_ts etime, + (D.end_ts-D.start_ts)/100 as cell + from + sched_slice A + left join + trace_section D + left join + thread B on A.itid = B.id + left join + process C on B.ipid = C.id + where + tid != 0 + and (A.ts) + between D.start_ts and D.end_ts)) + select cpu,ro, sum(case when ts <= st and ts + dur <= et then (ts + dur - st) when ts <= st and ts + dur > et then et-st when ts > st and ts + dur <= et then dur when ts > st and ts + dur > et then et - ts end)/cast(et-st as float) as rate -from cpu -group by cpu,ro; + from cpu + group by cpu,ro; ` let temp_get_tab_thread_states = `create table temp_get_tab_thread_states as select - IP.name as process, - IP.pid as pid, - A.name as thread, - A.tid as tid, - B.state as state, - B.dur as dur, - (B.ts - TR.start_ts + ifnull(B.dur,0)) as end_ts, - (B.ts - TR.start_ts) as start_ts -from thread_state AS B -left join thread as A on A.id = B.itid -left join trace_section AS TR -left join process AS IP on IP.id=ipid -where (B.ts - TR.start_ts > 0); -create index temp_get_tab_thread_states_idx0 on temp_get_tab_thread_states(process,pid,thread,tid,state); -create index temp_get_tab_thread_states_idx1 on temp_get_tab_thread_states(start_ts,end_ts); + IP.name as process, + IP.pid as pid, + A.name as thread, + A.tid as tid, + B.state as state, + B.dur as dur, + (B.ts - TR.start_ts + ifnull(B.dur,0)) as end_ts, + (B.ts - TR.start_ts) as start_ts + from + thread_state AS B + left join + thread as A + on + A.id = B.itid + left join + trace_section AS TR + left join + process AS IP + on + IP.id=ipid + where + (B.ts - TR.start_ts > 0); + create index temp_get_tab_thread_states_idx0 on temp_get_tab_thread_states(process,pid,thread,tid,state); + create index temp_get_tab_thread_states_idx1 on temp_get_tab_thread_states(start_ts,end_ts); `; let temp_get_tab_slices = `create table temp_get_tab_slices as @@ -261,12 +305,16 @@ let temp_get_tab_slices = `create table temp_get_tab_slices as A.tid as tid, (C.ts - D.start_ts + C.dur) as end_ts, (C.ts - D.start_ts) as start_ts -from thread A,trace_section D -left join callstack C on A.id = C.callid -where C.ts not null + from + thread A, + trace_section D + left join + callstack C on A.id = C.callid + where + C.ts not null and c.dur >= 0 and (C.ts - D.start_ts > 0); -create index temp_get_tab_slices_idx0 on temp_get_tab_slices(name); + create index temp_get_tab_slices_idx0 on temp_get_tab_slices(name); `; let delete_callstack_binder_data = `DELETE FROM callstack WHERE dur<0 or name like 'binder%';`; diff --git a/host/ide/src/trace/database/TraceWorker.ts b/host/ide/src/trace/database/TraceWorker.ts index 559550f62e06790b67669355d34972462b653df6..7bfd50244b19fec7d949cc34aefbb0de70e0a153 100644 --- a/host/ide/src/trace/database/TraceWorker.ts +++ b/host/ide/src/trace/database/TraceWorker.ts @@ -45,7 +45,7 @@ self.onmessage = async (e: MessageEvent) => { if (e.data.action === "open") { await initWASM(); // @ts-ignore - self.postMessage({id: e.data.id, action: "open", ready: true, index: 0}); + self.postMessage({id: e.data.id, action: e.data.action, ready: true, index: 0}); let uint8Array = new Uint8Array(e.data.buffer); let p = Module._malloc(uint8Array.length); Module.HEAPU8.set(uint8Array, p); @@ -54,7 +54,7 @@ self.onmessage = async (e: MessageEvent) => { Module._free(p); if (r1 == -1) { // @ts-ignore - self.postMessage({id: e.data.id, action: "open", init: false, msg: "parse data error"}); + self.postMessage({id: e.data.id, action: e.data.action, init: false, msg: "parse data error"}); return; } // @ts-ignore @@ -64,11 +64,15 @@ self.onmessage = async (e: MessageEvent) => { self.postMessage({id: e.data.id, ready: true, index: index + 1}); }); // @ts-ignore - self.postMessage({id: e.data.id, action: "open", init: true, msg: "ok"}); + self.postMessage({id: e.data.id, action: e.data.action, init: true, msg: "ok"}); } else if (e.data.action === "exec") { let arr = query(e.data.name, e.data.sql, e.data.params); // @ts-ignore - self.postMessage({id: e.data.id, action: "exec", results: arr}); + self.postMessage({id: e.data.id, action: e.data.action, results: arr}); + } else if (e.data.action == "exec-buf") { + let arr = queryArrayBuffer(e.data.name, e.data.sql, e.data.params); + // @ts-ignore + self.postMessage({id: e.data.id, action: e.data.action, results: arr},[arr]); } } @@ -81,6 +85,30 @@ function createView(sql: string) { return res; } +function queryArrayBuffer(name: string, sql: string, params: any) { + if (params) { + Reflect.ownKeys(params).forEach((key: any) => { + if (typeof params[key] === "string") { + sql = sql.replace(new RegExp(`\\${key}`, "g"), `'${params[key]}'`); + } else { + sql = sql.replace(new RegExp(`\\${key}`, "g"), params[key]); + } + }); + } + let arr: Array = [] + let enc = new TextEncoder(); + let dec = new TextDecoder(); + let sqlPtr = Module._malloc(sql.length); + let outPtr = Module._malloc(REQ_BUF_SIZE); + Module.HEAPU8.set(enc.encode(sql), sqlPtr); + let res = Module._TraceStreamerSqlQuery(sqlPtr, sql.length, outPtr, REQ_BUF_SIZE); + let out = Module.HEAPU8.subarray(outPtr, outPtr + res); + Module._free(sqlPtr); + Module._free(outPtr); + out = out.buffer.slice(out.byteOffset, out.byteLength + out.byteOffset) + return out; +} + function query(name: string, sql: string, params: any) { if (params) { Reflect.ownKeys(params).forEach((key: any) => { @@ -97,13 +125,15 @@ function query(name: string, sql: string, params: any) { let sqlPtr = Module._malloc(sql.length); let outPtr = Module._malloc(REQ_BUF_SIZE); Module.HEAPU8.set(enc.encode(sql), sqlPtr); - let a = new Date().getTime(); let res = Module._TraceStreamerSqlQuery(sqlPtr, sql.length, outPtr, REQ_BUF_SIZE); let out = Module.HEAPU8.subarray(outPtr, outPtr + res); let str = dec.decode(out); Module._free(sqlPtr); Module._free(outPtr); str = str.substring(str.indexOf("\n") + 1); + if (!str) { + return [] + } let parse = JSON.parse(str); let columns = parse.columns; let values = parse.values; diff --git a/host/ide/src/trace/database/TraceWorkerRoot.ts b/host/ide/src/trace/database/TraceWorkerRoot.ts new file mode 100644 index 0000000000000000000000000000000000000000..cbde9ebed90bf834997a69f93fa8fcc6bac33cfa --- /dev/null +++ b/host/ide/src/trace/database/TraceWorkerRoot.ts @@ -0,0 +1,36 @@ +/* + * 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. + */ + +let worker:Worker; +self.onmessage = (e)=>{ + if (e.data.action === "open") { + worker = new Worker("TraceWorker.js") + worker.onmessage = (msg)=>{ + self.postMessage(msg.data); + } + worker.postMessage(e.data,[e.data.buffer]); + } else if (e.data.action === "exec") { + worker.postMessage(e.data); + } else if (e.data.action == "exec-buf") { + // @ts-ignore + worker.postMessage(e.data); + } +} +self.onerror = event => { + worker.terminate(); +} +self.onclose = () => { + worker.terminate(); +} \ No newline at end of file diff --git a/host/ide/src/trace/grpc/HiProfilerClient.ts b/host/ide/src/trace/grpc/HiProfilerClient.ts index c4bbdb0672dee199ec09b4ac0285b01da95362fa..2375eca41581eaea6e27cba3e28dbede335414c6 100644 --- a/host/ide/src/trace/grpc/HiProfilerClient.ts +++ b/host/ide/src/trace/grpc/HiProfilerClient.ts @@ -12,12 +12,18 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import {Address, ProfilerClient} from "./ProfilerClient.js"; export class HiProfilerClient { private _client: ProfilerClient; private _address: Address; + public constructor(clients: ProfilerClient, addr: Address) { + this._client = clients; + this._address = addr; + }; + get client(): ProfilerClient { return this._client; } @@ -34,13 +40,8 @@ export class HiProfilerClient { this._address = value; } - public constructor(clients: ProfilerClient, addr: Address) { - this._client = clients; - this._address = addr; - }; - - public getProfilerClient(): ProfilerClient{ - return this._client; + public getProfilerClient(): ProfilerClient { + return this._client; } public getCapabilities() { diff --git a/host/ide/src/trace/grpc/ProfilerClient.ts b/host/ide/src/trace/grpc/ProfilerClient.ts index 73f01998fa2ae0acd0723ca47055d33d614c2060..25038dc82d17cdf214a31591ec51145fc461263f 100644 --- a/host/ide/src/trace/grpc/ProfilerClient.ts +++ b/host/ide/src/trace/grpc/ProfilerClient.ts @@ -12,122 +12,107 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + import * as path from 'path'; -const profilerServicePath = path.join(__dirname,'../proto', 'profiler_service.proto'); +const profilerServicePath = path.join(__dirname, '../proto', 'profiler_service.proto'); export class ProfilerClient { - // proto filePaths - private _filePaths: Array | undefined; - // client - private _client: any; - // profiler_proto - private _profiler_proto: any; - // ProfilerClient constructor - public constructor(address: Address) { - // load client port - let clientPort = this.loadAddress(address); - // load proto file - this.start(clientPort, profilerServicePath); - }; - - get filePaths(): Array | undefined { - return this._filePaths; - } - - set filePaths(value: Array | undefined) { - this._filePaths = value; - } - - get client(): any { - return this._client; - } - - set client(value: any) { - this._client = value; - } - - get profiler_proto(): any { - return this._profiler_proto; - } - - set profiler_proto(value: any) { - this._profiler_proto = value; - } - - start(address: string, filePath: string){ - // let loadPackage = proto_load.loadSync( - // filePath, - // { - // keepCase: true, - // longs: String, - // enums: String, - // defaults: true, - // oneofs: true - // } - // ); - // // profiler Proto - // this._profiler_proto = rpc.loadPackageDefinition(loadPackage); - // // get profilerProto service - // let profilerProto = this._profiler_proto.profiler; - // // client - // this._client = new profilerProto.IProfilerService('127.0.0.1:5555', rpc.credentials.createInsecure()); - } - - // Address - loadAddress(clientAddress: Address): string{ - return clientAddress.host + ':' + clientAddress.port; - }; - - public getProfilerClient(callback: any): any{ - return this._client; - }; - - public getCapabilities(callback: any) { - this._client. - this._client.getCapabilities(callback); - callback(); - }; - - public createSession(callback: any) { - this._client.createSession(callback); - callback(); - }; - - public startSession(callback: any) { - this._client.startSession(callback); - callback(); - }; - - public stopSession(callback: any) { - this._client.stopSession(callback); - callback(); - }; - - public destroySession(callback: any) { - this._client.destroySession(callback); - callback(); - }; - - public keepSession(callback: any) { - this._client.keepSession(callback); - callback(); - }; - - public shutdown(): void { - - }; - - public getChannel() { - return this._client.channelInterpretation; - }; + // proto filePaths + private _filePaths: Array | undefined; + // client + private _client: any; + // profiler_proto + private _profiler_proto: any; + + // ProfilerClient constructor + public constructor(address: Address) { + // load client port + let clientPort = this.loadAddress(address); + // load proto file + this.start(clientPort, profilerServicePath); + }; + + get filePaths(): Array | undefined { + return this._filePaths; + } + + set filePaths(value: Array | undefined) { + this._filePaths = value; + } + + get client(): any { + return this._client; + } + + set client(value: any) { + this._client = value; + } + + get profiler_proto(): any { + return this._profiler_proto; + } + + set profiler_proto(value: any) { + this._profiler_proto = value; + } + + start(address: string, filePath: string) { + } + + // Address + loadAddress(clientAddress: Address): string { + return clientAddress.host + ':' + clientAddress.port; + }; + + public getProfilerClient(callback: any): any { + return this._client; + }; + + public getCapabilities(callback: any) { + this._client.this._client.getCapabilities(callback); + callback(); + }; + + public createSession(callback: any) { + this._client.createSession(callback); + callback(); + }; + + public startSession(callback: any) { + this._client.startSession(callback); + callback(); + }; + + public stopSession(callback: any) { + this._client.stopSession(callback); + callback(); + }; + + public destroySession(callback: any) { + this._client.destroySession(callback); + callback(); + }; + + public keepSession(callback: any) { + this._client.keepSession(callback); + callback(); + }; + + public shutdown(): void { + + }; + + public getChannel() { + return this._client.channelInterpretation; + }; } export interface Address { - // port - port: string | number; + // port + port: string | number; - // host - host?: string | number; + // host + host?: string | number; } diff --git a/host/ide/src/trace/grpc/ProfilerController.ts b/host/ide/src/trace/grpc/ProfilerController.ts index bbc186a0c4b0dcccbba554244a326c6db99b5c85..941709da605d862edc504226b5277aa4b7e1c725 100644 --- a/host/ide/src/trace/grpc/ProfilerController.ts +++ b/host/ide/src/trace/grpc/ProfilerController.ts @@ -12,28 +12,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + export class ClientContainer { - // private _credentials: rpc.ChannelCredentials | undefined; - // private _clients: { service: any, client?: rpc.Client, target: any }[] = []; private _port: string | number | undefined; private _host: string | undefined; - /* get clients(): { service: any; client?: rpc.Client; target: any }[] { - return this._clients; - } - - set clients(value: { service: any; client?: rpc.Client; target: any }[]) { - this._clients = value; - }*/ - - /* get credentials(): rpc.ChannelCredentials | undefined { - return this._credentials; - } - - set credentials(value: rpc.ChannelCredentials | undefined) { - this._credentials = value; - }*/ - get port(): string | number | undefined { return this._port; } @@ -51,21 +34,6 @@ export class ClientContainer { } public registryClient(target: any, path: string) { - // let packageDefinition = proto_load.loadSync(path, { - // keepCase: true, - // longs: String, - // enums: String, - // defaults: true, - // oneofs: true - // }); - // let protoDescriptor = rpc.loadPackageDefinition(packageDefinition); - // - // const packages = Object.keys(protoDescriptor); - // for (let packageKey of packages) { - // for (let key in protoDescriptor[packageKey]) { - // - // } - // } }; public start() { @@ -74,23 +42,15 @@ export class ClientContainer { } private loadSettings() { - let { host, port} = SettingRegistry.settings; + let {host, port} = SettingRegistry.settings; this._host = host; this._port = port; } private _registryClient() { - // for (let clientContainer of this._clients) { - // let client: rpc.Client = new clientContainer.service( - // `${this.host}:${this.port}`, - // this.credentials - // ); - // clientContainer.client = client; - // } } } - export class SettingRegistry { static settings: Settings; diff --git a/host/ide/test/base-ui/checkbox/LitCheckBox.test.ts b/host/ide/test/base-ui/checkbox/LitCheckBox.test.ts index 3512ce08425f9a10ee6a9330ff3b4779a247025e..79972fbf76e65e5c0b05dcac410ad544a18db408 100644 --- a/host/ide/test/base-ui/checkbox/LitCheckBox.test.ts +++ b/host/ide/test/base-ui/checkbox/LitCheckBox.test.ts @@ -57,4 +57,105 @@ describe('checkBox Test', ()=>{ litCheckBox.checked = false expect(litCheckBox.checked).toBeFalsy(); }); + it('checkBoxTest06', function () { + document.body.innerHTML = ` + ` + let litCheckBox = new LitCheckBox(); + litCheckBox.indeterminate = false + expect(litCheckBox.indeterminate).toBeFalsy(); + }); + + it('checkBoxTest07', function () { + document.body.innerHTML = ` + ` + let litCheckBox = new LitCheckBox(); + litCheckBox.indeterminate = true + expect(litCheckBox.indeterminate).toBeTruthy(); + }); + + it('checkBoxTest08', function () { + let litCheckBox = new LitCheckBox(); + expect(litCheckBox.initHtml()).toMatchInlineSnapshot(` +" + + + + " +`); + }); }) \ No newline at end of file diff --git a/host/ide/test/base-ui/checkbox/LitCheckBoxWithText.test.ts b/host/ide/test/base-ui/checkbox/LitCheckBoxWithText.test.ts index 271b2437f6cf61c15a193536602f04da7df598dc..5d4b5bb400a70db954770f90e7a84683326add04 100644 --- a/host/ide/test/base-ui/checkbox/LitCheckBoxWithText.test.ts +++ b/host/ide/test/base-ui/checkbox/LitCheckBoxWithText.test.ts @@ -55,18 +55,65 @@ describe('checkBoxWithText Test', ()=>{ it('checkBoxWithTextTest05', function () { let litCheckBoxWithText = new LitCheckBoxWithText(); - expect(litCheckBoxWithText.lowerlimit).toEqual(undefined); + expect(litCheckBoxWithText.lowerLimit).toEqual("0"); }); it('checkBoxWithTextTest05', function () { let litCheckBoxWithText = new LitCheckBoxWithText(); - litCheckBoxWithText.lowerlimit = "111" - expect(litCheckBoxWithText.lowerlimit).toEqual("111"); + litCheckBoxWithText.lowerLimit = "111" + expect(litCheckBoxWithText.lowerLimit).toEqual("111"); }); it('checkBoxWithTextTest05', function () { let litCheckBoxWithText = new LitCheckBoxWithText(); - litCheckBoxWithText.uplimit = "111" - expect(litCheckBoxWithText.uplimit).toEqual("111"); + litCheckBoxWithText.upLimit = "111" + expect(litCheckBoxWithText.upLimit).toEqual("111"); + }); + + it('checkBoxWithTextTest05', function () { + let litCheckBoxWithText = new LitCheckBoxWithText(); + expect(litCheckBoxWithText.initHtml()).toMatchInlineSnapshot(` +" + + + + + " +`); + }); + + it('checkBoxWithTextTest06', function () { + let litCheckBoxWithText = new LitCheckBoxWithText(); + expect(litCheckBoxWithText.attributeChangedCallback("checked")).toBeUndefined(); + }); + + it('checkBoxWithTextTest07', function () { + let litCheckBoxWithText = new LitCheckBoxWithText(); + expect(litCheckBoxWithText.attributeChangedCallback("text")).toBeUndefined(); + }); + + it('checkBoxWithTextTest08', function () { + let litCheckBoxWithText = new LitCheckBoxWithText(); + expect(litCheckBoxWithText.attributeChangedCallback("lowerLimit")).toBeUndefined(); + }); + + it('checkBoxWithTextTest09', function () { + let litCheckBoxWithText = new LitCheckBoxWithText(); + expect(litCheckBoxWithText.attributeChangedCallback("upLimit")).toBeUndefined(); }); }) \ No newline at end of file diff --git a/host/ide/test/base-ui/checkbox/LitCheckGroup.test.ts b/host/ide/test/base-ui/checkbox/LitCheckGroup.test.ts index 57bd9df3cf91d8dfbdc5d6208844b4f485058142..02ce41c34d17a3ed012186c0a21e5dc21cbcf585 100644 --- a/host/ide/test/base-ui/checkbox/LitCheckGroup.test.ts +++ b/host/ide/test/base-ui/checkbox/LitCheckGroup.test.ts @@ -36,4 +36,33 @@ describe('LitCheckGroup Test', ()=>{ expect(litCheckGroup.value).toEqual([]); }); + it('LitCheckGroupTest03', function () { + let litCheckGroup = new LitCheckGroup(); + expect(litCheckGroup.initHtml()).toMatchInlineSnapshot(` +" + + " +`); + }); + }) \ No newline at end of file diff --git a/host/ide/test/base-ui/icon/LitIcon.test.ts b/host/ide/test/base-ui/icon/LitIcon.test.ts index dd3ab13755303d49378248bf0e2ab9c11efbf49b..63aca5ddbed04942dcd2137deaff984e4776b471 100644 --- a/host/ide/test/base-ui/icon/LitIcon.test.ts +++ b/host/ide/test/base-ui/icon/LitIcon.test.ts @@ -56,4 +56,43 @@ describe("testLitIcon Test", () => { litIcon.name = "sss" expect(litIcon.name).toBe("sss") }); + + it('testLitIcon07', () => { + let litIcon = new LitIcon(); + expect(litIcon.color = "#FFF").not.toBeUndefined(); + }); + + it('testLitIcon07', () => { + let litIcon = new LitIcon(); + expect(litIcon.initHtml()).toMatchInlineSnapshot(` +" + + + + + " +`); + }); }) diff --git a/host/ide/test/base-ui/menu/LitMainMenu.test.ts b/host/ide/test/base-ui/menu/LitMainMenu.test.ts index dc0fc181d802969b974befe9817ab6548afb2e17..82e6963c3194f3da08fd68c1e7da8d74992b8915 100644 --- a/host/ide/test/base-ui/menu/LitMainMenu.test.ts +++ b/host/ide/test/base-ui/menu/LitMainMenu.test.ts @@ -56,4 +56,80 @@ describe("LitMainMenu Test", () => { ] expect(litMainMenu.menus.length).toBe(1) }); + + it('LitMainMenu03', () => { + let litMainMenu = new LitMainMenu(); + expect(litMainMenu.initHtml()).toMatchInlineSnapshot(` +" + +
+ +
+ +
+
+
+ +
+
+
+ " +`); + }); }) diff --git a/host/ide/test/base-ui/menu/LitMainMenuGroup.test.ts b/host/ide/test/base-ui/menu/LitMainMenuGroup.test.ts index 5c870524864714552a9681c2eb18b4afe5ae838c..915a9fcdd2524cda457d055e02f87f8336eacf65 100644 --- a/host/ide/test/base-ui/menu/LitMainMenuGroup.test.ts +++ b/host/ide/test/base-ui/menu/LitMainMenuGroup.test.ts @@ -36,9 +36,97 @@ describe("litMainMenuGroup Test", () => { expect(litMainMenuGroup.collapsed).toBeTruthy() }); - it('litMainMenuGroup03', () => { + it('litMainMenuGroup04', () => { let litMainMenuGroup = new LitMainMenuGroup(); litMainMenuGroup.collapsed = false expect(litMainMenuGroup.collapsed).toBeFalsy() }); + + it('litMainMenuGroup06', () => { + let litMainMenuGroup = new LitMainMenuGroup(); + expect(litMainMenuGroup.radius).toBeFalsy() + }); + + it('litMainMenuGroup07', () => { + let litMainMenuGroup = new LitMainMenuGroup(); + expect(litMainMenuGroup.initHtml()).toMatchInlineSnapshot(` +" + +
+
+ + " +`); + }); + + it('litMainMenuGroup04', () => { + let litMainMenuGroup = new LitMainMenuGroup(); + litMainMenuGroup.nocollapsed = true + expect(litMainMenuGroup.nocollapsed).toBeTruthy() + }); + + it('litMainMenuGroup04', () => { + let litMainMenuGroup = new LitMainMenuGroup(); + litMainMenuGroup.nocollapsed = false + expect(litMainMenuGroup.nocollapsed).toBeFalsy() + }); + + it('litMainMenuGroup05', () => { + let litMainMenuGroup = new LitMainMenuGroup(); + expect(litMainMenuGroup.collapsed).toBeFalsy() + }); }) diff --git a/host/ide/test/base-ui/menu/LitMainMenuItem.test.ts b/host/ide/test/base-ui/menu/LitMainMenuItem.test.ts index 4dc93a17147dad3337b1f7d8715777aa0d0ac8d7..45cf99fe9567cff88a42d630e7034382b760510d 100644 --- a/host/ide/test/base-ui/menu/LitMainMenuItem.test.ts +++ b/host/ide/test/base-ui/menu/LitMainMenuItem.test.ts @@ -51,4 +51,100 @@ describe("litMainMenuItem Test", () => { litMainMenuItem.title ="test03" expect(litMainMenuItem.title).toEqual("test03") }); + + it('litMainMenuItem06', () => { + document.body.innerHTML = ` + ` + let litMainMenuItem = new LitMainMenuItem(); + expect(litMainMenuItem.isFile()).toBeFalsy(); + }); + + it('litMainMenuItem07', () => { + document.body.innerHTML = ` + ` + let litMainMenuItem = new LitMainMenuItem(); + litMainMenuItem.disabled = true; + expect(litMainMenuItem.disabled).toBeTruthy(); + }); + + it('litMainMenuItem08', () => { + document.body.innerHTML = ` + ` + let litMainMenuItem = new LitMainMenuItem(); + litMainMenuItem.disabled = false; + expect(litMainMenuItem.disabled).toBeFalsy(); + }); + + it('litMainMenuItem09', () => { + let litMainMenuItem = new LitMainMenuItem(); + expect(litMainMenuItem.initHtml()).toMatchInlineSnapshot(` +" + + + + " +`); + }); }) diff --git a/host/ide/test/base-ui/popover/LitPopContent.test.ts b/host/ide/test/base-ui/popover/LitPopContent.test.ts index b21ca9bbe6a7ab54ae05c5436ca6089a976a999a..83288e4412d1c4dcfd8eb46452f27ba2e4f16ad9 100644 --- a/host/ide/test/base-ui/popover/LitPopContent.test.ts +++ b/host/ide/test/base-ui/popover/LitPopContent.test.ts @@ -49,4 +49,46 @@ describe("LitPopCont Test", () => { litPopContent.name = "11" expect(litPopContent.name).toEqual("11") }); + + it('LitPopCont05', () => { + let litPopContent = new LitPopContent(); + expect(litPopContent.initHtml()).toMatchInlineSnapshot(` +" + +
+ +
+ " +`); + }); + + it('LitPopCont06', () => { + let litPopContent = new LitPopContent(); + expect(litPopContent.attributeChangedCallback("open","",null || "false")).toBeUndefined() + }); }) diff --git a/host/ide/test/base-ui/popover/LitPopover.test.ts b/host/ide/test/base-ui/popover/LitPopover.test.ts index a8be4f48cc2a9b0df11221286b0572cfc5be2e2c..0b9966f4759ef15ad5244d69e1aa4322f250e3ec 100644 --- a/host/ide/test/base-ui/popover/LitPopover.test.ts +++ b/host/ide/test/base-ui/popover/LitPopover.test.ts @@ -93,4 +93,330 @@ describe("LitPopover Test", () => { }] expect(litPopover.select).toEqual(["# Samples"]) }); + + it('LitPopover10', () => { + let litPopover = new LitPopover(); + litPopover.type = "multiple-text" + litPopover.title = "tee" + litPopover.dataSource = [{ + text: "# Samples", + isSelected: true + }] + expect(litPopover.trigger).not.toBeUndefined(); + }); + + it('LitPopover10', () => { + let litPopover = new LitPopover(); + litPopover.type = "multiple-text" + litPopover.title = "tee" + litPopover.dataSource = [{ + text: "# Samples", + isSelected: true + }] + expect(litPopover.limit).toEqual({textLowerLimit:"0",textUpperLimit:"∞"}); + }); + + it('LitPopover11', () => { + let litPopover = new LitPopover(); + litPopover.type = "multiple-text" + litPopover.title = "tee" + litPopover.dataSource = [{ + text: "# Samples", + isSelected: false + }] + expect(litPopover.limit).toEqual({textLowerLimit:"0",textUpperLimit:"∞"}); + }); + + it('LitPopover14', () => { + let litPopover = new LitPopover(); + litPopover.type = "data-ming" + litPopover.title = "tee" + litPopover.dataSource = [{ + text: "# Samples", + isSelected: false + }] + expect(litPopover.limit).toEqual({textLowerLimit:"",textUpperLimit:""}); + }); + + it('LitPopover12', () => { + let litPopover = new LitPopover(); + expect(litPopover.initHtml()).toMatchInlineSnapshot(` +" + + + " +`); + }); + + it('LitPopover13', () => { + let litPopover = new LitPopover(); + expect(litPopover.connectedCallback()).toBeUndefined() + }); }) diff --git a/host/ide/test/base-ui/popover/LitPopoverV.test.ts b/host/ide/test/base-ui/popover/LitPopoverV.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..dd9c9780fc7d13336c19166923584400f6598efb --- /dev/null +++ b/host/ide/test/base-ui/popover/LitPopoverV.test.ts @@ -0,0 +1,441 @@ +/* + * 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. + */ + +// @ts-ignore +import {LitPopover} from "../../../dist/base-ui/popover/LitPopoverV.js"; + +describe("LitPopoverV Test", () => { + it('LitPopoverV01', () => { + let litPopover = new LitPopover(); + expect(litPopover).not.toBeUndefined() + expect(litPopover).not.toBeNull() + }); + it('LitPopoverV02', () => { + let litPopoverV = new LitPopover(); + expect(litPopoverV.visible).toBe("false"); + }); + it('LitPopoverV03', () => { + let litPopoverV = new LitPopover(); + litPopoverV.visible = true; + expect(litPopoverV.visible).toBe("true"); + }); + it('LitPopoverV04', () => { + let litPopoverV = new LitPopover(); + litPopoverV.visible = false; + expect(litPopoverV.visible).toBe("false"); + }); + it('LitPopoverV05', () => { + let litPopoverV = new LitPopover(); + expect(litPopoverV.trigger).toBe("hover"); + }); + it('LitPopoverV06', () => { + let litPopoverV = new LitPopover(); + litPopoverV.trigger = "click"; + expect(litPopoverV.trigger).toBe("click"); + }); + + it('LitPopoverV07', () => { + let litPopoverV = new LitPopover(); + litPopoverV.title = "test"; + expect(litPopoverV.title).toBe("test"); + }); + + it('LitPopoverV08', () => { + let litPopoverV = new LitPopover(); + litPopoverV.width = "10px"; + expect(litPopoverV.width).toBe("10px"); + }); + + it('LitPopoverV09', () => { + let litPopoverV = new LitPopover(); + litPopoverV.width = "10px"; + expect(litPopoverV.width).toBe("10px"); + }); + + it('LitPopoverV10', () => { + let litPopoverV = new LitPopover(); + expect(litPopoverV.width).toBe("max-content"); + }); + + + it('LitPopoverV11', () => { + let litPopoverV = new LitPopover(); + expect(litPopoverV.haveRadio).toBeNull(); + }); + + it('LitPopoverV12', () => { + document.body.innerHTML = `` + let popver = document.querySelector("#litpop") as LitPopover; + expect(popver.haveRadio).toBeNull(); + }); + + it('LitPopoverV13', () => { + let litPopoverV = new LitPopover(); + expect(litPopoverV.initHtml()).toMatchInlineSnapshot(` +" + + +
+
null
+
+
+ + " +`); + }); +}); \ No newline at end of file diff --git a/host/ide/test/base-ui/progress-bar/LitProgressBar.test.ts b/host/ide/test/base-ui/progress-bar/LitProgressBar.test.ts index 0f2f37d313c34438c46b524784c12b6e177b0e64..5cd62a629e055621a0d822a7d00a658233ed4e48 100644 --- a/host/ide/test/base-ui/progress-bar/LitProgressBar.test.ts +++ b/host/ide/test/base-ui/progress-bar/LitProgressBar.test.ts @@ -21,7 +21,58 @@ describe('LitProgressBar Test', ()=>{ litProgressBar.loading = '' litProgressBar.loading = 'load' - it('LitProgressBarTest03', ()=>{ + it('LitProgressBarTest01', ()=>{ expect(litProgressBar.loading).toBeTruthy(); }) + + it('LitProgressBarTest02', ()=>{ + expect(litProgressBar.initHtml()).toMatchInlineSnapshot(` +" + +
+
+
+
+ " +`); + }) }) diff --git a/host/ide/test/base-ui/radiobox/LitRadioBox.test.ts b/host/ide/test/base-ui/radiobox/LitRadioBox.test.ts index 7bd211a9d4b35cc0ba2c08f92e8e3127c4112739..c41a42e2f026837d68e4734ea780801e1e1e2641 100644 --- a/host/ide/test/base-ui/radiobox/LitRadioBox.test.ts +++ b/host/ide/test/base-ui/radiobox/LitRadioBox.test.ts @@ -37,8 +37,175 @@ describe('LitRadioBox Test', ()=>{ expect(litRadioBox.value).toBe('value'); }) + it('LitRadioBoxTest03', ()=>{ + expect(litRadioBox.initHtml()).toMatchInlineSnapshot(` +" + + + + " +`); + }) + it('litRadioGroupTest01', ()=>{ let isReturn = litRadioGroup.value.length == 0 expect(isReturn).toBeTruthy(); }) + + it('litRadioGroupTest02', ()=>{ + expect(litRadioGroup.initHtml()).toMatchInlineSnapshot(` +" + + " +`); + }) }) diff --git a/host/ide/test/base-ui/select/LitSelect.test.ts b/host/ide/test/base-ui/select/LitSelect.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..5d8e0be992161b556b6994284c5b016bbd3714c4 --- /dev/null +++ b/host/ide/test/base-ui/select/LitSelect.test.ts @@ -0,0 +1,374 @@ +/* + * 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. + */ + +// @ts-ignore +import {LitButton, LitSelect} from "../../../dist/base-ui/select/LitSelect.js"; + +describe('LitSelect Test', ()=>{ + + it('LitSelectTest01', function () { + let litSelect = new LitSelect(); + expect(litSelect).not.toBeUndefined() + }); + + it('LitSelectTest02', function () { + document.body.innerHTML = `` + let select = document.querySelector("#litSelect") as LitSelect; + expect(select).not.toBeUndefined() + }); + + it('LitSelectTest03', function () { + document.body.innerHTML = `` + let select = document.querySelector("#litSelect") as LitSelect; + select.value = "value" + expect(select.value).toBe('value'); + }); + + it('LitSelectTest04', function () { + document.body.innerHTML = `` + let select = document.querySelector("#litSelect") as LitSelect; + select.border = "value" + expect(select.border).toBe('true'); + }); + it('LitSelectTest05', function () { + let lit = new LitSelect(); + expect(lit.border).toBe('true'); + }); + it('LitSelectTest06', function () { + document.body.innerHTML = `` + let select = document.querySelector("#litSelect") as LitSelect; + select.listHeight = true; + expect(select.listHeight).toBe('true'); + }); + + it('LitSelectTest07', function () { + document.body.innerHTML = `` + let select = document.querySelector("#litSelect") as LitSelect; + select.defaultValue = true; + expect(select.defaultValue).toBe('true'); + }); + + it('LitSelectTest08', function () { + document.body.innerHTML = `` + let select = document.querySelector("#litSelect") as LitSelect; + select.loading = 1 + expect(select.loading).toBe(true); + }); + + it('LitSelectTest09', function () { + document.body.innerHTML = `` + let select = document.querySelector("#litSelect") as LitSelect; + expect(select.isMultiple()).toBe(false); + }); + + it('LitSelectTest10', function () { + document.body.innerHTML = `` + let select = document.querySelector("#litSelect") as LitSelect; + select.inputElement.value = "3333"; + select.click(); + expect(select.focused).toBe(true); + }); + + it('LitSelectTest11', function () { + document.body.innerHTML = `` + let select = document.querySelector("#litSelect") as LitSelect; + select.clear() + expect(select.inputElement.value).toBe(""); + }); + + it('LitSelectTest12', function () { + document.body.innerHTML = `` + let select = document.querySelector("#litSelect") as LitSelect; + expect(select.reset()).toBeUndefined(); + }); + + it('LitSelectTest13', function () { + document.body.innerHTML = `` + let select = document.querySelector("#litSelect") as LitSelect; + let newTag =select.newTag("111","111"); + expect(newTag.text).toBe("111"); + }); + + it('LitSelectTest14', function () { + document.body.innerHTML = `` + let select = document.querySelector("#litSelect") as LitSelect; + select.dataSource = [{key:"111"}] + let cleart = select.clearElement as HTMLElement; + cleart.click() + expect(select.inputElement.value).toBe(""); + + }); + + it('LitSelectTest15', function () { + document.body.innerHTML = `` + let select = document.querySelector("#litSelect") as LitSelect; + let input = select.inputElement as HTMLInputElement; + input.value = "11" + expect(select.inputElement.value).toBe("11"); + + }); + + it('LitSelectTest16', function () { + document.body.innerHTML = `` + let select = document.querySelector("#litSelect") as LitSelect; + select.dataSource = [{key:"111"}] + expect(select.inputElement.value).toBe(""); + + }); + + it('LitSelectTest17', function () { + document.body.innerHTML = `` + let select = document.querySelector("#litSelect") as LitSelect; + select.placeholder = true; + expect(select.placeholder).toBe('true'); + }); + it('LitSelectTest20', function () { + document.body.innerHTML = `` + let select = document.querySelector("#litSelect") as LitSelect; + select.rounded = 1 + expect(select.rounded).toBe(true); + }); + + it('LitSelectTest21', function () { + document.body.innerHTML = `` + let select = document.querySelector("#litSelect") as LitSelect; + select.placement = 1 + expect(select.placement).toBe("1"); + }); + + it('LitSelectTest18', function () { + let litSelect = new LitSelect(); + expect(litSelect.initHtml()).toMatchInlineSnapshot(` +" + +
+
+
+ + + + +
+
+ + +
+ " +`); + }); + + it('LitSelectTest23', function () { + document.body.innerHTML = `` + let select = document.querySelector("#litSelect") as LitSelect; + select.canInsert = true + expect(select.canInsert).toBeTruthy(); + }); +}) diff --git a/host/ide/test/base-ui/select/LitSelectOption.test.ts b/host/ide/test/base-ui/select/LitSelectOption.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..8096114a1daa6cc0b59c4f8ab619176c797fe4d7 --- /dev/null +++ b/host/ide/test/base-ui/select/LitSelectOption.test.ts @@ -0,0 +1,88 @@ +/* + * 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. + */ + +// @ts-ignore +import {LitSelectOption} from "../../../dist/base-ui/select/LitSelectOption.js"; + +describe('LitSelectOption Test', ()=> { + it('LitSelectOptionTest01', function () { + document.body.innerHTML = ""; + let inner = document.querySelector("#aa") as LitSelectOption; + expect(inner).not.toBeUndefined() + }); + it('LitSelectOptionTest03 ', function () { + expect(LitSelectOption.adoptedCallback).toBeUndefined() + + }); + + + it('LitSelectOption02', function () { + let litSelect = new LitSelectOption(); + expect(litSelect.initHtml()).toMatchInlineSnapshot(` +" + +
+ +
+ + + " +`); + }); +}); \ No newline at end of file diff --git a/host/ide/test/base-ui/slider/LitSlider.test.ts b/host/ide/test/base-ui/slider/LitSlider.test.ts index d05e457757270f7c444a7ffd859e5cffc1e9120a..b866078626f85b4d780a3ee42cc60d3eff3aa9d5 100644 --- a/host/ide/test/base-ui/slider/LitSlider.test.ts +++ b/host/ide/test/base-ui/slider/LitSlider.test.ts @@ -26,10 +26,6 @@ describe('LitSlider Test', ()=>{ litSliderPanel.percent = 'percent' litSliderPanel.resultUnit = 'resultUnit' - litSliderPanel.litSlider = jest.fn(()=> true) - - litSliderPanel.sliderStyle = 'sliderStyle' - it('LitSliderTest01', ()=>{ expect(litSliderPanel.disabledX).toEqual(''); }) @@ -59,6 +55,10 @@ describe('LitSlider Test', ()=>{ }) it('LitSliderTest08', ()=>{ + litSliderPanel.litSliderStyle = jest.fn(()=>true) + litSliderPanel.litSliderStyle.minRange = jest.fn(()=>2) + litSliderPanel.litSliderStyle.maxRange = jest.fn(()=>1) + litSliderPanel.litSliderStyle.stepSize = jest.fn(()=>1) expect(litSliderPanel.renderDefaultSlider()).toBeUndefined(); }) @@ -67,10 +67,119 @@ describe('LitSlider Test', ()=>{ }) it('LitSliderTest10', ()=>{ - litSliderPanel.litSlider.removeEventListener = jest.fn(()=> true) - litSliderPanel.litSlider.removeEventListener = jest.fn(()=> true) - litSliderPanel.litSliderButton = jest.fn(()=> true) - litSliderPanel.litSliderButton.removeEventListener = jest.fn(()=> true) expect(litSliderPanel.disconnectedCallback()).toBeUndefined(); }) + + it('LitSliderTest11', ()=>{ + expect(litSliderPanel.disconnectedCallback()).toBeUndefined(); + }) + + it('LitSliderTest12', function () { + expect(litSliderPanel.attributeChangedCallback("percent","","0%" || null)).toBeUndefined(); + }); + + it('LitSliderTest13', function () { + expect(litSliderPanel.initHtml()).toMatchInlineSnapshot(` +" + + +
+ +
+ " +`); + }); }) diff --git a/host/ide/test/base-ui/switch/LitSwitch.test.ts b/host/ide/test/base-ui/switch/LitSwitch.test.ts index c0094b0a5583cee0b5d49cc45190e01327af11fa..fbc0144d69c4001b6b29419547b6af6b21fb4c23 100644 --- a/host/ide/test/base-ui/switch/LitSwitch.test.ts +++ b/host/ide/test/base-ui/switch/LitSwitch.test.ts @@ -20,6 +20,8 @@ describe('LitSwitch Test', ()=>{ let litSwitch = new LitSwitch(); litSwitch.checked = true litSwitch.checked = false + litSwitch.disabled = true + litSwitch.disabled =false it('LitSwitchTest01', ()=>{ expect(litSwitch.name).toBeNull(); @@ -53,4 +55,78 @@ describe('LitSwitch Test', ()=>{ it('LitSwitchTest08', ()=>{ expect(litSwitch.attributeChangedCallback('checked', 'disabled', null)).toBeUndefined() }) + + it('LitSwitchTest09', ()=>{ + expect(litSwitch.initHtml()).toMatchInlineSnapshot(` +" + + + " +`); + }) }) diff --git a/host/ide/test/base-ui/table/LitTable.test.ts b/host/ide/test/base-ui/table/LitTable.test.ts index b011898ce8c6729a0412d1ca8bdc8553e204cd3c..299fd49639e86ad82f3129cc963236026a5d1e33 100644 --- a/host/ide/test/base-ui/table/LitTable.test.ts +++ b/host/ide/test/base-ui/table/LitTable.test.ts @@ -15,8 +15,9 @@ // @ts-ignore import {LitTable} from "../../../dist/base-ui/table/lit-table.js"; +import {LitTableColumn} from "../../../src/base-ui/table/lit-table-column.js"; -describe('LitTable Test', ()=>{ +describe('LitTable Test', () => { let litTable = new LitTable(); litTable.selectable = true litTable.selectable = false @@ -27,59 +28,389 @@ describe('LitTable Test', ()=>{ litTable.dataSource = [{ id: 1, name: 'name' - },{ + }, { id: 2, name: 'nameValue' }] + const td = { + style: { + position: 'sticky', + left: '0px', + right: '0px', + boxShadow: '3px 0px 5px #33333333' + } + } + const placement = "left" - JSON.parse = jest.fn(()=>[['children', 'father'], ['children', 'father']]) + const element = { + style: { + display: 'none', + transform: 'translateY' + }, + childNodes:{forEach:true}, + onclick: 1 + } + const rowObject = { + children: { + length: 1, + }, + data: [{isSelected:undefined}], + depth: 1, + top: 1 + } + const firstElement = { + style: { + display: 'none', + paddingLeft: "", + transform: 'translateY' - litTable.columns = litTable.columns || jest.fn(()=>true) - litTable.ds = jest.fn(()=>[{ + }, + innerHTML: "", + title: "", + firstChild: null, + onclick: 1 + + }||undefined + + JSON.parse = jest.fn(() => [['children', 'father'], ['children', 'father']]) + + litTable.columns = litTable.columns || jest.fn(() => true) + litTable.ds = jest.fn(() => [{ id: 1, name: 'name' - },{ + }, { id: 2, name: 'nameValue' }]) - litTable.tbodyElement = jest.fn(()=> ({ + litTable.tbodyElement = jest.fn(() => ({ innerHTML: '' })) - litTable.tableColumns = jest.fn(()=>[]) + litTable.tableColumns = jest.fn(() => []) - litTable.tableColumns.forEach = jest.fn(()=>[]) + litTable.tableColumns.forEach = jest.fn(() => []) - it('LitTableTest01', ()=>{ + it('LitTableTest01', () => { expect(litTable.adoptedCallback()).toBeUndefined(); }) - it('LitTableTest02', ()=>{ - litTable.ds.forEach = jest.fn(()=> true) + it('LitTableTest02', () => { + litTable.ds.forEach = jest.fn(() => true) expect(litTable.renderTable()).toBeUndefined(); }) - // it('LitTableTest03', ()=>{ - // litTable.parentNode = jest.fn(()=> true) - // litTable.parentNode.append = jest.fn(()=> true) - // expect(litTable.renderTreeTable()).toBeUndefined(); - // }) - - it('LitTableTest04', ()=>{ + it('LitTableTest04', () => { litTable.switch = document.querySelector("#switch") as HTMLInputElement; expect(litTable.connectedCallback()).toBeUndefined() }) - it('LitTableTest05', ()=>{ + it('LitTableTest05', () => { let rowLength = litTable.getCheckRows().length == 0; expect(rowLength).toBeTruthy() }) - it('LitTableTest06', ()=>{ - expect(litTable.deleteRowsCondition(()=>{ + it('LitTableTest06', () => { + expect(litTable.deleteRowsCondition(() => { return true })).toBeUndefined() }) + + it('LitTableTest07', () => { + expect(litTable.selectable).not.toBeUndefined() + }) + + it('LitTableTest08', () => { + litTable.selectable = true + expect(litTable.selectable).toBeTruthy() + }) + + it('LitTableTest09', () => { + expect(litTable.scrollY).not.toBeUndefined() + }) + + it('LitTableTest10', () => { + expect(litTable.dataSource).not.toBeUndefined() + }) + + it('LitTableTest11', () => { + expect(litTable.recycleDataSource).not.toBeUndefined() + }) + + it('LitTableTest12', () => { + expect(litTable.fixed(td, placement)).toBeUndefined() + }) + + it('LitTableTest13', () => { + expect(litTable.fixed(td, "right")).toBe(undefined) + }) + + it('LitTableTest14', () => { + expect(litTable.meauseElementHeight()).toBe(27) + }) + + it('LitTableTest15', () => { + expect(litTable.meauseTreeElementHeight()).toBe(27) + }) + + it('LitTableTest16', () => { + document.body.innerHTML = "" + let table = document.querySelector("#tab") as LitTable; + let htmlElement = document.createElement('lit-table-column') as LitTableColumn; + htmlElement.setAttribute('title', "1"); + htmlElement.setAttribute('data-index', "1"); + htmlElement.setAttribute('key', "1"); + htmlElement.setAttribute('align', 'flex-start'); + htmlElement.setAttribute('height', '32px'); + table!.appendChild(htmlElement); + setTimeout(() => { + table.recycleDataSource = [{ + id: 1, + name: 'name' + }, { + id: 2, + name: 'nameValue' + }] + expect(table.meauseTreeElementHeight()).toBe(27) + }, 20) + }) + + it('LitTableTest17', () => { + expect(litTable.shadowRoot.innerHTML).toMatchInlineSnapshot(` +" + + + +
+
+
+
+
+
+
+ " +`); + }) + + it('LitTableTest18', () => { + expect(litTable.createExpandBtn({expanded:false})).not.toBeUndefined() + }) + + it('LitTableTest19', () => { + expect(litTable.reMeauseHeight()).toBeUndefined(); + }) + + it('LitTableTest20', () => { + const rowData= { + data:[{ + isSelected:undefined + }], + } + litTable.columns.forEach = jest.fn(()=>true) + expect(litTable.createNewTableElement(rowData)).not.toBeUndefined(); + }) + + it('LitTableTest21', () => { + expect(litTable.freshCurrentLine(element)).toBeUndefined(); + }) + + it('LitTableTest22', () => { + litTable.recycleDs.length = 1 + litTable.setCurrentSelection = jest.fn(()=>true) + expect(litTable.scrollToData()).toBeUndefined(); + }) + + it('LitTableTest23', () => { + expect(litTable.expandList()).toBeUndefined(); + }) + + it('LitTableTest24', () => { + expect(litTable.clearAllSelection()).toBeUndefined(); + }) + + it('LitTableTest25', () => { + expect(litTable.dispatchRowClickEvent({data:{isSelected:""}})).toBeUndefined(); + }) + + it('LitTableTest26', () => { + litTable.treeElement = jest.fn(()=>undefined) + litTable.treeElement.children = jest.fn(()=>[1]) + litTable.columns.forEach = jest.fn(()=>true) + litTable.treeElement.lastChild= jest.fn(()=>true) + litTable.treeElement.lastChild.style= jest.fn(()=>true) + expect(litTable.createNewTreeTableElement({data:""})).not.toBeUndefined(); + }); + + it('LitTableTest27', () => { + litTable.tableElement = jest.fn(()=>undefined) + litTable.tableElement.scrollTop = jest.fn(()=>1) + expect(litTable.move1px()).toBeUndefined(); + }) + + it('LitTableTest28', () => { + document.body.innerHTML = `` + let litTable = document.querySelector('#aaa') as LitTable + expect(litTable.renderTreeTable()).toBeUndefined(); + }) + + it('LitTableTest29', () => { + document.body.innerHTML = `` + let litTable = document.querySelector('#aaa') as LitTable + expect(litTable.setMouseIn(true,[])).toBeUndefined(); + }) + + it('LitTableTest30', () => { + document.body.innerHTML = `` + let litTable = document.querySelector('#aaa') as LitTable + const data = { + isSelected:true + } + expect(litTable.setCurrentSelection(data)).toBeUndefined(); + }) }) + diff --git a/host/ide/test/base-ui/table/LitTableColumn.test.ts b/host/ide/test/base-ui/table/LitTableColumn.test.ts index 6a1fc57dc499056ffd0f3af004f74369215f7ef8..3c4b6d7ccda569d8b5962ab562cae33b226b43ae 100644 --- a/host/ide/test/base-ui/table/LitTableColumn.test.ts +++ b/host/ide/test/base-ui/table/LitTableColumn.test.ts @@ -27,4 +27,18 @@ describe('LitTableGroup Test', ()=>{ it('LitTableGroupTest02', ()=>{ expect(litTableColumn.connectedCallback()).toBeUndefined(); }) + + it('LitTableGroupTest03', ()=>{ + expect(litTableColumn.shadowRoot.innerHTML).toMatchInlineSnapshot(` +" + + + " +`); + }) }) diff --git a/host/ide/test/base-ui/table/LitTableGroup.test.ts b/host/ide/test/base-ui/table/LitTableGroup.test.ts index 64ce85e320da07b7b950c46573f75cf6f71c57e3..6cda3ac11b5c2128f8814bf3ab562e498a7fb9e5 100644 --- a/host/ide/test/base-ui/table/LitTableGroup.test.ts +++ b/host/ide/test/base-ui/table/LitTableGroup.test.ts @@ -27,4 +27,15 @@ describe('LitTableGroup Test', ()=>{ it('LitTableGroupTest02', ()=>{ expect(litTableGroup.title).toBe('title'); }) + + it('LitTableGroupTest03', ()=>{ + expect(litTableGroup.shadowRoot.innerHTML).toMatchInlineSnapshot(` +" + + + " +`) + }) }) diff --git a/host/ide/test/base-ui/table/TableRowObject.test.ts b/host/ide/test/base-ui/table/TableRowObject.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..5864b8468d8db0f5dda06af4af37c8ceedb7e83a --- /dev/null +++ b/host/ide/test/base-ui/table/TableRowObject.test.ts @@ -0,0 +1,23 @@ +/* + * 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. + */ +// @ts-ignore +import {TableRowObject} from "../../../dist/base-ui/table/TableRowObject.js"; + +describe('TableRowObject Test', ()=>{ + + it('TableRowObjectTest01', ()=>{ + expect(new TableRowObject().top).toBe(0); + }) +}); \ No newline at end of file diff --git a/host/ide/test/base-ui/tabs/LitTabpane.test.ts b/host/ide/test/base-ui/tabs/LitTabpane.test.ts index 2094ef94c137d232e6a4d97626bc9ba32cd70a96..03884a6e1c1fc617c6cafe0e6f976a010e7411f4 100644 --- a/host/ide/test/base-ui/tabs/LitTabpane.test.ts +++ b/host/ide/test/base-ui/tabs/LitTabpane.test.ts @@ -20,7 +20,8 @@ describe('LitTabPane Test', ()=>{ let litTabPane = new LitTabpane(); litTabPane.tab = 'tab' - litTabPane.disabled = 'disabled' + litTabPane.disabled = null || false + litTabPane.disabled = !null || !false litTabPane.hidden = 'hidden' litTabPane.closeable = false litTabPane.key = 'key' @@ -40,14 +41,47 @@ describe('LitTabPane Test', ()=>{ it('LitTabPaneTest4', ()=>{ expect(litTabPane.disabled).toBeTruthy(); }) + it('LitTabPaneTest5', ()=>{ expect(litTabPane.hidden).toBeTruthy(); }) + it('LitTabPaneTest6', ()=>{ litTabPane.closeable = 'closeable' expect(litTabPane.closeable).toBeTruthy(); }) + it('LitTabPaneTest7', ()=>{ expect(litTabPane.key).toBe('key'); }) + + it('LitTabPaneTest9 ', function () { + expect(litTabPane.connectedCallback()).toBeUndefined() + + }); + + it('LitTabPaneTest10 ', function () { + expect(litTabPane.disconnectedCallback()).toBeUndefined() + + }); + + it('LitTabPaneTest11 ', function () { + expect(litTabPane.adoptedCallback()).toBeUndefined() + + }); + it('LitTabPaneTest8', ()=>{ + expect(litTabPane.initHtml()).toMatchInlineSnapshot(` +" + + + " +`); + }) }) diff --git a/host/ide/test/base-ui/tabs/LitTabs.test.ts b/host/ide/test/base-ui/tabs/LitTabs.test.ts index 06a740dbf6c48fc33908084313e0dbd1ed2b2385..c3f7e638c6bf3e9070fe5600e9dea951296e50a9 100644 --- a/host/ide/test/base-ui/tabs/LitTabs.test.ts +++ b/host/ide/test/base-ui/tabs/LitTabs.test.ts @@ -23,7 +23,8 @@ describe('LitSwitch Test', ()=>{ litTabs.mode = 'mode' litTabs.activekey = 'activekey' - litTabs.nav = jest.fn(()=>{ + + litTabs.nav = jest.fn(()=>{ let el = document.createElement('div'); let htmlDivElement = document.createElement('div'); htmlDivElement.setAttribute('class', 'nav-item[data-key=\'${key}\']') @@ -53,6 +54,10 @@ describe('LitSwitch Test', ()=>{ expect(litTabs.activekey).toBe('activekey'); }) + it('litTabsTest01', ()=>{ + expect(litTabs.onTabClick).toBeUndefined(); + }) + it('litTabsTest02', ()=>{ litTabs.nav = jest.fn(()=> true) litTabs.nav.querySelector = jest.fn(()=> { @@ -78,34 +83,47 @@ describe('LitSwitch Test', ()=>{ }) litTabs.nav.querySelectorAll = jest.fn(()=> true) - expect(litTabs.updateHidden('key', 'value')).toBeUndefined(); + expect(litTabs.updateHidden('key', "true")).toBeUndefined(); + }) + + it('litTabsTest13', ()=>{ + litTabs.nav = jest.fn(()=> true) + litTabs.nav.querySelector = jest.fn(()=> { + return document.createElement('div') as HTMLDivElement + }) + litTabs.nav.querySelectorAll = jest.fn(()=> true) + + expect(litTabs.updateHidden('key', !"true")).toBeUndefined(); }) it('litTabsTest05', ()=>{ expect(litTabs.initTabPos()).toBeUndefined(); }) - // it('litTabsTest07', ()=>{ + it('litTabsTest07', ()=>{ // litTabs.nav.querySelectorAll = jest.fn(()=> true) // litTabs.nav.querySelectorAll.forEach = jest.fn(()=> true) - // expect(litTabs.activeByKey('newKey')).toBeNull(); - // }) + expect(litTabs.activeByKey(null||undefined)).toBeUndefined(); + }) it('litTabsTest06', ()=>{ expect(litTabs.activePane('Key')).toBeFalsy(); }) - it('litTabsTest07', ()=>{ + it('litTabsTest007', ()=>{ expect(litTabs.connectedCallback()).toBeUndefined() }) it('litTabsTest8', ()=>{ - expect(litTabs.attributeChangedCallback('disabled', 'disabled', '')).toBeUndefined() + expect(litTabs.attributeChangedCallback('activekey', 'disabled', 'activekey')).toBeUndefined() }) it('litTabsTest9', ()=>{ expect(litTabs.adoptedCallback()).toBeUndefined(); }) + it('litTabsTest09', ()=>{ + expect(litTabs.disconnectedCallback()).toBeUndefined(); + }) it('litTabsTest10', ()=>{ expect(litTabs.position).toBe('position'); }) @@ -113,4 +131,387 @@ describe('LitSwitch Test', ()=>{ it('litTabsTest11', ()=>{ expect(litTabs.mode).toBe('mode'); }) + + it('litTabsTest12', ()=>{ + expect(litTabs.shadowRoot.innerHTML).toMatchInlineSnapshot(` +" + + +
+
+ +
+
+
+
+
+ +
+
+ NEED CONTENT +
+
+ " +`); + }) }) diff --git a/host/ide/test/log/Log.test.ts b/host/ide/test/log/Log.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..7dc33cdb80fe3a93a97e95f792697b152dfc08c2 --- /dev/null +++ b/host/ide/test/log/Log.test.ts @@ -0,0 +1,39 @@ +/* + * 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. + */ + +// @ts-ignore +import {debug, error, info, log, trace, warn} from "../../dist/log/Log.js"; + +describe(' logTest', () => { + + it('LogTest01', () => { + error("111") + }) + it('LogTest02', () => { + warn("111") + }) + it('LogTest03', () => { + info("111") + }) + it('LogTest04', () => { + debug("111") + }) + it('LogTest05', () => { + trace("111") + }) + it('LogTest05', () => { + log("111") + }) +}); \ No newline at end of file diff --git a/host/ide/test/trace/SpApplication.test.ts b/host/ide/test/trace/SpApplication.test.ts index c4817f6962f420c00f8a6cceecb5136120d1cfbb..303d8dd14c91108f4737a397b3f7094966917f2c 100644 --- a/host/ide/test/trace/SpApplication.test.ts +++ b/host/ide/test/trace/SpApplication.test.ts @@ -103,11 +103,269 @@ describe('spApplication Test', ()=>{ spApplication.vs = false; expect(spApplication.vs).toBeFalsy() }); + it('spApplicationTest20', function () { + let spApplication = new SpApplication(); + expect(spApplication.querySql).toBeFalsy() + }); it('spApplicationTest15',function (){ let spApplication = new SpApplication(); - expect(spApplication.freshMenuDisable).toBeTruthy() + expect(spApplication.freshMenuDisable()).toBeUndefined() + }) + + it('spApplicationTest16',function (){ + let spApplication = new SpApplication(); + expect(spApplication.addSkinListener()).toBeUndefined() + }) + + it('spApplicationTest17',function (){ + let spApplication = new SpApplication(); + expect(spApplication.removeSkinListener()).toBeUndefined() }) + it('spApplicationTest18',function (){ + document.body.innerHTML= "" + let element = document.querySelector("#sp") as SpApplication; + element.dispatchEvent(new Event("dragleave")) + }) + + it('spApplicationTest19',function (){ + document.body.innerHTML= "" + let element = document.querySelector("#sp") as SpApplication; + element.dispatchEvent(new Event("drop")) + //expect(SpApplication.removeSkinListener()).toBeUndefined() + }) + + it('spApplicationTest19',function (){ + document.body.innerHTML= "" + let element = document.querySelector("#sp") as SpApplication; + element.dispatchEvent(new Event("drop")) + //expect(SpApplication.removeSkinListener()).toBeUndefined() + }) + it('spApplicationTest21', function () { + let spApplication = new SpApplication(); + spApplication.showContent = true; + expect(spApplication.showContent).toBeTruthy() + }); + + it('spApplicationTest22', function () { + let spApplication = new SpApplication(); + spApplication.showConten = false; + expect(spApplication.showContent).toBeFalsy() + }); + + it('spApplicationTest23', function () { + let spApplication = new SpApplication(); + spApplication.openTraceFile = true; + expect(spApplication.openTraceFile).toBeTruthy() + }); + + it('spApplicationTest24', function () { + let spApplication = new SpApplication(); + spApplication.openTraceFile = false; + expect(spApplication.openTraceFile).toBeFalsy() + }); + + it('spApplicationTest25', function () { + let spApplication = new SpApplication(); + expect(spApplication.initHtml()).toMatchInlineSnapshot(` +" + +
+ +
+
+
+ + + +
+ +
+ +
+
+ + + + + + + + + +
+
+ " +`); + }); }) diff --git a/host/ide/test/trace/bean/AbilityMonitor.test.ts b/host/ide/test/trace/bean/AbilityMonitor.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..86b1823075cb9c31390a9a2761999e270cb524fa --- /dev/null +++ b/host/ide/test/trace/bean/AbilityMonitor.test.ts @@ -0,0 +1,390 @@ +/* + * 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. + */ +//@ts-ignore +import {SystemCpuSummary, SystemDiskIOSummary, ProcessHistory, LiveProcess, SystemNetworkSummary, SystemMemorySummary} from "../../../dist/trace/bean/AbilityMonitor.js" + +describe('AbilityMonitor Test', ()=>{ + let systemCpuSummary = new SystemCpuSummary(); + let systemDiskIOSummary = new SystemDiskIOSummary(); + let processHistory = new ProcessHistory(); + let liveProcess = new LiveProcess(); + let systemNetworkSummary = new SystemNetworkSummary(); + let systemMemorySummary = new SystemMemorySummary(); + + it('SystemCpuSummaryTest', function () { + systemCpuSummary = { + startTime: -1, + startTimeStr: "startTimeStr", + duration: -1, + durationStr: "durationStr", + totalLoad: -1, + totalLoadStr: "totalLoadStr", + userLoad: -1, + userLoadStr: "userLoadStr", + systemLoad: -1, + systemLoadStr: "systemLoadStr", + threads: -1, + threadsStr: "threadsStr", + }; + + expect(systemCpuSummary).not.toBeUndefined() + expect(systemCpuSummary).toMatchInlineSnapshot({ + startTime: expect.any(Number), + startTimeStr: expect.any(String), + duration: expect.any(Number), + durationStr: expect.any(String), + totalLoad: expect.any(Number), + totalLoadStr: expect.any(String), + userLoad: expect.any(Number), + userLoadStr: expect.any(String), + systemLoad: expect.any(Number), + systemLoadStr: expect.any(String), + threads: expect.any(Number), + threadsStr: expect.any(String) }, ` + Object { + "duration": Any, + "durationStr": Any, + "startTime": Any, + "startTimeStr": Any, + "systemLoad": Any, + "systemLoadStr": Any, + "threads": Any, + "threadsStr": Any, + "totalLoad": Any, + "totalLoadStr": Any, + "userLoad": Any, + "userLoadStr": Any, + } + `); + }); + + it('SystemCpuSummaryTest', function () { + systemDiskIOSummary = { + startTime: 1, + startTimeStr: "startTimeStr", + duration: 1, + durationStr: "durationStr", + dataRead: 1, + dataReadStr: "dataReadStr", + dataReadSec: 1, + dataReadSecStr: "dataReadSecStr", + dataWrite: 1, + dataWriteStr: "dataWriteStr", + dataWriteSec: 1, + dataWriteSecStr: "dataWriteSecStr", + readsIn: 1, + readsInStr: "readsInStr", + readsInSec: 1, + readsInSecStr: "readsInSecStr", + writeOut: 1, + writeOutStr: "writeOutStr", + writeOutSec: 1, + writeOutSecStr: "writeOutSecStr", + } + expect(systemDiskIOSummary).not.toBeUndefined(); + expect(systemDiskIOSummary).toMatchInlineSnapshot({ + startTime: expect.any(Number), + startTimeStr: expect.any(String), + duration: expect.any(Number), + durationStr: expect.any(String), + dataRead: expect.any(Number), + dataReadStr: expect.any(String), + dataReadSec: expect.any(Number), + dataReadSecStr: expect.any(String), + dataWrite: expect.any(Number), + dataWriteStr: expect.any(String), + dataWriteSec: expect.any(Number), + dataWriteSecStr: expect.any(String), + readsIn: expect.any(Number), + readsInStr: expect.any(String), + readsInSec: expect.any(Number), + readsInSecStr: expect.any(String), + writeOut: expect.any(Number), + writeOutStr: expect.any(String), + writeOutSec: expect.any(Number), + writeOutSecStr: expect.any(String) }, ` + Object { + "dataRead": Any, + "dataReadSec": Any, + "dataReadSecStr": Any, + "dataReadStr": Any, + "dataWrite": Any, + "dataWriteSec": Any, + "dataWriteSecStr": Any, + "dataWriteStr": Any, + "duration": Any, + "durationStr": Any, + "readsIn": Any, + "readsInSec": Any, + "readsInSecStr": Any, + "readsInStr": Any, + "startTime": Any, + "startTimeStr": Any, + "writeOut": Any, + "writeOutSec": Any, + "writeOutSecStr": Any, + "writeOutStr": Any, + } + `); + }); + + it('SystemCpuSummaryTest', function () { + systemDiskIOSummary = { + startTime: 1, + startTimeStr: "startTimeStr", + duration: 1, + durationStr: "durationStr", + dataRead: 1, + dataReadStr: "dataReadStr", + dataReadSec: 1, + dataReadSecStr: "dataReadSecStr", + dataWrite: 1, + dataWriteStr: "dataWriteStr", + dataWriteSec: 1, + dataWriteSecStr: "dataWriteSecStr", + readsIn: 1, + readsInStr: "readsInStr", + readsInSec: 1, + readsInSecStr: "readsInSecStr", + writeOut: 1, + writeOutStr: "writeOutStr", + writeOutSec: 1, + writeOutSecStr: "writeOutSecStr", + } + expect(systemDiskIOSummary).not.toBeUndefined(); + expect(systemDiskIOSummary).toMatchInlineSnapshot({ + startTime: expect.any(Number), + startTimeStr: expect.any(String), + duration: expect.any(Number), + durationStr: expect.any(String), + dataRead: expect.any(Number), + dataReadStr: expect.any(String), + dataReadSec: expect.any(Number), + dataReadSecStr: expect.any(String), + dataWrite: expect.any(Number), + dataWriteStr: expect.any(String), + dataWriteSec: expect.any(Number), + dataWriteSecStr: expect.any(String), + readsIn: expect.any(Number), + readsInStr: expect.any(String), + readsInSec: expect.any(Number), + readsInSecStr: expect.any(String), + writeOut: expect.any(Number), + writeOutStr: expect.any(String), + writeOutSec: expect.any(Number), + writeOutSecStr: expect.any(String) }, ` + Object { + "dataRead": Any, + "dataReadSec": Any, + "dataReadSecStr": Any, + "dataReadStr": Any, + "dataWrite": Any, + "dataWriteSec": Any, + "dataWriteSecStr": Any, + "dataWriteStr": Any, + "duration": Any, + "durationStr": Any, + "readsIn": Any, + "readsInSec": Any, + "readsInSecStr": Any, + "readsInStr": Any, + "startTime": Any, + "startTimeStr": Any, + "writeOut": Any, + "writeOutSec": Any, + "writeOutSecStr": Any, + "writeOutStr": Any, + } + `); + }); + + it('ProcessHistoryTest', function () { + processHistory = { + processId: -1, + alive: '', + firstSeen: '', + lastSeen: '', + processName: "", + responsibleProcess: "", + userName: "", + cpuTime: '', + } + expect(processHistory).not.toBeUndefined(); + expect(processHistory).toMatchInlineSnapshot({ + processId: expect.any(Number), + alive: expect.any(String), + firstSeen: expect.any(String), + lastSeen: expect.any(String), + processName: expect.any(String), + responsibleProcess: expect.any(String), + userName: expect.any(String), + cpuTime: expect.any(String) }, ` + Object { + "alive": Any, + "cpuTime": Any, + "firstSeen": Any, + "lastSeen": Any, + "processId": Any, + "processName": Any, + "responsibleProcess": Any, + "userName": Any, + } + `); + }); + + it('LiveProcessTest', function () { + liveProcess = { + processId: -1, + processName: "", + responsibleProcess: "", + userName: "", + cpu: '', + threads: -1, + } + expect(liveProcess).not.toBeUndefined(); + expect(liveProcess).toMatchInlineSnapshot({ + processId: expect.any(Number), + processName: expect.any(String), + responsibleProcess: expect.any(String), + userName: expect.any(String), + cpu: expect.any(String), + threads: expect.any(Number) }, ` + Object { + "cpu": Any, + "processId": Any, + "processName": Any, + "responsibleProcess": Any, + "threads": Any, + "userName": Any, + } + `) + }); + + it('SystemNetworkSummaryTest', function () { + systemNetworkSummary = { + startTime: -1, + startTimeStr: "", + duration: -1, + durationStr: "", + dataReceived: -1, + dataReceivedStr: "", + dataReceivedSec: -1, + dataReceivedSecStr: "", + dataSend: -1, + dataSendStr: "", + dataSendSec: -1, + dataSendSecStr: "", + packetsIn: -1, + packetsInSec: -1, + packetsOut: -1, + packetsOutSec: -1, + } + expect(systemNetworkSummary).not.toBeUndefined(); + expect(systemNetworkSummary).toMatchInlineSnapshot({ + startTime: expect.any(Number), + startTimeStr: expect.any(String), + duration: expect.any(Number), + durationStr: expect.any(String), + dataReceived: expect.any(Number), + dataReceivedStr: expect.any(String), + dataReceivedSec: expect.any(Number), + dataReceivedSecStr: expect.any(String), + dataSend: expect.any(Number), + dataSendStr: expect.any(String), + dataSendSec: expect.any(Number), + dataSendSecStr: expect.any(String), + packetsIn: expect.any(Number), + packetsInSec: expect.any(Number), + packetsOut: expect.any(Number), + packetsOutSec: expect.any(Number) }, ` + Object { + "dataReceived": Any, + "dataReceivedSec": Any, + "dataReceivedSecStr": Any, + "dataReceivedStr": Any, + "dataSend": Any, + "dataSendSec": Any, + "dataSendSecStr": Any, + "dataSendStr": Any, + "duration": Any, + "durationStr": Any, + "packetsIn": Any, + "packetsInSec": Any, + "packetsOut": Any, + "packetsOutSec": Any, + "startTime": Any, + "startTimeStr": Any, + } + `) + }); + + it('systemMemorySummaryTest', function () { + systemMemorySummary = { + startTime: -1, + startTimeStr: "", + duration: -1, + durationStr: "", + memoryTotal: -1, + memoryTotalStr: "", + cached: -1, + cachedStr: "", + swapTotal: -1, + swapTotalStr: "", + appMemory: -1, + cachedFiles: -1, + compressed: -1, + memoryUsed: -1, + wiredMemory: -1, + swapUsed: -1, + } + expect(systemMemorySummary).not.toBeUndefined(); + expect(systemMemorySummary).toMatchInlineSnapshot({ + startTime: expect.any(Number), + startTimeStr: expect.any(String), + duration: expect.any(Number), + durationStr: expect.any(String), + memoryTotal: expect.any(Number), + memoryTotalStr: expect.any(String), + cached: expect.any(Number), + cachedStr: expect.any(String), + swapTotal: expect.any(Number), + swapTotalStr: expect.any(String), + appMemory: expect.any(Number), + cachedFiles: expect.any(Number), + compressed: expect.any(Number), + memoryUsed: expect.any(Number), + wiredMemory: expect.any(Number), + swapUsed: expect.any(Number) }, ` + Object { + "appMemory": Any, + "cached": Any, + "cachedFiles": Any, + "cachedStr": Any, + "compressed": Any, + "duration": Any, + "durationStr": Any, + "memoryTotal": Any, + "memoryTotalStr": Any, + "memoryUsed": Any, + "startTime": Any, + "startTimeStr": Any, + "swapTotal": Any, + "swapTotalStr": Any, + "swapUsed": Any, + "wiredMemory": Any, + } + `) + }); +}) \ No newline at end of file diff --git a/host/ide/test/trace/bean/BaseStruct.test.ts b/host/ide/test/trace/bean/BaseStruct.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..c08660f3000516635233b94e371d859069d522dd --- /dev/null +++ b/host/ide/test/trace/bean/BaseStruct.test.ts @@ -0,0 +1 @@ +/* * 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. */ //@ts-ignore import { BaseStruct} from "../../../dist/trace/bean/BaseStruct.js" describe('BaseStruct Test', ()=>{ let baseStruct = new BaseStruct(); it('BaseStructTest01', function () { baseStruct = { isHover : false, }; expect(baseStruct).not.toBeUndefined() expect(baseStruct).toMatchInlineSnapshot({ isHover: expect.any(Boolean) }, ` Object { "isHover": Any, } `); })}) \ No newline at end of file diff --git a/host/ide/test/trace/bean/BoxSelection.test.ts b/host/ide/test/trace/bean/BoxSelection.test.ts index 1171184d06f232b293efcfd624c81a8f81ae8d38..bbfae611891e992445adcbdb72f5edf6bd22f1b2 100644 --- a/host/ide/test/trace/bean/BoxSelection.test.ts +++ b/host/ide/test/trace/bean/BoxSelection.test.ts @@ -14,27 +14,188 @@ */ // @ts-ignore -import {SelectionParam, SelectionData, Counter, Fps} from "../../../dist/trace/bean/BoxSelection.js" +import {SelectionParam, BoxJumpParam, SelectionData, Counter, Fps} from "../../../dist/trace/bean/BoxSelection.js" describe('BoxSelection Test', ()=>{ let selectionParam = new SelectionParam(); + let boxJumpParam = new BoxJumpParam(); let selectionData = new SelectionData(); let counter = new Counter(); let fps = new Fps(); - it('BoxSelectionTest01', function () { + selectionParam = { + cpus: 1, + threadIds: 2, + trackIds: 1, + funTids: 2, + heapIds: 1, + nativeMemory: 3, + leftNs: 1, + rightNs: 1, + hasFps: true, + statisticsSelectData: 1, + }; + expect(selectionParam).not.toBeUndefined() + expect(selectionParam).toMatchInlineSnapshot({ + cpus: expect.any(Number), + threadIds: expect.any(Number), + trackIds: expect.any(Number), + funTids: expect.any(Number), + heapIds: expect.any(Number), + nativeMemory: expect.any(Number), + leftNs: expect.any(Number), + rightNs: expect.any(Number), + hasFps: expect.any(Boolean) + }, + ` + Object { + "cpus": Any, + "funTids": Any, + "hasFps": Any, + "heapIds": Any, + "leftNs": Any, + "nativeMemory": Any, + "rightNs": Any, + "statisticsSelectData": 1, + "threadIds": Any, + "trackIds": Any, + } + `); }); it('BoxSelectionTest02', function () { - expect(selectionData).not.toBeUndefined() - }); + boxJumpParam = { + leftNs: 0, + rightNs: 0, + state: "", + processId: 0, + threadId: 0, + }; + expect(boxJumpParam).not.toBeUndefined() + expect(boxJumpParam).toMatchInlineSnapshot({ + leftNs: expect.any(Number), + rightNs: expect.any(Number), + state: expect.any(String), + processId: expect.any(Number), + threadId: expect.any(Number) }, ` + Object { + "leftNs": Any, + "processId": Any, + "rightNs": Any, + "state": Any, + "threadId": Any, + } + `); + }); it('BoxSelectionTest03', function () { + selectionData = { + name: "name", + process: "process", + pid: "pid", + thread: "thread", + tid: "tid", + wallDuration: 0, + avgDuration: "avgDuration", + occurrences: 0, + state: "state", + trackId: 0, + delta: "delta", + rate: "rate", + avgWeight: "avgWeight", + count: "count", + first: "first", + last: "last", + min: "min", + max: "max", + stateJX: "stateJX", + }; + expect(selectionData).not.toBeUndefined() + expect(selectionData).toMatchInlineSnapshot({ + process: expect.any(String), + pid: expect.any(String), + thread: expect.any(String), + tid: expect.any(String), + wallDuration: expect.any(Number), + avgDuration: expect.any(String), + occurrences: expect.any(Number), + state: expect.any(String), + trackId: expect.any(Number), + delta: expect.any(String), + rate: expect.any(String), + avgWeight: expect.any(String), + count: expect.any(String), + first: expect.any(String), + last: expect.any(String), + min: expect.any(String), + max: expect.any(String), + stateJX: expect.any(String) }, ` + Object { + "avgDuration": Any, + "avgWeight": Any, + "count": Any, + "delta": Any, + "first": Any, + "last": Any, + "max": Any, + "min": Any, + "name": "name", + "occurrences": Any, + "pid": Any, + "process": Any, + "rate": Any, + "state": Any, + "stateJX": Any, + "thread": Any, + "tid": Any, + "trackId": Any, + "wallDuration": Any, + } + `); + }); + + it('BoxSelectionTest04', function () { + counter = { + id: 0, + trackId: 0, + name: "", + value: 0, + startTime: 0, + }; expect(counter).not.toBeUndefined() + expect(counter).toMatchInlineSnapshot({ + id: expect.any(Number), + trackId: expect.any(Number), + name: expect.any(String), + value: expect.any(Number), + startTime: expect.any(Number) }, ` + Object { + "id": Any, + "name": Any, + "startTime": Any, + "trackId": Any, + "value": Any, + } + `) }); - it('BoxSelectionTest04', function () { + it('BoxSelectionTest05', function () { + fps = { + startNS: 0, + timeStr: "", + fps: 0, + }; expect(fps).not.toBeUndefined() + expect(fps).toMatchInlineSnapshot({ + startNS: expect.any(Number), + timeStr: expect.any(String), + fps: expect.any(Number) }, ` + Object { + "fps": Any, + "startNS": Any, + "timeStr": Any, + } + `); }); }) diff --git a/host/ide/test/trace/bean/CpuFreqStruct.test.ts b/host/ide/test/trace/bean/CpuFreqStruct.test.ts index 1d716aa3fac33d601e13cb05705be1d3e5e9964c..42b00f0f1deb4ff3143e7b220b39463563fb3ddb 100644 --- a/host/ide/test/trace/bean/CpuFreqStruct.test.ts +++ b/host/ide/test/trace/bean/CpuFreqStruct.test.ts @@ -33,7 +33,42 @@ describe('CpuFreqStruct Test', ()=>{ startNS: 200, value: 50 } + + const dataSource = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100 + }, + value: 50, + maxFreq: 50 + } + it('CpuFreqStructTest01', function () { expect(CpuFreqStruct.draw(ctx, data)).toBeUndefined() + expect(data).toMatchInlineSnapshot({ + startNS: expect.any(Number), + value: expect.any(Number) }, ` + Object { + "frame": Object { + "height": 100, + "width": 100, + "x": 20, + "y": 20, + }, + "startNS": Any, + "value": Any, + } + `); + }); + + it('CpuFreqStructTest02', function () { + expect(CpuFreqStruct.draw(ctx, {startNS:1})).toBeUndefined() + }); + + it('CpuFreqStructTest03 ', function () { + expect(CpuFreqStruct.draw(ctx,dataSource)).toBeUndefined() + }); }) diff --git a/host/ide/test/trace/bean/CpuStruct.test.ts b/host/ide/test/trace/bean/CpuStruct.test.ts index 266521c88c77e39de3dcf8a160b414c70d014684..a9358d8f751d56833497e8055bdbbb32a8065967 100644 --- a/host/ide/test/trace/bean/CpuStruct.test.ts +++ b/host/ide/test/trace/bean/CpuStruct.test.ts @@ -32,11 +32,30 @@ describe('CpuStruct Test', ()=>{ startNS: 200, value: 50 } + + it('CpuStructTest01', function () { expect(CpuStruct.draw(ctx, data)).toBeUndefined() + expect(data).toMatchInlineSnapshot({ + startNS: expect.any(Number), + value: expect.any(Number) }, ` + Object { + "frame": Object { + "height": 100, + "width": 100, + "x": 20, + "y": 20, + }, + "startNS": Any, + "value": Any, + } + `); }); it('CpuStructTest02', function () { expect(CpuStruct.equals({}, data)).toBeTruthy(); }); + + + }) diff --git a/host/ide/test/trace/bean/CpuUsage.test.ts b/host/ide/test/trace/bean/CpuUsage.test.ts index 920f4fcddf86c3b7706fe3bb8130a89d007ab6e1..0f3e886dec4e18ef43943038a5ec1d78c9cec935 100644 --- a/host/ide/test/trace/bean/CpuUsage.test.ts +++ b/host/ide/test/trace/bean/CpuUsage.test.ts @@ -21,10 +21,70 @@ describe('CpuUsage Test', ()=>{ let freq = new Freq(); it('CpuUsageTest01', function () { + cpuUsage = { + cpu: 0, + usage: 0, + usageStr: "", + top1: 0, + top2: 0, + top3: 0, + top1Percent: 0, + top1PercentStr: "", + top2Percent: 0, + top2PercentStr: "", + top3Percent: 0, + top3PercentStr: "", + } expect(cpuUsage).not.toBeUndefined() + expect(cpuUsage).toMatchInlineSnapshot({ + cpu: expect.any(Number), + usage: expect.any(Number), + usageStr: expect.any(String), + top1: expect.any(Number), + top2: expect.any(Number), + top3: expect.any(Number), + top1Percent: expect.any(Number), + top1PercentStr: expect.any(String), + top2Percent: expect.any(Number), + top2PercentStr: expect.any(String), + top3Percent: expect.any(Number), + top3PercentStr: expect.any(String) }, ` + Object { + "cpu": Any, + "top1": Any, + "top1Percent": Any, + "top1PercentStr": Any, + "top2": Any, + "top2Percent": Any, + "top2PercentStr": Any, + "top3": Any, + "top3Percent": Any, + "top3PercentStr": Any, + "usage": Any, + "usageStr": Any, + } + `); }); it('CpuUsageTest02', function () { + cpuUsage = { + cpu: 0, + value: 0, + startNs: 0, + dur: 0, + } expect(freq).not.toBeUndefined() + expect(cpuUsage).toMatchInlineSnapshot({ + cpu: expect.any(Number), + value: expect.any(Number), + startNs: expect.any(Number), + dur: expect.any(Number) }, ` + Object { + "cpu": Any, + "dur": Any, + "startNs": Any, + "value": Any, + } + `); }); }) diff --git a/host/ide/test/trace/bean/DiskAbilityMonitorStruct.test.ts b/host/ide/test/trace/bean/DiskAbilityMonitorStruct.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..5131ad5c5a5872a2486d33055381ce7ba93a7a45 --- /dev/null +++ b/host/ide/test/trace/bean/DiskAbilityMonitorStruct.test.ts @@ -0,0 +1,56 @@ +/* + * 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. + */ +// @ts-ignore +import {DiskAbilityMonitorStruct} from "../../../dist/trace/bean/DiskAbilityMonitorStruct.js" + +describe('DiskAbilityMonitorStruct Test', ()=> { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const data = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100 + }, + startNS: 200, + value: 50 + } + + const Sourcedata = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100 + + }, + value: 50, + maxDiskRate: 50 + + } + + it('DiskAbilityMonitorStructTest01', function () { + expect(DiskAbilityMonitorStruct.draw(ctx, data)).toBeUndefined() + }); + + it('DiskAbilityMonitorStructTest02', function () { + expect(DiskAbilityMonitorStruct.draw(ctx, Sourcedata)).toBeUndefined() + }); + +}) \ No newline at end of file diff --git a/host/ide/test/trace/bean/FpsStruct.test.ts b/host/ide/test/trace/bean/FpsStruct.test.ts index 568a5a581dda243ccc47b271f99675f1c47a0b79..92d7ae3447f5b20d45b809beb108321e9369f975 100644 --- a/host/ide/test/trace/bean/FpsStruct.test.ts +++ b/host/ide/test/trace/bean/FpsStruct.test.ts @@ -32,7 +32,51 @@ describe('FpsStruct Test', ()=>{ startNS: 200, value: 50 } + const node = { + startNS: 200, + frame:2, + dur:3, + } + const padding = 1 + const startNs = 1 + const endNS = 1 + const totalNS = 1 + const frame = { + x: 20, + y: 20, + width: 100, + height: 100 + } + const dataSource = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100 + }, + value: 50, + maxFps: 50 + } + + it('FpsStructTest01', function () { expect(FpsStruct.draw(ctx, data)).toBeUndefined() }); + + it('FpsStructTest04 ', function () { + expect(FpsStruct.draw(ctx,dataSource)).toBeUndefined() + + }); + + it('FpsStructTest02', function () { + let fpsStruct = new FpsStruct(); + expect(fpsStruct).not.toBeUndefined() + }); + + it('FpsStructTest03', function () { + expect(FpsStruct.setFrame(node,padding,startNs,endNS,totalNS,frame)).toBeUndefined() + }); + + + }) diff --git a/host/ide/test/trace/bean/FuncStruct.test.ts b/host/ide/test/trace/bean/FuncStruct.test.ts index f2ac0d789322ff2fcd2a9a5df709d3db805074ac..a58bd5e4e7436c4331355bf740fec657a79814e6 100644 --- a/host/ide/test/trace/bean/FuncStruct.test.ts +++ b/host/ide/test/trace/bean/FuncStruct.test.ts @@ -51,6 +51,10 @@ describe('FuncStruct Test', ()=>{ it('FuncStructTest03', function () { expect(FuncStruct.drawString(ctx, 2, durData, durData.frame)).toBeUndefined() }); + it('FuncStructTest06 ', function () { + expect(FuncStruct.drawString(ctx,3,durData,durData.frame)).toBeUndefined() + + }); it('FuncStructTest04', function () { expect(FuncStruct.isSelected({ @@ -60,11 +64,13 @@ describe('FuncStruct Test', ()=>{ })).toBeTruthy(); }); + it('FuncStructTest05', function () { expect(FuncStruct.isBinder({ startTs: 10, dur: 10, - funName: '' + funName: null })).toBeFalsy(); }); + }) diff --git a/host/ide/test/trace/bean/HeapBean.test.ts b/host/ide/test/trace/bean/HeapBean.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..ee020fae985be4a9179d4d32b0781e8b009393f4 --- /dev/null +++ b/host/ide/test/trace/bean/HeapBean.test.ts @@ -0,0 +1,58 @@ +/* + * 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. + */ + +// @ts-ignore +import {HeapBean} from "../../../dist/trace/bean/HeapBean.js" + +describe('HeapBean Test', ()=>{ + let heapBean = new HeapBean(); + + it('HeapBeanTest01', function () { + heapBean = { + MoudleName: "MoudleName", + AllocationFunction: "AllocationFunction", + Allocations: 0, + Deallocations: 0, + AllocationSize: 0, + DeAllocationSize: 0, + Total: 0, + RemainingSize: 0, + depth: 0, + } + expect(heapBean).not.toBeUndefined() + expect(heapBean).toMatchInlineSnapshot({ + MoudleName: expect.any(String), + AllocationFunction: expect.any(String), + Allocations: expect.any(Number), + Deallocations: expect.any(Number), + AllocationSize: expect.any(Number), + DeAllocationSize: expect.any(Number), + Total: expect.any(Number), + RemainingSize: expect.any(Number), + depth: expect.any(Number) }, ` + Object { + "AllocationFunction": Any, + "AllocationSize": Any, + "Allocations": Any, + "DeAllocationSize": Any, + "Deallocations": Any, + "MoudleName": Any, + "RemainingSize": Any, + "Total": Any, + "depth": Any, + } + `) + }); +}) \ No newline at end of file diff --git a/host/ide/test/trace/bean/HeapTreeDataBean.test.ts b/host/ide/test/trace/bean/HeapTreeDataBean.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..9f859d1656ba706700103714df87218b7608ea14 --- /dev/null +++ b/host/ide/test/trace/bean/HeapTreeDataBean.test.ts @@ -0,0 +1,55 @@ +/* + * 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. + */ + +// @ts-ignore +import {HeapTreeDataBean} from "../../../dist/trace/bean/HeapTreeDataBean.js" + +describe('HeapTreeDataBean Test', ()=>{ + let heapTreeDataBean = new HeapTreeDataBean(); + + it('HeapTreeDataBeanTest01', function () { + heapTreeDataBean = { + MoudleName: "MoudleName", + AllocationFunction: "AllocationFunction", + startTs: 0, + endTs: 0, + eventType: "eventType", + depth: 0, + heapSize: 0, + eventId: "eventId", + } + expect(heapTreeDataBean).not.toBeUndefined() + expect(heapTreeDataBean).toMatchInlineSnapshot({ + MoudleName: expect.any(String), + AllocationFunction: expect.any(String), + startTs: expect.any(Number), + endTs: expect.any(Number), + eventType: expect.any(String), + depth: expect.any(Number), + heapSize: expect.any(Number), + eventId: expect.any(String) }, ` + Object { + "AllocationFunction": Any, + "MoudleName": Any, + "depth": Any, + "endTs": Any, + "eventId": Any, + "eventType": Any, + "heapSize": Any, + "startTs": Any, + } + `) + }); +}) \ No newline at end of file diff --git a/host/ide/test/trace/bean/MemoryAbilityMonitorStruct.test.ts b/host/ide/test/trace/bean/MemoryAbilityMonitorStruct.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..1e74d9a42cb4422fe837d968b7992618cdc5a0b3 --- /dev/null +++ b/host/ide/test/trace/bean/MemoryAbilityMonitorStruct.test.ts @@ -0,0 +1,57 @@ +/* + * 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. + */ +// @ts-ignore +import {MemoryAbilityMonitorStruct} from "../../../dist/trace/bean/MemoryAbilityMonitorStruct.js" + +describe('MemoryAbilityMonitorStruct Test', ()=> { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const data = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100 + }, + startNS: 200, + value: 50 + } + + + const Sourcedata = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100 + }, + maxMemoryByte: 200, + value: 50 + } + + it('MemoryAbilityMonitorStructTest01', function () { + expect(MemoryAbilityMonitorStruct.draw(ctx, data)).toBeUndefined() + }); + + it('MemoryAbilityMonitorStructTest02', function () { + expect(MemoryAbilityMonitorStruct.draw(ctx, Sourcedata)).toBeUndefined() + }); + + + +}) \ No newline at end of file diff --git a/host/ide/test/trace/bean/NativeHook.test.ts b/host/ide/test/trace/bean/NativeHook.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..5b872a2742ecc47b628eea14e8fa449bc2464b7b --- /dev/null +++ b/host/ide/test/trace/bean/NativeHook.test.ts @@ -0,0 +1,354 @@ +/* + * 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. + */ + +// @ts-ignore +import {NativeHookStatistics, NativeHookMalloc, NativeEventHeap, NativeHookProcess, NativeHookStatisticsTableData, NativeMemory, NativeHookSamplerInfo, NativeHookSampleQueryInfo, NativeHookCallInfo} from "../../../dist/trace/bean/NativeHook.js" + +describe('NativeHook Test', ()=>{ + + it('NativeHookStatisticsTest01', function () { + let nativeHookStatistics = new NativeHookStatistics(); + nativeHookStatistics = { + eventId: 0, + eventType: "eventType", + subType: "subType", + heapSize: 0, + addr: "addr", + startTs: 0, + endTs: 0, + sumHeapSize: 0, + max: 0, + count: 0, + tid: 0, + isSelected: false, + } + expect(nativeHookStatistics).not.toBeUndefined() + expect(nativeHookStatistics).toMatchInlineSnapshot({ + eventId: expect.any(Number), + eventType: expect.any(String), + subType: expect.any(String), + heapSize: expect.any(Number), + addr: expect.any(String), + startTs: expect.any(Number), + endTs: expect.any(Number), + sumHeapSize: expect.any(Number), + max: expect.any(Number), + count: expect.any(Number), + tid: expect.any(Number), + isSelected: expect.any(Boolean) }, ` + Object { + "addr": Any, + "count": Any, + "endTs": Any, + "eventId": Any, + "eventType": Any, + "heapSize": Any, + "isSelected": Any, + "max": Any, + "startTs": Any, + "subType": Any, + "sumHeapSize": Any, + "tid": Any, + } + `) + }); + + it('NativeEventHeapTest02', function () { + let nativeHookMalloc = new NativeHookMalloc(); + nativeHookMalloc = { + eventType: "eventType", + subType: "subType", + heapSize: 0, + allocByte: 0, + allocCount: 0, + freeByte: 0, + freeCount: 0, + } + expect(nativeHookMalloc).not.toBeUndefined() + expect(nativeHookMalloc).toMatchInlineSnapshot({ + eventType: expect.any(String), + subType: expect.any(String), + heapSize: expect.any(Number), + allocByte: expect.any(Number), + allocCount: expect.any(Number), + freeByte: expect.any(Number), + freeCount: expect.any(Number) }, ` + Object { + "allocByte": Any, + "allocCount": Any, + "eventType": Any, + "freeByte": Any, + "freeCount": Any, + "heapSize": Any, + "subType": Any, + } + `) + }); + + it('NativeEventHeapTest03', function () { + let nativeEventHeap = new NativeEventHeap(); + nativeEventHeap = { + eventType: "eventType", + sumHeapSize: 0, + } + expect(nativeEventHeap).not.toBeUndefined() + expect(nativeEventHeap).toMatchInlineSnapshot({ + eventType: expect.any(String), + sumHeapSize: expect.any(Number) }, ` + Object { + "eventType": Any, + "sumHeapSize": Any, + } + `) + }); + + it('NativeHookProcessTest04', function () { + let nativeHookProcess = new NativeHookProcess(); + nativeHookProcess = { + ipid: 0, + pid: 0, + name: "name", + } + expect(nativeHookProcess).not.toBeUndefined() + expect(nativeHookProcess).toMatchInlineSnapshot({ + ipid: expect.any(Number), + pid: expect.any(Number), + name: expect.any(String) }, ` + Object { + "ipid": Any, + "name": Any, + "pid": Any, + } + `) + }); + + it('NativeHookStatisticsTableDataTest05', function () { + let nativeHookStatisticsTableData = new NativeHookStatisticsTableData(); + nativeHookStatisticsTableData = { + memoryTap: "", + existing: 0, + existingString: "", + allocCount: 0, + freeCount: 0, + totalBytes: 0, + totalBytesString: "", + maxStr: "", + max: 0, + totalCount: 0, + } + expect(nativeHookStatisticsTableData).not.toBeUndefined() + expect(nativeHookStatisticsTableData).toMatchInlineSnapshot({ + memoryTap: expect.any(String), + existing: expect.any(Number), + existingString: expect.any(String), + allocCount: expect.any(Number), + freeCount: expect.any(Number), + totalBytes: expect.any(Number), + totalBytesString: expect.any(String), + maxStr: expect.any(String), + max: expect.any(Number), + totalCount: expect.any(Number) }, ` + Object { + "allocCount": Any, + "existing": Any, + "existingString": Any, + "freeCount": Any, + "max": Any, + "maxStr": Any, + "memoryTap": Any, + "totalBytes": Any, + "totalBytesString": Any, + "totalCount": Any, + } + `) + }); + + it('NativeMemoryTest06', function () { + let nativeMemory = new NativeMemory(); + nativeMemory = { + index: 0, + eventId: 0, + eventType: "eventType", + subType: "subType", + addr: "addr", + startTs: 0, + timestamp: "timestamp", + heapSize: 0, + heapSizeUnit: "heapSizeUnit", + symbol: "symbol", + library: "library", + isSelected: false, + } + expect(nativeMemory).not.toBeUndefined() + expect(nativeMemory).toMatchInlineSnapshot({ + index: expect.any(Number), + eventId: expect.any(Number), + eventType: expect.any(String), + subType: expect.any(String), + addr: expect.any(String), + startTs: expect.any(Number), + timestamp: expect.any(String), + heapSize: expect.any(Number), + heapSizeUnit: expect.any(String), + symbol: expect.any(String), + library: expect.any(String), + isSelected: expect.any(Boolean) }, ` + Object { + "addr": Any, + "eventId": Any, + "eventType": Any, + "heapSize": Any, + "heapSizeUnit": Any, + "index": Any, + "isSelected": Any, + "library": Any, + "startTs": Any, + "subType": Any, + "symbol": Any, + "timestamp": Any, + } + `) + }); + + it('NativeHookCallInfoTest07', function () { + let nativeHookSamplerInfo = new NativeHookSamplerInfo(); + nativeHookSamplerInfo = { + current: "current", + currentSize: 0, + startTs: 0, + heapSize: 0, + snapshot: "snapshot", + growth: "growth", + total: 0, + totalGrowth: "totalGrowth", + existing: 0, + timestamp: "timestamp", + eventId: -1, + } + expect(nativeHookSamplerInfo).not.toBeUndefined() + expect(nativeHookSamplerInfo).toMatchInlineSnapshot({ + current: expect.any(String), + currentSize: expect.any(Number), + startTs: expect.any(Number), + heapSize: expect.any(Number), + snapshot: expect.any(String), + growth: expect.any(String), + total: expect.any(Number), + totalGrowth: expect.any(String), + existing: expect.any(Number), + timestamp: expect.any(String), + eventId: expect.any(Number) }, ` + Object { + "current": Any, + "currentSize": Any, + "eventId": Any, + "existing": Any, + "growth": Any, + "heapSize": Any, + "snapshot": Any, + "startTs": Any, + "timestamp": Any, + "total": Any, + "totalGrowth": Any, + } + `) + }); + + it('NativeHookCallInfoTest08', function () { + let nativeHookSampleQueryInfo = new NativeHookSampleQueryInfo(); + nativeHookSampleQueryInfo = { + eventId: -1, + current: 0, + eventType: "eventType", + subType: "subType", + growth: 0, + existing: 0, + addr: "addr", + startTs: 0, + endTs: 0, + total: 0, + } + + expect(nativeHookSampleQueryInfo).not.toBeUndefined() + expect(nativeHookSampleQueryInfo).toMatchInlineSnapshot({ + eventId: expect.any(Number), + current: expect.any(Number), + eventType: expect.any(String), + subType: expect.any(String), + growth: expect.any(Number), + existing: expect.any(Number), + addr: expect.any(String), + startTs: expect.any(Number), + endTs: expect.any(Number), + total: expect.any(Number) }, ` + Object { + "addr": Any, + "current": Any, + "endTs": Any, + "eventId": Any, + "eventType": Any, + "existing": Any, + "growth": Any, + "startTs": Any, + "subType": Any, + "total": Any, + } + `) + }); + + it('NativeHookCallInfoTest09', function () { + let nativeHookCallInfo = new NativeHookCallInfo(); + nativeHookCallInfo = { + id: "id", + pid: "pid", + library: "library", + title: "title", + count: 0, + type: 0, + heapSize: 0, + heapSizeStr: "heapSizeStr", + eventId: 0, + threadId: 0, + isSelected: false, + } + expect(nativeHookCallInfo).not.toBeUndefined() + expect(nativeHookCallInfo).toMatchInlineSnapshot({ + id: expect.any(String), + pid: expect.any(String), + library: expect.any(String), + title: expect.any(String), + count: expect.any(Number), + type: expect.any(Number), + heapSize: expect.any(Number), + heapSizeStr: expect.any(String), + eventId: expect.any(Number), + threadId: expect.any(Number), + isSelected: expect.any(Boolean) }, ` + Object { + "count": Any, + "eventId": Any, + "heapSize": Any, + "heapSizeStr": Any, + "id": Any, + "isSelected": Any, + "library": Any, + "pid": Any, + "threadId": Any, + "title": Any, + "type": Any, + } + `) + }); +}) \ No newline at end of file diff --git a/host/ide/test/trace/bean/NetworkAbilityMonitorStruct.test.ts b/host/ide/test/trace/bean/NetworkAbilityMonitorStruct.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..c221584f2a8d52a4b3e04efc25f6dcd552cb407b --- /dev/null +++ b/host/ide/test/trace/bean/NetworkAbilityMonitorStruct.test.ts @@ -0,0 +1,55 @@ +/* + * 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. + */ +// @ts-ignore +import {NetworkAbilityMonitorStruct} from "../../../dist/trace/bean/NetworkAbilityMonitorStruct.js" + +describe('NetworkAbilityMonitorStruct Test', ()=> { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const data = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100 + }, + startNS: 200, + value: 50 + } + + const Sourcedate = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100 + }, + value: 50, + maxNetworkRate: 50 + + } + + it('NetworkAbilityMonitorStructTest01', function () { + expect(NetworkAbilityMonitorStruct.draw(ctx, data)).toBeUndefined() + }); + + it('NetworkAbilityMonitorStructTest02', function () { + expect(NetworkAbilityMonitorStruct.draw(ctx, Sourcedate)).toBeUndefined() + }); + +}) \ No newline at end of file diff --git a/host/ide/test/trace/bean/PerfProfile.test.ts b/host/ide/test/trace/bean/PerfProfile.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..f4332f5a36ba4cba596b66c47bda21b8305044dc --- /dev/null +++ b/host/ide/test/trace/bean/PerfProfile.test.ts @@ -0,0 +1,264 @@ +/* + * 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. + */ + +// @ts-ignore +import {PerfFile, PerfThread, PerfCallChain, PerfCallChainMerageData, PerfSample, PerfStack} from "../../../dist/trace/bean/PerfProfile.js" + +describe('PerfProfile Test', ()=>{ + let perfFile = new PerfFile(); + let perfThread = new PerfThread(); + let perfCallChain = new PerfCallChain(); + let perfCallChainMerageData = new PerfCallChainMerageData(); + let perfSample = new PerfSample(); + let perfStack = new PerfStack(); + + it('PerfFile Test', function () { + perfFile = { + fileId: 0, + symbol: "symbol", + path: "path", + fileName: "fileName", + }; + + expect(perfFile).not.toBeUndefined() + expect(perfFile).toMatchInlineSnapshot({ + fileId: expect.any(Number), + symbol: expect.any(String), + path: expect.any(String), + fileName: expect.any(String) }, ` + Object { + "fileId": Any, + "fileName": Any, + "path": Any, + "symbol": Any, + } + `); + }); + + it('PerfThread Test', function () { + perfThread = { + tid: 0, + pid: 0, + threadName: "threadName", + processName: "processName", + } + + expect(perfThread).not.toBeUndefined() + expect(perfThread).toMatchInlineSnapshot({ + tid: expect.any(Number), + pid: expect.any(Number), + threadName: expect.any(String), + processName: expect.any(String) }, ` + Object { + "pid": Any, + "processName": Any, + "threadName": Any, + "tid": Any, + } + `); + }); + + it('perfCallChain Test', function () { + perfCallChain = { + tid: 0, + pid: 0, + name: "name", + fileName: "fileName", + threadState: "threadState", + startNS: 0, + dur: 0, + sampleId: 0, + callChainId: 0, + vaddrInFile: 0, + fileId: 0, + symbolId: 0, + parentId: "parentId", + id: "id", + topDownMerageId: "topDownMerageId", + topDownMerageParentId: "topDownMerageParentId", + bottomUpMerageId: "bottomUpMerageId", + bottomUpMerageParentId: "bottomUpMerageParentId", + depth: 0, + } + + expect(perfCallChain).not.toBeUndefined() + expect(perfCallChain).toMatchInlineSnapshot({ + tid: expect.any(Number), + pid: expect.any(Number), + name: expect.any(String), + fileName: expect.any(String), + threadState: expect.any(String), + startNS: expect.any(Number), + dur: expect.any(Number), + sampleId: expect.any(Number), + callChainId: expect.any(Number), + vaddrInFile: expect.any(Number), + fileId: expect.any(Number), + symbolId: expect.any(Number), + parentId: expect.any(String), + id: expect.any(String), + topDownMerageId: expect.any(String), + topDownMerageParentId: expect.any(String), + bottomUpMerageId: expect.any(String), + bottomUpMerageParentId: expect.any(String), + depth: expect.any(Number) }, ` + Object { + "bottomUpMerageId": Any, + "bottomUpMerageParentId": Any, + "callChainId": Any, + "depth": Any, + "dur": Any, + "fileId": Any, + "fileName": Any, + "id": Any, + "name": Any, + "parentId": Any, + "pid": Any, + "sampleId": Any, + "startNS": Any, + "symbolId": Any, + "threadState": Any, + "tid": Any, + "topDownMerageId": Any, + "topDownMerageParentId": Any, + "vaddrInFile": Any, + } + `) + }) + + it('perfCallChain Test', function () { + perfCallChainMerageData = { + id: "id", + parentId: "parentId", + symbolName: "symbolName", + symbol: "symbol", + libName: "libName", + self: "self", + weight: "weight", + selfDur: 0, + dur: 0, + tid: 0, + pid: 0, + type: 0, + isSelected: false, + } + + expect(perfCallChainMerageData).not.toBeUndefined() + expect(perfCallChainMerageData).toMatchInlineSnapshot({ + id: expect.any(String), + parentId: expect.any(String), + symbolName: expect.any(String), + symbol: expect.any(String), + libName: expect.any(String), + self: expect.any(String), + weight: expect.any(String), + selfDur: expect.any(Number), + dur: expect.any(Number), + tid: expect.any(Number), + pid: expect.any(Number), + type: expect.any(Number), + isSelected: expect.any(Boolean) }, ` + Object { + "dur": Any, + "id": Any, + "isSelected": Any, + "libName": Any, + "parentId": Any, + "pid": Any, + "self": Any, + "selfDur": Any, + "symbol": Any, + "symbolName": Any, + "tid": Any, + "type": Any, + "weight": Any, + } + `) + }) + + it('perfSample Test', function () { + perfSample = { + sampleId: 0, + time: 0, + timeString: "timeString", + core: 0, + coreName: "coreName", + state: "state", + pid: 0, + processName: "processName", + tid: 0, + threadName: "threadName", + depth: 0, + addr: "addr", + fileId: 0, + symbolId: 0, + } + expect(perfSample).not.toBeUndefined() + expect(perfSample).toMatchInlineSnapshot({ + sampleId: expect.any(Number), + time: expect.any(Number), + timeString: expect.any(String), + core: expect.any(Number), + coreName: expect.any(String), + state: expect.any(String), + pid: expect.any(Number), + processName: expect.any(String), + tid: expect.any(Number), + threadName: expect.any(String), + depth: expect.any(Number), + addr: expect.any(String), + fileId: expect.any(Number), + symbolId: expect.any(Number) }, ` + Object { + "addr": Any, + "core": Any, + "coreName": Any, + "depth": Any, + "fileId": Any, + "pid": Any, + "processName": Any, + "sampleId": Any, + "state": Any, + "symbolId": Any, + "threadName": Any, + "tid": Any, + "time": Any, + "timeString": Any, + } + `) + }) + + it('perfStack Test', function () { + perfStack = { + symbol: "", + path: "", + fileId: 0, + type: 0, + } + expect(perfStack).not.toBeUndefined() + expect(perfStack).toMatchInlineSnapshot({ + symbol: expect.any(String), + path: expect.any(String), + fileId: expect.any(Number), + type: expect.any(Number) }, ` + Object { + "fileId": Any, + "path": Any, + "symbol": Any, + "type": Any, + } + `) + }) +}) diff --git a/host/ide/test/trace/bean/StateProcessThread.test.ts b/host/ide/test/trace/bean/StateProcessThread.test.ts index 83be7ef5a9ace39a36da8cc01383120961303f10..b641d42093e3e47c7464fce17f6945662adb1323 100644 --- a/host/ide/test/trace/bean/StateProcessThread.test.ts +++ b/host/ide/test/trace/bean/StateProcessThread.test.ts @@ -14,12 +14,159 @@ */ // @ts-ignore -import {StateProcessThread} from "../../../dist/trace/bean/StateProcessThread.js" +import {StateProcessThread,SPTChild,SPT} from "../../../dist/trace/bean/StateProcessThread.js" describe('StateProcessThread Test', ()=>{ - let stateProcessThread = new StateProcessThread(); it('StateProcessThreadTest01', function () { + let stateProcessThread = new StateProcessThread(); + stateProcessThread = { + id: "id", + pid: "pid", + title: "title", + process: "process", + processId: -1, + thread: "thread", + threadId: -1, + state: "state", + wallDuration: 0, + avgDuration: "avgDuration", + count: 0, + minDuration: 0, + maxDuration: 0, + stdDuration: "stdDuration", + } expect(stateProcessThread).not.toBeUndefined() + expect(stateProcessThread).toMatchInlineSnapshot({ + id: expect.any(String), + pid: expect.any(String), + title: expect.any(String), + process: expect.any(String), + processId: expect.any(Number), + thread: expect.any(String), + threadId: expect.any(Number), + wallDuration: expect.any(Number), + avgDuration: expect.any(String), + count: expect.any(Number), + minDuration: expect.any(Number), + maxDuration: expect.any(Number), + stdDuration: expect.any(String) }, ` + Object { + "avgDuration": Any, + "count": Any, + "id": Any, + "maxDuration": Any, + "minDuration": Any, + "pid": Any, + "process": Any, + "processId": Any, + "state": "state", + "stdDuration": Any, + "thread": Any, + "threadId": Any, + "title": Any, + "wallDuration": Any, + } + `) + }); + + it('SPTChildTest02', function () { + let sptChild = new SPTChild(); + sptChild = { + process: "process", + processId: 0, + processName: "processName", + thread: "thread", + threadId: 0, + threadName: "threadName", + state: "state", + startNs: 0, + startTime: "startTime", + duration: 0, + cpu: 1, + core: "core", + priority: 0, + prior: "prior", + note: "note", + } + expect(sptChild).not.toBeUndefined() + expect(sptChild).toMatchInlineSnapshot({ + process: expect.any(String), + processId: expect.any(Number), + processName: expect.any(String), + thread: expect.any(String), + threadId: expect.any(Number), + threadName: expect.any(String), + state: expect.any(String), + startNs: expect.any(Number), + startTime: expect.any(String), + duration: expect.any(Number), + cpu: expect.any(Number), + core: expect.any(String), + priority: expect.any(Number), + prior: expect.any(String), + note: expect.any(String) }, ` + Object { + "core": Any, + "cpu": Any, + "duration": Any, + "note": Any, + "prior": Any, + "priority": Any, + "process": Any, + "processId": Any, + "processName": Any, + "startNs": Any, + "startTime": Any, + "state": Any, + "thread": Any, + "threadId": Any, + "threadName": Any, + } + `) + }); + + it('SPTTest03', function () { + let spt = new SPT(); + spt = { + process: "process", + processId: 0, + thread: "thread", + threadId: 0, + state: "state", + dur: 0, + start_ts: 0, + end_ts: 0, + cpu: 0, + priority: "priority", + note: "note", + } + expect(spt).not.toBeUndefined() + expect(spt).toMatchInlineSnapshot({ + process: expect.any(String), + processId: expect.any(Number), + thread: expect.any(String), + threadId: expect.any(Number), + state: expect.any(String), + dur: expect.any(Number), + start_ts: expect.any(Number), + end_ts: expect.any(Number), + cpu: expect.any(Number), + priority: expect.any(String), + note: expect.any(String) }, ` + Object { + "cpu": Any, + "dur": Any, + "end_ts": Any, + "note": Any, + "priority": Any, + "process": Any, + "processId": Any, + "start_ts": Any, + "state": Any, + "thread": Any, + "threadId": Any, + } + `) }); }) diff --git a/host/ide/test/trace/bean/ThreadStruct.test.ts b/host/ide/test/trace/bean/ThreadStruct.test.ts index 82c8abf9ed4164162e67b154a48d2b0a5588ccb0..18b16f1977ced3230e368414b2d3d4a7f4bb3615 100644 --- a/host/ide/test/trace/bean/ThreadStruct.test.ts +++ b/host/ide/test/trace/bean/ThreadStruct.test.ts @@ -64,6 +64,11 @@ describe('ThreadStruct Test', () => { expect(ThreadStruct.draw(ctx, dataSource)).toBeUndefined() }); + it('ThreadStructTest11', function () { + dataSource.state = "T"||"t" + expect(ThreadStruct.draw(ctx, dataSource)).toBeUndefined() + }); + it('ThreadStructTest06', function () { expect(ThreadStruct.drawString(ctx, '', 2, dataSource.frame)).toBeUndefined() }); diff --git a/host/ide/test/trace/component/DisassemblingWindow.test.ts b/host/ide/test/trace/component/DisassemblingWindow.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..f96a3a2d3502ae602ef3707011bfbeef89dd5e78 --- /dev/null +++ b/host/ide/test/trace/component/DisassemblingWindow.test.ts @@ -0,0 +1,34 @@ +/* + * 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. + */ +// @ts-ignore +import {DisassemblingWindow,Disassembling} from "../../../dist/trace/component/DisassemblingWindow.js" + +describe('DisassemblingWindow Test', () => { + let disassemblingWindow = new DisassemblingWindow(); + + it('DisassemblingWindowTest01', function () { + expect(disassemblingWindow.getMap("","")).not.toBeUndefined(); + }); + + it('DisassemblingWindowTest02', function () { + expect(disassemblingWindow.resetCanvas(2,1,1,1)).toBeUndefined(); + }); + + it('DisassemblingWindowTest03', function () { + document.body.innerHTML = '
' + let disassemblingWindow = document.querySelector('#ccc') as DisassemblingWindow + expect(disassemblingWindow.showLoading()).toBeUndefined(); + }); +}) diff --git a/host/ide/test/trace/component/FrameChart.test.ts b/host/ide/test/trace/component/FrameChart.test.ts index 71c0410c77dad47efb71e64efd3353b9633dfbc9..08dbc72f7034d01dfccfb5f930d9fcd161dee051 100644 --- a/host/ide/test/trace/component/FrameChart.test.ts +++ b/host/ide/test/trace/component/FrameChart.test.ts @@ -16,62 +16,182 @@ // @ts-ignore import {FrameChart} from "../../../dist/trace/component/FrameChart.js" - describe('FrameChart Test', () => { let node= [ {children: ''}, {children:{length:1}} - ] - + ] + let selectData = [length=1] + document.body.innerHTML = '' + let frameChart = document.querySelector('#ccc') as FrameChart it('FrameChartTest01', function () { - let frameChart = new FrameChart(); - frameChart.data = false; - expect(frameChart.data).toBeFalsy(); + frameChart.tabPaneScrollTop = false; + expect(frameChart.tabPaneScrollTop).toBeFalsy(); }); it('FrameChartTest02', function () { + expect(frameChart.updateFloatHint()).toBeUndefined(); + }); + + it('FrameChartTest03', function () { + frameChart.calculateChartData = jest.fn(()=>true) + expect(frameChart.redrawChart(selectData)).toBeUndefined(); + }); + + it('FrameChartTest05', function () { + let index = frameChart.scale(2) + expect(index).toBe(undefined); + }); + + it('FrameChartTest08', function () { + frameChart.translationDraw = jest.fn(()=>true) + expect(frameChart.translation()).toBeUndefined(); + }); + + it('FrameChartTest14', function () { let frameChart = new FrameChart(); - expect(frameChart.data).toBeUndefined(); + frameChart.translationDraw = jest.fn(()=>true) + expect(frameChart.translation(-1)).toBeUndefined(); }); - it('FrameChartTest03', function () { + it('FrameChartTest09', function () { + frameChart.selectTotalCount = false; + expect(frameChart.selectTotalCount).toBeFalsy(); + }); + + it('FrameChartTest11', function () { let frameChart = new FrameChart(); - frameChart.selectTotalSize = true; - expect(frameChart.selectTotalSize).toBeUndefined(); + frameChart.drawScale = jest.fn(()=>true) + expect(frameChart.calculateChartData()).not.toBeUndefined(); }); - it('FrameChartTest04', function () { + it('FrameChartTest12', function () { + expect(frameChart.updateCanvas()).toBeUndefined(); + }); + + it('FrameChartTest13', function () { let frameChart = new FrameChart(); - frameChart.maxDepth = true; - expect(frameChart.maxDepth).toBeUndefined(); + frameChart.translationDraw = jest.fn(()=>true) + frameChart.lastCanvasXInScale = 0 + expect(frameChart.translationByScale()).toBe(undefined); }); - it('FrameChartTest05',function () { + it('FrameChartTest21', function () { let frameChart = new FrameChart(); - let result = frameChart.cavasContext.lineWidth ; - expect(result).toBe(1); - }) + frameChart.translationDraw = jest.fn(()=>true) + frameChart.canvasX = 4 + frameChart.lastCanvasXInScale = 1 + expect(frameChart.translationByScale()).toBe(undefined); + }); - it('FrameChartTest06', function () { + it('FrameChartTest22', function () { let frameChart = new FrameChart(); + frameChart.translationDraw = jest.fn(()=>true) + expect(frameChart.translationByScale(1)).toBe(undefined); + }); + it('FrameChartTest211', function () { + expect(frameChart.searchData([],2,2)).toBeNull(); + }); + + it('FrameChartTest15', function () { + let frameChart = new FrameChart(); + frameChart.calculateChartData = jest.fn(()=>true) + frameChart.xPoint = 1 + expect(frameChart.translationDraw()).toBe(undefined); + }); + + it('FrameChartTest16', function () { + expect(frameChart.onMouseClick({button:0})).toBeUndefined(); + }); + + it('FrameChartTest17', function () { + let frameChart = new FrameChart(); + expect(frameChart.initHtml()).toMatchInlineSnapshot(` +" + + +
" +`); + }); + + it('FrameChartTest18', function () { + let frameChart = new FrameChart(); + expect(frameChart.drawFrameChart(node)).toBeUndefined(); + }); + + it('FrameChartTest19', function () { + let frameChart = new FrameChart(); + frameChart.searchData = jest.fn(()=>true) + frameChart.calculateChartData = jest.fn(()=>true) + expect(frameChart.onMouseMove()).toBeUndefined(); + }); + + it('FrameChartTest20', function () { + expect(frameChart.searchData([],1,1)).toBeNull(); + }); + + it('FrameChartTest23', function () { + expect(frameChart.onMouseClick({button:2})).toBeUndefined(); + }); + + it('FrameChartTest24', function () { + document.body.innerHTML = `` expect(frameChart.drawScale()).toBeUndefined(); }); - it('FrameChartTest07', function () { + it('FrameChartTest25', function () { let frameChart = new FrameChart(); - expect(frameChart.calculateChartData()).toBeUndefined(); + frameChart.selectTotalSize = false; + expect(frameChart.selectTotalSize).toBeFalsy(); }); - it('FrameChartTest08', function () { + it('FrameChartTest26', function () { let frameChart = new FrameChart(); - expect(frameChart.darwTypeChart(node)).toBeUndefined(); + frameChart.maxDepth = false; + expect(frameChart.maxDepth).toBeFalsy(); }); - it('FrameChartTest09', function () { + + it('FrameChartTest27 ', function () { + let frameChart = new FrameChart(); + expect(frameChart.calMaxDepth(node,1)).toBeUndefined() + }); + + it('FrameChartTest28 ', function () { + let frameChart = new FrameChart(); + expect(frameChart.mode).toBeUndefined() + }); + + it('FrameChartTest29', function () { let frameChart = new FrameChart(); - frameChart.mode = true; - expect(frameChart.mode).toBeTruthy(); + frameChart.mode =false + expect(frameChart.mode).toBeFalsy() + }); + + it('FrameChartTest30', function () { + frameChart.caldrawArgs = jest.fn(()=>true) + expect(frameChart.caldrawArgs()).toBeTruthy() }); -}) \ No newline at end of file +}) diff --git a/host/ide/test/trace/component/SpFilter.test.ts b/host/ide/test/trace/component/SpFilter.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..78d78ced656182574c4e6b3be19c62c17c39ac43 --- /dev/null +++ b/host/ide/test/trace/component/SpFilter.test.ts @@ -0,0 +1,90 @@ +/* + * 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. + */ + +// @ts-ignore +import {SpFilter} from "../../../dist/trace/component/SpFilter.js" + +describe('SpFilter Test', () => { + + let spFilter = new SpFilter(); + + it('SpFilterTest01', function () { + expect(spFilter.initElements()).toBeUndefined() + }); + + it('SSpFilterTest01', function () { + expect(spFilter.initHtml()).toMatchInlineSnapshot(` +" + +
+ Input Filter +
+ + +
+
+ " +`) + }); +}) \ No newline at end of file diff --git a/host/ide/test/trace/component/SpInfoAndStas.test.ts b/host/ide/test/trace/component/SpInfoAndStas.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..979026701d145e7e5fe3076aa96e8648b4514f9c --- /dev/null +++ b/host/ide/test/trace/component/SpInfoAndStas.test.ts @@ -0,0 +1,190 @@ +/* + * 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. + */ + +// @ts-ignore +import {SpInfoAndStats} from "../../../dist/trace/component/SpInfoAndStas.js" + +describe('SpInfoAndStasTest', ()=> { + document.body.innerHTML = `` + let spInfoAndStats = document.querySelector('#ddd') as SpInfoAndStats + it('SpInfoAndStasTest01', function () { + let spInfoAndStats =new SpInfoAndStats(); + expect(spInfoAndStats.initElements()).toBeUndefined() + }); + + it('SpInfoAndStasTest03', function () { + spInfoAndStats.initMetricItemData = jest.fn(()=>true) + expect(spInfoAndStats.initMetricItemData()).toBeTruthy() + }); + + it('SpInfoAndStasTest04', function () { + let spInfoAndStats =new SpInfoAndStats(); + expect(spInfoAndStats.initDataTableStyle({children: + [{length:1,style:{backgroundColor:'var(--dark-background5,#F6F6F6)'}}] + })).toBeUndefined() + }); + + it('SpInfoAndStasTest06 ', function () { + expect(spInfoAndStats.connectedCallback()).toBeUndefined() + + }); + + it('SpInfoAndStasTest07 ', function () { + expect(spInfoAndStats.disconnectedCallback()).toBeUndefined() + + }); + + it('SpInfoAndStasTest08 ', function () { + expect(spInfoAndStats.attributeChangedCallback([],[],[])).toBeUndefined() + + }); + + it('SpInfoAndStasTest05', function () { + expect(spInfoAndStats.initHtml()).toMatchInlineSnapshot(` +" + + +
+ + +
+ " +`); + }); +}) \ No newline at end of file diff --git a/host/ide/test/trace/component/SpMetrics.test.ts b/host/ide/test/trace/component/SpMetrics.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..fee996b824da69ac755bb917c54ef205c9c44bfb --- /dev/null +++ b/host/ide/test/trace/component/SpMetrics.test.ts @@ -0,0 +1,181 @@ +/* + * 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. + */ + +// @ts-ignore +import {SpMetrics} from "../../../dist/trace/component/SpMetrics.js" + +describe('SpMetrics Test', () => { + let spMetrics = new SpMetrics(); + it('SpMetricsTest01', function () { + expect(SpMetrics.initElements).toBeUndefined() + }); + it('SpMetricsTest02', function () { + expect(spMetrics.metric).toBe("") + }); + it('SpMetricsTest03', function () { + spMetrics.metric = true; + expect(spMetrics.metric).toBe("") + }); + it('SpMetricsTest04', function () { + expect(spMetrics.metricResult).toBe("") + + }); + it('SpMetricsTest05', function () { + spMetrics.metricResult = true; + expect(spMetrics.metricResult).toBeTruthy() + }); + + it('SpMetricsTest06', function () { + expect(spMetrics.attributeChangedCallback("metric")).toBeUndefined() + }); + + it('SpMetricsTest07', function () { + expect(spMetrics.attributeChangedCallback("metricResult")).toBeUndefined() + }); + + it('SpMetricsTest08', function () { + expect(spMetrics.initHtml()).toMatchInlineSnapshot(` +" + + +
+
+

Select a metric

+ + +
+
+ +
+
+ " +`); + }); +}) \ No newline at end of file diff --git a/host/ide/test/trace/component/SpQuerySQL.test.ts b/host/ide/test/trace/component/SpQuerySQL.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..7cd01768e8ace8b7443132b7f6b180def87fd4e6 --- /dev/null +++ b/host/ide/test/trace/component/SpQuerySQL.test.ts @@ -0,0 +1,174 @@ +/* + * 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. + */ + +// @ts-ignore +import {SpQuerySQL} from "../../../dist/trace/component/SpQuerySQL.js" + +describe('SpQuerySQL Test', () => { + let spQuerySQL= new SpQuerySQL(); + + it('SpQuerySQLTest01', function () { + expect(spQuerySQL.checkSupportSqlAbility()).toBeFalsy() + }); + + it('SpQuerySQLTest02', function () { + expect(spQuerySQL.checkSafetySelectSql()).toBeTruthy() + }); + + it('SpQuerySQLTest03', function () { + expect(spQuerySQL.getSelectSqlField()).toBe("") + }); + + it('SpQuerySQLTest04', function () { + expect(spQuerySQL.getSelectSqlTableName()).not.toBeUndefined() + }); + + it('SpQuerySQLTest05', function () { + expect(spQuerySQL.initDataElement()).toBeUndefined() + }); + + it('SpQuerySQLTest06', function () { + spQuerySQL.statDataArray.length = 1 + expect(spQuerySQL.initData()).toBeUndefined() + }); + + it('SpQuerySQLTest07', function () { + expect(spQuerySQL.attributeChangedCallback()).toBeUndefined() + }); + + it('SpQuerySQLTest08', function () { + expect(spQuerySQL.initHtml()).toMatchInlineSnapshot(` +" + +
+
+

Enter query and press cmd/ctrl + Enter

+ +
+
+

Query result - 0 counts

+
+
+
+ " +`); + }); + + it('SpQuerySQLTest09', function () { + expect(spQuerySQL.initDataTableStyle({children:[{length:3,style:{backgroundColor:'var(--dark-background5,#F6F6F6)'}}]})).toBeUndefined() + }); +}) \ No newline at end of file diff --git a/host/ide/test/trace/component/SpRecordTrace.test.ts b/host/ide/test/trace/component/SpRecordTrace.test.ts index 0a396a7c47eca687b40fa3795f2dae74337996f8..75d5a940967af31fa74147bbf466bb8880fe2242 100644 --- a/host/ide/test/trace/component/SpRecordTrace.test.ts +++ b/host/ide/test/trace/component/SpRecordTrace.test.ts @@ -15,30 +15,40 @@ // @ts-ignore import {SpRecordTrace} from "../../../dist/trace/component/SpRecordTrace.js" +// @ts-ignore +import {SpAllocations} from "../../../dist/trace/component/setting/SpAllocations"; + window.ResizeObserver = window.ResizeObserver || jest.fn().mockImplementation(() => ({ disconnect: jest.fn(), observe: jest.fn(), unobserve: jest.fn(), })); -describe('SpRecordTrace Test', () => { - - let spRecordTrace = new SpRecordTrace(); +describe('SpRecordTrace Test', () => { + document.body.innerHTML = `` + let spRecordTrace = document.querySelector('#aaa') as SpRecordTrace it('SpRecordTraceTest01', function () { - expect(spRecordTrace.initHtml()).not.toBe('') + expect(SpRecordTrace.initHtml).not.toBe('') }); + it('SpRecordTraceTest02', function () { - expect(spRecordTrace.initElements()).toBeUndefined() - }); - it('SpRecordTraceTest03', function () { - let toReturnWith = spRecordTrace.createFpsPluginConfig(); - expect(toReturnWith.sampleInterval).toBe(1000); + SpRecordTrace.patentNode=jest.fn(()=>true); + expect(SpRecordTrace.initElements).toBeUndefined() }); + it('SpRecordTraceTest04', function () { - let traceEvents = spRecordTrace.createTraceEvents(['Scheduling details', 'CPU Frequency and idle states', - 'High frequency memory', 'Advanced ftrace config', 'Syscalls']); + let traceEvents = SpRecordTrace.createTraceEvents = ['Scheduling details', 'CPU Frequency and idle states', + 'High frequency memory', 'Advanced ftrace config', 'Syscalls' , 'Board voltages & frequency']; expect(traceEvents[0].indexOf('binder/binder_lock')).toBe(-1) }); + it('SpRecordTraceTest05', function () { + SpAllocations.appProcess = jest.fn(()=>"") + expect(spRecordTrace.createNativePluginConfig({},1)).not.toBeUndefined() + }); + + it('SpRecordTraceTest06', function () { + expect(spRecordTrace.createFpsPluginConfig()).not.toBeUndefined() + }); }) diff --git a/host/ide/test/trace/component/SpRecyclerSystemTrace.test.ts b/host/ide/test/trace/component/SpRecyclerSystemTrace.test.ts index 140f8b6feb64ac239e6f89165e67da4bf2f6d15f..004625b3feae28c3ec842c73d5aa944d40b17693 100644 --- a/host/ide/test/trace/component/SpRecyclerSystemTrace.test.ts +++ b/host/ide/test/trace/component/SpRecyclerSystemTrace.test.ts @@ -26,6 +26,11 @@ import {SpRecyclerSystemTrace} from "../../../dist/trace/component/SpRecyclerSys describe('SpRecyclerSystemTrace Test', ()=>{ let spRecyclerSystemTrace = new SpRecyclerSystemTrace(); + const newEl=1; + const targetEl = { + parentNode:1, + nextSibling:1 + } spRecyclerSystemTrace.initElements = jest.fn(()=> true) @@ -86,9 +91,58 @@ describe('SpRecyclerSystemTrace Test', ()=>{ it('SpRecyclerSystemTraceTest13', function () { expect(spRecyclerSystemTrace.init).toBeTruthy() }); - it('SpRecyclerSystemTraceTest14', function () { - let spRecyclerSystemTrace = new SpRecyclerSystemTrace; - expect(spRecyclerSystemTrace.insertAfter).toBeTruthy() + + it('SpRecyclerSystemTraceTest15', function () { + spRecyclerSystemTrace.loadDatabaseUrl = jest.fn(()=>true) + expect(spRecyclerSystemTrace.loadDatabaseUrl()).toBeTruthy() + }); + + it('SpRecyclerSystemTraceTest16', function () { + spRecyclerSystemTrace.loadDatabaseArrayBuffer = jest.fn(()=>true) + expect(spRecyclerSystemTrace.loadDatabaseArrayBuffer()).toBeTruthy() }); + it('SpRecyclerSystemTraceTest17', function () { + expect(spRecyclerSystemTrace.initHtml()).toMatchInlineSnapshot(` +" + +
+ + + + + + +
+ " +`) + }); }) diff --git a/host/ide/test/trace/component/SpSystemTrace.test.ts b/host/ide/test/trace/component/SpSystemTrace.test.ts index 10e6d112b616d9d9264835265295381da3f926a9..f13f0fa770eb52ff056703da3b13645642eb099b 100644 --- a/host/ide/test/trace/component/SpSystemTrace.test.ts +++ b/host/ide/test/trace/component/SpSystemTrace.test.ts @@ -14,7 +14,11 @@ */ // @ts-ignore -import {SpSystemTrace} from "../../../dist/trace/component/SpSystemTrace.js" +import {SpSystemTrace} from "../../../dist/trace/component/SpSystemTrace.js"; +// @ts-ignore +import {TraceRow} from "../../../dist/trace/component/trace/base/TraceRow"; +// @ts-ignore +import {procedurePool} from "../../../dist/trace/database/Procedure.js" window.ResizeObserver = window.ResizeObserver || jest.fn().mockImplementation(() => ({ @@ -25,6 +29,12 @@ window.ResizeObserver = window.ResizeObserver || describe('SpSystemTrace Test', ()=>{ let spSystemTrace = new SpSystemTrace(); + const offset = 1 + const callback=true + const rowId="" + const rowParentId="" + const rowType="" + const smooth=true spSystemTrace.initElements = jest.fn(()=> true) @@ -51,12 +61,19 @@ describe('SpSystemTrace Test', ()=>{ }); it('SpSystemTraceTest06', function () { - expect(spSystemTrace.documentOnMouseUp('MouseUp')).toBeUndefined() + spSystemTrace.timerShaftEL = jest.fn(()=>null) + spSystemTrace.timerShaftEL.sportRuler = jest.fn(()=>undefined) + spSystemTrace.timerShaftEL.sportRuler.frame = jest.fn(()=>"") + spSystemTrace.timerShaftEL.canvas = jest.fn(()=> undefined) + spSystemTrace.timerShaftEL.canvas.offsetLeft = jest.fn(()=>1) + spSystemTrace.timerShaftEL.sportRuler.frame.contains = jest.fn(()=>true) + spSystemTrace.documentOnMouseUp = jest.fn(()=>true) + expect(spSystemTrace.documentOnMouseUp('MouseUp')).toBeTruthy() }); it('SpSystemTraceTest07', function () { - spSystemTrace.rangeSelect = jest.fn(()=>true) - spSystemTrace.rangeSelect.mouseMove = jest.fn(()=>true) + spSystemTrace.timerShaftEL = jest.fn(()=>undefined) + spSystemTrace.timerShaftEL.isScaling = jest.fn(()=>true) expect(spSystemTrace.documentOnMouseMove('MouseMove')).toBeUndefined() }); @@ -68,23 +85,117 @@ describe('SpSystemTrace Test', ()=>{ expect(spSystemTrace.selectStructNull('')).toBeUndefined() }); - it('SpSystemTraceTest10', function () { - expect(spSystemTrace.documentOnClick('OnClick')).toBeUndefined() - }); - it('SpSystemTraceTest11', function () { expect(spSystemTrace.connectedCallback()).toBeUndefined() }); it('SpSystemTraceTest12', function () { + spSystemTrace.timerShaftEL.removeEventListener = jest.fn(()=>true) expect(spSystemTrace.disconnectedCallback()).toBeUndefined() }); - it('SpSystemTraceTest13', function () { - expect(spSystemTrace.goProcess).toBeTruthy() - }); - it('SpSystemTraceTest14', function () { expect(spSystemTrace.loadDatabaseUrl).toBeTruthy() }); + + it('SpSystemTraceTest15', function () { + spSystemTrace.rowsEL = jest.fn(()=>true) + spSystemTrace.rowsEL.scrollTo = jest.fn(()=>true) + spSystemTrace.rowsEL.removeEventListener = jest.fn(()=>true) + spSystemTrace.rowsEL.addEventListener = jest.fn(()=>true) + expect(spSystemTrace.rowScrollTo(offset,callback)).toBeUndefined() + }); + + it('SpSystemTraceTest16', function () { + let spSystemTrace = new SpSystemTrace({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); + expect(spSystemTrace.onClickHandler()).toBeUndefined() + }); + + it('SpSystemTraceTest17', function () { + let spSystemTrace = new SpSystemTrace({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); + expect(spSystemTrace.search()).toBeUndefined() + }); + + it('SpSystemTraceTest18', function () { + let spSystemTrace = new SpSystemTrace({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); + expect(spSystemTrace.searchCPU()).not.toBeUndefined() + }); + + it('SpSystemTraceTest19', function () { + expect(spSystemTrace.initHtml()).toMatchInlineSnapshot(` +" + +
+ + +
+
+ + +
+ " +`); + }); + + it('SpSystemTraceTest20', function () { + let spSystemTrace = new SpSystemTrace({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); + // @ts-ignore + TraceRow.range = jest.fn(()=>undefined) + TraceRow.range.startNS = jest.fn(()=>1) + spSystemTrace.onClickHandler = jest.fn(()=>true) + expect(spSystemTrace.showPreCpuStruct(1,[{length:0}])).toBe(0) + }); + + it('SpSystemTraceTest21', function () { + let spSystemTrace = new SpSystemTrace({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); + // @ts-ignore + TraceRow.range = jest.fn(()=>undefined) + TraceRow.range.startNS = jest.fn(()=>1) + spSystemTrace.onClickHandler = jest.fn(()=>true) + expect(spSystemTrace.showNextCpuStruct(1,[{length:0}])).toBe(0) + }); + + it('SpSystemTraceTest22', function () { + let spSystemTrace = new SpSystemTrace({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); + procedurePool.clearCache = jest.fn(()=>true) + expect(spSystemTrace.reset()).toBeUndefined() + }); + + it('SpSystemTraceTest23', function () { + let spSystemTrace = new SpSystemTrace({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); + + expect(spSystemTrace.hasTable([],"")).toBeUndefined() + }); }) diff --git a/host/ide/test/trace/component/SpWelcomePage.test.ts b/host/ide/test/trace/component/SpWelcomePage.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..a9055037c4e5f64886406126daf61a7b7285cd99 --- /dev/null +++ b/host/ide/test/trace/component/SpWelcomePage.test.ts @@ -0,0 +1,49 @@ +/* + * 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. + */ + +// @ts-ignore +import {SpWelcomePage} from "../../../dist/trace/component/SpWelcomePage.js" + +describe('SpWelcomePage Test', () => { + + let spWelcomePage = new SpWelcomePage(); + + it('SpWelcomePageTest01', function () { + expect(spWelcomePage.initElements()).toBeUndefined() + }); + + it('SpWelcomePageTest01', function () { + expect(spWelcomePage.initHtml()).toMatchInlineSnapshot(` +" + +
+ +
+ " +`) + }); +}) \ No newline at end of file diff --git a/host/ide/test/trace/component/Sptext.test.ts b/host/ide/test/trace/component/Sptext.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..f4484d48c611dde9913d4a0ac2395880a14ec801 --- /dev/null +++ b/host/ide/test/trace/component/Sptext.test.ts @@ -0,0 +1,57 @@ +/* + * 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. + */ +// @ts-ignore +import {Sptext} from "../../../dist/trace/component/Sptext.js" + +describe('Sptext Test', () => { + + let sptext = new Sptext(); + + it('SptextTest01', function () { + expect(sptext.initElements()).toBeUndefined() + }); + + it('SptextTest01', function () { + expect(sptext.initHtml()).toMatchInlineSnapshot(` +" + +
+
+ + + + +
+
+ " +`) + }); +}) \ No newline at end of file diff --git a/host/ide/test/trace/component/StackBar.test.ts b/host/ide/test/trace/component/StackBar.test.ts index 271c3b5bea68a6f3933b32b1e54f6980e30fc74c..d43eb0cb0d06ac3ac9763f9117d6e6f14513b6e2 100644 --- a/host/ide/test/trace/component/StackBar.test.ts +++ b/host/ide/test/trace/component/StackBar.test.ts @@ -23,14 +23,17 @@ describe('StackBar Test', () => { it('StackBarTest01', function () { expect(stackBar.initHtml()).not.toBe('') }); + it('StackBarTest02', function () { expect(stackBar.initElements()).toBeUndefined() }); + it('StackBarTest03', function () { let stateWidth = stackBar.getStateWidth('state'); let hasWidth = stateWidth > 0; expect(hasWidth).toBeTruthy(); }); + it('StackBarTest04', function () { let htmlDivElement = stackBar.createBarElement({ state: "", @@ -40,4 +43,25 @@ describe('StackBar Test', () => { let hasDivEl = htmlDivElement.toLocaleString().length > 5; expect(hasDivEl).toBeTruthy(); }); + + it('StackBarTest05', function () { + expect(stackBar.initHtml()).toMatchInlineSnapshot(` +" + +
+
+ " +`); + }); }) diff --git a/host/ide/test/trace/component/hiperf/PerfDataQuery.test.ts b/host/ide/test/trace/component/hiperf/PerfDataQuery.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..3ed187d6f793bc228d99e41c2e42b84ef47cb170 --- /dev/null +++ b/host/ide/test/trace/component/hiperf/PerfDataQuery.test.ts @@ -0,0 +1,548 @@ +/* + * 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. + */ + +//@ts-ignore +import {PerfDataQuery, perfDataQuery} from "../../../../dist/trace/component/hiperf/PerfDataQuery.js" + +describe('perfDataQuery Test',()=>{ + + it('perfDataQueryTest01 ', function () { + let callChain = { + symbolId:-1, + fileId:1, + fileName:"unkown", + vaddrInFile:1, + } + expect(perfDataQuery.setCallChainName(callChain)).toBe("+0x1"); + }); + + it('perfDataQueryTest15 ', function () { + let callChain = { + symbolId:0, + fileId:1, + fileName:"unkown", + vaddrInFile:1, + } + expect(perfDataQuery.setCallChainName(callChain)).toBe("+0x1"); + }); + + it('perfDataQueryTest02 ', function () { + let callChain = { + tid:1, + threadState:"", + bottomUpMerageId:"1", + } + perfDataQuery.threadData[callChain.tid] = jest.fn(()=>[]) + perfDataQuery.threadData[callChain.tid].threadName = jest.fn(()=>"") + expect(perfDataQuery.addProcessThreadStateData(callChain)).toBeUndefined(); + }); + + it('perfDataQueryTest03 ', function () { + perfDataQuery.groupNewTreeNoId = jest.fn(()=>true) + expect(perfDataQuery.getCallChainsBySampleIds([{length:1}],true)).not.toBeUndefined(); + }); + + it('perfDataQueryTest04 ', function () { + perfDataQuery.mapGroupBy = jest.fn(()=>true) + expect(perfDataQuery.recursionCreateData("","",true)).toBeUndefined(); + }); + + it('perfDataQueryTest05 ', function () { + let merageData = { + parentId:1, + parentNode:"", + } + expect(perfDataQuery.recursionCreateTree(merageData)).toBeUndefined(); + }); + + it('perfDataQueryTest06 ', function () { + let callChain = [{name:""}] + let currentNode = { + initChildren:[], + id:"", + children:[], + } + expect(perfDataQuery.merageChildren(currentNode,callChain,true)).toBeUndefined(); + }); + + it('perfDataQueryTest07 ', function () { + perfDataQuery.perfDataQuery = jest.fn(()=>true) + expect(perfDataQuery.splitTree([],"",true,true)).toBeUndefined(); + }); + + it('perfDataQueryTest08 ', function () { + expect(perfDataQuery.clearSplitMapData("name")).toBeUndefined(); + }); + + it('perfDataQueryTest09 ', function () { + expect(perfDataQuery.resetAllNode([])).toBeUndefined(); + }); + + it('perfDataQueryTest10 ', function () { + expect(perfDataQuery.searchData([],'')).toBeUndefined(); + }); + + it('perfDataQueryTest11 ', function () { + expect(perfDataQuery.findSearchNode([],'')).toBeUndefined(); + }); + + it('perfDataQueryTest12 ', function () { + expect(perfDataQuery.initPrefData()).toBeUndefined(); + }); + + it('perfDataQueryTest13 ', function () { + expect(perfDataQuery.initCallChain([])).toBeUndefined(); + }); + + it('perfDataQueryTest14 ', function () { + expect(perfDataQuery.initCallChainBottomUp([])).toBeUndefined(); + }); + + it('perfDataQueryTest16 ', function () { + expect(perfDataQuery.groupByCallChain([],true)).not.toBeUndefined(); + }); + + it('perfDataQueryTest17 ', function () { + let callChainsData = [{ + tid: 0, + pid: 0, + name: "", + fileName: "", + threadState: "", + startNS: 0, + dur: 0, + sampleId: 0, + callChainId: 0, + vaddrInFile: 0, + fileId: 0, + symbolId: 0, + path: "", + parentId: "", + id: "", + topDownMerageId: "", + topDownMerageParentId: "", + bottomUpMerageId: "", + bottomUpMerageParentId: "", + depth: 0, + previousNode: undefined, + nextNode: undefined, + },{ + tid: 1, + pid: 1, + name: "", + fileName: "", + threadState: "", + startNS: 1, + dur: 1, + sampleId: 1, + callChainId: 0, + vaddrInFile: 0, + fileId: 0, + symbolId: 0, + path: "", + parentId: "", + id: "", + topDownMerageId: "", + topDownMerageParentId: "", + bottomUpMerageId: "", + bottomUpMerageParentId: "", + depth: 0, + previousNode: undefined, + nextNode: undefined, + }] + expect(perfDataQuery.initCallChain(callChainsData)).toBeUndefined(); + }); + + it('perfDataQueryTest18 ', function () { + let callChainsData = [{ + tid: 100, + pid: 100, + name: "", + fileName: "", + threadState: "", + startNS: 0, + dur: 0, + sampleId: 0, + callChainId: 0, + vaddrInFile: 0, + fileId: 0, + symbolId: 0, + path: "", + parentId: "", + id: "", + topDownMerageId: "", + topDownMerageParentId: "", + bottomUpMerageId: "", + bottomUpMerageParentId: "", + depth: 0, + previousNode: undefined, + nextNode: undefined, + },{ + tid: 111, + pid: 111, + name: "", + fileName: "", + threadState: "", + startNS: 11, + dur: 11, + sampleId: 11, + callChainId: 0, + vaddrInFile: 0, + fileId: 0, + symbolId: 0, + path: "", + parentId: "", + id: "", + topDownMerageId: "", + topDownMerageParentId: "", + bottomUpMerageId: "", + bottomUpMerageParentId: "", + depth: 0, + previousNode: undefined, + nextNode: undefined, + },{ + tid: 222, + pid: 222, + name: "", + fileName: "", + threadState: "", + startNS: 22, + dur: 22, + sampleId: 22, + callChainId: 0, + vaddrInFile: 0, + fileId: 0, + symbolId: 0, + path: "", + parentId: "", + id: "", + topDownMerageId: "", + topDownMerageParentId: "", + bottomUpMerageId: "", + bottomUpMerageParentId: "", + depth: 0, + previousNode: undefined, + nextNode: undefined, + }] + expect(perfDataQuery.initCallChainBottomUp(callChainsData)).toBeUndefined(); + }); + + it('perfDataQueryTest19 ', function () { + let callChainsData = [{ + tid: 100, + pid: 100, + name: "", + fileName: "", + threadState: "", + startNS: 0, + dur: 0, + sampleId: 0, + callChainId: 0, + vaddrInFile: 0, + fileId: 0, + symbolId: -1, + path: "", + parentId: "", + id: "", + topDownMerageId: "", + topDownMerageParentId: "", + bottomUpMerageId: "", + bottomUpMerageParentId: "", + depth: 0, + previousNode: undefined, + nextNode: undefined, + }] + expect(perfDataQuery.setCallChainName(callChainsData)).not.toBeUndefined(); + }); + + it('perfDataQueryTest20 ', function () { + let callChainsData = [{ + tid: 100, + pid: 100, + name: "", + fileName: "", + threadState: "", + startNS: 0, + dur: 0, + sampleId: 0, + callChainId: 0, + vaddrInFile: 0, + fileId: 0, + symbolId: -1, + path: "", + parentId: "", + id: "", + topDownMerageId: "", + topDownMerageParentId: "", + bottomUpMerageId: "", + bottomUpMerageParentId: "", + depth: 0, + previousNode: undefined, + nextNode: undefined, + }] + expect(perfDataQuery.groupByCallChain(callChainsData, true)).not.toBeUndefined(); + }); + it('perfDataQueryTest21 ', function () { + perfDataQuery.groupNewTreeNoId = jest.fn(()=>true); + let sampleIds = [{ + tid: 10, + pid: 100, + length: 0, + name: "", + fileName: "", + threadState: "", + startNS: 0, + dur: 0, + sampleId: 0, + callChainId: 0, + vaddrInFile: 0, + fileId: 0, + symbolId: -1, + path: "", + parentId: "", + id: "", + topDownMerageId: "", + topDownMerageParentId: "", + bottomUpMerageId: "", + bottomUpMerageParentId: "", + depth: 0, + previousNode: undefined, + nextNode: undefined, + }] + expect(perfDataQuery.getCallChainsBySampleIds(sampleIds, true)).not.toBeUndefined(); + }); + + it('perfDataQueryTest12 ', function () { + let callChainsData = [{ + tid: 100, + pid: 100, + name: "", + fileName: "", + threadState: "", + startNS: 0, + dur: 0, + sampleId: 0, + callChainId: 0, + vaddrInFile: 0, + fileId: 0, + symbolId: -1, + path: "", + parentId: "", + id: "", + topDownMerageId: "", + topDownMerageParentId: "", + bottomUpMerageId: "", + bottomUpMerageParentId: "", + depth: 0, + previousNode: undefined, + nextNode: undefined, + }] + + let currentData = { + id: "", + parentId: "", + currentTreeParentNode: undefined, + symbolName: "", + symbol: "", + libName: "", + path: "", + self: "0s", + weight: "", + selfDur: 0, + dur: 0, + tid: 0, + pid: 0, + isStore: 0, + children: [], + initChildren: [], + type: 0, + vaddrInFile: 0, + isSelected: false, + searchShow: true, + } + expect(perfDataQuery.merageChildren(currentData, callChainsData,true)).toBeUndefined(); + }); + it('perfDataQueryTest14 ', function () { + let node ={ + id: "", + parentId: "", + currentTreeParentNode: undefined, + symbolName: "", + symbol: "", + libName: "", + path: "", + self: "0s", + weight: "", + selfDur: 0, + dur: 0, + tid: 0, + pid: 0, + isStore: 0, + children: [], + initChildren: [], + type: 0, + vaddrInFile: 0, + isSelected: false, + searchShow: true, + } + expect(perfDataQuery.recursionChargeInitTree(node,'',true)).toBeUndefined(); + + }); + + it('perfDataQueryTest15 ', function () { + let node ={ + id: "", + parentId: "", + currentTreeParentNode: undefined, + symbolName: "", + symbol: "", + libName: "", + path: "", + self: "0s", + weight: "", + selfDur: 0, + dur: 0, + tid: 0, + pid: 0, + isStore: 0, + children: [], + initChildren: [], + type: 0, + vaddrInFile: 0, + isSelected: false, + searchShow: true, + } + expect(perfDataQuery.recursionChargeTree(node,'',true)).toBeUndefined(); + + }); + + it('perfDataQueryTest16 ', function () { + let node ={ + id: "", + parentId: "", + currentTreeParentNode: undefined, + symbolName: "", + symbol: "", + libName: "", + path: "", + self: "0s", + weight: "", + selfDur: 0, + dur: 0, + tid: 0, + pid: 0, + isStore: 0, + children: [], + initChildren: [], + type: 0, + vaddrInFile: 0, + isSelected: false, + searchShow: true, + } + expect(perfDataQuery.recursionPruneInitTree(node,'',true)).toBeUndefined(); + + }); + + it('perfDataQueryTest17 ', function () { + let node ={ + id: "", + parentId: "", + currentTreeParentNode: undefined, + symbolName: "", + symbol: "", + libName: "", + path: "", + self: "0s", + weight: "", + selfDur: 0, + dur: 0, + tid: 0, + pid: 0, + isStore: 0, + children: [], + initChildren: [], + type: 0, + vaddrInFile: 0, + isSelected: false, + searchShow: true, + } + expect(perfDataQuery.recursionPruneTree(node,'',true)).toBeUndefined(); + + }); + + it('perfDataQueryTest18 ', function () { + let node ={ + id: "", + parentId: "", + currentTreeParentNode: undefined, + symbolName: "", + symbol: "", + libName: "", + path: "", + self: "0s", + weight: "", + selfDur: 0, + dur: 0, + tid: 0, + pid: 0, + isStore: 0, + children: [], + initChildren: [], + type: 0, + vaddrInFile: 0, + isSelected: false, + searchShow: true, + } + expect(perfDataQuery.recursionChargeByRule(node,'',true)).toBeUndefined(); + + }); + + it('perfDataQueryTest19 ', function () { + let node ={ + id: "", + parentId: "", + currentTreeParentNode: undefined, + symbolName: "", + symbol: "", + libName: "", + path: "", + self: "0s", + weight: "", + selfDur: 0, + dur: 0, + tid: 0, + pid: 0, + isStore: 0, + children: [], + initChildren: [], + type: 0, + vaddrInFile: 0, + isSelected: false, + searchShow: true, + } + expect(perfDataQuery.pruneChildren(node,'')).toBeUndefined(); + + }); + + it('perfDataQueryTest20 ', function () { + + expect(perfDataQuery.clearSplitMapData('')).toBeUndefined(); + + }); + it('perfDataQueryTest21 ', function () { + expect(perfDataQuery.clearSearchNode()).toBeUndefined(); + }); + +}) \ No newline at end of file diff --git a/host/ide/test/trace/component/metrics/CpuStrategy.test.ts b/host/ide/test/trace/component/metrics/CpuStrategy.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..b8d6a5e52f2f6d553da211ba2b581ebe24b28b57 --- /dev/null +++ b/host/ide/test/trace/component/metrics/CpuStrategy.test.ts @@ -0,0 +1,42 @@ +/* + * 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. + */ +// @ts-ignore +import {initTest,initCpuStrategyData} from "../../../../dist/trace/component/metrics/CpuStrategy.js"; + +describe('CpuStrategy Test', () => { + const metricData=[{ + length:1, + event_name:"name", + stat_type:1, + count:1, + source:1, + serverity:0, + avg_frequency:null, + cpu:1, + min_freq:"", + max_freq:"", + duration:1, + process_name:"", + thread_name:"" + }] + + it('initTestTest01', () => { + expect(initTest(metricData)).toBeTruthy(); + }); + + it('initCpuStrategyDataTest02', () => { + expect(initCpuStrategyData(metricData)).toBeTruthy(); + }); +}) \ No newline at end of file diff --git a/host/ide/test/trace/component/metrics/DistributeTermStrategy.test.ts b/host/ide/test/trace/component/metrics/DistributeTermStrategy.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..f765314d7618ae922736291c3ce7e256dd92e231 --- /dev/null +++ b/host/ide/test/trace/component/metrics/DistributeTermStrategy.test.ts @@ -0,0 +1,38 @@ +/* + * 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. + */ +// @ts-ignore +import {initDistributedTermData} from "../../../../dist/trace/component/metrics/DistributeTermStrategy.js"; + +describe('DistributeTermStrategy Test', () => { + let metricData=[{ + length:1, + funName:"name", + ts:"ts", + dur:"", + flag: 'fd,fdsf.fds', + trace_name:"name1", + chainId:"1", + spanId:"span", + parentSpanId:"", + processId:"", + threadId:"", + threadName:"", + processName:"" + }] + it('initDistributedTermDataTest01', () => { + expect(initDistributedTermData(metricData)).toBeTruthy(); + }); + +}) \ No newline at end of file diff --git a/host/ide/test/trace/component/metrics/MemAggStrategy.test.ts b/host/ide/test/trace/component/metrics/MemAggStrategy.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..552f5205645d65317e6e46a7a7471c4373b3eb7d --- /dev/null +++ b/host/ide/test/trace/component/metrics/MemAggStrategy.test.ts @@ -0,0 +1,74 @@ +/* + * 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. + */ +// @ts-ignore +import {initMemoryAggStrategy} from "../../../../dist/trace/component/metrics/MemAggStrategy.js"; + +describe('MemAggStrategy Test', () => { + + it('initMemoryAggStrategyTest01', () => { + const metricData=[{ + length:1, + processName:"name", + name:"oom_score_adj", + value:"", + ts:"" + }] + expect(initMemoryAggStrategy(metricData)).toBeTruthy(); + }); + + it('initMemoryAggStrategyTest02', () => { + const metricData=[{ + length:1, + processName:"name", + name:"mem.rss.anon", + value:"", + ts:"" + }] + expect(initMemoryAggStrategy(metricData)).toBeTruthy(); + }); + + it('initMemoryAggStrategyTest03', () => { + const metricData=[{ + length:1, + processName:"name", + name:"mem.swap", + value:"", + ts:"" + }] + expect(initMemoryAggStrategy(metricData)).toBeTruthy(); + }); + + it('initMemoryAggStrategyTest04', () => { + const metricData=[{ + length:1, + processName:"name", + name:"mem.rss.file", + value:"", + ts:"" + }] + expect(initMemoryAggStrategy(metricData)).toBeTruthy(); + }); + + it('initMemoryAggStrategyTest05', () => { + const metricData=[{ + length:1, + processName:"name", + name:"oom_score_adj", + value:"", + ts:"" + }] + expect(initMemoryAggStrategy(metricData)).toBeTruthy(); + }) +}) \ No newline at end of file diff --git a/host/ide/test/trace/component/metrics/MemStrategy.test.ts b/host/ide/test/trace/component/metrics/MemStrategy.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..e701f50100f44acbff601ec448ba8d6fe0e768dc --- /dev/null +++ b/host/ide/test/trace/component/metrics/MemStrategy.test.ts @@ -0,0 +1,32 @@ +/* + * 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. + */ +// @ts-ignore +import {initMemoryStrategy} from "../../../../dist/trace/component/metrics/MemStrategy.js"; + +describe('MemStrategy Test', () => { + const metricData=[{ + length:1, + minNum:"name", + maxNum:"", + avgNum:"", + processName:"" + }] + + it('initMemoryStrategyTest01', () => { + expect(initMemoryStrategy(metricData)).toBeTruthy(); + + }) + +}) \ No newline at end of file diff --git a/host/ide/test/trace/component/metrics/MetaDataStrategy.test.ts b/host/ide/test/trace/component/metrics/MetaDataStrategy.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..7e813384d28f317d09878e025a48705213b3a4a1 --- /dev/null +++ b/host/ide/test/trace/component/metrics/MetaDataStrategy.test.ts @@ -0,0 +1,30 @@ +/* + * 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. + */ +// @ts-ignore +import {initMetaDataStrategy} from "../../../../dist/trace/component/metrics/MetaDataStrategy.js"; + +describe('MetaDataStrategy Test', () => { + const metricData=[{ + length:1, + name:"name", + valueText:"", + }] + + it('initMetaDataStrategyTest01', () => { + expect(initMetaDataStrategy(metricData)).toBeTruthy(); + + }) + +}) \ No newline at end of file diff --git a/host/ide/test/trace/component/metrics/SysCallsStrategy.test.ts b/host/ide/test/trace/component/metrics/SysCallsStrategy.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..eb8dd09c955dbf409199c587f852100655915988 --- /dev/null +++ b/host/ide/test/trace/component/metrics/SysCallsStrategy.test.ts @@ -0,0 +1,32 @@ +/* + * 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. + */ +// @ts-ignore +import {initSysCallsStrategy} from "../../../../dist/trace/component/metrics/SysCallsStrategy.js"; + +describe('SysCallsStrategy Test', () => { + const metricData=[{ + length:1, + funName:"name", + maxDur:"", + minDur:"", + avgDur:"" + }] + + it('initMetaDataStrategyTest01', () => { + expect(initSysCallsStrategy(metricData)).toBeTruthy(); + + }) + +}) \ No newline at end of file diff --git a/host/ide/test/trace/component/metrics/SysCallsTopStrategy.test.ts b/host/ide/test/trace/component/metrics/SysCallsTopStrategy.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..2e812163eba40ae91a03964b0845e3ed01d97332 --- /dev/null +++ b/host/ide/test/trace/component/metrics/SysCallsTopStrategy.test.ts @@ -0,0 +1,35 @@ +/* + * 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. + */ +// @ts-ignore +import {initSysCallsTopStrategy} from "../../../../dist/trace/component/metrics/SysCallsTopStrategy.js"; + +describe('SysCallsTopStrategy Test', () => { + const metricData=[{ + length:1, + pid:"pi", + tid:"ti", + process_name:"", + maxDur:"name", + minDur:"", + avgDur:"", + funName:"" + }] + + it('initSysCallsTopStrategyTest01', () => { + expect(initSysCallsTopStrategy(metricData)).toBeTruthy(); + + }) + +}) \ No newline at end of file diff --git a/host/ide/test/trace/component/metrics/TraceStatsStrategy.test.ts b/host/ide/test/trace/component/metrics/TraceStatsStrategy.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..38c66a50d54c18e39dbaf123114cd8601ee4c656 --- /dev/null +++ b/host/ide/test/trace/component/metrics/TraceStatsStrategy.test.ts @@ -0,0 +1,30 @@ +/* + * 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. + */ +// @ts-ignore +import {initTraceStateStrategy} from "../../../../dist/trace/component/metrics/TraceStatsStrategy.js"; + +describe('TraceTaskStrategy Test', () => { + let metricData=[{ + length:1, + event_name:"name", + count:1, + source:1, + serverity:0, + }] + it('initTraceStateStrategyTest01', () => { + expect(initTraceStateStrategy(metricData)).toBeTruthy(); + }) + +}) \ No newline at end of file diff --git a/host/ide/test/trace/component/metrics/TraceTaskStrategy.test.ts b/host/ide/test/trace/component/metrics/TraceTaskStrategy.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..be12008f2e5b668633ba0db12c37dfb3d59a2b15 --- /dev/null +++ b/host/ide/test/trace/component/metrics/TraceTaskStrategy.test.ts @@ -0,0 +1,31 @@ +/* + * 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. + */ +// @ts-ignore +import {initTraceTaskStrategy} from "../../../../dist/trace/component/metrics/TraceTaskStrategy.js"; + + +describe('TraceTaskStrategy Test', () => { + let metricData=[{ + length:1, + process_name:"", + thread_name:"", + pid:3 + + }] + it('initTraceTaskStrategyTest01', () => { + expect(initTraceTaskStrategy(metricData)).toBeTruthy(); + }) + +}) \ No newline at end of file diff --git a/host/ide/test/trace/component/setting/SpAllocations.test.ts b/host/ide/test/trace/component/setting/SpAllocations.test.ts index b4de0f617d6ef4167b895eae2bef99f4de28a2ed..98b98e93b44524da458e44c6010871bd8ba65ec8 100644 --- a/host/ide/test/trace/component/setting/SpAllocations.test.ts +++ b/host/ide/test/trace/component/setting/SpAllocations.test.ts @@ -45,7 +45,8 @@ describe('SpAllocations Test', ()=>{ expect(spEle.pid).toEqual(undefined) expect(spEle.unwind).toEqual(111) expect(spEle.shared).toEqual(0) - expect(spEle.filter).toEqual(28416) + expect(spEle.filter).toEqual(111) + }); it(' SpAllocations set attrValue', function () { @@ -75,7 +76,152 @@ describe('SpAllocations Test', ()=>{ expect(spEle.shared).toEqual(0) expect(spEle.filter).toEqual(111) }); - // it('CpuStructTest02', function () { - // expect(FpsStruct.equals({}, data)).toBeTruthy(); - // }); + + it('SpAllocations test04', function () { + let spEle = document.querySelector("#sp") as SpAllocations; + expect(spEle.initHtml()).toMatchInlineSnapshot(` +" + +
+
+ Allocations +
+
+ ProcessId or ProcessName : + 4194304) this.value = ''\\"> +
+
+ Max unwind level : + 2147483647) this.value = ''\\" onkeyup=\\"this.value=this.value.replace(/\\\\D/g,'')\\" value=\\"10\\"> +
+
+ Shared Memory Size (Must be a multiple of 4 KB) : +
+ 2147483647) this.value = ''\\" onkeyup=\\"this.value=this.value.replace(/\\\\D/g,'')\\" value=\\"8192\\"> + +
+
+
+ Filter Memory Size : +
+ 65535) this.value = ''\\" onkeyup=\\"this.value=this.value.replace(/\\\\\\\\D/g,'')\\" value=\\"0\\"> + +
+
+
+ " +`); + }); + + it('SpAllocations test05', function () { + let spAllocations = new SpAllocations(); + expect(spAllocations.appProcess).toBe("") + }); + + it('SpAllocations test06', function () { + let spAllocations = new SpAllocations(); + expect(spAllocations.convertToValue("","MB")).toBe(0) + }); + + it('SpAllocations test07', function () { + let spAllocations = new SpAllocations(); + expect(spAllocations.convertToValue("","KB")).toBe(0) + }) }) \ No newline at end of file diff --git a/host/ide/test/trace/component/setting/SpCheckDesBox.test.ts b/host/ide/test/trace/component/setting/SpCheckDesBox.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..31f72cb07cc6e102e2d66852f52c22241132a379 --- /dev/null +++ b/host/ide/test/trace/component/setting/SpCheckDesBox.test.ts @@ -0,0 +1,45 @@ +/* + * 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. + */ +//@ts-ignore +import {SpCheckDesBox} from "../../../../dist/trace/component/setting/SpCheckDesBox.js"; + +describe('SpCheckDesBox Test', () => { + let spCheckDesBox = new SpCheckDesBox(); + + it('SpCheckDesBoxTest01', function () { + expect(spCheckDesBox.value).toBe(''); + }); + + it('SpCheckDesBoxTest02', function () { + expect(spCheckDesBox.attributeChangedCallback('checked',"","")).toBeUndefined(); + }); + + it('SpCheckDesBoxTest03', function () { + expect(spCheckDesBox.attributeChangedCallback('value',"","")).toBeUndefined(); + }); + + it('SpCheckDesBoxTest04', function () { + expect(spCheckDesBox.attributeChangedCallback('des',"","")).toBeUndefined(); + }); + + it('SpCheckDesBoxTest05', function () { + expect(spCheckDesBox.checked).toBe(false); + }); + + it('SpCheckDesBoxTest06 ', function () { + expect(spCheckDesBox.connectedCallback()).toBeUndefined() + + }); +}) \ No newline at end of file diff --git a/host/ide/test/trace/component/setting/SpProbesConfig.test.ts b/host/ide/test/trace/component/setting/SpProbesConfig.test.ts index c105faf75f0266e24e02009f3d4533841cec92c4..3693cf6a5deef1fb6b4a58ae81869418d7cc5f0d 100644 --- a/host/ide/test/trace/component/setting/SpProbesConfig.test.ts +++ b/host/ide/test/trace/component/setting/SpProbesConfig.test.ts @@ -26,10 +26,109 @@ describe('SpProbesConfig Test', ()=>{ expect(new SpProbesConfig()).not.toBeNull(); }); - it(' SpProbesConfig get Default attrValue', function () { + it(' SpProbesConfig get Default attrValue', function () { let spEle = document.querySelector("#spconfig") as SpProbesConfig expect(spEle.traceConfig).toEqual([]) expect(spEle.traceEvents).toEqual([]) expect(spEle.memoryConfig).toEqual([]) }); + + it(' SpProbesConfig test', function () { + let spEle = document.querySelector("#spconfig") as SpProbesConfig + expect(spEle.initHtml()).toMatchInlineSnapshot(` +" + +
+
Record mode
+
+
+
+
+ + +
+ +
+
+
+
+
+ Memory Config +
+
+
+
+ " +`); + }); }) \ No newline at end of file diff --git a/host/ide/test/trace/component/setting/SpRecordPerf.test.ts b/host/ide/test/trace/component/setting/SpRecordPerf.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..583b477875960dba62396d8f014cf08d71bd980b --- /dev/null +++ b/host/ide/test/trace/component/setting/SpRecordPerf.test.ts @@ -0,0 +1,199 @@ +/* + * 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. + */ + +// @ts-ignore +import {SpRecordPerf} from "../../../../dist/trace/component/setting/SpRecordPerf.js"; + +describe('SpRecordPerf Test', ()=>{ + + let spRecordPerf = new SpRecordPerf(); + it('SpRecordPerfTest01', function () { + expect(spRecordPerf).not.toBeUndefined(); + }); + + it('SpRecordPerfTest02', function () { + expect(spRecordPerf.show).toBeFalsy(); + }); + + it('SpRecordPerfTest03', function () { + spRecordPerf.show = true; + expect(spRecordPerf.show).toBeTruthy(); + }); + + it('SpRecordPerfTest05', function () { + expect(spRecordPerf.unDisable()).toBeUndefined(); + }); + + + it('SpRecordPerfTest04', function () { + expect(spRecordPerf.initHtml()).toMatchInlineSnapshot(` +" + +
+
+
+ +
+ " +`); + }); + + it('SpRecordPerfTest06', function () { + expect(spRecordPerf.startSamp).toBeFalsy(); + }); + + it('SpRecordPerfTest07', function () { + spRecordPerf.startSamp = true + expect(spRecordPerf.startSamp).toBeTruthy(); + }); +}) \ No newline at end of file diff --git a/host/ide/test/trace/component/setting/SpRecordSetting.test.ts b/host/ide/test/trace/component/setting/SpRecordSetting.test.ts index 0832660f298291cf038c54b4fb6e119c663fbd7d..71d233b0f4edbd8dd5fb5b5b98d6608542abf949 100644 --- a/host/ide/test/trace/component/setting/SpRecordSetting.test.ts +++ b/host/ide/test/trace/component/setting/SpRecordSetting.test.ts @@ -33,4 +33,127 @@ describe('SpRecordSetting Test', ()=>{ expect(spEle.maxDur).toEqual(50) }); + it(' SpRecordSetting test', function () { + let spEle = document.querySelector("#setting") as SpRecordSetting + expect(spEle.initHtml()).toMatchInlineSnapshot(` +" + +
+
+ Record mode + Stop when full +
+
+ In-memory buffer size + + + +
+
+ Max duration + + + +
+
+ " +`); + }); }) \ No newline at end of file diff --git a/host/ide/test/trace/component/setting/SpTraceCommand.test.ts b/host/ide/test/trace/component/setting/SpTraceCommand.test.ts index 6695556c535da9b7b54fa06e4d7c27a0426e4d1e..54bc8d0b27739b76c60cbf91fad9420e79ce200d 100644 --- a/host/ide/test/trace/component/setting/SpTraceCommand.test.ts +++ b/host/ide/test/trace/component/setting/SpTraceCommand.test.ts @@ -14,7 +14,6 @@ */ // @ts-ignore - import {SpTraceCommand} from "../../../../dist/trace/component/setting/SpTraceCommand.js"; describe('SPTraceCommand Test', ()=>{ @@ -34,8 +33,101 @@ describe('SPTraceCommand Test', ()=>{ it(' SpAllocations set attrValue', function () { let spEle = document.querySelector("#command") as SpTraceCommand - spEle.hdcCommon = "aaaaaaaaaa" - expect(spEle.hdcCommon).toEqual("aaaaaaaaaa"); + spEle.hdcCommon = "test" + expect(spEle.hdcCommon).toEqual("test"); }); + it(' SpTraceCommand test', function () { + let spEle = document.querySelector("#command") as SpTraceCommand + expect(spEle.initHtml()).toMatchInlineSnapshot(` +" + +
+ + +
+ " +`) + }); }) \ No newline at end of file diff --git a/host/ide/test/trace/component/setting/utils/PluginConvertUtils.test.ts b/host/ide/test/trace/component/setting/utils/PluginConvertUtils.test.ts index 1a3a73a3f2eacde8d1e88cfda66355d4962914ee..aa3428527cec641c91f665a13108ccad2af93292 100644 --- a/host/ide/test/trace/component/setting/utils/PluginConvertUtils.test.ts +++ b/host/ide/test/trace/component/setting/utils/PluginConvertUtils.test.ts @@ -109,7 +109,7 @@ describe('PlugConvertUtils Test', ()=>{ }); it('PlugConvertUtils03', function () { - expect(PluginConvertUtils.BeanToCmdTxt(request, false)).not.toBeNull() + expect(PluginConvertUtils.BeanToCmdTxtWithObjName(request, false,'',1)).not.toBeNull() }); }) \ No newline at end of file diff --git a/host/ide/test/trace/component/trace/TimerShaftElement.test.ts b/host/ide/test/trace/component/trace/TimerShaftElement.test.ts index d4f37f42f5e1a117a70e7e0d7f99616367aded3e..c7e017e2f46d1b0537eb4f4139613ada38bcc0c4 100644 --- a/host/ide/test/trace/component/trace/TimerShaftElement.test.ts +++ b/host/ide/test/trace/component/trace/TimerShaftElement.test.ts @@ -14,8 +14,9 @@ */ // @ts-ignore -import {TimerShaftElement} from "../../../../dist/trace/component/trace/TimerShaftElement.js" - +import {TimerShaftElement,ns2s,ns2x} from "../../../../dist/trace/component/trace/TimerShaftElement.js"; +// @ts-ignore +import {Rect} from "../../../../dist/trace/database/ProcedureWorkerCommon"; describe('TimerShaftElement Test', () => { let timerShaftElement = new TimerShaftElement(); @@ -28,68 +29,18 @@ describe('TimerShaftElement Test', () => { expect(timerShaftElement.cpuUsage).toBeUndefined(); }); - it('TimerShaftElementTest02', function () { - timerShaftElement.rangeRuler = jest.fn(() => false) - timerShaftElement.loadComplete = jest.fn(() => false) - timerShaftElement.rangeRuler.markA = jest.fn(() => true) - timerShaftElement.rangeRuler.markB = jest.fn(() => true) - timerShaftElement.rangeRuler.markA.frame = jest.fn(() => true) - timerShaftElement.rangeRuler.markB.frame = jest.fn(() => true) - timerShaftElement.rangeRuler.markA.frame.x = jest.fn(() => 0) - timerShaftElement.rangeRuler.markB.frame.x = jest.fn(() => true) - timerShaftElement.rangeRuler.frame = jest.fn(() => true) - timerShaftElement.rangeRuler.frame.width = jest.fn(() => 8) - timerShaftElement.rangeRuler.cpuUsage = jest.fn(() => []) - timerShaftElement.sportRuler = jest.fn(() => true) - timerShaftElement.sportRuler.flagList = jest.fn(() => false) - timerShaftElement.sportRuler.flagList.length = jest.fn(() =>0) - timerShaftElement.totalNS =jest.fn(()=>false); - timerShaftElement.sportRuler.isRangeSelect = jest.fn(() => false) - expect(timerShaftElement.reset()).toBeUndefined(); - }); - - it('spApplicationTest10',function (){ - expect(timerShaftElement.reset()).not.toBeUndefined() - }); - - it('TimerShaftElementTest03', function () { timerShaftElement.timeRuler = jest.fn(() => false) - timerShaftElement.sportRuler = jest.fn(() => false) timerShaftElement.rangeRuler = jest.fn(() => false) timerShaftElement.timeRuler.frame = jest.fn(() => { return document.createElement('canvas') as HTMLCanvasElement }) - - timerShaftElement.sportRuler.frame = jest.fn(() => { - return document.createElement('canvas') as HTMLCanvasElement - }) - timerShaftElement.rangeRuler.frame = jest.fn(() => { return document.createElement('canvas') as HTMLCanvasElement }) expect(timerShaftElement.connectedCallback()).toBeUndefined(); }); - it('TimerShaftElementTest04', function () { - timerShaftElement.canvas = jest.fn(()=> { - return { - width: 20, - height: 20, - style: { - width: 30, - height: 30, - } - } - }) - timerShaftElement.canvas.style = jest.fn(() => true) - timerShaftElement.rangeRuler.fillX = jest.fn(() => true) - timerShaftElement.timeRuler.draw = jest.fn(() => true) - timerShaftElement.rangeRuler.draw = jest.fn(() => true) - timerShaftElement.sportRuler.draw = jest.fn(() => true) - expect(timerShaftElement.updateWidth(2)).toBeUndefined(); - }); - it('TimerShaftElementTest05', function () { expect(timerShaftElement.disconnectedCallback()).toBeUndefined(); }); @@ -97,15 +48,6 @@ describe('TimerShaftElement Test', () => { it('TimerShaftElementTest06', function () { expect(timerShaftElement.totalNS).toBe(10000000000); }); - it('TimerShaftElementTest10', function () { - timerShaftElement.totalNS = 10000000000; - expect(timerShaftElement.totalNS).toBe(10000000000); - }); - - it('TimerShaftElementTest07', function () { - // timerShaftElement._sportRuler.modifyFlagList = jest.fn(() => true) - expect(timerShaftElement.modifyFlagList()).toBeUndefined(); - }); it('TimerShaftElementTest08', function () { timerShaftElement.startNS = 'startNS' @@ -117,14 +59,151 @@ describe('TimerShaftElement Test', () => { expect(timerShaftElement.endNS).toBe('endNS'); }); - it('TimerShaftElementTest11', function () { - expect(timerShaftElement.render()).toBe(undefined); + it('TimerShaftElementTest14', function () { + expect(ns2s(1_000_0000)).toBe("10.0 ms"); + }); + + it('TimerShaftElementTest15', function () { + expect(timerShaftElement.initHtml()).toMatchInlineSnapshot(` +" + +
+
+
+
+ 10 + 0 +
+
+ +
+ " +`); + }); + + it('TimerShaftElementTest16', function () { + expect(ns2s(1)).toBe("1.0 ns"); + }); + + it('TimerShaftElementTest17', function () { + expect(ns2s(1_000)).toBe("1.0 μs"); + }); + + it('TimerShaftElementTest18', function () { + expect(ns2x(1,3,4,4,{width:1})).toBe(0); + }); + + it('TimerShaftElementTest19', function () { + expect(timerShaftElement.sportRuler).not.toBeUndefined(); + }); + + it('TimerShaftElementTest20', function () { + expect(timerShaftElement.isScaling()).toBeFalsy(); }); - it('TimerShaftElementTest12', function () { - timerShaftElement.ctx = jest.fn(()=>true) - timerShaftElement.ctx.fillStyle = jest.fn(()=>'transparent') - timerShaftElement.ctx.fillRect = jest.fn(()=>true) - expect(timerShaftElement.render()).toBe(undefined); + it('TimerShaftElementTest21', function () { + timerShaftElement.rangeRuler = jest.fn(()=>undefined) + timerShaftElement.rangeRuler.setRangeNS = jest.fn(()=>true) + expect(timerShaftElement.setRangeNS()).toBeFalsy(); }); + + it('TimerShaftElementTest22', function () { + timerShaftElement.rangeRuler = jest.fn(()=>undefined) + timerShaftElement.rangeRuler.getRange = jest.fn(()=>true) + expect(timerShaftElement.getRange()).toBeTruthy(); + }); + + it('TimerShaftElementTest23', function () { + timerShaftElement.rangeRuler = jest.fn(()=>undefined) + timerShaftElement.rangeRuler.frame = jest.fn(()=>Rect) + timerShaftElement.rangeRuler.frame.width = jest.fn(()=>1) + timerShaftElement._sportRuler = jest.fn(()=>undefined) + timerShaftElement._sportRuler.frame = jest.fn(()=>Rect) + timerShaftElement._sportRuler.frame.width = jest.fn(()=>1) + timerShaftElement.timeRuler = jest.fn(()=>undefined) + timerShaftElement.timeRuler.frame = jest.fn(()=>Rect) + timerShaftElement.timeRuler.frame.width = jest.fn(()=>1) + timerShaftElement.rangeRuler.fillX = jest.fn(()=>true) + timerShaftElement.render = jest.fn(()=>true) + expect(timerShaftElement.updateWidth()).toBeUndefined(); + }); + + it('TimerShaftElementTest24', function () { + timerShaftElement._sportRuler = jest.fn(()=>undefined) + timerShaftElement._sportRuler.modifyFlagList = jest.fn(()=>true) + expect(timerShaftElement.modifyFlagList()).toBeUndefined(); + }); + + it('TimerShaftElementTest25', function () { + timerShaftElement._sportRuler = jest.fn(()=>undefined) + timerShaftElement._sportRuler.drawTriangle = jest.fn(()=>true) + expect(timerShaftElement.drawTriangle()).toBeTruthy(); + }); + + it('TimerShaftElementTest26', function () { + timerShaftElement._sportRuler = jest.fn(()=>undefined) + timerShaftElement._sportRuler.removeTriangle = jest.fn(()=>true) + expect(timerShaftElement.removeTriangle()).toBeUndefined(); + }); + + it('TimerShaftElementTest27', function () { + timerShaftElement._sportRuler = jest.fn(()=>undefined) + timerShaftElement._sportRuler.setSlicesMark = jest.fn(()=>true) + expect(timerShaftElement.setSlicesMark()).toBeUndefined(); + }); + + + it('TimerShaftElementTest28', function () { + timerShaftElement.rangeRuler = jest.fn(()=>undefined) + timerShaftElement.rangeRuler.render = jest.fn(()=>true) + expect(timerShaftElement.render()).not.toBeUndefined(); + }); + + }) diff --git a/host/ide/test/trace/component/trace/base/RangeSelect.test.ts b/host/ide/test/trace/component/trace/base/RangeSelect.test.ts index 2e84cc0e2f9869470581840a4a1c3709c38a392c..3e10798fb6d4dbe9c0f4f404f8323cac95b3d3fb 100644 --- a/host/ide/test/trace/component/trace/base/RangeSelect.test.ts +++ b/host/ide/test/trace/component/trace/base/RangeSelect.test.ts @@ -147,6 +147,11 @@ describe("RangeSelect Test", () => { rangeSelect.timerShaftDragEL.timerShaftDragEL = jest.fn(()=>0) rangeSelect.spacerEL = jest.fn(()=>true) rangeSelect.spacerEL.offsetTop = jest.fn(()=>1) + rangeSelect.ns2x = jest.fn(()=> 1) + rangeSelect.mouseX = jest.fn(()=> 10) + rangeSelect.markA = jest.fn( ()=> 8) + rangeSelect.markB = jest.fn( ()=> 9) + expect(rangeSelect.mouseMove(rowsEL,mouseEvent)).toBeUndefined(); }); diff --git a/host/ide/test/trace/component/trace/base/TraceRow.test.ts b/host/ide/test/trace/component/trace/base/TraceRow.test.ts index da8ecac2169bd0b124c37c7d2f216c7cc568cb7b..6626e3f24d6b856c06f5da696c330d1ffe7e1228 100644 --- a/host/ide/test/trace/component/trace/base/TraceRow.test.ts +++ b/host/ide/test/trace/component/trace/base/TraceRow.test.ts @@ -15,111 +15,56 @@ // @ts-ignore import {TraceRow} from "../../../../../dist/trace/component/trace/base/TraceRow.js"; +// @ts-ignore +import {Sptext} from "../../../../../dist/trace/component/Sptext.js"; + describe("TraceRow Test", () => { beforeAll(() => { }) + const ctx = { + lineWidth:1, + strokeStyle:true + } it('TraceRow Test01', () => { - let traceRow = new TraceRow(); + let traceRow = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); expect(traceRow).not.toBeUndefined(); }); it('TraceRow Test02', () => { - let traceRow = new TraceRow(); + let traceRow = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); expect(traceRow.sleeping).toBeFalsy(); }); it('TraceRow Test03', () => { - let traceRow = new TraceRow(); + let traceRow = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); traceRow.sleeping = true expect(traceRow.sleeping).toBeTruthy(); }); it('TraceRow Test04', () => { - let traceRow = new TraceRow(); + let traceRow = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); traceRow.sleeping = false expect(traceRow.sleeping).toBeFalsy(); }); it('TraceRow Test05', () => { - let traceRow = new TraceRow(); + let traceRow = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); expect(traceRow.rangeSelect).toBeFalsy(); }); it('TraceRow Test06', () => { - let traceRow = new TraceRow(); + let traceRow = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); traceRow.rangeSelect = true expect(traceRow.rangeSelect).toBeTruthy(); }); - it('TraceRow Test07', () => { - const canvas = document.createElement('canvas'); - canvas.width = 1; - canvas.height = 1; - const ctx = canvas.getContext('2d'); - let traceRow = new TraceRow(); - //transferControlToOffscreen() - traceRow.canvas = jest.fn(()=>true) - traceRow.args = jest.fn(()=>true) - traceRow.args.isOffScreen = jest.fn(()=>true) - // @ts-ignore - traceRow.canvas.transferControlToOffscreen = jest.fn(()=>true) - traceRow.dataList = { - supplier:true, - isLoading:false, - } - traceRow.args={ - isOffScreen:true, - } - traceRow.supplier = true; - traceRow.isLoading = false; - traceRow.name = "111" - traceRow.height = 20 - traceRow.height = 30 - expect(traceRow.initCanvas()).toBeUndefined(); - }); - - it('TraceRow Test08', () => { - const canvas = document.createElement('canvas'); - canvas.width = 1; - canvas.height = 1; - const ctx = canvas.getContext('2d'); - let traceRow = new TraceRow(); - traceRow.dataList = { - supplier:true, - isLoading:false, - } - traceRow.supplier = true; - traceRow.isLoading = false; - traceRow.name = "111" - traceRow.height = 20 - traceRow.height = 30 - expect(traceRow.drawObject()).toBeUndefined(); - }); - - it('TraceRow Test09', () => { - const canvas = document.createElement('canvas'); - canvas.width = 1; - canvas.height = 1; - const ctx = canvas.getContext('2d'); - let traceRow = new TraceRow(); - traceRow.dataList = { - supplier:true, - isLoading:false, - } - traceRow.supplier = true; - traceRow.isLoading = false; - traceRow.name = "111" - traceRow.height = 20 - traceRow.height = 30 - expect(traceRow.drawObject()).toBeUndefined(); - }); it('TraceRow Test10', () => { const canvas = document.createElement('canvas'); canvas.width = 1; canvas.height = 1; const ctx = canvas.getContext('2d'); - let traceRow = new TraceRow(); + let traceRow = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); traceRow.dataList = { supplier:true, isLoading:false, @@ -137,7 +82,7 @@ describe("TraceRow Test", () => { canvas.width = 1; canvas.height = 1; const ctx = canvas.getContext('2d'); - let traceRow = new TraceRow(); + let traceRow = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); traceRow.dataList = { supplier:true, isLoading:false, @@ -155,7 +100,7 @@ describe("TraceRow Test", () => { canvas.width = 1; canvas.height = 1; const ctx = canvas.getContext('2d'); - let traceRow = new TraceRow(); + let traceRow = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); traceRow.dataList = { supplier:true, isLoading:false, @@ -169,152 +114,499 @@ describe("TraceRow Test", () => { }); it('TraceRow Test13', () => { - let traceRow = new TraceRow(); + let traceRow = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); expect(traceRow.collect).toBeFalsy(); }); it('TraceRow Test14', () => { - let traceRow = new TraceRow(); + let traceRow = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); traceRow.collect = true; expect(traceRow.collect).toBeTruthy(); }); it('TraceRow Test15', () => { - let traceRow = new TraceRow(); + let traceRow = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); expect(traceRow.rowType).toBeFalsy(); }); it('TraceRow Test16', () => { - let traceRow = new TraceRow(); + let traceRow = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); traceRow.rowType = true; expect(traceRow.rowType).toBeTruthy(); }); it('TraceRow Test17', () => { - let traceRow = new TraceRow(); + let traceRow = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); expect(traceRow.rowId).toBeFalsy(); }); it('TraceRow Test18', () => { - let traceRow = new TraceRow(); + let traceRow = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); traceRow.rowId = true; expect(traceRow.rowId).toBeTruthy(); }); it('TraceRow Test19', () => { - let traceRow = new TraceRow(); + let traceRow = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); expect(traceRow.rowParentId).toBeFalsy(); }); it('TraceRow Test20', () => { - let traceRow = new TraceRow(); + let traceRow = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); traceRow.rowParentId = true; expect(traceRow.rowParentId).toBeTruthy(); }); it('TraceRow Test21', () => { - let traceRow = new TraceRow(); + let traceRow = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); traceRow.rowHidden = true; expect(traceRow.rowHidden).toBeUndefined(); }); + it('TraceRow Test22', () => { - let traceRow = new TraceRow(); + let traceRow = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); expect(traceRow.name).toBeFalsy(); }); it('TraceRow Test23', () => { - let traceRow = new TraceRow(); + let traceRow = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); + traceRow.folder = false; expect(traceRow.folder).toBeFalsy(); }); it('TraceRow Test24', () => { - let traceRow = new TraceRow(); + let traceRow = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); traceRow.folder = true; expect(traceRow.folder).toBeTruthy(); }); it('TraceRow Test25', () => { - let traceRow = new TraceRow(); + let traceRow = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); + traceRow.expansion = false; expect(traceRow.expansion).toBeFalsy(); }); it('TraceRow Test26', () => { - let traceRow = new TraceRow(); + let traceRow = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); traceRow.expansion = true; expect(traceRow.expansion).toBeTruthy(); }); it('TraceRow Test27', () => { - let traceRow = new TraceRow(); + let traceRow = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); traceRow.tip = true; expect(traceRow.tip).toBeUndefined(); }); it('TraceRow Test28', () => { - let traceRow = new TraceRow(); + let traceRow = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); expect(traceRow.frame).not.toBeUndefined(); }); it('TraceRow Test29', () => { - let traceRow = new TraceRow(); + let traceRow = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); traceRow.frame = [0,0,0]; expect(traceRow.frame).toBeTruthy(); }); + it('TraceRow Test60', () => { + let traceRow = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); + expect(traceRow.disabledCheck).not.toBeUndefined(); + }); + + it('TraceRow Test61', () => { + let traceRow = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); + traceRow.disabledCheck = true; + expect(traceRow.disabledCheck).toBeTruthy(); + }); + + it('TraceRow Test62', () => { + let traceRow = new TraceRow({canvasNumber: 1, alpha: true, contextId: '2d', isOffScreen: true}); + expect(traceRow.folderPaddingLeft).toBeUndefined(); + }); + + it('TraceRow Test63', () => { + document.body.innerHTML = '
' + let traceRow = document.querySelector('.ccc') as TraceRow + expect(traceRow.setCheckBox()).toBeUndefined(); + }); + it('TraceRow Test30', () => { - let traceRow = new TraceRow(); + let traceRow = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); expect(traceRow.checkType).not.toBeUndefined(); }); it('TraceRow Test31', () => { - let traceRow = new TraceRow(); - traceRow.checkType = true; + let traceRow = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); + traceRow.checkType = "-1"; expect(traceRow.checkType).toBeTruthy(); }); it('TraceRow Test32', () => { - let traceRow = new TraceRow(); - expect(traceRow.drawType).toBeUndefined(); + let traceRow = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); + expect(traceRow.drawType).toBe(0); }); it('TraceRow Test33', () => { - let traceRow = new TraceRow(); + let traceRow = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); traceRow.drawType = true; expect(traceRow.drawType).toBeTruthy(); }); it('TraceRow Test34', () => { - let traceRow = new TraceRow(); + let traceRow = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); traceRow.args = jest.fn(()=>true) traceRow.args.isOffScreen = jest.fn(()=>null) expect(traceRow.updateWidth(1)).toBeUndefined(); }); - it('TraceRow Test35', () => { - let traceRow = new TraceRow(); - expect(traceRow.setCheckBox()).toBeUndefined(); - }); - it('TraceRow Test36', () => { - let traceRow = new TraceRow(); + let traceRow = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); expect(traceRow.onMouseHover()).toBeFalsy(); }); it('TraceRow Test37', () => { - let traceRow = new TraceRow(); + let traceRow = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); expect(traceRow.setTipLeft(1,null)).toBeFalsy(); }); it('TraceRow Test38', () => { - let traceRow = new TraceRow(); + let traceRow = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); expect(traceRow.onMouseLeave(1,1)).toBeFalsy(); }); it('TraceRow Test39', () => { - let traceRow = new TraceRow(); + let traceRow = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); expect(traceRow.draw(false)).toBeFalsy(); }); + it('TraceRow Test40', () => { + let traceRow = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); + traceRow.collect = 1 + expect(traceRow.collect).toBeTruthy(); + }); + + it('TraceRow Test41', () => { + let traceRow = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); + traceRow.collect = 0 + expect(traceRow.collect).toBeFalsy(); + }); + + it('TraceRow Test42', () => { + let traceRow = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); + traceRow.checkType = "0"; + expect(traceRow.checkType).toBe("0"); + }); + + it('TraceRow Test43', () => { + let traceRow = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); + traceRow.checkType = "1"; + expect(traceRow.checkType).toBe("1"); + }); + + it('TraceRow Test44', () => { + let traceRow = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); + traceRow.checkType = "2"; + expect(traceRow.checkType).toBe("2"); + }); + + + it('TraceRow Test45', () => { + let traceRow = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); + traceRow.checkType = 0; + expect(traceRow.checkType).toBe(""); + }); + + it('TraceRow Test46', () => { + let traceRow = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); + traceRow.rowHidden = false; + expect(traceRow.rowHidden).toBeUndefined(); + }); + + it('TraceRow Test47', () => { + let traceRow = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); + traceRow.highlight = false; + expect(traceRow.highlight).toBeFalsy(); + }); + + it('TraceRow Test48', () => { + let traceRow = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); + traceRow.highlight = true; + expect(traceRow.highlight).toBeFalsy(); + }); + + it('TraceRow Test49', () => { + let traceRow = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); + traceRow.setCheckBox = true; + expect(traceRow.highlight).toBeFalsy(); + }); + + it('TraceRow Test50', () => { + let traceRow = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); + traceRow.initCanvas = jest.fn(()=>null) + expect(traceRow.connectedCallback()).toBeUndefined(); + }); + + it('TraceRow Test51', () => { + let traceRow = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); + expect(traceRow.isInTimeRange()).toBe(false); + }); + + it('TraceRow Test52', () => { + let traceRow = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); + expect(traceRow.getLineColor()).toBe(""); + }); + + it('TraceRow Test53', () => { + let traceRow = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); + let value = traceRow.attributeChangedCallback("name") + expect(value).toBe(undefined); + }); + + it('TraceRow Test54', () => { + let traceRow = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); + let value = traceRow.attributeChangedCallback("height","1","2") + expect(value).toBe(undefined); + }); + + it('TraceRow Test55', () => { + let traceRow = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); + let value = traceRow.attributeChangedCallback("check-type","1","check") + expect(value).toBe(undefined); + }); + + it('TraceRow Test56', () => { + let traceRow = new TraceRow({canvasNumber:1,alpha: true, contextId: '2d', isOffScreen: true}); + expect(traceRow.initHtml()).toMatchInlineSnapshot(` +" + +
+
+ + + + +
+
+ Current Bytes
+
+ Native Memory Density
+
+ +
+ +
+
+
+ P:process [1573]
+ T:Thread [675] +
+
+
+ " +`); + }); }) \ No newline at end of file diff --git a/host/ide/test/trace/component/trace/base/TraceRowRecyclerView.test.ts b/host/ide/test/trace/component/trace/base/TraceRowRecyclerView.test.ts index 6aa8c61cb54897f6a729de2ada5607dc10c3fd6c..3185d3befb0987fa7096a8774a401d26fc3aa449 100644 --- a/host/ide/test/trace/component/trace/base/TraceRowRecyclerView.test.ts +++ b/host/ide/test/trace/component/trace/base/TraceRowRecyclerView.test.ts @@ -32,7 +32,8 @@ describe("TraceRow Test", () => { it('Test03', function () { let traceRow = new TraceRowRecyclerView(); - traceRow.dataSource=false + traceRow.measureHeight = jest.fn(()=>true) + traceRow.dataSource = true expect(traceRow.dataSource).toBeTruthy(); }); @@ -49,22 +50,84 @@ describe("TraceRow Test", () => { it('Test06', function () { let traceRow = new TraceRowRecyclerView(); - expect(traceRow.refreshRow()).toBeUndefined(); - }); + const obj={ + folder:false, + top:0, + name:"", + children:false, + rowId:"", + rowType:"", + rowParentId:"1", + expansion:false, + rowHidden:false, + rowHeight:40 + } + const el={ + obj:undefined, + style:{top:1,visibility:'visible'}, + name:"", + rowId:"", + rowType:"", + rowParentId:"1", + expansion:false, + rowHidden:false, + setAttribute:"", + removeAttribute:"" - it('Test07', function () { - let traceRow = new TraceRowRecyclerView(); - traceRow.dataSource = jest.fn(()=>true) - traceRow.dataSource.filter = jest.fn(()=>true) - expect(traceRow.measureHeight()).toBeUndefined(); + } + expect(traceRow.refreshRow(el,!obj)).toBeUndefined(); }); it('Test08', function () { let traceRow = new TraceRowRecyclerView(); expect(traceRow.initUI()).toBeUndefined(); }); + it('Test09', function () { let traceRow = new TraceRowRecyclerView(); expect(traceRow.initUI()).toBeUndefined(); }); + + it('Test09', function () { + let traceRow = new TraceRowRecyclerView(); + expect(traceRow.initHtml()).toMatchInlineSnapshot(` +" + +
+
+
+ + " +`) + }); }) \ No newline at end of file diff --git a/host/ide/test/trace/component/trace/base/TraceSheet.test.ts b/host/ide/test/trace/component/trace/base/TraceSheet.test.ts index 39ef4ca48217c030d92e11aed1bf6d7a1e8fe608..23dd5fc313a3ef2f052bfba1f42b716944599bde 100644 --- a/host/ide/test/trace/component/trace/base/TraceSheet.test.ts +++ b/host/ide/test/trace/component/trace/base/TraceSheet.test.ts @@ -15,6 +15,7 @@ // @ts-ignore import {TraceSheet} from "../../../../../dist/trace/component/trace/base/TraceSheet.js"; + window.ResizeObserver = window.ResizeObserver || jest.fn().mockImplementation(() => ({ disconnect: jest.fn(), @@ -25,70 +26,266 @@ window.ResizeObserver = window.ResizeObserver || describe("TraceSheet Test", () => { beforeAll(() => { }) -let val=[{ - cpus:{length:1,}, - threadIds:{length: 2}, - funTids:{length: 2}, - trackIds:{length: 2}, - hasFps:0, - heapIds:{length: 0}, - nativeMemory:{length: 1} -}] + let val = { + hasFps: 1, + cpus:{length:1}, + threadIds:[{length:2}], + funTids:{length:1}, + trackIds: {length:1}, + heapIds: {length:1}, + nativeMemory: {length:1}, + cpuAbilityIds:{length:1}, + memoryAbilityIds:{length:1}, + diskAbilityIds:{length:1}, + networkAbilityIds:{length:1}, + } + let e = {detail:{ + title:1, + state:0, + threadId:1, + processId:2 + }} + let selection ={ + hasFps: 1, + cpus:{length:1}, + threadIds:[{length:2}], + funTids:{length:1}, + trackIds: {length:1}, + heapIds: {length:1}, + nativeMemory: {length:1}, + cpuAbilityIds:{length:0}, + memoryAbilityIds:{length:0}, + diskAbilityIds:{length:0}, + networkAbilityIds:{length:0}, + perfSampleIds:{length:0}, + + } it('TraceSheet Test01', () => { - let traceRow = new TraceSheet(); - expect(traceRow).not.toBeUndefined() + let traceSheet = new TraceSheet(); + expect(traceSheet).not.toBeUndefined() }); it('TraceSheet Test02', () => { - let traceRow = new TraceSheet(); - expect(traceRow.recoveryBoxSelection).not.toBeUndefined() + let traceSheet = new TraceSheet(); + expect(traceSheet.recoveryBoxSelection).not.toBeUndefined() }); - it('TraceSheet Test03', () => { - let traceRow = new TraceSheet(); - expect(traceRow.hideBoxTab()).toBeUndefined() + let traceSheet = new TraceSheet(); + expect(traceSheet.hideBoxTab()).toBeUndefined() }); - /* it('TraceSheet Test04', () => { - let traceRow = new TraceSheet(); - expect(traceRow.hideOtherBoxTab("11")).not.toBeUndefined() + it('TraceSheet Test08', () => { + let traceSheet = new TraceSheet(); + expect(traceSheet.connectedCallback()).toBeUndefined() + }); + it('TraceSheet Test09', () => { + let traceSheet = new TraceSheet(); + expect(traceSheet.loadTabPaneData()).toBeUndefined() }); + it('TraceSheet Test10', () => { + let traceSheet = new TraceSheet(); + expect(traceSheet.clear()).toBeUndefined() + }); - it('TraceSheet Test05', () => { - let traceRow = new TraceSheet(); - expect(traceRow.hideOtherBoxTab("12")).not.toBeUndefined() + it('TraceSheet Test12', () => { + let traceSheet = new TraceSheet(); + traceSheet.litTabs = jest.fn(()=>true) + traceSheet.litTabs.activeByKey = jest.fn(()=>true) + let value = traceSheet.hideOtherBoxTab("11") + expect(value).toBeUndefined() }); + it('TraceSheet Test13', () => { + let traceSheet = new TraceSheet(); + traceSheet.litTabs = jest.fn(()=>true) + traceSheet.litTabs.activeByKey = jest.fn(()=>true) + let value = traceSheet.hideOtherBoxTab("12") + expect(value).toBeUndefined() + }); - it('TraceSheet Test06', () => { - let traceRow = new TraceSheet(); - expect(traceRow.hideOtherBoxTab("13")).not.toBeUndefined() + it('TraceSheet Test14', () => { + let traceSheet = new TraceSheet(); + traceSheet.litTabs = jest.fn(()=>true) + traceSheet.litTabs.activeByKey = jest.fn(()=>true) + let value = traceSheet.hideOtherBoxTab("13") + expect(value).toBeUndefined() }); - it('TraceSheet Test07', () => { - let traceRow = new TraceSheet(); - expect(traceRow.hideOtherBoxTab("14")).not.toBeUndefined() - });*/ + it('TraceSheet Test16', () => { + let traceSheet = new TraceSheet(); + traceSheet.litTabs = jest.fn(()=>true) + traceSheet.litTabs.activeByKey = jest.fn(()=>true) + let value = traceSheet.hideOtherBoxTab("14") + expect(value).toBeUndefined() + }); - it('TraceSheet Test08', () => { - let traceRow = new TraceSheet(); - expect(traceRow.connectedCallback()).toBeUndefined() + it('TraceSheet Test15', () => { + let traceSheet = new TraceSheet(); + traceSheet.setBoxActiveKey = jest.fn(()=>true) + expect(traceSheet.boxSelection(selection)).toBeTruthy() }); - it('TraceSheet Test09', () => { - let traceRow = new TraceSheet(); - expect(traceRow.loadTabPaneData()).toBeUndefined() + + it('TraceSheet Test17', () => { + let traceSheet = new TraceSheet(); + traceSheet.selection = jest.fn(()=>undefined) + traceSheet.selection.cpus = jest.fn(()=>[1]) + traceSheet.selection.threadIds = jest.fn(()=>[1]) + traceSheet.selection.funTids = jest.fn(()=>[1]) + traceSheet.selection.trackIds = jest.fn(()=>[1]) + traceSheet.selection.heapIds = jest.fn(()=>[1]) + traceSheet.selection.nativeMemory = jest.fn(()=>[1]) + traceSheet.selection.perfSampleIds = jest.fn(()=>[1]) + expect(traceSheet.recoveryBoxSelection()).toBeUndefined() }); - it('TraceSheet Test10', () => { - let traceRow = new TraceSheet(); - expect(traceRow.clear()).toBeUndefined() + it('TraceSheet Test18', () => { + let traceSheet = new TraceSheet(); + traceSheet.litTabs = jest.fn(()=>undefined) + traceSheet.litTabs.activeByKey = jest.fn(()=>true) + traceSheet.loadTabPaneData = jest.fn(()=>"") + expect(traceSheet.setBoxActiveKey(val)).toBeUndefined() }); - it('TraceSheet Test11', () => { - let traceRow = new TraceSheet(); - expect(traceRow.boxSelection(val)).toBeUndefined() + it('TraceSheet Test19', () => { + let traceSheet = new TraceSheet(); + expect(traceSheet.initHtml()).toMatchInlineSnapshot(` +" + +
+ +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ " +`) }); }) \ No newline at end of file diff --git a/host/ide/test/trace/component/trace/base/Utils.test.ts b/host/ide/test/trace/component/trace/base/Utils.test.ts index 0b70b4d7124f07fc83df773fcada772b0bad0614..947632f533181250d8f0bf16927699694310e236 100644 --- a/host/ide/test/trace/component/trace/base/Utils.test.ts +++ b/host/ide/test/trace/component/trace/base/Utils.test.ts @@ -68,21 +68,124 @@ describe("Utils Test", () => { }); it('Utils Test11', () => { - expect(Utils.getByteWithUnit(1_000_000_001)).toBe("1.00 Gb") + expect(Utils.getByteWithUnit(2_000_000_000)).toBe("1.86 Gb") }); it('Utils Test12', () => { - expect(Utils.getByteWithUnit(1_000_000_000)).toBe("1000.00 Mb") + expect(Utils.getByteWithUnit(1_000_000_000)).toBe("953.67 Mb") + }); + + it('Utils Test13', () => { + expect(Utils.getByteWithUnit(1000_000)).toBe("976.56 Kb") + }); + + it('Utils Test23', () => { + expect(Utils.getByteWithUnit(-2_000)).toBe("-1.95 Kb") }); it('Utils Test14', () => { - expect(Utils.getByteWithUnit(1000_000)).toBe("1000.00 kb") + expect(Utils.getTimeString( 1_000_000_000_000)).toBe("16m 40s ") }); - it('Utils Test13', () => { + it('Utils Test15', () => { + expect(Utils.getTimeString( 2_000_000)).toBe("2ms ") + }); + + it('Utils Test16', () => { + expect(Utils.getTimeString( 3_000)).toBe("3μs ") + }); + + it('Utils Test17', () => { + expect(Utils.getTimeString( 300)).toBe("300ns ") + }); + + it('Utils Test18', () => { expect(Utils.getTimeStringHMS(5900_000_000_000)).toBe("1:38:") }); + it('Utils Test19', () => { + expect(Utils.getTimeStringHMS(3_000_000_000)).toBe("3:") + }); + + it('Utils Test20', () => { + expect(Utils.getTimeStringHMS(2_000_000)).toBe("2.") + }); + + it('Utils Test21', () => { + expect(Utils.getTimeStringHMS(5_000)).toBe("5.") + }); + + it('Utils Test22', () => { + expect(Utils.getTimeStringHMS(90)).toBe("90") + }); + + it('Utils Test24', () => { + expect(Utils.getBinaryByteWithUnit(0)).toBe("0Bytes") + }); + + it('Utils Test25', () => { + expect(Utils.getBinaryByteWithUnit(3_000_000_000)).toBe("2.79Gib") + }); + + it('Utils Test26', () => { + expect(Utils.getBinaryByteWithUnit(2_000_000)).toBe("1.91Mib") + }); + + it('Utils Test27', () => { + expect(Utils.getBinaryByteWithUnit(2_000)).toBe("1.95kib") + }); + + it('Utils Test28', () => { + expect(Utils.getTimeStampHMS(3900_000_000_000)).toBe("01:05:00:000.000") + }); + + it('Utils Test29', () => { + expect(Utils.getTimeStampHMS(70_000_000_000)).toBe("01:10:000.000") + }); + + it('Utils Test30', () => { + expect(Utils.getTimeStampHMS(2_000_000_000)).toBe("02:000.000") + }); + + it('Utils Test31', () => { + expect(Utils.getTimeStampHMS(2_000_000)).toBe("00:002.000") + }); + + it('Utils Test32', () => { + expect(Utils.getTimeStampHMS(2_000)).toBe("00:000.002.") + }); + + it('Utils Test33', () => { + expect(Utils.getTimeStampHMS(1)).toBe("00:000.000001") + }); + + it('Utils Test40', () => { + expect(Utils.getDurString(61_000_000_000)).toBe("1:1.0s ") + }); + + it('Utils Test34', () => { + expect(Utils.getDurString(2_000_000_000)).toBe("2.0s ") + }); + + it('Utils Test35', () => { + expect(Utils.getDurString(1_800_000)).toBe("1ms ") + }); + + it('Utils Test36', () => { + expect(Utils.timeMsFormat2p(3800_000)).toBe("1.00h") + }); + + it('Utils Test37', () => { + expect(Utils.timeMsFormat2p(90_000)).toBe("1.00min") + }); + + it('Utils Test38', () => { + expect(Utils.timeMsFormat2p(2_000)).toBe("2.00s") + }); + + it('Utils Test39', () => { + expect(Utils.timeMsFormat2p(1)).toBe("1.00ms") + }); afterAll(() => { // 后处理操作 diff --git a/host/ide/test/trace/component/trace/search/Search.test.ts b/host/ide/test/trace/component/trace/search/Search.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..c3febe3c9e2cfa6bd52dae8ad160ab3b8192dc63 --- /dev/null +++ b/host/ide/test/trace/component/trace/search/Search.test.ts @@ -0,0 +1,155 @@ +/* + * 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. + */ + +// @ts-ignore +import {LitSearch} from "../../../../../dist/trace/component/trace/search/Search.js"; + +describe(" SearchTest", () => { + beforeAll(() => { + }) + it('Search Test01', () => { + let search = new LitSearch(); + expect(search).not.toBeUndefined() + }); + + it('Search Test02', () => { + let search = new LitSearch(); + search.list = ["1"]; + expect(search.list[0]).toBe("1"); + }); + + it('Search Test03', () => { + let search = new LitSearch(); + search.index = 1; + expect(search.index).toBe(1); + }); + + it('Search Test04', () => { + let search = new LitSearch(); + search.index = 1; + expect(search.total).toBe(0); + }); + + it('Search Test05', () => { + let search = new LitSearch(); + search.index = 1; + expect(search.setPercent("1",2)).toBeUndefined(); + }); + + it('Search Test06', () => { + let search = new LitSearch(); + search.index = 1; + expect(search.setPercent("1",101)).toBeUndefined(); + }); + + it('Search Test07', () => { + let search = new LitSearch(); + search.index = 1; + expect(search.setPercent("1",-1)).toBeUndefined(); + }); + + it('Search Test08', () => { + let search = new LitSearch(); + search.index = 1; + expect(search.setPercent("1",-2)).toBeUndefined(); + }); + + it('Search Test09', () => { + let search = new LitSearch(); + expect(search.clear()).toBeUndefined(); + }); + + it('Search Test11', function () { + let search = new LitSearch(); + search.search = jest.fn(()=>undefined) + search.search.blur = jest.fn(()=>true) + expect(search.blur()).toBeUndefined(); + }); + + it('Search Test10', () => { + let search = new LitSearch(); + expect(search.initHtml()).toMatchInlineSnapshot(` +" + +
+ + + +
+ 0/0 + + + | + + +
+
+ " +`); + }); +}); \ No newline at end of file diff --git a/host/ide/test/trace/component/trace/sheet/TabPaneBoxChild.test.ts b/host/ide/test/trace/component/trace/sheet/TabPaneBoxChild.test.ts index 8304782e909c6005ba933a5ec7000dfada5e64d3..155cacc6e204c67ce678b17c022819ed45c04dbc 100644 --- a/host/ide/test/trace/component/trace/sheet/TabPaneBoxChild.test.ts +++ b/host/ide/test/trace/component/trace/sheet/TabPaneBoxChild.test.ts @@ -16,6 +16,8 @@ // @ts-ignore // import { it } from "mocha" import {TabPaneBoxChild} from "../../../../../dist/trace/component/trace/sheet/TabPaneBoxChild.js" +import {getTabBoxChildData} from "../../../../../src/trace/database/SqlLite"; + window.ResizeObserver = window.ResizeObserver || jest.fn().mockImplementation(() => ({ disconnect: jest.fn(), @@ -23,12 +25,13 @@ window.ResizeObserver = window.ResizeObserver || unobserve: jest.fn(), })); + describe('TabPaneBoxChild Test', () => { + document.body.innerHTML = `
` + let element = document.querySelector("#div") as HTMLDivElement; let tabPaneBoxChild = new TabPaneBoxChild(); - tabPaneBoxChild.parentElement= jest.fn(()=> { - return {clientHeight:56} - }) - tabPaneBoxChild.parentElement.clientHeight= jest.fn(()=>100) + element.appendChild(tabPaneBoxChild) + tabPaneBoxChild.loadDataInCache = true tabPaneBoxChild.data = { cpus: [], threadIds: [], @@ -38,28 +41,56 @@ describe('TabPaneBoxChild Test', () => { leftNs: 0, rightNs: 0, hasFps: false, - // parentElement:{ - // clientHeight:0, - // } } - // tabPaneBoxChild.parentElement = { - // clientHeight:0, - // } + let val={ + leftNs:2, + rightNs:1, + state:"1", + processId:0, + threadId:1 + } it('TabPaneBoxChildTest01', function () { + expect(tabPaneBoxChild.sortByColumn({ + key: 'number', + })).toBeUndefined(); + }); + it('TabPaneCounterTest02', function () { expect(tabPaneBoxChild.sortByColumn({ - key: 'name', sort: () => { } })).toBeUndefined(); }); - // it('TabPaneBoxChildTest02',function(){ - // TabPaneBoxChild.parentElement= jest.fn(()=> { - // return {clientHeight:56} - // }) - // // TabPaneBoxChild.parentElement.clientHeight= jest.fn(()=>100) - // expect(tabPaneBoxChild.data).toBeUndefined(); - // }) - + + it('TabPaneCounterTest03', function () { + expect(tabPaneBoxChild.initHtml()).toMatchInlineSnapshot(` +" + + + + + + + + + + + + + + + + + + + " +`); + }); }) diff --git a/host/ide/test/trace/component/trace/sheet/TabPaneContextSwitch.test.ts b/host/ide/test/trace/component/trace/sheet/TabPaneContextSwitch.test.ts index 3d3b8e73d2e302cfb792f9a080e45fe6d3b79186..5b3c769fd2453e91d0437220617f28ec295a3a5a 100644 --- a/host/ide/test/trace/component/trace/sheet/TabPaneContextSwitch.test.ts +++ b/host/ide/test/trace/component/trace/sheet/TabPaneContextSwitch.test.ts @@ -55,4 +55,36 @@ describe('TabPaneContextSwitch Test', () => { let result = tabPaneContextSwitch.groupByThreadToMap(dataArray) expect(result.get(0).length).toBe(1); }); + + it('TabPaneContextSwitchTest04', function () { + expect(tabPaneContextSwitch).not.toBeUndefined(); + }); + + it('TabPaneContextSwitchTest05', function () { + expect(tabPaneContextSwitch.initHtml()).toMatchInlineSnapshot(` +" + + + + + + + + + " +`); + }); + + it('TabPaneContextSwitchTest06', function () { + document.body.innerHTML = `` + let tabPaneContextSwitch = document.querySelector('#Switch') as TabPaneContextSwitch + tabPaneContextSwitch.data = false + expect(tabPaneContextSwitch.data).toBeFalsy(); + }); }) diff --git a/host/ide/test/trace/component/trace/sheet/TabPaneCounter.test.ts b/host/ide/test/trace/component/trace/sheet/TabPaneCounter.test.ts index d7206491353087ba6a80996160e1f10a0c48096c..8ccc44e955c659256dda831d6b0d67e5c0138667 100644 --- a/host/ide/test/trace/component/trace/sheet/TabPaneCounter.test.ts +++ b/host/ide/test/trace/component/trace/sheet/TabPaneCounter.test.ts @@ -45,9 +45,16 @@ describe('TabPaneCounter Test', () => { key: 'name', sort: () => { } - })) + })).toBeUndefined(); }); + it('TabPaneCounterTest06', function () { + expect(tabPaneCounter.sortByColumn({ + key: 'number', + sort: () => { + } + })).toBeUndefined(); + }); it('TabPaneCounterTest04', function () { let mockgetTabCounters = sqlit.getTabCounters @@ -65,7 +72,6 @@ describe('TabPaneCounter Test', () => { expect(tabPaneCounter.data = a).toBeTruthy(); }); - it('TabPaneCounterTest05', function () { let mockgetTabCounters = sqlit.getTabCounters mockgetTabCounters.mockResolvedValue([] @@ -73,4 +79,39 @@ describe('TabPaneCounter Test', () => { let a = {rightNs: 1, trackIds: [11, 12, 13]} expect(tabPaneCounter.data = a).toBeTruthy(); }); + + it('TabPaneCounterTest06', function () { + expect(tabPaneCounter.initHtml()).toMatchInlineSnapshot(` +" + + + + + + + + + + + + + + + + + + + + + + + " +`); + }); }) diff --git a/host/ide/test/trace/component/trace/sheet/TabPaneCpu.test.ts b/host/ide/test/trace/component/trace/sheet/TabPaneCpu.test.ts index fed58e89359ecf027e3cd11f8481d1f21840ac8d..dbf606298685142c91f3379830d7c979ce96d382 100644 --- a/host/ide/test/trace/component/trace/sheet/TabPaneCpu.test.ts +++ b/host/ide/test/trace/component/trace/sheet/TabPaneCpu.test.ts @@ -23,7 +23,29 @@ describe('TabPaneCpu Test', ()=>{ it('TabPaneCpuTest01', function () { expect(tabPaneCpu.initHtml()).not.toBe('') }); + it('TabPaneCpuTest02', function () { expect(tabPaneCpu.initElements()).toBeUndefined() }); + + it('TabPaneCpuTest03', function () { + expect(tabPaneCpu.initHtml()).toMatchInlineSnapshot(` +" + + + + + + + + + " +`) + }); }) \ No newline at end of file diff --git a/host/ide/test/trace/component/trace/sheet/TabPaneCpuAbility.test.ts b/host/ide/test/trace/component/trace/sheet/TabPaneCpuAbility.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..f4e3cea52b36702c6262d58f4537ae2e626ae270 --- /dev/null +++ b/host/ide/test/trace/component/trace/sheet/TabPaneCpuAbility.test.ts @@ -0,0 +1,56 @@ +/* + * 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. + */ +// @ts-ignore +import {TabPaneCpuAbility} from "../../../../../dist/trace/component/trace/sheet/TabPaneCpuAbility.js" + +window.ResizeObserver = window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +describe('TabPaneCpuAbility Test', () => { + let tabPaneCpuAbility = new TabPaneCpuAbility(); + + it('TabPaneCpuAbilityTest01', function () { + tabPaneCpuAbility.queryResult.length = 2; + expect(tabPaneCpuAbility.filterData()).toBeUndefined(); + }); + + it('TabPaneCpuAbilityTest02', function () { + const systemCpuSummary = { + startTimeStr:"", + durationStr:"", + totalLoadStr:"", + userLoadStr:"", + systemLoadStr:"", + threadsStr:"" + } + expect(tabPaneCpuAbility.toCpuAbilityArray(systemCpuSummary)).not.toBeUndefined(); + }); + + it('TabPaneCpuAbilityTest03 ', function () { + expect(tabPaneCpuAbility.sortByColumn({ + key:'startTime', + })).toBeUndefined(); + }); + + it('TabPaneCpuAbilityTest04 ', function () { + expect(tabPaneCpuAbility.sortByColumn({ + key:!'startTime', + })).toBeUndefined(); + }); +}) \ No newline at end of file diff --git a/host/ide/test/trace/component/trace/sheet/TabPaneCpuByProcess.test.ts b/host/ide/test/trace/component/trace/sheet/TabPaneCpuByProcess.test.ts index 94fb290f37b9f2728598024db51d122228852d31..25cf945e99df7f378d1c35fdb8a0e5da1ea19c54 100644 --- a/host/ide/test/trace/component/trace/sheet/TabPaneCpuByProcess.test.ts +++ b/host/ide/test/trace/component/trace/sheet/TabPaneCpuByProcess.test.ts @@ -19,14 +19,25 @@ const sqlit = require("../../../../../dist/trace/database/SqlLite.js") jest.mock("../../../../../dist/trace/database/SqlLite.js"); describe('TabPaneCpuByProcess Test', () => { let tabPaneCpuByProcess = new TabPaneCpuByProcess(); - tabPaneCpuByProcess.sortByColumn = jest.fn(()=> true) + // tabPaneCpuByProcess.sortByColumn = jest.fn(()=> true) it('TabPaneCpuByProcessTest01', function () { expect(tabPaneCpuByProcess.sortByColumn({ - key: 'name', + key: 'number', + })).toBeUndefined(); + }); + + it('TabPaneCpuByProcessTest05', function () { + expect(tabPaneCpuByProcess.sortByColumn({ sort: () => { } - })).toBeTruthy(); + })).toBeUndefined(); + }); + + it('TabPaneCpuByProcessTest04', function () { + expect(tabPaneCpuByProcess.sortByColumn({ + key: 'pid'||'wallDuration'||'avgDuration'||'occurrences', + })).toBeUndefined(); }); it('TabPaneCpuByProcessTest02', function () { @@ -50,4 +61,31 @@ describe('TabPaneCpuByProcess Test', () => { let a = {rightNs: 1, cpus: [11, 12, 13]} expect(tabPaneCpuByProcess.data = a).toBeTruthy(); }); + + it('TabPaneCpuByProcessTest04', function () { + expect(tabPaneCpuByProcess.initHtml()).toMatchInlineSnapshot(` +" + + + + + + + + + + + + + + + " +`) + }); }) diff --git a/host/ide/test/trace/component/trace/sheet/TabPaneCpuByThread.test.ts b/host/ide/test/trace/component/trace/sheet/TabPaneCpuByThread.test.ts index d01b6ecce862afb4924bb6de15024a4edd9d46a8..4a2a2fe5e8e638818560a9695e7216374fb3fa22 100644 --- a/host/ide/test/trace/component/trace/sheet/TabPaneCpuByThread.test.ts +++ b/host/ide/test/trace/component/trace/sheet/TabPaneCpuByThread.test.ts @@ -15,15 +15,79 @@ // @ts-ignore import {TabPaneCpuByThread} from "../../../../../dist/trace/component/trace/sheet/TabPaneCpuByThread.js" +import {getTabCpuByThread} from "../../../../../src/trace/database/SqlLite"; +const sqlit = require("../../../../../dist/trace/database/SqlLite.js") +jest.mock("../../../../../dist/trace/database/SqlLite.js"); describe('TabPaneCpuByThread Test', () => { let tabPaneCpuByThread = new TabPaneCpuByThread(); it('TabPaneCpuByThreadTest01', function () { expect(tabPaneCpuByThread.sortByColumn({ - key: 'name', + key: 'number', sort: () => { } })).toBeUndefined(); }); + + it('TabPaneCpuByThreadTest02', function () { + expect(tabPaneCpuByThread.sortByColumn({ + key: 'pid'||'wallDuration'||'avgDuration'||'occurrences', + })).toBeUndefined(); + }); + + it('TabPaneCpuByThreadTest03', function () { + let mockgetTabCpuByThread = sqlit.getTabCpuByThread + mockgetTabCpuByThread.mockResolvedValue([{process : "test", + wallDuration: 10, + occurrences: 10, + thread:"" + }, + {process : "test2", + wallDuration: 11, + occurrences: 11, + thread:"" + }] + ) + let a = {rightNs: 1, cpus: [11, 12, 13]} + expect(tabPaneCpuByThread.data = a).toBeTruthy(); + }); + + it('TabPaneCpuByThreadTest04', function () { + let mockgetTabCpuByThread = sqlit.getTabCpuByThread + mockgetTabCpuByThread.mockResolvedValue([]) + let a = {rightNs: 1, cpus: [11, 12, 13]} + expect(tabPaneCpuByThread.data = a).toBeTruthy(); + }); + + it('TabPaneCpuByThreadTest05', function () { + expect(tabPaneCpuByThread.initHtml()).toMatchInlineSnapshot(` +" + + + + + + + + + + + + + + + + + + + " +`); + }); }) diff --git a/host/ide/test/trace/component/trace/sheet/TabPaneCpuUsage.test.ts b/host/ide/test/trace/component/trace/sheet/TabPaneCpuUsage.test.ts index d70e77feda656ac03d080bf3159592143e2bf2a5..dde00483ea3a93ec35fdbc154142cb82345cd492 100644 --- a/host/ide/test/trace/component/trace/sheet/TabPaneCpuUsage.test.ts +++ b/host/ide/test/trace/component/trace/sheet/TabPaneCpuUsage.test.ts @@ -15,10 +15,44 @@ // @ts-ignore import {TabPaneCpuUsage} from "../../../../../dist/trace/component/trace/sheet/TabPaneCpuUsage.js" +const sqlit = require("../../../../../dist/trace/database/SqlLite.js") +jest.mock("../../../../../dist/trace/database/SqlLite.js"); + describe('TabPaneCpuUsage Test', () => { let tabPaneCpuUsage = new TabPaneCpuUsage(); + let mockGetTabCpuUsage = sqlit.getTabCpuUsage + let mockGetTabCpuFreq = sqlit.getTabCpuFreq + + mockGetTabCpuUsage.mockResolvedValue([]) + mockGetTabCpuFreq.mockResolvedValue([]) + + let selectionData = { + cpus: [], + threadIds: [], + trackIds: [], + funTids: [], + heapIds: [], + nativeMemory: [], + cpuAbilityIds: [], + memoryAbilityIds: [], + diskAbilityIds: [], + networkAbilityIds: [], + leftNs: 0, + rightNs: 0, + hasFps: false, + statisticsSelectData: undefined, + perfSampleIds: [], + perfCpus: [], + perfProcess: [], + perfThread: [], + perfAll: false, + } + + tabPaneCpuUsage.data = selectionData + + it('TabPaneCpuUsageTest02', function () { expect(tabPaneCpuUsage.sortTable([[1,2,3,9,6,4],[5,2,1,4,9,6]],1,true)).toBeUndefined(); }); @@ -70,4 +104,37 @@ describe('TabPaneCpuUsage Test', () => { }]) expect(result.get(0).length).toBe(1); }); + + it('TabPaneCurrentSelectionTest07',function(){ + expect(tabPaneCpuUsage.initHtml()).toMatchInlineSnapshot(` +" + + + + + + + + + + + + + + + + + + + + + " +`); + }); }) diff --git a/host/ide/test/trace/component/trace/sheet/TabPaneCurrentSelection.test.ts b/host/ide/test/trace/component/trace/sheet/TabPaneCurrentSelection.test.ts index 5ecf5f1719d90fc6ba210676b7daa274b8f6afba..68be53981c41c4195cf00f766b8cd5d84ad39f85 100644 --- a/host/ide/test/trace/component/trace/sheet/TabPaneCurrentSelection.test.ts +++ b/host/ide/test/trace/component/trace/sheet/TabPaneCurrentSelection.test.ts @@ -29,6 +29,7 @@ describe('TabPaneCurrentSelection Test', () => { const canvas = document.createElement('canvas'); canvas.width = 1; canvas.height = 1; + let context = canvas.getContext("2d"); let cpuData = [{ cpu: 1, @@ -149,8 +150,9 @@ describe('TabPaneCurrentSelection Test', () => { }); it('TabPaneCurrentSelectionTest04', function () { - let result = tabPaneCurrentSelection.drawRight(canvas, wakeupBean) - expect(result).toBeUndefined(); + // @ts-ignore + document.body.innerHTML = ` `; + expect(tabPaneCurrentSelection.drawRight(canvas, wakeupBean)).toBeUndefined(); }); it('TabPaneCurrentSelectionTest06', function () { @@ -183,4 +185,69 @@ describe('TabPaneCurrentSelection Test', () => { expect(result).toBe('101ns '); }); + it('TabPaneCurrentSelectionTest13',function(){ + tabPaneCurrentSelection.setCpuData = jest.fn(()=>true); + tabPaneCurrentSelection.data = jest.fn(()=>true); + expect(tabPaneCurrentSelection.data).toBeUndefined(); + }); + + it('TabPaneCurrentSelectionTest14',function(){ + expect(tabPaneCurrentSelection.setCpuData(cpuData,undefined,1)).not.toBeUndefined(); + }); + + it('TabPaneCurrentSelectionTest15',function(){ + expect(tabPaneCurrentSelection.initHtml()).toMatchInlineSnapshot(` +" + +
+
+

+

Scheduling Latency

+
+
+
+ + + + + + + + +
+
+ +
+
+
+ " +`); + }); }) diff --git a/host/ide/test/trace/component/trace/sheet/TabPaneDiskAbility.test.ts b/host/ide/test/trace/component/trace/sheet/TabPaneDiskAbility.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..745bd893f57756af53ebe04adc71a7a3a7ccb330 --- /dev/null +++ b/host/ide/test/trace/component/trace/sheet/TabPaneDiskAbility.test.ts @@ -0,0 +1,57 @@ +/* + * 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. + */ +//@ts-ignore +import {TabPaneDiskAbility} from "../../../../../dist/trace/component/trace/sheet/TabPaneDiskAbility.js"; +window.ResizeObserver = window.ResizeObserver || jest.fn().mockImplementation(()=>({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), +})) + +describe('TabPaneDiskAbility Test', ()=>{ + + let tabPaneDiskAbility = new TabPaneDiskAbility(); + it('TabPaneDiskAbilityTest01',()=>{ + tabPaneDiskAbility.queryResult.length = 1; + expect(tabPaneDiskAbility.filterData()).toBeUndefined(); + }); + + it('TabPaneDiskAbilityTest02 ', function () { + const val = { + startTimeStr:"", + durationStr:"", + dataReadStr:"", + dataReadSecStr:"", + dataWriteStr:"", + readsInStr:"", + readsInSecStr:"", + writeOutStr:"", + writeOutSecStr:"" + } + expect(tabPaneDiskAbility.toDiskAbilityArray(val)).not.toBeUndefined(); + }); + + it('TabPaneDiskAbilityTest03 ', function () { + expect(tabPaneDiskAbility.sortByColumn({ + key:'startTime', + })).toBeUndefined(); + }); + + it('TabPaneDiskAbilityTest04 ', function () { + expect(tabPaneDiskAbility.sortByColumn({ + key:!'startTime', + })).toBeUndefined(); + }); +}) \ No newline at end of file diff --git a/host/ide/test/trace/component/trace/sheet/TabPaneFilter.test.ts b/host/ide/test/trace/component/trace/sheet/TabPaneFilter.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..69142be74fa06c31da34f00ec832e730e2540533 --- /dev/null +++ b/host/ide/test/trace/component/trace/sheet/TabPaneFilter.test.ts @@ -0,0 +1,323 @@ +/* + * 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. + */ + +// @ts-ignore +import {TabPaneFilter} from "../../../../../dist/trace/component/trace/sheet/TabPaneFilter.js" + +describe('TabPaneFilter Test', () => { + let tabPaneFilter = new TabPaneFilter(); + + it('TabPaneFilterTest01', function () { + expect(tabPaneFilter.firstSelect).toBe(""); + }); + + it('TabPaneFilterTest02', function () { + expect(tabPaneFilter.secondSelect).toBe(""); + }); + + it('TabPaneFilterTest03', function () { + expect(tabPaneFilter.filterValue).toBe(""); + }); + + it('TabPaneFilterTest04', function () { + tabPaneFilter.filterValue = true + expect(tabPaneFilter.filterValue).toBeTruthy(); + }); + + it('TabPaneFilterTest05', function () { + expect(tabPaneFilter.icon).toBe("tree"); + }); + + it('TabPaneFilterTest08', function () { + tabPaneFilter.iconEL.name = "menu" + expect(tabPaneFilter.icon).toBe("block"); + }); + + it('TabPaneFilterTest09', function () { + tabPaneFilter.iconEL.name = "" + expect(tabPaneFilter.icon).toBe(""); + }); + + it('TabPaneFilterTest06', function () { + tabPaneFilter.icon = true + expect(tabPaneFilter.icon).toBe(""); + }); + + it('TabPaneFilterTest07', function () { + expect(tabPaneFilter.initHtml()).toMatchInlineSnapshot(` +" + + + Input Filter + + +
+ +
+ +
+
Invert
+
Hide System so
+
+ Options +
+ +
+ + + +
+
Constraints:Only enabled with data and while stopped;
+
filters data to thresholds.
+
+ +
+
+ Sample Count Filter +
+ +
+
+ +
+
+
Reset
+
+
+ Symbol Filter +
+ +
+
+ +
+
+
Reset
+
+
+ Library Filter +
+ " +`); + }); + + it('TabPaneFilterTest10', function () { + expect(tabPaneFilter.addDataMining({name:""},"")).toBe(-1); + }); + + it('TabPaneFilterTest11', function () { + expect(tabPaneFilter.getFilterTreeData()).not.toBeUndefined(); + }); + + it('TabPaneFilterTest12', function () { + expect(tabPaneFilter.initializeFilterTree(true,true,true)).toBeUndefined(); + }); + + it('TabPaneFilterTest13', function () { + expect(tabPaneFilter.disabledMining).toBeFalsy(); + }); + + it('TabPaneFilterTest14', function () { + tabPaneFilter.disabledMining = true + expect(tabPaneFilter.disabledMining).toBeTruthy(); + }); +}) \ No newline at end of file diff --git a/host/ide/test/trace/component/trace/sheet/TabPaneFps.test.ts b/host/ide/test/trace/component/trace/sheet/TabPaneFps.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..7fb72715599bdc1d840a65a91ecbc12f6dc49828 --- /dev/null +++ b/host/ide/test/trace/component/trace/sheet/TabPaneFps.test.ts @@ -0,0 +1,62 @@ +/* + * 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. + */ +//@ts-ignore +import {TabPaneFps} from "../../../../../dist/trace/component/trace/sheet/TabPaneFps.js"; +const sqlit = require("../../../../../dist/trace/database/SqlLite.js") +jest.mock("../../../../../dist/trace/database/SqlLite.js"); + +describe('TabPaneFps Test', () => { + let tabPaneFps = new TabPaneFps(); + + it('TabPaneFpsTest01', function () { + let mockgetTabFps = sqlit.getTabFps + mockgetTabFps.mockResolvedValue( + [ + { leftNs : 10, + rightNs: 10, + }] + ) + let a = {rightNs: 1, leftNs:1} + expect(tabPaneFps.data = a).toBeTruthy(); + }); + + it('TabPaneFpsTest02', function () { + let mockgetTabFps = sqlit.getTabFps + mockgetTabFps.mockResolvedValue([]) + let a = {rightNs: 1, leftNs:1} + expect(tabPaneFps.data = a).toBeTruthy(); + }); + + it('TabPaneFpsTest03', function () { + expect(tabPaneFps.initHtml()).toMatchInlineSnapshot(` +" + + + + + + + + + " +`) + }); +}) \ No newline at end of file diff --git a/host/ide/test/trace/component/trace/sheet/TabPaneHeap.test.ts b/host/ide/test/trace/component/trace/sheet/TabPaneHeap.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..0f64de0e48dd2ea5e9de4148b428077dc5492819 --- /dev/null +++ b/host/ide/test/trace/component/trace/sheet/TabPaneHeap.test.ts @@ -0,0 +1,310 @@ +/* + * 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. + */ + +//@ts-ignore +import {TabPaneHeap} from "../../../../../dist/trace/component/trace/sheet/TabPaneHeap.js"; +//@ts-ignore +import {HeapBean} from "../../../../../dist/trace/bean/HeapBean"; +//@ts-ignore +import {HeapTreeDataBean} from "../../../../../dist/trace/bean/HeapTreeDataBean"; +//@ts-ignore +import {queryHeapAllData} from "../../../../../dist/trace/database/SqlLite"; +const sqlit = require("../../../../../dist/trace/database/SqlLite.js") +jest.mock("../../../../../dist/trace/database/SqlLite.js"); + +window.ResizeObserver = window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +describe('TabPaneHeap Test', () => { + document.body.innerHTML = `
` + let tabPane = document.querySelector('.heap') as TabPaneHeap; + + let tabPaneHeap = new TabPaneHeap(); + let list = [{ + AllocationSize:0, + DeAllocationSize:0, + RemainingSize:0, + children:[{ + length:1 + }] + }] + let selection = { + leftNs:1, + rightNs:1 + } + + let heapTreeDataBean: Array = [{ + MoudleName: 'abc', + AllocationFunction: 'ccc', + startTs: 0, + endTs: 0, + eventType: '', + depth: 0, + heapSize: 0, + eventId: "", + },{ + MoudleName: '', + AllocationFunction: '', + startTs: 0, + endTs: 0, + eventType: '', + depth: 0, + heapSize: 0, + eventId: "", + },{ + MoudleName: '', + AllocationFunction: '', + startTs: 0, + endTs: 0, + eventType: '', + depth: 0, + heapSize: 0, + eventId: "", + }] + + let mockGetHeapAllData = sqlit.queryHeapAllData + mockGetHeapAllData.mockResolvedValue(heapTreeDataBean); + + tabPane.data = [{ + cpus: [], + threadIds: [], + trackIds: [], + funTids: [], + heapIds: [], + nativeMemory: [], + cpuAbilityIds: [], + memoryAbilityIds: [], + diskAbilityIds: [], + networkAbilityIds: [], + leftNs: 0, + rightNs: 0, + hasFps: false, + statisticsSelectData: undefined, + perfSampleIds: [], + perfCpus: [], + perfProcess: [], + perfThread: [], + perfAll: false, + }] + + it('TabPaneHeapTest01', function () { + let listData: Array = [{ + MoudleName: '', + AllocationFunction: '', + Allocations: 0, + Deallocations: 0, + AllocationSize: 0, + DeAllocationSize: 0, + Total: 0, + RemainingSize: 0, + children: [], + depth: 0, + }] + expect(tabPaneHeap.setTreeDataSize(listData)).toBeUndefined(); + }); + + it('TabPaneHeapTest02', function () { + let beanList: Array = [{ + MoudleName: '', + AllocationFunction: '', + Allocations: 0, + Deallocations: 0, + AllocationSize: 0, + DeAllocationSize: 0, + Total: 0, + RemainingSize: 0, + children: [], + depth: 0, + },{ + MoudleName: '', + AllocationFunction: '', + Allocations: 0, + Deallocations: 0, + AllocationSize: 0, + DeAllocationSize: 0, + Total: 0, + RemainingSize: 0, + children: [], + depth: 0, + }] + + let heapTreeDataBean: Array = [{ + MoudleName: '', + AllocationFunction: '', + startTs: 0, + endTs: 0, + eventType: '', + depth: 0, + heapSize: 0, + eventId: "", + },{ + MoudleName: '', + AllocationFunction: '', + startTs: 0, + endTs: 0, + eventType: '', + depth: 0, + heapSize: 0, + eventId: "", + },{ + MoudleName: '', + AllocationFunction: '', + startTs: 0, + endTs: 0, + eventType: '', + depth: 0, + heapSize: 0, + eventId: "", + }] + + let selectionData = { + cpus: [], + threadIds: [], + trackIds: [], + funTids: [], + heapIds: [], + nativeMemory: [], + cpuAbilityIds: [], + memoryAbilityIds: [], + diskAbilityIds: [], + networkAbilityIds: [], + leftNs: 0, + rightNs: 0, + hasFps: false, + statisticsSelectData: undefined, + perfSampleIds: [], + perfCpus: [], + perfProcess: [], + perfThread: [], + perfAll: false, + } + expect(tabPaneHeap.merageTree(1, beanList,heapTreeDataBean,selectionData)).toBeUndefined(); + }); + + it('TabPaneHeapTest03', function () { + expect(tabPaneHeap.initHtml()).toMatchInlineSnapshot(` +" + + + + + + + + + + + + + + + + + + + + + " +`); + }); + + it('TabPaneHeapTest04', function () { + let beanList: Array = [{ + MoudleName: 'abc', + AllocationFunction: 'ccc', + Allocations: 0, + Deallocations: 0, + AllocationSize: 0, + DeAllocationSize: 0, + Total: 0, + RemainingSize: 0, + children: [], + depth: 0, + },{ + MoudleName: 'abc', + AllocationFunction: 'ccc', + Allocations: 0, + Deallocations: 0, + AllocationSize: 0, + DeAllocationSize: 0, + Total: 0, + RemainingSize: 0, + children: [], + depth: 0, + }] + + let heapTreeDataBean: Array = [{ + MoudleName: 'abc', + AllocationFunction: 'ccc', + startTs: 0, + endTs: 0, + eventType: '', + depth: 0, + heapSize: 0, + eventId: "", + },{ + MoudleName: '', + AllocationFunction: '', + startTs: 0, + endTs: 0, + eventType: '', + depth: 0, + heapSize: 0, + eventId: "", + },{ + MoudleName: '', + AllocationFunction: '', + startTs: 0, + endTs: 0, + eventType: '', + depth: 0, + heapSize: 0, + eventId: "", + }] + + let selectionData = { + cpus: [], + threadIds: [], + trackIds: [], + funTids: [], + heapIds: [], + nativeMemory: [], + cpuAbilityIds: [], + memoryAbilityIds: [], + diskAbilityIds: [], + networkAbilityIds: [], + leftNs: 0, + rightNs: 0, + hasFps: false, + statisticsSelectData: undefined, + perfSampleIds: [], + perfCpus: [], + perfProcess: [], + perfThread: [], + perfAll: false, + } + expect(tabPaneHeap.merageTree(1, beanList,heapTreeDataBean,selectionData)).toBeUndefined(); + }); +}) \ No newline at end of file diff --git a/host/ide/test/trace/component/trace/sheet/TabPaneHistoryProcesses.test.ts b/host/ide/test/trace/component/trace/sheet/TabPaneHistoryProcesses.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..ae51f808b509e64d3197b6bfb19f5e1bbc732253 --- /dev/null +++ b/host/ide/test/trace/component/trace/sheet/TabPaneHistoryProcesses.test.ts @@ -0,0 +1,64 @@ +/* + * 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. + */ +//@ts-ignore +import {TabPaneHistoryProcesses} from "../../../../../dist/trace/component/trace/sheet/TabPaneHistoryProcesses.js"; +window.ResizeObserver = window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +describe('TabPaneHistoryProcesses Test', function () { + + let tabPaneHistoryProcesses = new TabPaneHistoryProcesses(); + it('TabPaneHistoryProcessesTest01 ', function () { + tabPaneHistoryProcesses.queryResult.length = 1; + expect(tabPaneHistoryProcesses.filterData()).toBeUndefined(); + }); + + it('TabPaneHistoryProcessesTest02 ', function () { + const val = { + processId:-1, + processName:"", + alive:"", + firstSeen:"", + lastSeen:"", + responsibleProcess:"", + userName:"", + cpuTime:"" + } + expect(tabPaneHistoryProcesses.toProcessHistoryArray(val)).not.toBeUndefined(); + }); + + it('TabPaneHistoryProcessesTest03 ', function () { + expect(tabPaneHistoryProcesses.sortByColumn({ + key:'startTime', + })).toBeUndefined(); + }); + + it('TabPaneHistoryProcessesTest04 ', function () { + expect(tabPaneHistoryProcesses.sortByColumn({ + key:'alive', + })).toBeUndefined(); + }); + + it('TabPaneHistoryProcessesTest05 ', function () { + expect(tabPaneHistoryProcesses.sortByColumn({ + key:!'startTime'&&!'alive', + })).toBeUndefined(); + }); + +}); \ No newline at end of file diff --git a/host/ide/test/trace/component/trace/sheet/TabPaneLiveProcesses.test.ts b/host/ide/test/trace/component/trace/sheet/TabPaneLiveProcesses.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..75cb063c8dadef77af0492b83604711b0e1c15d8 --- /dev/null +++ b/host/ide/test/trace/component/trace/sheet/TabPaneLiveProcesses.test.ts @@ -0,0 +1,72 @@ +/* + * 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. + */ +//@ts-ignore +import {TabPaneLiveProcesses} from "../../../../../dist/trace/component/trace/sheet/TabPaneLiveProcesses.js"; +window.ResizeObserver = window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +describe('TabPaneLiveProcesses Test',function (){ + let tabPaneLiveProcesses = new TabPaneLiveProcesses(); + + it('TabPaneLiveProcessesTest01 ', function () { + tabPaneLiveProcesses.queryResult.length = 1; + expect(tabPaneLiveProcesses.filterData()).toBeUndefined(); + }); + + it('TabPaneLiveProcessesTest02 ', function () { + const live={ + processId:1, + processName:"", + responsibleProcess:"", + userName:"", + cpu:"1", + threads:-1, + memory:'', + diskReads:-1, + diskWrite:-1 + } + expect(tabPaneLiveProcesses.toLiveProcessArray(live)).not.toBeUndefined(); + }); + + it('TabPaneLiveProcessesTest03 ', function () { + expect(tabPaneLiveProcesses.sortByColumn({ + key:'startTime', + })).toBeUndefined(); + }); + + it('TabPaneLiveProcessesTest07 ', function () { + expect(tabPaneLiveProcesses.sortByColumn({ + key:'cpuTime', + })).toBeUndefined(); + }); + + it('TabPaneLiveProcessesTest04 ', function () { + expect(tabPaneLiveProcesses.sortByColumn({ + key:!'startTime'|| !'cpuTime', + })).toBeUndefined(); + }); + + it('TabPaneLiveProcessesTest05', function () { + expect(tabPaneLiveProcesses.timeFormat(70000)).toBe("1:10.0s "); + }); + + it('TabPaneLiveProcessesTest06', function () { + expect(tabPaneLiveProcesses.timeFormat(2000)).toBe("2.0s "); + }); +}) \ No newline at end of file diff --git a/host/ide/test/trace/component/trace/sheet/TabPaneMemoryAbility.test.ts b/host/ide/test/trace/component/trace/sheet/TabPaneMemoryAbility.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..2005fc5cee75997960cf201b34c461258b056ec9 --- /dev/null +++ b/host/ide/test/trace/component/trace/sheet/TabPaneMemoryAbility.test.ts @@ -0,0 +1,54 @@ +/* + * 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. + */ + +//@ts-ignore +import {TabPaneMemoryAbility} from "../../../../../dist/trace/component/trace/sheet/TabPaneMemoryAbility.js"; +window.ResizeObserver = window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +describe('TabPaneMemoryAbility Test', () => { + let tabPaneMemoryAbility = new TabPaneMemoryAbility(); + + it('TabPaneMemoryAbilityTest01', function () { + tabPaneMemoryAbility.queryResult.length = 1; + expect(tabPaneMemoryAbility.filterData()).toBeUndefined(); + }); + + it('TabPaneMemoryAbilityTest02', function () { + const systemMemorySummary = [{ + startTimeStr:"1", + durationStr:"1", + cached:"1", + swapTotal:"1" + }] + expect(tabPaneMemoryAbility.toMemoryAbilityArray(systemMemorySummary)).not.toBeUndefined(); + }); + + it('TabPaneMemoryAbilityTest03', function () { + expect(tabPaneMemoryAbility.sortByColumn({ + key:'startTime' + })).toBeUndefined(); + }); + + it('TabPaneMemoryAbilityTest04', function () { + expect(tabPaneMemoryAbility.sortByColumn({ + key:!'startTime' + })).toBeUndefined(); + }); +}) \ No newline at end of file diff --git a/host/ide/test/trace/component/trace/sheet/TabPaneNMCallInfo.test.ts b/host/ide/test/trace/component/trace/sheet/TabPaneNMCallInfo.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..4daa75ea4d0fd740838fb1a4cb17c5f2392120f1 --- /dev/null +++ b/host/ide/test/trace/component/trace/sheet/TabPaneNMCallInfo.test.ts @@ -0,0 +1,408 @@ +/* + * 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. + */ + +// @ts-ignore +import {TabPaneNMCallInfo} from "../../../../../dist/trace/component/trace/sheet/TabPaneNMCallInfo.js" +// @ts-ignore +import {HeapBean} from "../../../../../dist/trace/bean/HeapBean.js"; +import {queryHeapAllData} from "../../../../../src/trace/database/SqlLite"; +import {NativeHookCallInfo} from "../../../../../src/trace/bean/NativeHook"; +const sqlit = require("../../../../../dist/trace/database/SqlLite.js") +jest.mock("../../../../../dist/trace/database/SqlLite.js"); + +window.ResizeObserver = window.ResizeObserver || jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), +})); + +describe('TabPaneNMCallInfo Test', () => { + document.body.innerHTML = '' + let tabPaneNMCallInfo = document.querySelector('#ddd') + + let mockGetNativeHookEventTid = sqlit.queryNativeHookEventTid + + let nativeHookData = [ + { + eventId: 0, + eventType: "", + subType: "", + heapSize: 0, + addr: "", + startTs: 0, + endTs: 0, + sumHeapSize: 0, + max: 0, + count: 0, + tid: 0, + isSelected: false, + }, + { + eventId: 0, + eventType: "", + subType: "", + heapSize: 0, + addr: "", + startTs: 0, + endTs: 0, + sumHeapSize: 0, + max: 0, + count: 0, + tid: 0, + isSelected: false, + }, + ] + + mockGetNativeHookEventTid.mockResolvedValue(nativeHookData); + tabPaneNMCallInfo.currentSelection = jest.fn(()=>true) + TabPaneNMCallInfo.data = { + cpus: [], + threadIds: [], + trackIds: [], + funTids: [], + heapIds: [], + nativeMemory: [], + leftNs: 0, + rightNs: 0, + hasFps: false, + statisticsSelectData: undefined + } + it('TabPaneNMCallInfoTest01', function () { + let array = new Array(); + array.push({ + MoudleName: '', + AllocationFunction: '', + Allocations: 0, + Deallocations: 0, + AllocationSize: 0, + DeAllocationSize: 0, + Total: 0, + RemainingSize: 0, + children: [], + depth: 0, + }) + tabPaneNMCallInfo.groupByWithTid = jest.fn(()=>true) + let handleQueryResult = tabPaneNMCallInfo.handleQueryResult(nativeHookData); + expect(handleQueryResult).toEqual(true) + }); + + it('TabPaneNMCallInfoTest02', function () { + tabPaneNMCallInfo.currentSelection = jest.fn(()=>true) + tabPaneNMCallInfo.queryResult = jest.fn(()=>nativeHookData) + expect(tabPaneNMCallInfo.filterQueryData()).toBeUndefined(); + }); + + it('TabPaneNMCallInfoTest03', function () { + let hookData = new Array(); + hookData.push({ + id: "", + pid: "", + library: "", + title: "", + count: 0, + children: [], + depth: 0, + frame: undefined, + isHover: false, + parent: undefined, + size: 0, + symbol: "", + type: 0, + heapSize: 0, + heapSizeStr: "", + eventId: 0, + threadId: 0, + isSelected:false + }) + + tabPaneNMCallInfo.frameChart = jest.fn(()=>undefined) + tabPaneNMCallInfo.frameChart.calculateChartData = jest.fn(()=>true) + tabPaneNMCallInfo.frameChart.updateCanvas = jest.fn(()=>true) + let groupByWithTid = tabPaneNMCallInfo.groupByWithTid(hookData); + expect(groupByWithTid.length).toEqual(undefined) + }); + + it('TabPaneNMCallInfoTest04', function () { + let hookLeft = { + id: "", + pid: '', + library: "", + title: "", + count: 0, + children: [], + depth: 0, + frame: undefined, + isHover: false, + parent: undefined, + size: 0, + symbol: "", + type: 0, + heapSize: 0, + heapSizeStr: "", + eventId: 0, + threadId: 0 + } + + let hookRight = { + id: "", + pid: '', + library: "", + title: "", + count: 0, + children: [], + depth: 1, + frame: undefined, + isHover: false, + parent: undefined, + size: 0, + symbol: "", + type: 0, + heapSize: 0, + heapSizeStr: "", + eventId: 0, + threadId: 0 + } + let ListToTree = tabPaneNMCallInfo.listToTree(hookRight, hookLeft); + expect(ListToTree).toBeUndefined() + }); + + it('TabPaneNMCallInfoTest05', function () { + let hookLeft = { + id: "", + pid: '', + library: "", + title: "", + count: 0, + children: [], + depth: 0, + frame: undefined, + isHover: false, + parent: undefined, + size: 0, + symbol: "", + type: 0, + heapSize: 0, + heapSizeStr: "", + eventId: 0, + threadId: 0 + } + + let hookRight = { + id: "", + pid: '', + library: "", + title: "", + count: 0, + children: [hookLeft], + depth: 0, + frame: undefined, + isHover: false, + parent: undefined, + size: 0, + symbol: "", + type: 0, + heapSize: 0, + heapSizeStr: "", + eventId: 0, + threadId: 0 + } + let groupByWithTid = tabPaneNMCallInfo.listToTree(hookLeft, hookRight); + expect(groupByWithTid).toBeUndefined() + }); + + it('TabPaneNMCallInfoTest06', function () { + let target = { + id: "", + pid: '', + library: "", + title: "", + count: 0, + children: [{length:1}], + depth: 0, + frame: undefined, + isHover: false, + parent: undefined, + size: 0, + symbol: "", + type: 0, + heapSize: 0, + heapSizeStr: "", + eventId: 0, + threadId: 0 + } + let src = { + id: "", + pid: '', + library: "", + title: "", + count: 0, + children: [], + depth: 0, + frame: undefined, + isHover: false, + parent: undefined, + size: 0, + symbol: "", + type: 0, + heapSize: 0, + heapSizeStr: "", + eventId: 0, + threadId: 0 + } + let groupByWithTid = tabPaneNMCallInfo.mergeTree(target,src); + expect(groupByWithTid).toBeUndefined() + }); + + it('TabPaneNMCallInfoTest07', function () { + let target = { + id: "", + pid: '', + library: "", + title: "", + count: 0, + children: [], + depth: 0, + frame: undefined, + isHover: false, + parent: undefined, + size: 0, + symbol: "", + type: 0, + heapSize: 0, + heapSizeStr: "", + eventId: 0, + threadId: 0, + length:1 + } + + let src = { + id: "", + pid: '', + library: "", + title: "", + count: 0, + children: [target], + depth: 0, + frame: undefined, + isHover: false, + parent: undefined, + size: 0, + symbol: "", + type: 0, + heapSize: 0, + heapSizeStr: "", + eventId: 0, + threadId: 0 + } + let groupByWithTid = tabPaneNMCallInfo.mergeTree(target, src); + expect(groupByWithTid).toBeUndefined() + }); + + it('TabPaneNMCallInfoTest08', function () { + let hookLeft = { + id: "", + pid: '', + library: "", + title: "", + count: 0, + children: [], + depth: 0, + frame: undefined, + isHover: false, + parent: undefined, + size: 2, + symbol: "", + type: 0, + heapSize: 0, + heapSizeStr: "", + eventId: 0, + threadId: 0 + } + let groupByWithTid = tabPaneNMCallInfo.setRightTableData(hookLeft); + expect(groupByWithTid).toBeUndefined() + }); + + it('TabPaneNMCallInfoTest10', function () { + expect(tabPaneNMCallInfo.sortTreeByColumn()).toBeUndefined(); + }); + + it('TabPaneNMCallInfoTest11', function () { + expect(tabPaneNMCallInfo.initHtml()).toMatchInlineSnapshot(` +" + +
+ +
+ + + + + + + + + + + +
+
+ + + + + + + +
+
+ + + + +
+ " +`); + }); + +}) diff --git a/host/ide/test/trace/component/trace/sheet/TabPaneNMSampleList.test.ts b/host/ide/test/trace/component/trace/sheet/TabPaneNMSampleList.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..d889fa05ed700cc64b45c5bff2bf8ec932ddff86 --- /dev/null +++ b/host/ide/test/trace/component/trace/sheet/TabPaneNMSampleList.test.ts @@ -0,0 +1,253 @@ +/* + * 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. + */ + +// @ts-ignore +import {TabPaneNMSampleList} from "../../../../../dist/trace/component/trace/sheet/TabPaneNMSampleList.js" +// @ts-ignore +import {LitTable} from "../../../../../dist/base-ui/table/lit-table"; +const sqlit = require("../../../../../dist/trace/database/SqlLite.js") +jest.mock("../../../../../dist/trace/database/SqlLite.js"); + +window.ResizeObserver = window.ResizeObserver || jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), +})); +describe('TabPaneNMSampleList Test', () => { + document.body.innerHTML = '' + let tabPaneNMSampleList = document.querySelector('#ddt') + let mockGeTabCounters = sqlit.getTabCounters + let mockGetHookData = sqlit.queryAllHookData + let mockGetNativeHookEventId = sqlit.queryNativeHookEventId + let mockGetNativeHookSnapshot = sqlit.queryNativeHookSnapshot + let mockGetNativeHookSnapshotTypes = sqlit.queryNativeHookSnapshotTypes + + TabPaneNMSampleList.source = [{ + current: "", + currentSize: 0, + startTs: 0, + heapSize: 0, + snapshot: "", + growth: "", + total: 0, + totalGrowth: "", + existing: 0, + children: [], + tempList: [], + timestamp: "", + eventId: -1, + }] + TabPaneNMSampleList.filterSelect = '0' + + tabPaneNMSampleList.currentSelection = jest.fn(()=>true) + let dat = { + cpus: [], + threadIds: [], + trackIds: [], + funTids: [], + heapIds: [], + nativeMemory: [], + leftNs: 0, + rightNs: 0, + hasFps: false, + statisticsSelectData: undefined + } + + let NativeHookSnapshotTypes = [{ + eventId: -1, + current: 0, + eventType: "", + subType: "", + growth: 0, + existing: 0, + addr: "", + startTs: 0, + endTs: 0, + total: 0, + children: [], + }] + + mockGetNativeHookSnapshotTypes.mockResolvedValue(NativeHookSnapshotTypes); + mockGetHookData.mockResolvedValue(NativeHookSnapshotTypes); + mockGetNativeHookSnapshot.mockResolvedValue([]); + + tabPaneNMSampleList.data = dat + it('TabPaneNMSampleListTest01', function () { + expect(TabPaneNMSampleList.serSelection(dat)).toBeUndefined() + }); + + it('TabPaneNMSampleListTest02', function () { + let sampleData = { + index: 0, + eventId: 0, + eventType: "", + subType: "", + addr: "", + startTs: 0, + timestamp: "", + heapSize: 0, + heapSizeUnit: "", + symbol: "", + library: "", + } + expect(TabPaneNMSampleList.addSampleData(sampleData)).toBeUndefined() + }); + + it('TabPaneNMSampleListTest03', function () { + let sampleData = { + index: 0, + eventId: 0, + eventType: "", + subType: "", + addr: "", + startTs: 0, + timestamp: "", + heapSize: 0, + heapSizeUnit: "", + symbol: "", + library: "", + } + + let snapshot = { + current: "", + currentSize: 0, + startTs: 0, + heapSize: 0, + snapshot: "", + growth: "", + total: 0, + totalGrowth: "", + existing: 0, + children: [], + tempList: [], + timestamp: "", + eventId: -1, + } + + expect(TabPaneNMSampleList.querySnapshot(sampleData, snapshot)).toBeUndefined() + }); + + it('TabPaneNMSampleListTest04', function () { + let snapshot = { + current: "", + currentSize: 0, + startTs: 0, + heapSize: 0, + snapshot: "", + growth: "", + total: 0, + totalGrowth: "", + existing: 0, + children: [], + tempList: [], + timestamp: "", + eventId: -1, + } + + let snapshotLeft = { + current: "", + currentSize: 0, + startTs: 0, + heapSize: 0, + snapshot: "", + growth: "", + total: 0, + totalGrowth: "", + existing: 0, + children: [snapshot], + tempList: [], + timestamp: "", + eventId: -1, + } + + let snapshotRight = { + current: "", + currentSize: 0, + startTs: 0, + heapSize: 0, + snapshot: "", + growth: "", + total: 0, + totalGrowth: "", + existing: 0, + children: [snapshot], + tempList: [], + timestamp: "", + eventId: -1, + } + expect(TabPaneNMSampleList.prepChild(snapshotLeft, snapshotRight)).toBeUndefined() + }); + + it('TabPaneNMSampleListTest05', function () { + expect(tabPaneNMSampleList.initHtml()).toMatchInlineSnapshot(` +" + +
+
+ + + + + + + + + + + + + +
+
+ + + + + + + +
+
+ " +`); + }); + + it('TabPaneNMSampleListTest09', function () { + let rootSample ={ + growth:1, + existing:1, + children:[], + total:1 + } + + let merageSample ={ + growth:1, + endTs:2, + startTs:2, + addr:"1", + eventId:0, + } + expect(TabPaneNMSampleList.merageSampleData(1,1,rootSample,merageSample)).toBeUndefined() + }); +}) diff --git a/host/ide/test/trace/component/trace/sheet/TabPaneNMStatstics.test.ts b/host/ide/test/trace/component/trace/sheet/TabPaneNMStatstics.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..1edfb47fd73ae3578175f05812775a08795a10c9 --- /dev/null +++ b/host/ide/test/trace/component/trace/sheet/TabPaneNMStatstics.test.ts @@ -0,0 +1,371 @@ +/* + * 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. + */ + +// @ts-ignore +import {TabPaneNMStatstics} from "../../../../../dist/trace/component/trace/sheet/TabPaneNMStatstics.js" +// @ts-ignore +import {NativeHookMalloc, NativeHookStatistics, NativeHookStatisticsTableData} from "../../../../../dist/trace/bean/NativeHook"; + +window.ResizeObserver = window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +describe('TabPaneNMStatstics Test', () => { + let tabPaneNMStatstics = new TabPaneNMStatstics(); + document.body.innerHTML = '
' + + it('TabPaneNMStatsticsTest01', function () { + expect(tabPaneNMStatstics.setMallocTableData([1],[1])).toBeUndefined(); + }); + it('TabPaneNMStatsticsTest09', function () { + expect(tabPaneNMStatstics.setSubTypeTableData([1],[1])).toBeUndefined(); + }); + + it('TabPaneNMStatsticsTest02', function () { + let nativeHookMalloc: Array = [{ + eventType: "", + subType: "", + heapSize: 0, + allocByte: 0, + allocCount: 0, + freeByte: 0, + freeCount: 0, + }] + let nativeHookStatisticsTableData: Array = [{ + memoryTap: "", + existing: 0, + existingString: "", + allocCount: 0, + freeCount: 0, + totalBytes: 0, + totalBytesString: "", + maxStr: "", + max: 0, + totalCount: 0, + existingValue: [], + }] + + expect(tabPaneNMStatstics.setSubTypeTableData(nativeHookMalloc,nativeHookStatisticsTableData)).toBeUndefined(); + }); + + it('TabPaneNMStatsticsTest03', function () { + expect(tabPaneNMStatstics.initHtml()).toMatchInlineSnapshot(` +" + + + + + + + + + + + + + + + + + + + + + " +`); + }); + + it('TabPaneNMStatsticsTest04', function () { + let valData = { + cpus: [], + threadIds: [], + trackIds: [], + funTids: [], + heapIds: [], + nativeMemory: ["All Heap & Anonymous VM", "All Heap", "All Anonymous VM"], + cpuAbilityIds: [], + memoryAbilityIds: [], + diskAbilityIds: [], + networkAbilityIds: [], + leftNs: 0, + rightNs: 0, + hasFps: false, + statisticsSelectData: undefined, + perfSampleIds: [], + perfCpus: [], + perfProcess: [], + perfThread: [], + perfAll: false, + } + let nativeHookStatistics: Array = [{ + eventId: 0, + eventType: "AllocEvent", + subType: "", + heapSize: 0, + addr: "", + startTs: 0, + endTs: 0, + sumHeapSize: 0, + max: 100000, + count: 0, + tid: 0, + isSelected: false, + }] + + let nativeHookStatisticsTableData: Array = [{ + memoryTap: "", + existing: 0, + existingString: "", + allocCount: 0, + freeCount: 0, + totalBytes: 0, + totalBytesString: "", + maxStr: "", + max: 0, + totalCount: 0, + existingValue: [], + }] + + expect(tabPaneNMStatstics.setMemoryTypeData(valData,nativeHookStatistics, nativeHookStatisticsTableData)).toBeUndefined(); + }); + + it('TabPaneNMStatsticsTest05', function () { + let valData = { + cpus: [], + threadIds: [], + trackIds: [], + funTids: [], + heapIds: [], + nativeMemory: ["All Heap"], + cpuAbilityIds: [], + memoryAbilityIds: [], + diskAbilityIds: [], + networkAbilityIds: [], + leftNs: 0, + rightNs: 0, + hasFps: false, + statisticsSelectData: undefined, + perfSampleIds: [], + perfCpus: [], + perfProcess: [], + perfThread: [], + perfAll: false, + } + let nativeHookStatistics: Array = [{ + eventId: 0, + eventType: "FreeEvent", + subType: "", + heapSize: 0, + addr: "", + startTs: 0, + endTs: 0, + sumHeapSize: 0, + max: 100000, + count: 0, + tid: 0, + isSelected: false, + }] + + let nativeHookStatisticsTableData: Array = [{ + memoryTap: "", + existing: 0, + existingString: "", + allocCount: 0, + freeCount: 0, + totalBytes: 0, + totalBytesString: "", + maxStr: "", + max: 0, + totalCount: 0, + existingValue: [], + }] + + expect(tabPaneNMStatstics.setMemoryTypeData(valData,nativeHookStatistics, nativeHookStatisticsTableData)).toBeUndefined(); + }); + + it('TabPaneNMStatsticsTest06', function () { + let valData = { + cpus: [], + threadIds: [], + trackIds: [], + funTids: [], + heapIds: [], + nativeMemory: ["All Anonymous VM"], + cpuAbilityIds: [], + memoryAbilityIds: [], + diskAbilityIds: [], + networkAbilityIds: [], + leftNs: 0, + rightNs: 0, + hasFps: false, + statisticsSelectData: undefined, + perfSampleIds: [], + perfCpus: [], + perfProcess: [], + perfThread: [], + perfAll: false, + } + let nativeHookStatistics: Array = [{ + eventId: 0, + eventType: "MmapEvent", + subType: "", + heapSize: 0, + addr: "", + startTs: 0, + endTs: 0, + sumHeapSize: 0, + max: 100000, + count: 0, + tid: 0, + isSelected: false, + }] + + let nativeHookStatisticsTableData: Array = [{ + memoryTap: "", + existing: 0, + existingString: "", + allocCount: 0, + freeCount: 0, + totalBytes: 0, + totalBytesString: "", + maxStr: "", + max: 0, + totalCount: 0, + existingValue: [], + }] + + expect(tabPaneNMStatstics.setMemoryTypeData(valData,nativeHookStatistics, nativeHookStatisticsTableData)).toBeUndefined(); + }); + + it('TabPaneNMStatsticsTest07', function () { + let valData = { + cpus: [], + threadIds: [], + trackIds: [], + funTids: [], + heapIds: [], + nativeMemory: ["All Anonymous VM"], + cpuAbilityIds: [], + memoryAbilityIds: [], + diskAbilityIds: [], + networkAbilityIds: [], + leftNs: 0, + rightNs: 0, + hasFps: false, + statisticsSelectData: undefined, + perfSampleIds: [], + perfCpus: [], + perfProcess: [], + perfThread: [], + perfAll: false, + } + let nativeHookStatistics: Array = [{ + eventId: 0, + eventType: "MunmapEvent", + subType: "", + heapSize: 0, + addr: "", + startTs: 0, + endTs: 0, + sumHeapSize: 0, + max: 100000, + count: 0, + tid: 0, + isSelected: false, + }] + + let nativeHookStatisticsTableData: Array = [{ + memoryTap: "", + existing: 0, + existingString: "", + allocCount: 0, + freeCount: 0, + totalBytes: 0, + totalBytesString: "", + maxStr: "", + max: 0, + totalCount: 0, + existingValue: [], + }] + + expect(tabPaneNMStatstics.setMemoryTypeData(valData,nativeHookStatistics, nativeHookStatisticsTableData)).toBeUndefined(); + }); + + it('TabPaneNMStatsticsTest08', function () { + let valData = { + cpus: [], + threadIds: [], + trackIds: [], + funTids: [], + heapIds: [], + nativeMemory: ["All Heap & Anonymous VM", "All Heap", "All Anonymous VM"], + cpuAbilityIds: [], + memoryAbilityIds: [], + diskAbilityIds: [], + networkAbilityIds: [], + leftNs: 0, + rightNs: 0, + hasFps: false, + statisticsSelectData: undefined, + perfSampleIds: [], + perfCpus: [], + perfProcess: [], + perfThread: [], + perfAll: false, + } + let nativeHookStatistics: Array = [{ + eventId: 0, + eventType: "FreeEvent", + subType: "", + heapSize: 0, + addr: "", + startTs: 0, + endTs: 0, + sumHeapSize: 0, + max: 100000, + count: 0, + tid: 0, + isSelected: false, + }] + + let nativeHookStatisticsTableData: Array = [{ + memoryTap: "", + existing: 0, + existingString: "", + allocCount: 0, + freeCount: 0, + totalBytes: 0, + totalBytesString: "", + maxStr: "", + max: 100, + totalCount: 0, + existingValue: [], + }] + + expect(tabPaneNMStatstics.setMemoryTypeData(valData,nativeHookStatistics, nativeHookStatisticsTableData)).toBeUndefined(); + }); +}) \ No newline at end of file diff --git a/host/ide/test/trace/component/trace/sheet/TabPaneNMemory.test.ts b/host/ide/test/trace/component/trace/sheet/TabPaneNMemory.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..879c43b4e147925f83b8b9f44b0e6fc150e86b95 --- /dev/null +++ b/host/ide/test/trace/component/trace/sheet/TabPaneNMemory.test.ts @@ -0,0 +1,115 @@ +/* + * 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. + */ + +//@ts-ignore +import {TabPaneNMemory} from "../../../../../dist/trace/component/trace/sheet/TabPaneNMemory.js" + +window.ResizeObserver = window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +describe('TabPaneNMemory Test', () => { + let tabPaneNMemory = new TabPaneNMemory(); + let val={ + statisticsSelectData:{ + memoryTap:1 + } + } + let hook={eventId:1} + + it('TabPaneNMemoryTest01', function () { + expect(tabPaneNMemory.getTypeFromIndex(-1)).not.toBeUndefined(); + }); + + it('TabPaneNMemoryTest02', function () { + expect(tabPaneNMemory.getTypeFromIndex(0)).not.toBeUndefined(); + }); + + it('TabPaneNMemoryTest03', function () { + expect(tabPaneNMemory.getTypeFromIndex(1,{eventType:"AllocEvent"})).not.toBeUndefined(); + }); + + it('TabPaneNMemoryTest04', function () { + expect(tabPaneNMemory.getTypeFromIndex(2,{eventType:"MmapEvent"})).not.toBeUndefined(); + }); + + it('TabPaneNMemoryTest05', function () { + expect(tabPaneNMemory.handleQueryResult([1])).not.toBeUndefined(); + }); + + it('TabPaneNMemoryTest06', function () { + expect(tabPaneNMemory.initFilterTypes()).toBeUndefined(); + }); + + it('TabPaneNMemoryTest07', function () { + expect(tabPaneNMemory.filterQueryData()).toBeUndefined(); + }); + + it('TabPaneNMemoryTest08', function () { + expect(tabPaneNMemory.initHtml()).toMatchInlineSnapshot(` +" + +
+
+ + + + + + + + + + + + + + + + + +
+
+ + + + + + + +
+
+ " +`); + }); + + it('TabPaneNMemoryTest09', function () { + tabPaneNMemory.tblData = jest.fn(()=>undefined) + tabPaneNMemory.tblData.recycleDataSource = jest.fn(()=>true) + expect(tabPaneNMemory.setRightTableData()).toBeUndefined(); + }); +}) \ No newline at end of file diff --git a/host/ide/test/trace/component/trace/sheet/TabPaneNetworkAbility.test.ts b/host/ide/test/trace/component/trace/sheet/TabPaneNetworkAbility.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..b2481432d9835e43811815cac28360ad67ee603c --- /dev/null +++ b/host/ide/test/trace/component/trace/sheet/TabPaneNetworkAbility.test.ts @@ -0,0 +1,57 @@ +/* + * 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. + */ +//@ts-ignore +import {TabPaneNetworkAbility} from "../../../../../dist/trace/component/trace/sheet/TabPaneNetworkAbility.js"; +window.ResizeObserver = window.ResizeObserver || jest.fn().mockImplementation(()=>({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), +})) + +describe('TabPaneNetworkAbility Test', ()=>{ + + let tabPaneNetworkAbility = new TabPaneNetworkAbility(); + it('TabPaneNetworkAbilityTest01',()=>{ + tabPaneNetworkAbility.queryResult.length = 1; + expect(tabPaneNetworkAbility.filterData()).toBeUndefined(); + }); + + it('TabPaneNetworkAbilityTest02 ', function () { + const val = { + startTimeStr:"", + durationStr:"", + dataReceivedStr:"", + dataReceivedSecStr:"", + dataSendSecStr:"", + dataSendStr:"", + packetsIn:-1, + packetsOut:-1, + packetsOutSec:-1 + } + expect(tabPaneNetworkAbility.toNetWorkAbilityArray(val)).not.toBeUndefined(); + }); + + it('TabPaneNetworkAbilityTest03 ', function () { + expect(tabPaneNetworkAbility.sortByColumn({ + key:'startTime', + })).toBeUndefined(); + }); + + it('TabPaneNetworkAbilityTest04 ', function () { + expect(tabPaneNetworkAbility.sortByColumn({ + key:!'startTime', + })).toBeUndefined(); + }); +}) \ No newline at end of file diff --git a/host/ide/test/trace/component/trace/sheet/TabPanePTS.test.ts b/host/ide/test/trace/component/trace/sheet/TabPanePTS.test.ts index 76a843cc06432f87b75151cf38e95e87fa000bbd..956e44b55a0ae538cc5aa71dc0c56eef323373ac 100644 --- a/host/ide/test/trace/component/trace/sheet/TabPanePTS.test.ts +++ b/host/ide/test/trace/component/trace/sheet/TabPanePTS.test.ts @@ -15,14 +15,55 @@ // @ts-ignore import {TabPanePTS} from "../../../../../dist/trace/component/trace/sheet/TabPanePTS.js" +// @ts-ignore +import {SpSystemTrace} from "../../../../../dist/trace/component/SpSystemTrace.js"; window.ResizeObserver = window.ResizeObserver ||jest.fn().mockImplementation(() => ({ disconnect: jest.fn(), observe: jest.fn(), unobserve: jest.fn(), })); describe('TabPanePTS Test', () => { + document.body.innerHTML = `
` + let tabPane = document.querySelector('.pts') as TabPanePTS; let tabPanePTS = new TabPanePTS(); - + + SpSystemTrace.SPT_DATA = [{ + process: "", + processId: 0, + thread: "", + threadId: 0, + state: '', + dur: 0, + start_ts: 0, + end_ts: 0, + cpu: 0, + priority: "-", + note: "-", + },{ + process: "", + processId: 1, + thread: "", + threadId: 1, + state: '', + dur: 0, + start_ts: 0, + end_ts: 0, + cpu: 0, + priority: "-", + note: "-", + },{ + process: "", + processId: 2, + thread: "", + threadId: 2, + state: '', + dur: 0, + start_ts: 0, + end_ts: 0, + cpu: 0, + priority: "-", + note: "-", + }] let dataArray = [{ id: "", @@ -56,4 +97,59 @@ describe('TabPanePTS Test', () => { let result = tabPanePTS.groupByThreadToMap(dataArray) expect(result.get(0).length).toBe(1); }); + + it('TabPanePTSTest05', function () { + let data = { + cpus: [], + threadIds: [], + trackIds: [], + funTids: [], + heapIds: [], + nativeMemory: [], + cpuAbilityIds: [], + memoryAbilityIds: [], + diskAbilityIds: [], + networkAbilityIds: [], + leftNs: 0, + rightNs: 0, + hasFps: false, + statisticsSelectData: undefined, + perfSampleIds: [], + perfCpus: [], + perfProcess: [], + perfThread: [], + perfAll: false, + } + let queryDataInCacheData = tabPanePTS.queryDataInCacheData(data); + expect(queryDataInCacheData.length).toBeUndefined() + }); + + it('TabPanePTSTest04', function () { + expect(tabPanePTS.initHtml()).toMatchInlineSnapshot(` +" + + + + + + + + + + + + + + + + + " +`); + }); }) diff --git a/host/ide/test/trace/component/trace/sheet/TabPaneSPT.test.ts b/host/ide/test/trace/component/trace/sheet/TabPaneSPT.test.ts index e6cdc3d1fc75a223c21db98f3c5717008e79b77d..4458262bc6775aa6e50c3bb32326f1dcf2ec04fe 100644 --- a/host/ide/test/trace/component/trace/sheet/TabPaneSPT.test.ts +++ b/host/ide/test/trace/component/trace/sheet/TabPaneSPT.test.ts @@ -15,14 +15,74 @@ // @ts-ignore import {TabPaneSPT} from "../../../../../dist/trace/component/trace/sheet/TabPaneSPT.js" +// @ts-ignore +import {SpSystemTrace} from "../../../../../dist/trace/component/SpSystemTrace.js"; + window.ResizeObserver = window.ResizeObserver || jest.fn().mockImplementation(() => ({ disconnect: jest.fn(), observe: jest.fn(), unobserve: jest.fn(), })); + describe('TabPaneSPT Test', () => { let tabPaneSPT = new TabPaneSPT(); + + SpSystemTrace.SPT_DATA = [{ + process: "", + processId: 0, + thread: "", + threadId: 0, + state: '', + dur: 0, + start_ts: 0, + end_ts: 0, + cpu: 0, + priority: "-", + note: "-", + },{ + process: "", + processId: 1, + thread: "", + threadId: 1, + state: '', + dur: 0, + start_ts: 0, + end_ts: 0, + cpu: 0, + priority: "-", + note: "-", + },{ + process: "", + processId: 2, + thread: "", + threadId: 2, + state: '', + dur: 0, + start_ts: 0, + end_ts: 0, + cpu: 0, + priority: "-", + note: "-", + }] + + let dataList = [{ + id: "", + pid: "", + title: "", + children: [], + process: "", + processId: 0, + thread: "", + threadId: 0, + state: "", + wallDuration: 0, + avgDuration: "", + count: 0, + minDuration: 0, + maxDuration: 0, + stdDuration: "", + }] let dataArray = [{ id: "", @@ -56,4 +116,59 @@ describe('TabPaneSPT Test', () => { let result = tabPaneSPT.groupByStateProcessToMap(dataArray) expect(result.get('').get(0).length).toBe(1); }); + + it('TabPaneSPTTest05', function () { + let data = { + cpus: [], + threadIds: [], + trackIds: [], + funTids: [], + heapIds: [], + nativeMemory: [], + cpuAbilityIds: [], + memoryAbilityIds: [], + diskAbilityIds: [], + networkAbilityIds: [], + leftNs: 0, + rightNs: 0, + hasFps: false, + statisticsSelectData: undefined, + perfSampleIds: [], + perfCpus: [], + perfProcess: [], + perfThread: [], + perfAll: false, + } + let queryDataInCacheData = tabPaneSPT.queryDataByCacheData(data); + expect(queryDataInCacheData.length).toBeUndefined() + }); + + it('TabPaneSPTTest04', function () { + expect(tabPaneSPT.initHtml()).toMatchInlineSnapshot(` +" + + + + + + + + + + + + + + + + + " +`); + }); }) diff --git a/host/ide/test/trace/component/trace/sheet/TabPaneSlices.test.ts b/host/ide/test/trace/component/trace/sheet/TabPaneSlices.test.ts index d00e3b5b9e5a65982037ec7fa77aae610f9be59a..17a3a054d092651789968f54abf46182759e4537 100644 --- a/host/ide/test/trace/component/trace/sheet/TabPaneSlices.test.ts +++ b/host/ide/test/trace/component/trace/sheet/TabPaneSlices.test.ts @@ -21,14 +21,20 @@ jest.mock("../../../../../dist/trace/database/SqlLite.js"); describe('TabPaneSlices Test', () => { let tabPaneSlices = new TabPaneSlices(); - tabPaneSlices.sortByColumn = jest.fn(()=> true) - it('TabPaneSlicesTest01', function () { expect(tabPaneSlices.sortByColumn({ key: 'name', sort: () => { } - })).toBeTruthy(); + })).toBeUndefined(); + }); + + it('TabPaneSlicesTest05', function () { + expect(tabPaneSlices.sortByColumn({ + key: !'name', + sort: () => { + } + })).toBeUndefined(); }); it('TabPaneSlicesTest02', function () { @@ -51,4 +57,29 @@ describe('TabPaneSlices Test', () => { let a = {rightNs: 1, leftNs: 0, funTids: [11, 12, 13]} expect(tabPaneSlices.data = a).toBeTruthy(); }); + + it('TabPaneSlicesTest04', function () { + expect(tabPaneSlices.initHtml()).toMatchInlineSnapshot(` +" + + + + + + + + + + + + + " +`); + }); }) diff --git a/host/ide/test/trace/component/trace/sheet/TabPaneThreadStates.test.ts b/host/ide/test/trace/component/trace/sheet/TabPaneThreadStates.test.ts index e2dcc099a1cc0b51909d5da77044a3f024601246..53abf08cdd9ea59b169428e9d10dff29c3fe1bb1 100644 --- a/host/ide/test/trace/component/trace/sheet/TabPaneThreadStates.test.ts +++ b/host/ide/test/trace/component/trace/sheet/TabPaneThreadStates.test.ts @@ -21,14 +21,20 @@ jest.mock("../../../../../dist/trace/database/SqlLite.js"); describe('TabPaneThreadStates Test', () => { let tabPaneThreadStates = new TabPaneThreadStates(); - tabPaneThreadStates.sortByColumn = jest.fn(() => true) - it('TabPaneThreadStatesTest01', function () { expect(tabPaneThreadStates.sortByColumn({ - key: 'name', + key: 'name' || "thread" || "state", + sort: () => { + } + })).toBeUndefined(); + }); + + it('TabPaneThreadStatesTest05', function () { + expect(tabPaneThreadStates.sortByColumn({ + key: !'name' || ! "thread" || !"state", sort: () => { } - })).toBeTruthy(); + })).toBeUndefined(); }); @@ -61,4 +67,40 @@ describe('TabPaneThreadStates Test', () => { let a = {rightNs: 1, leftNs: 0, threadIds: [11, 12, 13]} expect(tabPaneThreadStates.data = a).toBeTruthy(); }); + + it('TabPaneThreadStatesTest04', function () { + expect(tabPaneThreadStates.initHtml()).toMatchInlineSnapshot(` +" + +
+ + +
+ + + + + + + + + + + + + + + + + + + " +`); + }); }) diff --git a/host/ide/test/trace/component/trace/sheet/TabPaneThreadSwitch.test.ts b/host/ide/test/trace/component/trace/sheet/TabPaneThreadSwitch.test.ts index cd1fce51cad6516ad122f5e263728871d066dbfa..b7dc5b11bcada66c14efd0fb6b1c9d8ac756d6d1 100644 --- a/host/ide/test/trace/component/trace/sheet/TabPaneThreadSwitch.test.ts +++ b/host/ide/test/trace/component/trace/sheet/TabPaneThreadSwitch.test.ts @@ -15,12 +15,14 @@ // @ts-ignore import {TabPaneThreadSwitch} from "../../../../../dist/trace/component/trace/sheet/TabPaneThreadSwitch.js" + window.ResizeObserver = window.ResizeObserver || jest.fn().mockImplementation(() => ({ disconnect: jest.fn(), observe: jest.fn(), unobserve: jest.fn(), })); + describe('TabPaneContextSwitch Test', () => { let tabPaneThreadSwitch = new TabPaneThreadSwitch(); let dataArray = [{ @@ -40,11 +42,12 @@ describe('TabPaneContextSwitch Test', () => { maxDuration: 0, stdDuration: "", }] -let val={ - leftNs:1, - rightNs:1, -} + let val={ + leftNs:1, + rightNs:1, + } + it('TabPaneThreadSwitchTest01', function () { let result = tabPaneThreadSwitch.groupByStateToMap(dataArray); expect(result.get('').length).toBe(1); @@ -60,14 +63,36 @@ let val={ expect(result.get('').get(0).length).toBe(1); }); + it('TabPaneThreadSwitchTest04', function () { - expect(tabPaneThreadSwitch.data).toBeUndefined(); + document.body.innerHTML = `` + let tabPaneThreadSwitch = document.querySelector('#ThreadSwitch') as TabPaneThreadSwitch + tabPaneThreadSwitch.data = false + expect(tabPaneThreadSwitch.data).toBeFalsy(); }); - it('TabPaneThreadSwitchTest05', function () { - expect(tabPaneThreadSwitch.queryDataByCacheData(val)).toBeUndefined(); + it('TabPaneThreadSwitchTest06', function () { + expect(tabPaneThreadSwitch.initElements()).toBeUndefined(); }); - - + it('TabPaneThreadSwitchTest07', function () { + expect(tabPaneThreadSwitch.initHtml()).toMatchInlineSnapshot(` +" + + + + + + + + + " +`); + }); }) diff --git a/host/ide/test/trace/component/trace/sheet/TabPerfProfile.test.ts b/host/ide/test/trace/component/trace/sheet/TabPerfProfile.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..f8da759aa02fdcf81ed23f975986ca98e63a40fa --- /dev/null +++ b/host/ide/test/trace/component/trace/sheet/TabPerfProfile.test.ts @@ -0,0 +1,63 @@ +/* + * 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. + */ +//@ts-ignore +import {TabpanePerfProfile} from "../../../../../dist/trace/component/trace/sheet/TabPerfProfile.js" +//@ts-ignore +import {perfDataQuery} from "../../../../../dist/trace/component/hiperf/PerfDataQuery.js"; + +window.ResizeObserver = window.ResizeObserver || + jest.fn().mockImplementation(() => ({ + disconnect: jest.fn(), + observe: jest.fn(), + unobserve: jest.fn(), + })); + +describe('TabPerfProfile Test', () => { + + document.body.innerHTML = `` + let tabpanePerfProfile = document.querySelector('#perfprofile') as TabpanePerfProfile + + it('TabpanePerfProfileTest01 ', function () { + TabpanePerfProfile.getParentTree = jest.fn(()=>true) + expect(tabpanePerfProfile.getParentTree([],{},[])).not.toBeUndefined(); + }); + + it('TabpanePerfProfileTest02 ', function () { + expect(tabpanePerfProfile.getChildTree([],"1",[])).not.toBeUndefined(); + }); + + it('TabpanePerfProfileTest03 ', function () { + let call = { + id:"1", + dur:1, + children:[] + } + expect(tabpanePerfProfile.setRightTableData(call)).toBeUndefined(); + }); + + it('TabpanePerfProfileTest04 ', function () { + expect(tabpanePerfProfile.filterSampleIds(true,"1","112")).not.toBeUndefined(); + }); + + it('TabpanePerfProfileTest05 ', function () { + expect(tabpanePerfProfile.hideSystemLibrary()).toBeUndefined(); + }); + + it('TabpanePerfProfileTest06 ', function () { + let startNum = 1 + let endNum = "∞" + expect(tabpanePerfProfile.hideNumMaxAndMin(startNum,endNum)).toBeUndefined(); + }); +}) \ No newline at end of file diff --git a/host/ide/test/trace/component/trace/timer-shaft/Flag.test.ts b/host/ide/test/trace/component/trace/timer-shaft/Flag.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..965a7d64ce7905eee8366a86bd0a8f47a9958803 --- /dev/null +++ b/host/ide/test/trace/component/trace/timer-shaft/Flag.test.ts @@ -0,0 +1,24 @@ +/* + * 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. + */ +// @ts-ignore +import {Flag} from "../../../../../dist/trace/component/trace/timer-shaft/Flag.js"; + +describe('Flag Test',()=>{ + + it('FlagTest01 ', function () { + let flag = new Flag(); + expect(flag).not.toBeUndefined(); + }); +}) diff --git a/host/ide/test/trace/component/trace/timer-shaft/Graph.test.ts b/host/ide/test/trace/component/trace/timer-shaft/Graph.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..0e6422c8e9d6c36fef42f1955eb284b6ce14ee93 --- /dev/null +++ b/host/ide/test/trace/component/trace/timer-shaft/Graph.test.ts @@ -0,0 +1,24 @@ +/* + * 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. + */ +// @ts-ignore +import {Graph} from "../../../../../dist/trace/component/trace/timer-shaft/Graph.js"; + +describe('Flag Test',()=>{ + + it('FlagTest01 ', function () { + let graph = new Graph(); + expect(graph).not.toBeUndefined(); + }); +}) diff --git a/host/ide/test/trace/component/trace/timer-shaft/RangeRuler.test.ts b/host/ide/test/trace/component/trace/timer-shaft/RangeRuler.test.ts index 99775c99538cd8e4f44aab9dc3baca4773796fcb..d2fbb9eb932e3e7b840357edd8aef018889b8537 100644 --- a/host/ide/test/trace/component/trace/timer-shaft/RangeRuler.test.ts +++ b/host/ide/test/trace/component/trace/timer-shaft/RangeRuler.test.ts @@ -17,14 +17,19 @@ import {RangeRuler} from "../../../../../dist/trace/component/trace/timer-shaft/RangeRuler.js" // @ts-ignore import {Mark} from "../../../../../dist/trace/component/trace/timer-shaft/RangeRuler.js"; +import {TimerShaftElement} from "../../../../../src/trace/component/trace/TimerShaftElement"; -describe('RangeRuler Test', ()=>{ +describe('RangeRuler Test', () => { const canvas = document.createElement('canvas'); canvas.width = 1; canvas.height = 1; const ctx = canvas.getContext('2d'); - let rangeRuler = new RangeRuler(canvas , ctx, { + document.body.innerHTML = '' + + let timerShaftElement = document.querySelector('#timerShaftEL') as TimerShaftElement; + + let rangeRuler = new RangeRuler(timerShaftElement, { x: 20, y: 20, width: 100, @@ -32,8 +37,9 @@ describe('RangeRuler Test', ()=>{ }, { startX: 10, endX: 30 + }, () => { }); - let mark = new Mark(canvas , ctx, '', { + let mark = new Mark(canvas, ctx, '', { x: 20, y: 20, width: 100, @@ -56,7 +62,33 @@ describe('RangeRuler Test', ()=>{ expect(rangeRuler.fillX()).toBeUndefined(); }); + it('RangeRulerTest21', function () { + rangeRuler.range.startNS =-1 + expect(rangeRuler.fillX()).toBe(undefined); + }); + + it('RangeRulerTest22', function () { + rangeRuler.range.endNS =-1 + expect(rangeRuler.fillX()).toBe(undefined); + }); + + it('RangeRulerTest23', function () { + rangeRuler.range.endNS =-1; + rangeRuler.range.totalNS =-2 + expect(rangeRuler.fillX()).toBe(undefined); + }); + + it('RangeRulerTest24', function () { + rangeRuler.range.startNS =-1; + rangeRuler.range.totalNS =-2 + expect(rangeRuler.fillX()).toBe(undefined); + }); + it('RangeRulerTest03', function () { + // window.requestAnimationFrame = window.requestAnimationFrame || + // jest.fn().mockImplementation(() => ({ + // + // })); expect(rangeRuler.keyPress({ key: 'w' })).toBeUndefined(); @@ -117,20 +149,20 @@ describe('RangeRuler Test', ()=>{ }); it('RangeRulerTest13', function () { - rangeRuler.markA = jest.fn(()=>true) - rangeRuler.rangeRect = jest.fn(()=>true) - rangeRuler.rangeRect.containsWithPadding = jest.fn(()=>true) + rangeRuler.markA = jest.fn(() => true) + rangeRuler.rangeRect = jest.fn(() => true) + rangeRuler.rangeRect.containsWithPadding = jest.fn(() => true) - rangeRuler.markA = jest.fn(()=> { + rangeRuler.markA = jest.fn(() => { return { frame: { x: 20 } } }) - rangeRuler.markA.isHover = jest.fn(()=> true) - rangeRuler.markA.frame = jest.fn(()=> []) - rangeRuler.markA.frame.x = jest.fn(()=>true) + rangeRuler.markA.isHover = jest.fn(() => true) + rangeRuler.markA.frame = jest.fn(() => []) + rangeRuler.markA.frame.x = jest.fn(() => true) expect(rangeRuler.mouseDown({ key: '' @@ -138,62 +170,75 @@ describe('RangeRuler Test', ()=>{ }); it('RangeRulerTest14', function () { - rangeRuler.markA = jest.fn(()=>true) - rangeRuler.rangeRect = jest.fn(()=>true) - rangeRuler.rangeRect.containsWithPadding = jest.fn(()=>false) - rangeRuler.frame = jest.fn(()=>false) - rangeRuler.frame.containsWithMargin = jest.fn(()=> true) - rangeRuler.rangeRect.containsWithMargin = jest.fn(()=> false) - rangeRuler.markB.isHover = jest.fn(()=> true) - rangeRuler.markB.frame = jest.fn(()=> true) - rangeRuler.markB.frame.x = jest.fn(()=>true) + rangeRuler.markA = jest.fn(() => true) + rangeRuler.rangeRect = jest.fn(() => true) + rangeRuler.rangeRect.containsWithPadding = jest.fn(() => false) + rangeRuler.frame = jest.fn(() => false) + rangeRuler.frame.containsWithMargin = jest.fn(() => true) + rangeRuler.rangeRect.containsWithMargin = jest.fn(() => false) + rangeRuler.markB.isHover = jest.fn(() => true) + rangeRuler.markB.frame = jest.fn(() => true) + rangeRuler.markB.frame.x = jest.fn(() => true) expect(rangeRuler.mouseDown({ key: '' })).toBeUndefined(); }); it('RangeRulerTest15', function () { - rangeRuler.markA = jest.fn(()=>true) - rangeRuler.markA.inspectionFrame = jest.fn(()=>true) - rangeRuler.markA.inspectionFrame.contains = jest.fn(()=>true) - rangeRuler.markA.frame = jest.fn(()=> true) - rangeRuler.markA.frame.x = jest.fn(()=>true) - rangeRuler.markA.draw = jest.fn(()=>true) + rangeRuler.markA = jest.fn(() => true) + rangeRuler.markA.inspectionFrame = jest.fn(() => true) + rangeRuler.markA.inspectionFrame.contains = jest.fn(() => true) + rangeRuler.markA.frame = jest.fn(() => true) + rangeRuler.markA.frame.x = jest.fn(() => true) + rangeRuler.markA.draw = jest.fn(() => true) + rangeRuler.centerXPercentage = jest.fn(() => -1) expect(rangeRuler.mouseMove({ key: '' })).toBeUndefined(); }); - it('RangeRulerTest16', ()=> { - rangeRuler.markA = jest.fn(()=>false) - rangeRuler.markA.draw = jest.fn(()=>true) - rangeRuler.markA.frame = jest.fn(()=> true) - rangeRuler.markA.frame.x = jest.fn(()=>true) - rangeRuler.markA.inspectionFrame = jest.fn(()=>false) - rangeRuler.markA.inspectionFrame.contains = jest.fn(()=>false) - rangeRuler.movingMark = jest.fn(()=>false) - rangeRuler.movingMark.frame = jest.fn(()=> false) - rangeRuler.movingMark.frame.x = jest.fn(()=>false) - rangeRuler.rangeRect = jest.fn(()=>true) - rangeRuler.rangeRect.containsWithPadding = jest.fn(()=>true) - rangeRuler.movingMark.inspectionFrame = jest.fn(()=>false) - rangeRuler.movingMark.inspectionFrame.x = jest.fn(()=>false) + it('RangeRulerTest16', () => { + rangeRuler.markA = jest.fn(() => false) + rangeRuler.markA.draw = jest.fn(() => true) + rangeRuler.markA.frame = jest.fn(() => true) + rangeRuler.markA.frame.x = jest.fn(() => true) + rangeRuler.markA.inspectionFrame = jest.fn(() => false) + rangeRuler.markA.inspectionFrame.contains = jest.fn(() => false) + rangeRuler.movingMark = jest.fn(() => false) + rangeRuler.movingMark.frame = jest.fn(() => false) + rangeRuler.movingMark.frame.x = jest.fn(() => false) + rangeRuler.rangeRect = jest.fn(() => true) + rangeRuler.rangeRect.containsWithPadding = jest.fn(() => true) + rangeRuler.movingMark.inspectionFrame = jest.fn(() => false) + rangeRuler.movingMark.inspectionFrame.x = jest.fn(() => false) expect(rangeRuler.mouseMove({ key: '' })).toBeUndefined(); }); - it('RangeRulerTest17', ()=> { - rangeRuler.notifyHandler = jest.fn(()=>true) - rangeRuler.movingMark.inspectionFrame.x = jest.fn(()=>false) - rangeRuler.c = jest.fn(()=>true) - rangeRuler.frame = jest.fn(()=>true) - rangeRuler.frame.x = jest.fn(()=>true) - rangeRuler.frame.y = jest.fn(()=>true) - rangeRuler.c.clearRect = jest.fn(()=>true) + + it('RangeRulerTest17', () => { + rangeRuler.notifyHandler = jest.fn(() => true) + rangeRuler.movingMark.inspectionFrame.x = jest.fn(() => false) + // rangeRuler.c = jest.fn(()=>true) + // rangeRuler.c.clearRect = jest.fn(()=>true) + rangeRuler.frame = jest.fn(() => true) + rangeRuler.frame.x = jest.fn(() => true) + rangeRuler.frame.y = jest.fn(() => true) expect(rangeRuler.draw()).toBeUndefined(); }); it('RangeRulerTest18', function () { expect(mark.isHover).toBeTruthy(); }); + it('RangeRulerTest19', function () { + rangeRuler.clearRect = jest.fn(() => true) + expect(rangeRuler.draw()).toBeUndefined(); + + }) + + it('RangeRulerTest20', function () { + rangeRuler.setRangeNS(0, 2000) + expect(rangeRuler.getRange().startX).toBe(0) + + }) }) diff --git a/host/ide/test/trace/component/trace/timer-shaft/SportRuler.test.ts b/host/ide/test/trace/component/trace/timer-shaft/SportRuler.test.ts index 41d3e8338cfab12b07b2b86f45ff640415871dcd..3a9f48d35a1e122649e182b66af42b12851c0c9a 100644 --- a/host/ide/test/trace/component/trace/timer-shaft/SportRuler.test.ts +++ b/host/ide/test/trace/component/trace/timer-shaft/SportRuler.test.ts @@ -15,18 +15,30 @@ // @ts-ignore import {SportRuler} from "../../../../../dist/trace/component/trace/timer-shaft/SportRuler.js" +// @ts-ignore +import {TimerShaftElement} from "../../../../../dist/trace/component/trace/TimerShaftElement.js"; +// @ts-ignore +import {Flag} from "../../../../../dist/trace/component/trace/timer-shaft/Flag.js"; +// @ts-ignore +import {TraceRow, RangeSelectStruct} from "../../../../../dist/trace/component/trace/base/TraceRow.js"; -describe('SportRuler Test', ()=>{ +describe('SportRuler Test', () => { const canvas = document.createElement('canvas'); canvas.width = 1; canvas.height = 1; const ctx = canvas.getContext('2d'); - let sportRuler = new SportRuler(canvas, ctx, { + document.body.innerHTML = '' + + let timerShaftElement = document.querySelector('#timerShaftEL') as TimerShaftElement; + + let sportRuler = new SportRuler(timerShaftElement, { x: 20, y: 20, width: 100, height: 100, + }, () => { + }, () => { }); sportRuler.range = { @@ -39,29 +51,6 @@ describe('SportRuler Test', ()=>{ xsTxt: [], } - it('SportRulerTest01', function () { - expect(sportRuler.drawTheFlag(2, '#999999', false, 'text')).toBeUndefined(); - }); - - it('SportRulerTest02', function () { - let randomRgbColor = sportRuler.randomRgbColor(); - let isColor = randomRgbColor.length > 4; - expect(isColor).toBeTruthy() - }); - - it('SportRulerTest03', function () { - expect(sportRuler.onFlagRangeEvent({ - x: 0, - y: 0, - width: 0, - height: 0, - time: 0, - color: "", - selected: false, - text: "", - }, 2)).toBeUndefined(); - }); - it('SportRulerTest04', function () { expect(sportRuler.mouseMove({ offsetY: 20, @@ -74,31 +63,219 @@ describe('SportRuler Test', ()=>{ expect(ranges.endNS).toBe(20); }) - it('SportRulerTest06', function () { - sportRuler.flagListIdx = jest.fn(()=>"flagListIdx") - sportRuler.flagList = jest.fn(()=>true) - expect(sportRuler.modifyFlagList('amend', {})).toBeUndefined(); - }) + // it('SportRulerTest06', function () { + // sportRuler.flagListIdx = jest.fn(() => "flagListIdx") + // sportRuler.flagList = jest.fn(() => true) + // expect(sportRuler.modifyFlagList('amend', {})).toBeUndefined(); + // }) it('SportRulerTest07', function () { - sportRuler.flagList.splice = jest.fn(()=>true) - expect(sportRuler.modifyFlagList('remove', {})).toBeUndefined(); + sportRuler.flagList.splice = jest.fn(() => true) + expect(sportRuler.modifyFlagList('remove')).toBeUndefined(); }) it('SportRulerTest08', function () { + let numbers = Array(); + numbers.push(12) + numbers.push(56) + sportRuler.flagList = [{ + totalNS: 10000, + startX: 0, + endX: 1000, + startNS: 0, + endNS: 10000, + xs: numbers, + xsTxt: ['s', 'f'] + }] + sportRuler.flagList.xs = jest.fn(()=> numbers) + let flags = new Array() + flags.push({ + x: 0, + y: 0, + width: 0, + height: 0, + time: 20, + color: "", + selected: false, + text: "", + hidden: false, + type: "", + }) + sportRuler.flagList = flags; + + let rangeSelectStruct = new RangeSelectStruct(); + rangeSelectStruct.startNS = 20 + rangeSelectStruct.endX = 1000 + rangeSelectStruct.startNS = 20 + rangeSelectStruct.endNS = 200 + // TraceRow.rangeSelectObject = rangeSelectStruct expect(sportRuler.draw()).toBeUndefined(); }) it('SportRulerTest09', function () { - expect(sportRuler.mouseUp()).toBeUndefined(); + let flags = new Array() + flags.push({ + x: 0, + y: 0, + width: 0, + height: 0, + time: 20, + color: "", + selected: false, + text: "", + hidden: false, + type: "", + }) + sportRuler.flagList = flags; + sportRuler.edgeDetection = jest.fn(()=> true) + + expect(sportRuler.mouseUp({offsetX: 20})).toBeUndefined(); }) it('SportRulerTest10', function () { - sportRuler.draw = jest.fn(()=>true) + sportRuler.draw = jest.fn(() => true) expect(sportRuler.mouseMove({ offsetX: 10000, offsetY: 10000 })).toBeUndefined(); }); + it('SportRulerTest11', function () { + let range = sportRuler.range; + expect(sportRuler.range.endNS).toBe(20) + }) + + it('SportRulerTest12', function () { + let flags = new Array() + flags.push({ + x: 0, + y: 0, + width: 0, + height: 0, + time: 0, + color: "", + selected: false, + text: "", + hidden: false, + type: "", + }) + sportRuler.flagList = flags; + sportRuler.drawTriangle(1000, 'triangle'); + // expect(sportRuler.range()).toBeUndefined(); + }) + + it('SportRulerTest13', function () { + let flags = new Array() + flags.push({ + x: 0, + y: 0, + width: 0, + height: 0, + time: 1000, + color: "", + selected: false, + text: "", + hidden: false, + type: "triangle", + }) + sportRuler.flagList = flags; + sportRuler.drawTriangle(1000, 'triangle'); + // expect(sportRuler.range()).toBeUndefined(); + }) + + it('SportRulerTest14', function () { + let flags = new Array() + flags.push({ + x: 0, + y: 0, + width: 0, + height: 0, + time: 0, + color: "", + selected: false, + text: "", + hidden: false, + type: "triangle", + }) + sportRuler.flagList = flags; + sportRuler.drawTriangle(1000, 'square'); + // expect(sportRuler.range()).toBeUndefined(); + }) + + it('SportRulerTest22', function () { + let flags = new Array() + flags.push({ + x: 0, + y: 0, + width: 0, + height: 0, + time: 0, + color: "", + selected: false, + text: "", + hidden: false, + type: "triangle", + }) + sportRuler.flagList = flags; + sportRuler.drawTriangle(1000, 'inverted'); + + }) + + // it('SportRulerTest15', function () { + // sportRuler.flagList.findIndex = jest.fn(() => 0) + // sportRuler.drawTriangle(1000, 'square') + // expect(sportRuler.range()).toBeUndefined(); + // }) + + // it('SportRulerTest16', function () { + // sportRuler.flagList.findIndex = jest.fn(() => -1) + // sportRuler.drawTriangle(1000, 'inverted') + // expect(sportRuler.range()).toBeUndefined(); + // }) + + it('SportRulerTest17', function () { + sportRuler.removeTriangle('inverted') + // expect(sportRuler.range()).toBeUndefined(); + }) + + it('SportRulerTest18', function () { + sportRuler.flagList.findIndex = jest.fn(() => 0) + sportRuler.removeTriangle('square') + // expect(sportRuler.range()).toBeUndefined(); + }) + + it('SportRulerTest19', function () { + sportRuler.drawInvertedTriangle(100, '#000000') + // expect(sportRuler.range()).toBeUndefined(); + }) + + it('SportRulerTest20', function () { + sportRuler.drawFlag(100, '#000000', false, 'text', '') + // expect(sportRuler.range()).toBeUndefined(); + }) + + it('SportRulerTest23', function () { + sportRuler.drawFlag(100, '#000000', false, 'text', 'triangle') + }) + + it('SportRulerTest21', function () { + let flags = new Array() + flags.push({ + x: 0, + y: 0, + width: 0, + height: 0, + time: 20, + color: "", + selected: false, + text: "", + hidden: false, + type: "", + }) + sportRuler.flagList = flags; + sportRuler.flagList.find = jest.fn(()=> false) + expect(sportRuler.mouseUp({offsetX: 20})).toBeUndefined(); + }) + + }) diff --git a/host/ide/test/trace/component/trace/timer-shaft/TabPaneFlag.test.ts b/host/ide/test/trace/component/trace/timer-shaft/TabPaneFlag.test.ts index 88198fa1f5bb856f9a54d18c55be597b1af29b7f..31483b8595039e62530c365c25d44e6a7a82ffe5 100644 --- a/host/ide/test/trace/component/trace/timer-shaft/TabPaneFlag.test.ts +++ b/host/ide/test/trace/component/trace/timer-shaft/TabPaneFlag.test.ts @@ -21,23 +21,22 @@ describe('TabPaneFlag Test', ()=>{ canvas.width = 1; canvas.height = 1; const ctx = canvas.getContext('2d'); - - let tabPaneFlag = new TabPaneFlag(canvas , ctx, { - x: 20, - y: 20, - width: 100, - height: 100 - }, 10000000000); + let tabPaneFlag = new TabPaneFlag() it('TabPaneFlagTest01', function () { + document.body.innerHTML = ' ' + tabPaneFlag = document.querySelector('#remove-flag') as TabPaneFlag; + let htmlButtonElement = document.createElement('button') as HTMLButtonElement; + document.body.appendChild(htmlButtonElement) + htmlButtonElement.dispatchEvent(new Event('click')) expect(tabPaneFlag.initElements()).toBeUndefined(); }); - it('TabPaneFlagTest01', function () { + it('TabPaneFlagTest02', function () { expect(tabPaneFlag.initHtml()).not.toBe('') }); - it('TabPaneFlagTest01', function () { + it('TabPaneFlagTest03', function () { expect(tabPaneFlag.setFlagObj({ x: 0, y: 0, @@ -47,6 +46,57 @@ describe('TabPaneFlag Test', ()=>{ color: "", selected: false, text: "", - }, 5)).toBeUndefined(); + })).toBeUndefined(); + }); + + it('TabPaneFlagTest04', function () { + expect(tabPaneFlag.initHtml()).toMatchInlineSnapshot(` +" + +
+
Annotation at
+ + Change color: + +
+ " +`); }); }) diff --git a/host/ide/test/trace/component/trace/timer-shaft/TimeRuler.test.ts b/host/ide/test/trace/component/trace/timer-shaft/TimeRuler.test.ts index cb3ae26ea93cedbc8bbf821b0757d47c2bf1d080..f9105019985fea08064b60a0dbf150f48adfa961 100644 --- a/host/ide/test/trace/component/trace/timer-shaft/TimeRuler.test.ts +++ b/host/ide/test/trace/component/trace/timer-shaft/TimeRuler.test.ts @@ -15,14 +15,19 @@ // @ts-ignore import {TimeRuler} from "../../../../../dist/trace/component/trace/timer-shaft/TimeRuler.js" +// @ts-ignore +import {TimerShaftElement} from "../../../../../dist/trace/component/trace/TimerShaftElement.js"; describe('TimeRuler Test', ()=>{ const canvas = document.createElement('canvas'); canvas.width = 1; canvas.height = 1; const ctx = canvas.getContext('2d'); + document.body.innerHTML = '' + + let timerShaftElement = document.querySelector('#timerShaftEL') as TimerShaftElement; - let timeRuler = new TimeRuler(canvas , ctx, { + let timeRuler = new TimeRuler(timerShaftElement ,{ x: 20, y: 20, width: 100, diff --git a/host/ide/test/trace/database/Procedure.test.ts b/host/ide/test/trace/database/Procedure.test.ts index c3cb4c95993cfc4840c0068f96a92307c1897c4c..d2d46e1169b6d351c61c14f49403b6a00c30585f 100644 --- a/host/ide/test/trace/database/Procedure.test.ts +++ b/host/ide/test/trace/database/Procedure.test.ts @@ -13,12 +13,16 @@ * limitations under the License. */ // @ts-ignore -import {procedurePool} from "../../../dist/trace/database/Procedure.js" +import {procedurePool,ProcedureThread} from "../../../dist/trace/database/Procedure.js" describe('procedure Test', () => { - // let procedure = new procedurePool(); + + it('ProfilerClientTest02', function () { + expect(procedurePool.isIdle()).not.toBeUndefined(); + }); + it('ProfilerClientTest01', function () { - expect(procedurePool.uuid).toBeUndefined(); + expect(procedurePool.submitWithName()).toBeUndefined(); }); - }) +}) diff --git a/host/ide/test/trace/database/ProcedureWorker.test.ts b/host/ide/test/trace/database/ProcedureWorker.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..aa116ac15a7c0e154cdb257bbff2713566ad553e --- /dev/null +++ b/host/ide/test/trace/database/ProcedureWorker.test.ts @@ -0,0 +1,52 @@ +/* + * 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. + */ + +// @ts-ignore +import {ProcedureWorker,drawSelection} from "../../../dist/trace/database/ProcedureWorker.js"; + +describe('ProcedureWorker Test', ()=>{ + + it('ProcedureWorkerTest01', function () { + const context = { + globalAlpha:0.5, + fillStyle:"#666666", + fillRect:'', + } + const params ={ + isRangeSelect:{}, + rangeSelectObject:{ + startX:"", + endX:"", + startNS:"", + endNS:"", + + }, + startNS:"", + endNS:"", + totalNS:1, + frame:{ + x:"", + y:"", + height:1, + width:1, + } + + } + let drawSelection = jest.fn(() => true) + // @ts-ignore + expect(drawSelection(context,params)).toBeTruthy(); + + }); +}) \ No newline at end of file diff --git a/host/ide/test/trace/database/ProcedureWorkerCPU.test.ts b/host/ide/test/trace/database/ProcedureWorkerCPU.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..d319e00c89aaf3333b1137a9fbb51c06dd639e27 --- /dev/null +++ b/host/ide/test/trace/database/ProcedureWorkerCPU.test.ts @@ -0,0 +1,95 @@ +/* + * 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. + */ + +// @ts-ignore +import {cpu, CpuStruct} from "../../../dist/trace/database/ProcedureWorkerCPU.js"; +// @ts-ignore +import {Rect} from "../../../dist/trace/component/trace/timer-shaft/Rect.js"; + +describe(' Test', () => { + const dataSource = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100 + }, + startNS: 200, + processId : '' + } + + it('CPUTest01', () => { + let dataList = new Array(); + dataList.push({startTime: 0, dur: 10, frame: {x:0, y:9, width:10, height:10}}) + dataList.push({startTime: 1, dur: 111}) + let rect = new Rect(0, 10, 10, 10); + cpu(dataList, new Set(), 1, 100254, 100254, rect) + }) + + it('CPUTest02', () => { + let dataList = new Array(); + dataList.push({startTime: 0, dur: 10, frame: {x:0, y:9, width:10, height:10}}) + dataList.push({startTime: 1, dur: 111, frame: {x:0, y:9, width:10, height:10}}) + let rect = new Rect(0, 10, 10, 10); + cpu(dataList, new Set(), 1, 100254, 100254, rect) + }) + + it('CPUTest03', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const data = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100 + }, + startNS: 200, + value: 50 + } + expect(CpuStruct.draw(ctx, data)).toBeUndefined() + }) + + it('CPUTest04', () => { + expect(CpuStruct.equals(new CpuStruct(),new CpuStruct())).toBeTruthy(); + }) + it('CPUTest06', () => { + expect(CpuStruct.equals([],dataSource)).toBeFalsy() + }) + + + it('CPUTest05', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const data = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100 + }, + startNS: 200, + value: 50 + } + expect(CpuStruct.draw(ctx, data)).toBeUndefined() + }) + +}); \ No newline at end of file diff --git a/host/ide/test/trace/database/ProcedureWorkerCommon.test.ts b/host/ide/test/trace/database/ProcedureWorkerCommon.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..824780794a22bc724a09b9810d398e01fbd5ff3c --- /dev/null +++ b/host/ide/test/trace/database/ProcedureWorkerCommon.test.ts @@ -0,0 +1,212 @@ +/* + * 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. + */ +// @ts-ignore +import { + ChartStruct, + ColorUtils, + drawFlagLine, + drawLines, + getFrameChartColor, + getHeatColor, + Point, + Rect, + ns2s + // @ts-ignore +} from "../../../dist/trace/database/ProcedureWorkerCommon.js" +// @ts-ignore +import {Flag} from "../../../dist/trace/database/ProcedureWorkerTimeline.js"; + +describe('ProcedureWorkerCommon Test', () => { + let rect = new Rect(); + + + it('ProcedureWorkerCommon01', function () { + expect(rect.contains(1, 2)).not.toBeUndefined(); + }); + + it('ProcedureWorkerCommon02', function () { + expect(rect.containsWithPadding()).not.toBeUndefined(); + }); + + it('ProcedureWorkerCommon03', function () { + let point = new Point(); + expect(point).not.toBeUndefined(); + }) + + + it('ProcedureWorkerCommon04', function () { + let rect = new Rect(); + expect(Rect.contains(rect, 1, 2)).toBe(false); + }) + + + it('ProcedureWorkerCommon05', function () { + let rect = new Rect(); + expect(Rect.containsWithPadding(rect, 1, 2, 1, 2)).toBe(false); + }) + + it('ProcedureWorkerCommon06', function () { + let rect = new Rect(); + expect(Rect.containsWithMargin(rect, 1, 2, 1, 2, 1, 1)).toBe(false); + }) + + + it('ProcedureWorkerCommon07', function () { + let rect = new Rect(); + let rect2 = new Rect(); + expect(Rect.intersect(rect, rect2)).toBe(false); + }) + + it('ProcedureWorkerCommon08', function () { + let rect = new Rect(); + expect(rect.containsWithMargin(1, 2, 3, 5, 4, 5)).toBe(false); + }) + + it('ProcedureWorkerCommon09', function () { + let rect = new Rect(); + expect(rect.containsWithPadding(1, 2, 3, 5)).toBe(false); + }) + + it('ProcedureWorkerCommon10', function () { + let rect = new Rect(); + let rect2 = new Rect(); + expect(rect.intersect(rect2)).toBe(false); + }) + + + it('ProcedureWorkerCommon011', function () { + expect(ColorUtils.formatNumberComma("11232")).toBe("11,232"); + }) + + it('ProcedureWorkerCommon012', function () { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + let aaa = [1, 2, 3] + drawLines(ctx, aaa, 1, "#ffff") + expect(ColorUtils.formatNumberComma("11232")).toBe("11,232"); + }) + + it('ProcedureWorkerCommon013', function () { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + let aaa = [1, 2, 3] + let flag = new Flag(1, 2, 3, 4, 5, "#FFF", false); + let rect2 = new Rect(); + drawFlagLine(ctx, aaa, flag, 1, 2, 2, rect2) + expect(ColorUtils.formatNumberComma("11232")).toBe("11,232"); + }) + + + it('ProcedureWorkerCommon014', function () { + expect(getHeatColor(1).b).toBe(100); + }) + + it('ProcedureWorkerCommon015', function () { + expect(getFrameChartColor(1,"").b).toBe(100); + }) + + it('ProcedureWorkerCommon016', function () { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + const Sourcedata = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100 + }, + percent: 200, + value: 50 + }; + // @ts-ignore + document.body.innerHTML = ` `; + expect(ChartStruct.draw(ctx,Sourcedata,1)).toBeUndefined() + }) + + it('ProcedureWorkerCommon017', function () { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + let rect2 = new Rect(); + let rect = new Rect(); + expect(ChartStruct.drawString(ctx,"111",1,rect)).toBe(false); + }) + + it('ProcedureWorkerCommon018', function () { + + expect(ChartStruct.isHover()).toBeTruthy() + }) + + it('ProcedureWorkerCommon019 ', function () { + const node = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + total: 50, + size: 50, + count: 50, + parent: { + children:[{ + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + }], + frame: { + x: 20, + y: 20, + width: 100, + height: 100, + }, + } + + } + let frame = new Rect(0, 10, 10, 10); + expect(ChartStruct.setFuncFrame(node,frame,1,)).toBeUndefined() + }); + + it('ProcedureWorkerCommon20', function () { + expect(ns2s(2_000_000_000)).toBe("2.0 s"); + }); + + it('ProcedureWorkerCommon21', function () { + expect(ns2s(2_000_000)).toBe("2.0 ms"); + }); + + it('ProcedureWorkerCommon22', function () { + expect(ns2s(2_000)).toBe("2.0 μs"); + }); + + it('ProcedureWorkerCommon23', function () { + expect(ns2s(1)).toBe("1.0 ns"); + }); + + it('ProcedureWorkerCommon24', function () { + expect(ns2s(-1)).toBe("-1.0 s"); + }); +}) + diff --git a/host/ide/test/trace/database/ProcedureWorkerCpuAbility.test.ts b/host/ide/test/trace/database/ProcedureWorkerCpuAbility.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..08b1a763724e5cb900ec24df1f6b7f4e08035e02 --- /dev/null +++ b/host/ide/test/trace/database/ProcedureWorkerCpuAbility.test.ts @@ -0,0 +1,60 @@ +/* + * 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. + */ +// @ts-ignore +import {CpuAbilityMonitorStruct,cpuAbility} from "../../../dist/trace/database/ProcedureWorkerCpuAbility.js"; +//@ts-ignore +import {Rect} from "../../../dist/trace/database/ProcedureWorkerCommon"; + +describe('CpuAbilityMonitorStruct Test', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const data = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100 + }, + startNS: 200, + value: 50 + } + + const Sourcedata = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100 + }, + maxCpuUtilization: 200, + value: 50 + } + it('CpuAbilityMonitorStructTest01', function () { + expect(CpuAbilityMonitorStruct.draw(ctx, data)).toBeUndefined() + }); + it('CpuAbilityMonitorStructTest03', function () { + expect(CpuAbilityMonitorStruct.draw(ctx, Sourcedata)).toBeUndefined() + }); + it('CpuAbilityMonitorStructTest02', function () { + let dataList = new Array(); + dataList.push({startNs: 0, dur: 10, frame: {x:0, y:9, width:10, height:10}}) + dataList.push({startNs: 1, dur: 111}) + cpuAbility(dataList, new Set(), 1, 100254, 100254, "") + }); + +}) \ No newline at end of file diff --git a/host/ide/test/trace/database/ProcedureWorkerDiskIoAbility.test.ts b/host/ide/test/trace/database/ProcedureWorkerDiskIoAbility.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..f33953561eb9aaf5468d02de3487d8b9bb63b2d7 --- /dev/null +++ b/host/ide/test/trace/database/ProcedureWorkerDiskIoAbility.test.ts @@ -0,0 +1,60 @@ +/* + * 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. + */ +// @ts-ignore +import {DiskAbilityMonitorStruct,diskIoAbility} from "../../../dist/trace/database/ProcedureWorkerDiskIoAbility.js"; +//@ts-ignore +import {Rect} from "../../../dist/trace/database/ProcedureWorkerCommon"; + +describe('ProcedureWorkerDiskIoAbility Test', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const data = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100 + }, + startNS: 200, + value: 50 + } + const Sourcedata = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100 + }, + maxDiskRate: 200, + value: 50 + } + + it('ProcedureWorkerDiskIoAbilityTest01', function () { + expect(DiskAbilityMonitorStruct.draw(ctx, data)).toBeUndefined() + }); + + it('ProcedureWorkerDiskIoAbilityTest03', function () { + expect(DiskAbilityMonitorStruct.draw(ctx, Sourcedata)).toBeUndefined() + }); + it('CpuAbilityMonitorStructTest02', function () { + let dataList = new Array(); + dataList.push({startNS: 0, dur: 10, frame: {x:0, y:9, width:10, height:10}}) + dataList.push({startNS: 1, dur: 111}) + diskIoAbility(dataList, new Set(), 1, 100254, 100254, "") + }); +}) \ No newline at end of file diff --git a/host/ide/test/trace/database/ProcedureWorkerFPS.test.ts b/host/ide/test/trace/database/ProcedureWorkerFPS.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..e5056976306c6bc36ca87434fbde8c5a1d916cef --- /dev/null +++ b/host/ide/test/trace/database/ProcedureWorkerFPS.test.ts @@ -0,0 +1,101 @@ +/* + * 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. + */ + +// @ts-ignore +import {fps, FpsStruct} from "../../../dist/trace/database/ProcedureWorkerFps.js"; +// @ts-ignore +import {Rect} from "../../../dist/trace/component/trace/timer-shaft/Rect.js"; + +describe(' FPSTest', () => { + + it('FpsTest01', () => { + let dataList = new Array(); + dataList.push({startTime: 0, dur: 10, frame: {x:0, y:9, width:10, height:10}}) + dataList.push({startTime: 1, dur: 111}) + let rect = new Rect(0, 10, 10, 10); + fps(dataList, new Set(), 1, 100254, 100254, rect) + }) + + it('FpsTest02', () => { + let dataList = new Array(); + dataList.push({startTime: 0, dur: 10, frame: {x:0, y:9, width:10, height:10}}) + dataList.push({startTime: 1, dur: 111, frame: {x:0, y:9, width:10, height:10}}) + let rect = new Rect(0, 10, 10, 10); + fps(dataList, new Set(), 1, 100254, 100254, rect) + }) + + it('FpsTest03', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const data = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100 + }, + startNS: 200, + value: 50 + } + + expect(FpsStruct.draw(ctx, data)).toBeUndefined() + }) + + + it('FpsTest04', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const data = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100 + }, + startNS: 200, + value: 50 + } + new FpsStruct(1); + FpsStruct.hoverFpsStruct = jest.fn(() => {startNS:200}) + FpsStruct.a = jest.fn(() => data); + expect(FpsStruct.draw(ctx, data)).toBeUndefined() + }) + it('FpsTest05 ', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + const Sourcedate = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100 + }, + maxFps: 200, + value: 50 + } + expect(FpsStruct.draw(ctx,Sourcedate)).toBeUndefined() + + + + }); +}); \ No newline at end of file diff --git a/host/ide/test/trace/database/ProcedureWorkerFreq.test.ts b/host/ide/test/trace/database/ProcedureWorkerFreq.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..8d7bdf648ca5d15d7844dab8220662e0741858dd --- /dev/null +++ b/host/ide/test/trace/database/ProcedureWorkerFreq.test.ts @@ -0,0 +1,76 @@ +/* + * 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. + */ + +// @ts-ignore +import {CpuFreqStruct, freq} from "../../../dist/trace/database/ProcedureWorkerFreq.js"; +// @ts-ignore +import {Rect} from "../../../dist/trace/component/trace/timer-shaft/Rect.js"; + +describe('freqTest', () => { + + it('freqTest01', () => { + let dataList = new Array(); + dataList.push({startTime: 0, dur: 10, frame: {x:0, y:9, width:10, height:10}}) + dataList.push({startTime: 1, dur: 111}) + let rect = new Rect(0, 10, 10, 10); + freq(dataList, new Set(), 1, 100254, 100254, rect) + }) + + it('freqTest02', () => { + let dataList = new Array(); + dataList.push({startTime: 0, dur: 10, frame: {x:0, y:9, width:10, height:10}}) + dataList.push({startTime: 1, dur: 111, frame: {x:0, y:9, width:10, height:10}}) + let rect = new Rect(0, 10, 10, 10); + freq(dataList, new Set(), 1, 100254, 100254, rect) + }) + + it('freqTest03', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const data = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100 + }, + startNS: 200, + value: 50 + } + + expect(CpuFreqStruct.draw(ctx, data)).toBeUndefined() + + }) + it('freqTest04', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + const Sourcedata = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100 + }, + maxFreq: 200, + value: 50 + } + expect(CpuFreqStruct.draw(ctx,Sourcedata)).toBeUndefined()}) + +}); \ No newline at end of file diff --git a/host/ide/test/trace/database/ProcedureWorkerFunc.test.ts b/host/ide/test/trace/database/ProcedureWorkerFunc.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..343691b506c9742e43deb517912a5fc7c678a5a8 --- /dev/null +++ b/host/ide/test/trace/database/ProcedureWorkerFunc.test.ts @@ -0,0 +1,81 @@ +/* + * 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. + */ + +// @ts-ignore +import {func, FuncStruct} from "../../../dist/trace/database/ProcedureWorkerFunc.js"; +// @ts-ignore +import {Rect} from "../../../dist/trace/component/trace/timer-shaft/Rect.js"; +import {markAsUntransferable} from "worker_threads"; + +describe(' FPSTest', () => { + + it('FuncTest01', () => { + let dataList = new Array(); + dataList.push({startTime: 0, dur: 10, frame: {x:0, y:9, width:10, height:10}}) + dataList.push({startTime: 1, dur: 111}) + let rect = new Rect(0, 10, 10, 10); + func(dataList, new Set(), 1, 100254, 100254, rect) + }) + + it('FuncTest02', () => { + let dataList = new Array(); + dataList.push({startTime: 0, dur: 10, frame: {x:0, y:9, width:10, height:10}}) + dataList.push({startTime: 1, dur: 111, frame: {x:0, y:9, width:10, height:10}}) + let rect = new Rect(0, 10, 10, 10); + func(dataList, new Set(), 1, 100254, 100254, rect) + }) + + it('FuncTest03', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const data = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100 + }, + startNS: 200, + value: 50, + dur:undefined || null || 0 + } + expect(FuncStruct.draw(ctx, data)).toBeUndefined() + }) + + + it('FuncTest04', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + FuncStruct.drawString(ctx, "1", 1,new Rect(0,0,100,100)); + }) + + it('FuncTest05', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + FuncStruct.drawString(ctx, "1", 2,new Rect(1,1,150,150)); + }); + + it('FuncTest06 ', function () { + let str = "" + expect(FuncStruct.getInt(str)).toBe(0); + }); +}); \ No newline at end of file diff --git a/host/ide/test/trace/database/ProcedureWorkerHeap.test.ts b/host/ide/test/trace/database/ProcedureWorkerHeap.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..71f59a86a1b5f42d9e1a31aed56b8f96946cdd37 --- /dev/null +++ b/host/ide/test/trace/database/ProcedureWorkerHeap.test.ts @@ -0,0 +1,75 @@ +/* + * 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. + */ + +// @ts-ignore +import {heap, HeapStruct} from "../../../dist/trace/database/ProcedureWorkerHeap.js"; +// @ts-ignore +import {Rect} from "../../../dist/trace/component/trace/timer-shaft/Rect.js"; + +describe(' Test', () => { + + it('HeapTest01', () => { + let dataList = new Array(); + dataList.push({startTime: 0, dur: 10, frame: {x:0, y:9, width:10, height:10}}) + dataList.push({startTime: 1, dur: 111}) + let rect = new Rect(0, 10, 10, 10); + heap(dataList, new Set(), 1, 100254, 100254, rect) + }) + + it('HeapTest02', () => { + let dataList = new Array(); + dataList.push({startTime: 0, dur: 10, frame: {x:0, y:9, width:10, height:10}}) + dataList.push({startTime: 1, dur: 111, frame: {x:0, y:9, width:10, height:10}}) + let rect = new Rect(0, 10, 10, 10); + heap(dataList, new Set(), 1, 100254, 100254, rect) + }) + + it('HeapTest03', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const data = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100 + }, + startNS: 200, + value: 50 + } + expect(HeapStruct.draw(ctx, data)).toBeUndefined() + }) + it('HeapTest04', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const data = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100 + }, + maxHeapSize: 200, + value: 50 + } + expect(HeapStruct.draw(ctx, data)).toBeUndefined() + }) +}); \ No newline at end of file diff --git a/host/ide/test/trace/database/ProcedureWorkerHiPerfCPU.test.ts b/host/ide/test/trace/database/ProcedureWorkerHiPerfCPU.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..701c9792611fe521884cd770228055bc86d707a0 --- /dev/null +++ b/host/ide/test/trace/database/ProcedureWorkerHiPerfCPU.test.ts @@ -0,0 +1,55 @@ +/* + * 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. + */ +//@ts-ignore +import {hiPerfCpu,HiPerfCpuStruct} from "../../../dist/trace/database/ProcedureWorkerHiPerfCPU.js"; + +describe('ProcedureWorkerHiPerfCPU Test', ()=>{ + + it('ProcedureWorkerHiPerfCPUTest01',()=>{ + const data = { + frame:undefined, + cpu:1, + startNs:1, + value:1, + } + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + expect(HiPerfCpuStruct.draw(ctx,'',data,true)).toBeUndefined(); + }); + + it('ProcedureWorkerHiPerfCPUTest02', function () { + let dataList = new Array(); + dataList.push({startNS: 0, dur: 10,length:1, frame: {x:0, y:9, width:10, height:10}}) + dataList.push({startNS: 1, dur: 2,length:1}) + hiPerfCpu(dataList, new Set(), 1, 8, 3, "",true) + }); + + it('ProcedureWorkerHiPerfCPUTest03', function () { + let dataList = new Array(); + dataList.push({startNS: 0, dur: 10,length:1, frame: {x:0, y:9, width:10, height:10}}) + dataList.push({startNS: 1, dur: 2,length:1}) + hiPerfCpu(dataList, new Set(), 1, 8, 3, "",false) + }); + + it('ProcedureWorkerHiPerfCPUTest04',()=>{ + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + expect(HiPerfCpuStruct.drawRoundRectPath(ctx,1,1,1,1,1)).toBeUndefined(); + }); +}) \ No newline at end of file diff --git a/host/ide/test/trace/database/ProcedureWorkerHiPerfProcess.test.ts b/host/ide/test/trace/database/ProcedureWorkerHiPerfProcess.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..d73a4c2807176e6a7a4920a36904aa44448f664b --- /dev/null +++ b/host/ide/test/trace/database/ProcedureWorkerHiPerfProcess.test.ts @@ -0,0 +1,47 @@ +/* + * 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. + */ +//@ts-ignore +import {hiPerfProcess,HiPerfProcessStruct} from "../../../dist/trace/database/ProcedureWorkerHiPerfProcess.js"; + +describe('ProcedureWorkerHiPerfCPU Test', ()=>{ + + it('ProcedureWorkerHiPerfCPUTest01',()=>{ + const data = { + frame:undefined, + cpu:1, + startNs:1, + value:1, + } + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + expect(HiPerfProcessStruct.draw(ctx,'',data,true)).toBeUndefined(); + }); + + it('ProcedureWorkerHiPerfCPUTest02', function () { + let dataList = new Array(); + dataList.push({startNS: 0, dur: 10,length:1, frame: {x:0, y:9, width:10, height:10}}) + dataList.push({startNS: 1, dur: 2,length:1}) + hiPerfProcess(dataList, new Set(), 1, 8, 3, "",true) + }); + + it('ProcedureWorkerHiPerfCPUTest03', function () { + let dataList = new Array(); + dataList.push({startNS: 0, dur: 10,length:1, frame: {x:0, y:9, width:10, height:10}}) + dataList.push({startNS: 1, dur: 2,length:1}) + hiPerfProcess(dataList, new Set(), 1, 8, 3, "",false) + }); +}) \ No newline at end of file diff --git a/host/ide/test/trace/database/ProcedureWorkerHiPerfThread.test.ts b/host/ide/test/trace/database/ProcedureWorkerHiPerfThread.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..25a34b3e57f859131529bc7e82162edd5041e2b0 --- /dev/null +++ b/host/ide/test/trace/database/ProcedureWorkerHiPerfThread.test.ts @@ -0,0 +1,47 @@ +/* + * 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. + */ +//@ts-ignore +import {hiPerfThread,HiPerfThreadStruct} from "../../../dist/trace/database/ProcedureWorkerHiPerfThread.js"; + +describe('ProcedureWorkerHiPerfCPU Test', ()=>{ + + it('ProcedureWorkerHiPerfCPUTest01',()=>{ + const data = { + frame:undefined, + cpu:1, + startNs:1, + value:1, + } + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + expect(HiPerfThreadStruct.draw(ctx,'',data,true)).toBeUndefined(); + }); + + it('ProcedureWorkerHiPerfCPUTest02', function () { + let dataList = new Array(); + dataList.push({startNS: 0, dur: 10,length:1, frame: {x:0, y:9, width:10, height:10}}) + dataList.push({startNS: 1, dur: 2,length:1}) + hiPerfThread(dataList, new Set(), 1, 8, 3, "",true) + }); + + it('ProcedureWorkerHiPerfCPUTest03', function () { + let dataList = new Array(); + dataList.push({startNS: 0, dur: 10,length:1, frame: {x:0, y:9, width:10, height:10}}) + dataList.push({startNS: 1, dur: 2,length:1}) + hiPerfThread(dataList, new Set(), 1, 8, 3, "",false) + }); +}) \ No newline at end of file diff --git a/host/ide/test/trace/database/ProcedureWorkerMem.test.ts b/host/ide/test/trace/database/ProcedureWorkerMem.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..90a12a854aa5b4f65d22dd589391b68af6049194 --- /dev/null +++ b/host/ide/test/trace/database/ProcedureWorkerMem.test.ts @@ -0,0 +1,63 @@ +/* + * 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. + */ + +// @ts-ignore +import {mem, ProcessMemStruct} from "../../../dist/trace/database/ProcedureWorkerMem.js"; +// @ts-ignore +import {Rect} from "../../../dist/trace/component/trace/timer-shaft/Rect.js"; + +describe(' Test', () => { + + it('MemTest01', () => { + let dataList = new Array(); + dataList.push({startTime: 0, duration: 10, frame: {x:0, y:9, width:10, height:10}}) + dataList.push({startTime: 1, duration: 111}) + let rect = new Rect(0, 10, 10, 10); + mem(dataList, new Set(), 1, 100254, 100256, rect) + }) + + it('MemTest02', () => { + let dataList = new Array(); + dataList.push({startTime: 0, duration: 10, frame: {x:0, y:9, width:10, height:10}}) + dataList.push({startTime: 1, duration: 111, frame: {x:0, y:9, width:10, height:10}}) + let rect = new Rect(0, 10, 10, 10); + mem(dataList, new Set(), 2, 100254, 100254, rect) + }) + + it('MemTest03', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const data = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100 + }, + startNS: 200, + value: 50 + } + expect(ProcessMemStruct.draw(ctx, data)).toBeUndefined() + }) + + + // it('MemTest03', () => { + // setMemFrame(dataList, new Set(), 1, 100254, 100254, rect) + // }) + +}); \ No newline at end of file diff --git a/host/ide/test/trace/database/ProcedureWorkerMemoryAbility.test.ts b/host/ide/test/trace/database/ProcedureWorkerMemoryAbility.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..bbb5c0bd67602581b3d67cd55ab8b66588baa5b4 --- /dev/null +++ b/host/ide/test/trace/database/ProcedureWorkerMemoryAbility.test.ts @@ -0,0 +1,45 @@ +/* + * 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. + */ +//@ts-ignore +import {memoryAbility,MemoryAbilityMonitorStruct} from "../../../dist/trace/database/ProcedureWorkerMemoryAbility.js"; + +describe('ProcedureWorkerMemoryAbility Test', ()=>{ + + it('ProcedureWorkerMemoryAbilityTest01',()=>{ + const data = { + frame:{ + width:10, + height:10, + x:1, + y:1, + }, + cpu:1, + startNs:1, + value:1, + } + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + expect(MemoryAbilityMonitorStruct.draw(ctx,data)).toBeUndefined(); + }); + + it('ProcedureWorkerMemoryAbilityTest02', function () { + let dataList = new Array(); + dataList.push({startNS: 0, dur: 10, frame: {x:0, y:9, width:10, height:10}}) + dataList.push({startNS: 1, dur: 2}) + memoryAbility(dataList, new Set(), 1, 8, 3, "") + }); +}) \ No newline at end of file diff --git a/host/ide/test/trace/database/ProcedureWorkerNetworkAbility.test.ts b/host/ide/test/trace/database/ProcedureWorkerNetworkAbility.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..58d1e886d2b01efedb9d49123ef19df3c4130335 --- /dev/null +++ b/host/ide/test/trace/database/ProcedureWorkerNetworkAbility.test.ts @@ -0,0 +1,45 @@ +/* + * 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. + */ +//@ts-ignore +import {NetworkAbilityMonitorStruct,networkAbility} from "../../../dist/trace/database/ProcedureWorkerNetworkAbility.js"; + +describe('ProcedureWorkerNetworkAbility Test', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const data = { + frame: { + x: 2, + y: 2, + width: 10, + height: 10 + }, + startNS: 21, + value: 5 + } + + it('ProcedureWorkerNetworkAbilityTest01', function () { + expect(NetworkAbilityMonitorStruct.draw(ctx, data)).toBeUndefined() + }); + + it('ProcedureWorkerNetworkAbilityTest02', function () { + let dataList = new Array(); + dataList.push({startNS: 0, dur: 10, frame: {x:0, y:9, width:10, height:10}}) + dataList.push({startNS: 1, dur: 1}) + networkAbility(dataList, new Set(), 1, 9, 2, "") + }); +}) \ No newline at end of file diff --git a/host/ide/test/trace/database/ProcedureWorkerProcess.test.ts b/host/ide/test/trace/database/ProcedureWorkerProcess.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..6a4db3a3f12f7cd6556a5e3308b190bec1560033 --- /dev/null +++ b/host/ide/test/trace/database/ProcedureWorkerProcess.test.ts @@ -0,0 +1,58 @@ +/* + * 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. + */ + +// @ts-ignore +import {proc, ProcessStruct} from "../../../dist/trace/database/ProcedureWorkerProcess.js"; +// @ts-ignore +import {Rect} from "../../../dist/trace/component/trace/timer-shaft/Rect.js"; + +describe(' ProcessTest', () => { + + it('ProcessTest01', () => { + let dataList = new Array(); + dataList.push({startTime: 0, dur: 10, frame: {x:0, y:9, width:10, height:10}}) + dataList.push({startTime: 1, dur: 111}) + let rect = new Rect(0, 10, 10, 10); + proc(dataList, new Set(), 1, 100254, 100254, rect) + }) + + it('ProcessTest02', () => { + let dataList = new Array(); + dataList.push({startTime: 0, dur: 10, frame: {x:0, y:9, width:10, height:10}}) + dataList.push({startTime: 1, dur: 111, frame: {x:0, y:9, width:10, height:10}}) + let rect = new Rect(0, 10, 10, 10); + proc(dataList, new Set(), 1, 100254, 100254, rect) + }) + + it('ProcessTest04', () => { + const node = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100 + }, + startNS: 200, + value: 50 + } + const frame = { + x: 20, + y: 20, + width: 100, + height: 100 + } + expect(ProcessStruct.setFrame(node, 1,1,1,frame)).toBeUndefined() + }) +}); \ No newline at end of file diff --git a/host/ide/test/trace/database/ProcedureWorkerThread.test.ts b/host/ide/test/trace/database/ProcedureWorkerThread.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..2ea8ea276390055ca59f3fa91246708f1152dc07 --- /dev/null +++ b/host/ide/test/trace/database/ProcedureWorkerThread.test.ts @@ -0,0 +1,175 @@ +/* + * 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. + */ + +// @ts-ignore +import {thread, ThreadStruct} from "../../../dist/trace/database/ProcedureWorkerThread.js"; +// @ts-ignore +import {Rect} from "../../../dist/trace/component/trace/timer-shaft/Rect.js"; + +describe(' ThreadTest', () => { + + it('ThreadTest01', () => { + let dataList = new Array(); + dataList.push({startTime: 0, dur: 10, frame: {x:0, y:9, width:10, height:10}}) + dataList.push({startTime: 1, dur: 111}) + let rect = new Rect(0, 10, 10, 10); + thread(dataList, new Set(), 1, 100254, 100254, rect) + }) + + it('ThreadTest02', () => { + let dataList = new Array(); + dataList.push({startTime: 0, dur: 10, frame: {x:0, y:9, width:10, height:10}}) + dataList.push({startTime: 1, dur: 111, frame: {x:0, y:9, width:10, height:10}}) + let rect = new Rect(0, 10, 10, 10); + thread(dataList, new Set(), 1, 100254, 100254, rect) + }) + + it('ThreadTest03', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const data = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100 + }, + startNS: 200, + value: 50 + } + expect(ThreadStruct.draw(ctx, data)).toBeUndefined() + }) + + it('ThreadTest04', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const data = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100 + }, + startNS: 200, + value: 50, + state:"S" + } + expect(ThreadStruct.draw(ctx, data)).toBeUndefined() + }) + + it('ThreadTest05', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const data = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100 + }, + startNS: 200, + value: 50, + state:"R" + } + expect(ThreadStruct.draw(ctx, data)).toBeUndefined() + }) + + it('ThreadTest06', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const data = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100 + }, + startNS: 200, + value: 50, + state:"D" + } + expect(ThreadStruct.draw(ctx, data)).toBeUndefined() + }) + + it('ThreadTest07', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const data = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100 + }, + startNS: 200, + value: 50, + state:"Running" + } + expect(ThreadStruct.draw(ctx, data)).toBeUndefined() + }) + + it('ThreadTest08', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + + const data = { + frame: { + x: 20, + y: 20, + width: 100, + height: 100 + }, + startNS: 200, + value: 50, + state:"T" + } + expect(ThreadStruct.draw(ctx, data)).toBeUndefined() + }) + + it('ThreadTest09', () => { + const d1 = { + cpu:1, + tid:1, + state:"", + startTime:1, + dur:1 + } + const d2 = { + cpu:1, + tid:1, + state:"", + startTime:1, + dur:1 + } + expect(ThreadStruct.equals(d1, d2)).toBeTruthy() + }) +}); \ No newline at end of file diff --git a/host/ide/test/trace/database/ProcedureWorkerTimeline.test.ts b/host/ide/test/trace/database/ProcedureWorkerTimeline.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..508220498f554a6f6b30251b06d426485fae9a95 --- /dev/null +++ b/host/ide/test/trace/database/ProcedureWorkerTimeline.test.ts @@ -0,0 +1,107 @@ +/* + * 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. + */ + +// @ts-ignore +import {RangeRuler, SportRuler, timeline} from "../../../dist/trace/database/ProcedureWorkerTimeline.js"; +// @ts-ignore +import {Rect} from "../../../dist/trace/component/trace/timer-shaft/Rect.js"; + +describe(' ProcedureWorkerTimelineTest', () => { + + it('timelineTest', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + let dataList = new Array(); + dataList.push({startTime: 0, dur: 10, frame: {x:0, y:9, width:10, height:10}}) + dataList.push({startTime: 1, dur: 111}) + let rect = new Rect(0, 10, 10, 10); + timeline(canvas, ctx, 1, 100254, 100254, rect, null, null, null, null,null,null,0,0,(e:any) => { + }) + }) + + + it('SportRulerTest01', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + let rect = new Rect(0, 10, 10, 10); + let sportRuler = new SportRuler(canvas,ctx,rect); + sportRuler.modifyFlagList("amend") + sportRuler.modifyFlagList("remove") + sportRuler.drawTheFlag(0,"#999999",false,!""); + sportRuler.randomRgbColor(); + sportRuler.mouseMove(new MouseEvent("")); + sportRuler.mouseUp(new MouseEvent("")); + sportRuler.onFlagRangeEvent('1',2); + }) + + it('SportRulerTest02', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + let rect = new Rect(0, 10, 10, 10); + let rangeRuler = new RangeRuler(canvas,ctx,rect,{ + startX: 0, + endX: rect.width, + startNS: 0, + endNS: 111, + totalNS: 111, + xs: [], + xsTxt: [] + },(a:any) =>{}); + rangeRuler.draw(); + rangeRuler.drawCpuUsage(); + rangeRuler.mouseDown({offsetX:1,offsetY:1}) + rangeRuler.mouseUp(new MouseEvent("")) + rangeRuler.mouseMove(new MouseEvent("")) + rangeRuler.mouseOut(new MouseEvent("")) + rangeRuler.range.startNS=-2 + rangeRuler.range.endNS=-2 + rangeRuler.range.totalNS=-7 + rangeRuler.fillX(); + rangeRuler.keyPress(new KeyboardEvent("")); + rangeRuler.pressFrameId = !-1 + rangeRuler.keyUp(new KeyboardEvent("")); + rangeRuler.keyUp({key:'w'}); + rangeRuler.keyUp({key:'s'}); + rangeRuler.keyUp({key:'a'}); + rangeRuler.keyUp({key:'d'}); + + }) + + it('SportRulerTest03', () => { + const canvas = document.createElement('canvas'); + canvas.width = 1; + canvas.height = 1; + const ctx = canvas.getContext('2d'); + let rect = new Rect(0, 10, 10, 10); + let rangeRuler = new RangeRuler(canvas,ctx,rect,{ + startX: 0, + endX: rect.width, + startNS: 0, + endNS: 111, + totalNS: 111, + xs: [], + xsTxt: [] + },(a:any) =>{}); + rangeRuler.cpuUsage = true; + expect(rangeRuler.cpuUsage).toBeUndefined(); + }) + +}); \ No newline at end of file diff --git a/host/ide/test/trace/database/SqlLite.test.ts b/host/ide/test/trace/database/SqlLite.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..ad207dc9445b9aa5345b102e64e7266ad01ad198 --- /dev/null +++ b/host/ide/test/trace/database/SqlLite.test.ts @@ -0,0 +1,27 @@ +/* + * 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. + */ +// @ts-ignore +import {threadPool, DbThread,DbPool } from "../../../dist/trace/database/SqlLite.js"; +// import {DbPool} from "../../../src/trace/database/SqlLite"; + +describe('SqlLite Test', () => { + it('SqlLiteTest01', function () { + expect(DbThread).not.toBeTruthy(); + }); + it('SqlLiteTest02', function () { + expect(DbPool).not.toBeUndefined(); + + }); +}) \ No newline at end of file diff --git a/host/ide/test/trace/grpc/HiProfilerClient.test.ts b/host/ide/test/trace/grpc/HiProfilerClient.test.ts index cfe9dcee069dd66c11c03f7bdb44d0631124da53..08c2a9ee3c54a0330346d753cce9374e839fc3d5 100644 --- a/host/ide/test/trace/grpc/HiProfilerClient.test.ts +++ b/host/ide/test/trace/grpc/HiProfilerClient.test.ts @@ -37,7 +37,7 @@ describe('HiProfilerClient Test', ()=>{ }); it('HiProfilerClientTest05', function () { - expect(hiProfilerClient.getProfilerClient()).toBeUndefined(); + expect(hiProfilerClient.getProfilerClient()).toBeTruthy(); }); }) \ No newline at end of file diff --git a/host/ide/test/trace/grpc/ProfilerClient.test.ts b/host/ide/test/trace/grpc/ProfilerClient.test.ts index a4e00e769e34b03384a98e71ce12369508ca8cfb..0021ee1b6326007df5281a2305f2c4be489b3b50 100644 --- a/host/ide/test/trace/grpc/ProfilerClient.test.ts +++ b/host/ide/test/trace/grpc/ProfilerClient.test.ts @@ -17,14 +17,39 @@ import {ProfilerClient} from "../../../dist/trace/grpc/ProfilerClient.js" describe('HiProfilerClient Test', ()=>{ + it('HiProfilerClientTest01 ', function () { + expect(ProfilerClient.client).toBeUndefined() - - it('ProfilerClientTest01', function () { - expect(ProfilerClient.client).toBeUndefined(); }); - it('ProfilerClientTest01', function () { + it('HiProfilerClientTest02', function () { ProfilerClient.client = true; - expect(ProfilerClient.client).toBeTruthy(); + expect(ProfilerClient.client).toBeTruthy() + + }); + it('HiProfilerClientTest03 ', function () { + expect(ProfilerClient.filePaths).toBeUndefined() + + }); + it('HiProfilerClientTest04', function () { + ProfilerClient.filePaths = true; + expect(ProfilerClient.filePaths).toBeTruthy() + + }); + it('HiProfilerClientTest05', function () { + expect(ProfilerClient.profiler_proto).toBeUndefined() + }); + it('HiProfilerClientTest06', function () { + ProfilerClient.profiler_proto = true; + expect(ProfilerClient.profiler_proto).toBeTruthy() + }); + + it('HiProfilerClientTest07 ', function () { + expect(ProfilerClient.shutdown).toBeUndefined() + + }); + it('HiProfilerClientTest08', function () { + ProfilerClient.getChannel = jest.fn(()=>true) + expect(ProfilerClient.getChannel()).toBeTruthy(); }); }) \ No newline at end of file diff --git a/host/ide/test/trace/grpc/ProfilerController.test.ts b/host/ide/test/trace/grpc/ProfilerController.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..7b4e6cfdfd573bc50d5f4d9cd33ef77b3df4935d --- /dev/null +++ b/host/ide/test/trace/grpc/ProfilerController.test.ts @@ -0,0 +1,56 @@ +/* + * 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. + */ + +// @ts-ignore +import {ClientContainer} from "../../../dist/trace/grpc/ProfilerController.js" + +describe('HiProfilerClient Test', ()=>{ + + let profilerController= new ClientContainer(); + + it('ProfilerClientTest01', function () { + expect(profilerController.port).toBeUndefined(); + }); + + it('ProfilerClientTest02', function () { + profilerController.port = true; + expect(profilerController.port).toBeTruthy(); + }); + + it('ProfilerClientTest03', function () { + expect(profilerController.host).toBeUndefined(); + }); + + it('ProfilerClientTest04', function () { + profilerController.host = true; + expect(profilerController.host).toBeTruthy(); + }); + + // it('ProfilerClientTest05', function () { + // expect(profilerController.host).toBe(true); + // }); + + it('ProfilerClientTest06', function () { + profilerController.loadSettings = jest.fn(()=>true) + expect(profilerController.start()).toBeUndefined(); + }); + + it('ProfilerClientTest07', function () { + profilerController.loadSettings = jest.fn(()=>true) + expect(profilerController.loadSettings()).toBeTruthy(); + }); + + +}) \ No newline at end of file diff --git a/host/trace_streamer/BUILD.gn b/host/trace_streamer/BUILD.gn index 092bb98c46e3328169c387349de1c53cf88bb3d3..b181cd7528d574ca13df8b1af5816e607e54a2fd 100644 --- a/host/trace_streamer/BUILD.gn +++ b/host/trace_streamer/BUILD.gn @@ -17,6 +17,11 @@ group("trace_streamer") { } else if (is_test) { deps = [ "test:unittest" ] testonly = true + } else if (is_fuzz) { + deps = [ "test:fuzztest" ] + testonly = true + } else if (is_protoc) { + deps = [ "//third_party/protobuf:protoc" ] } else { deps = [ "src:trace_streamer" ] } diff --git a/host/trace_streamer/README.md b/host/trace_streamer/README.md index eb0deec07b8f4c55fed4152454f49cad6d721cb9..6a0a046e6371e080e28c75b670bc05c2f49b42ef 100644 --- a/host/trace_streamer/README.md +++ b/host/trace_streamer/README.md @@ -1,13 +1,15 @@ # trace_streamer工具说明 +trace_streamer是一个trace数据流转化器,可以将一个trace文本文件或者基于proto序列化的二进制文件转换成为sqlite数据库的形式。 trace_streamer使用C++实现,支持在ohos, linux, mac等系统上使用,具有良好的跨平台特性。 +![GitHub Logo](./figures/trace_streamer_stream.png) +## 关于trace解析工具的使用说明: trace_streamer工具可以2种方式使用 1. 可以将系统离线trace文件解析并转为db,此工具支持基于文本的trace和基于proto的trace。 2. trace_streamer工具还可以WebAssembly的方式在浏览器中运行,需暴露相关接口给js文件。 -## 关于trace解析工具的使用说明: ### 导出db模式 在导出db模式下,trace_streamer.exe trace文件路径名 -e 导出db路径名.db 此命令可以将trace文件转为db -本应用支持在ohos, linux, windows, mac使用。 +本应用支持在ohos, linux, mac使用。 关于db文件的说明: 使用db查看工具查看stat表,可以浏览当前数据一共有多少类数据,各类数据都收到多少条,数据是否正常等情况。在meta表会记录数据库导出时的一些系统信息,比如导入和导出的文件全路径,解析时间等信息。 meta表可以选择不导出(有些情况下会暴露系统敏感信息),在导出时添加 -nm选项即可。 @@ -63,247 +65,43 @@ EMSCRIPTEN_KEEPALIVE int TraceStreamerSqlQuery(const uint8_t* sql, int sqlLen, u ./trace_streamer --help -i 选项可查看应用支持的事件源和具体的事件名列表 -#### trace_streamer支持的事件解析 -本工具支持基于文本的trace(# TRACE)和基于proto的二进制日志文件的解析,支持的事件列表如下: -##### ftrace事件 -``` -binder_transaction -binder_transaction_received -binder_transaction_alloc_buf -binder_transaction_lock -binder_transaction_locked -binder_transaction_unlock -sched_switch -task_rename -task_newtask -tracing_mark_write -print -sched_wakeup -sched_waking -cpu_idle -cpu_frequency -suspend_resume -workqueue_execute_start -workqueue_execute_end -clock_set_rate -clock_enable -clock_disable -clk_set_rate -clk_enable -clk_disable -sys_enter -sys_exit -regulator_set_voltage -regulator_set_voltage_complete -regulator_disable -regulator_disable_complete -ipi_entry -ipi_exit -irq_handler_entry -irq_handler_exit -softirq_raise -softirq_entry -softirq_exit -sched_wakeup_new -sched_process_exit -trace_event_clock_sync -``` -##### 内存事件 -``` -mem.vm.size -mem.rss -mem.rss.anon -mem.rss.file -mem.rss.schem -mem.swap -mem.locked -mem.hwm -mem.oom_score_adj +### trace_streamer支持解析的事件列表 +支持的事件列表参见<> +## TraceStreamer重要概念介绍 +### 1. 进程和线程标识符 ``` -##### 系统内存事件 -``` -sys.mem.unspecified -sys.mem.total -sys.mem.free -sys.mem.avaiable -sys.mem.buffers -sys.mem.cached -sys.mem.swap.chard -sys.mem.active -sys.mem.inactive -sys.mem.active.anon -sys.mem.inactive.anon -sys.mem.active_file -sys.mem.inactive_file -sys.mem.unevictable -sys.mem.mlocked -sys.mem.swap.total -sys.mem.swap.free -sys.mem.dirty -sys.mem.writeback -sys.mem.anon.pages -sys.mem.mapped -sys.mem.shmem -sys.mem.slab -sys.mem.slab.reclaimable -sys.mem.slab.unreclaimable -sys.mem.kernel.stack -sys.mem.page.tables -sys.mem.commit.limit -sys.mem.commited.as -sys.mem.vmalloc.total -sys.mem.vmalloc.used -sys.mem.vmalloc.chunk -sys.mem.cma.total -sys.mem.cma.free -``` -##### 系统虚拟内存事件 -``` -sys.virtual.mem.unspecified -sys.virtual.mem.nr.free.pages -sys.virtual.mem.nr.alloc.batch -sys.virtual.mem.nr.inactive.anon -sys.virtual.mem.nr.active_anon -sys.virtual.mem.nr.inactive.file -sys.virtual.mem.nr.active_file -sys.virtual.mem.nr.unevictable -sys.virtual.mem.nr.mlock -sys.virtual.mem.anon.pages -sys.virtual.mem.nr.mapped -sys.virtual.mem.nr.file.pages -sys.virtual.mem.nr.dirty -sys.virtual.mem.nr.writeback -sys.virtual.mem.nr.slab.reclaimable -sys.virtual.mem.nr.slab.unreclaimable -sys.virtual.mem.nr.page_table.pages -sys.virtual.mem.nr_kernel.stack -sys.virtual.mem.nr.overhead -sys.virtual.mem.nr.unstable -sys.virtual.mem.nr.bounce -sys.virtual.mem.nr.vmscan.write -sys.virtual.mem.nr.vmscan.immediate.reclaim -sys.virtual.mem.nr.writeback_temp -sys.virtual.mem.nr.isolated_anon -sys.virtual.mem.nr.isolated_file -sys.virtual.mem.nr.shmem -sys.virtual.mem.nr.dirtied -sys.virtual.mem.nr.written -sys.virtual.mem.nr.pages.scanned -sys.virtual.mem.workingset.refault -sys.virtual.mem.workingset.activate -sys.virtual.mem.workingset_nodereclaim -sys.virtual.mem.nr_anon.transparent.hugepages -sys.virtual.mem.nr.free_cma -sys.virtual.mem.nr.swapcache -sys.virtual.mem.nr.dirty.threshold -sys.virtual.mem.nr.dirty.background.threshold -sys.virtual.mem.vmeminfo.pgpgin -sys.virtual.mem.pgpgout -sys.virtual.mem.pgpgoutclean -sys.virtual.mem.pswpin -sys.virtual.mem.pswpout -sys.virtual.mem.pgalloc.dma -sys.virtual.mem.pgalloc.normal -sys.virtual.mem.pgalloc.movable -sys.virtual.mem.pgfree -sys.virtual.mem.pgactivate -sys.virtual.mem.pgdeactivate -sys.virtual.mem.pgfault -sys.virtual.mem.pgmajfault -sys.virtual.mem.pgrefill.dma -sys.virtual.mem.pgrefill.normal -sys.virtual.mem.pgrefill.movable -sys.virtual.mem.pgsteal.kswapd.dma -sys.virtual.mem.pgsteal.kswapd.normal -sys.virtual.mem.pgsteal.kswapd.movable -sys.virtual.mem.pgsteal.direct.dma -sys.virtual.mem.pgsteal.direct.normal -sys.virtual.mem.pgsteal_direct.movable -sys.virtual.mem.pgscan.kswapd.dma -sys.virtual.mem.pgscan_kswapd.normal -sys.virtual.mem.pgscan.kswapd.movable -sys.virtual.mem.pgscan.direct.dma -sys.virtual.mem.pgscan.direct.normal -sys.virtual.mem.pgscan.direct.movable -sys.virtual.mem.pgscan.direct.throttle -sys.virtual.mem.pginodesteal -sys.virtual.mem.slabs_scanned -sys.virtual.mem.kswapd.inodesteal -sys.virtual.mem.kswapd.low.wmark.hit.quickly -sys.virtual.mem.high.wmark.hit.quickly -sys.virtual.mem.pageoutrun -sys.virtual.mem.allocstall -sys.virtual.mem.pgrotated -sys.virtual.mem.drop.pagecache -sys.virtual.mem.drop.slab -sys.virtual.mem.pgmigrate.success -sys.virtual.mem.pgmigrate.fail -sys.virtual.mem.compact.migrate.scanned -sys.virtual.mem.compact.free.scanned -sys.virtual.mem.compact.isolated -sys.virtual.mem.compact.stall -sys.virtual.mem.compact.fail -sys.virtual.mem.compact.success -sys.virtual.mem.compact.daemon.wake -sys.virtual.mem.unevictable.pgs.culled -sys.virtual.mem.unevictable.pgs.scanned -sys.virtual.mem.unevictable.pgs.rescued -sys.virtual.mem.unevictable.pgs.mlocked -sys.virtual.mem.unevictable.pgs.munlocked -sys.virtual.mem.unevictable.pgs.cleared -sys.virtual.mem.unevictable.pgs.stranded -sys.virtual.mem.nr.zspages -sys.virtual.mem.nr.ion.heap -sys.virtual.mem.nr.gpu.heap -sys.virtual.mem.allocstall.dma -sys.virtual.mem.allocstall.movable -sys.virtual.mem.allocstall.normal -sys.virtual.mem.compact_daemon.free.scanned -sys.virtual.mem.compact.daemon.migrate.scanned -sys.virtual.mem.nr.fastrpc -sys.virtual.mem.nr.indirectly.reclaimable -sys.virtual.mem.nr_ion_heap_pool -sys.virtual.mem.nr.kernel_misc.reclaimable -sys.virtual.mem.nr.shadow_call.stack_bytes -sys.virtual.mem.nr.shmem.hugepages -sys.virtual.mem.nr.shmem.pmdmapped -sys.virtual.mem.nr.unreclaimable.pages -sys.virtual.mem.nr.zone.active.anon -sys.virtual.mem.nr.zone.active.file -ys.virtual.mem.nr.zone.inactive_anon -sys.virtual.mem.nr.zone.inactive_file -sys.virtual.mem.nr.zone.unevictable -sys.virtual.mem.nr.zone.write_pending -sys.virtual.mem.oom.kill -sys.virtual.mem.pglazyfree -sys.virtual.mem.pglazyfreed -sys.virtual.mem.pgrefill -sys.virtual.mem.pgscan.direct -sys.virtual.mem.pgscan.kswapd -sys.virtual.mem.pgskip.dma -sys.virtual.mem.pgskip.movable -sys.virtual.mem.pgskip.normal -sys.virtual.mem.pgsteal.direct -sys.virtual.mem.pgsteal.kswapd -sys.virtual.mem.swap.ra -sys.virtual.mem.swap.ra.hit +在通用操作系统中,进程号(pid/tgid)和线程号(tid)可能会被重复用于标识不同的进程或者线程。所以在trace数据源中,进程号(pid)和线程号(tid)也可能被重用。 +TraceStreamer在解析数据过程中,使用ipid(internal pid)唯一标识进程, itid(internal tid)唯一标识线程。 ``` +### 2. 计量器 +用来记录系统中各种随时间连续变化的数值。例如: CPU的频率, 内存的使用量, 界面刷新频率。 +#### 举例 +CPU频率: +![GitHub Logo](./figures/cpu_frequency.png) +内存占用: +![GitHub Logo](./figures/mem_usage.png) +### 3. 过滤器 +TraceStreamer设计过程中使用了流式处理的思想,数据从入口进入以后,就像进入一条河流,从上游流向下游,在河道中央有很多过滤器,每种过滤器会将流过的数据中自己关注的内容吸附捕捉到。最终,每个过滤器都拥有了大量同类型的数据,而且这些数据都是按时间序列排列的。TraceStreamer使用filterid来标识同一种用途的数据,可以方便在UI中绘制。 +![image][filterimageid] + +## Stat表设计 +具体内容参见 [des_stat](../doc/des_stat.md) ## trace_streamer开发环境搭建和编译运行指引 -本应用使用gn作为构建工具,支持在linux环境同时编译linux,windows和mac使用QtCreator作为开发IDE +本应用使用gn作为构建工具。 ### 1、开发环境 -ubuntu使用vscode,windows和mac使用QtCreator +ubuntu和mac使用vscode # 对外部的依赖 本应用依赖与sqlite,protobuf(htrace解析部分依赖) 本应用同时依赖于src/protos目录下文件来生成相关pb.h,pb.cc文件 -### 2.1、 编译linux版应用 +### 2.1、 编译linux和Mac版应用 在根目录下执行相关命令进行编译 -### 2.2、编译Windows版和Mac应用 -在项目目录下有pro文件,为QtCreator的工程文件,但部分内容赖在于上面所添加的外部依赖,如果要编译相关平台应用,开发者需自行补充相关工程文件,或者在论坛留言 +### 2.2、 编译wasm +在根目录下执行相关命令进行编译 ### 2.3、开始编译 -具体方法可参考《compile_trace_streamer.md》 \ No newline at end of file +具体方法可参考[compile_trace_streamer](./doc/compile_trace_streamer.md) \ No newline at end of file diff --git a/host/trace_streamer/build.sh b/host/trace_streamer/build.sh index 9e183eeac90d0bd477bbe47f73d14a24b5a55d3c..d897642bccccf3e326ca24779f42175d92d2e2b9 100644 --- a/host/trace_streamer/build.sh +++ b/host/trace_streamer/build.sh @@ -1,4 +1,4 @@ -#! /bin/bash +#!/bin/bash # Copyright (C) 2021 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. @@ -11,18 +11,34 @@ # 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. +set -e PARAMS=$* echo $PARAMS echo "begin to check input" target_os='linux' +target_dir='linux' +gn_path='linux' is_debug='false' is_clean='false' +target='trace_streamer' +gn='gn' +ninja='ninja' +case "$OSTYPE" in + solaris*) echo "SOLARIS" ;; + darwin*) gn_path='macx' target_os='macx' ;; + linux*) gn_path='linux' target_os='linux' ;; + bsd*) echo "is bsd os" ;; + msys*) gn_path='windows' target_os='windows' gn='gn.exe' ninja='ninja.exe' ;; + *) echo "unknown: $OSTYPE" ;; +esac +usage="Usage: $basename $0 wasm/test/fuzz/protoc debug/release/clean" + if [ "$#" -ne "0" ];then - if [ $1 == "wasm" ];then + if [ "$1" == "wasm" ];then if [ ! -d "prebuilts/emsdk" ];then echo "you need emsdk to compile wasm" - mv emsdk.tar.gz prebuilts/ - mv ../emsdk.tar.gz prebuilts/ + #mv emsdk.tar.gz prebuilts/ + #mv ../emsdk.tar.gz prebuilts/ if [ ! -f "prebuilts/emsdk.tar.gz" ];then # consider # you need to get emsdk.tar.gz some where @@ -32,44 +48,53 @@ if [ "$#" -ne "0" ];then tar -zxvf prebuilts/emsdk.tar.gz -C prebuilts/ fi fi - target_os='wasm' + target='wasm' fi - if [ $1 == "test" ];then - target_os='test' + if [ "$1" == "test" ];then + target='test' + fi + if [ "$1" == "fuzz" ];then + target='fuzz' + fi + if [ "$1" == "protoc" ];then + target='protoc' fi fi if [ "$#" -eq "2" ];then - if [ "$1" != 'windows' ] && [ $1 != "linux" ] && [ $1 != "wasm" ] && [ $1 != "test" ];then + if [ "$1" != 'trace' ] && [ "$1" != "linux" ]&& [ "$1" != "windows" ]&& [ "$1" != "trace_streamer" ] && [ "$1" != "wasm" ] && [ "$1" != "test" ] && [ "$1" != "fuzz" ] && [ "$1" != "protoc" ];then echo "failed" - echo "Usage: `basename $0` windows/linux/wasm/test debug/release/clean" + echo "$usage" exit fi - if [ $2 != "debug" -a $2 != "release" -a $2 != "clean" ];then + if [ "$2" != "debug" -a "$2" != "release" -a "$2" != "clean" ];then echo "failed" - echo "Usage: `basename $0` windows/linux debug/release/clean" + echo "$usage" exit fi - if [ $2 == "debug" ];then + if [ "$2" == "debug" ];then is_debug='true' - elif [ $2 == "clean" ];then + elif [ "$2" == "clean" ];then is_clean='true' else is_debug='false' fi - target_os=$1 - if [ $target_os == "windows" ];then + if [ "$target_os" == "windows" ];then echo "gn only support linux and wasm build currently" - mkdir out/windows + if [ ! -d "out/windows" ];then + mkdir out/windows + fi touch out/windows/trace_streamer.exe exit fi echo "platform is $target_os" echo "isdebug: $is_debug" + echo "isclean: $is_clean" else - echo "Usage: `basename $0` windows/linux/wasm debug/release wasm[optional]" + echo "$usage" echo "You provided $# parameters,but 2 are required." echo "use default input paramter" echo "platform is $target_os" + echo "target is $target" echo "is_debug:$is_debug" fi echo "gen ..." @@ -86,18 +111,20 @@ echo "" echo "if you are compiling first time, or your proto has changed, you need to run ./src/protos/protogen.sh" echo "" echo "" -echo +echo #./src/protos/protogen.sh -mkdir prebuilts/$target_os -if [ ! -f "prebuilts/$target_os/gn" ];then +if [ ! -d "prebuilts/$gn_path" ];then + mkdir prebuilts/$gn_path +fi +if [ ! -f "prebuilts/$gn_path/gn" ];then echo "you may get gn for $target_os and place it in prebuilts/$target_os" - ehco "the file can be get at https://gitee.com/su_fu/public_tools/raw/master/gn/$target_os/gn, you need to download it manually" + echo "the file can be get at https://gitee.com/su_fu/public_tools/raw/master/gn/$target_os/gn, you need to download it manually" #wget https://gitee.com/su_fu/public_tools/raw/master/gn/$target_os/gn #mv gn prebuilts/$target_os/ #chmod +x prebuilts/$target_os/gn exit fi -if [ ! -f "prebuilts/$target_os/ninja" ];then +if [ ! -f "prebuilts/$gn_path/ninja" ];then echo "you may get ninja for $target_os and place it in prebuilts/$target_os" ehco "the file can be get at https://gitee.com/su_fu/public_tools/raw/master/gn/$target_os/ninja, you need to download it manually" #wget "https://gitee.com/su_fu/public_tools/raw/master/gn/$target_os/ninja" @@ -107,13 +134,24 @@ if [ ! -f "prebuilts/$target_os/ninja" ];then exit fi echo "$is_clean" +if [ $target == 'test' ] || [ $target == 'fuzz' ] || [ $target='wasm' ];then + target_dir=$target +else + target_dir=$target_os +fi +if [ $target == 'trace_streamer' ] || [ $target == 'trace' ];then + target_dir=$target_os +fi +echo "target_dir:" $target_dir +# exit if [ "$is_clean" == 'true' ];then - prebuilts/$target_os/gn gen out/"$target_os""$ext" --clean - prebuilts/$target_os/ninja -C out/"$target_os""$ext" -t clean + prebuilts/$gn_path/$gn gen out/"$target_dir""$ext" --clean + prebuilts/$gn_path/$ninja -C out/"$target_dir""$ext" -t clean else - prebuilts/$target_os/gn gen out/"$target_os""$ext" --args='is_debug='"$is_debug"' target_os="'"$target_os"'"' + prebuilts/$gn_path/$gn gen out/"$target_dir""$ext" --args='is_debug='"$is_debug"' target="'"$target"'" target_os="'"$target_os"'"' echo "begin to build ..." mkdir -p out/windows touch out/windows/trace_streamer.exe - prebuilts/$target_os/ninja -v -C out/"$target_os""$ext" + prebuilts/$gn_path/$ninja -C out/"$target_dir""$ext" + # prebuilts/$gn_path/ninja -C out/"$target_os""$ext" fi diff --git a/host/trace_streamer/build/test.gni b/host/trace_streamer/build/test.gni index 6912354f710b31f32341dfbd16e51f3d78cef2be..8bdf099d0885508f019e08b7d705a0acd5ea229e 100644 --- a/host/trace_streamer/build/test.gni +++ b/host/trace_streamer/build/test.gni @@ -21,5 +21,28 @@ template("ohos_unittest") { if (defined(invoker.ldflags)) { print(invoker.ldflags) } + if (defined(invoker.cflags)) { + print(invoker.cflags) + cflags += invoker.cflags + } + } +} + +template("ohos_fuzztest") { + executable(target_name) { + forward_variables_from(invoker, "*") + testonly = true + deps = [] + if (defined(invoker.deps)) { + deps += invoker.deps + } + if (defined(invoker.cflags)) { + cflags += invoker.cflags + } + ldflags += [ "-fsanitize=fuzzer" ] + cflags += [ + "-fno-sanitize-coverage=trace-pc-guard,edge,trace-cmp,indirect-calls,8bit-counters", + "-fsanitize=fuzzer", + ] } } diff --git a/host/trace_streamer/doc/README.md b/host/trace_streamer/doc/README.md index eb0deec07b8f4c55fed4152454f49cad6d721cb9..e0d5c9eb8e4777f12600182b62831f54bafe589e 100644 --- a/host/trace_streamer/doc/README.md +++ b/host/trace_streamer/doc/README.md @@ -1,13 +1,15 @@ # trace_streamer工具说明 +trace_streamer是一个trace数据流转化器,可以将一个trace文本文件或者基于proto序列化的二进制文件转换成为sqlite数据库的形式。 trace_streamer使用C++实现,支持在ohos, linux, mac等系统上使用,具有良好的跨平台特性。 +![GitHub Logo](.././figures/trace_streamer_stream.png) +## 关于trace解析工具的使用说明: trace_streamer工具可以2种方式使用 1. 可以将系统离线trace文件解析并转为db,此工具支持基于文本的trace和基于proto的trace。 2. trace_streamer工具还可以WebAssembly的方式在浏览器中运行,需暴露相关接口给js文件。 -## 关于trace解析工具的使用说明: ### 导出db模式 在导出db模式下,trace_streamer.exe trace文件路径名 -e 导出db路径名.db 此命令可以将trace文件转为db -本应用支持在ohos, linux, windows, mac使用。 +本应用支持在ohos, linux, mac使用。 关于db文件的说明: 使用db查看工具查看stat表,可以浏览当前数据一共有多少类数据,各类数据都收到多少条,数据是否正常等情况。在meta表会记录数据库导出时的一些系统信息,比如导入和导出的文件全路径,解析时间等信息。 meta表可以选择不导出(有些情况下会暴露系统敏感信息),在导出时添加 -nm选项即可。 @@ -63,247 +65,43 @@ EMSCRIPTEN_KEEPALIVE int TraceStreamerSqlQuery(const uint8_t* sql, int sqlLen, u ./trace_streamer --help -i 选项可查看应用支持的事件源和具体的事件名列表 -#### trace_streamer支持的事件解析 -本工具支持基于文本的trace(# TRACE)和基于proto的二进制日志文件的解析,支持的事件列表如下: -##### ftrace事件 -``` -binder_transaction -binder_transaction_received -binder_transaction_alloc_buf -binder_transaction_lock -binder_transaction_locked -binder_transaction_unlock -sched_switch -task_rename -task_newtask -tracing_mark_write -print -sched_wakeup -sched_waking -cpu_idle -cpu_frequency -suspend_resume -workqueue_execute_start -workqueue_execute_end -clock_set_rate -clock_enable -clock_disable -clk_set_rate -clk_enable -clk_disable -sys_enter -sys_exit -regulator_set_voltage -regulator_set_voltage_complete -regulator_disable -regulator_disable_complete -ipi_entry -ipi_exit -irq_handler_entry -irq_handler_exit -softirq_raise -softirq_entry -softirq_exit -sched_wakeup_new -sched_process_exit -trace_event_clock_sync -``` -##### 内存事件 -``` -mem.vm.size -mem.rss -mem.rss.anon -mem.rss.file -mem.rss.schem -mem.swap -mem.locked -mem.hwm -mem.oom_score_adj +### trace_streamer支持解析的事件列表 +支持的事件列表参见<> +## TraceStreamer重要概念介绍 +### 1. 进程和线程标识符 ``` -##### 系统内存事件 -``` -sys.mem.unspecified -sys.mem.total -sys.mem.free -sys.mem.avaiable -sys.mem.buffers -sys.mem.cached -sys.mem.swap.chard -sys.mem.active -sys.mem.inactive -sys.mem.active.anon -sys.mem.inactive.anon -sys.mem.active_file -sys.mem.inactive_file -sys.mem.unevictable -sys.mem.mlocked -sys.mem.swap.total -sys.mem.swap.free -sys.mem.dirty -sys.mem.writeback -sys.mem.anon.pages -sys.mem.mapped -sys.mem.shmem -sys.mem.slab -sys.mem.slab.reclaimable -sys.mem.slab.unreclaimable -sys.mem.kernel.stack -sys.mem.page.tables -sys.mem.commit.limit -sys.mem.commited.as -sys.mem.vmalloc.total -sys.mem.vmalloc.used -sys.mem.vmalloc.chunk -sys.mem.cma.total -sys.mem.cma.free -``` -##### 系统虚拟内存事件 -``` -sys.virtual.mem.unspecified -sys.virtual.mem.nr.free.pages -sys.virtual.mem.nr.alloc.batch -sys.virtual.mem.nr.inactive.anon -sys.virtual.mem.nr.active_anon -sys.virtual.mem.nr.inactive.file -sys.virtual.mem.nr.active_file -sys.virtual.mem.nr.unevictable -sys.virtual.mem.nr.mlock -sys.virtual.mem.anon.pages -sys.virtual.mem.nr.mapped -sys.virtual.mem.nr.file.pages -sys.virtual.mem.nr.dirty -sys.virtual.mem.nr.writeback -sys.virtual.mem.nr.slab.reclaimable -sys.virtual.mem.nr.slab.unreclaimable -sys.virtual.mem.nr.page_table.pages -sys.virtual.mem.nr_kernel.stack -sys.virtual.mem.nr.overhead -sys.virtual.mem.nr.unstable -sys.virtual.mem.nr.bounce -sys.virtual.mem.nr.vmscan.write -sys.virtual.mem.nr.vmscan.immediate.reclaim -sys.virtual.mem.nr.writeback_temp -sys.virtual.mem.nr.isolated_anon -sys.virtual.mem.nr.isolated_file -sys.virtual.mem.nr.shmem -sys.virtual.mem.nr.dirtied -sys.virtual.mem.nr.written -sys.virtual.mem.nr.pages.scanned -sys.virtual.mem.workingset.refault -sys.virtual.mem.workingset.activate -sys.virtual.mem.workingset_nodereclaim -sys.virtual.mem.nr_anon.transparent.hugepages -sys.virtual.mem.nr.free_cma -sys.virtual.mem.nr.swapcache -sys.virtual.mem.nr.dirty.threshold -sys.virtual.mem.nr.dirty.background.threshold -sys.virtual.mem.vmeminfo.pgpgin -sys.virtual.mem.pgpgout -sys.virtual.mem.pgpgoutclean -sys.virtual.mem.pswpin -sys.virtual.mem.pswpout -sys.virtual.mem.pgalloc.dma -sys.virtual.mem.pgalloc.normal -sys.virtual.mem.pgalloc.movable -sys.virtual.mem.pgfree -sys.virtual.mem.pgactivate -sys.virtual.mem.pgdeactivate -sys.virtual.mem.pgfault -sys.virtual.mem.pgmajfault -sys.virtual.mem.pgrefill.dma -sys.virtual.mem.pgrefill.normal -sys.virtual.mem.pgrefill.movable -sys.virtual.mem.pgsteal.kswapd.dma -sys.virtual.mem.pgsteal.kswapd.normal -sys.virtual.mem.pgsteal.kswapd.movable -sys.virtual.mem.pgsteal.direct.dma -sys.virtual.mem.pgsteal.direct.normal -sys.virtual.mem.pgsteal_direct.movable -sys.virtual.mem.pgscan.kswapd.dma -sys.virtual.mem.pgscan_kswapd.normal -sys.virtual.mem.pgscan.kswapd.movable -sys.virtual.mem.pgscan.direct.dma -sys.virtual.mem.pgscan.direct.normal -sys.virtual.mem.pgscan.direct.movable -sys.virtual.mem.pgscan.direct.throttle -sys.virtual.mem.pginodesteal -sys.virtual.mem.slabs_scanned -sys.virtual.mem.kswapd.inodesteal -sys.virtual.mem.kswapd.low.wmark.hit.quickly -sys.virtual.mem.high.wmark.hit.quickly -sys.virtual.mem.pageoutrun -sys.virtual.mem.allocstall -sys.virtual.mem.pgrotated -sys.virtual.mem.drop.pagecache -sys.virtual.mem.drop.slab -sys.virtual.mem.pgmigrate.success -sys.virtual.mem.pgmigrate.fail -sys.virtual.mem.compact.migrate.scanned -sys.virtual.mem.compact.free.scanned -sys.virtual.mem.compact.isolated -sys.virtual.mem.compact.stall -sys.virtual.mem.compact.fail -sys.virtual.mem.compact.success -sys.virtual.mem.compact.daemon.wake -sys.virtual.mem.unevictable.pgs.culled -sys.virtual.mem.unevictable.pgs.scanned -sys.virtual.mem.unevictable.pgs.rescued -sys.virtual.mem.unevictable.pgs.mlocked -sys.virtual.mem.unevictable.pgs.munlocked -sys.virtual.mem.unevictable.pgs.cleared -sys.virtual.mem.unevictable.pgs.stranded -sys.virtual.mem.nr.zspages -sys.virtual.mem.nr.ion.heap -sys.virtual.mem.nr.gpu.heap -sys.virtual.mem.allocstall.dma -sys.virtual.mem.allocstall.movable -sys.virtual.mem.allocstall.normal -sys.virtual.mem.compact_daemon.free.scanned -sys.virtual.mem.compact.daemon.migrate.scanned -sys.virtual.mem.nr.fastrpc -sys.virtual.mem.nr.indirectly.reclaimable -sys.virtual.mem.nr_ion_heap_pool -sys.virtual.mem.nr.kernel_misc.reclaimable -sys.virtual.mem.nr.shadow_call.stack_bytes -sys.virtual.mem.nr.shmem.hugepages -sys.virtual.mem.nr.shmem.pmdmapped -sys.virtual.mem.nr.unreclaimable.pages -sys.virtual.mem.nr.zone.active.anon -sys.virtual.mem.nr.zone.active.file -ys.virtual.mem.nr.zone.inactive_anon -sys.virtual.mem.nr.zone.inactive_file -sys.virtual.mem.nr.zone.unevictable -sys.virtual.mem.nr.zone.write_pending -sys.virtual.mem.oom.kill -sys.virtual.mem.pglazyfree -sys.virtual.mem.pglazyfreed -sys.virtual.mem.pgrefill -sys.virtual.mem.pgscan.direct -sys.virtual.mem.pgscan.kswapd -sys.virtual.mem.pgskip.dma -sys.virtual.mem.pgskip.movable -sys.virtual.mem.pgskip.normal -sys.virtual.mem.pgsteal.direct -sys.virtual.mem.pgsteal.kswapd -sys.virtual.mem.swap.ra -sys.virtual.mem.swap.ra.hit +在通用操作系统中,进程号(pid/tgid)和线程号(tid)可能会被重复用于标识不同的进程或者线程。所以在trace数据源中,进程号(pid)和线程号(tid)也可能被重用。 +TraceStreamer在解析数据过程中,使用ipid(internal pid)唯一标识进程, itid(internal tid)唯一标识线程。 ``` +### 2. 计量器 +用来记录系统中各种随时间连续变化的数值。例如: CPU的频率, 内存的使用量, 界面刷新频率。 +#### 举例 +CPU频率: +![GitHub Logo](.././figures/cpu_frequency.png) +内存占用: +![GitHub Logo](.././figures/mem_usage.png) +### 3. 过滤器 +TraceStreamer设计过程中使用了流式处理的思想,数据从入口进入以后,就像进入一条河流,从上游流向下游,在河道中央有很多过滤器,每种过滤器会将流过的数据中自己关注的内容吸附捕捉到。最终,每个过滤器都拥有了大量同类型的数据,而且这些数据都是按时间序列排列的。TraceStreamer使用filterid来标识同一种用途的数据,可以方便在UI中绘制。 +![image][filterimageid] + +## Stat表设计 +具体内容参见 [des_stat](.././des_stat.md) ## trace_streamer开发环境搭建和编译运行指引 -本应用使用gn作为构建工具,支持在linux环境同时编译linux,windows和mac使用QtCreator作为开发IDE +本应用使用gn作为构建工具。 ### 1、开发环境 -ubuntu使用vscode,windows和mac使用QtCreator +ubuntu和mac使用vscode # 对外部的依赖 本应用依赖与sqlite,protobuf(htrace解析部分依赖) 本应用同时依赖于src/protos目录下文件来生成相关pb.h,pb.cc文件 -### 2.1、 编译linux版应用 +### 2.1、 编译linux和Mac版应用 在根目录下执行相关命令进行编译 -### 2.2、编译Windows版和Mac应用 -在项目目录下有pro文件,为QtCreator的工程文件,但部分内容赖在于上面所添加的外部依赖,如果要编译相关平台应用,开发者需自行补充相关工程文件,或者在论坛留言 +### 2.2、 编译wasm +在根目录下执行相关命令进行编译 ### 2.3、开始编译 -具体方法可参考《compile_trace_streamer.md》 \ No newline at end of file +具体方法可参考[compile_trace_streamer](.././compile_trace_streamer.md) \ No newline at end of file diff --git a/host/trace_streamer/doc/des_compile_trace_streamer.md b/host/trace_streamer/doc/compile_trace_streamer.md similarity index 40% rename from host/trace_streamer/doc/des_compile_trace_streamer.md rename to host/trace_streamer/doc/compile_trace_streamer.md index dd1f00ff4a9805c45a94254c90ca3e4069accf21..18dd1ebe52cbdc258bf4ca9287297f7cf9595177 100644 --- a/host/trace_streamer/doc/des_compile_trace_streamer.md +++ b/host/trace_streamer/doc/compile_trace_streamer.md @@ -6,7 +6,7 @@ 本工具默认编译方式是使用gn + 编译方式 ``` -./build.sh linux/wasm +./build.sh linux/wasm/macx ``` 如果需要编译WebAssembly版本,您需要在prebuilts/目录下安装emsdk ``` @@ -49,85 +49,4 @@ prebuilts/emsdk 之后调用 ``` ./build.sh wasm进行编译,您需要将sh脚本进行部分修改,因为这个脚本内置了一些库的下载和解析方式 -``` -本工具还支持使用QtCreator来编译。 - -src/trace_streamer.pro 是工程文件,编译本工具需要依赖Sqlite库和一些基于proto的pb.h文件 -## 2 准备工程 -### 2.1 基于proto文件生成pb文件 -您需要自行下载并编译一个当前系统(linux)可用的proobuf/protoc程序,此全路径为位于out/linux/protoc -src/protos目录下有一个protogen.sh文件,运行该文件可以在third_party/protogen目录下生成项目需要的pb相关文件 -序列化二进制的解析依赖于基于proto生成的.pb.cc文件。 -在执行protogen.sh脚本之后 -你的目录结构当类似如下结构: -``` -third_party/protogen/types/plugins/ftrace_data/*.pb.cc -third_party/sqlite/*. -third_party/protobuf/* -``` -### 2.2 获取第三方依赖库 -从 -https://gitee.com/openharmony/third_party_sqlite -获取sqlite3目录到代码根目录的third_party目录 -从 -https://gitee.com/openharmony/third_party_protobuf -获取protobuf目录到代码根目录的third_party目录 -之后,你的目录当如下所示 -trace_streamer/third_party/protobuf -trace_streamer/third_party/sqlite -# 3 (linux和ohos平台)使用gn编译TraceStreamer -在编译WebAssembly目标时,需要将sqlite3和protobuf里面相关的ohos_xxx_library统一修改为source_set -## 3.2 准备gn -在自己的项目中使用gn,必须遵循以下要求: -在根目录创建.gn文件,该文件用于指定CONFIG.gn文件的位置; -在BUILDCONFIG.gn中指定编译时使用的编译工具链; -在独立的gn文件中定义编译使用的工具链; -在项目根目录下创建BUILD.gn文件,指定编译的目标。 -``` -cp prebuilts/gn ./ -``` -不同的操作系统下,你需要获取不同的gn -## 3.3 执行编译 -./build.sh linux debug -或./build.sh linux debug -./build.sh将直接编译linux的release版本 -build.sh wasm 命令将可以编译WebAssembly版本 -特别说明:编译WebAssembly版本需要emSDK支持,你需要将build.sh里面的相关路径做更改,以保证编译时必须的文件是存在的 -# 4 编译Windows版本或Mac版本 -## 4.1 编译依赖文件 -### 4.1.1 编译SqliteLib -使用QtCreator打开prebuiltsprebuilts/buildprotobuf/sqlite.pro -### 4.1.2 编译ProtobufLib -使用QtCreator打开prebuilts/buildprotobuf/protobuf.pro -编译之后,文件结构当如下所示: -``` -lib -├── linux -│ ├── libdl.so -│ └── libsqlite.a -├── linux_debug -│ ├── libprotobuf.a -│ └── libsqlite.a -├── macx -│ ├── libprotobuf.a -│ └── libsqlite.a -├── macx_debug -│ ├── libprotobuf.a -│ └── libsqlite.a -├── windows -│ ├── libprotobuf.a -│ └── libsqlite.a -└── windows_debug - ├── libprotobuf.a - └── libsqlite.a -``` -## 4.2 编译TraceStreamer -之后,使用QtCreator打开src/trace_streamer.pro,选择合适的构建工具,执行 Ctrl + b 即可编译 - -编译之后的可执行文件位于out目录 -``` -- out ----- linux (Linux平台下QtCreator或gn生成) ----- macx (mac平台下QtCreator或gn生成) ----- windows (windows平台下QtCreator或gn生成) ``` \ No newline at end of file diff --git a/host/trace_streamer/doc/compiler_ut.md b/host/trace_streamer/doc/compiler_ut.md new file mode 100644 index 0000000000000000000000000000000000000000..02d13a67ac291b9707aee7734e032f4ae5a59fb3 --- /dev/null +++ b/host/trace_streamer/doc/compiler_ut.md @@ -0,0 +1,28 @@ +直接运行./build.sh test 即可编译ut代码,编译ut时,可能会遇到一些问题,需要将部分代码做如下处理: +v412.pb.h +大约第36行,添加如下内容 +``` +#ifdef major +#undef major +#endif +#ifdef minor +#undef minor +#endif +``` +gtest-port.h 第286行,在 +``` +#include +``` +修改为 +``` +#undef private +#define private private +#include +#undef private +#define private public +``` +编译ut需要您在third_party下放置一个gtest的工程 + +在ut代码编译完成之后,直接运行./test.sh,可以执行所有ut,显示正确与否 +在ut执行之后,直接运行./lcov.sh,可以生成覆盖率报告 +覆盖率报告位于out/test/html目录 \ No newline at end of file diff --git a/host/trace_streamer/doc/des_binder.md b/host/trace_streamer/doc/des_binder.md new file mode 100644 index 0000000000000000000000000000000000000000..5543132bcb09319f971557341729552be3b88137 --- /dev/null +++ b/host/trace_streamer/doc/des_binder.md @@ -0,0 +1,62 @@ +# binder事件上下文如何关联 +binder事件相对复杂,这里是从ftrace事件中抽离出来的binder相关消息,用来作为开发者或用户追踪binder事件的参考 +a binder event is identified by the sender and receive device, and a reply message only end +the last binder msg which reply the calling one. +the alloc_buf msg can always flow the binder_transaction, so we no need to identify the alloc msg with transactionID + +## TAG TT need reply!!! needReply = !isReply && !(flags & 0x01); +``` +RenderThread-2267 ( 1592) [003] ...1 168766.128108: binder_transaction: transaction=25155526 dest_node=25155471 dest_proc=506 dest_thread=0 reply=0 flags=0x10 code=0x9 +RenderThread-2267 ( 1592) [003] ...1 168766.128110: binder_transaction_alloc_buf: transaction=25155526 data_size=120 offsets_size=8 +``` +### received +``` +Binder:506_2-537 ( 506) [003] ...1 168766.128154: binder_transaction_received: transaction=25155526 +``` +### binder is in DB, TAG A needReply +``` +Binder:506_2-537 ( 506) [003] ...1 168766.128221: binder_transaction: transaction=25155529 dest_node=25155527 dest_proc=1592 dest_thread=2267 reply=0 flags=0x10 code=0x5f474854 +Binder:506_2-537 ( 506) [003] ...1 168766.128223: binder_transaction_alloc_buf: transaction=25155529 data_size=72 offsets_size=0 +``` +## +``` +RenderThread-2267 ( 1592) [003] ...1 168766.128243: binder_transaction_received: transaction=25155529 +``` +### the flowing is for TAG A, this is the reply for TAG A +``` +RenderThread-2267 ( 1592) [003] ...1 168766.128262: binder_transaction: transaction=25155530 dest_node=0 dest_proc=506 dest_thread=537 reply=1 flags=0x8 code=0x0 + +RenderThread-2267 ( 1592) [003] ...1 168766.128264: binder_transaction_alloc_buf: transaction=25155530 data_size=4 offsets_size=0 +``` +### calc the dur of TAG A +``` +Binder:506_2-537 ( 506) [003] ...1 168766.128288: binder_transaction_received: transaction=25155530 +``` +### binder last TAG A needReply, this is TAG B needReply!!! +``` +Binder:506_2-537 ( 506) [003] ...1 168766.128328: binder_transaction: transaction=25155532 dest_node=25155527 dest_proc=1592 dest_thread=2267 reply=0 flags=0x10 code=0x2 +Binder:506_2-537 ( 506) [003] ...1 168766.128330: binder_transaction_alloc_buf: transaction=25155532 data_size=72 offsets_size=0 +``` +## in db +``` +RenderThread-2267 ( 1592) [003] ...1 168766.128347: binder_transaction_received: transaction=25155532 +``` +## the reply message is not in db Session D, this is the reply for TAG B +``` +RenderThread-2267 ( 1592) [003] ...1 168766.128361: binder_transaction: transaction=25155533 dest_node=0 dest_proc=506 dest_thread=537 reply=1 flags=0x0 code=0x0 +RenderThread-2267 ( 1592) [003] ...1 168766.128363: binder_transaction_alloc_buf: transaction=25155533 data_size=4 offsets_size=0 +``` +### no this message in db, calcate the dur of TAG B +``` +Binder:506_2-537 ( 506) [003] ...1 168766.128385: binder_transaction_received: transaction=25155533 +``` +### no this message in db Session E, this is the reply for TAG TT +``` +Binder:506_2-537 ( 506) [003] ...1 168766.128412: binder_transaction: transaction=25155534 dest_node=0 dest_proc=1592 dest_thread=2267 reply=1 flags=0x0 code=0x0 + +Binder:506_2-537 ( 506) [003] ...1 168766.128413: binder_transaction_alloc_buf: transaction=25155534 data_size=68 offsets_size=0 +``` +## the dur of TAG TT is calcated by the flowing msg +``` +RenderThread-2267 ( 1592) [003] ...1 168766.128430: binder_transaction_received: transaction=25155534 +``` \ No newline at end of file diff --git a/host/trace_streamer/doc/des_stat.md b/host/trace_streamer/doc/des_stat.md index e1048f51e1dbb4e9fbe08a809856d2bba903a5d2..e71a4f429023bba22e5cad4200fe4d81dd1bbbb8 100644 --- a/host/trace_streamer/doc/des_stat.md +++ b/host/trace_streamer/doc/des_stat.md @@ -1,7 +1,10 @@ # TraceStreamer 解析数据状态表 -TraceStreamer使用stat表统计解析trace数据源过程遇到的重要事件状态。通过stat表可以对trace数据源中各个类型事件的数据有一个基本了解。 +TraceStreamer使用stat表统计解析trace数据源过程遇到的重要事件状态。通过stat表可以对trace数据源中各个类型事件的数据的数量,数据质量有一个基本了解。 +我们对不同类型的数据,统计了收到多少条,数据逻辑是否匹配,是否有不合法数据,是否有数据丢失情况,所有这些,是基于对数据格式本身和数据前后关系的主观认识。欢迎开发者提供更多的思路来帮我们完善数据本身的校验工作。 ## stat表支持统计的事件列表如下: -|event_name | +### ftrace事件统计 +ftrace相关事件属于系统内核事件,具体请参考linux内核相关技术网站(www.kernel.org) +|事件名称 | | ---- | |binder_transaction | |binder_transaction_alloc_buf | @@ -17,17 +20,12 @@ TraceStreamer使用stat表统计解析trace数据源过程遇到的重要事件 |clock_set_rate | |cpu_frequency | |cpu_idle | -|hidump_fps | -|hilog | |ipi_entry | |ipi_exit | |irq_handler_entry | |irq_handler_exit | -|memory | -|native_hook_free | -|native_hook_malloc | +|memory (进程内存) | |oom_score_adj_update | -|other | |print | |regulator_disable | |regulator_disable_complete | @@ -47,8 +45,6 @@ TraceStreamer使用stat表统计解析trace数据源过程遇到的重要事件 |suspend_resume | |sys_enter | |sys_exit | -|sys_memory | -|sys_virtual_memory | |task_newtask | |task_rename | |trace_bblock_bio_queue | @@ -68,6 +64,40 @@ TraceStreamer使用stat表统计解析trace数据源过程遇到的重要事件 |tracing_mark_write | |workqueue_execute_end | |workqueue_execute_start | +## fps事件统计 +|事件名称 | +| ---- | +|hidump_fps | +## 日志事件统计 +|事件名称 | +| ---- | +|hilog | +## 系统内存和系统虚拟内存事件 +|事件名称 | +| ---- | +|sys_memory | +|sys_virtual_memory | +## 内存申请和释放事件 +|事件名称 | +| ---- | +|native_hook_free | +|native_hook_malloc | +## 磁盘读写事件统计 +|事件名称 | +| ---- | +|trace_diskio | +## 进程事件统计 +|事件名称 | +| ---- | +|trace_process | +## CPU使用率事件解析 +|事件名称 | +| ---- | +|trace_cpu_usage | +## 网络数据事件解析 +|事件名称 | +| ---- | +|trace_network | ## 事件对应解析状态: 每种事件解析数据都有5种状态,描述如下表: @@ -81,7 +111,9 @@ TraceStreamer使用stat表统计解析trace数据源过程遇到的重要事件 ## 数据状态级别 数据状态级别总共有4种,分别是:info, warn, error,fatal。由于数据的重要性不同,不同事件的同一种状态可能对应不同的级别。 -例如binder_transaction_received的 not_supported状态的数据为info级别,而binder_transaction_alloc_buf的not_supported状态数据为warn级别。 +例如binder_transaction_received的 not_supported状态的数据为info级别,而binder_transaction_alloc_buf的not_supported状态数据为warn级别。 + +您可以在src/cfg/trace_streamer_config.cpp的InitSecurityMap方法中自行定义相关事件的优先级。 ## 事件,状态与级别对应关系 | event_name | stat_type | serverity | @@ -321,6 +353,26 @@ TraceStreamer使用stat表统计解析trace数据源过程遇到的重要事件 | native_hook_free | not_match | info | | native_hook_free | not_supported | warn | | native_hook_free | invalid_data | error | +| trace_diskio | received | info | +| trace_diskio | data_lost | error | +| trace_diskio | not_match | info | +| trace_diskio | not_supported | warn | +| trace_diskio | invalid_data | error | +| trace_process | received | info | +| trace_process | data_lost | error | +| trace_process | not_match | info | +| trace_process | not_supported | warn | +| trace_process | invalid_data | error | +| trace_cpu_usage | received | info | +| trace_cpu_usage | data_lost | error | +| trace_cpu_usage | not_match | info | +| trace_cpu_usage | not_supported | warn | +| trace_cpu_usage | invalid_data | error | +| trace_network | received | info | +| trace_network | data_lost | error | +| trace_network | not_match | info | +| trace_network | not_supported | warn | +| trace_network | invalid_data | error | | sys_memory | received | info | | sys_memory | data_lost | error | | sys_memory | not_match | info | diff --git a/host/trace_streamer/doc/des_support_eventlist.md b/host/trace_streamer/doc/des_support_event.md similarity index 100% rename from host/trace_streamer/doc/des_support_eventlist.md rename to host/trace_streamer/doc/des_support_event.md diff --git a/host/trace_streamer/doc/des_tables.md b/host/trace_streamer/doc/des_tables.md index efe0a6f7b4ab4352fc1a9cce82963d86293d8a4e..1c4a985960e00832e58da84eafc2bb7227eb4597 100644 --- a/host/trace_streamer/doc/des_tables.md +++ b/host/trace_streamer/doc/des_tables.md @@ -4,30 +4,44 @@ ``` ## ___TraceStreamer输出数据库包含以下表格___ -* trace_range : 记录ftrace数据与其他类型数据的时间交集,供前端展示数据时使用。 -* process : 记录进程信息。 -* thread : 记录线程信息。 -* thread_state : 记录线程状态信息。 -* instant : 记录Sched_waking, sched_wakeup事件, 用作ThreadState表的上下文使用。 -* raw : 此数据结构主要作为ThreadState的上下文使用,这张表是sched_waking,sched_wakup, cpu_idle事件的原始记录。 +* args : 记录方法参数集合 * callstack : 记录调用堆栈和异步调用,其中depth,stack_id和parent_stack_id仅在非异步调用中有效。当cookid不为空时,为异步调用,此时callid为进程唯一号,否则为线程唯一号。 +* clk_event_filter : 记录时钟信息。 +* clock_event_filter :此结构用来维护时钟事件和cpu与唯一的ID做关联 +* cpu_measure_filter : cpu事件过滤器表。 +* cpu_usage :记录CPU使用率事件。 +* data_dict : 记录常用的字符串,将字符串和索引关联,降低程序运行的内存占用,用作辅助数据。 +* data_type : 记录数据类型和typeId的关联关系。 +* diskio :记录磁盘读写数据事件。 +* hidump : 记录FPS(Frame Per Second)数据。 +* instant : 记录Sched_waking, sched_wakeup事件, 用作ThreadState表的上下文使用。 * irq : 记录中断相关事件。 -* measure : 记录所有的计量值。 +* live_process :记录了一些实时的进程中执行的一些数据。 * log : 记录hilog打印日志数据。 -* heap : 记录堆内存申请与释放相关的数据。 -* heap_frame : 记录堆内存申请与释放相关的调用栈。 -* hidump : 记录FPS(Frame Per Second)数据。 +* measure : 记录所有的计量值。 +* measure_filter : 记录一个递增的filterid队列,所有其他的filter类型在获取过程中,均从此数据列表中获取下一个可用的filter_id并做记录。 +* meta : 记录执行解析操作相关的基本信息。 +* native_hook :记录堆内存申请与释放相关的数据。 +* native_hook_frame :记录堆内存申请与释放相关的调用栈。 +* network :抓取网络信息传输时产生的一些相关信息 +* perf_callchain :记录Hiperf采样数据的调用栈信息。 +* perf_files :记录Hiperf工具采集到的函数符号表和文件名。 +* perf_report :记录Hiperf工具采集数据时的配置信息。包括:抓取的事件类型,抓取数据的命令, 抓数据时指定的进程名称。 +* perf_sample :记录Hiperf工具的采样信息。 +* perf_thread :记录Hiperf工具采集到的进程和线程数据。 +* process : 记录所有的进程信息。 +* process_filter :过滤进程。 +* process_measure_filter : 将进程ID作为key1,进程的内存,界面刷新,屏幕亮度等信息作为key2,唯一确定一个filter_id +* raw : 此数据结构主要作为ThreadState的上下文使用,这张表是sched_waking,sched_wakup, cpu_idle事件的原始记录。 +* sched_slice :此数据结构主要作为ThreadState的上下文使用,这张表是sched_switch事件的原始记录 +* stat :此结果用来统计数据解析中各类数据的数据条数,数据和合法性,数据的匹配程度(begin-end),数据的损失等,查看此结构对应的表,可对数据源有基本的了解 * symbols : 记录系统调用名称和其函数指针的对应关系,trace中用addr来映射function_name来节省存储空间 * syscall : 记录用户空间函数与内核空间函数相互调用记录 -* args : 记录方法参数集合 * sys_event_filter : 记录所有的filter -* clk_event_filter : 记录时钟事件 -* cpu_measure_filter : cpu事件过滤器表。 -* measure_filter : 记录一个递增的filterid队列,所有其他的filter类型在获取过程中,均从此数据列表中获取下一个可用的filter_id并做记录。 -* process_measure_filter : 将进程ID作为key1,进程的内存,界面刷新,屏幕亮度等信息作为key2,唯一确定一个filter_id -* data_type : 记录数据类型和typeId的关联关系。 -* data_dict : 记录常用的字符串,将字符串和索引关联,降低程序运行的内存占用,用作辅助数据。 -* meta : 记录执行解析操作相关的基本信息。 +* thread : 记录所有的线程信息。 +* thread_filter :过滤线程。 +* thread_state : 记录线程状态信息。 +* trace_range : 记录ftrace数据与其他类型数据的时间交集,供前端展示数据时使用。 ## ___表格关系图___ @@ -52,17 +66,17 @@ select thread_state.* from thread, thread_state where thread.tid = 123 and threa ### 堆内存数据变化表关系图 ![GitHub Logo](../figures/dump_and_mem.png) ### 描述: -heap表记录堆内存申请(AllocEvent)和释放(FreeEvent)数据。heap表通过ipid和itid字段分别与process和thread表的id字段关联,通过eventId与heap_frame表的eventId字段相关联。 -heap表字段解释如下: - eventId: 唯一标识一次堆内存申请或释放, 通过与heap_frame表关联可以拿到当前申请或释放的函数调用堆栈。 +native_hook表记录堆内存申请(AllocEvent)和释放(FreeEvent)数据。native_hook表通过ipid和itid字段分别与process和thread表的id字段关联,通过eventId与native_hook_frame表的eventId字段相关联。 +native_hook表字段解释如下: + eventId: 唯一标识一次堆内存申请或释放, 通过与native_hook_frame表关联可以拿到当前申请或释放的函数调用堆栈。 addr: 堆内存申请/释放的地址 - heap_size: 堆内存申请/释放的大小 -heap_frame表记录内存申请/释放的调用堆栈。通过eventId区分一组调用堆栈,depth为堆栈深度,depth为0时,表示当前行为栈顶数据。 + native_hook_size: 堆内存申请/释放的大小 +native_hook_frame表记录内存申请/释放的调用堆栈。通过eventId区分一组调用堆栈,depth为堆栈深度,depth为0时,表示当前行为栈顶数据。 ### 举例: 已知tid = 123, 查看当前线程的所有堆内存变化信息,可以使用如下SQL语句: -select heap.* from thread, heap where thread.tid = 123 and thread.id = heap.itid +select native_hook.* from thread, native_hook where thread.tid = 123 and thread.id = native_hook.itid 已知eventid = 0, 查看当前内存变化调用堆栈 -select * from heap_frame where eventId = 0 +select * from native_hook_frame where eventId = 0 ### 日志表与进程线程表关系图 ![GitHub Logo](../figures/log.png) @@ -72,6 +86,8 @@ log表记录日志信息。可以根据seq字段的连续性,来判断是否 已知tid = 123, 查看当前线程的所有error级别的日志,可以使用如下SQL语句: select * from log where tid = 123 and level = "error" +### perf表关系图 + ## TraceStreamer输出数据库表格详细介绍 ### trace_range表 @@ -83,6 +99,7 @@ select * from log where tid = 123 and level = "error" #### 关键字段描述: start_ts: trace的开始时间,纳秒为单位 end_ts: trace的结束时间,纳秒为单位 + ### process表 #### 表结构: | Columns Name | SQL TYPE | @@ -96,6 +113,7 @@ end_ts: trace的结束时间,纳秒为单位 id: 进程在数据库重新重新定义的id,从0开始序列增长 pid: 进程的真实id name: 进程名字 + ### thread表 #### 表结构: | Columns Name | SQL TYPE | @@ -110,7 +128,7 @@ name: 进程名字 |is_main_thread|INT | #### 字段详细描述: id: 线程在数据库重新重新定义的id,从0开始序列增长 -ipid: 线程所属的进程id, 关联进程表中的ID +ipid: 线程所属的进程id, 关联process表中的ID name: 线程名字 is_main_thread: 是否主线程,主线程即该线程实际就是进程本身 @@ -130,7 +148,7 @@ id: 线程状态在数据库中的id,从0开始序列增长 ts: 该线程状态的起始时间 dur: 该线程状态的持续时间 cpu: 该线程在哪个cpu上执行(针对running状态的线程) -itid: 该状态所属的线程所属的进程id, 关联进程表中的ID +itid: 该状态所属的线程id, 关联线程表中的id state: 线程实际的的状态值 ``` 'R', Runnable状态 @@ -156,6 +174,7 @@ state: 线程实际的的状态值 |ref_type |NUM | #### 表描述: 记录了系统中的waking和wakeup事件。 + ### raw表 #### 表结构: | Columns Name | SQL TYPE | @@ -203,28 +222,45 @@ parent_id: 父调用的id |ts |INT | |value |INT | |filter_id |INT | -#### 字段详细描述: +#### 关键字段描述: +ts: 事件时间 +value: 数值 +filter_id: 对应filter表中的ID -### heap表 +### native_hook表 #### 表结构: | Columns Name | SQL TYPE | |---- |---- | +|id |INT | |eventId |INT | |ipid |INT | |itid |INT | |event_type |NUM | +|sub_type |NUM | |start_ts |INT | |end_ts |INT | |dur |INT | |addr |INT | |heap_size |INT | |all_heap_size |INT | -#### 字段详细描述: +|current_size_dur |INT | +#### 关键字段描述: +eventId:唯一标识一条native_hook数据 +event_type:事件类型取值范围(AllocEvent,FreeEvent,MmapEvent, MunmapEvent) +sub_type:子事件类型(只有sub_type字段为MmapEvent时,该字段才会有值) +start_ts:申请内存开始时间 +end_ts:释放内存时间 +Dur:申请内存活跃时间 +Addr:申请内存地址 +mem_size:申请或释放内存大小 +all_mem_size:从采集数据开始到当前时刻,申请并活跃的内存总量。 event_type为AllocEvent或者FreeEvent时,表示活跃的堆内存总量。当event_type为MmapEvent或者MunmapEvent时,表示活跃的映射内存总量。 +current_size_dur:表示当前活跃内存总量的持续时间 -### heap_frame表 +### native_hook_frame表 #### 表结构: | Columns Name | SQL TYPE | |---- |---- | +|id |INT | |eventId |INT | |depth |INT | |ip |INT | @@ -235,14 +271,17 @@ parent_id: 父调用的id |symbol_offset |INT | #### 表描述: 记录了内存的申请和释放的堆栈。 + ### hidump表 #### 表结构: | Columns Name | SQL TYPE | |---- |---- | +|id |INT | |ts |INT | |fps |INT | #### 表描述: 此表记录了设备的帧率信息,fps。 + ### symbols表 #### 表结构: | Columns Name | SQL TYPE | @@ -262,10 +301,10 @@ parent_id: 父调用的id |type |NUM | |name |INT | |source_arg_set_id |INT | - #### 字段详细描述: 过滤分类(type),过滤名称(key2),数据ID(key1)。 数据ID在process_measure_filter, sys_event_filter中作为id。 + ### process_measure_filter表 将进程ID作为key1,进程的内存,界面刷新,屏幕亮度等信息作为key2,唯一确定一个filter_id, filter_id同时被记录在measure_filter表中。 #### 表结构: @@ -278,7 +317,76 @@ parent_id: 父调用的id #### 字段详细描述: filterid: 来自measure_filter表 name: cpu状态名 -ipid: 进程内部编号 +ipid: 进程内部编号 + +### sys_event_filter表 +#### 表结构: +| Columns Name | SQL TYPE | +|---- |---- | +|id |INT | +|type |NUM | +|name |NUM | +#### 表描述: +记录所有的filter + +### clk_event_filter表 +#### 表结构: +| Columns Name | SQL TYPE | +|---- |---- | +|id |INT | +|type |NUM | +|name |NUM | +|cpu |INT | +#### 字段详细描述: +Type:时钟事件类型 +Name:时钟事件名称 + +### cpu_measure_filter表 +#### 表结构: +| Columns Name | SQL TYPE | +|---- |---- | +|id |INT | +|type |NUM | +|name |NUM | +|cpu |INT | +#### 主要字段描述: +Id(filterid), cpu:事件名称,cpu号 + +### measure_filter表 +#### 表结构: +| Columns Name | SQL TYPE | +|---- |---- | +|id |INT | +|type |NUM | +|name |NUM | +|source_arg_set_id |INT | +#### 字段详细描述: +Id:filterID +Type:过滤分类 +Name:过滤名称 + +### irq表 +#### 表结构: +| Columns Name | SQL TYPE | +|---- |---- | +|id |INT | +|ts |INT | +|dur |INT | +|callid |INT | +|cat |NUM | +|name |NUM | +|depth |INT | +|cookie |INT | +|parent_id |INT | +|argsetid |INT | +|chainId |NUM | +|spanId |NUM | +|parentSpanId |NUM | +|flag |NUM | +|args |NUM | +#### 表描述: +记录中断相关事件。 + ### data_type表 #### 表结构: | Columns Name | SQL TYPE | @@ -287,7 +395,8 @@ ipid: 进程内部编号 |typeId |INT | |desc |NUM | #### 表描述: -此表记录了一个数据类型ID和数据描述的映射。 +此表记录了一个数据类型ID和数据描述的映射。 + ### data_dict表 #### 表结构: | Columns Name | SQL TYPE | @@ -295,7 +404,8 @@ ipid: 进程内部编号 |id |INT | |data |NUM | #### 表描述: -此表记录了一个数据类型ID和字符串的映射。 +此表记录了一个数据类型ID和字符串的映射。 + ### meta表 #### 表结构: | Columns Name | SQL TYPE | @@ -304,3 +414,241 @@ ipid: 进程内部编号 |value |NUM | #### 表描述: 此表记录了数据解析或导出时的一些现场数据,比如使用的trace_streamer版本, 工具的发布时间,数据解析的时间,数据的持续时长,以及原始数据的格式。 + +### clock_event_filter表 +#### 表结构: +| Columns Name | SQL TYPE | +|---- |---- | +|id |INT | +|type |NUM | +|name |NUM | +|cpu |INT | +#### 表描述: +此结构用来维护时钟事件和cpu与唯一的ID做关联 + +### cpu_usage表 +#### 表结构: +| Columns Name | SQL TYPE | +|---- |---- | +|ts |INT | +|dur |INT | +|total_load |REAL | +|user_load |REAL | +|system_load |REAL | +|process_num |INT | +#### 表描述: +total_load: 总负荷 +user_load: 用户负载 +system_load: 系统负载 +process_num: 线程数 + +### diskio表 +#### 表结构: +| Columns Name | SQL TYPE | +|---- |---- | +|ts |INT | +|dur |INT | +|rd |INT | +|wr |INT | +|rd_speed |REAL | +|wr_speed |REAL | +|rd_count |INT | +|wr_count |INT | +|rd_count_speed |REAL | +|wr_count_speed |REAL | +#### 主要字段描述: +rd_sectors_kb:读数据的速度。 +wr_sectors_kb:写入数据的速度。 +ts:时间戳 + +### live_process表 +#### 表结构: +| Columns Name | SQL TYPE | +|---- |---- | +|ts |INT | +|dur |INT | +|cpu_time |INT | +|process_id |INT | +|process_name |NUM | +|parent_process_id |INT | +|uid |INT | +|user_name |NUM | +|cpu_usage |REAL | +|pss_info |INT | +|thread_num |INT | +|disk_writes |INT | +|disk_reads |INT | +#### 主要字段描述: +process_id: 进程id +process_name: 进程名 +parent_process_id: 父进程的id +uid: 用户id +user_name: 用户名 +cpu_usage: cpu使用率 +pss_info: 进程信息 +thread_num: 线程数量 +disk_writes: 磁盘写量 +disk_reads: 磁盘读量 + +### network表 +#### 表结构: +| Columns Name | SQL TYPE | +|---- |---- | +|ts |INT | +|dur |INT | +|tx |INT | +|rx |INT | +|tx_speed |REAL | +|rx_speed |REAL | +|packet_in |INT | +|packet_in_sec |REAL | +|packet_out |INT | +|packet_out_sec |REAL | +|net_type |NUM | +#### 主要字段描述: +ts:时间戳 +tv_sec:时间,秒为单位 +tv_nsec:时间,纳秒为单位 +tx_bytes:网络数据的写入量 +rx_bytes:网络数据的读取量 + +### perf_callchain表 +#### 表结构: +| Columns Name | SQL TYPE | +|---- |---- | +|id |INT | +|sample_id |INT | +|callchain_id |INT | +|vaddr_in_file |INT | +|file_id |INT | +|symbol_id |INT | +#### 主要字段描述: +Sample_id: 与PerfSample中的Sample_id相关联。代表一次采样。 +callchain_id: 调用栈深度。 +vaddr_in_file: 函数在文件中的虚拟地址。 +file_id: 与PerfFiles中的file_id字段相关联。 +symbol_id : 与PerfFiles中的symbol_id相关联。 + +### perf_files表 +#### 表结构: +| Columns Name | SQL TYPE | +|---- |---- | +|id |INT | +|file_id |INT | +|symbol |NUM | +|path |NUM | +#### 主要字段描述: +file_id: 文件编号。 +serial_id: 一个文件中可能有多个函数,serial_id表示函数的编号。 +symbol: 函数名 +path: 文件路径。 + +### perf_report表 +#### 表结构: +| Columns Name | SQL TYPE | +|---- |---- | +|id |INT | +|report_type |NUM | +|report_value |NUM | +#### 主要字段描述: +report_type: 数据类型。取值只有三种类型:config_name(事件类型), workload(抓取的进程名), cmdline(抓取命令)。 +report_value: 对应类型的取值。 + +### perf_sample表 +#### 表结构: +| Columns Name | SQL TYPE | +|---- |---- | +|id |INT | +|sample_id |INT | +|timestamp |INT | +|thread_id |INT | +|event_count |INT | +|event_type_id |INT | +|timestamp_trace |INT | +|cpu_id |INT | +|thread_state |NUM | +#### 主要字段描述: +sample_id: 采样编码。 +timestamp:未进行时钟源同步的时间戳。 +thread_id: 线程号。 +event_count: 采样统计。 +event_type_id: 事件类型编号。与PerfReport表的id字段相关联。 +timestamp_trace:时钟源同步后的时间戳。 +cpu_id: cpu核编号。 +thread_state: 线程状态。采样对应Sched_Waking事件时,为Runing;对应Sched_Switch事件时,为Suspend。其余事件类型,为“-”。 + +### perf_thread表 +#### 表结构: +| Columns Name | SQL TYPE | +|---- |---- | +|id |INT | +|thread_id |INT | +|process_id |INT | +|thread_name |NUM | +#### 表描述: +thread_id: 线程号 +process_id: 进程号 +thread_name: 线程名 + +### process_filter表 +#### 表结构: +| Columns Name | SQL TYPE | +|---- |---- | +|id |INT | +|type |NUM | +|name |NUM | +|ipid |INT | +#### 主要字段描述: +id: 进程id +type: 进程类型 +name: 进程名 +ipid: 该进程表中的id与process表中的id相关联 + +### sched_slice表 +#### 表结构: +| Columns Name | SQL TYPE | +|---- |---- | +|id |INT | +|type |NUM | +|ts |INT | +|dur |INT | +|cpu |INT | +|itid |INT | +|end_state |NUM | +|priority |INT | +#### 主要字段描述: +Dur:状态持续时长 +ts:事件发生事件 +cpu:事件发生在哪个cpu +itid:事件对应哪个utid +end_state:线程的终结状态 + +### stat表 +#### 表结构: +| Columns Name | SQL TYPE | +|---- |---- | +|event_name |NUM | +|stat_type |NUM | +|count |INT | +|serverity |NUM | +|source |NUM | +#### 主要字段描述: +event_name:数据类型 +stat_type:数据状态 +count:数据条数 +severity:严重级别 +source:数据来源 + +### thread_filter表 +#### 表结构: +| Columns Name | SQL TYPE | +|---- |---- | +|id |INT | +|type |NUM | +|name |NUM | +|itid |INT | +#### 主要字段描述: +id:线程id +type:线程类型 +name:线程名称 +itid:该表中的tid与thread表中的tid相关联 diff --git a/host/trace_streamer/doc/des_wakup.md b/host/trace_streamer/doc/des_wakup.md new file mode 100644 index 0000000000000000000000000000000000000000..077374b8cf13146447d80f55037ce0770f17dadc --- /dev/null +++ b/host/trace_streamer/doc/des_wakup.md @@ -0,0 +1,3 @@ +各应用程序对于trace事件的waking和wakeup处理是略有区别的。 +waking是开始唤醒线程,wakeup是线程正式被唤醒,进入runnable(可运行状态) +我们的策略是:被唤醒才是真正进入runnable状态,在没有wakeup事件的情况下,以waking为准。 \ No newline at end of file diff --git a/host/trace_streamer/figures/dump_and_mem.png b/host/trace_streamer/figures/dump_and_mem.png index b7e3cc26ca286702c9ca9869fc203aff34a8da39..886198f131dd54f498c00dce10313e29a992a481 100644 Binary files a/host/trace_streamer/figures/dump_and_mem.png and b/host/trace_streamer/figures/dump_and_mem.png differ diff --git a/host/trace_streamer/gn/BUILD.gn b/host/trace_streamer/gn/BUILD.gn index a44389bdd809eccfeeb146bb62d42242f4a1c6ae..0f45342d802cdbc62750ca43115d431cc5037f32 100644 --- a/host/trace_streamer/gn/BUILD.gn +++ b/host/trace_streamer/gn/BUILD.gn @@ -11,6 +11,7 @@ # See the License for the specific language governing permissions and # limitations under the License. print("target_os", target_os) +print("target_name", target) group("default_deps") { public_configs = [ ":default_config" ] public_deps = [] @@ -24,10 +25,16 @@ config("default_config") { config("trace_cfg") { cflags_cc = [ "-std=c++17", - "-fno-rtti", - "-fno-exceptions", + + # "-std=gnu++17", "-fvisibility=hidden", ] + if (!is_test) { + cflags_cc += [ + "-fno-rtti", + # "-fno-exceptions", + ] + } } config("visibility_hidden") { @@ -41,12 +48,11 @@ config("default") { cflags = [ "-fstrict-aliasing", - "-fPIC", "-g", "-Wformat", ] - if (is_linux) { + if (is_linux || is_macx) { cflags += [ "-Wa,--noexecstack", "-fcolor-diagnostics", @@ -55,25 +61,35 @@ config("default") { ] if (!use_wasm) { cflags += [ - "-fPIE", "-fstack-protector-strong", "-fstack-protector-all", "-D_FORTIFY_SOURCE=2 -O2", + "-D SUPPORTTHREAD", # if support thread ] } - libs += [ - "pthread", - "rt", - ] - if (is_debug) { - libs += [ "dl" ] + + # cflags += [ "-D USE_VTABLE" ] + cflags += [ "-D BINDER_EXP" ] + libs += [ "pthread" ] + if (!is_macx) { + libs += [ "rt" ] + } + if (!is_win) { + cflags += [ + "-fPIE", + "-fPIC", + ] + } + if (is_win) { + cflags += [ "/W0" ] + defines = [ "WIN32_LEAN_AND_MEAN" ] } } } config("symbols") { cflags = [ "-O0" ] - if (is_linux) { + if (is_linux || is_macx) { cflags += [ "-funwind-tables" ] } } @@ -85,42 +101,60 @@ config("release") { ] cflags += [ "-O3" ] - ldflags = [ - "-fuse-ld=gold", - "-fstack-protector", - "-Wl,--gc-sections", - "-Wl,-O1", - "-fpie", - "-pie", - ] + ldflags = [ "-fstack-protector" ] + if (!is_macx) { + ldflags += [ + "-fuse-ld=gold", + "-Wl,--gc-sections", + "-Wl,-O1", + ] + } + + if (!is_win && !is_macx) { + ldflags += [ + "-fPIC", + "-fpie", + "-pie", + ] + } defines = [ "NDEBUG" ] } config("shared_library") { - ldflags = [ "-fPIC" ] + if (!is_win) { + ldflags = [ "-fPIC" ] + } } config("executable") { print("use_wasm", use_wasm) ldflags = [] - if (is_linux && !use_wasm) { - ldflags += [ - # "-Wl,-rpath=\$ORIGIN/.", + if (is_linux || (is_macx && !use_wasm)) { + ldflags += [] + } + if (!is_macx && !use_wasm) { + ldflags = [ + "-Wl,--disable-new-dtags", + "-Wl,-z,noexecstack", + "-lrt", + "-fuse-ld=gold", "-Wl,-z,now", - - # "-Wl,-rpath-link=.", "-Wl,-z,relro", - "-lrt", "-fpie", "-pie", - "-Wl,-z,noexecstack", - "-Wl,--disable-new-dtags", - - # "-s", # delete sambols ] } - if (!is_debug) { + if (is_macx) { + ldflags += [ + "-Wl,-U,__sanitizer_options_link_helper", + "-fdata-sections", + "-ffunction-sections", + ] + } + if (!is_debug && !is_macx) { ldflags += [ "-s" ] + } else if (!is_debug && is_macx) { + ldflags += [ "-dead_strip" ] } } diff --git a/host/trace_streamer/gn/CONFIG.gn b/host/trace_streamer/gn/CONFIG.gn index babf9755e98d0478a5f2d895668a9d296c026c0d..585c6e9870cf0fcdb9e97fda1bb580f845d6defe 100644 --- a/host/trace_streamer/gn/CONFIG.gn +++ b/host/trace_streamer/gn/CONFIG.gn @@ -12,32 +12,43 @@ # limitations under the License. is_win = false is_linux = false +is_macx = false +is_protoc = false declare_args() { ar = "ar" is_debug = true use_wasm = false is_test = false + testonly = false + is_fuzz = false + is_macx = false + target = "trace_streamer" } if (target_os == "linux") { - is_win = false is_linux = true - is_test = false +} else if (target_os == "macx") { + is_macx = true } else if (target_os == "windows") { is_win = true - is_linux = false - is_test = false -} else if (target_os == "wasm") { - is_win = false - is_linux = true +} else { + print("unknown platform " + target_os) + exit(-1) +} + +if (target == "wasm") { use_wasm = true - is_test = false -} else if (target_os == "test") { - is_win = false - is_linux = true - use_wasm = false +} else if (target == "test") { is_test = true + testonly = true +} else if (target == "fuzz") { + is_fuzz = true + testonly = true +} else if (target == "protoc") { + is_protoc = true +} else if (target == "trace_streamer" || target == "streamer") { + print("build " + target) } else { - print("unknown platform " + target_os) + print("unknown target " + target_os) exit(-1) } @@ -59,7 +70,9 @@ if (!is_debug) { set_defaults("ohos_source_set") { configs = default_configs } - +set_defaults("ohos_shared_library") { + configs = default_configs +} set_defaults("executable") { configs = default_configs configs += [ "//gn:executable" ] diff --git a/host/trace_streamer/gn/toolchain/BUILD.gn b/host/trace_streamer/gn/toolchain/BUILD.gn index e1b24fd43144cd73b0ff6dfff19499fef1b9f63c..0e34297f615d91494cf8880d6b7716dd680b1ff3 100644 --- a/host/trace_streamer/gn/toolchain/BUILD.gn +++ b/host/trace_streamer/gn/toolchain/BUILD.gn @@ -13,12 +13,14 @@ import("//gn/wasm.gni") declare_args() { - if (target_os == "linux" || target_os == "wasm" || target_os == "test") { + if (target_os == "linux" || target_os == "macx") { cc = "/usr/bin/clang" cxx = "/usr/bin/clang++" + pic = "-fPIC" } else if (target_os == "windows") { - cc = "~/mingw-w64/ohos/linux-x86_64/clang-mingw/bin/clang" - cxx = "~/mingw-w64/ohos/linux-x86_64/clang-mingw/bin/clang++" + cc = "clang.exe" + cxx = "clang++.exe" + pic = "" } if (use_wasm == true) { print("make_wasm") @@ -26,7 +28,6 @@ declare_args() { print("no make_wasm") } cc_wrapper = "" - is_mac = false } toolchain("wasm") { # emsdk_dir and em_config are defined in wasm.gni. @@ -124,7 +125,7 @@ toolchain("gcc_like") { tool("cxx") { depfile = "{{output}}.d" # must be defined - command = "$cxx -o {{output}} -MMD -MF $depfile {{defines}} -fPIC {{include_dirs}} {{cflags}} {{cflags_cc}} -c {{source}}" + command = "$cxx -o {{output}} -MMD -MF $depfile {{defines}} $pic {{include_dirs}} {{cflags}} {{cflags_cc}} -c {{source}}" outputfiles = "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o" outputs = [ outputfiles ] @@ -133,7 +134,7 @@ toolchain("gcc_like") { tool("cc") { depfile = "{{output}}.d" - command = "$cc -o {{output}} -MMD -MF $depfile {{defines}} -fPIC {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}}" + command = "$cc -o {{output}} -MMD -MF $depfile {{defines}} $pic {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}}" outputfiles = "{{source_out_dir}}/{{target_output_name}}.{{source_name_part}}.o" outputs = [ outputfiles ] diff --git a/host/trace_streamer/gn/wasm.gni b/host/trace_streamer/gn/wasm.gni index 7209ff6666891129c98ee7cce901d63564e7bd88..3d030377308a12b790fb37f0de1d4947cea3c130 100644 --- a/host/trace_streamer/gn/wasm.gni +++ b/host/trace_streamer/gn/wasm.gni @@ -61,10 +61,10 @@ template("wasm_lib") { ] } else { _target_ldflags += [ - "-g2", # Required for getting C++ symbol names. + # "-g2", # Required for getting C++ symbol names. "-O3", - "-s", - "ASSERTIONS=1", + # "-s", + # "ASSERTIONS=1", ] } diff --git a/host/trace_streamer/prebuilts/buildprotobuf/libprotobuf_lite_la_SOURCES.pri b/host/trace_streamer/prebuilts/buildprotobuf/libprotobuf_lite_la_SOURCES.pri deleted file mode 100644 index 39c051faf41b82d7cf1e62dda7c147eeb95d9494..0000000000000000000000000000000000000000 --- a/host/trace_streamer/prebuilts/buildprotobuf/libprotobuf_lite_la_SOURCES.pri +++ /dev/null @@ -1,64 +0,0 @@ -# Copyright (C) 2021 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. - message("qmake" $${PROTOBUDIR}"/src") -win32 { -SOURCES += $${PROTOBUDIR}/src/google/protobuf/io/io_win32.cc -} -SOURCES += \ - $${PROTOBUDIR}/src/google/protobuf/stubs/bytestream.cc \ - $${PROTOBUDIR}/src/google/protobuf/stubs/common.cc \ - $${PROTOBUDIR}/src/google/protobuf/stubs/int128.cc \ -# $${PROTOBUDIR}/src/google/protobuf/stubs/once.cc \ - $${PROTOBUDIR}/src/google/protobuf/stubs/int128.h \ -# $${PROTOBUDIR}/src/google/protobuf/io/io_win32.cc \ - $${PROTOBUDIR}/src/google/protobuf/stubs/status.cc \ - $${PROTOBUDIR}/src/google/protobuf/stubs/statusor.cc \ - $${PROTOBUDIR}/src/google/protobuf/stubs/statusor.h \ - $${PROTOBUDIR}/src/google/protobuf/stubs/stringpiece.cc \ - $${PROTOBUDIR}/src/google/protobuf/stubs/stringprintf.cc \ - $${PROTOBUDIR}/src/google/protobuf/stubs/structurally_valid.cc \ - $${PROTOBUDIR}/src/google/protobuf/stubs/strutil.cc \ - $${PROTOBUDIR}/src/google/protobuf/stubs/time.cc \ -# $${PROTOBUDIR}/src/google/protobuf/any_lite.cc \ - $${PROTOBUDIR}/src/google/protobuf/arena.cc \ -# $${PROTOBUDIR}/src/google/protobuf/arenastring.cc \ - $${PROTOBUDIR}/src/google/protobuf/extension_set.cc \ - $${PROTOBUDIR}/src/google/protobuf/generated_enum_util.cc \ - $${PROTOBUDIR}/src/google/protobuf/generated_message_util.cc \ -# $${PROTOBUDIR}/src/google/protobuf/generated_message_table_driven_lite.cc \ - $${PROTOBUDIR}/src/google/protobuf/implicit_weak_message.cc \ - $${PROTOBUDIR}/src/google/protobuf/message_lite.cc \ - $${PROTOBUDIR}/src/google/protobuf/parse_context.cc \ - $${PROTOBUDIR}/src/google/protobuf/repeated_field.cc \ -# $${PROTOBUDIR}/src/google/protobuf/stubs/atomicops_internals_x86_gcc.cc \ -# $${PROTOBUDIR}/src/google/protobuf/stubs/atomicops_internals_x86_msvc.cc \ - $${PROTOBUDIR}/src/google/protobuf/wire_format_lite.cc \ - $${PROTOBUDIR}/src/google/protobuf/io/coded_stream.cc \ - $${PROTOBUDIR}/src/google/protobuf/io/strtod.cc \ - $${PROTOBUDIR}/src/google/protobuf/io/zero_copy_stream.cc \ - $${PROTOBUDIR}/src/google/protobuf/io/zero_copy_stream_impl.cc \ - $${PROTOBUDIR}/src/google/protobuf/io/zero_copy_stream_impl_lite.cc - -HEADERS += \ - $${PROTOBUDIR}/src/google/protobuf/stubs/bytestream.h \ - $${PROTOBUDIR}/src/google/protobuf/stubs/hash.h \ - $${PROTOBUDIR}/src/google/protobuf/io/coded_stream_inl.h \ -# $${PROTOBUDIR}/src/google/protobuf/generated_message_table_driven_lite.h \ - $${PROTOBUDIR}/src/google/protobuf/stubs/time.h \ - $${PROTOBUDIR}/src/google/protobuf/stubs/stringprintf.h \ - $${PROTOBUDIR}/src/google/protobuf/stubs/stringpiece.h \ - $${PROTOBUDIR}/src/google/protobuf/stubs/status.h \ - $${PROTOBUDIR}/src/google/protobuf/stubs/status_macros.h \ -# $${PROTOBUDIR}/src/google/protobuf/io/io_win32.h \ - $${PROTOBUDIR}/src/google/protobuf/stubs/map_util.h \ - $${PROTOBUDIR}/src/google/protobuf/stubs/mathutil.h diff --git a/host/trace_streamer/prebuilts/buildprotobuf/libprotoc_la_SOURCES.pri b/host/trace_streamer/prebuilts/buildprotobuf/libprotoc_la_SOURCES.pri deleted file mode 100644 index ed1da78266e36cf066115d956dfe442f8c2743d2..0000000000000000000000000000000000000000 --- a/host/trace_streamer/prebuilts/buildprotobuf/libprotoc_la_SOURCES.pri +++ /dev/null @@ -1,173 +0,0 @@ -# Copyright (C) 2021 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. - message("qmake" $${PROTOBUDIR}"/src/google/protobuf/compiler/") -SOURCES += \ - $${PROTOBUDIR}/src/google/protobuf/compiler/code_generator.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/command_line_interface.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/plugin.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/plugin.pb.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/subprocess.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/zip_writer.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/cpp/cpp_enum.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/cpp/cpp_enum_field.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/cpp/cpp_extension.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/cpp/cpp_field.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/cpp/cpp_file.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/cpp/cpp_generator.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/cpp/cpp_helpers.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/cpp/cpp_map_field.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/cpp/cpp_message.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/cpp/cpp_message_field.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/cpp/cpp_padding_optimizer.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/cpp/cpp_primitive_field.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/cpp/cpp_service.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/cpp/cpp_string_field.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_context.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_enum.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_enum_lite.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_enum_field.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_enum_field_lite.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_extension.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_extension_lite.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_field.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_file.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_generator.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_generator_factory.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_helpers.cc \ -# $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_lazy_message_field.cc \ -# $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_lazy_message_field_lite.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_map_field.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_map_field_lite.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_message_lite.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_message_builder.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_message_builder_lite.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_message_field.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_message_field_lite.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_name_resolver.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_primitive_field.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_primitive_field_lite.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_shared_code_generator.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_service.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_string_field.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_string_field_lite.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_doc_comment.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/js/js_generator.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/js/well_known_types_embed.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/objectivec/objectivec_enum.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/objectivec/objectivec_enum_field.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/objectivec/objectivec_extension.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/objectivec/objectivec_field.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/objectivec/objectivec_file.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/objectivec/objectivec_generator.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/objectivec/objectivec_helpers.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/objectivec/objectivec_map_field.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/objectivec/objectivec_message.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/objectivec/objectivec_message_field.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/objectivec/objectivec_oneof.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.cc \ -# $${PROTOBUDIR}/src/google/protobuf/compiler/php/php_generator.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/python/python_generator.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/ruby/ruby_generator.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/csharp/csharp_doc_comment.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/csharp/csharp_enum.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/csharp/csharp_enum_field.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/csharp/csharp_field_base.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/csharp/csharp_generator.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_message.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/csharp/csharp_helpers.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/csharp/csharp_map_field.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/csharp/csharp_message.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/csharp/csharp_message_field.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/csharp/csharp_primitive_field.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/csharp/csharp_reflection_class.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/csharp/csharp_source_generator_base.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/csharp/csharp_wrapper_field.cc \ - -HEADERS += \ - $${PROTOBUDIR}/src/google/protobuf/compiler/cpp/cpp_padding_optimizer.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/cpp/cpp_primitive_field.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/cpp/cpp_options.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/cpp/cpp_service.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/cpp/cpp_string_field.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_enum_field.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_enum_field_lite.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_context.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_enum.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_enum_lite.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_extension.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_field.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_map_field.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_map_field_lite.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_helpers.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_file.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_message_field.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_generator_factory.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_extension_lite.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_message_field_lite.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_message.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_message_lite.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_message_builder.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_message_builder_lite.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_name_resolver.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_options.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_primitive_field.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_primitive_field_lite.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_shared_code_generator.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_service.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_string_field.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/objectivec/objectivec_enum.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_string_field_lite.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/scc.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/subprocess.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/zip_writer.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/cpp/cpp_enum.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/cpp/cpp_enum_field.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/cpp/cpp_extension.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/cpp/cpp_field.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/cpp/cpp_file.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/cpp/cpp_helpers.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/cpp/cpp_map_field.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/cpp/cpp_message.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/cpp/cpp_message_field.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/cpp/cpp_message_layout_helper.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/java/java_doc_comment.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/objectivec/objectivec_enum_field.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/objectivec/objectivec_extension.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/objectivec/objectivec_field.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/objectivec/objectivec_file.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/objectivec/objectivec_helpers.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/objectivec/objectivec_map_field.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/objectivec/objectivec_message.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/objectivec/objectivec_message_field.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/objectivec/objectivec_nsobject_methods.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/objectivec/objectivec_oneof.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/objectivec/objectivec_primitive_field.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/csharp/csharp_doc_comment.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/csharp/csharp_wrapper_field.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/csharp/csharp_repeated_enum_field.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/csharp/csharp_repeated_message_field.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/csharp/csharp_repeated_primitive_field.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/csharp/csharp_source_generator_base.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/csharp/csharp_message_field.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/csharp/csharp_options.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/csharp/csharp_primitive_field.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/csharp/csharp_reflection_class.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/csharp/csharp_enum.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/csharp/csharp_enum_field.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/csharp/csharp_field_base.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/csharp/csharp_helpers.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/csharp/csharp_map_field.h \ - $${PROTOBUDIR}/src/google/protobuf/compiler/csharp/csharp_message.h \ diff --git a/host/trace_streamer/prebuilts/buildprotobuf/protobuf.pri b/host/trace_streamer/prebuilts/buildprotobuf/protobuf.pri deleted file mode 100644 index 1bfc0847435faaf99b4e88841f30d67c37d65530..0000000000000000000000000000000000000000 --- a/host/trace_streamer/prebuilts/buildprotobuf/protobuf.pri +++ /dev/null @@ -1,69 +0,0 @@ -# Copyright (C) 2021 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. -PROTOBUDIR = $$PWD/../../third_party/protobuf - message("qmake" $${PROTOBUDIR}"/src/google/protobuf/") -SOURCES += \ -$${PROTOBUDIR}/src/google/protobuf/any.cc \ -$${PROTOBUDIR}/src/google/protobuf/any_lite.cc \ - $${PROTOBUDIR}/src/google/protobuf/any.pb.cc \ - $${PROTOBUDIR}/src/google/protobuf/api.pb.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/importer.cc \ - $${PROTOBUDIR}/src/google/protobuf/compiler/parser.cc \ - $${PROTOBUDIR}/src/google/protobuf/descriptor.cc \ - $${PROTOBUDIR}/src/google/protobuf/descriptor.pb.cc \ - $${PROTOBUDIR}/src/google/protobuf/descriptor_database.cc \ - $${PROTOBUDIR}/src/google/protobuf/duration.pb.cc \ - $${PROTOBUDIR}/src/google/protobuf/dynamic_message.cc \ - $${PROTOBUDIR}/src/google/protobuf/empty.pb.cc \ - $${PROTOBUDIR}/src/google/protobuf/extension_set_heavy.cc \ - $${PROTOBUDIR}/src/google/protobuf/field_mask.pb.cc \ - $${PROTOBUDIR}/src/google/protobuf/generated_message_reflection.cc \ - $${PROTOBUDIR}/src/google/protobuf/generated_message_table_driven.cc \ - $${PROTOBUDIR}/src/google/protobuf/io/gzip_stream.cc \ - $${PROTOBUDIR}/src/google/protobuf/io/printer.cc \ - $${PROTOBUDIR}/src/google/protobuf/io/tokenizer.cc \ - $${PROTOBUDIR}/src/google/protobuf/map_field.cc \ - $${PROTOBUDIR}/src/google/protobuf/message.cc \ - $${PROTOBUDIR}/src/google/protobuf/reflection_ops.cc \ - $${PROTOBUDIR}/src/google/protobuf/service.cc \ - $${PROTOBUDIR}/src/google/protobuf/source_context.pb.cc \ - $${PROTOBUDIR}/src/google/protobuf/struct.pb.cc \ -# $${PROTOBUDIR}/src/google/protobuf/stubs/mathlimits.cc \ - $${PROTOBUDIR}/src/google/protobuf/stubs/substitute.cc \ - $${PROTOBUDIR}/src/google/protobuf/text_format.cc \ - $${PROTOBUDIR}/src/google/protobuf/timestamp.pb.cc \ - $${PROTOBUDIR}/src/google/protobuf/type.pb.cc \ - $${PROTOBUDIR}/src/google/protobuf/unknown_field_set.cc \ -# $${PROTOBUDIR}/src/google/protobuf/util/delimited_message_util.cc \ - $${PROTOBUDIR}/src/google/protobuf/util/field_comparator.cc \ - $${PROTOBUDIR}/src/google/protobuf/util/field_mask_util.cc \ - $${PROTOBUDIR}/src/google/protobuf/util/internal/datapiece.cc \ - $${PROTOBUDIR}/src/google/protobuf/util/internal/default_value_objectwriter.cc \ - $${PROTOBUDIR}/src/google/protobuf/util/internal/error_listener.cc \ - $${PROTOBUDIR}/src/google/protobuf/util/internal/field_mask_utility.cc \ - $${PROTOBUDIR}/src/google/protobuf/util/internal/json_escaping.cc \ - $${PROTOBUDIR}/src/google/protobuf/util/internal/json_objectwriter.cc \ - $${PROTOBUDIR}/src/google/protobuf/util/internal/json_stream_parser.cc \ - $${PROTOBUDIR}/src/google/protobuf/util/internal/object_writer.cc \ - $${PROTOBUDIR}/src/google/protobuf/util/internal/proto_writer.cc \ - $${PROTOBUDIR}/src/google/protobuf/util/internal/protostream_objectsource.cc \ - $${PROTOBUDIR}/src/google/protobuf/util/internal/protostream_objectwriter.cc \ - $${PROTOBUDIR}/src/google/protobuf/util/internal/type_info.cc \ - $${PROTOBUDIR}/src/google/protobuf/util/internal/type_info_test_helper.cc \ - $${PROTOBUDIR}/src/google/protobuf/util/internal/utility.cc \ - $${PROTOBUDIR}/src/google/protobuf/util/json_util.cc \ - $${PROTOBUDIR}/src/google/protobuf/util/message_differencer.cc \ - $${PROTOBUDIR}/src/google/protobuf/util/time_util.cc \ - $${PROTOBUDIR}/src/google/protobuf/util/type_resolver_util.cc \ - $${PROTOBUDIR}/src/google/protobuf/wire_format.cc \ - $${PROTOBUDIR}/src/google/protobuf/wrappers.pb.cc diff --git a/host/trace_streamer/prebuilts/buildprotobuf/protobufbuild.gn b/host/trace_streamer/prebuilts/buildprotobuf/protobufbuild.gn new file mode 100644 index 0000000000000000000000000000000000000000..235114d33023d86425bac943fc756892dedf3c22 --- /dev/null +++ b/host/trace_streamer/prebuilts/buildprotobuf/protobufbuild.gn @@ -0,0 +1,346 @@ +# Copyright (c) 2021 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. + +import("//build/ohos.gni") + +config("protobuf_config") { + include_dirs = [ "src" ] +} +protobuf_dir = "src/google/protobuf" +protobuf_lite_src = [ + "$protobuf_dir/any_lite.cc", + "$protobuf_dir/arena.cc", + "$protobuf_dir/extension_set.cc", + "$protobuf_dir/generated_enum_util.cc", + "$protobuf_dir/generated_message_table_driven_lite.cc", + "$protobuf_dir/generated_message_util.cc", + "$protobuf_dir/implicit_weak_message.cc", + "$protobuf_dir/io/coded_stream.cc", + "$protobuf_dir/io/io_win32.cc", + "$protobuf_dir/io/strtod.cc", + "$protobuf_dir/io/zero_copy_stream.cc", + "$protobuf_dir/io/zero_copy_stream_impl.cc", + "$protobuf_dir/io/zero_copy_stream_impl_lite.cc", + "$protobuf_dir/message_lite.cc", + "$protobuf_dir/parse_context.cc", + "$protobuf_dir/repeated_field.cc", + "$protobuf_dir/stubs/bytestream.cc", + "$protobuf_dir/stubs/common.cc", + "$protobuf_dir/stubs/int128.cc", + "$protobuf_dir/stubs/status.cc", + "$protobuf_dir/stubs/statusor.cc", + "$protobuf_dir/stubs/stringpiece.cc", + "$protobuf_dir/stubs/stringprintf.cc", + "$protobuf_dir/stubs/structurally_valid.cc", + "$protobuf_dir/stubs/strutil.cc", + "$protobuf_dir/stubs/time.cc", + "$protobuf_dir/wire_format_lite.cc", +] + +protobuf_src = [ + "$protobuf_dir/any.cc", + "$protobuf_dir/any.pb.cc", + "$protobuf_dir/api.pb.cc", + "$protobuf_dir/compiler/importer.cc", + "$protobuf_dir/compiler/parser.cc", + "$protobuf_dir/descriptor.cc", + "$protobuf_dir/descriptor.pb.cc", + "$protobuf_dir/descriptor_database.cc", + "$protobuf_dir/duration.pb.cc", + "$protobuf_dir/dynamic_message.cc", + "$protobuf_dir/empty.pb.cc", + "$protobuf_dir/extension_set_heavy.cc", + "$protobuf_dir/field_mask.pb.cc", + "$protobuf_dir/generated_message_reflection.cc", + "$protobuf_dir/generated_message_table_driven.cc", + "$protobuf_dir/io/gzip_stream.cc", + "$protobuf_dir/io/printer.cc", + "$protobuf_dir/io/tokenizer.cc", + "$protobuf_dir/map_field.cc", + "$protobuf_dir/message.cc", + "$protobuf_dir/reflection_ops.cc", + "$protobuf_dir/service.cc", + "$protobuf_dir/source_context.pb.cc", + "$protobuf_dir/struct.pb.cc", + "$protobuf_dir/stubs/substitute.cc", + "$protobuf_dir/text_format.cc", + "$protobuf_dir/timestamp.pb.cc", + "$protobuf_dir/type.pb.cc", + "$protobuf_dir/unknown_field_set.cc", + "$protobuf_dir/util/delimited_message_util.cc", + "$protobuf_dir/util/field_comparator.cc", + "$protobuf_dir/util/field_mask_util.cc", + "$protobuf_dir/util/internal/datapiece.cc", + "$protobuf_dir/util/internal/default_value_objectwriter.cc", + "$protobuf_dir/util/internal/error_listener.cc", + "$protobuf_dir/util/internal/field_mask_utility.cc", + "$protobuf_dir/util/internal/json_escaping.cc", + "$protobuf_dir/util/internal/json_objectwriter.cc", + "$protobuf_dir/util/internal/json_stream_parser.cc", + "$protobuf_dir/util/internal/object_writer.cc", + "$protobuf_dir/util/internal/proto_writer.cc", + "$protobuf_dir/util/internal/protostream_objectsource.cc", + "$protobuf_dir/util/internal/protostream_objectwriter.cc", + "$protobuf_dir/util/internal/type_info.cc", + "$protobuf_dir/util/internal/type_info_test_helper.cc", + "$protobuf_dir/util/internal/utility.cc", + "$protobuf_dir/util/json_util.cc", + "$protobuf_dir/util/message_differencer.cc", + "$protobuf_dir/util/time_util.cc", + "$protobuf_dir/util/type_resolver_util.cc", + "$protobuf_dir/wire_format.cc", + "$protobuf_dir/wrappers.pb.cc", +] +if (use_wasm) { + source_set("protobuf_lite") { + sources = protobuf_lite_src + include_dirs = [ + "$protobuf_dir/**/*.h", + "$protobuf_dir/**/*.inc", + "src", + ] + + cflags_cc = [ "-Wno-sign-compare" ] + cflags = [ + "-Wno-sign-compare", + "-D HAVE_PTHREAD", + "-std=c++17", + ] + + #configs = default_configs + + public_configs = [ ":protobuf_config" ] + } +} else { + source_set("protobuf_lite") { + sources = protobuf_lite_src + include_dirs = [ + "$protobuf_dir/**/*.h", + "$protobuf_dir/**/*.inc", + "src", + ] + + cflags_cc = [ "-Wno-sign-compare" ] + cflags = [ + "-Wno-sign-compare", + "-D HAVE_PTHREAD", + "-std=c++17", + ] + + # configs = default_configs + + public_configs = [ ":protobuf_config" ] + } +} +if (use_wasm) { + source_set("protobuf") { + sources = protobuf_src + include_dirs = [ + "$protobuf_dir/**/*.h", + "$protobuf_dir/**/*.inc", + "src", + ] + cflags_cc = [ "-Wno-sign-compare" ] + cflags = [ + "-Wno-sign-compare", + "-D HAVE_PTHREAD", + "-std=c++17", + ] + + deps = [ ":protobuf_lite" ] + + #configs = default_configs + + public_configs = [ ":protobuf_config" ] + } +} else { + source_set("protobuf") { + sources = protobuf_src + include_dirs = [ + "$protobuf_dir/**/*.h", + "$protobuf_dir/**/*.inc", + "src", + ] + + #cflags_cc = [ + # "-Wno-sign-compare", + # "-ftrapv", + # "-fstack-protector-strong", + # "-fstack-protector-all", + # "-D_FORTIFY_SOURCE=2 -O2", + + #] + cflags = [ + "-Wno-sign-compare", + "-D HAVE_PTHREAD", + "-ftrapv", + "-fstack-protector-strong", + "-fstack-protector-all", + "-D_FORTIFY_SOURCE=2 -O2", + "-std=c++17", + + # "-Wl,--disable-new-dtags,--rpath,/libpath1:/libpath2" + ] + + ldflags = [ "-fstack-protector" ] + if (!is_macx) { + ldflags += [ + "-fuse-ld=gold", + "-Wl,--gc-sections", + "-Wl,-O1", + "-fpie", + "-pie", + ] + } + + if (!is_win) { + cflags += [ + "-fPIE", + "-fPIC", + ] + } + + deps = [ ":protobuf_lite" ] + + public_configs = [ ":protobuf_config" ] + } + source_set("protoc_lib") { + sources = [ + "$protobuf_dir/compiler/code_generator.cc", + "$protobuf_dir/compiler/command_line_interface.cc", + "$protobuf_dir/compiler/cpp/cpp_enum.cc", + "$protobuf_dir/compiler/cpp/cpp_enum_field.cc", + "$protobuf_dir/compiler/cpp/cpp_extension.cc", + "$protobuf_dir/compiler/cpp/cpp_field.cc", + "$protobuf_dir/compiler/cpp/cpp_file.cc", + "$protobuf_dir/compiler/cpp/cpp_generator.cc", + "$protobuf_dir/compiler/cpp/cpp_helpers.cc", + "$protobuf_dir/compiler/cpp/cpp_map_field.cc", + "$protobuf_dir/compiler/cpp/cpp_message.cc", + "$protobuf_dir/compiler/cpp/cpp_message_field.cc", + "$protobuf_dir/compiler/cpp/cpp_padding_optimizer.cc", + "$protobuf_dir/compiler/cpp/cpp_primitive_field.cc", + "$protobuf_dir/compiler/cpp/cpp_service.cc", + "$protobuf_dir/compiler/cpp/cpp_string_field.cc", + "$protobuf_dir/compiler/csharp/csharp_doc_comment.cc", + "$protobuf_dir/compiler/csharp/csharp_enum.cc", + "$protobuf_dir/compiler/csharp/csharp_enum_field.cc", + "$protobuf_dir/compiler/csharp/csharp_field_base.cc", + "$protobuf_dir/compiler/csharp/csharp_generator.cc", + "$protobuf_dir/compiler/csharp/csharp_helpers.cc", + "$protobuf_dir/compiler/csharp/csharp_map_field.cc", + "$protobuf_dir/compiler/csharp/csharp_message.cc", + "$protobuf_dir/compiler/csharp/csharp_message_field.cc", + "$protobuf_dir/compiler/csharp/csharp_primitive_field.cc", + "$protobuf_dir/compiler/csharp/csharp_reflection_class.cc", + "$protobuf_dir/compiler/csharp/csharp_repeated_enum_field.cc", + "$protobuf_dir/compiler/csharp/csharp_repeated_message_field.cc", + "$protobuf_dir/compiler/csharp/csharp_repeated_primitive_field.cc", + "$protobuf_dir/compiler/csharp/csharp_source_generator_base.cc", + "$protobuf_dir/compiler/csharp/csharp_wrapper_field.cc", + "$protobuf_dir/compiler/java/java_context.cc", + "$protobuf_dir/compiler/java/java_doc_comment.cc", + "$protobuf_dir/compiler/java/java_enum.cc", + "$protobuf_dir/compiler/java/java_enum_field.cc", + "$protobuf_dir/compiler/java/java_enum_field_lite.cc", + "$protobuf_dir/compiler/java/java_enum_lite.cc", + "$protobuf_dir/compiler/java/java_extension.cc", + "$protobuf_dir/compiler/java/java_extension_lite.cc", + "$protobuf_dir/compiler/java/java_field.cc", + "$protobuf_dir/compiler/java/java_file.cc", + "$protobuf_dir/compiler/java/java_generator.cc", + "$protobuf_dir/compiler/java/java_generator_factory.cc", + "$protobuf_dir/compiler/java/java_helpers.cc", + "$protobuf_dir/compiler/java/java_map_field.cc", + "$protobuf_dir/compiler/java/java_map_field_lite.cc", + "$protobuf_dir/compiler/java/java_message.cc", + "$protobuf_dir/compiler/java/java_message_builder.cc", + "$protobuf_dir/compiler/java/java_message_builder_lite.cc", + "$protobuf_dir/compiler/java/java_message_field.cc", + "$protobuf_dir/compiler/java/java_message_field_lite.cc", + "$protobuf_dir/compiler/java/java_message_lite.cc", + "$protobuf_dir/compiler/java/java_name_resolver.cc", + "$protobuf_dir/compiler/java/java_primitive_field.cc", + "$protobuf_dir/compiler/java/java_primitive_field_lite.cc", + "$protobuf_dir/compiler/java/java_service.cc", + "$protobuf_dir/compiler/java/java_shared_code_generator.cc", + "$protobuf_dir/compiler/java/java_string_field.cc", + "$protobuf_dir/compiler/java/java_string_field_lite.cc", + "$protobuf_dir/compiler/js/js_generator.cc", + "$protobuf_dir/compiler/js/well_known_types_embed.cc", + "$protobuf_dir/compiler/objectivec/objectivec_enum.cc", + "$protobuf_dir/compiler/objectivec/objectivec_enum_field.cc", + "$protobuf_dir/compiler/objectivec/objectivec_extension.cc", + "$protobuf_dir/compiler/objectivec/objectivec_field.cc", + "$protobuf_dir/compiler/objectivec/objectivec_file.cc", + "$protobuf_dir/compiler/objectivec/objectivec_generator.cc", + "$protobuf_dir/compiler/objectivec/objectivec_helpers.cc", + "$protobuf_dir/compiler/objectivec/objectivec_map_field.cc", + "$protobuf_dir/compiler/objectivec/objectivec_message.cc", + "$protobuf_dir/compiler/objectivec/objectivec_message_field.cc", + "$protobuf_dir/compiler/objectivec/objectivec_oneof.cc", + "$protobuf_dir/compiler/objectivec/objectivec_primitive_field.cc", + "$protobuf_dir/compiler/php/php_generator.cc", + "$protobuf_dir/compiler/plugin.cc", + "$protobuf_dir/compiler/plugin.pb.cc", + "$protobuf_dir/compiler/python/python_generator.cc", + "$protobuf_dir/compiler/ruby/ruby_generator.cc", + "$protobuf_dir/compiler/subprocess.cc", + "$protobuf_dir/compiler/zip_writer.cc", + ] + include_dirs = [ + "$protobuf_dir/**/*.h", + "$protobuf_dir/**/*.inc", + "src", + ] + if (!use_wasm) { + configs = default_configs + } + cflags_cc = [ + "-Wno-sign-compare", + "-Wno-unused-function", + "-Wno-unused-private-field", + + # "-std=gnu++17", + ] + cflags = [ + "-Wno-sign-compare", + "-D HAVE_PTHREAD", + "-Wno-unused-function", + "-std=c++17", + + # "-Wl,--disable-new-dtags,--rpath,/libpath1:/libpath2" + ] + + deps = [ + ":protobuf", + ":protobuf_lite", + ] + + public_configs = [ ":protobuf_config" ] + } + executable("protoc") { + sources = [ "$protobuf_dir/compiler/main.cc" ] + include_dirs = [ + "$protobuf_dir/**/*.h", + "$protobuf_dir/**/*.inc", + "src", + ] + deps = [ ":protoc_lib" ] + cflags_cc = [ "-Wno-sign-compare" ] + cflags = [ + "-Wno-sign-compare", + "-D HAVE_PTHREAD", + ] + } +} diff --git a/host/trace_streamer/src/base/base.pri b/host/trace_streamer/prebuilts/buildsqlite/sqlite3build.gn similarity index 38% rename from host/trace_streamer/src/base/base.pri rename to host/trace_streamer/prebuilts/buildsqlite/sqlite3build.gn index e972a9228132e178c5b570e684b8fe7860f11f54..30fdd67c0bee79dfb198b30dadc15fe185738c19 100644 --- a/host/trace_streamer/src/base/base.pri +++ b/host/trace_streamer/prebuilts/buildsqlite/sqlite3build.gn @@ -11,13 +11,38 @@ # See the License for the specific language governing permissions and # limitations under the License. -INCLUDEPATH +=$$PWD -HEADERS += \ - $$PWD/ts_common.h \ - $$PWD/double_map.h - -SOURCES += \ - $$PWD/codec_cov.cpp \ - $$PWD/file.cpp \ - $$PWD/parting_string.cpp \ - $$PWD/log.cpp +import("//build/ohos.gni") +config("sqlite_config") { + include_dirs = [ "include" ] + cflags = [ + "-Wno-shorten-64-to-32", + "-Wno-double-promotion", + "-Wno-disabled-macro-expansion", + "-Wno-float-equal", + "-Wno-cast-qual", + "-Wno-conversion", + "-Wno-cast-align", + "-Wno-unused-macros", + "-Wno-comma", + "-Wno-unreachable-code-break", + "-Wno-unreachable-code", + "-Wno-unreachable-code-return", + "-DSQLITE_THREADSAFE=1", + "-DQLITE_DEFAULT_MEMSTATUS=0", + "-DSQLITE_LIKE_DOESNT_MATCH_BLOBS", + "-DSQLITE_OMIT_DEPRECATED", + "-DSQLITE_OMIT_SHARED_CACHE", + "-DHAVE_USLEEP", + "-DHAVE_UTIME", + "-DSQLITE_BYTEORDER=1234", + "-DSQLITE_DEFAULT_AUTOVACUUM=0", + "-DSQLITE_DEFAULT_MMAP_SIZE=0", + "-DSQLITE_CORE", + "-DSQLITE_TEMP_STORE=3", + "-DSQLITE_OMIT_LOAD_EXTENSION", + ] +} +ohos_source_set("sqlite") { + sources = [ "src/sqlite3.c" ] + public_configs = [ ":sqlite_config" ] +} diff --git a/host/trace_streamer/prebuilts/protos/BUILD.gn b/host/trace_streamer/prebuilts/protos/BUILD.gn index 760af44d8dc6aec956d492d366aaa61bbc1b4a66..c91f3ff6e0266cc5c4a6f1a9842438e9432c25f4 100644 --- a/host/trace_streamer/prebuilts/protos/BUILD.gn +++ b/host/trace_streamer/prebuilts/protos/BUILD.gn @@ -12,15 +12,19 @@ # limitations under the License. import("//build/ohos.gni") +import("../../src/ts.gni") OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR = "//third_party/protobuf" proto_dir = "//third_party/protogen" services_dir = "$proto_dir/services" -ftrace_data_dir = "$proto_dir/types/plugins/ftrace_data" +ftrace_data_dir = "$proto_dir/types/plugins/ftrace_data/${kernel_version}" memory_data_dir = "$proto_dir/types/plugins/memory_data" hilog_data_dir = "$proto_dir/types/plugins/hilog_data" native_hook_dir = "$proto_dir/types/plugins/native_hook" hidump_data_dir = "$proto_dir/types/plugins/hidump_data" - +network_data_dir = "$proto_dir/types/plugins/network_data" +cpu_data_dir = "$proto_dir/types/plugins/cpu_data" +diskio_data_dir = "$proto_dir/types/plugins/diskio_data" +process_data_dir = "$proto_dir/types/plugins/process_data" config("ts_proto_include_config") { include_dirs = [ "$ftrace_data_dir", @@ -36,14 +40,19 @@ source_set("ts_proto_data_cpp") { "${OHOS_PROFILER_3RDPARTY_PROTOBUF_DIR}:protobuf_lite", ] cflags = [ - "-fPIC", "-ftrapv", - "-fPIE", "-D_FORTIFY_SOURCE=2 -O2", "-Wno-zero-length-array", - - # "-Wl,--disable-new-dtags,--rpath,/libpath1:/libpath2" + "-std=c++17", ] + + if (!is_win) { + print("xxx") + cflags += [ + "-fPIE", + "-fPIC", + ] + } if (!use_wasm) { cflags += [ "-fstack-protector-strong", # @@ -71,6 +80,11 @@ source_set("ts_proto_data_cpp") { "$ftrace_data_dir/irq.pb.cc", "$ftrace_data_dir/kmem.pb.cc", "$ftrace_data_dir/net.pb.cc", + + # "$ftrace_data_dir/mmc.pb.cc", + # "$ftrace_data_dir/f2fs.pb.cc", + # "$ftrace_data_dir/gpu_mem.pb.cc", + # "$ftrace_data_dir/regulator.pb.cc", "$ftrace_data_dir/oom.pb.cc", "$ftrace_data_dir/pagemap.pb.cc", "$ftrace_data_dir/power.pb.cc", @@ -87,7 +101,6 @@ source_set("ts_proto_data_cpp") { "$ftrace_data_dir/vmscan.pb.cc", "$ftrace_data_dir/workqueue.pb.cc", "$ftrace_data_dir/writeback.pb.cc", - "$hidump_data_dir/hidump_plugin_config.pb.cc", "$hidump_data_dir/hidump_plugin_result.pb.cc", "$hilog_data_dir/hilog_plugin_result.pb.cc", "$memory_data_dir/memory_plugin_common.pb.cc", @@ -95,6 +108,10 @@ source_set("ts_proto_data_cpp") { "$memory_data_dir/memory_plugin_result.pb.cc", "$native_hook_dir/native_hook_config.pb.cc", "$native_hook_dir/native_hook_result.pb.cc", + "${cpu_data_dir}/cpu_plugin_result.pb.cc", + "${diskio_data_dir}/diskio_plugin_result.pb.cc", + "${network_data_dir}/network_plugin_result.pb.cc", + "${process_data_dir}/process_plugin_result.pb.cc", "${services_dir}/common_types.pb.cc", ] } diff --git a/host/trace_streamer/src/BUILD.gn b/host/trace_streamer/src/BUILD.gn index 3abb1454fb5c04175f128905a9c978899c3d58ef..83345d6a3b0a1af79181dcda5a625f596bf2b240 100644 --- a/host/trace_streamer/src/BUILD.gn +++ b/host/trace_streamer/src/BUILD.gn @@ -40,14 +40,21 @@ ohos_source_set("lib") { "parser", "cfg", "parser/htrace_parser", + "parser/hiperf_parser", + "parser/hiperf_parser/hiperf/linux", + "parser/hiperf_parser/hiperf/include", "parser/htrace_parser/htrace_event_parser", "parser/htrace_parser/htrace_cpu_parser", "//third_party/sqlite/include", "${OHOS_PROTO_GEN}/types/plugins/memory_data", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data", + "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/${kernel_version}", "${OHOS_PROTO_GEN}/types/plugins/hilog_data", "${OHOS_PROTO_GEN}/types/plugins/native_hook", "${OHOS_PROTO_GEN}/types/plugins/hidump_data", + "${OHOS_PROTO_GEN}/types/plugins/network_data", + "${OHOS_PROTO_GEN}/types/plugins/cpu_data", + "${OHOS_PROTO_GEN}/types/plugins/diskio_data", + "${OHOS_PROTO_GEN}/types/plugins/process_data", "${OHOS_PROTO_GEN}", "//third_party/protobuf/src", ] @@ -72,6 +79,8 @@ ohos_source_set("trace_streamer_source") { "filter/irq_filter.h", "filter/measure_filter.cpp", "filter/measure_filter.h", + "filter/perf_data_filter.cpp", + "filter/perf_data_filter.h", "filter/process_filter.cpp", "filter/process_filter.h", "filter/slice_filter.cpp", @@ -106,21 +115,25 @@ ohos_source_set("trace_streamer_source") { "table/clock_event_filter_table.h", "table/cpu_measure_filter_table.cpp", "table/cpu_measure_filter_table.h", + "table/cpu_usage_info_table.cpp", + "table/cpu_usage_info_table.h", "table/data_dict_table.cpp", "table/data_dict_table.h", "table/data_type_table.cpp", "table/data_type_table.h", + "table/disk_io_table.cpp", + "table/disk_io_table.h", + "table/filter_constraints.cpp", "table/filter_table.cpp", "table/filter_table.h", - "table/heap_frame_table.cpp", - "table/heap_frame_table.h", - "table/heap_table.cpp", - "table/heap_table.h", "table/hidump_table.cpp", "table/hidump_table.h", + "table/index_map.cpp", "table/instants_table.cpp", "table/instants_table.h", "table/irq_table.cpp", + "table/live_process_table.cpp", + "table/live_process_table.h", "table/log_table.cpp", "table/log_table.h", "table/measure_filter_table.cpp", @@ -129,6 +142,22 @@ ohos_source_set("trace_streamer_source") { "table/measure_table.h", "table/meta_table.cpp", "table/meta_table.h", + "table/native_hook_frame_table.cpp", + "table/native_hook_frame_table.h", + "table/native_hook_table.cpp", + "table/native_hook_table.h", + "table/network_table.cpp", + "table/network_table.h", + "table/perf_call_chain_table.cpp", + "table/perf_call_chain_table.h", + "table/perf_files_table.cpp", + "table/perf_files_table.h", + "table/perf_report_table.cpp", + "table/perf_report_table.h", + "table/perf_sample_table.cpp", + "table/perf_sample_table.h", + "table/perf_thread_table.cpp", + "table/perf_thread_table.h", "table/process_filter_table.cpp", "table/process_filter_table.h", "table/process_measure_filter_table.cpp", @@ -183,25 +212,39 @@ ohos_source_set("trace_streamer_source") { "parser/htrace_parser", "parser/htrace_parser/htrace_event_parser", "parser/htrace_parser/htrace_cpu_parser", + "parser/hiperf_parser", + "parser/hiperf_parser/hiperf/linux", + "parser/hiperf_parser/hiperf/kernel", + "parser/hiperf_parser/hiperf/include", + "../prebuilts/emsdk/emsdk/emscripten/system/include", "//third_party/sqlite/include", "${OHOS_PROTO_GEN}/types/plugins/memory_data", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data", + "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/${kernel_version}", "${OHOS_PROTO_GEN}/types/plugins/hilog_data", "${OHOS_PROTO_GEN}/types/plugins/native_hook", "${OHOS_PROTO_GEN}/types/plugins/hidump_data", + "${OHOS_PROTO_GEN}/types/plugins/network_data", + "${OHOS_PROTO_GEN}/types/plugins/cpu_data", + "${OHOS_PROTO_GEN}/types/plugins/diskio_data", + "${OHOS_PROTO_GEN}/types/plugins/process_data", "${OHOS_PROTO_GEN}", "//third_party/protobuf/src", + "//third_party/perf_include", ] deps = [ "base:base", "ext:sqliteext", "include:ibase", + "parser/hiperf_parser:hiperf_parser", "parser/htrace_parser:htrace_parser", "//third_party/sqlite:sqlite", ] - if (use_wasm) { - sources += [ "rpc/wasm_func.cpp" ] + if (use_wasm || enable_ts_utest) { + sources += [ + "rpc/wasm_func.cpp", + "rpc/wasm_func.h", + ] } if (enable_ts_utest && !use_wasm) { cflags = [ @@ -222,7 +265,9 @@ if (use_wasm) { deps = [ ":lib" ] } } else { - executable("trace_streamer") { - deps = [ ":lib" ] + if (!is_test && !is_fuzz) { + executable("trace_streamer") { + deps = [ ":lib" ] + } } } diff --git a/host/trace_streamer/src/base/BUILD.gn b/host/trace_streamer/src/base/BUILD.gn index 110bed46b652bdc52ea836da59bd8c2dc114baf7..3c151a7add7517a154c9c0e691e8b69eaa979429 100644 --- a/host/trace_streamer/src/base/BUILD.gn +++ b/host/trace_streamer/src/base/BUILD.gn @@ -21,7 +21,9 @@ ohos_source_set("base") { "codec_cov.cpp", "file.cpp", "log.cpp", + "meta.cpp", "parting_string.cpp", + "string_help.cpp", ] if (enable_ts_utest && !use_wasm) { cflags = [ diff --git a/host/trace_streamer/src/base/log.cpp b/host/trace_streamer/src/base/log.cpp index 7a751c899f3153b7fa520bd4e1e89eaec591a078..7d167a90cb4f5f1678b59e23518ddce9873b89d1 100644 --- a/host/trace_streamer/src/base/log.cpp +++ b/host/trace_streamer/src/base/log.cpp @@ -14,9 +14,4 @@ */ #include "log.h" - -// namespace SysTuning { -// namespace base { bool g_cleanMode = false; -// } // namespace base -// } // namespace SysTuning diff --git a/host/trace_streamer/src/base/meta.cpp b/host/trace_streamer/src/base/meta.cpp new file mode 100644 index 0000000000000000000000000000000000000000..10b1f57e9029565212dbf0a95864afe0ffcfb7a1 --- /dev/null +++ b/host/trace_streamer/src/base/meta.cpp @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2021 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. + */ +#include "meta.h" +size_t g_loadSize = 0; +std::string TRACE_STREAM_VERSION = "2.5.115"; // version +std::string TRACE_STREAM_PUBLISHVERSION = "2022/6/14"; // publish datetime diff --git a/host/trace_streamer/src/base/meta.h b/host/trace_streamer/src/base/meta.h new file mode 100644 index 0000000000000000000000000000000000000000..a7558554ea8e55a4363f08dc195aa1aaa1da745b --- /dev/null +++ b/host/trace_streamer/src/base/meta.h @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2021 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. + */ + +#ifndef META_H +#define META_H +#include +#include +extern size_t g_loadSize; +extern std::string TRACE_STREAM_VERSION; // version +extern std::string TRACE_STREAM_PUBLISHVERSION; // publish datetime +#endif diff --git a/host/trace_streamer/src/base/string_help.cpp b/host/trace_streamer/src/base/string_help.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0edb0401229d8a1b4a60e21f40840d08a5f0b48d --- /dev/null +++ b/host/trace_streamer/src/base/string_help.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2021 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. + */ +#include "string_help.h" +#include +#include +#include +#include +int memcpy_s(void* dest, uint32_t destSize, const void* src, size_t srcSize) +{ + if (srcSize > destSize || src == nullptr || dest == nullptr) { + return -1; + } else { + if (!memcpy(dest, src, srcSize)) { + printf("memcpy fail\n"); + return -1; + } + } + return 0; +} +void* memset_s(void* dest, size_t destSize, int ch, size_t n) +{ + return memset(dest, 0, n); +} + +int snprintf_s(char* strDest, size_t destMax, size_t count, const char* format, ...) +{ + int ret; + va_list ap; + __builtin_va_start(ap, format); + ret = sprintf(strDest, format, ap); + __builtin_va_end(ap); + return ret; +} + +int strncpy_s(char* strDest, size_t destMax, const char* strSrc, size_t count) +{ + return memcpy_s(strDest, destMax, strDest, count); +} + +int sscanf_s(const char* buffer, const char* format, ...) +{ + va_list ap; + __builtin_va_start(ap, format); + int ret = scanf(buffer, format, ap); + __builtin_va_end(ap); + return ret; +} +int sprintf_s(char* strDest, size_t destMax, const char* format, ...) +{ + va_list ap; + __builtin_va_start(ap, format); + int ret = sprintf(strDest, format, ap); + __builtin_va_end(ap); + return ret; +} diff --git a/host/trace_streamer/src/base/string_help.h b/host/trace_streamer/src/base/string_help.h new file mode 100644 index 0000000000000000000000000000000000000000..6415d316c8ae850f57295f71ef7394df0b3e3361 --- /dev/null +++ b/host/trace_streamer/src/base/string_help.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2021 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. + */ +#ifndef SRC_TRACE_BASE_STRINGHELP_H +#define SRC_TRACE_BASE_STRINGHELP_H + +#include +#include +int memcpy_s(void* dest, uint32_t destSize, const void* src, size_t srcSize); +void* memset_s(void* dest, size_t destSize, int ch, size_t n); +int snprintf_s(char* strDest, size_t destMax, size_t count, const char* format, ...); +int strncpy_s(char* strDest, size_t destMax, const char* strSrc, size_t count); +int sscanf_s(const char* buffer, const char* format, ...); +int sprintf_s(char* strDest, size_t destMax, const char* format, ...); +#endif // SRC_TRACE_BASE_STRINGHELP_H diff --git a/host/trace_streamer/src/base/ts_common.h b/host/trace_streamer/src/base/ts_common.h index 57ada7286e98a2074d96da60135f7a432e62426c..60b298820d5edd02385660773c19f8b88f75668f 100644 --- a/host/trace_streamer/src/base/ts_common.h +++ b/host/trace_streamer/src/base/ts_common.h @@ -32,6 +32,8 @@ const size_t MAX_SIZE_T = std::numeric_limits::max(); const uint32_t INVALID_ID = std::numeric_limits::max(); const uint64_t SEC_TO_NS = 1000 * 1000 * 1000; const int STR_DEFAULT_LEN = -1; +const auto INVALID_CPU = INVALID_UINT64; +const auto INVALID_TIME = INVALID_UINT64; enum BuiltinClocks { TS_CLOCK_UNKNOW = 0, TS_CLOCK_BOOTTIME = 1, @@ -99,11 +101,12 @@ enum SchedWakeType { SCHED_WAKEUP = 1, // sched_wakeup }; using DataIndex = uint64_t; -using TableRowId = uint64_t; +using TableRowId = uint32_t; using InternalPid = uint32_t; using InternalTid = uint32_t; using InternalTime = uint64_t; using FilterId = uint32_t; +using InternalCpu = uint64_t; // how many cpus? could change to int8_t? enum BaseDataType { BASE_DATA_TYPE_INT, diff --git a/host/trace_streamer/src/cfg/cfg.pri b/host/trace_streamer/src/cfg/cfg.pri deleted file mode 100644 index 7833002efccdde1f36fe5cd2730085e4a687c623..0000000000000000000000000000000000000000 --- a/host/trace_streamer/src/cfg/cfg.pri +++ /dev/null @@ -1,19 +0,0 @@ -# Copyright (C) 2021 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. - -INCLUDEPATH +=$$PWD -HEADERS += \ - $$PWD/trace_streamer_config.h - -SOURCES += \ - $$PWD/trace_streamer_config.cpp diff --git a/host/trace_streamer/src/cfg/trace_streamer_config.cpp b/host/trace_streamer/src/cfg/trace_streamer_config.cpp index e72cf60d218d31458c62c45f2f6dea8548cccd6b..c82a42c64394db453290d337b687d3b62aef6dda 100644 --- a/host/trace_streamer/src/cfg/trace_streamer_config.cpp +++ b/host/trace_streamer/src/cfg/trace_streamer_config.cpp @@ -136,6 +136,11 @@ void TraceStreamerConfig::InitEventNameMap() {TRACE_MEMORY, TRACE_ACTION_MEMORY}, {TRACE_SYS_MEMORY, TRACE_ACTION_SYS_MEMORY}, {TRACE_SYS_VIRTUAL_MEMORY, TRACE_ACTION_SYS_VIRTUAL_MEMORY}, + {TRACE_DISKIO, TRACE_ACTION_DISKIO}, + {TRACE_PROCESS, TRACE_ACTION_PROCESS}, + {TRACE_CPU_USAGE, TRACE_ACTION_CPU_USAGE}, + {TRACE_NETWORK, TRACE_ACTION_NETWORK}, + {TRACE_PERF, TRACE_ACTION_PERF}, {TRACE_EVENT_SIGNAL_GENERATE, TRACE_ACTION_SIGNAL_GENERATE}, {TRACE_EVENT_SIGNAL_DELIVER, TRACE_ACTION_SIGNAL_DELIVER}, {TRACE_EVENT_BLOCK_BIO_BACKMERGE, TRACE_ACTION_BLOCK_BIO_BACKMERGE}, @@ -155,46 +160,47 @@ void TraceStreamerConfig::InitEventNameMap() {TRACE_HILOG, TRACE_ACTION_HILOG}, {TRACE_HIDUMP_FPS, TRACE_ACTION_HIDUMP_FPS}, {TRACE_NATIVE_HOOK_MALLOC, TRACE_ACTION_NATIVE_HOOK_MALLOC}, - {TRACE_NATIVE_HOOK_FREE, TRACE_ACTION_NATIVE_HOOK_FREE}}; + {TRACE_NATIVE_HOOK_FREE, TRACE_ACTION_NATIVE_HOOK_FREE}, + {TRACE_NATIVE_HOOK_MMAP, TRACE_ACTION_NATIVE_HOOK_MMAP}, + {TRACE_NATIVE_HOOK_MUNMAP, TRACE_ACTION_NATIVE_HOOK_MUNMAP}}; } void TraceStreamerConfig::InitSysMemMap() { - sysMemNameMap_ = { - {SysMeminfoType::PMEM_UNSPECIFIED, SYS_MEMINFO_UNSPECIFIED_DESC}, - {SysMeminfoType::PMEM_MEM_TOTAL, SYS_MEMINFO_MEM_TOTAL_DESC}, - {SysMeminfoType::PMEM_MEM_FREE, SYS_MEMINFO_MEM_FREE_DESC}, - {SysMeminfoType::PMEM_MEM_AVAILABLE, SYS_MEMINFO_MEM_AVAILABLE_DESC}, - {SysMeminfoType::PMEM_BUFFERS, SYS_MEMINFO_BUFFERS_DESC}, - {SysMeminfoType::PMEM_CACHED, SYS_MEMINFO_CACHED_DESC}, - {SysMeminfoType::PMEM_SWAP_CACHED, SYS_MEMINFO_SWAP_CACHED_DESC}, - {SysMeminfoType::PMEM_ACTIVE, SYS_MEMINFO_ACTIVE_DESC}, - {SysMeminfoType::PMEM_INACTIVE, SYS_MEMINFO_INACTIVE_DESC}, - {SysMeminfoType::PMEM_ACTIVE_ANON, SYS_MEMINFO_ACTIVE_ANON_DESC}, - {SysMeminfoType::PMEM_INACTIVE_ANON, SYS_MEMINFO_INACTIVE_ANON_DESC}, - {SysMeminfoType::PMEM_ACTIVE_FILE, SYS_MEMINFO_ACTIVE_FILE_DESC}, - {SysMeminfoType::PMEM_INACTIVE_FILE, SYS_MEMINFO_INACTIVE_FILE_DESC}, - {SysMeminfoType::PMEM_UNEVICTABLE, SYS_MEMINFO_UNEVICTABLE_DESC}, - {SysMeminfoType::PMEM_MLOCKED, SYS_MEMINFO_MLOCKED_DESC}, - {SysMeminfoType::PMEM_SWAP_TOTAL, SYS_MEMINFO_SWAP_TOTAL_DESC}, - {SysMeminfoType::PMEM_SWAP_FREE, SYS_MEMINFO_SWAP_FREE_DESC}, - {SysMeminfoType::PMEM_DIRTY, SYS_MEMINFO_DIRTY_DESC}, - {SysMeminfoType::PMEM_WRITEBACK, SYS_MEMINFO_WRITEBACK_DESC}, - {SysMeminfoType::PMEM_ANON_PAGES, SYS_MEMINFO_ANON_PAGES_DESC}, - {SysMeminfoType::PMEM_MAPPED, SYS_MEMINFO_MAPPED_DESC}, - {SysMeminfoType::PMEM_SHMEM, SYS_MEMINFO_SHMEM_DESC}, - {SysMeminfoType::PMEM_SLAB, SYS_MEMINFO_SLAB_DESC}, - {SysMeminfoType::PMEM_SLAB_RECLAIMABLE, SYS_MEMINFO_SLAB_RECLAIMABLE_DESC}, - {SysMeminfoType::PMEM_SLAB_UNRECLAIMABLE, SYS_MEMINFO_SLAB_UNRECLAIMABLE_DESC}, - {SysMeminfoType::PMEM_KERNEL_STACK, SYS_MEMINFO_KERNEL_STACK_DESC}, - {SysMeminfoType::PMEM_PAGE_TABLES, SYS_MEMINFO_PAGE_TABLES_DESC}, - {SysMeminfoType::PMEM_COMMIT_LIMIT, SYS_MEMINFO_COMMIT_LIMIT_DESC}, - {SysMeminfoType::PMEM_COMMITED_AS, SYS_MEMINFO_COMMITED_AS_DESC}, - {SysMeminfoType::PMEM_VMALLOC_TOTAL, SYS_MEMINFO_VMALLOC_TOTAL_DESC}, - {SysMeminfoType::PMEM_VMALLOC_USED, SYS_MEMINFO_VMALLOC_USED_DESC}, - {SysMeminfoType::PMEM_VMALLOC_CHUNK, SYS_MEMINFO_VMALLOC_CHUNK_DESC}, - {SysMeminfoType::PMEM_CMA_TOTAL, SYS_MEMINFO_CMA_TOTAL_DESC}, - {SysMeminfoType::PMEM_CMA_FREE, SYS_MEMINFO_CMA_FREE_DESC}, - }; + sysMemNameMap_ = {{SysMeminfoType::PMEM_UNSPECIFIED, SYS_MEMINFO_UNSPECIFIED_DESC}, + {SysMeminfoType::PMEM_MEM_TOTAL, SYS_MEMINFO_MEM_TOTAL_DESC}, + {SysMeminfoType::PMEM_MEM_FREE, SYS_MEMINFO_MEM_FREE_DESC}, + {SysMeminfoType::PMEM_MEM_AVAILABLE, SYS_MEMINFO_MEM_AVAILABLE_DESC}, + {SysMeminfoType::PMEM_BUFFERS, SYS_MEMINFO_BUFFERS_DESC}, + {SysMeminfoType::PMEM_CACHED, SYS_MEMINFO_CACHED_DESC}, + {SysMeminfoType::PMEM_SWAP_CACHED, SYS_MEMINFO_SWAP_CACHED_DESC}, + {SysMeminfoType::PMEM_ACTIVE, SYS_MEMINFO_ACTIVE_DESC}, + {SysMeminfoType::PMEM_INACTIVE, SYS_MEMINFO_INACTIVE_DESC}, + {SysMeminfoType::PMEM_ACTIVE_ANON, SYS_MEMINFO_ACTIVE_ANON_DESC}, + {SysMeminfoType::PMEM_INACTIVE_ANON, SYS_MEMINFO_INACTIVE_ANON_DESC}, + {SysMeminfoType::PMEM_ACTIVE_FILE, SYS_MEMINFO_ACTIVE_FILE_DESC}, + {SysMeminfoType::PMEM_INACTIVE_FILE, SYS_MEMINFO_INACTIVE_FILE_DESC}, + {SysMeminfoType::PMEM_UNEVICTABLE, SYS_MEMINFO_UNEVICTABLE_DESC}, + {SysMeminfoType::PMEM_MLOCKED, SYS_MEMINFO_MLOCKED_DESC}, + {SysMeminfoType::PMEM_SWAP_TOTAL, SYS_MEMINFO_SWAP_TOTAL_DESC}, + {SysMeminfoType::PMEM_SWAP_FREE, SYS_MEMINFO_SWAP_FREE_DESC}, + {SysMeminfoType::PMEM_DIRTY, SYS_MEMINFO_DIRTY_DESC}, + {SysMeminfoType::PMEM_WRITEBACK, SYS_MEMINFO_WRITEBACK_DESC}, + {SysMeminfoType::PMEM_ANON_PAGES, SYS_MEMINFO_ANON_PAGES_DESC}, + {SysMeminfoType::PMEM_MAPPED, SYS_MEMINFO_MAPPED_DESC}, + {SysMeminfoType::PMEM_SHMEM, SYS_MEMINFO_SHMEM_DESC}, + {SysMeminfoType::PMEM_SLAB, SYS_MEMINFO_SLAB_DESC}, + {SysMeminfoType::PMEM_SLAB_RECLAIMABLE, SYS_MEMINFO_SLAB_RECLAIMABLE_DESC}, + {SysMeminfoType::PMEM_SLAB_UNRECLAIMABLE, SYS_MEMINFO_SLAB_UNRECLAIMABLE_DESC}, + {SysMeminfoType::PMEM_KERNEL_STACK, SYS_MEMINFO_KERNEL_STACK_DESC}, + {SysMeminfoType::PMEM_PAGE_TABLES, SYS_MEMINFO_PAGE_TABLES_DESC}, + {SysMeminfoType::PMEM_COMMIT_LIMIT, SYS_MEMINFO_COMMIT_LIMIT_DESC}, + {SysMeminfoType::PMEM_COMMITED_AS, SYS_MEMINFO_COMMITED_AS_DESC}, + {SysMeminfoType::PMEM_VMALLOC_TOTAL, SYS_MEMINFO_VMALLOC_TOTAL_DESC}, + {SysMeminfoType::PMEM_VMALLOC_USED, SYS_MEMINFO_VMALLOC_USED_DESC}, + {SysMeminfoType::PMEM_VMALLOC_CHUNK, SYS_MEMINFO_VMALLOC_CHUNK_DESC}, + {SysMeminfoType::PMEM_CMA_TOTAL, SYS_MEMINFO_CMA_TOTAL_DESC}, + {SysMeminfoType::PMEM_CMA_FREE, SYS_MEMINFO_CMA_FREE_DESC}, + {SysMeminfoType::PMEM_KERNEL_RECLAIMABLE, SYS_MEMINFO_KERNEL_RECLAIMABLE_DESC}}; } void TraceStreamerConfig::InitSysVmemMap() @@ -803,6 +809,26 @@ void TraceStreamerConfig::InitSecurityMap() {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, }, }, + { + TRACE_NATIVE_HOOK_MMAP, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_NATIVE_HOOK_MUNMAP, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, { TRACE_SYS_MEMORY, { @@ -823,6 +849,56 @@ void TraceStreamerConfig::InitSecurityMap() {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, }, }, + { + TRACE_DISKIO, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_PROCESS, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_CPU_USAGE, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_NETWORK, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, + { + TRACE_PERF, + { + {STAT_EVENT_RECEIVED, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_DATA_LOST, STAT_SEVERITY_LEVEL_ERROR}, + {STAT_EVENT_NOTMATCH, STAT_SEVERITY_LEVEL_INFO}, + {STAT_EVENT_NOTSUPPORTED, STAT_SEVERITY_LEVEL_WARN}, + {STAT_EVENT_DATA_INVALID, STAT_SEVERITY_LEVEL_ERROR}, + }, + }, { TRACE_EVENT_SIGNAL_GENERATE, { diff --git a/host/trace_streamer/src/cfg/trace_streamer_config.h b/host/trace_streamer/src/cfg/trace_streamer_config.h index 3e71a1a1f669c5ad8910b2867bf04c0e54df2fbf..319fec956317c9fcfab9172ec99015ee3a14f8ea 100644 --- a/host/trace_streamer/src/cfg/trace_streamer_config.h +++ b/host/trace_streamer/src/cfg/trace_streamer_config.h @@ -70,8 +70,15 @@ enum SupportedTraceEventType { TRACE_HIDUMP_FPS, TRACE_NATIVE_HOOK_MALLOC, TRACE_NATIVE_HOOK_FREE, + TRACE_NATIVE_HOOK_MMAP, + TRACE_NATIVE_HOOK_MUNMAP, TRACE_SYS_MEMORY, TRACE_SYS_VIRTUAL_MEMORY, + TRACE_DISKIO, + TRACE_PROCESS, + TRACE_CPU_USAGE, + TRACE_NETWORK, + TRACE_PERF, TRACE_EVENT_SIGNAL_GENERATE, TRACE_EVENT_SIGNAL_DELIVER, TRACE_EVENT_BLOCK_BIO_BACKMERGE, @@ -211,6 +218,8 @@ private: const std::string TRACE_ACTION_HIDUMP_FPS = "hidump_fps"; const std::string TRACE_ACTION_NATIVE_HOOK_MALLOC = "native_hook_malloc"; const std::string TRACE_ACTION_NATIVE_HOOK_FREE = "native_hook_free"; + const std::string TRACE_ACTION_NATIVE_HOOK_MMAP = "native_hook_mmap"; + const std::string TRACE_ACTION_NATIVE_HOOK_MUNMAP = "native_hook_munmap"; const std::string TRACE_ACTION_SIGNAL_GENERATE = "signal_generate"; const std::string TRACE_ACTION_SIGNAL_DELIVER = "signal_deliver"; const std::string TRACE_ACTION_BLOCK_BIO_BACKMERGE = "trace_block_bio_backmerge"; @@ -229,6 +238,11 @@ private: const std::string TRACE_ACTION_SYS_MEMORY = "sys_memory"; const std::string TRACE_ACTION_SYS_VIRTUAL_MEMORY = "sys_virtual_memory"; + const std::string TRACE_ACTION_DISKIO = "trace_diskio"; + const std::string TRACE_ACTION_PROCESS = "trace_process"; + const std::string TRACE_ACTION_CPU_USAGE = "trace_cpu_usage"; + const std::string TRACE_ACTION_NETWORK = "trace_network"; + const std::string TRACE_ACTION_PERF = "trace_perf"; const std::string TRACE_ACTION_OTHER = "other"; const std::string MEM_INFO_VM_SIZE_DESC = "mem.vm.size"; @@ -276,6 +290,7 @@ private: const std::string SYS_MEMINFO_VMALLOC_CHUNK_DESC = "sys.mem.vmalloc.chunk"; const std::string SYS_MEMINFO_CMA_TOTAL_DESC = "sys.mem.cma.total"; const std::string SYS_MEMINFO_CMA_FREE_DESC = "sys.mem.cma.free"; + const std::string SYS_MEMINFO_KERNEL_RECLAIMABLE_DESC = "sys.mem.kernel.reclaimable"; const std::string SYS_VMEMINFO_UNSPECIFIED_DESC = "sys.virtual.mem.unspecified"; const std::string SYS_VMEMINFO_NR_FREE_PAGES_DESC = "sys.virtual.mem.nr.free.pages"; const std::string SYS_VMEMINFO_NR_ALLOC_BATCH_DESC = "sys.virtual.mem.nr.alloc.batch"; diff --git a/host/trace_streamer/src/ext/sqlite_ext.pri b/host/trace_streamer/src/ext/sqlite_ext.pri deleted file mode 100644 index 6d1a82c69bc447f9b6b9260de2aaa6a427c8a0cb..0000000000000000000000000000000000000000 --- a/host/trace_streamer/src/ext/sqlite_ext.pri +++ /dev/null @@ -1,16 +0,0 @@ -# Copyright (C) 2021 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. -SOURCES += $$PWD/sqlite_ext_funcs.cpp -HEADERS += $$PWD/sqlite_ext_funcs.h -INCLUDEPATH += $$PWD/../../third_party/sqlite/include, - $$PWD/../include \ No newline at end of file diff --git a/host/trace_streamer/src/filter/binder_filter.cpp b/host/trace_streamer/src/filter/binder_filter.cpp index b13ad8edea336e800a48b66de7adfefd88222d7a..83f3fb5147ef77eb7df1850b41a39c2800960daf 100644 --- a/host/trace_streamer/src/filter/binder_filter.cpp +++ b/host/trace_streamer/src/filter/binder_filter.cpp @@ -51,22 +51,6 @@ std::string BinderFilter::GetBinderFlagsDesc(uint32_t flag) } return str; } -void BinderFilter::MaybeDealEvent() -{ - if (tsBinderEventQueue_.size() > MAX_CACHE_SIZE) { - DealEvent(tsBinderEventQueue_.begin()->second.get()); - tsBinderEventQueue_.erase(tsBinderEventQueue_.begin()); - } -} - -void BinderFilter::FinishBinderEvent() -{ - for (auto it = tsBinderEventQueue_.begin(); it != tsBinderEventQueue_.end(); it++) { - DealEvent(it->second.get()); - } - tsBinderEventQueue_.clear(); -} - void BinderFilter::SendTraction(int64_t ts, uint32_t tid, uint64_t transactionId, @@ -76,108 +60,6 @@ void BinderFilter::SendTraction(int64_t ts, bool isReply, int32_t flags, int32_t code) -{ - auto sendTractionEvent = std::make_unique(ts, tid, transactionId, destNode, - destTgid, destTid, isReply, flags, code); - auto binderEvent = std::make_unique(); - binderEvent->type_ = TS_EVENT_BINDER_SEND; - binderEvent->senderBinderEvent_ = std::move(sendTractionEvent); - tsBinderEventQueue_.insert(std::make_pair(ts, std::move(binderEvent))); - MaybeDealEvent(); -} -void BinderFilter::ReceiveTraction(int64_t ts, uint32_t pid, uint64_t transactionId) -{ - auto receiveTractionEvent = std::make_unique(ts, pid, transactionId); - auto binderEvent = std::make_unique(); - binderEvent->type_ = TS_EVENT_BINDER_RECIVED; - binderEvent->receivedBinderEvent_ = std::move(receiveTractionEvent); - tsBinderEventQueue_.insert(std::make_pair(ts, - std::move(binderEvent))); - MaybeDealEvent(); -} -void BinderFilter::TransactionAllocBuf(int64_t ts, uint32_t pid, uint64_t dataSize, uint64_t offsetsSize) -{ - auto tractionAllocBufEvent = std::make_unique(ts, pid, dataSize, offsetsSize); - auto binderEvent = std::make_unique(); - binderEvent->type_ = TS_EVENT_BINDER_ALLOC_BUF; - binderEvent->binderAllocBufEvent_ = std::move(tractionAllocBufEvent); - tsBinderEventQueue_.insert(std::make_pair(ts, - std::move(binderEvent))); - MaybeDealEvent(); -} -void BinderFilter::TractionLock(int64_t ts, uint32_t pid, const std::string& tag) -{ - auto tractionLockEvent = std::make_unique(ts, pid, tag); - auto binderEvent = std::make_unique(); - binderEvent->type_ = TS_EVENT_BINDER_LOCK; - binderEvent->binderLockEvent_ = std::move(tractionLockEvent); - tsBinderEventQueue_.insert(std::make_pair(ts, - std::move(binderEvent))); - MaybeDealEvent(); -} -void BinderFilter::TractionLocked(int64_t ts, uint32_t pid, const std::string& tag) -{ - auto tractionLockedEvent = std::make_unique(ts, pid, tag); - auto binderEvent = std::make_unique(); - binderEvent->type_ = TS_EVENT_BINDER_LOCKED; - binderEvent->binderLockedEvent_ = std::move(tractionLockedEvent); - tsBinderEventQueue_.insert(std::make_pair(ts, - std::move(binderEvent))); - MaybeDealEvent(); -} -void BinderFilter::TractionUnlock(int64_t ts, uint32_t pid, const std::string& tag) -{ - auto tractionUnlockEvent = std::make_unique(ts, pid, tag); - auto binderEvent = std::make_unique(); - binderEvent->type_ = TS_EVENT_BINDER_UNLOCK; - binderEvent->binderUnlockEvent_ = std::move(tractionUnlockEvent); - tsBinderEventQueue_.insert(std::make_pair(ts, - std::move(binderEvent))); - MaybeDealEvent(); -} -void BinderFilter::DealEvent(const TSBinderEvent* event) -{ - switch (static_cast(event->type_)) { - case TS_EVENT_BINDER_SEND: - ExecSendTraction(event->senderBinderEvent_->ts_, event->senderBinderEvent_->tid_, - event->senderBinderEvent_->transactionId_, event->senderBinderEvent_->destNode_, - event->senderBinderEvent_->destTgid_, event->senderBinderEvent_->destTid_, - event->senderBinderEvent_->isReply_, event->senderBinderEvent_->flags_, - event->senderBinderEvent_->code_); - break; - case TS_EVENT_BINDER_RECIVED: - ExecReceiveTraction(event->receivedBinderEvent_->ts_, event->receivedBinderEvent_->pid_, - event->receivedBinderEvent_->transactionId_); - break; - case TS_EVENT_BINDER_ALLOC_BUF: - ExecTransactionAllocBuf(event->binderAllocBufEvent_->ts_, event->binderAllocBufEvent_->pid_, - event->binderAllocBufEvent_->dataSize_, event->binderAllocBufEvent_->offsetsSize_); - break; - case TS_EVENT_BINDER_LOCK: - ExecTractionLock(event->binderLockEvent_->ts_, event->binderLockEvent_->pid_, - event->binderLockEvent_->tag_); - break; - case TS_EVENT_BINDER_LOCKED: - ExecTractionLocked(event->binderLockedEvent_->ts_, event->binderLockedEvent_->pid_, - event->binderLockedEvent_->tag_); - break; - case TS_EVENT_BINDER_UNLOCK: - ExecTractionUnlock(event->binderUnlockEvent_->ts_, event->binderUnlockEvent_->pid_, - event->binderUnlockEvent_->tag_); - break; - default: - break; - } -} -void BinderFilter::ExecSendTraction(int64_t ts, - uint32_t tid, - uint64_t transactionId, - int32_t destNode, - int32_t destTgid, - int32_t destTid, - bool isReply, - int32_t flags, - int32_t code) { auto flagsStr = traceDataCache_->GetDataIndex("0x" + base::number(flags, base::INTEGER_RADIX_TYPE_HEX) + GetBinderFlagsDesc(flags)); @@ -209,12 +91,14 @@ void BinderFilter::ExecSendTraction(int64_t ts, transWaitingRcv_[transactionId] = tid; } else { // transaction not need reply + // tid calling id + // a binder event only care the transactionId and the callint tid streamFilters_->sliceFilter_->BeginAsyncBinder(ts, tid, binderCatalogId_, transAsyncId_, argsSend); transNoNeedReply_[transactionId] = argsSend; } } } -void BinderFilter::ExecReceiveTraction(int64_t ts, uint32_t pid, uint64_t transactionId) +void BinderFilter::ReceiveTraction(int64_t ts, uint32_t pid, uint64_t transactionId) { InternalTid internalTid = streamFilters_->processFilter_->UpdateOrCreateThread(ts, pid); const auto threadName = traceDataCache_->GetConstThreadData(internalTid).nameIndex_; @@ -248,15 +132,16 @@ void BinderFilter::ExecReceiveTraction(int64_t ts, uint32_t pid, uint64_t transa return; } // the code below can be hard to understand, may be a EndBinder will be better - // this problem cna be test after the IDE is finished + // this problem can be test after the IDE is finished if (transNoNeedReply_.count(transactionId)) { auto args = transNoNeedReply_[transactionId]; streamFilters_->sliceFilter_->BeginAsyncBinder(ts, pid, binderCatalogId_, asyncRcvId_, args); + // maybe you can use the flowing code: streamFilters_->sliceFilter_->EndBinder(ts, pid); transNoNeedReply_.erase(transactionId); return; } } -void BinderFilter::ExecTransactionAllocBuf(int64_t ts, uint32_t pid, uint64_t dataSize, uint64_t offsetsSize) +void BinderFilter::TransactionAllocBuf(int64_t ts, uint32_t pid, uint64_t dataSize, uint64_t offsetsSize) { ArgsSet args; args.AppendArg(dataSizeId_, BASE_DATA_TYPE_INT, dataSize); @@ -264,12 +149,12 @@ void BinderFilter::ExecTransactionAllocBuf(int64_t ts, uint32_t pid, uint64_t da streamFilters_->sliceFilter_->AddArgs(pid, binderCatalogId_, transSliceId_, args); UNUSED(ts); } -void BinderFilter::ExecTractionLock(int64_t ts, uint32_t pid, const std::string& tag) +void BinderFilter::TractionLock(int64_t ts, uint32_t pid, const std::string& tag) { lastEventTs_[pid] = ts; streamFilters_->sliceFilter_->BeginBinder(ts, pid, binderCatalogId_, lockTryId_); } -void BinderFilter::ExecTractionLocked(int64_t ts, uint32_t pid, const std::string& tag) +void BinderFilter::TractionLocked(int64_t ts, uint32_t pid, const std::string& tag) { if (!lastEventTs_.count(pid)) { streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_BINDER_TRANSACTION_LOCKED, STAT_EVENT_NOTMATCH); @@ -280,7 +165,7 @@ void BinderFilter::ExecTractionLocked(int64_t ts, uint32_t pid, const std::strin lastEventTs_.erase(pid); lastEventTs_[pid] = ts; } -void BinderFilter::ExecTractionUnlock(int64_t ts, uint32_t pid, const std::string& tag) +void BinderFilter::TractionUnlock(int64_t ts, uint32_t pid, const std::string& tag) { if (!lastEventTs_.count(pid)) { streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_BINDER_TRANSACTION_UNLOCK, STAT_EVENT_NOTMATCH); diff --git a/host/trace_streamer/src/filter/binder_filter.h b/host/trace_streamer/src/filter/binder_filter.h index 183338494d511467e6d7cd10076746af57ae281d..ccf796324b3e8bd4edea07c22a7bbf28cb976091 100644 --- a/host/trace_streamer/src/filter/binder_filter.h +++ b/host/trace_streamer/src/filter/binder_filter.h @@ -45,113 +45,8 @@ public: void TractionLock(int64_t ts, uint32_t pid, const std::string& tag); void TractionLocked(int64_t ts, uint32_t pid, const std::string& tag); void TractionUnlock(int64_t ts, uint32_t pid, const std::string& tag); - void FinishBinderEvent(); private: - void MaybeDealEvent(); - - class TSSendTractionEvent { - public: - TSSendTractionEvent(int64_t ts, - uint32_t tid, - uint64_t transactionId, - int32_t destNode, - int32_t destTgid, - int32_t destTid, - bool isReply, - int32_t flags, - int32_t code) - : ts_(ts), - tid_(tid), - transactionId_(transactionId), - destNode_(destNode), - destTgid_(destTgid), - destTid_(destTid), - isReply_(isReply), - flags_(flags), - code_(code) - { - } - ~TSSendTractionEvent() {} - int64_t ts_; - uint32_t tid_; - uint64_t transactionId_; - int32_t destNode_; - int32_t destTgid_; - int32_t destTid_; - bool isReply_; - int32_t flags_; - int32_t code_; - }; - class TSReceiveTractionEvent { - public: - TSReceiveTractionEvent(int64_t ts, uint32_t pid, uint64_t transactionId) - : ts_(ts), pid_(pid), transactionId_(transactionId) - { - } - ~TSReceiveTractionEvent() {} - uint64_t ts_; - uint32_t pid_; - uint64_t transactionId_; - }; - class TSTractionLockEvent { - public: - TSTractionLockEvent(int64_t ts, uint32_t pid, const std::string& tag) : ts_(ts), pid_(pid), tag_(tag) {} - ~TSTractionLockEvent() {} - uint64_t ts_; - uint32_t pid_; - const std::string tag_; - }; - class TSTransactionAllocBufEvent { - public: - TSTransactionAllocBufEvent(int64_t ts, uint32_t pid, uint64_t dataSize, uint64_t offsetsSize) - : ts_(ts), pid_(pid), dataSize_(dataSize), offsetsSize_(offsetsSize) - { - } - ~TSTransactionAllocBufEvent() {} - uint64_t ts_; - uint32_t pid_; - uint64_t dataSize_; - uint64_t offsetsSize_; - }; - enum TSBinderEventType { - TS_EVENT_BINDER_SEND, - TS_EVENT_BINDER_RECIVED, - TS_EVENT_BINDER_ALLOC_BUF, - TS_EVENT_BINDER_LOCK, - TS_EVENT_BINDER_LOCKED, - TS_EVENT_BINDER_UNLOCK - }; - class TSBinderEvent { - public: - TSBinderEvent() {} - ~TSBinderEvent() {} - TSBinderEventType type_; - // us union below will be a good choice - // but union with unique_ptr can bring about runtime error on windows and mac,only work well on linux - std::unique_ptr senderBinderEvent_ = {}; - std::unique_ptr receivedBinderEvent_ = {}; - std::unique_ptr binderAllocBufEvent_ = {}; - std::unique_ptr binderLockEvent_ = {}; - std::unique_ptr binderLockedEvent_ = {}; - std::unique_ptr binderUnlockEvent_ = {}; - }; - void DealEvent(const TSBinderEvent* event); - - void ExecSendTraction(int64_t ts, - uint32_t tid, - uint64_t transactionId, - int32_t destNode, - int32_t destTgid, - int32_t destTid, - bool isReply, - int32_t flags, - int32_t code); - void ExecReceiveTraction(int64_t ts, uint32_t pid, uint64_t transactionId); - void ExecTransactionAllocBuf(int64_t ts, uint32_t pid, uint64_t dataSize, uint64_t offsetsSize); - void ExecTractionLock(int64_t ts, uint32_t pid, const std::string& tag); - void ExecTractionLocked(int64_t ts, uint32_t pid, const std::string& tag); - void ExecTractionUnlock(int64_t ts, uint32_t pid, const std::string& tag); std::string GetBinderFlagsDesc(uint32_t flag); bool IsValidUint32(uint32_t value) const { @@ -162,36 +57,31 @@ private: uint32_t statusCodeMsgFlag_ = 0x08; uint32_t acceptFdsMsgFlag_ = 0x10; uint32_t noFlagsMsgFlag_ = 0; - DataIndex binderCatalogId_ = traceDataCache_->GetDataIndex("binder"); - DataIndex replyId_ = traceDataCache_->GetDataIndex("binder reply"); - DataIndex isReplayId_ = traceDataCache_->GetDataIndex("reply transaction?"); - DataIndex flagsId_ = traceDataCache_->GetDataIndex("flags"); - DataIndex transSliceId_ = traceDataCache_->GetDataIndex("binder transaction"); - DataIndex transId_ = traceDataCache_->GetDataIndex("transaction id"); - DataIndex asyncRcvId_ = traceDataCache_->GetDataIndex("binder async rcv"); - DataIndex codeId_ = traceDataCache_->GetDataIndex("code"); - DataIndex callingTid_ = traceDataCache_->GetDataIndex("calling tid"); - DataIndex destNodeId_ = traceDataCache_->GetDataIndex("destination node"); - DataIndex destThreadId_ = traceDataCache_->GetDataIndex("destination thread"); - DataIndex destThreadNameId_ = traceDataCache_->GetDataIndex("destination name"); - DataIndex destSliceId_ = traceDataCache_->GetDataIndex("destination slice id"); - DataIndex destProcessId_ = traceDataCache_->GetDataIndex("destination process"); - DataIndex transAsyncId_ = traceDataCache_->GetDataIndex("binder transaction async"); - DataIndex lockTryId_ = traceDataCache_->GetDataIndex("binder lock waiting"); - DataIndex lockHoldId_ = traceDataCache_->GetDataIndex("binder lock held"); - DataIndex dataSizeId_ = traceDataCache_->GetDataIndex("data size"); - DataIndex dataOffsetSizeId_ = traceDataCache_->GetDataIndex("offsets size"); - DataIndex nullStringId_ = traceDataCache_->GetDataIndex("null"); + const DataIndex binderCatalogId_ = traceDataCache_->GetDataIndex("binder"); + const DataIndex replyId_ = traceDataCache_->GetDataIndex("binder reply"); + const DataIndex isReplayId_ = traceDataCache_->GetDataIndex("reply transaction?"); + const DataIndex flagsId_ = traceDataCache_->GetDataIndex("flags"); + const DataIndex transSliceId_ = traceDataCache_->GetDataIndex("binder transaction"); + const DataIndex transId_ = traceDataCache_->GetDataIndex("transaction id"); + const DataIndex asyncRcvId_ = traceDataCache_->GetDataIndex("binder async rcv"); + const DataIndex codeId_ = traceDataCache_->GetDataIndex("code"); + const DataIndex callingTid_ = traceDataCache_->GetDataIndex("calling tid"); + const DataIndex destNodeId_ = traceDataCache_->GetDataIndex("destination node"); + const DataIndex destThreadId_ = traceDataCache_->GetDataIndex("destination thread"); + const DataIndex destThreadNameId_ = traceDataCache_->GetDataIndex("destination name"); + const DataIndex destSliceId_ = traceDataCache_->GetDataIndex("destination slice id"); + const DataIndex destProcessId_ = traceDataCache_->GetDataIndex("destination process"); + const DataIndex transAsyncId_ = traceDataCache_->GetDataIndex("binder transaction async"); + const DataIndex lockTryId_ = traceDataCache_->GetDataIndex("binder lock waiting"); + const DataIndex lockHoldId_ = traceDataCache_->GetDataIndex("binder lock held"); + const DataIndex dataSizeId_ = traceDataCache_->GetDataIndex("data size"); + const DataIndex dataOffsetSizeId_ = traceDataCache_->GetDataIndex("offsets size"); + const DataIndex nullStringId_ = traceDataCache_->GetDataIndex("null"); std::unordered_map lastEventTs_ = {}; std::unordered_set transReplyWaitingReply_ = {}; std::unordered_map transWaitingRcv_ = {}; std::unordered_map transNoNeedReply_ = {}; std::unordered_map binderFlagDescs_ = {}; - std::multimap> tsBinderEventQueue_; - // timestamp of ftrace events from different cpu can be outof order - // keep a cache of ftrace events in memory and keep msg in order - // the value below is the count of msg, maybe you can change it - const size_t MAX_CACHE_SIZE = 10000; }; } // namespace TraceStreamer } // namespace SysTuning diff --git a/host/trace_streamer/src/filter/clock_filter.h b/host/trace_streamer/src/filter/clock_filter.h index 6d8e29db686a76fc0d45e8e75048c224da7851a3..9b9471585d3778611f995fa2a24f89a2edfb072f 100644 --- a/host/trace_streamer/src/filter/clock_filter.h +++ b/host/trace_streamer/src/filter/clock_filter.h @@ -58,6 +58,10 @@ public: { primaryClock_ = primary; } + ClockId GetPrimaryClock() + { + return primaryClock_; + } uint64_t ToPrimaryTraceTime(ClockId srcClockId, uint64_t srcTs) const; uint64_t Convert(ClockId srcClockId, uint64_t srcTs, ClockId desClockId) const; void AddClockSnapshot(const std::vector& snapShot); diff --git a/host/trace_streamer/src/filter/cpu_filter.cpp b/host/trace_streamer/src/filter/cpu_filter.cpp index 8ce228345836a20d9669d0721a9aac8695de6d62..7c104b4c30ba8e260986d902e11e23795795c725 100644 --- a/host/trace_streamer/src/filter/cpu_filter.cpp +++ b/host/trace_streamer/src/filter/cpu_filter.cpp @@ -26,99 +26,6 @@ void CpuFilter::InsertSwitchEvent(uint64_t ts, uint64_t prevState, uint64_t nextPid, uint64_t nextPior) -{ - auto switchEvent = std::make_unique(ts, cpu, prevPid, prevPior, prevState, nextPid, nextPior); - auto cpuEvent = std::make_unique(); - cpuEvent->type_ = TS_EVENT_THREAD_SWITCH; - cpuEvent->switchEvent_ = std::move(switchEvent); - tsCpuEventQueue_.insert(std::make_pair(ts, std::move(cpuEvent))); - MaybeDealEvent(); -} -bool CpuFilter::InsertProcessExitEvent(uint64_t ts, uint64_t cpu, uint64_t pid) -{ - auto processExitEvent = std::make_unique(ts, cpu, pid); - auto cpuEvent = std::make_unique(); - cpuEvent->type_ = TS_EVENT_PROCESS_EXIT; - cpuEvent->processExitEvent_ = std::move(processExitEvent); - tsCpuEventQueue_.insert(std::make_pair(ts, - std::move(cpuEvent))); - MaybeDealEvent(); - return true; -} - -bool CpuFilter::InsertProcessFreeEvent(uint64_t ts, uint64_t pid) -{ - auto processExitEvent = std::make_unique(ts, 0, pid); - auto cpuEvent = std::make_unique(); - cpuEvent->type_ = TS_EVENT_PROCESS_FREE; - cpuEvent->processExitEvent_ = std::move(processExitEvent); - tsCpuEventQueue_.insert(std::make_pair(ts, - std::move(cpuEvent))); - MaybeDealEvent(); - return true; -} -void CpuFilter::InsertWakeupEvent(uint64_t ts, uint64_t internalTid) -{ - auto wakeupEvent = std::make_unique(TSWakeupEvent(ts, internalTid)); - auto cpuEvent = std::make_unique(); - cpuEvent->type_ = TS_EVENT_THREAD_WAKING; - cpuEvent->wakeupEvent_ = std::move(wakeupEvent); - tsCpuEventQueue_.insert(std::make_pair(ts, - std::move(cpuEvent))); - MaybeDealEvent(); -} -uint64_t CpuFilter::RemberInternalTidInStateTable(uint64_t uid, uint64_t row, uint64_t state) -{ - if (internalTidToRowThreadState_.find(uid) != internalTidToRowThreadState_.end()) { - internalTidToRowThreadState_.at(uid) = TPthread{row, state}; - } else { - internalTidToRowThreadState_.insert(std::make_pair(uid, TPthread{row, state})); - } - return 0; -} - -void CpuFilter::MaybeDealEvent() -{ - if (tsCpuEventQueue_.size() > MAX_CACHE_SIZE) { - DealEvent(tsCpuEventQueue_.begin()->second.get()); - tsCpuEventQueue_.erase(tsCpuEventQueue_.begin()); - } -} - -void CpuFilter::DealEvent(const TSCpuEvent* event) -{ - switch (static_cast(event->type_)) { - case TS_EVENT_THREAD_SWITCH: - ExecInsertSwitchEvent(event->switchEvent_->ts_, event->switchEvent_->cpu_, event->switchEvent_->prevPid_, - event->switchEvent_->prevPior_, event->switchEvent_->prevState_, - event->switchEvent_->nextPid_, event->switchEvent_->nextPior_); - break; - case TS_EVENT_THREAD_WAKING: - ExecInsertWakeupEvent(event->wakeupEvent_->ts_, event->wakeupEvent_->pid_); - break; - case TS_EVENT_PROCESS_EXIT: - case TS_EVENT_PROCESS_FREE: - ExecInsertProcessExitEvent(event->processExitEvent_->ts_, event->processExitEvent_->cpu_, - event->processExitEvent_->pid_); - break; - default: - break; - } -} -void CpuFilter::FinishCpuEvent() -{ - for (auto it = tsCpuEventQueue_.begin(); it != tsCpuEventQueue_.end(); it++) { - DealEvent(it->second.get()); - } - tsCpuEventQueue_.clear(); -} -void CpuFilter::ExecInsertSwitchEvent(uint64_t ts, - uint64_t cpu, - uint64_t prevPid, - uint64_t prevPior, - uint64_t prevState, - uint64_t nextPid, - uint64_t nextPior) { auto index = traceDataCache_->GetSchedSliceData()->AppendSchedSlice(ts, 0, cpu, nextPid, 0, nextPior); @@ -134,10 +41,10 @@ void CpuFilter::ExecInsertSwitchEvent(uint64_t ts, CheckWakeupEvent(nextPid); auto lastRow = RowOfInternalTidInStateTable(nextPid); if (lastRow != INVALID_UINT64) { - traceDataCache_->GetThreadStateData()->UpdateDuration(lastRow, ts); + traceDataCache_->GetThreadStateData()->UpdateDuration(static_cast(lastRow), ts); } index = - traceDataCache_->GetThreadStateData()->AppendThreadState(ts, INVALID_UINT64, cpu, nextPid, TASK_RUNNING); + traceDataCache_->GetThreadStateData()->AppendThreadState(ts, INVALID_TIME, cpu, nextPid, TASK_RUNNING); RemberInternalTidInStateTable(nextPid, index, TASK_RUNNING); if (cpuToRowThreadState_.find(cpu) == cpuToRowThreadState_.end()) { cpuToRowThreadState_.insert(std::make_pair(cpu, index)); @@ -150,33 +57,53 @@ void CpuFilter::ExecInsertSwitchEvent(uint64_t ts, CheckWakeupEvent(prevPid); auto lastRow = RowOfInternalTidInStateTable(prevPid); if (lastRow != INVALID_UINT64) { - traceDataCache_->GetThreadStateData()->UpdateDuration(lastRow, ts); + traceDataCache_->GetThreadStateData()->UpdateDuration(static_cast(lastRow), ts); } - auto temp = traceDataCache_->GetThreadStateData()->AppendThreadState(ts, INVALID_UINT64, INVALID_UINT64, + auto temp = traceDataCache_->GetThreadStateData()->AppendThreadState(ts, INVALID_TIME, INVALID_CPU, prevPid, prevState); RemberInternalTidInStateTable(prevPid, temp, prevState); } } -void CpuFilter::ExecInsertWakeupEvent(uint64_t ts, uint64_t internalTid) +bool CpuFilter::InsertProcessExitEvent(uint64_t ts, uint64_t cpu, uint64_t pid) +{ + UNUSED(cpu); + auto thread = traceDataCache_->GetThreadData(static_cast(pid)); + if (thread) { + thread->endT_ = ts; + return true; + } + return false; +} + +bool CpuFilter::InsertProcessFreeEvent(uint64_t ts, uint64_t pid) +{ + auto thread = traceDataCache_->GetThreadData(static_cast(pid)); + if (thread) { + thread->endT_ = ts; + return true; + } + return false; +} +void CpuFilter::InsertWakeupEvent(uint64_t ts, uint64_t internalTid) { /* repeated wakeup msg may come, we only record last wakeupmsg, and the wakeup will only insert to DataCache when a sched_switch comes */ if (lastWakeUpMsg.find(internalTid) != lastWakeUpMsg.end()) { - lastWakeUpMsg.at(internalTid) = ts; + // waking event is alaways before wakeup event + // use waking event only lastWakeUpMsg.at(internalTid) = ts; } else { lastWakeUpMsg.insert(std::make_pair(internalTid, ts)); } } -bool CpuFilter::ExecInsertProcessExitEvent(uint64_t ts, uint64_t cpu, uint64_t pid) +uint64_t CpuFilter::RemberInternalTidInStateTable(uint64_t uid, uint64_t row, uint64_t state) { - UNUSED(cpu); - auto thread = traceDataCache_->GetThreadData(static_cast(pid)); - if (thread) { - thread->endT_ = ts; - return true; + if (internalTidToRowThreadState_.find(uid) != internalTidToRowThreadState_.end()) { + internalTidToRowThreadState_.at(uid) = TPthread{row, state}; + } else { + internalTidToRowThreadState_.insert(std::make_pair(uid, TPthread{row, state})); } - return false; + return 0; } uint64_t CpuFilter::RowOfInternalTidInStateTable(uint64_t uid) const { @@ -209,9 +136,9 @@ void CpuFilter::CheckWakeupEvent(uint64_t internalTid) return; } if (lastrow != INVALID_UINT64) { - traceDataCache_->GetThreadStateData()->UpdateDuration(lastrow, ts); + traceDataCache_->GetThreadStateData()->UpdateDuration(static_cast(lastrow), ts); } - auto index = traceDataCache_->GetThreadStateData()->AppendThreadState(ts, INVALID_UINT64, INVALID_UINT64, + auto index = traceDataCache_->GetThreadStateData()->AppendThreadState(ts, INVALID_TIME, INVALID_CPU, internalTid, TASK_RUNNABLE); RemberInternalTidInStateTable(internalTid, index, TASK_RUNNABLE); } diff --git a/host/trace_streamer/src/filter/cpu_filter.h b/host/trace_streamer/src/filter/cpu_filter.h index a798a11664ec875ab258bb85f40e24752d228a05..626438b7f47e17417bf29cbd2c4342bf7b893e8c 100644 --- a/host/trace_streamer/src/filter/cpu_filter.h +++ b/host/trace_streamer/src/filter/cpu_filter.h @@ -48,86 +48,12 @@ public: void InsertWakeupEvent(uint64_t ts, uint64_t internalTid); bool InsertProcessExitEvent(uint64_t ts, uint64_t cpu, uint64_t pid); bool InsertProcessFreeEvent(uint64_t ts, uint64_t pid); - void FinishCpuEvent(); private: - void MaybeDealEvent(); - - class TSSwitchEvent { - public: - TSSwitchEvent(uint64_t ts, - uint64_t cpu, - uint64_t prevPid, - uint64_t prevPior, - uint64_t prevState, - uint64_t nextPid, - uint64_t nextPior) - : ts_(ts), - cpu_(cpu), - prevPid_(prevPid), - prevPior_(prevPior), - prevState_(prevState), - nextPid_(nextPid), - nextPior_(nextPior) - - { - } - ~TSSwitchEvent() {} - uint64_t ts_; - uint64_t cpu_; - uint64_t prevPid_; - uint64_t prevPior_; - uint64_t prevState_; - uint64_t nextPid_; - uint64_t nextPior_; - }; - class TSWakeupEvent { - public: - TSWakeupEvent(uint64_t ts, uint64_t pid) : ts_(ts), pid_(pid) {} - ~TSWakeupEvent() {} - uint64_t ts_; - uint64_t pid_; - }; - class TSProcessExitEvent { - public: - TSProcessExitEvent(uint64_t ts, uint64_t cpu, uint64_t pid) : ts_(ts), cpu_(cpu), pid_(pid) {} - ~TSProcessExitEvent() {} - uint64_t ts_; - uint64_t cpu_; - uint64_t pid_; - }; - enum TSCpuEventType { - TS_EVENT_THREAD_SWITCH, - TS_EVENT_THREAD_WAKING, - TS_EVENT_PROCESS_EXIT, - TS_EVENT_PROCESS_FREE - }; - class TSCpuEvent { - public: - TSCpuEvent() {} - ~TSCpuEvent() {} - TSCpuEventType type_; - // us union below will be a good choice - // but union with unique_ptr can bring about runtime error on windows and mac,only work well on linux - std::unique_ptr switchEvent_ = {}; - std::unique_ptr wakeupEvent_ = {}; - std::unique_ptr processExitEvent_ = {}; - }; - void DealEvent(const TSCpuEvent* event); - void ExecInsertSwitchEvent(uint64_t ts, - uint64_t cpu, - uint64_t prevPid, - uint64_t prevPior, - uint64_t prevState, - uint64_t nextPid, - uint64_t nextPior); - void ExecInsertWakeupEvent(uint64_t ts, uint64_t internalTid); - bool ExecInsertProcessExitEvent(uint64_t ts, uint64_t cpu, uint64_t pid); void CheckWakeupEvent(uint64_t internalTid); uint64_t RemberInternalTidInStateTable(uint64_t uid, uint64_t row, uint64_t state = TASK_INVALID); uint64_t RowOfInternalTidInStateTable(uint64_t uid) const; uint64_t StateOfInternalTidInStateTable(uint64_t uid) const; - std::multimap> tsCpuEventQueue_; std::map cpuToRowThreadState_ = {}; std::map cpuToRowSched_ = {}; std::map lastWakeUpMsg = {}; @@ -137,10 +63,6 @@ private: uint64_t state_; }; std::map internalTidToRowThreadState_ = {}; - // timestamp of ftrace events from different cpu can be outof order - // keep a cache of ftrace events in memory and keep msg in order - // the value below is the count of msg, maybe you can change it - const size_t MAX_CACHE_SIZE = 10000; }; } // namespace TraceStreamer } // namespace SysTuning diff --git a/host/trace_streamer/src/filter/filter.pri b/host/trace_streamer/src/filter/filter.pri deleted file mode 100644 index 1de2180993eaf1e2197e3f0ae56f0d02a212d70f..0000000000000000000000000000000000000000 --- a/host/trace_streamer/src/filter/filter.pri +++ /dev/null @@ -1,43 +0,0 @@ -# Copyright (C) 2021 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. - -INCLUDEPATH +=$$PWD \ - $$PWD/../cfg -HEADERS += \ - $$PWD/clock_filter.h \ - $$PWD/cpu_filter.h \ - $$PWD/filter_base.h \ - $$PWD/filter_filter.h \ - $$PWD/measure_filter.h \ - $$PWD/process_filter.h \ - $$PWD/slice_filter.h \ - $$PWD/symbols_filter.h \ - $$PWD/stat_filter.h \ - $$PWD/binder_filter.h \ - $$PWD/args_filter.h \ - $$PWD/irq_filter.h \ - $$PWD/system_event_measure_filter.h -SOURCES += \ - $$PWD/clock_filter.cpp \ - $$PWD/cpu_filter.cpp \ - $$PWD/filter_base.cpp \ - $$PWD/filter_filter.cpp \ - $$PWD/measure_filter.cpp \ - $$PWD/process_filter.cpp \ - $$PWD/slice_filter.cpp \ - $$PWD/symbols_filter.cpp \ - $$PWD/stat_filter.cpp \ - $$PWD/binder_filter.cpp \ - $$PWD/args_filter.cpp \ - $$PWD/irq_filter.cpp \ - $$PWD/system_event_measure_filter.cpp diff --git a/host/trace_streamer/src/filter/irq_filter.h b/host/trace_streamer/src/filter/irq_filter.h index d13c9b34216721c3f7529b97e58eb2c8402fe239..57076d48f617c2f052778b346c44f3cb00c7a805 100644 --- a/host/trace_streamer/src/filter/irq_filter.h +++ b/host/trace_streamer/src/filter/irq_filter.h @@ -37,12 +37,12 @@ public: void SoftIrqExit(int64_t ts, uint32_t cpu, uint32_t vec); private: - DataIndex irqId_ = traceDataCache_->GetDataIndex("irq_id"); - DataIndex irqRet_ = traceDataCache_->GetDataIndex("irq_ret"); - DataIndex irqHandled_ = traceDataCache_->GetDataIndex("handled"); - DataIndex irqUnHandled_ = traceDataCache_->GetDataIndex("unhandled"); - DataIndex irqCatalog_ = traceDataCache_->GetDataIndex("irq"); - DataIndex softIrqCatalog_ = traceDataCache_->GetDataIndex("softirq"); + const DataIndex irqId_ = traceDataCache_->GetDataIndex("irq_id"); + const DataIndex irqRet_ = traceDataCache_->GetDataIndex("irq_ret"); + const DataIndex irqHandled_ = traceDataCache_->GetDataIndex("handled"); + const DataIndex irqUnHandled_ = traceDataCache_->GetDataIndex("unhandled"); + const DataIndex irqCatalog_ = traceDataCache_->GetDataIndex("irq"); + const DataIndex softIrqCatalog_ = traceDataCache_->GetDataIndex("softirq"); std::unordered_map lastEventTs_ = {}; std::unordered_set transReplyWaitingReply_ = {}; std::unordered_map transWaitingRcv_ = {}; diff --git a/host/trace_streamer/src/filter/measure_filter.h b/host/trace_streamer/src/filter/measure_filter.h index ef8efeb43c229171506b0ef7250786241c2714dc..9bcc13af77307f7aad55bca03d692854d9290cf1 100644 --- a/host/trace_streamer/src/filter/measure_filter.h +++ b/host/trace_streamer/src/filter/measure_filter.h @@ -67,12 +67,12 @@ private: { E_CLK_ENABLE_FILTER, "clk_enable_filter" }, { E_CLK_DISABLE_FILTER, "clk_disable_filter" } }; - DataIndex clockSetRateDataIndex_ = traceDataCache_->GetDataIndex("clock_set_rate"); - DataIndex clockEnableDataIndex_ = traceDataCache_->GetDataIndex("clock_enable"); - DataIndex clockDisableDataIndex_ = traceDataCache_->GetDataIndex("clock_disable"); - DataIndex clkSetRateDataIndex_ = traceDataCache_->GetDataIndex("clk_set_rate"); - DataIndex clkEnableDataIndex_ = traceDataCache_->GetDataIndex("clk_enable"); - DataIndex clkDisableDataIndex_ = traceDataCache_->GetDataIndex("clk_disable"); + const DataIndex clockSetRateDataIndex_ = traceDataCache_->GetDataIndex("clock_set_rate"); + const DataIndex clockEnableDataIndex_ = traceDataCache_->GetDataIndex("clock_enable"); + const DataIndex clockDisableDataIndex_ = traceDataCache_->GetDataIndex("clock_disable"); + const DataIndex clkSetRateDataIndex_ = traceDataCache_->GetDataIndex("clk_set_rate"); + const DataIndex clkEnableDataIndex_ = traceDataCache_->GetDataIndex("clk_enable"); + const DataIndex clkDisableDataIndex_ = traceDataCache_->GetDataIndex("clk_disable"); }; } // namespace TraceStreamer } // namespace SysTuning diff --git a/host/trace_streamer/src/filter/perf_data_filter.cpp b/host/trace_streamer/src/filter/perf_data_filter.cpp new file mode 100644 index 0000000000000000000000000000000000000000..db8d8905b12a50667c5d1658cb996d46b880e257 --- /dev/null +++ b/host/trace_streamer/src/filter/perf_data_filter.cpp @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2021 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. + */ +#include "perf_data_filter.h" +#include "measure_filter.h" +#include "process_filter.h" +#include "slice_filter.h" +#include "string_to_numerical.h" +namespace SysTuning { +namespace TraceStreamer { +PerfDataFilter::PerfDataFilter(TraceDataCache* dataCache, const TraceStreamerFilters* filter) + : FilterBase(dataCache, filter), fileIdToRowInFileTable_(INVALID_UINT64), fileIdToRowInChainTable_(INVALID_UINT64) +{ +} +PerfDataFilter::~PerfDataFilter() = default; + +size_t PerfDataFilter::AppendPerfFiles(uint64_t fileId, uint32_t serial, DataIndex symbols, DataIndex filePath) +{ + fileIds_.emplace(fileId); + auto size = traceDataCache_->GetPerfFilesData()->AppendNewPerfFiles(fileId, serial, symbols, filePath); + fileIdToRowInFileTable_.Insert(fileId, serial, size); + if (!serial) { + fileIdToRow_.insert(std::make_pair(fileId, size)); + } + return size; +} + +size_t PerfDataFilter::AppendPerfCallChain(uint64_t sampleId, + uint64_t callchainId, + uint64_t vaddrInFile, + uint64_t fileId, + uint64_t symbolId) +{ + auto size = traceDataCache_->GetPerfCallChainData()->AppendNewPerfCallChain(sampleId, callchainId, vaddrInFile, + fileId, symbolId); + fileIdToRowInChainTable_.Insert(fileId, symbolId, size); + return size; +} +void PerfDataFilter::Finish() +{ + auto fileIds = traceDataCache_->GetPerfCallChainData()->FileIds(); + auto symbolsIds = traceDataCache_->GetPerfCallChainData()->SymbolIds(); + auto size = traceDataCache_->GetPerfCallChainData()->Size(); + auto filePath = traceDataCache_->GetPerfFilesData()->FilePaths(); + auto sambols = traceDataCache_->GetPerfFilesData()->Symbols(); + uint64_t flag = 1; + flag = ~(flag << 63); + for (auto i = 0; i < size; i++) { + if (fileIds_.find(fileIds[i]) == fileIds_.end()) { + // When the function name is empty and there is no file information to which the function belongs, + // set the function name to the virtual address of the function in the file + traceDataCache_->GetPerfCallChainData()->SetName( + i, "+0x" + base::number(traceDataCache_->GetPerfCallChainData()->VaddrInFiles()[i] & flag)); + continue; + } + if (symbolsIds[i] == -1) { + // When the function name is empty, if there has the file Id to which the function belongs,but the symboleid + // is -1. Set the function name as "the file name of the function at the top of the callstack + the virtual + // address of this function" + auto pathIndex = filePath[fileIdToRow_.at(fileIds[i])]; + auto fullPath = traceDataCache_->GetDataFromDict(pathIndex); + auto iPos = fullPath.find_last_of('/'); + fullPath = fullPath.substr(iPos + 1, -1); + traceDataCache_->GetPerfCallChainData()->SetName( + i, fullPath + "+0x" + base::number(traceDataCache_->GetPerfCallChainData()->VaddrInFiles()[i] & flag)); + continue; + } + // When the function name is empty, if there has the file Id to which the function belongs,and the symboleid + // is not -1. Set the function name as the virtual address of this function + auto value = fileIdToRowInFileTable_.Find(fileIds[i], symbolsIds[i]); + if (value == INVALID_UINT64) { + traceDataCache_->GetPerfCallChainData()->SetName( + i, "+0x" + base::number(traceDataCache_->GetPerfCallChainData()->VaddrInFiles()[i] & flag)); + continue; + } + // The function name is not empty + traceDataCache_->GetPerfCallChainData()->SetName(i, traceDataCache_->GetDataFromDict(sambols[value])); + } +} +} // namespace TraceStreamer +} // namespace SysTuning diff --git a/host/trace_streamer/src/filter/perf_data_filter.h b/host/trace_streamer/src/filter/perf_data_filter.h new file mode 100644 index 0000000000000000000000000000000000000000..e61c3e57136f9e4ec1debcba572f8432cce24554 --- /dev/null +++ b/host/trace_streamer/src/filter/perf_data_filter.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2021 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. + */ + +#ifndef PERF_DATA_FILTER_H +#define PERF_DATA_FILTER_H +#include +#include +#include +#include "filter_base.h" +#include "trace_data_cache.h" +#include "trace_streamer_filters.h" +#include "double_map.h" +namespace SysTuning { +namespace TraceStreamer { +class PerfDataFilter : private FilterBase { +public: + PerfDataFilter(TraceDataCache*, const TraceStreamerFilters*); + PerfDataFilter(const PerfDataFilter&) = delete; + PerfDataFilter& operator=(const PerfDataFilter&) = delete; + ~PerfDataFilter() override; + +public: + size_t AppendPerfFiles(uint64_t fileId, uint32_t serial, DataIndex symbols, DataIndex filePath); + size_t AppendPerfCallChain(uint64_t sampleId, + uint64_t callchainId, + uint64_t vaddrInFile, + uint64_t fileId, + uint64_t symbolId); + void Finish(); + +private: + DoubleMap fileIdToRowInFileTable_; + DoubleMap fileIdToRowInChainTable_; + std::set fileIds_; + std::map fileIdToRow_{}; +}; +} // namespace TraceStreamer +} // namespace SysTuning + +#endif // PERF_DATA_FILTER_H diff --git a/host/trace_streamer/src/filter/slice_filter.cpp b/host/trace_streamer/src/filter/slice_filter.cpp index 5ae3854fea33cd9ae923fdedea937a2179e806e7..6c181103c9be816bd5427b88d9e5c10ab604bcf1 100644 --- a/host/trace_streamer/src/filter/slice_filter.cpp +++ b/host/trace_streamer/src/filter/slice_filter.cpp @@ -134,11 +134,25 @@ size_t SliceFilter::BeginAsyncBinder(uint64_t timestamp, uint32_t pid, DataIndex if (args.valuesMap_.size()) { argSetId = streamFilters_->argsFilter_->NewArgs(args); slices->AppendArgSet(argSetId); - binderQueue_[pid] = argSetId; +#ifdef BINDER_EXP + if (binderQueue_.count(pid) > MAX_BINDER_EVENT_NOT_MATCH) { + TS_LOGE("more than %zu binder events do not match, clear them, pid:%d", MAX_BINDER_EVENT_NOT_MATCH, pid); + binderQueue_.erase(pid); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_BINDER_TRANSACTION, STAT_EVENT_DATA_LOST); + } +#endif + binderQueue_.emplace(pid, argSetId); } else { argSetId = streamFilters_->argsFilter_->NewArgs(args); slices->AppendArgSet(argSetId); - binderQueue_[pid] = argSetId; +#ifdef BINDER_EXP + if (binderQueue_.count(pid) > MAX_BINDER_EVENT_NOT_MATCH) { + TS_LOGE("more than %zu binder events do not match, clear them, pid:%d", MAX_BINDER_EVENT_NOT_MATCH, pid); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_BINDER_TRANSACTION, STAT_EVENT_DATA_LOST); + binderQueue_.erase(pid); + } +#endif + binderQueue_.emplace(pid, argSetId); } argsToSliceQueue_[argSetId] = static_cast(index); return index; @@ -150,25 +164,24 @@ size_t SliceFilter::BeginBinder(uint64_t timestamp, uint32_t pid, DataIndex cat, struct SliceData sliceData = {timestamp, 0, internalTid, cat, nameIndex}; auto slices = traceDataCache_->GetInternalSlicesData(); - auto sliceStack = &sliceStackMap_[sliceData.internalTid]; + auto sliceStack = &binderStackMap_[sliceData.internalTid]; if (sliceStack->size() >= std::numeric_limits::max()) { TS_LOGW("stack depth out of range."); } const uint8_t depth = static_cast(sliceStack->size()); size_t index = slices->AppendInternalSlice(sliceData.timestamp, sliceData.duration, sliceData.internalTid, sliceData.cat, sliceData.name, depth, std::nullopt); - sliceStack->push_back(index); uint32_t argSetId = INVALID_INT32; if (args.valuesMap_.size()) { argSetId = streamFilters_->argsFilter_->NewArgs(args); slices->AppendArgSet(argSetId); - binderQueue_[pid] = argSetId; + binderQueue_.emplace(pid, argSetId); } else { argSetId = streamFilters_->argsFilter_->NewArgs(args); slices->AppendArgSet(argSetId); - binderQueue_[pid] = argSetId; + binderQueue_.emplace(pid, argSetId); } argsToSliceQueue_[argSetId] = static_cast(index); return index; @@ -176,33 +189,39 @@ size_t SliceFilter::BeginBinder(uint64_t timestamp, uint32_t pid, DataIndex cat, uint32_t SliceFilter::AddArgs(uint32_t tid, DataIndex key1, DataIndex key2, ArgsSet &args) { - if (!binderQueue_.count(tid)) { + auto argSize = binderQueue_.count(tid); + if (!argSize) { return INVALID_UINT32; } - streamFilters_->argsFilter_->AppendArgs(args, binderQueue_[tid]); - return argsToSliceQueue_[binderQueue_[tid]]; + auto it = binderQueue_.equal_range(tid); + auto itor = it.first; + streamFilters_->argsFilter_->AppendArgs(args, itor->second); + return argsToSliceQueue_[itor->second]; } bool SliceFilter::EndBinder(uint64_t timestamp, uint32_t pid, DataIndex category, DataIndex name, ArgsSet args) { - if (!binderQueue_.count(pid)) { + auto argSize = binderQueue_.count(pid); + if (!argSize) { return false; } - auto lastRow = argsToSliceQueue_[binderQueue_[pid]]; + auto it = binderQueue_.equal_range(pid); + auto itor = it.first; + auto lastRow = argsToSliceQueue_[itor->second]; auto slices = traceDataCache_->GetInternalSlicesData(); slices->SetDuration(lastRow, timestamp); - streamFilters_->argsFilter_->AppendArgs(args, binderQueue_[pid]); - argsToSliceQueue_.erase(binderQueue_[pid]); + streamFilters_->argsFilter_->AppendArgs(args, itor->second); + argsToSliceQueue_.erase(itor->second); - binderQueue_.erase(pid); + binderQueue_.erase(itor); InternalTid internalTid = streamFilters_->processFilter_->UpdateOrCreateThread(timestamp, pid); - const auto& stack = sliceStackMap_[internalTid]; + const auto& stack = binderStackMap_[internalTid]; if (stack.empty()) { TS_LOGE("a slice end do not match a slice start event"); callEventDisMatchCount++; return false; } - sliceStackMap_[internalTid].pop_back(); + binderStackMap_[internalTid].pop_back(); return true; } @@ -322,11 +341,11 @@ bool SliceFilter::EndSlice(uint64_t timestamp, uint32_t pid, uint32_t threadGrou size_t index = stack.back(); slices->SetDuration(index, timestamp); sliceStackMap_[internalTid].pop_back(); - // update dur of parent slice maybe - auto parentId = slices->ParentIdData()[index]; - if (parentId.has_value()) { - slices->SetDuration(parentId.value(), timestamp); - } + // update dur of parent slice maybe, + // just marke the dur as -1, auto parentId = slices->ParentIdData()[index]; + // just marke the dur as -1, if (parentId.has_value()) { + // just marke the dur as -1, slices->SetDuration(parentId.value(), timestamp); + // just marke the dur as -1, } return true; } diff --git a/host/trace_streamer/src/filter/slice_filter.h b/host/trace_streamer/src/filter/slice_filter.h index c2cb7ad83412c26916311ad332e13ed654a0d6bb..5798258279fa0ceedf84b96541753caa874e6fb9 100644 --- a/host/trace_streamer/src/filter/slice_filter.h +++ b/host/trace_streamer/src/filter/slice_filter.h @@ -81,13 +81,16 @@ private: uint64_t asyncEventSize_ = 0; uint64_t asyncEventDisMatchCount = 0; uint64_t callEventDisMatchCount = 0; - std::unordered_map binderQueue_ = {}; + std::unordered_multimap binderQueue_ = {}; std::unordered_map argsToSliceQueue_ = {}; struct SliceInfo { uint32_t row; ArgsSet args_tracker; }; std::unordered_map> argsSet_ = {}; +#ifdef BINDER_EXP + const size_t MAX_BINDER_EVENT_NOT_MATCH = 1000; +#endif }; } // namespace TraceStreamer } // namespace SysTuning diff --git a/host/trace_streamer/src/include/file.h b/host/trace_streamer/src/include/file.h index 97be5664c8497e15aaa1d121bc77b9778a8a3131..221c9f54402c3457e3441f5a664915f654dbb69a 100644 --- a/host/trace_streamer/src/include/file.h +++ b/host/trace_streamer/src/include/file.h @@ -27,6 +27,36 @@ enum TraceParserStatus { TRACE_PARSE_ERROR = 2, TRACE_PARSER_ABNORMAL = 3 }; +struct ProfilerTraceFileHeader { + // Some space is reserved to facilitate the subsequent addition of fields in the header + static constexpr uint32_t HEADER_SIZE = 1024; + static constexpr uint32_t SHA256_SIZE = 256 / 8; + static constexpr uint64_t HEADER_MAGIC = 0x464F5250534F484FuLL; + static constexpr uint32_t V_MAJOR = 0x0001; + static constexpr uint32_t V_MAJOR_BITS = 16; + static constexpr uint32_t V_MINOR = 0x0000; + static constexpr uint32_t TRACE_VERSION = (V_MAJOR << V_MAJOR_BITS) | V_MINOR; + enum DataType { + HIPROFILER_PROTOBUF_BIN = 0, + HIPERF_DATA, + UNKNOW_TYPE = 1024, + }; + struct HeaderData { + // Magic number, used to distinguish offline files + uint64_t magic_ = HEADER_MAGIC; + // Total length, which can be used to check whether the document is truncated; + uint64_t length_ = HEADER_SIZE; + uint32_t version_ = TRACE_VERSION; + // The number of segments in the load data. The number of segments is even. One describes the length L and the + // other describes the next data v + uint32_t segments_ = 0; + // Sha256 of load data is used to verify whether the load data is complete; + uint8_t sha256_[SHA256_SIZE] = {}; + DataType dataType_ = UNKNOW_TYPE; + } __attribute__((packed)); + HeaderData data_ = {}; + uint8_t padding_[HEADER_SIZE - sizeof(data_)] = {}; +}; void SetAnalysisResult(TraceParserStatus stat); diff --git a/host/trace_streamer/src/include/string_to_numerical.h b/host/trace_streamer/src/include/string_to_numerical.h index 3340f5009fabbb38351458ddf3710da1e735399a..8b2ad70b021703548353f9df92b14d827ac835b1 100644 --- a/host/trace_streamer/src/include/string_to_numerical.h +++ b/host/trace_streamer/src/include/string_to_numerical.h @@ -29,18 +29,21 @@ enum IntegerRadixType { inline std::optional StrToUInt32(const std::string& str, int base = INTEGER_RADIX_TYPE_DEC) { if (!str.empty()) { - uint32_t value = static_cast(std::stoul(str, nullptr, base)); - return std::make_optional(value); + char* endPtr = nullptr; + auto value = static_cast(std::strtoul(str.c_str(), &endPtr, base)); + if (!*endPtr) { + return std::make_optional(value); + } } return std::nullopt; } -inline std::string number(int value, int base = INTEGER_RADIX_TYPE_DEC) +inline std::string number(uint64_t value, int base = INTEGER_RADIX_TYPE_DEC) { std::stringstream ss; if (base == INTEGER_RADIX_TYPE_DEC) { - ss << std::oct << value; + ss << std::dec << value; } else if (base == INTEGER_RADIX_TYPE_HEX) { ss << std::hex << value; } @@ -50,8 +53,11 @@ inline std::string number(int value, int base = INTEGER_RADIX_TYPE_DEC) inline std::optional StrToInt32(const std::string& str, int base = INTEGER_RADIX_TYPE_DEC) { if (!str.empty()) { - int32_t value = static_cast(std::stol(str, nullptr, base)); - return std::make_optional(value); + char* endPtr = nullptr; + auto value = static_cast(std::strtol(str.c_str(), &endPtr, base)); + if (!*endPtr) { + return std::make_optional(value); + } } return std::nullopt; @@ -60,8 +66,11 @@ inline std::optional StrToInt32(const std::string& str, int base = INTE inline std::optional StrToUInt64(const std::string& str, int base = INTEGER_RADIX_TYPE_DEC) { if (!str.empty()) { - uint64_t value = static_cast(std::stoull(str, nullptr, base)); - return std::make_optional(value); + char* endPtr = nullptr; + auto value = static_cast(std::strtoull(str.c_str(), &endPtr, base)); + if (!*endPtr) { + return std::make_optional(value); + } } return std::nullopt; @@ -70,8 +79,11 @@ inline std::optional StrToUInt64(const std::string& str, int base = IN inline std::optional StrToInt64(const std::string& str, int base = INTEGER_RADIX_TYPE_DEC) { if (!str.empty()) { - int64_t value = static_cast(std::stoll(str, nullptr, base)); - return std::make_optional(value); + char* endPtr = nullptr; + int64_t value = static_cast(std::strtoll(str.c_str(), &endPtr, base)); + if (!*endPtr) { + return std::make_optional(value); + } } return std::nullopt; } diff --git a/host/trace_streamer/src/main.cpp b/host/trace_streamer/src/main.cpp index 8b16b5a49261b986e9e698e39ed993ad0b42a5c8..9c7a56eb49445fc7823de8f603fb74ac92076f15 100644 --- a/host/trace_streamer/src/main.cpp +++ b/host/trace_streamer/src/main.cpp @@ -28,6 +28,7 @@ #include "filter/slice_filter.h" #include "http_server.h" #include "log.h" +#include "meta.h" #include "parser/bytrace_parser/bytrace_event_parser.h" #include "parser/bytrace_parser/bytrace_parser.h" #include "parting_string.h" @@ -45,9 +46,7 @@ using namespace SysTuning::base; constexpr size_t G_CHUNK_SIZE = 1024 * 1024; constexpr int G_MIN_PARAM_NUM = 2; constexpr size_t G_FILE_PERMISSION = 664; -size_t g_loadSize = 0; -const char* TRACE_STREAM_VERSION = "2.3.118"; // version -const char* TRACE_STREAM_PUBLISHVERSION = "2022/3/29"; // publish datetime +// set version info in meta.cpp please void ExportStatusToLog(const std::string& dbPath, TraceParserStatus status) { std::string path = dbPath + ".ohos.ts"; @@ -87,7 +86,7 @@ void PrintInformation() } void PrintVersion() { - fprintf(stderr, "version %s\n", TRACE_STREAM_VERSION); + fprintf(stderr, "version %s\n", TRACE_STREAM_VERSION.c_str()); } bool ReadAndParser(SysTuning::TraceStreamer::TraceStreamerSelector& ta, int fd) @@ -182,18 +181,18 @@ int ExportDatabase(TraceStreamerSelector& ts, const std::string& sqliteFilePath) return 0; } +struct TraceExportOption { + std::string traceFilePath; + std::string sqliteFilePath; + bool interactiveState = false; + bool exportMetaTable = true; +}; struct HttpOption { bool enable = false; int port = 9001; }; -int CheckArgs(int argc, - char** argv, - bool& interactiveState, - bool& exportMetaTable, - std::string& traceFilePath, - std::string& sqliteFilePath, - HttpOption& httpOption) +int CheckArgs(int argc, char** argv, TraceExportOption& traceExportOption, HttpOption& httpOption) { for (int i = 1; i < argc; i++) { if (!strcmp(argv[i], "-e")) { @@ -201,15 +200,15 @@ int CheckArgs(int argc, ShowHelpInfo(argv[0]); return 1; } - sqliteFilePath = std::string(argv[i]); + traceExportOption.sqliteFilePath = std::string(argv[i]); continue; } else if (!strcmp(argv[i], "-c") || !strcmp(argv[i], "--command")) { - interactiveState = true; + traceExportOption.interactiveState = true; continue; } else if (!strcmp(argv[i], "-i") || !strcmp(argv[i], "--info")) { PrintInformation(); } else if (!strcmp(argv[i], "-nm") || !strcmp(argv[i], "--nometa")) { - exportMetaTable = false; + traceExportOption.exportMetaTable = false; continue; } else if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--v") || !strcmp(argv[i], "-version") || !strcmp(argv[i], "--version")) { @@ -226,10 +225,11 @@ int CheckArgs(int argc, httpOption.port = std::stoi(argv[i]); continue; } - traceFilePath = std::string(argv[i]); + traceExportOption.traceFilePath = std::string(argv[i]); } - if ((traceFilePath.empty() || (!interactiveState && sqliteFilePath.empty())) - && !httpOption.enable) { + if ((traceExportOption.traceFilePath.empty() || + (!traceExportOption.interactiveState && traceExportOption.sqliteFilePath.empty())) && + !httpOption.enable) { ShowHelpInfo(argv[0]); return 1; } @@ -237,22 +237,18 @@ int CheckArgs(int argc, } } // namespace TraceStreamer } // namespace SysTuning - int main(int argc, char** argv) { if (argc < G_MIN_PARAM_NUM) { ShowHelpInfo(argv[0]); return 1; } - std::string traceFilePath; - std::string sqliteFilePath; - bool interactiveState = false; - bool exportMetaTable = true; + TraceExportOption tsOption; HttpOption httpOption; - int ret = CheckArgs(argc, argv, interactiveState, exportMetaTable, traceFilePath, sqliteFilePath, httpOption); + int ret = CheckArgs(argc, argv, tsOption, httpOption); if (ret) { - if (!sqliteFilePath.empty()) { - ExportStatusToLog(sqliteFilePath, GetAnalysisResult()); + if (!tsOption.sqliteFilePath.empty()) { + ExportStatusToLog(tsOption.sqliteFilePath, GetAnalysisResult()); } return 0; } @@ -265,23 +261,28 @@ int main(int argc, char** argv) return 0; } TraceStreamerSelector ts; - ts.EnableMetaTable(exportMetaTable); - if (OpenAndParserFile(ts, traceFilePath)) { - if (!sqliteFilePath.empty()) { - ExportStatusToLog(sqliteFilePath, GetAnalysisResult()); + ts.EnableMetaTable(tsOption.exportMetaTable); + if (OpenAndParserFile(ts, tsOption.traceFilePath)) { + if (!tsOption.sqliteFilePath.empty()) { + ExportStatusToLog(tsOption.sqliteFilePath, GetAnalysisResult()); } return 1; } - if (interactiveState) { + if (tsOption.interactiveState) { + MetaData* metaData = ts.GetMetaData(); + metaData->SetOutputFileName("command line mode"); + metaData->SetParserToolVersion(TRACE_STREAM_VERSION.c_str()); + metaData->SetParserToolPublishDateTime(TRACE_STREAM_PUBLISHVERSION.c_str()); + metaData->SetTraceDataSize(g_loadSize); ts.SearchData(); return 0; } - if (ExportDatabase(ts, sqliteFilePath)) { - ExportStatusToLog(sqliteFilePath, GetAnalysisResult()); + if (ExportDatabase(ts, tsOption.sqliteFilePath)) { + ExportStatusToLog(tsOption.sqliteFilePath, GetAnalysisResult()); return 1; } - if (!sqliteFilePath.empty()) { - ExportStatusToLog(sqliteFilePath, GetAnalysisResult()); + if (!tsOption.sqliteFilePath.empty()) { + ExportStatusToLog(tsOption.sqliteFilePath, GetAnalysisResult()); } return 0; } diff --git a/host/trace_streamer/src/multi_platform/BUILD.gn b/host/trace_streamer/src/multi_platform/BUILD.gn deleted file mode 100644 index 35da1afb016d016c274e973b3089cff451e5daa3..0000000000000000000000000000000000000000 --- a/host/trace_streamer/src/multi_platform/BUILD.gn +++ /dev/null @@ -1,305 +0,0 @@ -# Copyright (C) 2021 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. -import("//build/ohos.gni") -import("../ts.gni") -if (use_wasm) { -} else { -} -if (use_wasm) { - source_set("proto_services_cpp") { - sources = [ - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/compaction.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/compaction.pb.h", - ] - include_dirs = [ - "//third_party/protobuf/src", - "//src/include", - ] - } -} else { - shared_library("proto_services_cpp") { - sources = [ - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/compaction.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/compaction.pb.h", - ] - include_dirs = [ - "//third_party/protobuf/src", - "//src/include", - ] - } -} -if (use_wasm) { - source_set("ftrace_data_cpp") { - sources = [ - "${OHOS_PROTO_GEN}/services/common_types.pb.cc", - "${OHOS_PROTO_GEN}/services/common_types.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/binder.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/binder.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/block.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/block.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/cgroup.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/cgroup.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/clk.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/clk.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/cpuhp.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/cpuhp.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/dma_fence.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/dma_fence.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/ext4.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/ext4.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/filelock.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/filelock.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/filemap.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/filemap.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/ftrace.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/ftrace.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/ftrace_event.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/ftrace_event.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/gpio.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/gpio.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/i2c.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/i2c.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/ipi.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/ipi.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/irq.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/irq.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/kmem.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/kmem.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/net.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/net.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/oom.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/oom.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/pagemap.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/pagemap.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/power.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/power.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/printk.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/printk.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/raw_syscalls.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/raw_syscalls.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/rcu.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/rcu.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/sched.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/sched.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/signal.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/signal.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/sunrpc.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/sunrpc.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/task.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/task.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/timer.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/timer.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/trace_plugin_result.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/trace_plugin_result.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/v4l2.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/v4l2.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/vmscan.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/vmscan.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/workqueue.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/workqueue.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/writeback.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/writeback.pb.h", - ] - include_dirs = [ - "//third_party/protobuf/src", - "//src/include", - ] - } -} else { - shared_library("ftrace_data_cpp") { - sources = [ - "${OHOS_PROTO_GEN}/services/common_types.pb.cc", - "${OHOS_PROTO_GEN}/services/common_types.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/binder.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/binder.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/block.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/block.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/cgroup.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/cgroup.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/clk.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/clk.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/cpuhp.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/cpuhp.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/dma_fence.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/dma_fence.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/ext4.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/ext4.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/filelock.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/filelock.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/filemap.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/filemap.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/ftrace.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/ftrace.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/ftrace_event.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/ftrace_event.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/gpio.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/gpio.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/i2c.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/i2c.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/ipi.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/ipi.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/irq.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/irq.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/kmem.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/kmem.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/net.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/net.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/oom.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/oom.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/pagemap.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/pagemap.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/power.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/power.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/printk.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/printk.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/raw_syscalls.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/raw_syscalls.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/rcu.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/rcu.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/sched.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/sched.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/signal.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/signal.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/sunrpc.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/sunrpc.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/task.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/task.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/timer.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/timer.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/trace_plugin_result.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/trace_plugin_result.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/v4l2.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/v4l2.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/vmscan.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/vmscan.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/workqueue.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/workqueue.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/writeback.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/ftrace_data/writeback.pb.h", - ] - include_dirs = [ - "//third_party/protobuf/src", - "//src/include", - ] - } -} -if (use_wasm) { - source_set("memory_data_cpp") { - sources = [ - "${OHOS_PROTO_GEN}/types/plugins/memory_data/memory_plugin_common.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/memory_data/memory_plugin_common.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/memory_data/memory_plugin_config.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/memory_data/memory_plugin_config.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/memory_data/memory_plugin_result.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/memory_data/memory_plugin_result.pb.h", - ] - include_dirs = [ - "//third_party/protobuf/src", - "//src/include", - ] - } -} else { - shared_library("memory_data_cpp") { - sources = [ - "${OHOS_PROTO_GEN}/types/plugins/memory_data/memory_plugin_common.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/memory_data/memory_plugin_common.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/memory_data/memory_plugin_config.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/memory_data/memory_plugin_config.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/memory_data/memory_plugin_result.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/memory_data/memory_plugin_result.pb.h", - ] - include_dirs = [ - "//third_party/protobuf/src", - "//src/include", - ] - } -} -if (use_wasm) { - source_set("hilog_data_cpp") { - sources = [ - "${OHOS_PROTO_GEN}/types/plugins/hilog_data/hilog_plugin_result.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/hilog_data/hilog_plugin_result.pb.h", - ] - include_dirs = [ - "//third_party/protobuf/src", - "//src/include", - ] - } -} else { - shared_library("hilog_data_cpp") { - sources = [ - "${OHOS_PROTO_GEN}/types/plugins/hilog_data/hilog_plugin_result.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/hilog_data/hilog_plugin_result.pb.h", - ] - include_dirs = [ - "//third_party/protobuf/src", - "//src/include", - ] - } -} - -if (use_wasm) { - source_set("native_hook_cpp") { - sources = [ - "${OHOS_PROTO_GEN}/types/plugins/native_hook/native_hook_config.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/native_hook/native_hook_config.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/native_hook/native_hook_result.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/native_hook/native_hook_result.pb.h", - ] - include_dirs = [ - "//third_party/protobuf/src", - "//src/include", - ] - } -} else { - shared_library("native_hook_cpp") { - sources = [ - "${OHOS_PROTO_GEN}/types/plugins/native_hook/native_hook_config.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/native_hook/native_hook_config.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/native_hook/native_hook_result.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/native_hook/native_hook_result.pb.h", - ] - include_dirs = [ - "//third_party/protobuf/src", - "//src/include", - ] - } -} - -if (use_wasm) { - source_set("hidump_data_cpp") { - sources = [ - "${OHOS_PROTO_GEN}/types/plugins/hidump_data/hidump_plugin_config.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/hidump_data/hidump_plugin_config.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/hidump_data/hidump_plugin_result.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/hidump_data/hidump_plugin_result.pb.h", - ] - include_dirs = [ - "//third_party/protobuf/src", - "//src/include", - ] - } -} else { - shared_library("hidump_data_cpp") { - sources = [ - "${OHOS_PROTO_GEN}/types/plugins/hidump_data/hidump_plugin_config.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/hidump_data/hidump_plugin_config.pb.h", - "${OHOS_PROTO_GEN}/types/plugins/hidump_data/hidump_plugin_result.pb.cc", - "${OHOS_PROTO_GEN}/types/plugins/hidump_data/hidump_plugin_result.pb.h", - ] - include_dirs = [ - "//third_party/protobuf/src", - "//src/include", - ] - } -} diff --git a/host/trace_streamer/src/multi_platform/global.pri b/host/trace_streamer/src/multi_platform/global.pri deleted file mode 100644 index a1dab5b59f50c843ae3cc438c38b50bcd8f23ae8..0000000000000000000000000000000000000000 --- a/host/trace_streamer/src/multi_platform/global.pri +++ /dev/null @@ -1,75 +0,0 @@ -# Copyright (C) 2021 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. - -#DEFINES +=_AIX -#DEFINES +=_GLIBCXX_BITS_STD_ABS_H -#DEFINES +=__CORRECT_ISO_CPP_STDLIB_H_PROTO -#DEFINES += __CORRECT_ISO_CPP11_MATH_H_PROTO_FP -#DEFINES +=__CORRECT_ISO_CPP_MATH_H_PROTO -#DEFINES +=_GLIBCXX_USE_C99_LONG_LONG_DYNAMIC - -INCLUDEPATH +=$${ROOTSRCDIR}/include -INCLUDEPATH +=$${ROOTSRCDIR}/ -CONFIG(debug, debug|release){ - BUILDVERSION = _debug - message("debug") -}else{ - message("release") - BUILDVERSION = - DEFINES += NDEBUG -} -contains(QT_ARCH, i386) { - message("qmake" $$TARGET "32-bit") - BIT = x32 -} else { - message("qmake" $$TARGET "64-bit") - BIT = -} -macx{ - PLATFORM = macx - TOOL = - BIT = -} -unix:!macx { - PLATFORM = linux - TOOL = - BIT = -} -win32 { - PLATFORM = windows - TOOL = -} -DESTFOLDER =$${PLATFORM}$${BIT}$${TOOL}$${BUILDVERSION} -islib{ -message("this is for lib") -DESTDIR = $${ROOTSRCDIR}/lib/$${DESTFOLDER} -} else { -message("this is for app") -DESTDIR = $${ROOTSRCDIR}/out/$${DESTFOLDER} -} -unix{ -QMAKE_CXXFLAGS += -BigObj -INCLUDEPATH += $$DESTDIR/gen/build_config -INCLUDEPATH += $$DESTDIR/gen -INCLUDEPATH +=/usr/include/c++/7 -INCLUDEPATH +=/usr/include/x86_64-linux-gnu/ -} else { -INCLUDEPATH += $${GENDIR}/gen/build_config -INCLUDEPATH += $${GENDIR}/gen -DEFINES += WIN32 -QMAKE_CXXFLAGS += -BigObj -staticlib{ -QMAKE_CXXFLAGS += -Ofast -flto -} -} -OBJECTS_DIR = $${ROOTSRCDIR}/tmp_$${TARGET}_$${DESTFOLDER} diff --git a/host/trace_streamer/src/multi_platform/protogen.pri b/host/trace_streamer/src/multi_platform/protogen.pri deleted file mode 100644 index 72da7fded06058c7c2aeef807a04ab35f2d50fdc..0000000000000000000000000000000000000000 --- a/host/trace_streamer/src/multi_platform/protogen.pri +++ /dev/null @@ -1,107 +0,0 @@ -# Copyright (C) 2021 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. -PROTOGEN = $$PWD/../../third_party/protogen -INCLUDEPATH += $${PROTOGEN}/types/plugins/ftrace_data \ - $${PROTOGEN}/types/plugins/memory_data \ - $${PROTOGEN}/types/plugins/hilog_data \ - $${PROTOGEN}/types/plugins/native_hook \ - $${PROTOGEN}/types/plugins/hidump_data \ - $${PROTOGEN} -SOURCES +=$${PROTOGEN}/services/common_types.pb.cc \ - $${PROTOGEN}/types/plugins/ftrace_data/trace_plugin_result.pb.cc \ - $${PROTOGEN}/types/plugins/ftrace_data/ftrace_event.pb.cc \ - $${PROTOGEN}/types/plugins/ftrace_data/irq.pb.cc \ - $${PROTOGEN}/types/plugins/ftrace_data/vmscan.pb.cc \ - $${PROTOGEN}/types/plugins/ftrace_data/workqueue.pb.cc \ - $${PROTOGEN}/types/plugins/ftrace_data/task.pb.cc \ - $${PROTOGEN}/types/plugins/ftrace_data/power.pb.cc \ - $${PROTOGEN}/types/plugins/ftrace_data/sched.pb.cc \ - $${PROTOGEN}/types/plugins/ftrace_data/filemap.pb.cc \ - $${PROTOGEN}/types/plugins/ftrace_data/i2c.pb.cc \ - $${PROTOGEN}/types/plugins/ftrace_data/kmem.pb.cc \ - $${PROTOGEN}/types/plugins/ftrace_data/block.pb.cc \ - $${PROTOGEN}/types/plugins/ftrace_data/ipi.pb.cc \ - $${PROTOGEN}/types/plugins/ftrace_data/ftrace.pb.cc \ - $${PROTOGEN}/types/plugins/ftrace_data/ext4.pb.cc \ - $${PROTOGEN}/types/plugins/ftrace_data/oom.pb.cc \ - $${PROTOGEN}/types/plugins/ftrace_data/compaction.pb.cc \ - $${PROTOGEN}/types/plugins/ftrace_data/clk.pb.cc \ - $${PROTOGEN}/types/plugins/ftrace_data/cgroup.pb.cc \ - $${PROTOGEN}/types/plugins/ftrace_data/binder.pb.cc \ - $${PROTOGEN}/types/plugins/ftrace_data/signal.pb.cc \ - $${PROTOGEN}/types/plugins/ftrace_data/sunrpc.pb.cc \ - $${PROTOGEN}/types/plugins/ftrace_data/net.pb.cc \ - $${PROTOGEN}/types/plugins/ftrace_data/cpuhp.pb.cc \ - $${PROTOGEN}/types/plugins/ftrace_data/writeback.pb.cc \ - $${PROTOGEN}/types/plugins/ftrace_data/v4l2.pb.cc \ - $${PROTOGEN}/types/plugins/ftrace_data/pagemap.pb.cc \ - $${PROTOGEN}/types/plugins/ftrace_data/dma_fence.pb.cc \ - $${PROTOGEN}/types/plugins/ftrace_data/printk.pb.cc \ - $${PROTOGEN}/types/plugins/ftrace_data/filelock.pb.cc \ - $${PROTOGEN}/types/plugins/ftrace_data/gpio.pb.cc \ - $${PROTOGEN}/types/plugins/ftrace_data/timer.pb.cc \ - $${PROTOGEN}/types/plugins/ftrace_data/raw_syscalls.pb.cc \ - $${PROTOGEN}/types/plugins/ftrace_data/rcu.pb.cc \ - \ - $${PROTOGEN}/types/plugins/memory_data/memory_plugin_common.pb.cc \ - $${PROTOGEN}/types/plugins/memory_data/memory_plugin_config.pb.cc \ - $${PROTOGEN}/types/plugins/memory_data/memory_plugin_result.pb.cc \ - $${PROTOGEN}/types/plugins/hilog_data/hilog_plugin_result.pb.cc \ - $${PROTOGEN}/types/plugins/native_hook/native_hook_result.pb.cc \ - $${PROTOGEN}/types/plugins/native_hook/native_hook_config.pb.cc \ - $${PROTOGEN}/types/plugins/hidump_data/hidump_plugin_result.pb.cc \ - $${PROTOGEN}/types/plugins/hidump_data/hidump_plugin_config.pb.cc - -HEADERS += $${PROTOGEN}/services/common_types.pb.h \ - $${PROTOGEN}/types/plugins/ftrace_data/trace_plugin_result.pb.h \ - $${PROTOGEN}/types/plugins/ftrace_data/ftrace_event.pb.h \ - $${PROTOGEN}/types/plugins/ftrace_data/irq.pb.h \ - $${PROTOGEN}/types/plugins/ftrace_data/vmscan.pb.h \ - $${PROTOGEN}/types/plugins/ftrace_data/workqueue.pb.h \ - $${PROTOGEN}/types/plugins/ftrace_data/task.pb.h \ - $${PROTOGEN}/types/plugins/ftrace_data/power.pb.h \ - $${PROTOGEN}/types/plugins/ftrace_data/sched.pb.h \ - $${PROTOGEN}/types/plugins/ftrace_data/filemap.pb.h \ - $${PROTOGEN}/types/plugins/ftrace_data/i2c.pb.h \ - $${PROTOGEN}/types/plugins/ftrace_data/kmem.pb.h \ - $${PROTOGEN}/types/plugins/ftrace_data/block.pb.h \ - $${PROTOGEN}/types/plugins/ftrace_data/ipi.pb.h \ - $${PROTOGEN}/types/plugins/ftrace_data/ftrace.pb.h \ - $${PROTOGEN}/types/plugins/ftrace_data/ext4.pb.h \ - $${PROTOGEN}/types/plugins/ftrace_data/oom.pb.h \ - $${PROTOGEN}/types/plugins/ftrace_data/compaction.pb.h \ - $${PROTOGEN}/types/plugins/ftrace_data/clk.pb.h \ - $${PROTOGEN}/types/plugins/ftrace_data/cgroup.pb.h \ - $${PROTOGEN}/types/plugins/ftrace_data/signal.pb.h \ - $${PROTOGEN}/types/plugins/ftrace_data/binder.pb.h \ - $${PROTOGEN}/types/plugins/ftrace_data/net.pb.h \ - $${PROTOGEN}/types/plugins/ftrace_data/v4l2.pb.h \ - $${PROTOGEN}/types/plugins/ftrace_data/writeback.pb.h \ - $${PROTOGEN}/types/plugins/ftrace_data/cpuhp.pb.h \ - $${PROTOGEN}/types/plugins/ftrace_data/pagemap.pb.h \ - $${PROTOGEN}/types/plugins/ftrace_data/dma_fence.pb.h \ - $${PROTOGEN}/types/plugins/ftrace_data/printk.pb.h \ - $${PROTOGEN}/types/plugins/ftrace_data/filelock.pb.h \ - $${PROTOGEN}/types/plugins/ftrace_data/gpio.pb.h \ - $${PROTOGEN}/types/plugins/ftrace_data/timer.pb.h \ - $${PROTOGEN}/types/plugins/ftrace_data/raw_syscalls.pb.h \ - $${PROTOGEN}/types/plugins/ftrace_data/rcu.pb.h \ - \ - $${PROTOGEN}/types/plugins/memory_data/memory_plugin_common.pb.h \ - $${PROTOGEN}/types/plugins/memory_data/memory_plugin_config.pb.h \ - $${PROTOGEN}/types/plugins/memory_data/memory_plugin_result.pb.h \ - $${PROTOGEN}/types/plugins/hilog_data/hilog_plugin_result.pb.h \ - $${PROTOGEN}/types/plugins/native_hook/native_hook_result.pb.h \ - $${PROTOGEN}/types/plugins/native_hook/native_hook_config.pb.h \ - $${PROTOGEN}/types/plugins/hidump_data/hidump_plugin_result.pb.h \ - $${PROTOGEN}/types/plugins/hidump_data/hidump_plugin_config.pb.h diff --git a/host/trace_streamer/src/parser/bytrace_parser/bytrace_event_parser.cpp b/host/trace_streamer/src/parser/bytrace_parser/bytrace_event_parser.cpp index 8ab3d13df46530c63811a7380019de3f8045de94..343b559dcfea29ab330c99aff9000d552b6a6719 100644 --- a/host/trace_streamer/src/parser/bytrace_parser/bytrace_event_parser.cpp +++ b/host/trace_streamer/src/parser/bytrace_parser/bytrace_event_parser.cpp @@ -47,10 +47,6 @@ std::string GetFunctionName(const std::string_view& text, const std::string_view BytraceEventParser::BytraceEventParser(TraceDataCache* dataCache, const TraceStreamerFilters* filter) : EventParserBase(dataCache, filter), - ioWaitId_(const_cast(dataCache)->GetDataIndex("io_wait")), - workQueueId_(const_cast(dataCache)->GetDataIndex("workqueue")), - schedWakeupId_(const_cast(dataCache)->GetDataIndex("sched_wakeup")), - schedBlockedReasonId_(const_cast(dataCache)->GetDataIndex("sched_blocked_reason")), printEventParser_(traceDataCache_, streamFilters_) { eventToFunctionMap_ = { @@ -61,7 +57,9 @@ BytraceEventParser::BytraceEventParser(TraceDataCache* dataCache, const TraceStr {config_.eventNameMap_.at(TRACE_EVENT_TASK_NEWTASK), bind(&BytraceEventParser::TaskNewtaskEvent, this, std::placeholders::_1, std::placeholders::_2)}, {config_.eventNameMap_.at(TRACE_EVENT_TRACING_MARK_WRITE), - bind(&BytraceEventParser::TracingMarkWriteEvent, this, std::placeholders::_1, std::placeholders::_2)}, + bind(&BytraceEventParser::TracingMarkWriteOrPrintEvent, this, std::placeholders::_1, std::placeholders::_2)}, + {config_.eventNameMap_.at(TRACE_EVENT_PRINT), + bind(&BytraceEventParser::TracingMarkWriteOrPrintEvent, this, std::placeholders::_1, std::placeholders::_2)}, {config_.eventNameMap_.at(TRACE_EVENT_SCHED_WAKEUP), bind(&BytraceEventParser::SchedWakeupEvent, this, std::placeholders::_1, std::placeholders::_2)}, {config_.eventNameMap_.at(TRACE_EVENT_SCHED_WAKING), @@ -117,7 +115,7 @@ BytraceEventParser::BytraceEventParser(TraceDataCache* dataCache, const TraceStr bool BytraceEventParser::SchedSwitchEvent(const ArgsMap& args, const BytraceLine& line) const { - if (args.empty() || args.size() < MIN_SCHED_ARGS_COUNT) { + if (args.empty() || args.size() < MIN_SCHED_SWITCH_ARGS_COUNT) { TS_LOGD("Failed to parse sched_switch event, no args or args size < 6"); streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SCHED_SWITCH, STAT_EVENT_DATA_INVALID); return false; @@ -163,6 +161,11 @@ bool BytraceEventParser::SchedSwitchEvent(const ArgsMap& args, const BytraceLine bool BytraceEventParser::TaskRenameEvent(const ArgsMap& args, const BytraceLine& line) const { + if (args.empty() || args.size() < MIN_TASK_RENAME_ARGS_COUNT) { + TS_LOGD("Failed to parse task_rename event, no args or args size < 2"); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_TASK_RENAME, STAT_EVENT_DATA_INVALID); + return false; + } auto prevCommStr = std::string_view(args.at("newcomm")); auto pidValue = base::StrToUInt32(args.at("pid")); streamFilters_->processFilter_->UpdateOrCreateThreadWithName(line.ts, pidValue.value(), prevCommStr); @@ -178,13 +181,13 @@ bool BytraceEventParser::TaskNewtaskEvent(const ArgsMap& args, const BytraceLine return true; } -bool BytraceEventParser::TracingMarkWriteEvent(const ArgsMap& args, const BytraceLine& line) const +bool BytraceEventParser::TracingMarkWriteOrPrintEvent(const ArgsMap& args, const BytraceLine& line) { UNUSED(args); printEventParser_.ParsePrintEvent(line.ts, line.pid, line.argsStr.c_str()); return true; } - +// prefer to use waking, unless no waking, can use wakeup bool BytraceEventParser::SchedWakeupEvent(const ArgsMap& args, const BytraceLine& line) const { if (args.size() < MIN_SCHED_WAKEUP_ARGS_COUNT) { @@ -198,10 +201,13 @@ bool BytraceEventParser::SchedWakeupEvent(const ArgsMap& args, const BytraceLine streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SCHED_WAKEUP, STAT_EVENT_DATA_INVALID); return false; } - DataIndex name = traceDataCache_->GetDataIndex(std::string_view("sched_wakeup")); auto instants = traceDataCache_->GetInstantsData(); - InternalTid internalTid = streamFilters_->processFilter_->UpdateOrCreateThread(line.ts, wakePidValue.value()); - instants->AppendInstantEventData(line.ts, name, internalTid); + InternalTid internalTid = streamFilters_->processFilter_->UpdateOrCreateThread(line.ts, wakePidValue.value_or(0)); + streamFilters_->cpuFilter_->InsertWakeupEvent(line.ts, internalTid); + + InternalTid wakeupFromPid = streamFilters_->processFilter_->UpdateOrCreateThread(line.ts, line.pid); + + instants->AppendInstantEventData(line.ts, schedWakeupName_, internalTid, wakeupFromPid); std::optional targetCpu = base::StrToUInt32(args.at("target_cpu")); if (targetCpu.has_value()) { traceDataCache_->GetRawData()->AppendRawData(0, line.ts, RAW_SCHED_WAKEUP, targetCpu.value(), internalTid); @@ -212,6 +218,11 @@ bool BytraceEventParser::SchedWakeupEvent(const ArgsMap& args, const BytraceLine bool BytraceEventParser::SchedWakingEvent(const ArgsMap& args, const BytraceLine& line) const { + if (args.empty() || args.size() < MIN_SCHED_WAKING_ARGS_COUNT) { + TS_LOGD("Failed to parse sched_waking event, no args or args size < 4"); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SCHED_WAKING, STAT_EVENT_DATA_INVALID); + return false; + } std::optional wakePidValue = base::StrToUInt32(args.at("pid")); auto wakePidStr = std::string_view(args.at("comm")); if (!wakePidValue.has_value()) { @@ -219,17 +230,21 @@ bool BytraceEventParser::SchedWakingEvent(const ArgsMap& args, const BytraceLine streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SCHED_WAKING, STAT_EVENT_DATA_INVALID); return false; } - DataIndex name = traceDataCache_->GetDataIndex(std::string_view("sched_waking")); auto instants = traceDataCache_->GetInstantsData(); DataIndex wakePidStrIndex = traceDataCache_->GetDataIndex(wakePidStr); - InternalTid internalTid = streamFilters_->processFilter_->UpdateOrCreateThreadWithNameIndex(line.ts, - wakePidValue.value(), - wakePidStrIndex); + InternalTid internalTid = streamFilters_->processFilter_->UpdateOrCreateThreadWithNameIndex( + line.ts, wakePidValue.value(), wakePidStrIndex); + + DataIndex wakeByPidStrIndex = traceDataCache_->GetDataIndex(line.task); + InternalTid internalTidWakeup = + streamFilters_->processFilter_->UpdateOrCreateThreadWithNameIndex(line.ts, line.pid, wakeByPidStrIndex); streamFilters_->cpuFilter_->InsertWakeupEvent(line.ts, internalTid); - instants->AppendInstantEventData(line.ts, name, internalTid); + InternalTid wakeupFromPid = streamFilters_->processFilter_->UpdateOrCreateThread(line.ts, line.pid); + instants->AppendInstantEventData(line.ts, schedWakingName_, internalTid, wakeupFromPid); std::optional targetCpu = base::StrToUInt32(args.at("target_cpu")); if (targetCpu.has_value()) { - traceDataCache_->GetRawData()->AppendRawData(0, line.ts, RAW_SCHED_WAKING, targetCpu.value(), internalTid); + traceDataCache_->GetRawData()->AppendRawData(0, line.ts, RAW_SCHED_WAKING, targetCpu.value(), + internalTidWakeup); streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SCHED_WAKING, STAT_EVENT_RECEIVED); } @@ -238,6 +253,11 @@ bool BytraceEventParser::SchedWakingEvent(const ArgsMap& args, const BytraceLine bool BytraceEventParser::CpuIdleEvent(const ArgsMap& args, const BytraceLine& line) const { + if (args.empty() || args.size() < MIN_CPU_IDLE_ARGS_COUNT) { + TS_LOGD("Failed to parse cpu_idle event, no args or args size < 2"); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CPU_IDLE, STAT_EVENT_DATA_INVALID); + return false; + } std::optional eventCpuValue = base::StrToUInt32(args.at("cpu_id")); std::optional newStateValue = base::StrToInt64(args.at("state")); if (!eventCpuValue.has_value()) { @@ -261,6 +281,11 @@ bool BytraceEventParser::CpuIdleEvent(const ArgsMap& args, const BytraceLine& li bool BytraceEventParser::CpuFrequencyEvent(const ArgsMap& args, const BytraceLine& line) const { + if (args.empty() || args.size() < MIN_CPU_FREQUENCY_ARGS_COUNT) { + TS_LOGD("Failed to parse cpu_frequency event, no args or args size < 2"); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CPU_FREQUENCY, STAT_EVENT_DATA_INVALID); + return false; + } std::optional eventCpuValue = base::StrToUInt32(args.at("cpu_id")); std::optional newStateValue = base::StrToInt64(args.at("state")); @@ -311,6 +336,11 @@ bool BytraceEventParser::WorkqueueExecuteEndEvent(const ArgsMap& args, const Byt bool BytraceEventParser::ProcessExitEvent(const ArgsMap& args, const BytraceLine& line) const { + if (args.empty() || args.size() < MIN_PROCESS_EXIT_ARGS_COUNT) { + TS_LOGD("Failed to parse process_exit event, no args or args size < 2"); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_PROCESS_EXIT, STAT_EVENT_DATA_INVALID); + return false; + } auto comm = std::string_view(args.at("comm")); auto pid = base::StrToUInt32(args.at("pid")); if (!pid.has_value()) { @@ -329,6 +359,11 @@ bool BytraceEventParser::ProcessExitEvent(const ArgsMap& args, const BytraceLine bool BytraceEventParser::SetRateEvent(const ArgsMap& args, const BytraceLine& line) const { + if (args.empty() || args.size() < MIN_CLOCK_SET_RATE_ARGS_COUNT) { + TS_LOGD("Failed to parse clock_set_rate event, no args or args size < 3"); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CLOCK_SET_RATE, STAT_EVENT_DATA_INVALID); + return false; + } auto name = std::string_view(args.at("name")); auto state = base::StrToInt64(args.at("state")); auto cpu = base::StrToUInt64(args.at("cpu_id")); @@ -340,6 +375,11 @@ bool BytraceEventParser::SetRateEvent(const ArgsMap& args, const BytraceLine& li bool BytraceEventParser::ClockEnableEvent(const ArgsMap& args, const BytraceLine& line) const { + if (args.empty() || args.size() < MIN_CLOCK_ENABLE_ARGS_COUNT) { + TS_LOGD("Failed to parse clock_enable event, no args or args size < 3"); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CLOCK_ENABLE, STAT_EVENT_DATA_INVALID); + return false; + } auto name = std::string_view(args.at("name")); auto state = base::StrToInt64(args.at("state")); auto cpuId = base::StrToUInt64(args.at("cpu_id")); @@ -350,6 +390,11 @@ bool BytraceEventParser::ClockEnableEvent(const ArgsMap& args, const BytraceLine } bool BytraceEventParser::ClockDisableEvent(const ArgsMap& args, const BytraceLine& line) const { + if (args.empty() || args.size() < MIN_CLOCK_DISABLE_ARGS_COUNT) { + TS_LOGD("Failed to parse clock_disable event, no args or args size < 3"); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_CLOCK_DISABLE, STAT_EVENT_DATA_INVALID); + return false; + } auto name = std::string_view(args.at("name")); auto state = base::StrToInt64(args.at("state")); auto cpuId = base::StrToUInt64(args.at("cpu_id")); @@ -411,8 +456,11 @@ bool BytraceEventParser::IpiExitEvent(const ArgsMap& args, const BytraceLine& li } bool BytraceEventParser::IrqHandlerEntryEvent(const ArgsMap& args, const BytraceLine& line) const { - UNUSED(args); - UNUSED(line); + if (args.empty() || args.size() < MIN_IRQ_HANDLER_ENTRY_ARGS_COUNT) { + TS_LOGD("Failed to parse irq_handler_entry event, no args or args size < 2"); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_IRQ_HANDLER_ENTRY, STAT_EVENT_DATA_INVALID); + return false; + } traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_IRQ_HANDLER_ENTRY, STAT_EVENT_RECEIVED); auto name = std::string_view(args.at("name")); streamFilters_->irqFilter_->IrqHandlerEntry(line.ts, line.cpu, traceDataCache_->GetDataIndex(name)); @@ -420,8 +468,11 @@ bool BytraceEventParser::IrqHandlerEntryEvent(const ArgsMap& args, const Bytrace } bool BytraceEventParser::IrqHandlerExitEvent(const ArgsMap& args, const BytraceLine& line) const { - UNUSED(args); - UNUSED(line); + if (args.empty() || args.size() < MIN_IRQ_HANDLER_EXIT_ARGS_COUNT) { + TS_LOGD("Failed to parse irq_handler_exit event, no args or args size < 2"); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_IRQ_HANDLER_EXIT, STAT_EVENT_DATA_INVALID); + return false; + } traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_IRQ_HANDLER_EXIT, STAT_EVENT_RECEIVED); uint32_t ret = (args.at("ret") == "handled") ? 1 : 0; streamFilters_->irqFilter_->IrqHandlerExit(line.ts, line.cpu, ret); @@ -437,6 +488,11 @@ bool BytraceEventParser::SoftIrqRaiseEvent(const ArgsMap& args, const BytraceLin } bool BytraceEventParser::SoftIrqEntryEvent(const ArgsMap& args, const BytraceLine& line) const { + if (args.empty() || args.size() < MIN_SOFTIRQ_ENTRY_ARGS_COUNT) { + TS_LOGD("Failed to parse softirq_entry event, no args or args size < 2"); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SOFTIRQ_ENTRY, STAT_EVENT_DATA_INVALID); + return false; + } traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_SOFTIRQ_ENTRY, STAT_EVENT_RECEIVED); auto vec = base::StrToUInt32(args.at("vec")); streamFilters_->irqFilter_->SoftIrqEntry(line.ts, line.cpu, vec.value()); @@ -444,6 +500,11 @@ bool BytraceEventParser::SoftIrqEntryEvent(const ArgsMap& args, const BytraceLin } bool BytraceEventParser::SoftIrqExitEvent(const ArgsMap& args, const BytraceLine& line) const { + if (args.empty() || args.size() < MIN_SOFTIRQ_EXIT_ARGS_COUNT) { + TS_LOGD("Failed to parse softirq_exit event, no args or args size < 2"); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_SOFTIRQ_EXIT, STAT_EVENT_DATA_INVALID); + return false; + } traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_SOFTIRQ_EXIT, STAT_EVENT_RECEIVED); auto vec = base::StrToUInt32(args.at("vec")); streamFilters_->irqFilter_->SoftIrqExit(line.ts, line.cpu, vec.value()); @@ -452,6 +513,11 @@ bool BytraceEventParser::SoftIrqExitEvent(const ArgsMap& args, const BytraceLine bool BytraceEventParser::BinderTransaction(const ArgsMap& args, const BytraceLine& line) const { + if (args.empty() || args.size() < MIN_BINDER_TRANSACTION_ARGS_COUNT) { + TS_LOGD("Failed to parse binder_transaction event, no args or args size < 7"); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_BINDER_TRANSACTION, STAT_EVENT_DATA_INVALID); + return false; + } streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_BINDER_TRANSACTION, STAT_EVENT_RECEIVED); auto transactionId = base::StrToInt64(args.at("transaction")); auto destNode = base::StrToUInt32(args.at("dest_node")); @@ -470,6 +536,11 @@ bool BytraceEventParser::BinderTransaction(const ArgsMap& args, const BytraceLin } bool BytraceEventParser::BinderTransactionReceived(const ArgsMap& args, const BytraceLine& line) const { + if (args.empty() || args.size() < MIN_BINDER_TRANSACTION_RECEIVED_ARGS_COUNT) { + TS_LOGD("Failed to parse binder_transaction_received event, no args or args size < 1"); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_BINDER_TRANSACTION_RECEIVED, STAT_EVENT_DATA_INVALID); + return false; + } streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_BINDER_TRANSACTION_RECEIVED, STAT_EVENT_RECEIVED); auto transactionId = base::StrToInt64(args.at("transaction")); streamFilters_->binderFilter_->ReceiveTraction(line.ts, line.pid, transactionId.value()); @@ -478,8 +549,11 @@ bool BytraceEventParser::BinderTransactionReceived(const ArgsMap& args, const By } bool BytraceEventParser::BinderTransactionAllocBufEvent(const ArgsMap& args, const BytraceLine& line) const { - UNUSED(args); - UNUSED(line); + if (args.empty() || args.size() < MIN_BINDER_TRANSACTION_ALLOC_BUF_ARGS_COUNT) { + TS_LOGD("Failed to parse binder_transaction_alloc_buf event, no args or args size < 3"); + streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_BINDER_TRANSACTION_ALLOC_BUF, STAT_EVENT_DATA_INVALID); + return false; + } streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_BINDER_TRANSACTION_ALLOC_BUF, STAT_EVENT_RECEIVED); auto dataSize = base::StrToUInt64(args.at("data_size")); auto offsetsSize = base::StrToUInt64(args.at("offsets_size")); @@ -487,23 +561,72 @@ bool BytraceEventParser::BinderTransactionAllocBufEvent(const ArgsMap& args, con TS_LOGD("dataSize:%lu, offsetSize:%lu", dataSize.value(), offsetsSize.value()); return true; } -bool BytraceEventParser::ParseDataItem(const BytraceLine& line, const ArgsMap& args, uint32_t tgid) const +void BytraceEventParser::ParseDataItem(const BytraceLine& line) +{ + eventList_.push_back(std::move(std::make_unique(line.ts, std::move(line)))); + return; +} +void BytraceEventParser::GetDataSegArgs(BytraceLine& bufLine, ArgsMap& args, uint32_t& tgid) const { - traceDataCache_->UpdateTraceTime(line.ts); - if (tgid) { - streamFilters_->processFilter_->UpdateOrCreateThreadWithPidAndName(line.pid, tgid, line.task); + if (bufLine.tGidStr.at(0) != '-') { + tgid = base::StrToUInt32(bufLine.tGidStr).value_or(0); } else { - // When tgid is zero, only use tid create thread - streamFilters_->processFilter_->GetOrCreateThreadWithPid(line.pid, tgid); + tgid = 0; } - auto it = eventToFunctionMap_.find(line.eventName); - if (it != eventToFunctionMap_.end()) { - return it->second(args, line); + for (base::PartingString ss(bufLine.argsStr, ' '); ss.Next();) { + std::string key; + std::string value; + if (!(std::string(ss.GetCur()).find("=") != std::string::npos)) { + key = "name"; + value = ss.GetCur(); + args.emplace(std::move(key), std::move(value)); + continue; + } + for (base::PartingString inner(ss.GetCur(), '='); inner.Next();) { + if (key.empty()) { + key = inner.GetCur(); + } else { + value = inner.GetCur(); + } + } + args.emplace(std::move(key), std::move(value)); + } +} +void BytraceEventParser::FilterAllEvents() +{ + auto cmp = [](const std::unique_ptr& a, const std::unique_ptr& b) { + return a->eventTimestamp < b->eventTimestamp; + }; + std::sort(eventList_.begin(), eventList_.end(), cmp); + size_t maxBuffSize = 1000 * 1000; + while (eventList_.size()) { + int size = std::min(maxBuffSize, eventList_.size()); + auto endOfList = eventList_.begin() + size; + for (auto itor = eventList_.begin(); itor != endOfList; itor++) { + EventInfo* event = itor->get(); + auto it = eventToFunctionMap_.find(event->line.eventName); + if (it != eventToFunctionMap_.end()) { + uint32_t tgid; + ArgsMap args; + GetDataSegArgs(event->line, args, tgid); + if (tgid) { + streamFilters_->processFilter_->UpdateOrCreateThreadWithPidAndName(event->line.pid, tgid, + event->line.task); + } else { + // When tgid is zero, only use tid create thread + streamFilters_->processFilter_->GetOrCreateThreadWithPid(event->line.pid, tgid); + } + traceDataCache_->UpdateTraceTime(event->line.ts); + it->second(args, event->line); + } else { + traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_OTHER, STAT_EVENT_NOTSUPPORTED); + TS_LOGW("UnRecognizable event name:%s", event->line.eventName.c_str()); + } + } + eventList_.erase(eventList_.begin(), endOfList); } - TS_LOGW("UnRecognizable event name:%s", line.eventName.c_str()); - traceDataCache_->GetStatAndInfo()->IncreaseStat(TRACE_EVENT_OTHER, STAT_EVENT_NOTSUPPORTED); - return false; + eventList_.clear(); } } // namespace TraceStreamer } // namespace SysTuning diff --git a/host/trace_streamer/src/parser/bytrace_parser/bytrace_event_parser.h b/host/trace_streamer/src/parser/bytrace_parser/bytrace_event_parser.h index 6f3aee89862234506890581037458f4f38b5d244..05ce5737803bd98d6e33fb2a433b5fcd1d217b25 100644 --- a/host/trace_streamer/src/parser/bytrace_parser/bytrace_event_parser.h +++ b/host/trace_streamer/src/parser/bytrace_parser/bytrace_event_parser.h @@ -17,6 +17,7 @@ #define SRC_BYTRACE_EVENT_PARSER_H #include +#include #include "common_types.h" #include "event_parser_base.h" @@ -31,14 +32,15 @@ using ArgsMap = std::unordered_map; class BytraceEventParser : private EventParserBase { public: BytraceEventParser(TraceDataCache* dataCache, const TraceStreamerFilters* filter); - bool ParseDataItem(const BytraceLine& line, const ArgsMap& args, uint32_t tgid) const; + void ParseDataItem(const BytraceLine& line); + void FilterAllEvents(); private: using FuncCall = std::function; bool SchedSwitchEvent(const ArgsMap& args, const BytraceLine& line) const; bool TaskRenameEvent(const ArgsMap& args, const BytraceLine& line) const; bool TaskNewtaskEvent(const ArgsMap& args, const BytraceLine& line) const; - bool TracingMarkWriteEvent(const ArgsMap& args, const BytraceLine& line) const; + bool TracingMarkWriteOrPrintEvent(const ArgsMap& args, const BytraceLine& line); bool SchedWakeupEvent(const ArgsMap& args, const BytraceLine& line) const; bool SchedWakingEvent(const ArgsMap& args, const BytraceLine& line) const; bool CpuIdleEvent(const ArgsMap& args, const BytraceLine& line) const; @@ -63,15 +65,40 @@ private: bool BinderTransaction(const ArgsMap& args, const BytraceLine& line) const; bool BinderTransactionReceived(const ArgsMap& args, const BytraceLine& line) const; bool BinderTransactionAllocBufEvent(const ArgsMap& args, const BytraceLine& line) const; + void GetDataSegArgs(BytraceLine& bufLine, ArgsMap& args, uint32_t& tgid) const; private: - const DataIndex ioWaitId_; - const DataIndex workQueueId_; - const DataIndex schedWakeupId_; - const DataIndex schedBlockedReasonId_; + class EventInfo { + public: + EventInfo(uint64_t ts, BytraceLine li) : eventTimestamp(ts), line(li) {} + uint64_t eventTimestamp; + BytraceLine line; + }; std::map eventToFunctionMap_ = {}; - const unsigned int MIN_SCHED_ARGS_COUNT = 6; + const unsigned int MIN_SCHED_SWITCH_ARGS_COUNT = 6; const unsigned int MIN_SCHED_WAKEUP_ARGS_COUNT = 2; + const unsigned int MIN_TASK_RENAME_ARGS_COUNT = 2; + const unsigned int MIN_SCHED_WAKING_ARGS_COUNT = 4; + const unsigned int MIN_CPU_IDLE_ARGS_COUNT = 2; + const unsigned int MIN_CPU_FREQUENCY_ARGS_COUNT = 2; + const unsigned int MIN_PROCESS_EXIT_ARGS_COUNT = 2; + const unsigned int MIN_CLOCK_SET_RATE_ARGS_COUNT = 3; + const unsigned int MIN_CLOCK_ENABLE_ARGS_COUNT = 3; + const unsigned int MIN_CLOCK_DISABLE_ARGS_COUNT = 3; + const unsigned int MIN_IRQ_HANDLER_ENTRY_ARGS_COUNT = 2; + const unsigned int MIN_IRQ_HANDLER_EXIT_ARGS_COUNT = 2; + const unsigned int MIN_SOFTIRQ_ENTRY_ARGS_COUNT = 2; + const unsigned int MIN_SOFTIRQ_EXIT_ARGS_COUNT = 2; + const unsigned int MIN_BINDER_TRANSACTION_ARGS_COUNT = 7; + const unsigned int MIN_BINDER_TRANSACTION_RECEIVED_ARGS_COUNT = 1; + const unsigned int MIN_BINDER_TRANSACTION_ALLOC_BUF_ARGS_COUNT = 3; + std::vector> eventList_ = {}; PrintEventParser printEventParser_; + const DataIndex schedWakeupName_ = traceDataCache_->GetDataIndex("sched_wakeup"); + const DataIndex schedWakingName_ = traceDataCache_->GetDataIndex("sched_waking"); + const DataIndex ioWaitId_ = traceDataCache_->GetDataIndex("io_wait"); + const DataIndex workQueueId_ = traceDataCache_->GetDataIndex("workqueue"); + const DataIndex schedWakeupId_ = traceDataCache_->GetDataIndex("sched_wakeup"); + const DataIndex schedBlockedReasonId_ = traceDataCache_->GetDataIndex("sched_blocked_reason"); }; } // namespace TraceStreamer } // namespace SysTuning diff --git a/host/trace_streamer/src/parser/bytrace_parser/bytrace_parser.cpp b/host/trace_streamer/src/parser/bytrace_parser/bytrace_parser.cpp index cdf20e3f9f6ed331b57e73d40fe715be32665c6f..aa7fe93a6713f4aa8f42160e3c7b050203118758 100644 --- a/host/trace_streamer/src/parser/bytrace_parser/bytrace_parser.cpp +++ b/host/trace_streamer/src/parser/bytrace_parser/bytrace_parser.cpp @@ -23,11 +23,13 @@ namespace SysTuning { namespace TraceStreamer { BytraceParser::BytraceParser(TraceDataCache* dataCache, const TraceStreamerFilters* filters) : ParserBase(filters), - eventParser_(std::make_unique(dataCache, filters)), - dataSegArray(new DataSegment[MAX_SEG_ARRAY_SIZE]) + eventParser_(std::make_unique(dataCache, filters)) { #ifdef SUPPORTTHREAD - noThread_ = false; + supportThread_ = true; + dataSegArray = std::make_unique(MAX_SEG_ARRAY_SIZE); +#else + dataSegArray = std::make_unique(1); #endif } @@ -41,8 +43,7 @@ void BytraceParser::WaitForParserEnd() usleep(sleepDur_ * sleepDur_); } } - streamFilters_->cpuFilter_->FinishCpuEvent(); - streamFilters_->binderFilter_->FinishBinderEvent(); + eventParser_->FilterAllEvents(); } void BytraceParser::ParseTraceDataSegment(std::unique_ptr bufferStr, size_t size) { @@ -51,14 +52,14 @@ void BytraceParser::ParseTraceDataSegment(std::unique_ptr bufferStr, } packagesBuffer_.insert(packagesBuffer_.end(), &bufferStr[0], &bufferStr[size]); auto packagesBegin = packagesBuffer_.begin(); - while (1) { auto packagesLine = std::find(packagesBegin, packagesBuffer_.end(), '\n'); - if (packagesLine == packagesBuffer_.end()) { + if (packagesLine == packagesBuffer_.end() || packagesLine == packagesBuffer_.begin()) { break; } - - std::string bufferLine(packagesBegin, packagesLine); + // Support parsing windows file format(ff=dos) + auto extra = *(packagesLine - 1) == '\r' ? 1 : 0; + std::string bufferLine(packagesBegin, packagesLine - extra); if (IsTraceComment(bufferLine)) { traceCommentLines_++; @@ -90,6 +91,11 @@ void BytraceParser::ParseTraceDataSegment(std::unique_ptr bufferStr, void BytraceParser::ParseTraceDataItem(const std::string& buffer) { + if (!supportThread_) { + dataSegArray[rawDataHead_].seg = std::move(buffer); + ParserData(dataSegArray[rawDataHead_]); + return; + } int head = rawDataHead_; while (!toExit_) { if (dataSegArray[head].status.load() != TS_PARSE_STATUS_INIT) { @@ -99,12 +105,10 @@ void BytraceParser::ParseTraceDataItem(const std::string& buffer) } dataSegArray[head].seg = std::move(buffer); dataSegArray[head].status = TS_PARSE_STATUS_SEPRATED; - if (!noThread_) { - rawDataHead_ = (rawDataHead_ + 1) % MAX_SEG_ARRAY_SIZE; - } + rawDataHead_ = (rawDataHead_ + 1) % MAX_SEG_ARRAY_SIZE; break; } - if (!parseThreadStarted_ && !noThread_) { + if (!parseThreadStarted_) { parseThreadStarted_ = true; int tmp = maxThread_; while (tmp--) { @@ -114,9 +118,6 @@ void BytraceParser::ParseTraceDataItem(const std::string& buffer) TS_LOGI("parser Thread:%d/%d start working ...\n", maxThread_ - tmp, maxThread_); } } - if (noThread_) { - ParserData(dataSegArray[head]); - } return; } int BytraceParser::GetNextSegment() @@ -188,38 +189,8 @@ void BytraceParser::GetDataSegAttr(DataSegment& seg, const std::smatch& matcheLi seg.bufLine.ts = static_cast(optionalTime.value() * 1e9); seg.bufLine.tGidStr = tGidStr; seg.bufLine.eventName = eventName; - GetDataSegArgs(seg); seg.status = TS_PARSE_STATUS_PARSED; } - -void BytraceParser::GetDataSegArgs(DataSegment& seg) const -{ - seg.args.clear(); - if (seg.bufLine.tGidStr != "-----") { - seg.tgid = base::StrToUInt32(seg.bufLine.tGidStr).value_or(0); - } else { - seg.tgid = 0; - } - - for (base::PartingString ss(seg.bufLine.argsStr, ' '); ss.Next();) { - std::string key; - std::string value; - if (!(std::string(ss.GetCur()).find("=") != std::string::npos)) { - key = "name"; - value = ss.GetCur(); - seg.args.emplace(std::move(key), std::move(value)); - continue; - } - for (base::PartingString inner(ss.GetCur(), '='); inner.Next();) { - if (key.empty()) { - key = inner.GetCur(); - } else { - value = inner.GetCur(); - } - } - seg.args.emplace(std::move(key), std::move(value)); - } -} void BytraceParser::ParseThread() { while (1) { @@ -251,14 +222,15 @@ void BytraceParser::ParserData(DataSegment& seg) parsedTraceValidLines_++; } GetDataSegAttr(seg, matcheLine); - if (!filterThreadStarted_ && !noThread_) { + if (!supportThread_) { + FilterData(seg); + return; + } + if (!filterThreadStarted_) { filterThreadStarted_ = true; std::thread ParserThread(&BytraceParser::FilterThread, this); ParserThread.detach(); } - if (noThread_) { - FilterData(seg); - } } void BytraceParser::FilterThread() { @@ -271,14 +243,21 @@ void BytraceParser::FilterThread() } bool BytraceParser::FilterData(DataSegment& seg) { + if (!supportThread_) { + eventParser_->ParseDataItem(seg.bufLine); + return true; + } if (seg.status.load() == TS_PARSE_STATUS_INVALID) { seg.status = TS_PARSE_STATUS_INIT; - if (!noThread_) { - filterHead_ = (filterHead_ + 1) % MAX_SEG_ARRAY_SIZE; - } + filterHead_ = (filterHead_ + 1) % MAX_SEG_ARRAY_SIZE; streamFilters_->statFilter_->IncreaseStat(TRACE_EVENT_OTHER, STAT_EVENT_DATA_INVALID); return true; } + if (!supportThread_) { + eventParser_->ParseDataItem(seg.bufLine); + seg.status = TS_PARSE_STATUS_INIT; + return true; + } if (seg.status.load() != TS_PARSE_STATUS_PARSED) { if (toExit_ && !parserThreadCount_) { TS_LOGI("exiting FilterThread Thread\n"); @@ -286,17 +265,11 @@ bool BytraceParser::FilterData(DataSegment& seg) filterThreadStarted_ = false; return false; } - if (!noThread_) { // wasm do not allow thread - usleep(sleepDur_); - } + usleep(sleepDur_); return true; } - BytraceLine line = seg.bufLine; - uint32_t tgid = seg.tgid; - eventParser_->ParseDataItem(line, seg.args, tgid); - if (!noThread_) { - filterHead_ = (filterHead_ + 1) % MAX_SEG_ARRAY_SIZE; - } + eventParser_->ParseDataItem(seg.bufLine); + filterHead_ = (filterHead_ + 1) % MAX_SEG_ARRAY_SIZE; seg.status = TS_PARSE_STATUS_INIT; return true; } @@ -304,12 +277,11 @@ bool BytraceParser::FilterData(DataSegment& seg) std::string BytraceParser::StrTrim(const std::string& input) const { std::string str = input; - auto posBegin = std::find_if(str.begin(), str.end(), IsNotSpace); - str.erase(str.begin(), posBegin); - - auto posEnd = std::find_if(str.rbegin(), str.rend(), IsNotSpace); - str.erase(posEnd.base(), str.end()); - + if (str.empty()) { + return str; + } + str.erase(0, str.find_first_not_of(" ")); + str.erase(str.find_last_not_of(" ") + 1); return str; } } // namespace TraceStreamer diff --git a/host/trace_streamer/src/parser/bytrace_parser/bytrace_parser.h b/host/trace_streamer/src/parser/bytrace_parser/bytrace_parser.h index 95c552efed3e2370db24ac3847c9b2cbfab451d8..2ebf8621f607dcce215f4b7149582bd65af56482 100644 --- a/host/trace_streamer/src/parser/bytrace_parser/bytrace_parser.h +++ b/host/trace_streamer/src/parser/bytrace_parser/bytrace_parser.h @@ -54,7 +54,7 @@ private: enum ErrorCode { ERROR_CODE_EXIT = -2, ERROR_CODE_NODATA = -1 }; int GetNextSegment(); void GetDataSegAttr(DataSegment& seg, const std::smatch& matcheLine) const; - void GetDataSegArgs(DataSegment& seg) const; + void FilterThread(); inline static bool IsNotSpace(char c) { @@ -96,7 +96,7 @@ private: int rawDataHead_ = 0; int filterHead_ = 0; const int sleepDur_ = 100; - bool noThread_ = true; + bool supportThread_ = false; }; } // namespace TraceStreamer } // namespace SysTuning diff --git a/host/trace_streamer/src/parser/common_types.h b/host/trace_streamer/src/parser/common_types.h index 5d7c0a416ad3c77523cc5b4a16cadd8842947ae7..403b304c8172c681246693c72db0cc5cc0f5a004 100644 --- a/host/trace_streamer/src/parser/common_types.h +++ b/host/trace_streamer/src/parser/common_types.h @@ -19,10 +19,14 @@ #include #include #include +#include "cpu_plugin_result.pb.h" +#include "diskio_plugin_result.pb.h" #include "hidump_plugin_result.pb.h" #include "hilog_plugin_result.pb.h" #include "memory_plugin_result.pb.h" #include "native_hook_result.pb.h" +#include "network_plugin_result.pb.h" +#include "process_plugin_result.pb.h" #include "services/common_types.pb.h" #include "trace_plugin_result.pb.h" #include "ts_common.h" @@ -70,16 +74,18 @@ enum ParseStatus { struct DataSegment { std::string seg; BytraceLine bufLine; - std::unordered_map args; - uint32_t tgid; std::atomic status{TS_PARSE_STATUS_INIT}; }; enum DataSourceType { DATA_SOURCE_TYPE_TRACE, DATA_SOURCE_TYPE_MEM, DATA_SOURCE_TYPE_HILOG, - DATA_SOURCE_TYPE_HEAP, - DATA_SOURCE_TYPE_FPS + DATA_SOURCE_TYPE_ALLOCATION, + DATA_SOURCE_TYPE_FPS, + DATA_SOURCE_TYPE_NETWORK, + DATA_SOURCE_TYPE_DISKIO, + DATA_SOURCE_TYPE_CPU, + DATA_SOURCE_TYPE_PROCESS, }; // 注意使用完之后恢复初始化状态,保证下次使用不会出现数据混乱。 struct HtraceDataSegment { @@ -88,14 +94,46 @@ struct HtraceDataSegment { HilogInfo logData; BatchNativeHookData batchNativeHookData; HidumpInfo hidumpInfo; + CpuData cpuInfo; + NetworkDatas networkInfo; + DiskioData diskIOInfo; + ProcessData processInfo; uint64_t timeStamp; - TracePluginResult traceData; + std::unique_ptr traceData; BuiltinClocks clockId; DataSourceType dataType; std::atomic status{TS_PARSE_STATUS_INIT}; }; -struct TracePoint { +class TracePoint { +public: + TracePoint() {} + TracePoint(const TracePoint& point) + { + phase_ = point.phase_; + tgid_ = point.tgid_; + name_ = point.name_; + value_ = point.value_; + categoryGroup_ = point.categoryGroup_; + chainId_ = point.chainId_; + spanId_ = point.spanId_; + parentSpanId_ = point.parentSpanId_; + flag_ = point.flag_; + args_ = point.args_; + } + void operator=(const TracePoint& point) + { + phase_ = point.phase_; + tgid_ = point.tgid_; + name_ = point.name_; + value_ = point.value_; + categoryGroup_ = point.categoryGroup_; + chainId_ = point.chainId_; + spanId_ = point.spanId_; + parentSpanId_ = point.parentSpanId_; + flag_ = point.flag_; + args_ = point.args_; + } char phase_ = '\0'; uint32_t tgid_ = 0; std::string name_ = ""; diff --git a/host/trace_streamer/prebuilts/buildprotobuf/protobuf.pro b/host/trace_streamer/src/parser/hiperf_parser/BUILD.gn similarity index 42% rename from host/trace_streamer/prebuilts/buildprotobuf/protobuf.pro rename to host/trace_streamer/src/parser/hiperf_parser/BUILD.gn index 16afcce35f9128fe4cda5635837e2d5709de561a..87ded10e3e34670b35c2d6fbfb646a01aaae70ff 100644 --- a/host/trace_streamer/prebuilts/buildprotobuf/protobuf.pro +++ b/host/trace_streamer/src/parser/hiperf_parser/BUILD.gn @@ -10,26 +10,40 @@ # 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. -QT -= gui core -TEMPLATE = lib -#TEMPLATE = app -CONFIG += c++14 lib -#CONFIG += c++14 -TARGET = protobuf -DEFINES += HAVE_PTHREAD +import("//build/ohos.gni") +import("../../ts.gni") +ohos_source_set("hiperf_parser_src") { + sources = [ "perf_data_parser.cpp" ] + include_dirs = [ + "hiperf/linux", + "hiperf/kernel", + ".", + "../../base", + "../../cfg", + "hiperf/include", + "../../include", + "../../", + "../../filter", + "../../trace_data", + "..", + "../htrace_parser", + "../../trace_streamer", + "//third_party/sqlite/include", + "${OHOS_PROTO_GEN}/types/plugins/memory_data", + "//third_party/protobuf/src", + "//third_party/perf_include", + ] +} -DEFINES += HAVE_PTHREAD -PROTOBUDIR = $$PWD/../../third_party/protobuf -ROOTSRCDIR = $$PWD/../../src/ -include($$PWD/../../src/multi_platform/global.pri) - -LIBS += -L$$DESTDIR/ -lstdc++ - -#INCLUDEPATH += $$PWD/$${PROTOBUDIR}/src -INCLUDEPATH += $$PWD/../../third_party/protobuf/src - -message("includepath is:"$$INCLUDEPATH) -include($$PWD/protobuf.pri) -include($$PWD/libprotobuf_lite_la_SOURCES.pri) -include($$PWD/libprotoc_la_SOURCES.pri) +group("hiperf_parser") { + deps = [ + ":hiperf_parser_src", + "hiperf:hiperf", + "//third_party/protobuf:protobuf", + "//third_party/protobuf:protobuf_lite", + ] + if (target != "test") { + deps += [ "//prebuilts/protos:ts_proto_data_cpp" ] + } +} diff --git a/host/trace_streamer/prebuilts/buildsqlite/sqlite.pro b/host/trace_streamer/src/parser/hiperf_parser/hiperf/BUILD.gn similarity index 32% rename from host/trace_streamer/prebuilts/buildsqlite/sqlite.pro rename to host/trace_streamer/src/parser/hiperf_parser/hiperf/BUILD.gn index 50d80823e05b0cec037bc7efd38601b13f277508..29b5d8cdf8f499ba8644a4eb920053ad8c11c98e 100644 --- a/host/trace_streamer/prebuilts/buildsqlite/sqlite.pro +++ b/host/trace_streamer/src/parser/hiperf_parser/hiperf/BUILD.gn @@ -10,22 +10,65 @@ # 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. -QT -= gui core -TEMPLATE = lib -#TEMPLATE = app -CONFIG += c++14 lib -#CONFIG += c++14 -TARGET = sqlite -DEFINES += HAVE_PTHREAD -LIBDIR = $$PWD/../../third_party/sqlite -ROOTSRCDIR = $$PWD/../../src/ -include($$PWD/../../src/multi_platform/global.pri) +import("//build/ohos.gni") +import("../../../ts.gni") +ohos_source_set("hiperf_src") { + sources = [ + "callstack.cpp", + "callstack.h", + "debug_logger.cpp", + "debug_logger.h", + "dwarf_encoding.cpp", + "dwarf_encoding.h", + "elf_file.cpp", + "elf_header.cpp", + "elf_symbol.cpp", -LIBS += -L$$DESTDIR/ -lstdc++ + # "hashlist.hpp", + "hashlist.h", + "option.cpp", + "perf_event_record.cpp", -#INCLUDEPATH += $$PWD/$${PROTOBUDIR}/src -INCLUDEPATH += $$PWD/../../third_party/sqlite/include + # "perf_events.cpp", + "perf_file_format.cpp", + "perf_file_reader.cpp", + "program_header.cpp", + "register.cpp", + "register.h", + "report.cpp", -message("includepath is:"$$INCLUDEPATH) -SOURCES += $${LIBDIR}/src/sqlite3.c + # "ring_buffer.cpp", + "include/symbols_file.h", + "section_header.cpp", + "subcommand.cpp", + "subcommand_dump.cpp", + "symbols_file.cpp", + "utilities.cpp", + "virtual_runtime.cpp", + "virtual_thread.cpp", + ] + include_dirs = [ + "linux", + "kernel", + "../", + "./", + "../../../base", + "include", + "../../../include", + "../../../", + "../../../trace_streamer", + "//third_party/perf_include", + ] +} + +group("hiperf") { + deps = [ + ":hiperf_src", + "//third_party/protobuf:protobuf", + "//third_party/protobuf:protobuf_lite", + ] + if (target != "test") { + deps += [ "//prebuilts/protos:ts_proto_data_cpp" ] + } +} diff --git a/host/trace_streamer/src/parser/hiperf_parser/hiperf/callstack.cpp b/host/trace_streamer/src/parser/hiperf_parser/hiperf/callstack.cpp new file mode 100644 index 0000000000000000000000000000000000000000..dc5ae0f91761c0b870f2b583ebca795b1c01980f --- /dev/null +++ b/host/trace_streamer/src/parser/hiperf_parser/hiperf/callstack.cpp @@ -0,0 +1,662 @@ +/* + * Copyright (c) 2021-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. + */ +#define HILOG_TAG "CallStack" + +#include "callstack.h" + +#include +#if HAVE_LIBUNWIND +#include +extern "C" { +#include +} +#endif + +#include "register.h" +#if defined(target_cpu_arm) +// reg size is int (unw_word_t) +#define UNW_WORD_PFLAG "x" +#elif defined(__arm__) && defined(target_cpu_x64) +// reg size is long long (unw_word_t) +#define UNW_WORD_PFLAG "llx" +#else +// reg size is long (unw_word_t) +#define UNW_WORD_PFLAG "zx" +#endif +namespace OHOS { +namespace Developtools { +namespace HiPerf { +#if HAVE_LIBUNWIND +const std::map UNW_ERROR_MAP = { + {UNW_ESUCCESS, std::to_string(UNW_ESUCCESS)}, + {UNW_EUNSPEC, std::to_string(UNW_EUNSPEC)}, + {UNW_ENOMEM, std::to_string(UNW_ENOMEM)}, + {UNW_EBADREG, std::to_string(UNW_EBADREG)}, + {UNW_EREADONLYREG, std::to_string(UNW_EREADONLYREG)}, + {UNW_ESTOPUNWIND, std::to_string(UNW_ESTOPUNWIND)}, + {UNW_EINVALIDIP, std::to_string(UNW_EINVALIDIP)}, + {UNW_EBADFRAME, std::to_string(UNW_EBADFRAME)}, + {UNW_EINVAL, std::to_string(UNW_EINVAL)}, + {UNW_EBADVERSION, std::to_string(UNW_EBADVERSION)}, + {UNW_ENOINFO, std::to_string(UNW_ENOINFO)}, +}; +const std::string CallStack::GetUnwErrorName(int error) +{ + if (UNW_ERROR_MAP.count(static_cast(-error)) > 0) { + return UNW_ERROR_MAP.at(static_cast(-error)); + } else { + return "UNKNOW_UNW_ERROR"; + } +} + +void CallStack::dumpUDI(unw_dyn_info_t &di) +{ + HLOGV("unwind_table info: "); + HLOGV(" di.start_ip: 0x%016" UNW_WORD_PFLAG "", di.start_ip); + HLOGV(" di.end_ip: 0x%016" UNW_WORD_PFLAG "", di.end_ip); + HLOGV(" di.u.rti.segbase: 0x%016" UNW_WORD_PFLAG "", di.u.rti.segbase); + HLOGV(" di.u.rti.table_data: 0x%016" UNW_WORD_PFLAG "", di.u.rti.table_data); + HLOGV(" di.u.rti.table_len: 0x%016" UNW_WORD_PFLAG "", di.u.rti.table_len); +} + +bool CallStack::fillUDI(unw_dyn_info_t &di, SymbolsFile &symbolsFile, const MemMapItem &mmap, + const VirtualThread &thread) +{ + di.start_ip = mmap.begin_; + di.end_ip = mmap.end_; +#ifndef target_cpu_arm + uint64_t fdeTableElfOffset, fdeTableSize, ehFrameHdrElfOffset; + if ((UNW_INFO_FORMAT_REMOTE_TABLE == di.format) && + symbolsFile.GetHDRSectionInfo(ehFrameHdrElfOffset, fdeTableElfOffset, fdeTableSize)) { + /* + unw_word_t name_ptr; // addr. of table name (e.g., library name) + unw_word_t segbase; // segment base + unw_word_t table_len; // must be a multiple of sizeof(unw_word_t)! + unw_word_t table_data; + */ + /* + all the rti addr is offset of the elf file + begin - page offset = elf file base addr in vaddr user space + begin - page offset + elf offset = vaddr in real word.(for this thread) + */ + + // segbase is file offset . + /* + 00200000-00344000 r--p 00000000 08:02 46404365 + 00344000-005c4000 r-xp 00143000 08:02 46404365 + + LOAD 0x00000000001439c0 0x00000000003449c0 0x00000000003449c0 + 0x000000000027f3c0 0x000000000027f3c0 R E 0x1000 + + GNU_EH_FRAME 0x00000000000f3248 0x00000000002f3248 0x00000000002f3248 + 0x000000000000bb04 0x000000000000bb04 R 0x4 + + */ + const MemMapItem *ehFrameMmap = thread.FindMapByFileInfo(mmap.name_, ehFrameHdrElfOffset); + + if (ehFrameMmap == nullptr) { + HLOGE("no ehframe mmap found."); + return false; + } + + di.u.rti.segbase = ehFrameMmap->begin_ + ehFrameHdrElfOffset - ehFrameMmap->pageoffset_; + di.u.rti.table_data = ehFrameMmap->begin_ + fdeTableElfOffset - ehFrameMmap->pageoffset_; + di.u.rti.table_len = fdeTableSize / sizeof(unw_word_t); + + HLOGV(" map pageoffset: 0x%016" PRIx64 "", mmap.pageoffset_); + HLOGV(" ehFrameHdrElfOffset: 0x%016" PRIx64 "", ehFrameHdrElfOffset); + HLOGV(" fdeTableElfOffset: 0x%016" PRIx64 "", fdeTableElfOffset); + HLOGV(" fdeTableSize: 0x%016" PRIx64 "", fdeTableSize); + return true; + } else { + HLOGD("SymbolsFile::GetHDRSectionInfo() failed"); + } +#else + uint64_t SectionVaddr, SectionSize, SectionFileOffset; + if ((UNW_INFO_FORMAT_ARM_EXIDX == di.format) && + symbolsFile.GetSectionInfo(ARM_EXIDX, SectionVaddr, SectionSize, SectionFileOffset)) { + const MemMapItem *targetMmap = thread.FindMapByFileInfo(mmap.name_, SectionFileOffset); + if (targetMmap == nullptr) { + HLOGE("no debug mmap found."); + return false; + } + HLOGV(" begin: %" PRIx64 " offset:%" PRIx64 "", targetMmap->begin_, + targetMmap->pageoffset_); + + di.u.rti.table_data = targetMmap->begin_ + SectionFileOffset - targetMmap->pageoffset_; + di.u.rti.table_len = SectionSize; + HLOGV(" SectionName: %s", std::string(ARM_EXIDX).c_str()); + HLOGV(" SectionVaddrt: 0x%016" PRIx64 "", SectionVaddr); + HLOGV(" SectionFileOffset 0x%016" PRIx64 "", SectionFileOffset); + HLOGV(" SectionSize: 0x%016" PRIx64 "", SectionSize); + + // GetSectionInfo return true, but SectionVaddr || SectionSize is 0 ??? + HLOG_ASSERT(SectionVaddr != 0 && SectionSize != 0); + return true; + } else { + HLOGD("SymbolsFile::GetSectionInfo() failed"); + } +#endif + return false; +} + +/* + https://www.nongnu.org/libunwind/man/libunwind-dynamic(3).html +*/ +int CallStack::FindUnwindTable(SymbolsFile *symbolsFile, const MemMapItem &mmap, + UnwindInfo *unwindInfoPtr, unw_addr_space_t as, unw_word_t ip, + unw_proc_info_t *pi, int need_unwind_info, void *arg) +{ + HLOGM("try search debug info at %s", symbolsFile->filePath_.c_str()); + auto &dynInfoProcessMap = unwindInfoPtr->callStack.unwindDynInfoMap_; + // all the thread in same process have same mmap and symbols + if (dynInfoProcessMap.find(unwindInfoPtr->thread.pid_) == dynInfoProcessMap.end()) { + dynInfoProcessMap.emplace(unwindInfoPtr->thread.pid_, dsoUnwDynInfoMap {}); + } + dsoUnwDynInfoMap &dynFileMap = dynInfoProcessMap[unwindInfoPtr->thread.pid_]; + // find use dso name as key + if (dynFileMap.find(symbolsFile->filePath_) == dynFileMap.end()) { + unw_dyn_info_t newdi; + if (memset_s(&newdi, sizeof(unw_dyn_info_t), 0, sizeof(unw_dyn_info_t)) != EOK) { + HLOGE("memset_s() failed"); + return -UNW_EUNSPEC; + } +#ifdef target_cpu_arm + // arm use .ARM.exidx , not use ehframe + newdi.format = UNW_INFO_FORMAT_ARM_EXIDX; +#else + // otherwise we use EH FRAME + newdi.format = UNW_INFO_FORMAT_REMOTE_TABLE; +#endif + if (fillUDI(newdi, *symbolsFile, mmap, unwindInfoPtr->thread)) { + dumpUDI(newdi); + // we make a option empty value first + std::optional &odi = dynFileMap[symbolsFile->filePath_]; + odi = newdi; + } else { + HLOGV("fillUDI failed()"); + return -UNW_EUNSPEC; + } + } + + HLOG_ASSERT(dynInfoProcessMap.find(unwindInfoPtr->thread.pid_) != dynInfoProcessMap.end()); + HLOG_ASSERT_MESSAGE(dynFileMap.find(symbolsFile->filePath_) != dynFileMap.end(), "%s", + symbolsFile->filePath_.c_str()); + std::optional &odi = + dynInfoProcessMap.at(unwindInfoPtr->thread.pid_).at(symbolsFile->filePath_); + + if (odi.has_value()) { + unw_dyn_info_t &di = odi.value(); + /* + we don't use dwarf_search_unwind_table + because in arm it will search two function: + 1 arm_search_unwind_table first + 2 dwarf_search_unwind_table + + see libunwind_i.h for arm + define tdep_search_unwind_table UNW_OBJ(search_unwind_table) + + */ + int ret = static_cast( + tdep_search_unwind_table(as, ip, &di, pi, need_unwind_info, arg)); + + HLOGM("search_unwind_table ret %d:%s", ret, GetUnwErrorName(ret).c_str()); + + if (UNW_ESUCCESS != ret) { + if (UNW_ENOINFO != ret) { + HLOGW("search_unwind_table ret error %d:%s", ret, GetUnwErrorName(ret).c_str()); + } + return -UNW_EUNSPEC; + } else { + return UNW_ESUCCESS; + } + } else { + HLOGW("no debug info found for thread %d:%s", unwindInfoPtr->thread.tid_, + unwindInfoPtr->thread.name_.c_str()); + return -UNW_EUNSPEC; + } +} + +int CallStack::FindProcInfo(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi, + int need_unwind_info, void *arg) +{ + UnwindInfo *unwindInfoPtr = static_cast(arg); + + HLOGM("need_unwind_info ret %d ip %" UNW_WORD_PFLAG "", need_unwind_info, ip); + const MemMapItem *mmap = unwindInfoPtr->thread.FindMapByAddr(ip); + if (mmap != nullptr) { + SymbolsFile *symbolsFile = unwindInfoPtr->thread.FindSymbolsFileByMap(*mmap); + if (symbolsFile != nullptr) { + return FindUnwindTable(symbolsFile, *mmap, unwindInfoPtr, as, ip, pi, need_unwind_info, + arg); + } else { + HLOGW("no symbols file found for thread %d:%s", unwindInfoPtr->thread.tid_, + unwindInfoPtr->thread.name_.c_str()); + } + } else { + HLOGE("ip 0x%016" UNW_WORD_PFLAG " not found in thread %d:%s", ip, + unwindInfoPtr->thread.tid_, unwindInfoPtr->thread.name_.c_str()); + } + + return -UNW_EUNSPEC; +} + +bool CallStack::ReadVirtualThreadMemory(UnwindInfo &unwindInfoPtr, unw_word_t addr, + unw_word_t *data) +{ + auto process = unwindInfoPtr.callStack.porcessMemoryMap_.find(unwindInfoPtr.thread.pid_); + if (process != unwindInfoPtr.callStack.porcessMemoryMap_.end()) { + auto memory = process->second.find(addr); + if (memory != process->second.end()) { + *data = memory->second; + return true; + } + } + + if (unwindInfoPtr.thread.ReadRoMemory(addr, (uint8_t *)data, sizeof(unw_word_t))) { + unwindInfoPtr.callStack.porcessMemoryMap_[unwindInfoPtr.thread.pid_][addr] = *data; + return true; + } else { + return false; + } +} + +int CallStack::AccessMem([[maybe_unused]] unw_addr_space_t as, unw_word_t addr, + unw_word_t *valuePoint, int writeOperation, void *arg) +{ + UnwindInfo *unwindInfoPtr = static_cast(arg); + *valuePoint = 0; + HLOGDUMMY("try access addr 0x%" UNW_WORD_PFLAG " ", addr); + HLOG_ASSERT(writeOperation == 0); + + /* Check overflow. */ + if (addr + sizeof(unw_word_t) < addr) { + HLOGE("address overfolw at 0x%" UNW_WORD_PFLAG " increase 0x%zu", addr, sizeof(unw_word_t)); + return -UNW_EUNSPEC; + } + + if (addr < unwindInfoPtr->callStack.stackPoint_ or + addr + sizeof(unw_word_t) >= unwindInfoPtr->callStack.stackEnd_) { + if (ReadVirtualThreadMemory(*unwindInfoPtr, addr, valuePoint)) { + HLOGM("access_mem addr %p get val 0x%" UNW_WORD_PFLAG ", from mmap", + reinterpret_cast(addr), *valuePoint); + } else { + HLOGW("access_mem addr %p failed, from mmap, ", reinterpret_cast(addr)); + HLOGW("stack range 0x%" PRIx64 " - 0x%" PRIx64 "(0x%" PRIx64 ")", + unwindInfoPtr->callStack.stackPoint_, unwindInfoPtr->callStack.stackEnd_, + unwindInfoPtr->callStack.stackEnd_ - unwindInfoPtr->callStack.stackPoint_); + return -UNW_EUNSPEC; + } + } else { + size_t stackOffset = addr - unwindInfoPtr->callStack.stackPoint_; + *valuePoint = *(unw_word_t *)&unwindInfoPtr->callStack.stack_[stackOffset]; + HLOGM("access_mem addr %p val %" UNW_WORD_PFLAG ", from stack offset %zu", + reinterpret_cast(addr), *valuePoint, stackOffset); + } + + return UNW_ESUCCESS; +} + +int CallStack::AccessReg([[maybe_unused]] unw_addr_space_t as, unw_regnum_t regnum, + unw_word_t *valuePoint, int writeOperation, void *arg) +{ + UnwindInfo *unwindInfoPtr = static_cast(arg); + uint64_t val; + int perfRegIndex = LibunwindRegIdToPerfReg(regnum); + if (perfRegIndex < 0) { + HLOGE("can't read reg %d", perfRegIndex); + return perfRegIndex; + } + /* Don't support write, I suspect we don't need it. */ + if (writeOperation) { + HLOGE("access_reg %d", regnum); + return -UNW_EINVAL; + } + + if (unwindInfoPtr->callStack.regsNum_ == 0) { + return -UNW_EUNSPEC; + } + + if (!RegisterGetValue(val, unwindInfoPtr->callStack.regs_, static_cast(perfRegIndex), + unwindInfoPtr->callStack.regsNum_)) { + HLOGE("can't read reg %d", perfRegIndex); + return -UNW_EUNSPEC; + } + + *valuePoint = (unw_word_t)val; + HLOGM("reg %d:%s, val 0x%" UNW_WORD_PFLAG "", regnum, RegisterGetName(static_cast(perfRegIndex)).c_str(), + *valuePoint); + return UNW_ESUCCESS; +} + +void CallStack::PutUnwindInfo([[maybe_unused]] unw_addr_space_t as, + [[maybe_unused]] unw_proc_info_t *pi, [[maybe_unused]] void *arg) +{ +} + +int CallStack::AccessFpreg([[maybe_unused]] unw_addr_space_t as, [[maybe_unused]] unw_regnum_t num, + [[maybe_unused]] unw_fpreg_t *val, [[maybe_unused]] int writeOperation, + [[maybe_unused]] void *arg) +{ + return -UNW_EINVAL; +} + +int CallStack::GetDynInfoListAaddr([[maybe_unused]] unw_addr_space_t as, + [[maybe_unused]] unw_word_t *dil_vaddr, + [[maybe_unused]] void *arg) +{ + return -UNW_ENOINFO; +} + +int CallStack::Resume([[maybe_unused]] unw_addr_space_t as, [[maybe_unused]] unw_cursor_t *cu, + [[maybe_unused]] void *arg) +{ + return -UNW_EINVAL; +} + +int CallStack::getProcName([[maybe_unused]] unw_addr_space_t as, [[maybe_unused]] unw_word_t addr, + [[maybe_unused]] char *bufp, [[maybe_unused]] size_t buf_len, + [[maybe_unused]] unw_word_t *offp, [[maybe_unused]] void *arg) +{ + return -UNW_EINVAL; +} + +void CallStack::UnwindStep(unw_cursor_t &c, std::vector &callStack, size_t maxStackLevel) +{ + while (callStack.size() < maxStackLevel) { + int ret = unw_step(&c); + if (ret > 0) { + unw_word_t ip, sp; + unw_get_reg(&c, UNW_REG_IP, &ip); + unw_get_reg(&c, UNW_REG_SP, &sp); + + if (ip == 0) { + HLOGD("ip == 0 something is wrong. break"); + break; + } + + /* + * Decrement the IP for any non-activation frames. + * this is required to properly find the srcline + * for caller frames. + * See also the documentation for dwfl_frame_pc(), + * which this code tries to replicate. + */ + if (unw_is_signal_frame(&c) <= 0) { + --ip; + } + HLOGV("unwind:%zu: ip 0x%" UNW_WORD_PFLAG " sp 0x%" UNW_WORD_PFLAG "", callStack.size(), + ip, sp); + if (callStack.back().ip_ == ip && callStack.back().sp_ == sp) { + HLOGW("we found a same frame, stop here"); + break; + } + callStack.emplace_back(ip, sp); + } else { + HLOGV("no more frame step found. ret %d:%s", ret, GetUnwErrorName(ret).c_str()); + break; + } + } +} +#endif + +bool CallStack::GetIpSP(uint64_t &ip, uint64_t &sp, const u64 *regs, size_t regNum) const +{ + if (regNum > 0) { + if (!RegisterGetSPValue(sp, arch_, regs, regNum)) { + HLOGW("unable get sp"); + return false; + } + if (!RegisterGetIPValue(ip, arch_, regs, regNum)) { + HLOGW("unable get ip"); + return false; + } + if (ip != 0) { + return true; + } + } else { + HLOGW("reg size is 0"); + return false; + } + return false; +} + +#if HAVE_LIBUNWIND +bool CallStack::DoUnwind(const VirtualThread &thread, std::vector &callStack, + size_t maxStackLevel) +{ + unw_addr_space_t addr_space; + UnwindInfo unwindInfo = { + .thread = thread, + .callStack = *this, + }; + unw_cursor_t c; + if (unwindAddrSpaceMap_.count(thread.tid_) == 0) { + addr_space = unw_create_addr_space(&accessors_, 0); + if (!addr_space) { + HLOGE("Can't create unwind vaddress space."); + return false; + } + unwindAddrSpaceMap_.emplace(thread.tid_, addr_space); + unw_set_caching_policy(addr_space, UNW_CACHE_GLOBAL); + unw_flush_cache(addr_space, 0, 0); + } else { + addr_space = unwindAddrSpaceMap_.at(thread.tid_); + } + + int ret = unw_init_remote(&c, addr_space, &unwindInfo); + if (ret) { + HLOGE("unwind error %d:%s see unw_error_t.", ret, GetUnwErrorName(ret).c_str()); + return false; + } else { + UnwindStep(c, callStack, maxStackLevel); + } + return true; +} +#endif + +bool CallStack::UnwindCallStack(const VirtualThread &thread, bool abi32, u64 *regs, u64 regsNum, + const u8 *stack, u64 stackSize, std::vector &callStack, + size_t maxStackLevel) +{ + regs_ = regs; + regsNum_ = regsNum; + stack_ = stack; + stackSize_ = stackSize; + + arch_ = GetArchTypeFromABI(abi32); + UpdateRegForABI(arch_, regs_); + if (!RegisterGetSPValue(stackPoint_, arch_, regs_, regsNum_)) { + HLOGE("RegisterGetSPValue failed"); + return false; + } else { + stackEnd_ = stackPoint_ + stackSize_; + } + +#if HAVE_LIBUNWIND + uint64_t ip, sp; + if (!GetIpSP(ip, sp, regs_, regsNum_)) { + HLOGW("unable get sp or sp , unable unwind"); + return false; + } else { + if (ip != 0) { + HLOGV("unwind:%zu: ip 0x%" PRIx64 " sp 0x%" PRIx64 "", callStack.size(), ip, sp); + callStack.emplace_back(ip, sp); + } + } + + /* + * If we need more than one entry, do the DWARF + * unwind itself. + */ + if (maxStackLevel - 1 > 0) { + return DoUnwind(thread, callStack, maxStackLevel); + } +#endif + return true; +} + +void CallStack::LogFrame(const std::string msg, const std::vector &frames) +{ + HLOGM("%s", msg.c_str()); + int level = 0; + for (auto frame : frames) { + HLOGM("%d:%s", level++, frame.ToString().c_str()); + } +} + +/* +we should have CallStack cache for each thread +end begin +0. A -> B -> C -> E -> F +1. C -> E -> F +2. B -> C +3. A -> B -> C +4. B -> G -> H +5. J -> C + +0 is our cache +1 2 3... is from record + +use expandLimit to setup how may frame match is needs + +*/ +size_t CallStack::DoExpandCallStack(std::vector &newCallFrames, + const std::vector &cachedCallFrames, + size_t expandLimit) +{ + int maxCycle = 0; + + if (expandLimit == 0 or newCallFrames.size() < expandLimit or + cachedCallFrames.size() < expandLimit) { + HLOGM("expandLimit %zu not match new %zu cache %zu", expandLimit, newCallFrames.size(), + cachedCallFrames.size()); + return 0; // size not enough + } + + // called (Stack Buttom) , this will NOT change when compare + // in case1 newIt -> C + // in case2 newIt -> B + const auto newIt = newCallFrames.end() - expandLimit; + + HLOGM("try find new call chain bottom %s for limit %zu", newIt->ToString().c_str(), + expandLimit); + + // first frame search, from called - > caller + // for case 2 it should found B + size_t distances = expandLimit - 1; + auto cachedIt = find(cachedCallFrames.begin(), cachedCallFrames.end(), *newIt); + if (cachedIt == cachedCallFrames.end()) { + HLOGM("not found in first search"); + } + + // cache frame found + while (std::distance(cachedIt, cachedCallFrames.end()) >= signed(expandLimit)) { + HLOG_ASSERT_MESSAGE(maxCycle++ < MAX_CALL_FRAME_EXPAND_CYCLE, "MAX_UNWIND_CYCLE = %d reach", + MAX_CALL_FRAME_EXPAND_CYCLE); + + if (std::equal(newIt, newIt + expandLimit, cachedIt)) { + HLOGM("match %s + %zu", newIt->ToString().c_str(), expandLimit); + cachedIt += expandLimit; // in while we check the boundary safe + if (cachedIt == cachedCallFrames.end()) { + // same but no more need expand + break; + } + + // expand the frame and make some log ? + LogFrame("newCallStack:", newCallFrames); + LogFrame("cachedCallStack:", cachedCallFrames); + + newCallFrames.insert(newCallFrames.end(), cachedIt, cachedCallFrames.end()); + auto expands = std::distance(cachedIt, cachedCallFrames.end()); + HLOGV("merge callstack increse to %zu (+%zd) ", newCallFrames.size(), expands); + // we done the deal + return expands; + } else { + // quick search next same farme again + cachedIt++; + if (cachedIt != cachedCallFrames.end()) { + HLOGM("search next"); + cachedIt = find(cachedIt, cachedCallFrames.end(), *newIt); + } + } + } + HLOGM("cachedIt distance %zd , need %zd", std::distance(cachedCallFrames.begin(), cachedIt), + distances); + return 0u; // nothing expand +} + +size_t CallStack::ExpandCallStack(pid_t tid, std::vector &callFrames, size_t expandLimit) +{ + size_t expand = 0u; + if (expandLimit == 0) { + return expand; // nothing need to do + } else if (callFrames.size() < expandLimit) { + HLOGM("new callstack is too small, skip it"); + return expand; + } + if (!cachedCallFramesMap_.count(tid)) { + cachedCallFramesMap_[tid].reserve(MAX_CALL_FRAME_EXPAND_CACHE_SIZE); + } + if (callFrames.size() >= 1u) { + // get top (Earliest caller) + HashList> &cachedCallFrames = cachedCallFramesMap_[tid]; + HLOGV("find call stack frames in cache size %zu", cachedCallFrames.size()); + // compare + using namespace std::rel_ops; // enable complement comparing operators + for (auto itr = cachedCallFrames.begin(); itr < cachedCallFrames.end(); ++itr) { + // each cached callstack + /* + stack 2 1 0 + cache A -> B -> C + new B -> C + check: + 1 if new B == cache C + 2 if new B == cache B + 3 if new C == new C (if limit > 0) + 4 insert A after B in new stack + */ + const std::vector &cachedCallStack = *itr; + if (cachedCallStack.size() < expandLimit) { + HLOGM("cache callstack is too small, skip it"); + continue; // check next + } + expand = DoExpandCallStack(callFrames, cachedCallStack, expandLimit); + if (expand > 0) { + break; + } + } + // add new one in to cache cachedCallFrames. + // further optimization can be done by caching pointer which avoids copying + // vector + cachedCallFrames[callFrames[0].ip_] = callFrames; + } + HLOGM("expand %zu", expand); + return expand; +} + +CallStack::CallStack() {} + +CallStack::~CallStack() +{ +#if HAVE_LIBUNWIND + for (auto &pair : unwindAddrSpaceMap_) { + unw_destroy_addr_space(pair.second); + } +#endif +} +} // namespace HiPerf +} // namespace Developtools +} // namespace OHOS diff --git a/host/trace_streamer/src/parser/hiperf_parser/hiperf/debug_logger.cpp b/host/trace_streamer/src/parser/hiperf_parser/hiperf/debug_logger.cpp new file mode 100644 index 0000000000000000000000000000000000000000..171585d8554d02dfc4565fc38c6b7d48758b0e5e --- /dev/null +++ b/host/trace_streamer/src/parser/hiperf_parser/hiperf/debug_logger.cpp @@ -0,0 +1,294 @@ +/* + * Copyright (c) 2021-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. + */ + +#include "debug_logger.h" + +#include + +#include "option.h" +#if is_ohos +#include "hiperf_hilog.h" +#endif + +using namespace std::literals::chrono_literals; +using namespace std::chrono; +namespace OHOS { +namespace Developtools { +namespace HiPerf { +#ifdef HIPERF_DEBUG +DebugLogger::DebugLogger() : timeStamp_(steady_clock::now()), logPath_(DEFAULT_LOG_PATH) +{ + OpenLog(); +} + +ScopeDebugLevel::ScopeDebugLevel(DebugLevel level, bool mix) +{ + savedDebugLevel_ = DebugLogger::GetInstance()->SetLogLevel(level); + savedMixOutput_ = DebugLogger::GetInstance()->SetMixLogOutput(mix); +} + +ScopeDebugLevel::~ScopeDebugLevel() +{ + DebugLogger::GetInstance()->SetLogLevel(savedDebugLevel_); + DebugLogger::GetInstance()->SetMixLogOutput(savedMixOutput_); +} + +DebugLogger::~DebugLogger() +{ + Disable(); + if (file_ != nullptr) { + fclose(file_); + file_ = nullptr; + } +} + +void DebugLogger::Disable(bool disable) +{ + if (logDisabled_ != disable) { + logDisabled_ = disable; + if (!disable) { + // reopen the log file + OpenLog(); + } + } +} + +#if is_ohos +#ifndef CONFIG_NO_HILOG +int DebugLogger::HiLog(std::string &buffer) const +{ + size_t lastLF = buffer.find_last_of('\n'); + if (lastLF != std::string::npos) { + buffer.erase(lastLF, 1); + } + return OHOS::HiviewDFX::HiLog::Debug(HIPERF_HILOG_LABLE[MODULE_DEFAULT], "%{public}s", + buffer.c_str()); +} +#endif +#endif + +int DebugLogger::Log(DebugLevel level, const std::string &logTag, const char *fmt, ...) const +{ + constexpr const int DEFAULT_STRING_BUF_SIZE = 4096; +#ifdef HIPERF_DEBUG_TIME + const auto startSprintf = steady_clock::now(); +#endif + const auto startTime = steady_clock::now(); + if (!ShouldLog(level, logTag) or logDisabled_ or fmt == nullptr) { +#ifdef HIPERF_DEBUG_TIME + logTimes_ += duration_cast(steady_clock::now() - startSprintf); +#endif + return 0; + } + va_list va; + int ret = 0; + + std::string buffer(DEFAULT_STRING_BUF_SIZE, '\0'); + va_start(va, fmt); + ret = vsnprintf_s(buffer.data(), buffer.size(), buffer.size() - 1, fmt, va); + va_end(va); +#ifdef HIPERF_DEBUG_TIME + logSprintfTimes_ += duration_cast(steady_clock::now() - startSprintf); +#endif + if ((mixLogOutput_ and level < LEVEL_FATAL) or level == LEVEL_FATAL) { + ret = fprintf(stdout, "%s", buffer.data()); // to the stdout + } + + if (enableHilog_) { +#if is_ohos && !defined(CONFIG_NO_HILOG) + std::lock_guard lock(logMutex_); + ret = HiLog(buffer); // to the hilog +#endif + } else if (file_ != nullptr) { + std::lock_guard lock(logMutex_); +#ifdef HIPERF_DEBUG_TIME + const auto startWriteTime = steady_clock::now(); +#endif + milliseconds timeStamp = duration_cast(startTime - timeStamp_); + fprintf(file_, "%05" PRId64 "ms %s", (int64_t)timeStamp.count(), buffer.data()); // to the file +#ifdef HIPERF_DEBUG_TIME + logWriteTimes_ += duration_cast(steady_clock::now() - startWriteTime); +#endif + } + +#ifdef HIPERF_DEBUG_TIME + logTimes_ += duration_cast(steady_clock::now() - startTime); + logCount_++; +#endif + if (level == LEVEL_FATAL && exitOnFatal_) { + fflush(file_); + logDisabled_ = true; + exit(-1); + } + return ret; +} + +bool DebugLogger::EnableHiLog(bool enable) +{ + enableHilog_ = enable; + if (enable) { + if (fprintf(stdout, "change to use hilog\n") < 0) { + // what can we do here ??? + } + } + return enableHilog_; +} + +bool DebugLogger::ShouldLog(DebugLevel level, const std::string &logtag) const +{ + return GetLogLevelByTag(logtag) <= level; +} + +DebugLevel DebugLogger::SetLogLevel(DebugLevel debugLevel) +{ + DebugLevel lastLevel = DebugLogger::GetInstance()->debugLevel_; + debugLevel_ = debugLevel; + // force print + printf("setLogLevel %d\n", debugLevel); + return lastLevel; +} + +bool DebugLogger::SetMixLogOutput(bool enable) +{ + bool lastMixLogOutput = mixLogOutput_; + mixLogOutput_ = enable; + return lastMixLogOutput; +} + +bool DebugLogger::SetLogPath(const std::string &newLogPath) +{ + // make sure not write happend when rename + std::lock_guard lock(logMutex_); + if (newLogPath.empty() and newLogPath != logPath_) { + return false; + } + if (file_ != nullptr) { + fclose(file_); + file_ = nullptr; + if (rename(logPath_.c_str(), newLogPath.c_str()) != 0) { + // reopen the old log file path + OpenLog(); + return false; + } + } + logPath_ = newLogPath; + return OpenLog(); +} + +void DebugLogger::SetLogTags(const std::string &tags) +{ + HLOGI(" tags is '%s'", tags.c_str()); + auto tagLevels = StringSplit(tags, ","); + logTagLevelmap_.clear(); + for (auto tagLevel : tagLevels) { + auto tagLevelPair = StringSplit(tagLevel, ":"); + if (tagLevelPair.size() == 1) { // only tag + logTagLevelmap_[tagLevelPair[0]] = LEVEL_MUCH; + } else { // tag:level + logTagLevelmap_[tagLevelPair[0]] = GetLogLevelByName(tagLevelPair[1].c_str()); + } + } + for (auto it = logTagLevelmap_.begin(); it != logTagLevelmap_.end(); it++) { + HLOGD(" '%s'='%s'", it->first.c_str(), GetLogLevelName(it->second).c_str()); + } +} + +DebugLevel DebugLogger::GetLogLevelByTag(const std::string &tag) const +{ + if (logTagLevelmap_.count(tag) > 0) { + return logTagLevelmap_.at(tag); + } else { + return GetLogLevel(); + } +} + +const std::string DebugLogger::GetLogLevelName(DebugLevel level) const +{ + return DebugLevelMap.at(level); +} + +DebugLevel DebugLogger::GetLogLevelByName(const std::string &name) const +{ + for (auto it = DebugLevelMap.begin(); it != DebugLevelMap.end(); it++) { + if (it->second == name) { + return it->first; + } + } + // not found ? + return LEVEL_MUCH; +} + +// only use for UT +void DebugLogger::Reset() +{ + EnableHiLog(false); + SetLogLevel(LEVEL_VERBOSE); + Disable(false); + SetLogPath(DEFAULT_LOG_PATH); + SetLogTags(""); +} + +bool DebugLogger::RestoreLog() +{ + // use append not write for continually write + return OpenLog(logPath_, "a"); +} + +bool DebugLogger::OpenLog(const std::string &tempLogPath, const std::string &flags) +{ + std::lock_guard lock(logMutex_); + + if (logDisabled_) { + // don't reopen it when we crash or something else. + return false; + } + if (!tempLogPath.empty()) { + fclose(file_); + std::string resolvedPath = CanonicalizeSpecPath(tempLogPath.c_str()); + file_ = fopen(resolvedPath.c_str(), flags.c_str()); + } + if (file_ != nullptr) { + // already open + return true; + } else { + std::string resolvedPath = CanonicalizeSpecPath(logPath_.c_str()); + file_ = fopen(resolvedPath.c_str(), "w"); + } + if (file_ == nullptr) { + fprintf(stdout, "unable save log file to '%s' because '%d'\n", logPath_.c_str(), errno); + return false; + } else { + fseek(file_, 0, SEEK_SET); + // ecach log can save 6ms (29ms -> 23ms) + fprintf(stdout, "log will save at '%s'\n", logPath_.c_str()); + return true; + } +} + +__attribute__((weak)) DebugLevel DebugLogger::debugLevel_ = LEVEL_DEBUG; +__attribute__((weak)) bool DebugLogger::logDisabled_ = true; +std::unique_ptr DebugLogger::logInstance_; + +DebugLogger *DebugLogger::GetInstance() +{ + if (logInstance_ == nullptr) { + logInstance_ = std::make_unique(); + } + return logInstance_.get(); +} +#endif +} // namespace HiPerf +} // namespace Developtools +} // namespace OHOS diff --git a/host/trace_streamer/src/parser/hiperf_parser/hiperf/dwarf_encoding.cpp b/host/trace_streamer/src/parser/hiperf_parser/hiperf/dwarf_encoding.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1cfb7bcedab01309b217d9d6ba523e98c2037de7 --- /dev/null +++ b/host/trace_streamer/src/parser/hiperf_parser/hiperf/dwarf_encoding.cpp @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2021-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. + */ +#define HILOG_TAG "Dwarf" + +#include "dwarf_encoding.h" + +#include "utilities.h" +namespace OHOS { +namespace Developtools { +namespace HiPerf { +DwarfEncoding::DwarfEncoding(dw_encode_t dw, const unsigned char *&data, uint64_t vaddrBase, + uint64_t vaddrPC, uint64_t vaddrText) + : dw_(dw), data_(data), vaddrBase_(vaddrBase), vaddrPC_(vaddrPC), vaddrText_(vaddrText) +{ + value_[0] = ReadValue(data); +} + +const std::string DwarfEncoding::ToString() const +{ + std::string debugString = ApplicationName() + ":" + FormatName() + " format:" + ToHex(dw_) + + " value size:" + std::to_string(GetSize()) + " raw:"; + + size_t size = GetSize(); + const unsigned char *data = data_; + while (size-- > 0) { + debugString.append(ToHex(data[0]) + " "); + data++; + } + + debugString.append(" | " + ToHex(GetValue(), GetSize(), true)); + debugString.append(" applied:" + ToHex(GetAppliedValue(), GetSize())); + return debugString; +} + +const unsigned char *DwarfEncoding::GetEnd() const +{ + return data_ + GetSize(); +} + +const unsigned char *DwarfEncoding::GetData() const +{ + return data_; +} + +size_t DwarfEncoding::GetSize() const +{ + return DWFormatSizeMap.at((dw_encode_t)Format()); +} + +uint64_t DwarfEncoding::GetValue() const +{ + return value_[0]; +} + +uint64_t DwarfEncoding::GetAppliedValue() const +{ + if ((Application() & DW_EH_PE_datarel) == DW_EH_PE_datarel) { + return value_[0] + vaddrBase_; + } else if ((Application() & DW_EH_PE_textrel) == DW_EH_PE_textrel) { + return value_[0] + vaddrText_; + } else if ((Application() & DW_EH_PE_pcrel) == DW_EH_PE_pcrel) { + return value_[0] + vaddrPC_; + } + HLOGM("Application is empty"); + + return value_[0]; +} + +bool DwarfEncoding::IsOmit() const +{ + return (dw_ == DW_EH_PE_omit); +} + +dw_encode_t DwarfEncoding::Format() const +{ + return (dw_ & 0x0F); +} +dw_encode_t DwarfEncoding::Application() const +{ + return (dw_ & 0xF0); +} +uint64_t DwarfEncoding::ReadValue(const unsigned char *&data) const +{ + switch (Format()) { + case DW_EH_PE_udata2: + return dwReadAnyTypeData(data, uint16_t()); + case DW_EH_PE_udata4: + return dwReadAnyTypeData(data, uint32_t()); + case DW_EH_PE_udata8: + return dwReadAnyTypeData(data, uint64_t()); + case DW_EH_PE_sdata2: + return dwReadAnyTypeData(data, int16_t()); + case DW_EH_PE_sdata4: + return dwReadAnyTypeData(data, int32_t()); + case DW_EH_PE_sdata8: + return dwReadAnyTypeData(data, int64_t()); + default: + return -1; + } +} +const std::string DwarfEncoding::FormatName() const +{ + switch (Format()) { + case DW_EH_PE_absptr: + return "DW_EH_PE_absptr"; + case DW_EH_PE_uleb128: + return "DW_EH_PE_uleb128"; + case DW_EH_PE_udata2: + return "DW_EH_PE_udata2"; + case DW_EH_PE_udata4: + return "DW_EH_PE_udata4"; + case DW_EH_PE_udata8: + return "DW_EH_PE_udata8"; + case DW_EH_PE_sleb128: + return "DW_EH_PE_sleb128"; + case DW_EH_PE_sdata2: + return "DW_EH_PE_data2"; + case DW_EH_PE_sdata4: + return "DW_EH_PE_sdata4"; + case DW_EH_PE_sdata8: + return "DW_EH_PE_sdata8"; + case DW_EH_PE_omit: + return "DW_EH_PE_omit"; + default: + return "unknown format"; + } +} +const std::string DwarfEncoding::ApplicationName() const +{ + switch (Application()) { + case DW_EH_PE_pcrel: + return "DW_EH_PE_pcrel"; + case DW_EH_PE_textrel: + return "DW_EH_PE_textrel"; + case DW_EH_PE_datarel: + return "DW_EH_PE_datarel"; + case DW_EH_PE_funcrel: + return "DW_EH_PE_funcrel"; + case DW_EH_PE_aligned: + return "DW_EH_PE_aligned"; + case DW_EH_PE_omit: + return "DW_EH_PE_omit"; + case DW_EH_PE_nothing: + return "DW_EH_PE_empty"; + default: + return "unknown format"; + } +} +} // namespace HiPerf +} // namespace Developtools +} // namespace OHOS diff --git a/host/trace_streamer/src/parser/hiperf_parser/hiperf/elf_file.cpp b/host/trace_streamer/src/parser/hiperf_parser/hiperf/elf_file.cpp new file mode 100644 index 0000000000000000000000000000000000000000..53894c94ca15a98f2988d2bcb73145ccb4d60bde --- /dev/null +++ b/host/trace_streamer/src/parser/hiperf_parser/hiperf/elf_file.cpp @@ -0,0 +1,359 @@ +/* + * Copyright (c) 2021-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. + */ + +#include +#include "string_help.h" +#include "utilities.h" + +using namespace OHOS::Developtools::HiPerf::ELF; +namespace OHOS { +namespace Developtools { +namespace HiPerf { +ElfFile::ElfFile(const std::string &filename) +{ +#if is_mingw + std::string resolvedPath = CanonicalizeSpecPath(filename.c_str()); + fd_ = open(resolvedPath.c_str(), O_RDONLY | O_BINARY); +#else + std::string resolvedPath = CanonicalizeSpecPath(filename.c_str()); + fd_ = open(resolvedPath.c_str(), O_RDONLY); +#endif + if (fd_ != -1) { + struct stat sb; + if (fstat(fd_, &sb) == -1) { + HLOGE("unable to check the file size"); + } else { + HLOGD("file stat size %" PRIu64 "", sb.st_size); + + mmap_ = mmap(0, sb.st_size, PROT_READ, MAP_PRIVATE, fd_, 0); + if (mmap_ == MMAP_FAILED) { + HLOGE("unable to map the file size %" PRIu64 " ", sb.st_size); + mmapSize_ = 0; + } else { + mmapSize_ = sb.st_size; + HLOGD("mmap build with size %" PRIu64 " ", mmapSize_); + } + } + } +} + +ElfFile::~ElfFile() +{ + if (mmap_ != MMAP_FAILED) { + munmap(mmap_, mmapSize_); + } + + if (fd_ != -1) { + close(fd_); + fd_ = -1; + } +} + +std::unique_ptr ElfFile::MakeUnique(const std::string &filename) +{ + std::unique_ptr file {new (std::nothrow) ElfFile(filename)}; + if (file == nullptr) { + HLOGE("Error in ElfFile::MakeUnique(): ElfFile::ElfFile() failed"); + return nullptr; + } + if (!file->IsOpened()) { + HLOGE("Error in ElfFile::MakeUnique(): elf file not opended"); + return nullptr; + } + if (!file->ParseFile()) { + HLOGE("parse elf file failed"); + return nullptr; + } + return file; +} + +bool ElfFile::ParseFile() +{ + if (!ParseElfHeader()) { + HLOGE("Error in ElfFile::MakeUnique(): ElfFile::ParseElfHeader() failed"); + return false; + } + if (!ParsePrgHeaders()) { + HLOGE("Error in ElfFile::MakeUnique(): ElfFile::ParsePrgHeaders() failed"); + return false; + } + if (!ParseSecNamesStr()) { + HLOGE("Error in ElfFile::MakeUnique(): ElfFile::ParseSecNamesStr() failed"); + return false; + } + if (!ParseSecHeaders()) { + HLOGE("Error in ElfFile::MakeUnique(): ElfFile::ParseSecHeaders() failed"); + return false; + } + return true; +} + +bool ElfFile::ParseElfHeader() +{ + ssize_t ret = lseek(fd_, 0, SEEK_SET); + if (ret != 0) { + HLOGW("lseek ret %zu", ret); + return false; + } + HLOG_ASSERT(ret == 0); + unsigned char ehdrBuf[ehdr64Size] {0}; + size_t readsize = ReadFile(ehdrBuf, ehdr64Size); + if (readsize < ehdr64Size) { + HLOGW("file size not enough, try read %zu, only have %zu", ehdr64Size, readsize); + } + HLOG_ASSERT(readsize > 0); + ehdr_ = ElfHeader::MakeUnique(ehdrBuf, readsize); + return !(ehdr_ == nullptr); +} + +bool ElfFile::ParsePrgHeaders() +{ + size_t phdrSize = ehdr_->phdrEntSize_; + size_t numPhdrs = ehdr_->phdrNumEnts_; + uint64_t phdrOffset = ehdr_->phdrOffset_; + int64_t ret = lseek(fd_, phdrOffset, SEEK_SET); + HLOG_ASSERT(ret == static_cast(phdrOffset)); + char *phdrsBuf = new (std::nothrow) char[phdrSize * numPhdrs]; + if (phdrsBuf == nullptr) { + HLOGE("Error in ELF::ElfFile::ParsePrgHeaders(): new failed"); + return false; + } + (void)memset_s(phdrsBuf, phdrSize * numPhdrs, 0, phdrSize * numPhdrs); + ret = ReadFile(phdrsBuf, phdrSize * numPhdrs); + if (ret != static_cast(phdrSize * numPhdrs)) { + delete[] phdrsBuf; + phdrsBuf = nullptr; + return false; + } + char *phdrBuf = phdrsBuf; + for (size_t count = 0; count < numPhdrs; ++count) { + std::unique_ptr phdr = ProgramHeader::MakeUnique(phdrBuf, phdrSize); + if (phdr == nullptr) { + delete[] phdrsBuf; + phdrsBuf = nullptr; + HLOGE("Error in Elf::ParsePrgHeaders(): ProgramHeader::MakeUnique() failed"); + return false; + } + phdrs_.push_back(std::move(phdr)); + phdrBuf += phdrSize; + } + delete[] phdrsBuf; + phdrsBuf = nullptr; + return true; +} + +bool ElfFile::ParseSecNamesStr() +{ + // get string table section header + size_t shdrSize = ehdr_->shdrEntSize_; + size_t shdrIndex = ehdr_->shdrStrTabIdx_; + uint64_t shdrOffset = ehdr_->shdrOffset_ + ((uint64_t)shdrIndex) * shdrSize; + int64_t ret = lseek(fd_, shdrOffset, SEEK_SET); + HLOG_ASSERT(ret == static_cast(shdrOffset)); + char *shdrBuf = new (std::nothrow) char[shdrSize]; + if (shdrBuf == nullptr) { + HLOGE("Error in ElfFile::ParseSecNamesStr(): new failed"); + return false; + } + (void)memset_s(shdrBuf, shdrSize, 0, shdrSize); + ret = ReadFile(shdrBuf, shdrSize); + HLOG_ASSERT(ret == static_cast(shdrSize)); + const std::string secName {".shstrtab"}; + shdrs_[secName] = SectionHeader::MakeUnique(shdrBuf, shdrSize, shdrIndex); + if (shdrs_[secName] == nullptr) { + HLOGE("Error in ElfFile::ParseSecNamesStr(): SectionHeader::MakeUnique() failed"); + delete[] shdrBuf; + shdrBuf = nullptr; + return false; + } + delete[] shdrBuf; + shdrBuf = nullptr; + + // get content of string section table + uint64_t secOffset = shdrs_[secName]->fileOffset_; + size_t secSize = shdrs_[secName]->secSize_; + ret = lseek(fd_, secOffset, SEEK_SET); + HLOG_ASSERT(ret == static_cast(secOffset)); + char *secNamesBuf = new (std::nothrow) char[secSize]; + if (secNamesBuf == nullptr) { + HLOGE("Error in ElfFile::ParseSecNamesStr(): new secNamesBuf failed"); + return false; + } + (void)memset_s(secNamesBuf, secSize, '\0', secSize); + ret = ReadFile(secNamesBuf, secSize); + if (ret != static_cast(secSize)) { + delete[] secNamesBuf; + secNamesBuf = nullptr; + return false; + } + secNamesStr_ = std::string(secNamesBuf, secNamesBuf + secSize); + delete[] secNamesBuf; + secNamesBuf = nullptr; + return true; +} + +bool ElfFile::ParseSecHeaders() +{ + size_t shdrSize = ehdr_->shdrEntSize_; + size_t numShdrs = ehdr_->shdrNumEnts_; + uint64_t shdrOffset = ehdr_->shdrOffset_; + int64_t ret = lseek(fd_, shdrOffset, SEEK_SET); + HLOG_ASSERT(ret == static_cast(shdrOffset)); + char *shdrsBuf = new (std::nothrow) char[shdrSize * numShdrs]; + if (shdrsBuf == nullptr) { + HLOGE("Error in ELF::ElfFile::ParseSecHeaders(): new failed"); + return false; + } + (void)memset_s(shdrsBuf, shdrSize * numShdrs, '\0', shdrSize * numShdrs); + ret = ReadFile(shdrsBuf, shdrSize * numShdrs); + HLOG_ASSERT(ret == static_cast(shdrSize * numShdrs)); + char *shdrBuf = shdrsBuf; + for (size_t count = 0; count < numShdrs; ++count) { + if (count == ehdr_->shdrStrTabIdx_) { + shdrBuf += shdrSize; + continue; + } + std::unique_ptr shdr = SectionHeader::MakeUnique(shdrBuf, shdrSize, count); + if (shdr == nullptr) { + delete[] shdrsBuf; + shdrsBuf = nullptr; + return false; + } + std::string secName = GetSectionName(shdr->nameIndex_); + shdrs_[secName] = std::move(shdr); + shdr.reset(nullptr); + shdrBuf += shdrSize; + } + delete[] shdrsBuf; + shdrsBuf = nullptr; + return true; +} + +bool ElfFile::ParseSymTable(const std::string secName) +{ + if (shdrs_.find(secName) == shdrs_.end()) { + HLOGE("Error in ELF::ElfFile::ParseSymTable(): section %s does not exist", secName.c_str()); + return false; + } else { + return ParseSymTable(shdrs_[secName].get()); + } +} + +bool ElfFile::ParseSymTable(const SectionHeader *shdr) +{ + if (shdr == nullptr) { + return false; + } + uint64_t secOffset = shdr->fileOffset_; + int64_t ret = lseek(fd_, secOffset, SEEK_SET); + HLOG_ASSERT(ret == static_cast(secOffset)); + uint64_t secSize = shdr->secSize_; + uint64_t entrySize = shdr->secEntrySize_; + char *secBuf = new (std::nothrow) char[secSize]; + if (secBuf == nullptr) { + HLOGE("Error in EFL::ElfFile::ParseSymTable(): new failed"); + return false; + } + ret = ReadFile(secBuf, secSize); + HLOG_ASSERT(ret == static_cast(secSize)); + symTable_ = SymbolTable::MakeUnique(symNamesStr_, secBuf, secSize, entrySize); + if (symTable_ == nullptr) { + delete[] secBuf; + secBuf = nullptr; + return false; + } + delete[] secBuf; + secBuf = nullptr; + return true; +} + +bool ElfFile::ParseSymNamesStr() +{ + const std::string secName {".strtab"}; + if (shdrs_.find(secName) == shdrs_.end()) { + HLOGE("Error in ElfFile::ParseSymNamesStr(): section %s does not exist", secName.c_str()); + return false; + } + const auto &shdr = shdrs_[secName]; + uint64_t secOffset = shdr->fileOffset_; + uint64_t secSize = shdr->secSize_; + int64_t ret = lseek(fd_, secOffset, SEEK_SET); + char *secBuf = new (std::nothrow) char[secSize]; + if (secBuf == nullptr) { + HLOGE("Error in ElfFile::ParsesymNamesStr(): new failed"); + return false; + } + (void)memset_s(secBuf, secSize, '\0', secSize); + ret = ReadFile(secBuf, secSize); + HLOG_ASSERT(ret == static_cast(secSize)); + symNamesStr_ = std::string(secBuf, secSize); + if (symNamesStr_ == "") { + delete[] secBuf; + secBuf = nullptr; + return false; + } + delete[] secBuf; + secBuf = nullptr; + return true; +} + +bool ElfFile::ParseDynSymTable() +{ + const std::string secName {".dynsym"}; + if (shdrs_.find(secName) == shdrs_.end()) { + HLOGE("Error in ELF::ElfFile::ParseSymTable(): section %s does not exist", secName.c_str()); + return false; + } + const auto &shdr = shdrs_[secName]; + uint64_t secOffset = shdr->fileOffset_; + int64_t ret = lseek(fd_, secOffset, SEEK_SET); + HLOG_ASSERT(ret == static_cast(secOffset)); + uint64_t secSize = shdr->secSize_; + uint64_t entrySize = shdr->secEntrySize_; + char *secBuf = new (std::nothrow) char[secSize]; + if (secBuf == nullptr) { + HLOGE("Error in EFL::ElfFile::ParseDynSymTable(): new failed"); + return false; + } + ret = ReadFile(secBuf, secSize); + HLOG_ASSERT(ret == static_cast(secSize)); + dynSymTable_ = SymbolTable::MakeUnique(symNamesStr_, secBuf, secSize, entrySize); + if (dynSymTable_ == nullptr) { + delete[] secBuf; + secBuf = nullptr; + return false; + } + delete[] secBuf; + secBuf = nullptr; + return true; +} + +std::string ElfFile::GetSectionName(const uint32_t startIndex) +{ + if (startIndex >= secNamesStr_.size()) { + HLOGF("out_of_range %s ,endIndex %d ", secNamesStr_.c_str(), startIndex); + return ""; + } + size_t endIndex {startIndex}; + for (; endIndex < secNamesStr_.size(); ++endIndex) { + if (secNamesStr_[endIndex] == '\0') { + break; + } + } + return secNamesStr_.substr(startIndex, endIndex - startIndex); +} +} // namespace HiPerf +} // namespace Developtools +} // namespace OHOS diff --git a/host/trace_streamer/src/parser/hiperf_parser/hiperf/elf_header.cpp b/host/trace_streamer/src/parser/hiperf_parser/hiperf/elf_header.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c444eb910eac8ea1622a1d761ba0e848bc51aad4 --- /dev/null +++ b/host/trace_streamer/src/parser/hiperf_parser/hiperf/elf_header.cpp @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2021 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. + */ + +#include "elf_parser.h" + +namespace OHOS { +namespace Developtools { +namespace HiPerf { +namespace ELF { +std::unique_ptr ElfHeader::MakeUnique(unsigned char * const ehdrBuf, + const std::size_t bufSize) +{ + std::unique_ptr ehdr {new (std::nothrow) ElfHeader()}; + if (ehdr == nullptr) { + HLOGV("ElfHeader() failed"); + return nullptr; + } + if (!ehdr->Init(ehdrBuf, bufSize)) { + HLOGV("ElfHeader::Init(ehdrBuf, bufSize) failed\n"); + DumpEhdrBuf(reinterpret_cast(ehdrBuf), bufSize); + return nullptr; + } + return ehdr; +} + +bool ElfHeader::Init(unsigned char * const ehdrBuf, const std::size_t bufSize) +{ + std::string magicStr {ehdrBuf, ehdrBuf + SELFMAG}; + std::string elfMagic {ELFMAG}; + if (magicStr.compare(elfMagic) != 0) { + HLOGE("elf magic not found"); + return false; + } + if (memcpy_s(ehdrIdent_, EI_NIDENT, ehdrBuf, EI_NIDENT) != 0) { + HLOGE("init ehdrIdent_ failed"); + return false; + } + if (ehdrBuf[EI_CLASS] == ELFCLASS32 and ParseElf32Header(ehdrBuf, bufSize)) { + return true; + } + if (ehdrBuf[EI_CLASS] == ELFCLASS64 and ParseElf64Header(ehdrBuf, bufSize)) { + return true; + } + HLOGE("init elf header failed, elf header buffer dumped"); + return false; +} + +bool ElfHeader::ParseElf32Header(unsigned char * const ehdrBuf, const std::size_t bufSize) +{ + if (bufSize < ehdr32Size) { + HLOGE("bad elf32 header buffer"); + return false; + } + size_t curIndex {EI_NIDENT}; + uint16_t *u2Buf = reinterpret_cast(ehdrBuf + curIndex); + type_ = u2Buf[0]; + curIndex += sizeof(uint16_t); + + u2Buf = reinterpret_cast(ehdrBuf + curIndex); + machine_ = u2Buf[0]; + curIndex += sizeof(uint16_t); + + uint32_t *u4Buf = reinterpret_cast(ehdrBuf + curIndex); + elfVersion_ = u4Buf[0]; + curIndex += sizeof(uint32_t); + + u4Buf = reinterpret_cast(ehdrBuf + curIndex); + prgEntryVaddr_ = u4Buf[0]; + curIndex += sizeof(uint32_t); + + u4Buf = reinterpret_cast(ehdrBuf + curIndex); + phdrOffset_ = u4Buf[0]; + curIndex += sizeof(uint32_t); + + u4Buf = reinterpret_cast(ehdrBuf + curIndex); + shdrOffset_ = u4Buf[0]; + curIndex += sizeof(uint32_t); + + u4Buf = reinterpret_cast(ehdrBuf + curIndex); + ehdrFlags_ = u4Buf[0]; + curIndex += sizeof(uint32_t); + + u2Buf = reinterpret_cast(ehdrBuf + curIndex); + ehdrSize_ = u2Buf[0]; + curIndex += sizeof(uint16_t); + + u2Buf = reinterpret_cast(ehdrBuf + curIndex); + phdrEntSize_ = u2Buf[0]; + curIndex += sizeof(uint16_t); + + u2Buf = reinterpret_cast(ehdrBuf + curIndex); + phdrNumEnts_ = u2Buf[0]; + curIndex += sizeof(uint16_t); + + u2Buf = reinterpret_cast(ehdrBuf + curIndex); + shdrEntSize_ = u2Buf[0]; + curIndex += sizeof(uint16_t); + + u2Buf = reinterpret_cast(ehdrBuf + curIndex); + shdrNumEnts_ = u2Buf[0]; + curIndex += sizeof(uint16_t); + + u2Buf = reinterpret_cast(ehdrBuf + curIndex); + shdrStrTabIdx_ = u2Buf[0]; + +#ifdef HIPERF_DEBUG_ASSERT + curIndex += sizeof(uint16_t); + HLOG_ASSERT(curIndex == ehdrSize_); + HLOG_ASSERT(shdr32Size == ehdrSize_); +#endif + return true; +} + +bool ElfHeader::ParseElf64Header(unsigned char * const ehdrBuf, const std::size_t bufSize) +{ + if (bufSize < ehdr64Size) { + HLOGE("bad elf64 header buffer"); + return false; + } + size_t curIndex {EI_NIDENT}; + uint16_t *u2Buf = reinterpret_cast(ehdrBuf + curIndex); + type_ = u2Buf[0]; + curIndex += sizeof(uint16_t); + + u2Buf = reinterpret_cast(ehdrBuf + curIndex); + machine_ = u2Buf[0]; + curIndex += sizeof(uint16_t); + + uint32_t *u4Buf = reinterpret_cast(ehdrBuf + curIndex); + elfVersion_ = u4Buf[0]; + curIndex += sizeof(uint32_t); + + uint64_t *u8Buf = reinterpret_cast(ehdrBuf + curIndex); + prgEntryVaddr_ = u8Buf[0]; + curIndex += sizeof(uint64_t); + + u8Buf = reinterpret_cast(ehdrBuf + curIndex); + phdrOffset_ = u8Buf[0]; + curIndex += sizeof(uint64_t); + + u8Buf = reinterpret_cast(ehdrBuf + curIndex); + shdrOffset_ = u8Buf[0]; + curIndex += sizeof(uint64_t); + + u4Buf = reinterpret_cast(ehdrBuf + curIndex); + ehdrFlags_ = u4Buf[0]; + curIndex += sizeof(uint32_t); + + u2Buf = reinterpret_cast(ehdrBuf + curIndex); + ehdrSize_ = u2Buf[0]; + curIndex += sizeof(uint16_t); + + u2Buf = reinterpret_cast(ehdrBuf + curIndex); + phdrEntSize_ = u2Buf[0]; + curIndex += sizeof(uint16_t); + + u2Buf = reinterpret_cast(ehdrBuf + curIndex); + phdrNumEnts_ = u2Buf[0]; + curIndex += sizeof(uint16_t); + + u2Buf = reinterpret_cast(ehdrBuf + curIndex); + shdrEntSize_ = u2Buf[0]; + curIndex += sizeof(uint16_t); + + u2Buf = reinterpret_cast(ehdrBuf + curIndex); + shdrNumEnts_ = static_cast(*u2Buf); + curIndex += sizeof(uint16_t); + + u2Buf = reinterpret_cast(ehdrBuf + curIndex); + shdrStrTabIdx_ = u2Buf[0]; + +#ifdef HIPERF_DEBUG_ASSERT + curIndex += sizeof(uint16_t); + HLOG_ASSERT(curIndex == ehdrSize_); + HLOG_ASSERT(shdr64Size == ehdrSize_); +#endif + return true; +} +} // namespace ELF +} // namespace HiPerf +} // namespace Developtools +} // namespace OHOS diff --git a/host/trace_streamer/src/parser/hiperf_parser/hiperf/elf_symbol.cpp b/host/trace_streamer/src/parser/hiperf_parser/hiperf/elf_symbol.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7f2681051fe949d495e7df947ee1841cfee5f85d --- /dev/null +++ b/host/trace_streamer/src/parser/hiperf_parser/hiperf/elf_symbol.cpp @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2021-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. + */ + +#include + +using namespace OHOS::Developtools::HiPerf::ELF; +namespace OHOS { +namespace Developtools { +namespace HiPerf { +std::unique_ptr ElfSymbol::MakeUnique(char * const symBuf, const std::size_t bufSize) +{ + std::unique_ptr sym {new (std::nothrow) ElfSymbol()}; + if (sym == nullptr) { + HLOGE("Error in ElfSymbol::MakeUnique(): ElfSymbol::ElfSymbol() failed"); + return nullptr; + } + if (!sym->Init(symBuf, bufSize)) { + HLOGE("ElfSymbol::Init(symBuf, bufSize) failed"); + DumpSymBuf(symBuf, bufSize); + return nullptr; + } + return sym; +} + +bool ElfSymbol::ParseElf32Symbol(char * const symBuf) +{ + uint32_t *u4Buf = reinterpret_cast(symBuf); + constexpr uint32_t nameOffset {0}; + nameIndex_ = u4Buf[nameOffset]; + constexpr uint32_t valueOffset {1}; + symValue_ = u4Buf[valueOffset]; + constexpr uint32_t sizeOffset {2}; + symSize_ = u4Buf[sizeOffset]; + constexpr uint32_t infoOffset {12}; + symInfo_ = symBuf[infoOffset]; + constexpr uint32_t otherInfoOffset {13}; + symOtherInfo_ = symBuf[otherInfoOffset]; + uint16_t *u2Buf = reinterpret_cast(symBuf); + constexpr uint32_t secOffset {7}; + secIndex_ = u2Buf[secOffset]; + return true; +} + +bool ElfSymbol::ParseElf64Symbol(char * const symBuf) +{ + uint32_t *u4Buf = reinterpret_cast(symBuf); + constexpr uint32_t nameOffset {0}; + nameIndex_ = u4Buf[nameOffset]; + constexpr uint32_t infoOffset {4}; + symInfo_ = symBuf[infoOffset]; + constexpr uint32_t otherInfoOffset {5}; + symOtherInfo_ = symBuf[otherInfoOffset]; + uint16_t *u2Buf = reinterpret_cast(symBuf); + constexpr uint32_t secOffset {3}; + secIndex_ = u2Buf[secOffset]; + uint64_t *u8Buf = reinterpret_cast(symBuf); + constexpr uint32_t valueOffset {1}; + symValue_ = u8Buf[valueOffset]; + constexpr uint32_t sizeOffset {2}; + symSize_ = u8Buf[sizeOffset]; + return true; +} + +std::unique_ptr SymbolTable::MakeUnique(const std::string &symNamesStr, + const char * const secBuf, + const uint64_t secSize, + const uint64_t entrySize) +{ + std::unique_ptr symTable {new (std::nothrow) SymbolTable(symNamesStr)}; + if (symNamesStr.empty()) { + HLOGE("symNamesStr is empty"); + } + if (symTable == nullptr) { + HLOGE("Error in SymbleTable::MakeUnique(): SymbleTable::SymbolTable() failed"); + return nullptr; + } + char *symBuf = const_cast(secBuf); + for (uint64_t curPos = 0; curPos < secSize; curPos += entrySize) { + symBuf = const_cast(secBuf + curPos); + /* + not >= , change to > + Section Headers: + [Nr] Name Type Address Offset + Size EntSize Flags Link Info Align + [ 0] NULL 0000000000000000 00000000 + 0000000000000000 0000000000000000 0 0 0 + [ 1] .text NOBITS 000000009c868f20 00000000 + 0000000000000164 0000000000000000 AX 0 0 4096 + [ 2] .strtab STRTAB 0000000000000000 00000040 + 0000000000000042 0000000000000000 0 0 4096 + [ 3] .symtab SYMTAB 0000000000000000 00000082 + 0000000000000030 0000000000000018 2 1 8 + [ 4] .debug_frame PROGBITS 0000000000000000 000000b2 + 00000000000000c8 0000000000000000 0 0 8 + [ 5] .shstrtab STRTAB 0000000000000000 0000017a + 000000000000002e 0000000000000000 0 0 1 + + Symbol table '.symtab' contains 2 entries: + Num: Value Size Type Bind Vis Ndx Name + 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND + 1: 000000009c868f20 356 FUNC GLOBAL DEFAULT 1 + */ + if ((curPos + entrySize) > secSize) { + break; + } + std::unique_ptr sym = ElfSymbol::MakeUnique(symBuf, entrySize); + if (sym == nullptr) { + HLOGE("Error in SymbolTable::MakeUnique(): ElfSymbol::MakeUnique() failed"); + return nullptr; + } + symTable->symbols_.emplace_back(std::move(sym)); + } + return symTable; +} +} // namespace HiPerf +} // namespace Developtools +} // namespace OHOS diff --git a/host/trace_streamer/src/parser/hiperf_parser/hiperf/hashlist.hpp b/host/trace_streamer/src/parser/hiperf_parser/hiperf/hashlist.hpp new file mode 100644 index 0000000000000000000000000000000000000000..718c434debe7d805491b6f4d51e9e234208814c2 --- /dev/null +++ b/host/trace_streamer/src/parser/hiperf_parser/hiperf/hashlist.hpp @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2021-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. + */ + +#ifndef HIPERF_HASHLIST_HPP +#define HIPERF_HASHLIST_HPP +#include "hashlist.h" + +namespace OHOS { +namespace Developtools { +namespace HiPerf { +} // namespace HiPerf +} // namespace Developtools +} // namespace OHOS +#endif // HIPERF_HASHLIST_HPP diff --git a/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/callstack.h b/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/callstack.h new file mode 100644 index 0000000000000000000000000000000000000000..57eb1690c4dd2d051defb51ac0ca1c5d1907d658 --- /dev/null +++ b/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/callstack.h @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2021 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. + */ +#ifndef HIPERF_CALLSTACK_H +#define HIPERF_CALLSTACK_H + +#if HAVE_LIBUNWIND +// for libunwind.h empty struct has size 0 in c, size 1 in c++ +#define UNW_EMPTY_STRUCT uint8_t unused +#include +#endif + +#include +#include +#include +#include + +#if !is_mingw +#include +#endif + +#include "hashlist.h" +#include "register.h" +#include "utilities.h" +#include "virtual_thread.h" + +namespace OHOS { +namespace Developtools { +namespace HiPerf { +const int MAX_CALL_FRAME_EXPAND_CYCLE = 10; +const size_t MAX_CALL_FRAME_EXPAND_CACHE_SIZE = 10; +const size_t MAX_CALL_FRAME_UNWIND_SIZE = 256; +// if ip is 0 , 1 both not useful +const uint64_t BAD_IP_ADDRESS = 2; + +#if HAVE_LIBUNWIND +struct UnwindInfo; +#endif + +class CallStack { +public: + CallStack(); + ~CallStack(); + bool UnwindCallStack(const VirtualThread &thread, bool abi32, u64 *regs, u64 regsNum, + const u8 *stack, u64 stackSize, std::vector &, + size_t maxStackLevel = MAX_CALL_FRAME_UNWIND_SIZE); + size_t ExpandCallStack(pid_t tid, std::vector &callFrames, size_t expandLimit = 1u); + +private: + uint64_t stackPoint_ = 0; + uint64_t stackEnd_ = 0; + u64 *regs_ = nullptr; // not const , be cause we will fix it for arm64 cpu in UpdateRegForABI + u64 regsNum_ = 0; + const u8 *stack_ = nullptr; + u64 stackSize_ = 0; + + void LogFrame(const std::string msg, const std::vector &frames); + size_t DoExpandCallStack(std::vector &newCallFrames, + const std::vector &cachedCallFrames, size_t expandLimit); + + // we have a cache for all thread + std::map>> cachedCallFramesMap_; + bool GetIpSP(uint64_t &ip, uint64_t &sp, const u64 *regs, size_t regNum) const; + ArchType arch_ = ArchType::UNSUPPORT; +#if HAVE_LIBUNWIND + static bool ReadVirtualThreadMemory(UnwindInfo &unwindInfoPtr, unw_word_t addr, + unw_word_t *data); + static const std::string GetUnwErrorName(int error); + static void dumpUDI(unw_dyn_info_t &di); + static bool fillUDI(unw_dyn_info_t &di, SymbolsFile &symbolsFile, const MemMapItem &mmap, + const VirtualThread &thread); + static int FindProcInfo(unw_addr_space_t as, unw_word_t ip, unw_proc_info_t *pi, + int need_unwind_info, void *arg); + static int AccessMem(unw_addr_space_t as, unw_word_t addr, unw_word_t *valuePoint, + int writeOperation, void *arg); + static int AccessReg(unw_addr_space_t as, unw_regnum_t regnum, unw_word_t *valuePoint, + int writeOperation, void *arg); + static void PutUnwindInfo(unw_addr_space_t as, unw_proc_info_t *pi, void *arg); + static int AccessFpreg(unw_addr_space_t as, unw_regnum_t num, unw_fpreg_t *val, + int writeOperation, void *arg); + static int GetDynInfoListAaddr(unw_addr_space_t as, unw_word_t *dil_vaddr, void *arg); + static int Resume(unw_addr_space_t as, unw_cursor_t *cu, void *arg); + static int getProcName(unw_addr_space_t as, unw_word_t addr, char *bufp, size_t buf_len, + unw_word_t *offp, void *arg); + static int FindUnwindTable(SymbolsFile *symbolsFile, const MemMapItem &mmap, + UnwindInfo *unwindInfoPtr, unw_addr_space_t as, unw_word_t ip, + unw_proc_info_t *pi, int need_unwind_info, void *arg); + void UnwindStep(unw_cursor_t &c, std::vector &callFrames, size_t maxStackLevel); + std::unordered_map unwindAddrSpaceMap_; + + using dsoUnwDynInfoMap = std::unordered_map>; + std::unordered_map unwindDynInfoMap_; + + using unwMemoryCache = std::unordered_map; + std::unordered_map porcessMemoryMap_; + + unw_accessors_t accessors_ = { + .find_proc_info = FindProcInfo, + .put_unwind_info = PutUnwindInfo, + .get_dyn_info_list_addr = GetDynInfoListAaddr, + .access_mem = AccessMem, + .access_reg = AccessReg, + .access_fpreg = AccessFpreg, + .resume = Resume, + .get_proc_name = getProcName, + }; + bool DoUnwind(const VirtualThread &thread, std::vector &callStack, + size_t maxStackLevel); +#endif +}; + +#if HAVE_LIBUNWIND +struct UnwindInfo { + const VirtualThread &thread; + const u64 *regs; + size_t regNumber; + ArchType arch; + CallStack &callStack; +}; +#endif +} // namespace HiPerf +} // namespace Developtools +} // namespace OHOS +#endif // HIPERF_CALLSTACK_H diff --git a/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/debug_logger.h b/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/debug_logger.h new file mode 100644 index 0000000000000000000000000000000000000000..b3e2befece57a8c3af86b21ad9da94435cea29f5 --- /dev/null +++ b/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/debug_logger.h @@ -0,0 +1,336 @@ +/* + * Copyright (c) 2021-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. + * + */ +#ifndef HIPERF_DEBUG_H +#define HIPERF_DEBUG_H + +#include +#include +#include +#include +#include +#include +#include +#include + +#if !is_mingw +#include +#undef gettid +#define gettid() syscall(SYS_gettid) +#else +#include "windows.h" +inline long gettid() +{ + return GetCurrentThreadId(); +} +#endif // !is_mingw + +namespace OHOS { +namespace Developtools { +namespace HiPerf { +enum DebugLevel { + LEVEL_MUCH = 1, + LEVEL_VERBOSE, + LEVEL_DEBUG, + LEVEL_INFO, + LEVEL_WARNING, + LEVEL_ERROR, + LEVEL_FATAL, + LEVEL_STDOUT, // printf + LEVEL_MAX, // max +}; + +#ifdef HIPERF_DEBUG +#if is_ohos || is_double_framework +const std::string DEFAULT_UT_LOG_DIR = "/data/local/tmp/"; +const std::string DEFAULT_LOG_PATH = "/data/local/tmp/hiperf_log.txt"; +#elif is_mingw +const std::string DEFAULT_LOG_PATH = ".\\hiperf_log.txt"; +#elif is_linux +const std::string DEFAULT_UT_LOG_DIR = "./"; +const std::string DEFAULT_LOG_PATH = "hiperf_log.txt"; +#else +#error unkow os +#endif + +#define HILOG_BASE_TAG "HILOG" +#ifndef HILOG_TAG +#define HILOG_TAG "" +#define HILOG_TAG_NAME HILOG_BASE_TAG +#else +#define HILOG_TAG_NAME HILOG_BASE_TAG "_" HILOG_TAG +#endif + +#define SHORT_FILENAME \ + (__builtin_strrchr(__FILE__, '/') ? __builtin_strrchr(__FILE__, '/') + 1 : __FILE__) + +const std::map DebugLevelMap = { + {LEVEL_MUCH, "M"}, {LEVEL_VERBOSE, "V"}, {LEVEL_DEBUG, "D"}, {LEVEL_INFO, "I"}, + {LEVEL_WARNING, "W"}, {LEVEL_ERROR, "E"}, {LEVEL_FATAL, "F"}, +}; +constexpr const int LOG_BUFFER_SIZE = 4 * 1024 * 1024; + +class DebugLogger { +public: + DebugLogger(); + ~DebugLogger(); + + static DebugLogger *GetInstance(); + DebugLevel SetLogLevel(DebugLevel debugLevel); + bool SetMixLogOutput(bool enable); + bool SetLogPath(const std::string &logPath); + void SetLogTags(const std::string &tags); + + int Log(DebugLevel level, const std::string &logTag, const char *fmt, ...) const + __attribute__((format(printf, 4, 5))); + // for class, pointer need add 1 offset (first one is *this) + + bool EnableHiLog(bool = true); + DebugLevel GetLogLevel() const + { + return debugLevel_; + }; + + void Disable(bool disable = true); + static bool logDisabled_; + +#ifdef HIPERF_DEBUG_TIME + mutable size_t logCount_ = 0; + mutable std::chrono::microseconds logTimes_ = std::chrono::microseconds::zero(); + mutable std::chrono::microseconds logWriteTimes_ = std::chrono::microseconds::zero(); + mutable std::chrono::microseconds logSprintfTimes_ = std::chrono::microseconds::zero(); +#endif + + // used in UT + bool OpenLog(const std::string & = "", const std::string & = "w"); + bool RestoreLog(); + void Reset(); + +private: + bool ShouldLog(DebugLevel debugLevel, const std::string &logTag) const; + DebugLevel GetLogLevelByName(const std::string &) const; + DebugLevel GetLogLevelByTag(const std::string &) const; + const std::string GetLogLevelName(DebugLevel) const; + + int HiLog(std::string &buffer) const; + + static std::unique_ptr logInstance_; + + mutable std::recursive_mutex logMutex_; + static DebugLevel debugLevel_; + const std::chrono::steady_clock::time_point timeStamp_; + FILE *file_ = nullptr; + bool mixLogOutput_ = false; // log mix to std + bool enableHilog_ = false; + bool exitOnFatal_ = true; + std::string logPath_; + std::map logTagLevelmap_; + + friend class OptionDebugTest; + friend class DebugLoggerTest; + FRIEND_TEST(DebugLoggerTest, SetLogTags); + FRIEND_TEST(DebugLoggerTest, Disable); +}; + +#ifdef HIPERF_DEBUG_PRINTF +#ifndef printf +#define printf(format, ...) \ + do { \ + std::printf(format, ##__VA_ARGS__); \ + DebugLogger::GetInstance()->Log(LEVEL_STDOUT, HILOG_TAG, format, ##__VA_ARGS__); \ + } while (0) +#endif + +#ifndef perror +#define perror(format, ...) \ + do { \ + std::perror(format); \ + DebugLogger::GetInstance()->Log(LEVEL_STDOUT, HILOG_TAG, format "<%d>\n", \ + ##__VA_ARGS__, errno); \ + } while (0) +#endif +#endif + +class ScopeDebugLevel { +public: + ScopeDebugLevel(DebugLevel level, bool mix = false); + ~ScopeDebugLevel(); + +private: + DebugLevel savedDebugLevel_; + bool savedMixOutput_ = false; // log mix to std +}; +#define TempMixLogLevel(level) ScopeDebugLevel tempLogLevel(level, true) + +#define LOG_LEVEL(LEVEL) LOG_##LEVEL +#define LOG_LEVEL_MUCH "M:" +#define LOG_LEVEL_VERBOSE "V:" +#define LOG_LEVEL_DEBUG "D:" +#define LOG_LEVEL_INFO "I:" +#define LOG_LEVEL_WARNING "W:" +#define LOG_LEVEL_ERROR "E:" +#define LOG_LEVEL_FATAL "F:" + +#ifndef HLOG +#define HLOG(level, format, ...) \ + do { \ + if (__builtin_expect(!DebugLogger::logDisabled_, false)) { \ + DebugLogger::GetInstance()->Log( \ + level, HILOG_TAG, \ + HILOG_TAG_NAME "/" LOG_LEVEL(level) "<%ld>[%s:%d]%s:" format "\n", gettid(), \ + SHORT_FILENAME, __LINE__, __FUNCTION__, ##__VA_ARGS__); \ + } \ + } while (0) +#endif + +// only log first n times +#ifndef HLOGV_FIRST +#define HLOGV_FIRST(first, format, ...) \ + do { \ + static int limit = first; \ + if (limit > 0) { \ + HLOG(LEVEL_VERBOSE, format, ##__VA_ARGS__); \ + if (--limit == 0) { \ + HLOG(LEVEL_VERBOSE, " nexttime log will be suppressed..."); \ + } \ + } \ + } while (0) +#endif + +#ifndef HLOGV_FIRST_LOCAL +#define HLOGV_FIRST_LOCAL(local_limit, format, ...) \ + { \ + if (local_limit != 0) { \ + HLOG(LEVEL_VERBOSE, format, ##__VA_ARGS__); \ + if (local_limit > 0 && --local_limit == 0) { \ + HLOG(LEVEL_VERBOSE, " nexttime log will be suppressed..."); \ + } \ + } \ + } +#endif + +#ifndef HLOGV +#define HLOGV_IF(condition, format, ...) \ + if (condition) { \ + HLOG(LEVEL_VERBOSE, format, ##__VA_ARGS__) \ + } +#define HLOGVVV HLOGV +#endif + +#ifndef HLOGDUMMY +#define HLOGDUMMY(format, ...) while (0) +#endif + +#ifndef HLOGM +#define HLOGM(format, ...) HLOG(LEVEL_MUCH, format, ##__VA_ARGS__) +#define HLOGMMM HLOGM +#endif + +#ifndef HLOGV +#define HLOGV(format, ...) HLOG(LEVEL_VERBOSE, format, ##__VA_ARGS__) +#endif + +#ifndef HLOGD +#define HLOGD(format, ...) HLOG(LEVEL_DEBUG, format, ##__VA_ARGS__) +#define HLOGDDD HLOGM +#endif + +#ifndef HLOGI +#define HLOGI(format, ...) HLOG(LEVEL_INFO, format, ##__VA_ARGS__) +#endif + +#ifndef HLOGW +#define HLOGW(format, ...) HLOG(LEVEL_WARNING, format, ##__VA_ARGS__) +#endif + +#ifndef HLOGE +#define HLOGE(format, ...) HLOG(LEVEL_ERROR, format, ##__VA_ARGS__) +#endif + +#ifndef HLOGEP +#define HLOGEP(format, ...) \ + HLOG(LEVEL_ERROR, format "(errno %d)", ##__VA_ARGS__, errno) +#endif + +#ifndef HLOGF +#define HLOGF(format, ...) \ + HLOG(LEVEL_FATAL, "FATAL error at %s:%d " format, __FILE__, __LINE__, ##__VA_ARGS__) +#endif + +#ifndef HLOG_ASSERT_MESSAGE +#define HLOG_ASSERT_MESSAGE(condition, format, ...) \ + if (!(condition)) { \ + HLOG(LEVEL_FATAL, " assert failed: '%s' " format, #condition, ##__VA_ARGS__); \ + } +#endif + +#ifndef HLOG_ASSERT +#define HLOG_ASSERT(condition) HLOG_ASSERT_MESSAGE(condition, "") +#endif + +#undef assert +#else +#define HLOGDUMMY(...) \ + do { \ + } while (0) +#define HLOGEP(...) \ + do { \ + } while (0) +#define HLOGM(...) \ + do { \ + } while (0) +#define HLOGMMM(...) \ + do { \ + } while (0) +#define HLOGV(...) \ + do { \ + } while (0) +#define HLOGVVV(...) \ + do { \ + } while (0) +#define HLOGD(...) \ + do { \ + } while (0) +#define HLOGDDD(...) \ + do { \ + } while (0) +#define HLOGI(...) \ + do { \ + } while (0) +#define HLOGW(...) \ + do { \ + } while (0) +#define HLOGE(...) \ + do { \ + } while (0) +#define HLOGF(...) \ + do { \ + } while (0) +#define HLOG_ASSERT_MESSAGE(...) \ + do { \ + } while (0) +#define HLOG_ASSERT(...) \ + do { \ + } while (0) + +class ScopeDebugLevel { +public: + ScopeDebugLevel(DebugLevel level, bool mix = false) {} +}; +#endif +} // namespace HiPerf +} // namespace Developtools +} // namespace OHOS +#endif // _HIPERF_DEBUG_H_ diff --git a/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/dwarf_encoding.h b/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/dwarf_encoding.h new file mode 100644 index 0000000000000000000000000000000000000000..0417890bd93fa89471d19e580eb374a63dd70e5c --- /dev/null +++ b/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/dwarf_encoding.h @@ -0,0 +1,193 @@ +/* + * Copyright (c) 2021 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. + */ +#ifndef DWARF_ENCODING_H +#define DWARF_ENCODING_H + +#include "utilities.h" + +// now we only support 64 bit. +using uleb128_t = uint64_t; +using sleb128_t = int64_t; + +namespace OHOS { +namespace Developtools { +namespace HiPerf { +static constexpr const int LEB_BYTE_EFFECTIVE_LENGTH = 7; +static constexpr const int SIGN_BIT_OF_BYTE = 0x40; +static constexpr const int MAX_VALUE_OF_BYTE = 0x7f; +static constexpr const int MORE_BIT_OF_BYTE = 0x80; + +/* +10.5.1. DWARF Exception Header Encoding +The DWARF Exception Header Encoding is used to describe the type of data used in the .eh_frame and +.eh_frame_hdr section. The upper 4 bits indicate how the value is to be applied. The lower 4 bits +indicate the format of the data. +using dw_encode_t = unsigned char; // 4 bits + 4 bits +*/ + +using dw_encode_t = unsigned char; // 4 bits + 4 bits + +// Table 10-5. DWARF Exception Header value format + +enum DW_EH_PE_VF { + DW_EH_PE_absptr = 0x00, // a literal pointer whose size is determined by the architecture. + DW_EH_PE_uleb128 = 0x01, // Unsigned value is encoded using the Little Endian Base 128 (LEB128) + DW_EH_PE_udata2 = 0x02, // A 2 bytes unsigned value. + DW_EH_PE_udata4 = 0x03, // A 4 bytes unsigned value. + DW_EH_PE_udata8 = 0x04, // An 8 bytes unsigned value. + DW_EH_PE_sleb128 = 0x09, // Signed value is encoded using the Little Endian Base 128(LEB128) + DW_EH_PE_sdata2 = 0x0A, // A 2 bytes signed value. + DW_EH_PE_sdata4 = 0x0B, // A 4 bytes signed value. + DW_EH_PE_sdata8 = 0x0C, // An 8 bytes signed value. +}; + +// Table 10-6. DWARF Exception Header application +enum DW_EH_PE_A { + DW_EH_PE_nothing = 0x00, // nothing to do + DW_EH_PE_pcrel = 0x10, // relative to the current program counter. + DW_EH_PE_textrel = 0x20, // relative to the beginning of the .text section. + DW_EH_PE_datarel = 0x30, // relative to the beginning of the .got or .eh_frame_hdr section. + DW_EH_PE_funcrel = 0x40, // relative to the beginning of the function. + DW_EH_PE_aligned = 0x50, // aligned to an address unit sized boundary. + DW_EH_PE_omit = 0xff, // indicate that no value ispresent. +}; + +const std::map DWFormatSizeMap = { +#ifdef ARM + {DW_EH_PE_absptr, 4}, +#else + {DW_EH_PE_absptr, 8}, +#endif +#ifdef NOT_USE + {DW_EH_PE_uleb128, sizeof(char) * 128}, +#endif + {DW_EH_PE_udata2, sizeof(char) * 2}, + {DW_EH_PE_udata4, sizeof(char) * 4}, + {DW_EH_PE_udata8, sizeof(char) * 8}, +#ifdef NOT_USE + {DW_EH_PE_sleb128, sizeof(char) * 128}, +#endif + {DW_EH_PE_sdata2, sizeof(char) * 2}, + {DW_EH_PE_sdata4, sizeof(char) * 4}, + {DW_EH_PE_sdata8, sizeof(char) * 8}, +}; + +template +uint64_t dwReadAnyTypeData(const unsigned char *&buffer, T) +{ + T value; + if (memcpy_s(&value, sizeof(T), buffer, sizeof(T)) != 0) { + return 0; + } + buffer += sizeof(T); + return static_cast(value); +} + +class DwarfEncoding { +public: + DwarfEncoding(dw_encode_t dw, const unsigned char *&data, uint64_t vaddrBase = 0, + uint64_t vaddrPC = 0, uint64_t vaddrText = 0); + + const std::string ToString() const; + + const unsigned char *GetEnd() const; + + const unsigned char *GetData() const; + + size_t GetSize() const; + + uint64_t GetValue() const; + + uint64_t GetAppliedValue() const; + + bool IsOmit() const; + +private: + dw_encode_t dw_; + const unsigned char *data_; + uint64_t vaddrBase_ = 0; + uint64_t vaddrPC_ = 0; + uint64_t vaddrText_ = 0; + uint64_t value_[2] = {0, 0}; + + dw_encode_t Format() const; + + dw_encode_t Application() const; + + uint64_t ReadValue(const unsigned char *&data) const; + + const std::string FormatName() const; + + const std::string ApplicationName() const; +}; + +/* +Linux Standard Base Core Specification 4.1 +Chapter 10. Object Format +10.6.2. The .eh_frame_hdr section + +Table 10-11. .eh_frame_hdr Section Format + +Encoding Field +unsigned byte version +unsigned byte eh_frame_ptr_enc +unsigned byte fde_count_enc +unsigned byte table_enc +encoded eh_frame_ptr +encoded fde_count + binary search table +*/ + +struct binary_search_table { + uint64_t ipVaddrOffset; + uint64_t fdeVaddrOffset; +}; + +struct eh_frame_hdr { + // Version of the .eh_frame_hdr format. This value shall be 1. + dw_encode_t version; + + // The encoding format of the eh_frame_ptr field. + dw_encode_t eh_frame_ptr_enc; + + // The encoding format of the fde_count field. A value of DW_EH_PE_omit indicates the binary + // search table is not present. + dw_encode_t fde_count_enc; + + // The encoding format of the entries in the binary search table. A value of DW_EH_PE_omit + // indicates the binary search table is not present. + dw_encode_t table_enc; + + // The encoded value of the pointer to the start of the .eh_frame section. + /* + dw_encode_t eh_frame_ptr + dw_encode_t fde_count + */ + // A binary search table containing fde_count entries. Each entry of the table consist of two + // encoded values, the initial location, and the address. The entries are sorted in an + // increasing order by the initial location value. + + /* + * struct { + * encoded start_ip + * encoded fde_addr + * } binary_search_table[fde_count] + */ + unsigned char encode_data[0]; +} PACKED; +} // namespace HiPerf +} // namespace Developtools +} // namespace OHOS +#endif // DWARF_ENCODING_H diff --git a/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/elf_parser.h b/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/elf_parser.h new file mode 100644 index 0000000000000000000000000000000000000000..f757d24be57ccc27b57ed9a67589f7f6ec175a71 --- /dev/null +++ b/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/elf_parser.h @@ -0,0 +1,305 @@ +/* + * Copyright (c) 2021 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. + */ + +#ifndef ELF_PARSER_H_ +#define ELF_PARSER_H_ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include "debug_logger.h" +#include "noncopyable.h" +#include "utilities.h" + +#if !is_mingw +#include +#include +#endif + +namespace OHOS { +namespace Developtools { +namespace HiPerf { +namespace ELF { +using namespace std::string_literals; + +constexpr std::size_t ehdr32Size {52}; +constexpr std::size_t ehdr64Size {64}; +constexpr std::size_t shdr32Size {40}; +constexpr std::size_t shdr64Size {64}; +constexpr std::size_t phdr32Size {32}; +constexpr std::size_t phdr64Size {56}; +constexpr std::size_t symEnt32Size {16}; +constexpr std::size_t symEnt64Size {24}; + +class ElfHeader { +public: + static std::unique_ptr MakeUnique(unsigned char * const ehdrBuf, + const std::size_t bufSize); + bool Init(unsigned char * const ehdrBuf, const std::size_t bufSize); + + unsigned char ehdrIdent_[EI_NIDENT]; + uint16_t type_; + uint16_t machine_; + uint16_t ehdrSize_; + uint16_t phdrEntSize_; + uint16_t phdrNumEnts_; + uint16_t shdrEntSize_; + uint16_t shdrNumEnts_; + uint16_t shdrStrTabIdx_; + uint32_t elfVersion_; + uint32_t ehdrFlags_; + uint64_t prgEntryVaddr_; + uint64_t phdrOffset_; + uint64_t shdrOffset_; + +private: + explicit ElfHeader() = default; + bool ParseElf32Header(unsigned char * const ehdrBuf, const std::size_t bufSize); + bool ParseElf64Header(unsigned char * const ehdrBuf, const std::size_t bufSize); + static inline void DumpEhdrBuf(const char * const ehdrBuf, const std::size_t bufSize) + { + const std::string fileName {"ehdr_buffer_dump"}; + std::ofstream ofs {fileName, std::ios::binary}; + if (ofs.is_open()) { + ofs.write(ehdrBuf, bufSize); + } + } +}; + +class ProgramHeader { +public: + static std::unique_ptr MakeUnique(char * const phdrBuf, const size_t bufSize); + inline bool Init(char * const phdrBuf, const size_t bufSize) + { + if (bufSize == phdr32Size and ParsePrgHeader32(phdrBuf)) { + return true; + } + if (bufSize == phdr64Size and ParsePrgHeader64(phdrBuf)) { + return true; + } + HLOGE("parse program header failed, program header buffer dumped"); + return false; + } + + uint32_t type_; + uint32_t flags_; + uint64_t offset_; + uint64_t vaddr_; + uint64_t paddr_; + uint64_t fileSize_; + uint64_t memSize_; + uint64_t secAlign_; + +private: + explicit ProgramHeader() = default; + bool ParsePrgHeader32(char * const phdrBuf); + bool ParsePrgHeader64(char * const phdrBuf); + static inline void DumpPhdrBuf(const char * const phdrBuf, const std::size_t bufSize) + { + const std::string fileName {"phdr_buffer_dump"}; + std::ofstream ofs {fileName, std::ios::binary}; + if (ofs.is_open()) { + ofs.write(phdrBuf, bufSize); + } + } +}; + +class SectionHeader { +public: + static std::unique_ptr MakeUnique(char * const shdrBuf, const size_t bufSize, + const size_t index); + + inline bool Init(char * const shdrBuf, const size_t bufSize, const size_t index) + { + secIndex_ = index; + if (bufSize == shdr32Size and ParseSecHeader32(shdrBuf)) { + return true; + } + if (bufSize == shdr64Size and ParseSecHeader64(shdrBuf)) { + return true; + } + HLOGE("parse section header failed, section header buffer dumped"); + return false; + } + + uint32_t nameIndex_; + uint32_t link_; + uint32_t info_; + uint64_t secFlags_; + uint64_t secVaddr_; + uint64_t fileOffset_; + uint64_t secSize_; + uint64_t secAddrAlign_; + uint64_t secEntrySize_; + uint64_t secType_; + uint32_t secIndex_; + std::string secTypeName_; + +private: + explicit SectionHeader() = default; + bool ParseSecHeader32(char * const shdrBuf); + bool ParseSecHeader64(char * const shdrBuf); + static inline void DumpShdrBuf(const char * const shdrBuf, const std::size_t bufSize) + { + const std::string fileName {"shdr_buffer_dump"}; + std::ofstream ofs {fileName, std::ios::binary}; + if (ofs.is_open()) { + ofs.write(shdrBuf, bufSize); + } + } +}; + +class ElfSymbol { +public: + static std::unique_ptr MakeUnique(char * const symBuf, const std::size_t bufSize); + inline bool Init(char * const symBuf, const std::size_t bufSize) + { + if (bufSize == symEnt32Size and ParseElf32Symbol(symBuf)) { + return true; + } + if (bufSize == symEnt64Size and ParseElf64Symbol(symBuf)) { + return true; + } + HLOGE("parse elf symbol failed, symbol buffer dumped"); + return false; + } + + uint16_t secIndex_; + uint32_t nameIndex_; + uint64_t symValue_; + uint64_t symSize_; + unsigned char symInfo_; + unsigned char symOtherInfo_; + +private: + explicit ElfSymbol() = default; + bool ParseElf32Symbol(char * const symBuf); + bool ParseElf64Symbol(char * const symBuf); + static inline void DumpSymBuf(const char * const symBuf, const std::size_t bufSize) + { + const std::string fileName {"shdr_buffer_dump"}; + std::ofstream ofs {fileName, std::ios::binary}; + if (ofs.is_open()) { + ofs.write(symBuf, bufSize); + } + } +}; + +class SymbolTable { +public: + static std::unique_ptr MakeUnique(const std::string &symNamesStr, + const char * const secBuf, + const uint64_t secSize, + const uint64_t entrySize); + + std::vector> symbols_; + +private: + explicit SymbolTable(const std::string &symNamesStr) : symNamesStr_ {symNamesStr} {} + + const std::string symNamesStr_ {}; +}; + +class ElfFile : public Noncopyable { +public: + virtual ~ElfFile(); + static std::unique_ptr MakeUnique(const std::string &filename); + bool ParseFile(); + bool ParseSymTable(const SectionHeader *shdr); + std::string GetSectionName(const uint32_t startIndex); + + inline bool IsOpened() const + { + return fd_ != -1; + } + + inline const char *GetStrPtr(uint32_t sh_link, uint32_t st_name) + { + for (const auto &shdrsItem : shdrs_) { + if (shdrsItem.second->secIndex_ == sh_link) { + if (mmap_ != MMAP_FAILED) { + char *elfFileBegin = (char *)mmap_; + return elfFileBegin + shdrsItem.second->fileOffset_ + st_name; + } + } + } + HLOGE("string not found sh_link %u st_name %d", sh_link, st_name); + return nullptr; + } + + inline const unsigned char *GetSectionData(uint32_t shIndex) + { + for (const auto &shdrsItem : shdrs_) { + if (shdrsItem.second->secIndex_ == shIndex) { + if (mmap_ != MMAP_FAILED) { + const unsigned char *elfFileBegin = (const unsigned char *)mmap_; + return elfFileBegin + shdrsItem.second->fileOffset_; + } + } + } + HLOGE("string not found shIndex %u ", shIndex); + return nullptr; + } + + using SecHeaderTableType = std::unordered_map>; + using PrgHeaderTableType = std::vector>; + int fd_ {-1}; + std::unique_ptr ehdr_ {nullptr}; + SecHeaderTableType shdrs_ {}; + PrgHeaderTableType phdrs_ {}; + std::string secNamesStr_ {}; + std::string symNamesStr_ {}; + std::unique_ptr symTable_ {nullptr}; + std::unique_ptr dynSymTable_ {nullptr}; + +protected: + // for fuzz test we make a virtual function + virtual ssize_t ReadFile(void *buf, size_t count) + { + return read(fd_, buf, count); + }; + explicit ElfFile(const std::string &filename); + +private: + bool ParseElfHeader(); + bool ParsePrgHeaders(); + bool ParseSecNamesStr(); + bool ParseSecHeaders(); + bool ParseSymNamesStr(); + bool ParseSymTable(const std::string = ".symtab"); + bool ParseDynSymTable(); + + void *mmap_ = MMAP_FAILED; + uint64_t mmapSize_ = 0; +}; +} // namespace ELF +} // namespace HiPerf +} // namespace Developtools +} // namespace OHOS +#endif // ELF_PARSER_H_ diff --git a/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/hashlist.h b/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/hashlist.h new file mode 100644 index 0000000000000000000000000000000000000000..02f81c1eea580e11a224d7d6c7de42f4e883c52d --- /dev/null +++ b/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/hashlist.h @@ -0,0 +1,1146 @@ +/* + * Copyright (c) 2021 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. + */ + +#ifndef HIPERF_HASHLIST_H +#define HIPERF_HASHLIST_H + +#include + +namespace OHOS { +namespace Developtools { +namespace HiPerf { +class Link { +public: + Link() = default; + ~Link() = default; + Link(const Link &link) : prev_ {link.prev_}, next_ {link.next_} {} + Link(Link &&link) : prev_ {link.prev_}, next_ {link.next_} + { + link.prev_ = nullptr; + link.next_ = nullptr; + } + Link &operator=(const Link &link) + { + prev_ = link.prev_; + next_ = link.next_; + return *this; + } + Link &operator=(Link &&link) + { + prev_ = link.prev_; + link.prev_ = nullptr; + next_ = link.next_; + link.next_ = nullptr; + return *this; + } + Link *prev_ {nullptr}; + Link *next_ {nullptr}; +}; + +template +class LinkNode { +public: + Link link_ {}; + Key key_ {}; + Val val_ {}; + + explicit LinkNode() = default; + ~LinkNode() = default; + explicit LinkNode(const Key &key); + explicit LinkNode(const Key &key, const Val &val); + explicit LinkNode(const Key &key, Val &&val); + LinkNode(const LinkNode &node); + LinkNode(LinkNode &&node); + LinkNode &operator=(const LinkNode &node); + LinkNode &operator=(LinkNode &&node); + static LinkNode *GetLinkNode(Val *pval); + static LinkNode *GetLinkNode(Link *plink); +}; + +template +class HashList { +public: + class Iterator { + public: + Iterator() = default; + ~Iterator() = default; + explicit Iterator(LinkNode *pnode, HashList *phashList); + explicit Iterator(const LinkNode *pnode, const HashList *phashList); + Iterator(const Iterator &itr); + Iterator(Iterator &&itr); + Iterator &operator=(const Iterator &itr); + Iterator &operator=(Iterator &&itr); + Iterator &operator++() noexcept; + Iterator operator++(int) noexcept; + Iterator &operator--() noexcept; + Iterator operator--(int) noexcept; + bool operator<(const Iterator &itr) const noexcept; + bool operator==(const Iterator &itr) const noexcept; + Val &operator*(); + const Val &operator*() const; + Val *operator->(); + const Val *operator->() const; + void swap(HashList::Iterator &other); + LinkNode *GetNode() const + { + return pnode_; + } + + private: + bool IsDangled() const noexcept + { + return phashList_ == nullptr; + } + + LinkNode *pnode_ {nullptr}; + HashList *phashList_ {nullptr}; + }; + + class ReverseIterator { + public: + ReverseIterator() = default; + ~ReverseIterator() = default; + explicit ReverseIterator(LinkNode *pnode, HashList *phashList); + explicit ReverseIterator(const LinkNode *pnode, const HashList *phashList); + ReverseIterator(const ReverseIterator &itr); + ReverseIterator(ReverseIterator &&itr); + ReverseIterator &operator=(const ReverseIterator &itr); + ReverseIterator &operator=(ReverseIterator &&itr); + ReverseIterator &operator++() noexcept; + ReverseIterator operator++(int) noexcept; + ReverseIterator &operator--() noexcept; + ReverseIterator operator--(int) noexcept; + bool operator<(const ReverseIterator &itr) const noexcept; + bool operator==(const ReverseIterator &itr) const noexcept; + Val &operator*(); + const Val &operator*() const; + Val *operator->(); + const Val *operator->() const; + void swap(HashList::ReverseIterator &other); + + LinkNode *GetNode() + { + return pnode_; + } + + private: + bool IsDangled() const noexcept + { + return phashList_ == nullptr; + } + + LinkNode *pnode_ {nullptr}; + HashList *phashList_ {nullptr}; + }; + +public: + explicit HashList(const std::size_t numItem = 0); + ~HashList(); + + HashList(const HashList &source) = delete; + HashList &operator=(const HashList &source) = delete; + HashList(HashList &&source); + HashList &operator=(HashList &&source); + + // capacity + inline std::size_t size() const + { + return valueTab_.size(); + } + inline bool empty() const + { + return (dataHead_.next_ == &dataHead_) and (dataHead_.prev_ == &dataHead_); + } + inline std::size_t capacity() const + { + return numItem_; + } + inline bool IsFull() const + { + return freeHead_.next_ == &freeHead_; + } + inline std::size_t count(const Key &key) const + { + return valueTab_.count(key); + } + + int reserve(const std::size_t numItem); + // iterators + Iterator begin(); + const Iterator cbegin() const; + Iterator end(); + const Iterator cend() const; + ReverseIterator rbegin(); + const ReverseIterator crbegin() const; + ReverseIterator rend(); + const ReverseIterator crend() const; + // element access + Val &front(); + const Val &front() const; + Val &back(bool prepend = false); + Val &operator[](const Key &key); + // lookup + Iterator find(const Key &key); + // modifiers + void push_front(const Key &key, const Val &val); + void push_front(const Key &key, Val &&val); + void push_back(const Key &key, const Val &val); + void push_back(const Key &key, Val &&val); + void pop_front(); + void pop_back(); + Iterator erase(const Key &key); + Iterator erase(const Iterator pos); + Iterator erase(const Iterator first, const Iterator last); + +private: + void MoveToHead(LinkNode *&pnode); + void MoveToTail(LinkNode *&pnode); + bool MoveNode(const Iterator &pos, LinkNode *&pnode); + LinkNode *AllocateNode(const Key &key); + LinkNode *AllocateNode(const Key &key, const Val &val); + LinkNode *AllocateNode(const Key &key, Val &&val); + void ReclaimNode(LinkNode *&pnode); + + std::size_t numItem_ {0}; + LinkNode *pData_ {nullptr}; + Link dataHead_ {}; + Link freeHead_ {}; + std::unordered_map *> valueTab_ {}; +}; +// implementation of template class LinkNode +template +LinkNode::LinkNode(const Key &key) : key_ {key} {} + +template +LinkNode::LinkNode(const Key &key, const Val &val) : key_ {key}, val_ {val} {} + +template +LinkNode::LinkNode(const Key &key, Val &&val) : key_ {key}, val_ {std::move(val)} {} + +template +LinkNode::LinkNode(const LinkNode& node) + :link_ {node.link_}, + key_ {node.key_}, + val_ {node.val_} +{} + +template +LinkNode::LinkNode(LinkNode&& node) + :link_ {std::move(node.link_)}, + key_ {std::move(node.key_)}, + val_ {std::move(node.val_)} +{} + +template +auto LinkNode::operator=(const LinkNode& node) +-> LinkNode& +{ + link_ = node.link_; + key_ = node.key_; + val_ = node.val_; +} + +template +auto LinkNode::operator=(LinkNode&& node) +-> LinkNode& +{ + link_ = std::move(node.link_); + key_ = std::move(node.key_); + val_ = std::move(node.val_); +} + +template +auto LinkNode::GetLinkNode(Val *pval) +-> LinkNode* +{ + if (pval) { + LinkNode *pnode {nullptr}; + Val* offset = &pnode->val_; + auto nodeAddr = reinterpret_cast(pval) - reinterpret_cast(offset); + return reinterpret_cast*>(nodeAddr); + } + return nullptr; +} + +template +auto LinkNode::GetLinkNode(Link *plink) +-> LinkNode* +{ + if (plink) { + LinkNode *pnode {nullptr}; + Link* offset = &pnode->link_; + auto nodeAddr = reinterpret_cast(plink) - reinterpret_cast(offset); + return reinterpret_cast*>(nodeAddr); + } + return nullptr; +} +// end of LinkNode + +// implementation of template class Iterator +template +HashList::Iterator::Iterator(LinkNode *pnode, HashList *phashList) + : pnode_ {pnode}, phashList_ {phashList} +{ + if (phashList_ == nullptr) { + pnode_ = nullptr; + } +} + +template +HashList::Iterator::Iterator(const LinkNode* pnode, const HashList* phashList) + : pnode_{const_cast*>(pnode)}, phashList_{const_cast(phashList)} +{ + if (phashList_ == nullptr) { + pnode_ = nullptr; + } +} + +template +HashList::Iterator::Iterator(const Iterator& itr) + : pnode_ {itr.pnode_}, phashList_ {itr.phashList_} +{} + +template +HashList::Iterator::Iterator(Iterator&& itr) + : pnode_ {itr.pnode_}, phashList_ {itr.phashList_} +{ + itr.pnode_ = nullptr; + itr.phashList_ = nullptr; +} + +template +auto HashList::Iterator::operator=(const Iterator& itr) +-> HashList::Iterator& +{ + Iterator temp {itr}; + swap(temp); + return *this; +} + +template +auto HashList::Iterator::operator=(Iterator&& itr) +-> HashList::Iterator& +{ + Iterator temp {std::move(itr)}; + swap(temp); + return *this; +} + +template +auto HashList::Iterator::operator++() noexcept +-> HashList::Iterator & +{ + if (pnode_ == nullptr or phashList_ == nullptr) { + phashList_ = nullptr; + return *this; + } + Link* plink = pnode_->link_.next_; + if (plink == &phashList_->dataHead_) { + pnode_ = nullptr; + return *this; + } + auto pnode = LinkNode::GetLinkNode(plink); + pnode_ = pnode; + return *this; +} + +template +auto HashList::Iterator::operator++(int) noexcept +-> HashList::Iterator +{ + Iterator res {*this}; + if (pnode_ == nullptr or phashList_ == nullptr) { + phashList_ = nullptr; + return res; + } + Link* plink = pnode_->link_.next_; + if (plink == &phashList_->dataHead_) { + pnode_ = nullptr; + return res; + } + auto pnode = LinkNode::GetLinkNode(plink); + pnode_ = pnode; + return res; +} + +template +auto HashList::Iterator::operator--() noexcept +-> HashList::Iterator & +{ + if (phashList_ == nullptr) { + return *this; + } + Link* plink {nullptr}; + if (pnode_ == nullptr) { + plink = phashList_->dataHead_.prev_; + } else { + plink = pnode_->link_.prev_; + } + if (plink == &phashList_->dataHead_) { + pnode_ = nullptr; + phashList_ = nullptr; + return *this; + } + pnode_ = LinkNode::GetLinkNode(plink); + return *this; +} + +template +auto HashList::Iterator::operator--(int) noexcept +-> HashList::Iterator +{ + Iterator res {*this}; + if (phashList_ == nullptr) { + return res; + } + Link* plink {nullptr}; + if (pnode_ == nullptr) { + plink = phashList_->dataHead_.prev_; + } else { + plink = pnode_->link_.prev_; + } + if (plink == &phashList_->dataHead_) { + pnode_ = nullptr; + phashList_ = nullptr; + return res; + } + pnode_ = LinkNode::GetLinkNode(plink); + return res; +} + +template +bool HashList::Iterator::operator<(const HashList::Iterator &itr) const noexcept +{ + if (IsDangled() or itr.IsDangled()) { + return false; + } + if (phashList_ != itr.phashList_) { + return false; + } + Iterator tempItr {*this}; + if (tempItr == itr) { + return false; + } + while (!tempItr.IsDangled()) { + tempItr++; + if (tempItr == itr) { + return true; + } + } + return false; +} + +template +bool HashList::Iterator::operator==(const HashList::Iterator &itr) const noexcept +{ + if (IsDangled() or itr.IsDangled()) { + return false; + } + if (phashList_ != itr.phashList_) { + return false; + } + return pnode_ == itr.pnode_; +} + +template +Val& HashList::Iterator::operator*() +{ + return pnode_->val_; +} + +template +const Val& HashList::Iterator::operator*() const +{ + return pnode_->val_; +} + +template +Val* HashList::Iterator::operator->() +{ + return &pnode_->val_; +} + +template +const Val* HashList::Iterator::operator->() const +{ + return &pnode_->val_; +} + +template +void HashList::Iterator::swap(HashList::Iterator& other) +{ + using std::swap; + swap(pnode_, other.pnode_); + swap(phashList_, other.phashList_); +} +// end of Iterator + +// Implementation of ReverseIterator +template +HashList::ReverseIterator::ReverseIterator(LinkNode *pnode, HashList *phashList) + : pnode_ {pnode}, phashList_ {phashList} +{ + if (phashList_ == nullptr) { + pnode_ = nullptr; + } +} + +template +HashList::ReverseIterator::ReverseIterator(const LinkNode *pnode, const HashList *phashList) + : pnode_ {const_cast *>(pnode)}, + phashList_ {const_cast(phashList)} +{ + if (phashList_ == nullptr) { + pnode_ = nullptr; + } +} + +template +HashList::ReverseIterator::ReverseIterator(const ReverseIterator &itr) + : pnode_ {itr.pnode_}, phashList_ {itr.phashList_} +{} + +template +HashList::ReverseIterator::ReverseIterator(ReverseIterator &&itr) + : pnode_ {itr.pnode_}, phashList_ {itr.phashList_} +{ + itr.pnode_ = nullptr; + itr.phashList_ = nullptr; +} + +template +auto HashList::ReverseIterator::operator=(const ReverseIterator& itr) +-> HashList::ReverseIterator& +{ + ReverseIterator temp {itr}; + swap(temp); + return *this; +} + +template +auto HashList::ReverseIterator::operator=(ReverseIterator&& itr) +-> HashList::ReverseIterator& +{ + ReverseIterator temp {std::move(itr)}; + swap(temp); + return *this; +} + +template +auto HashList::ReverseIterator::operator++() noexcept +-> HashList::ReverseIterator & +{ + if (pnode_ == nullptr or phashList_ == nullptr) { + phashList_ = nullptr; + return *this; + } + Link* plink = &pnode_->link_; + plink = plink->prev_; + if (plink == &phashList_->dataHead_) { + pnode_ = nullptr; + return *this; + } + pnode_ = LinkNode::GetLinkNode(plink); + return *this; +} + +template +auto HashList::ReverseIterator::operator++(int) noexcept +-> HashList::ReverseIterator +{ + ReverseIterator res {*this}; + if (pnode_ == nullptr or phashList_ == nullptr) { + phashList_ = nullptr; + return res; + } + Link* plink = &pnode_->link_; + plink = plink->prev_; + if (plink == &phashList_->dataHead_) { + pnode_ = nullptr; + return res; + } + pnode_ = LinkNode::GetLinkNode(plink); + return res; +} + +template +auto HashList::ReverseIterator::operator--() noexcept +-> HashList::ReverseIterator & +{ + if (phashList_ == nullptr) { + return *this; + } + Link* plink {nullptr}; + if (pnode_ == nullptr) { + plink = phashList_->dataHead_.next_; + } else { + plink = pnode_->link_.next_; + } + if (plink == &phashList_->dataHead_) { + pnode_ = nullptr; + phashList_ = nullptr; + return *this; + } + pnode_ = LinkNode::GetLinkNode(plink); + return *this; +} + +template +auto HashList::ReverseIterator::operator--(int) noexcept +-> HashList::ReverseIterator +{ + ReverseIterator res {*this}; + if (phashList_ == nullptr) { + return res; + } + Link* plink {nullptr}; + if (pnode_ == nullptr) { + plink = phashList_->dataHead_.next_; + } else { + plink = pnode_->link_.next_; + } + if (plink == &phashList_->dataHead_) { + pnode_ = nullptr; + phashList_ = nullptr; + return res; + } + pnode_ = LinkNode::GetLinkNode(plink); + return res; +} + +template +bool HashList::ReverseIterator::operator<( + const HashList::ReverseIterator &itr) const noexcept +{ + if (IsDangled() or itr.IsDangled()) { + return false; + } + if (phashList_ != itr.phashList_) { + return false; + } + HashList::ReverseIterator tempItr {*this}; + if (tempItr == itr) { + return false; + } + while (!tempItr.IsDangled()) { + tempItr++; + if (tempItr == itr) { + return true; + } + } + return false; +} + +template +bool HashList::ReverseIterator::operator==( + const HashList::ReverseIterator &itr) const noexcept +{ + if (IsDangled() or itr.IsDangled()) { + return false; + } + if (phashList_ != itr.phashList_) { + return false; + } + return pnode_ == itr.pnode_; +} + +template +Val& HashList::ReverseIterator::operator*() +{ + return pnode_->val_; +} + +template +const Val& HashList::ReverseIterator::operator*() const +{ + return pnode_->val_; +} + +template +Val* HashList::ReverseIterator::operator->() +{ + return &pnode_->val_; +} + +template +const Val* HashList::ReverseIterator::operator->() const +{ + return &pnode_->val_; +} + +template +void HashList::ReverseIterator::swap(HashList::ReverseIterator& other) +{ + using std::swap; + swap(pnode_, other.pnode_); + swap(phashList_, other.phashList_); +} +// end of ReverseIterator + +// implementation of template class HashList +template +HashList::HashList(const std::size_t numItem) : numItem_ {numItem} +{ + dataHead_.next_ = &dataHead_; + dataHead_.prev_ = &dataHead_; + if (numItem_) { + valueTab_.reserve(numItem_); + pData_ = new(std::nothrow) LinkNode[numItem_]; + if (pData_) { + freeHead_.next_ = &(pData_[0].link_); + std::size_t last {numItem_ - 1}; + for (std::size_t index = 0; index < last;) { + LinkNode &curNnode = pData_[index]; + curNnode.link_.next_ = &(pData_[++index].link_); + } + pData_[last].link_.next_ = &freeHead_; + } else { + numItem_ = 0; + freeHead_.next_ = &freeHead_; + freeHead_.prev_ = &freeHead_; + } + } +} + +template +int HashList::reserve(const std::size_t numItem) +{ + if (numItem_ != 0) { + return -1; + } + if (numItem) { + numItem_ = numItem; + valueTab_.reserve(numItem_); + pData_ = new(std::nothrow) LinkNode[numItem_]; + dataHead_.next_ = &dataHead_; + dataHead_.prev_ = &dataHead_; + if (pData_) { + freeHead_.next_ = &(pData_[0].link_); + std::size_t last {numItem_ - 1}; + for (std::size_t index = 0; index < last;) { + LinkNode &curNnode = pData_[index]; + curNnode.link_.next_ = &(pData_[++index].link_); + } + pData_[last].link_.next_ = &freeHead_; + } else { + numItem_ = 0; + freeHead_.next_ = &freeHead_; + freeHead_.prev_ = &freeHead_; + } + } + return numItem_; +} + +template +HashList::~HashList() +{ + if (pData_) { + delete[] pData_; + pData_ = nullptr; + } + valueTab_.clear(); + dataHead_.next_ = &dataHead_; + dataHead_.prev_ = &dataHead_; + freeHead_.next_ = nullptr; + freeHead_.prev_ = nullptr; + numItem_ = 0; +} + +template +HashList::HashList(HashList &&source) + : numItem_ {source.numItem_}, + pData_ {source.pData_}, + dataHead_ {std::move(source.dataHead_)}, + freeHead_ {std::move(source.freeHead_)}, + valueTab_ {std::move(source.valueTab_)} +{ + source.pData_ = nullptr; +} + +template +auto HashList::operator=(HashList &&source) +-> HashList& +{ + if (this == &source) { + return *this; + } + if (pData_) { + delete[] pData_; + pData_ = nullptr; + } + numItem_ = source.numItem_; + pData_ = source.pData_; + source.pData_ = nullptr; + dataHead_ = std::move(source.dataHead_); + freeHead_ = std::move(source.freeHead_); + valueTab_ = std::move(source.valueTab_); + return *this; +} + +template +auto HashList::begin() +-> HashList::Iterator +{ + if (empty()) { + return end(); + } + return Iterator(LinkNode::GetLinkNode(dataHead_.next_), this); +} + +template +auto HashList::cbegin() const +-> const HashList::Iterator +{ + if (empty()) { + return cend(); + } + return Iterator(LinkNode::GetLinkNode(dataHead_.next_), this); +} + +template +auto HashList::end() +-> HashList::Iterator +{ + return Iterator(nullptr, this); +} + +template +auto HashList::cend() const +-> const HashList::Iterator +{ + return Iterator(nullptr, this); +} + +template +auto HashList::rbegin() +-> HashList::ReverseIterator +{ + if (empty()) { + return rend(); + } + return ReverseIterator(LinkNode::GetLinkNode(dataHead_.prev_), this); +} + +template +auto HashList::crbegin() const +-> const HashList::ReverseIterator +{ + if (empty()) { + return crend(); + } + return ReverseIterator(LinkNode::GetLinkNode(dataHead_.prev_), this); +} + +template +auto HashList::rend() +-> HashList::ReverseIterator +{ + return ReverseIterator(nullptr, this); +} + +template +auto HashList::crend() const +-> const HashList::ReverseIterator +{ + return ReverseIterator(nullptr, this); +} + +template +Val& HashList::front() +{ + LinkNode *pnode = LinkNode::GetLinkNode(dataHead_.next_); + return pnode->val_; +} + +template +const Val& HashList::front() const +{ + return front(); +} + +template +Val& HashList::back(bool prepend) +{ + auto pnode = LinkNode::GetLinkNode(dataHead_.prev_); + if (prepend) { + MoveToHead(pnode); + } + return pnode->val_; +} + +template +Val& HashList::operator[](const Key &key) +{ + LinkNode *pnode {nullptr}; + if (valueTab_.find(key) == valueTab_.end()) { + pnode = AllocateNode(key); + valueTab_[key] = pnode; + } else { + pnode = valueTab_[key]; + } + if (pnode) { + MoveToHead(pnode); + } + return pnode->val_; +} + +template +auto HashList::find(const Key &key) +-> HashList::Iterator +{ + const auto &itr = valueTab_.find(key); + if (itr == valueTab_.end()) { + return end(); + } + return Iterator(itr->second, this); +} + +template +void HashList::push_front(const Key& key, const Val& val) +{ + if (valueTab_.find(key) == valueTab_.end()) { + LinkNode* pnode = AllocateNode(key, val); + MoveToHead(pnode); + valueTab_[pnode->key_] = pnode; + } else { + MoveToHead(valueTab_[key]); + this->operator[](key) = val; + } +} + +template +void HashList::push_front(const Key& key, Val&& val) +{ + if (valueTab_.find(key) == valueTab_.end()) { + LinkNode* pnode = AllocateNode(key, std::move(val)); + MoveToHead(pnode); + valueTab_[pnode->key_] = pnode; + } else { + MoveToHead(valueTab_[key]); + this->operator[](key) = val; + } +} + +template +void HashList::push_back(const Key& key, const Val& val) +{ + if (valueTab_.find(key) == valueTab_.end()) { + LinkNode* pnode = AllocateNode(key, val); + MoveToTail(pnode); + valueTab_[pnode->key_] = pnode; + } else { + MoveToTail(valueTab_[key]); + this->operator[](key) = val; + } +} + +template +void HashList::push_back(const Key& key, Val&& val) +{ + if (valueTab_.find(key) == valueTab_.end()) { + LinkNode* pnode = AllocateNode(key, std::move(val)); + MoveToTail(pnode); + valueTab_[pnode->key_] = pnode; + } else { + MoveToTail(valueTab_[key]); + this->operator[](key) = val; + } +} + +template +void HashList::pop_front() +{ + if (empty()) { + return; + } + LinkNode* pnode = LinkNode::GetLinkNode(dataHead_.next_); + valueTab_.erase(pnode->key_); + ReclaimNode(pnode); +} + +template +void HashList::pop_back() +{ + if (empty()) { + return; + } + LinkNode* pnode = LinkNode::GetLinkNode(dataHead_.prev_); + valueTab_.erase(pnode->key_); + ReclaimNode(pnode); +} + +template +auto HashList::erase(const Key& key) +-> HashList::Iterator +{ + if (valueTab_.find(key) == valueTab_.end()) { + return end(); + } + LinkNode *pnode = valueTab_[key]; + valueTab_.erase(key); + Link* plink = pnode->link_.next_; + Iterator tempItr {LinkNode::GetLinkNode(plink), this}; + ReclaimNode(pnode); + return tempItr; +} + +template +auto HashList::erase(const Iterator pos) +-> HashList::Iterator +{ + // assume pos is valid, otherwise the result is undefined + Iterator tempItr {pos}; + ++tempItr; + LinkNode *pnode = pos.GetNode(); + valueTab_.erase(pnode->key_); + ReclaimNode(pnode); + return tempItr; +} + +template +auto HashList::erase(const Iterator first, const Iterator last) +-> HashList::Iterator +{ + // assume pos is valid, otherwise the result is undefined + if (first <= last) { + Iterator curPos {first}; + while (curPos < last) { + curPos = erase(curPos); + } + return last; + } + return end(); +} + +template +bool HashList::MoveNode(const Iterator& pos, LinkNode *&pnode) +{ + LinkNode *curNode = pos.GetNode(); + if (curNode == pnode) { + return true; + } + if (pnode->link_.next_ == &curNode->link_) { + return true; + } + Link* prevLink = pnode->link_.prev_; + Link* nextLink = pnode->link_.next_; + if (prevLink and nextLink) { + prevLink->next_ = nextLink; + nextLink->prev_ = prevLink; + } + Link *currLink = &curNode->link_; + prevLink = currLink->prev_; + nextLink = &pnode->link_; + prevLink->next_ = nextLink; + nextLink->prev_ = prevLink; + nextLink->next_ = currLink; + currLink->prev_ = nextLink; + return true; +} + +template +void HashList::MoveToHead(LinkNode *&pnode) +{ + if (pnode->link_.prev_ and pnode->link_.next_) { + Link* prev = pnode->link_.prev_; + Link* next = pnode->link_.next_; + prev->next_ = next; + next->prev_ = prev; + } + pnode->link_.next_ = dataHead_.next_; + dataHead_.next_->prev_ = &pnode->link_; + dataHead_.next_ = &pnode->link_; + pnode->link_.prev_ = &dataHead_; +} + +template +void HashList::MoveToTail(LinkNode *&pnode) +{ + if (pnode->link_.prev_ and pnode->link_.next_) { + Link* prev = pnode->link_.prev_; + Link* next = pnode->link_.next_; + prev->next_ = next; + next->prev_ = prev; + } + pnode->link_.prev_ = dataHead_.prev_; + dataHead_.prev_->next_ = &pnode->link_; + pnode->link_.next_ = &dataHead_; + dataHead_.prev_ = &pnode->link_; +} + +template +auto HashList::AllocateNode(const Key &key) +->LinkNode * +{ + if (IsFull()) { + pop_back(); + } + LinkNode * pnode = LinkNode::GetLinkNode(freeHead_.next_); + freeHead_.next_ = freeHead_.next_->next_; + pnode->link_.next_ = nullptr; + pnode->link_.prev_ = nullptr; + pnode->key_ = key; + pnode->val_ = Val(); + return pnode; +} + +template +auto HashList::AllocateNode(const Key &key, const Val &val) +->LinkNode * +{ + if (IsFull()) { + pop_back(); + } + LinkNode *pnode = LinkNode::GetLinkNode(freeHead_.next_); + freeHead_.next_ = freeHead_.next_->next_; + pnode->link_.next_ = nullptr; + pnode->link_.prev_ = nullptr; + pnode->key_ = key; + pnode->val_ = val; + return pnode; +} + +template +auto HashList::AllocateNode(const Key &key, Val &&val) +->LinkNode * +{ + if (IsFull()) { + pop_back(); + } + LinkNode * pnode = LinkNode::GetLinkNode(freeHead_.next_); + freeHead_.next_ = freeHead_.next_->next_; + pnode->link_.next_ = nullptr; + pnode->link_.prev_ = nullptr; + pnode->key_ = key; + pnode->val_ = std::move(val); + return pnode; +} + +template +void HashList::ReclaimNode(LinkNode *&pnode) +{ + Link *prevLink = pnode->link_.prev_; + Link *nextLink = pnode->link_.next_; + prevLink->next_ = nextLink; + nextLink->prev_ = prevLink; + pnode->link_.prev_ = nullptr; + pnode->link_.next_ = freeHead_.next_; + freeHead_.next_ = &pnode->link_; + return; +} +} // namespace HiPerf +} // namespace Developtools +} // namespace OHOS +#endif // HIPERF_HASHLIST_H diff --git a/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/mem_map_item.h b/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/mem_map_item.h new file mode 100644 index 0000000000000000000000000000000000000000..c0501a1927662c4982dced003bbf3528dc1a6771 --- /dev/null +++ b/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/mem_map_item.h @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2021 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. + */ + +#ifndef MEMMAPITEM_H +#define MEMMAPITEM_H + +#include + +#include +#include + +namespace OHOS { +namespace Developtools { +namespace HiPerf { +class MemMapItem { +public: + uint64_t begin_ = 0; + uint64_t end_ = 0; + uint16_t type_ = 0; // rwx : PROT_READ | PROT_WRITE | PROT_EXEC + uint16_t flags = 0; // ps : MAP_PRIVATE | MAP_SHARED + uint64_t pageoffset_ = 0; + uint64_t major_ = 0; + uint64_t minor_ = 0; + ino_t inode = 0; + std::string name_; + std::string_view nameHold_; + + MemMapItem() {} + MemMapItem(uint64_t begin, uint64_t end, uint64_t offset, const std::string &name) + : begin_(begin), + end_(end), + pageoffset_(offset), + name_(name), + nameHold_(MemoryHold::Get().HoldStringView(name)) + { + } + + // use for find + inline bool operator==(const std::string &name) const + { + return name_ == name; + } + + inline bool operator<(const MemMapItem &other) const + { + return end_ < other.end_; + } + + uint64_t FileOffsetFromAddr(uint64_t addr) const + { + // real vaddr - real map begin = addr offset in section + // section offset + page off set = file offset + return addr - begin_ + pageoffset_; + } + // debug only + const std::string ToString() const + { + std::stringstream sstream; + sstream << "0x" << std::hex << begin_; + sstream << "-0x" << std::hex << end_; + sstream << " type 0x" << std::hex << type_; + sstream << " flags 0x" << std::hex << flags; + sstream << " pageoffset 0x" << std::hex << pageoffset_; + sstream << " " << name_; + return sstream.str(); + } + static bool GreaterSort(const MemMapItem &a, const MemMapItem &b) + { + return (a.begin_ > b.begin_); + } + static bool LessSort(const MemMapItem &a, const MemMapItem &b) + { + return (a.begin_ < b.begin_); + } + // The range [first, last) must be partitioned with respect to the expression !(value < element) + // or !comp(value, element) + static bool ValueLessThan(uint64_t vaddr, const MemMapItem &a) + { + return vaddr <= a.begin_; + } + bool Contain(uint64_t addr) const + { + return addr >= begin_ and addr < end_; + } +}; +} // namespace HiPerf +} // namespace Developtools +} // namespace OHOS +#endif // MEMMAPITEM_H diff --git a/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/noncopyable.h b/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/noncopyable.h new file mode 100644 index 0000000000000000000000000000000000000000..846fbd8c4156ca32dc5e2cafe6150aba7c8740aa --- /dev/null +++ b/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/noncopyable.h @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2021 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. + */ +#ifndef NONCOPYABLE_H_ +#define NONCOPYABLE_H_ +class Noncopyable { +public: + Noncopyable() = default; + ~Noncopyable() = default; + +private: + Noncopyable(const Noncopyable &); + const Noncopyable &operator=(const Noncopyable &); +}; +#endif // NONCOPYABLE_H_ diff --git a/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/option.h b/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/option.h new file mode 100644 index 0000000000000000000000000000000000000000..ad67aec1a63c81fac01d9b89c114cbe1b493870e --- /dev/null +++ b/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/option.h @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2021-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. + */ +#ifndef HIPERF_OPTION_H_ +#define HIPERF_OPTION_H_ + +#include +#include +#include +#include +#include + +#include "debug_logger.h" +#include "utilities.h" + +using argsVector = std::vector; +namespace OHOS { +namespace Developtools { +namespace HiPerf { +namespace Option { +struct MainOption { + std::string help; + std::function &)> callBackFunction; +}; + +// called from main +bool RegisterMainOption(const std::string &, const std::string &, + std::function &)>); + +void ClearMainOptions(); + +bool CheckOptionFormat(const std::string &optionName); + +argsVector::iterator FindOption(argsVector &args, const std::string &optionName); + +// some option function +bool GetValueFromString(const std::string &optionValue, const std::string &optionName, bool &value); +bool GetValueFromString(const std::string &optionValue, const std::string &optionName, int &); +bool GetValueFromString(const std::string &optionValue, const std::string &optionName, + float &value); +bool GetValueFromString(const std::string &optionValue, const std::string &optionName, + std::string &value); +bool GetValueFromString(const std::string &optionValue, const std::string &optionName, + std::vector &value); +bool GetValueFromString(const std::string &optionValue, const std::string &optionName, + std::vector &value); + +bool GetOptionTrackedCommand(argsVector &args, std::vector &trackedCommand); + +/* +Return false to indicate that the parameter is illegal +The program should exit with an error. + +Return true, indicating that the parameter is legal (but the user does not necessarily enter the +parameter) +*/ +template +bool GetOptionValue(argsVector &args, std::string optionName, T &value) +{ + // we need keep the ref if we got failed + // so we use a local value first. + T localValues = {}; + if constexpr (std::is_same>>::value) { + // try unitl failed. + while (true) { + if (!GetOptionValue(args, optionName, localValues.emplace_back())) { + printf("incorrect option %s\n", optionName.c_str()); + return false; // format error + } else if (localValues.back().size() == 0) { + // if the last one we request is empty , we remove it + localValues.pop_back(); + // nothing more needed + // we don't allow empty value + break; + } + } + if (localValues.size() > 0) { + value = localValues; + } + return true; + } else { + if (!CheckOptionFormat(optionName)) { + if (optionName.empty()) { + printf("unable to use empty option name!\n"); + } else { + printf("format error. must use '-' at the begin of option '%s'!\n", + optionName.c_str()); + } + return false; // something wrong + } + auto it = FindOption(args, optionName); + if (it == args.end()) { + HLOGV("not found option, return default value"); + return true; // not found but also not error + } else { + it = args.erase(it); + // some special case + if constexpr (std::is_same::value) { + // for bool we don't need get value. + // this always return true + GetValueFromString(optionName, optionName, value); + return true; + } else if (it == args.end()) { + // no value means failed + printf("option %s value missed\n", optionName.c_str()); + return false; + } else if (GetValueFromString(*it, optionName, localValues)) { + // got some value + value = localValues; + args.erase(it); + return true; + } else { + // have value but convert failed. + printf("incorrect option value '%s'. View the usage with the --help option.\n", + (*it).c_str()); + return false; + } + } + } +} + +const MainOption *FindMainOption(std::string); + +const std::map> &GetMainOptions(); +} // namespace Option +} // namespace HiPerf +} // namespace Developtools +} // namespace OHOS +#endif // HIPERF_OPTION_H_ diff --git a/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/perf_event_record.h b/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/perf_event_record.h new file mode 100644 index 0000000000000000000000000000000000000000..8663ce9cc1942d16c528ec71274b17e9cd713941 --- /dev/null +++ b/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/perf_event_record.h @@ -0,0 +1,436 @@ +/* + * Copyright (c) 2021-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. + */ +#ifndef HIPERF_PERF_EVENT_RECORD_H +#define HIPERF_PERF_EVENT_RECORD_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "debug_logger.h" +#include "mem_map_item.h" +#include "perf_record_format.h" +#include "utilities.h" + +namespace OHOS { +namespace Developtools { +namespace HiPerf { +static constexpr uint32_t RECORD_SIZE_LIMIT = 65535; + +enum perf_event_hiperf_ext_type { + PERF_RECORD_HIPERF_CALLSTACK = UINT32_MAX / 2, +}; + +struct CallFrame { + uint64_t ip_ = 0; + uint64_t sp_ = 0; + + uint64_t vaddrInFile_ = 0; // in symbol file vaddr + int32_t symbolIndex_ = -1; // symbols index , should update after sort + std::string_view symbolName_; + std::string_view filePath_; // lib path , elf path + + CallFrame(uint64_t ip, uint64_t sp = 0) : ip_(ip), sp_(sp) {} + + // this is for ut test + CallFrame(uint64_t ip, uint64_t vaddrInFile, const char *name, const char *filePath) + : ip_(ip), vaddrInFile_(vaddrInFile), symbolName_(name), filePath_(filePath) + { + } + bool operator==(const CallFrame &b) const + { + return (ip_ == b.ip_) && (sp_ == b.sp_); + } + bool operator!=(const CallFrame &b) const + { + return (ip_ != b.ip_) || (sp_ != b.sp_); + } + std::string ToString() const + { + return StringPrintf("ip: 0x%016llx sp: 0x%016llx", ip_, sp_); + } + std::string ToSymbolString() const + { + std::string output; + if (vaddrInFile_ != 0) { + output = StringPrintf("va: 0x%016llx(%llx) ", vaddrInFile_, ip_); + } else { + output = StringPrintf("ip: 0x%016llx ", ip_); + } + output.append(": "); + output.append(symbolName_); + + output.append("@"); + output.append(filePath_); + if (symbolIndex_ != -1) { + output.append(":"); + output.append(std::to_string(symbolIndex_)); + } + return output; + } +}; + +struct AttrWithId { + perf_event_attr attr; + std::vector ids; + std::string name; // will be empty in GetAttrSection +}; + +class PerfEventRecord { +public: + PerfEventRecord(const PerfEventRecord &) = delete; + PerfEventRecord &operator=(const PerfEventRecord &) = delete; + + struct perf_event_header header; + const std::string name_ {}; + + PerfEventRecord(perf_event_type type, bool in_kernel, const std::string &name); + PerfEventRecord(perf_event_hiperf_ext_type type, const std::string &name); + + PerfEventRecord(uint8_t *p, const std::string &name); + + virtual ~PerfEventRecord() {} + + virtual size_t GetSize() const + { + return header.size; + }; + size_t GetHeaderSize() const + { + return sizeof(header); + }; + void GetHeaderBinary(std::vector &buf) const; + + uint32_t GetType() const + { + return header.type; + }; + uint16_t GetMisc() const + { + return header.misc; + }; + bool inKernel() + { + return header.misc & PERF_RECORD_MISC_KERNEL; + } + bool inUser() + { + return header.misc & PERF_RECORD_MISC_USER; + } + const std::string &GetName() const + { + return name_; + }; + + // to support --exclude-hiperf, return sample_id.pid to filter record, + virtual pid_t GetPid() const + { + return 0; + }; + + virtual bool GetBinary(std::vector &buf) const = 0; + void Dump(int indent = 0) const; + virtual void DumpData(int indent) const = 0; + virtual void DumpLog(const std::string &prefix) const; +}; + +// define convert from linux/perf_event.h +// description from https://man7.org/linux/man-pages/man2/perf_event_open.2.html + +constexpr __u64 SAMPLE_ID = PERF_SAMPLE_TID | PERF_SAMPLE_TIME | PERF_SAMPLE_ID | + PERF_SAMPLE_STREAM_ID | PERF_SAMPLE_CPU | PERF_SAMPLE_IDENTIFIER; + +constexpr __u64 SAMPLE_TYPE = PERF_SAMPLE_IP | SAMPLE_ID | PERF_SAMPLE_PERIOD; + +constexpr __u32 MIN_SAMPLE_STACK_SIZE = 8; +constexpr __u32 MAX_SAMPLE_STACK_SIZE = 65528; + +class PerfRecordMmap : public PerfEventRecord { +public: + PerfRecordMmapData data_; + + explicit PerfRecordMmap(uint8_t *p); + + PerfRecordMmap(bool inKernel, u32 pid, u32 tid, u64 addr, u64 len, u64 pgoff, + const std::string &filename); + + bool GetBinary(std::vector &buf) const override; + void DumpData(int indent) const override; + void DumpLog(const std::string &prefix) const override; +}; + +class PerfRecordMmap2 : public PerfEventRecord { +public: + PerfRecordMmap2Data data_; + + explicit PerfRecordMmap2(uint8_t *p); + + PerfRecordMmap2(bool inKernel, u32 pid, u32 tid, u64 addr, u64 len, u64 pgoff, u32 maj, u32 min, + u64 ino, u32 prot, u32 flags, const std::string &filename); + + PerfRecordMmap2(bool inKernel, u32 pid, u32 tid, const MemMapItem &item); + + bool GetBinary(std::vector &buf) const override; + void DumpData(int indent) const override; + void DumpLog(const std::string &prefix) const override; +}; + +class PerfRecordLost : public PerfEventRecord { +public: + PerfRecordLostData data_; + + explicit PerfRecordLost(uint8_t *p); + + bool GetBinary(std::vector &buf) const override; + void DumpData(int indent) const override; + + // only for UT + PerfRecordLost(bool inKernel, u64 id, u64 lost) + : PerfEventRecord(PERF_RECORD_LOST, inKernel, "lost") + { + data_.id = id; + data_.lost = lost; + header.size = sizeof(header) + sizeof(data_); + } +}; + +class PerfRecordComm : public PerfEventRecord { +public: + PerfRecordCommData data_; + + explicit PerfRecordComm(uint8_t *p); + + PerfRecordComm(bool inKernel, u32 pid, u32 tid, const std::string &comm); + + bool GetBinary(std::vector &buf) const override; + void DumpData(int indent) const override; + void DumpLog(const std::string &prefix) const override; +}; + +class PerfRecordSample : public PerfEventRecord { +public: + PerfRecordSampleData data_ = {}; + uint64_t sampleType_ = SAMPLE_TYPE; + + // extend + // hold the new ips memory (after unwind) + // used for data_.ips replace (ReplaceWithCallStack) + std::vector ips_; + std::vector callFrames_; + + // referenced input(p) in PerfRecordSample, require caller keep input(p) together + PerfRecordSample(uint8_t *p, const perf_event_attr &attr); + bool GetBinary(std::vector &buf) const override; + void DumpData(int indent = 0) const override; + void DumpLog(const std::string &prefix) const override; + + // originalSize is use for expand callstack + void ReplaceWithCallStack(size_t originalSize = 0); + pid_t GetPid() const override; + + // only for UT + PerfRecordSample(bool inKernel, u32 pid, u32 tid, u64 period = 0, u64 time = 0, u64 id = 0) + : PerfEventRecord(PERF_RECORD_SAMPLE, inKernel, "sample") + { + data_.pid = pid; + data_.tid = tid; + data_.period = period; + data_.time = time; + data_.id = 0; + header.size = sizeof(header) + sizeof(data_); + }; +}; + +class PerfRecordExit : public PerfEventRecord { +public: + PerfRecordExitData data_; + + explicit PerfRecordExit(uint8_t *p); + + bool GetBinary(std::vector &buf) const override; + void DumpData(int indent) const override; +}; + +class PerfRecordThrottle : public PerfEventRecord { +public: + PerfRecordThrottleData data_; + + PerfRecordThrottle(uint8_t *p); + + bool GetBinary(std::vector &buf) const override; + void DumpData(int indent) const override; +}; + +class PerfRecordUnthrottle : public PerfEventRecord { +public: + PerfRecordThrottleData data_; + + explicit PerfRecordUnthrottle(uint8_t *p); + + bool GetBinary(std::vector &buf) const override; + void DumpData(int indent) const override; +}; + +class PerfRecordFork : public PerfEventRecord { +public: + PerfRecordForkData data_; + + explicit PerfRecordFork(uint8_t *p); + + bool GetBinary(std::vector &buf) const override; + void DumpData(int indent) const override; +}; + +/* + This record indicates a read event. +*/ +class PerfRecordRead : public PerfEventRecord { +public: + PerfRecordReadData data_; + + explicit PerfRecordRead(uint8_t *p); + bool GetBinary(std::vector &buf) const override; + void DumpData(int indent) const override; +}; + +/* + This record reports that new data is available in the + separate AUX buffer region. + + aux_offset + offset in the AUX mmap region where the new + data begins. + aux_size + size of the data made available. + flags describes the AUX update. + PERF_AUX_FLAG_TRUNCATED + if set, then the data returned was + truncated to fit the available buffer + size. + + PERF_AUX_FLAG_OVERWRITE + if set, then the data returned has + overwritten previous data. +*/ +class PerfRecordAux : public PerfEventRecord { +public: + PerfRecordAuxData data_; + + explicit PerfRecordAux(uint8_t *p); + bool GetBinary(std::vector &buf) const override; + void DumpData(int indent) const override; +}; + +/* + This record indicates which process has initiated an + instruction trace event, allowing tools to properly + correlate the instruction addresses in the AUX buffer + with the proper executable. + + pid process ID of the thread starting an + instruction trace. + tid thread ID of the thread starting an instruction + trace. +*/ +class PerfRecordItraceStart : public PerfEventRecord { +public: + PerfRecordItraceStartData data_; + + explicit PerfRecordItraceStart(uint8_t *p); + bool GetBinary(std::vector &buf) const override; + void DumpData(int indent) const override; +}; + +/* + When using hardware sampling (such as Intel PEBS) this + record indicates some number of samples that may have + been lost. +*/ +class PerfRecordLostSamples : public PerfEventRecord { +public: + PerfRecordLostSamplesData data_; + + explicit PerfRecordLostSamples(uint8_t *p); + bool GetBinary(std::vector &buf) const override; + void DumpData(int indent) const override; +}; + +/* + This record indicates a context switch has happened. + The PERF_RECORD_MISC_SWITCH_OUT bit in the misc field + indicates whether it was a context switch into or away + from the current process. +*/ +class PerfRecordSwitch : public PerfEventRecord { +public: + PerfRecordSwitchData data_; + explicit PerfRecordSwitch(uint8_t *p); + bool GetBinary(std::vector &buf) const override; + void DumpData([[maybe_unused]] int indent) const override {}; +}; + +/* + As with PERF_RECORD_SWITCH this record indicates a + context switch has happened, but it only occurs when + sampling in CPU-wide mode and provides additional + information on the process being switched to/from. + The PERF_RECORD_MISC_SWITCH_OUT bit in the misc field + indicates whether it was a context switch into or away + from the current process. + + next_prev_pid + The process ID of the previous (if switching + in) or next (if switching out) process on the + CPU. + + next_prev_tid + The thread ID of the previous (if switching in) + or next (if switching out) thread on the CPU. +*/ +class PerfRecordSwitchCpuWide : public PerfEventRecord { +public: + PerfRecordSwitchCpuWideData data_; + explicit PerfRecordSwitchCpuWide(uint8_t *p); + bool GetBinary(std::vector &buf) const override; + void DumpData(int indent) const override; +}; + +std::unique_ptr GetPerfEventRecord(const int type, uint8_t *data, + const perf_event_attr &attr); + +template +void PushToBinary(bool condition, uint8_t *&p, const T &v); + +template +void PushToBinary2(bool condition, uint8_t *&p, const T1 &v1, const T2 &v2); + +template +void PopFromBinary(bool condition, uint8_t *&p, T &v); + +template +void PopFromBinary2(bool condition, uint8_t *&p, T1 &v1, T2 &v2); +} // namespace HiPerf +} // namespace Developtools +} // namespace OHOS +#endif // HIPERF_PERF_EVENT_RECORD_H diff --git a/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/perf_events.h b/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/perf_events.h new file mode 100644 index 0000000000000000000000000000000000000000..b39d9e1854a634ff3e66f08587aae7a610724408 --- /dev/null +++ b/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/perf_events.h @@ -0,0 +1,523 @@ +/* + * Copyright (c) 2021-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. + */ +#ifndef HIPERF_PERF_EVENTS_H +#define HIPERF_PERF_EVENTS_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if !is_mingw +#include +#endif + +#include +#include + +#include "debug_logger.h" +#include "perf_event_record.h" +#include "ring_buffer.h" +#include "tracked_command.h" +#include "utilities.h" +#include "virtual_runtime.h" + +// this for some performance debug +#define HIDEBUG_SKIP_CALLBACK 0 + +namespace OHOS { +namespace Developtools { +namespace HiPerf { +using ConfigTable = std::map<__u64, const std::string>; +using SharedConfigTable = std::unique_ptr; + +static const std::string PERF_EVENT_PARANOID = "/proc/sys/kernel/perf_event_paranoid"; +static const std::string PERF_DISABLE_PARAM = "security.perf_harden"; + +// define convert from linux/perf_event.h +// description from https://man7.org/linux/man-pages/man2/perf_event_open.2.html + +static const ConfigTable PERF_HW_CONFIGS = { + {PERF_COUNT_HW_CPU_CYCLES, "hw-cpu-cycles"}, + {PERF_COUNT_HW_INSTRUCTIONS, "hw-instructions"}, + {PERF_COUNT_HW_CACHE_REFERENCES, "hw-cache-references"}, + {PERF_COUNT_HW_CACHE_MISSES, "hw-cache-misses"}, + {PERF_COUNT_HW_BRANCH_INSTRUCTIONS, "hw-branch-instructions"}, + {PERF_COUNT_HW_BRANCH_MISSES, "hw-branch-misses"}, + {PERF_COUNT_HW_BUS_CYCLES, "hw-bus-cycles"}, + {PERF_COUNT_HW_STALLED_CYCLES_FRONTEND, "hw-stalled-cycles-backend"}, + {PERF_COUNT_HW_STALLED_CYCLES_BACKEND, "hw-stalled-cycles-frontend"}, + {PERF_COUNT_HW_REF_CPU_CYCLES, "hw-ref-cpu-cycles"}, +}; +static const ConfigTable PERF_HW_CACHE_CONFIGS = { + {PERF_COUNT_HW_CACHE_L1D, "hw-cache-l1d"}, {PERF_COUNT_HW_CACHE_L1I, "hw-cache-l1i"}, + {PERF_COUNT_HW_CACHE_LL, "hw-cache-ll"}, {PERF_COUNT_HW_CACHE_DTLB, "hw-cache-dtlb"}, + {PERF_COUNT_HW_CACHE_ITLB, "hw-cache-itlb"}, {PERF_COUNT_HW_CACHE_BPU, "hw-cache-bpu"}, + {PERF_COUNT_HW_CACHE_NODE, "hw-cache-node"}, +}; +static const ConfigTable PERF_HW_CACHE_OP_CONFIGS = { + {PERF_COUNT_HW_CACHE_OP_READ, "hw-cache-op-read"}, + {PERF_COUNT_HW_CACHE_OP_WRITE, "hw-cache-op-write"}, + {PERF_COUNT_HW_CACHE_OP_PREFETCH, "hw-cache-op-prefetch"}, +}; +static const ConfigTable PERF_HW_CACHE_OP_RESULT_CONFIGS = { + {PERF_COUNT_HW_CACHE_RESULT_ACCESS, "hw-cache-result-access"}, + {PERF_COUNT_HW_CACHE_RESULT_MISS, "hw-cache-result-miss"}, +}; +static const ConfigTable PERF_SW_CONFIGS = { + {PERF_COUNT_SW_CPU_CLOCK, "sw-cpu-clock"}, + {PERF_COUNT_SW_TASK_CLOCK, "sw-task-clock"}, + {PERF_COUNT_SW_PAGE_FAULTS, "sw-page-faults"}, + {PERF_COUNT_SW_CONTEXT_SWITCHES, "sw-context-switches"}, + {PERF_COUNT_SW_CPU_MIGRATIONS, "sw-cpu-migrations"}, + {PERF_COUNT_SW_PAGE_FAULTS_MIN, "sw-page-faults-min"}, + {PERF_COUNT_SW_PAGE_FAULTS_MAJ, "sw-page-faults-maj"}, + {PERF_COUNT_SW_ALIGNMENT_FAULTS, "sw-alignment-faults"}, + {PERF_COUNT_SW_EMULATION_FAULTS, "sw-emulation-faults"}, + {PERF_COUNT_SW_DUMMY, "sw-dummy"}, + {PERF_COUNT_SW_BPF_OUTPUT, "sw-bpf-output"}, +}; +static const ConfigTable PERF_RAW_CONFIGS = { + {0x0, "raw-sw-incr"}, + {0x1, "raw-l1-icache-refill"}, + {0x2, "raw-l1-itlb-refill"}, + {0x3, "raw-l1-dcache-refill"}, + {0x4, "raw-l1-dcache"}, + {0x5, "raw-l1-dtlb-refill"}, + {0x6, "raw-load-retired"}, + {0x7, "raw-store-retired"}, + {0x8, "raw-instruction-retired"}, + {0x9, "raw-exception-taken"}, + {0xa, "raw-exception-return"}, + {0xb, "raw-cid-write-retired"}, + {0xc, "raw-pc-write-retired"}, + {0xd, "raw-br-immed-retired"}, + {0xe, "raw-br-return-retired"}, + {0xf, "raw-unaligned-ldst-retired"}, + {0x10, "raw-br-mis-pred"}, + {0x11, "raw-cpu-cycles"}, + {0x12, "raw-br-pred"}, + {0x13, "raw-mem-access"}, + {0x14, "raw-l1-icache"}, + {0x15, "raw-l1-dcache-wb"}, + {0x16, "raw-l2-dcache"}, + {0x17, "raw-l2-dcache-refill"}, + {0x18, "raw-l2-dcache-wb"}, + {0x19, "raw-bus-access"}, + {0x1a, "raw-memory-error"}, + {0x1b, "raw-inst-spec"}, + {0x1c, "raw-ttbr-write-retired"}, + {0x1d, "raw-bus-cycles"}, + {0x1f, "raw-l1-dcache-allocate"}, + {0x20, "raw-l2-dcache-allocate"}, + {0x21, "raw-br-retired"}, + {0x22, "raw-br-mis-pred-retired"}, + {0x23, "raw-stall-frontend"}, + {0x24, "raw-stall-backend"}, + {0x25, "raw-l1-dtlb"}, + {0x26, "raw-l1-itlb"}, + {0x27, "raw-l2-icache"}, + {0x28, "raw-l2-icache-refill"}, + {0x29, "raw-l3-dcache-allocate"}, + {0x2a, "raw-l3-dcache-refill"}, + {0x2b, "raw-l3-dcache"}, + {0x2c, "raw-l3-dcache-wb"}, + {0x2d, "raw-l2-dtlb-refill"}, + {0x2e, "raw-l2-itlb-refill"}, + {0x2f, "raw-l2-dtlb"}, + {0x30, "raw-l2-itlb"}, +}; +static ConfigTable PERF_TRACEPOINT_CONFIGS = { + +}; + +static const std::map PERF_TYPES = { + {PERF_TYPE_HARDWARE, "hardware"}, + {PERF_TYPE_SOFTWARE, "software"}, + {PERF_TYPE_TRACEPOINT, "tracepoint"}, + {PERF_TYPE_HW_CACHE, "hardware cache"}, + {PERF_TYPE_RAW, "raw"}, +}; + +static std::map TYPE_CONFIGS = { + {PERF_TYPE_HARDWARE, (PERF_HW_CONFIGS)}, {PERF_TYPE_SOFTWARE, (PERF_SW_CONFIGS)}, + {PERF_TYPE_HW_CACHE, (PERF_HW_CACHE_CONFIGS)}, {PERF_TYPE_RAW, (PERF_RAW_CONFIGS)}, + {PERF_TYPE_TRACEPOINT, (PERF_TRACEPOINT_CONFIGS)}, +}; + +// default config +static const std::vector<__u64> DEFAULT_HW_CONFIGS = { + PERF_COUNT_HW_CPU_CYCLES, +#if defined(__aarch64__) + PERF_COUNT_HW_STALLED_CYCLES_FRONTEND, + PERF_COUNT_HW_STALLED_CYCLES_BACKEND, +#endif + PERF_COUNT_HW_INSTRUCTIONS, + PERF_COUNT_HW_BRANCH_INSTRUCTIONS, + PERF_COUNT_HW_BRANCH_MISSES, +}; +static const std::vector<__u64> DEFAULT_SW_CONFIGS = { + PERF_COUNT_SW_TASK_CLOCK, + PERF_COUNT_SW_CONTEXT_SWITCHES, + PERF_COUNT_SW_PAGE_FAULTS, +}; +static const std::map> DEFAULT_TYPE_CONFIGS = { + {PERF_TYPE_HARDWARE, DEFAULT_HW_CONFIGS}, + {PERF_TYPE_SOFTWARE, DEFAULT_SW_CONFIGS}, +}; + +struct read_format_event { + __u64 value; /* The value of the event */ + __u64 id; /* if PERF_FORMAT_ID */ +}; + +struct read_format_group { + __u64 nr; /* The number of events */ + __u64 time_enabled; /* if PERF_FORMAT_TOTAL_TIME_ENABLED */ + __u64 time_running; /* if PERF_FORMAT_TOTAL_TIME_RUNNING */ + read_format_event events[1]; +}; + +struct read_format_no_group { + __u64 value; /* The value of the event */ + __u64 time_enabled; /* if PERF_FORMAT_TOTAL_TIME_ENABLED */ + __u64 time_running; /* if PERF_FORMAT_TOTAL_TIME_RUNNING */ + __u64 id; /* if PERF_FORMAT_ID */ +}; + +/* +2 allow only user-space measurements (default since + Linux 4.6). +1 allow both kernel and user measurements (default + before Linux 4.6). +0 allow access to CPU-specific data but not raw + tracepoint samples. +-1 no restrictions. +*/ +enum PerfEventParanoid { + NOLIMIT = -1, + KERNEL_USER_CPU = 0, + KERNEL_USER = 1, + USER = 2, + UNKNOW = 99, +}; + +class PerfEvents { +public: + static constexpr uint64_t DEFAULT_SAMPLE_FREQUNCY = 4000; + static constexpr uint64_t DEFAULT_SAMPLE_PERIOD = 1; + static constexpr uint64_t DEFAULT_TIMEOUT = 10 * 1000; + static constexpr size_t MIN_BUFFER_SIZE = 64 * 1024 * 1024; +#ifdef LITTLE_MEMORY + static constexpr size_t MAX_BUFFER_SIZE = 128 * 1024 * 1024; +#else + static constexpr size_t MAX_BUFFER_SIZE = 256 * 1024 * 1024; +#endif + static constexpr size_t BUFFER_LOW_LEVEL = 10 * 1024 * 1024; + static constexpr size_t BUFFER_CRITICAL_LEVEL = 5 * 1024 * 1024; + + PerfEvents(); + ~PerfEvents(); + + bool AddEvents(const std::vector &eventStrings, bool group = false); + bool PrepareTracking(void); + bool StartTracking(bool immediately = true); + bool StopTracking(void); + bool PauseTracking(void); + bool ResumeTracking(void); + /* call sequence + 1. setXXX + 2. AddEvents() + 3. PrepareTracking + 4. StartTracking (blocking...) + */ + bool EnableTracking(); + bool IsTrackRunning(); + + void SetSystemTarget(bool); + void SetCpu(const std::vector cpus); // cpu id must be [0~N] + void SetPid(const std::vector pids); // tis is same as pid in kernel + void SetTimeOut(float timeOut); + void SetTimeReport(int); + void SetVerboseReport(bool); + bool AddOffCpuEvent(); + + inline void SetTrackedCommand(const std::vector &trackedCommand) + { + if (!trackedCommand.empty()) { + trackedCommand_ = TrackedCommand::CreateInstance(trackedCommand); + } + } + + void SetSampleFrequency(unsigned int frequency); + void SetSamplePeriod(unsigned int period); + + enum SampleStackType { + NONE, + FP, + DWARF, + }; + void SetSampleStackType(SampleStackType type); + void SetDwarfSampleStackSize(uint32_t stackSize); + void SetMmapPages(size_t mmapPages); + std::vector GetAttrWithId() const; + + void SetInherit(bool inherit) + { + inherit_ = inherit; + }; + void SetClockId(int clockId) + { + clockId_ = clockId; + }; + bool SetBranchSampleType(uint64_t value); + bool AddDefaultEvent(perf_type_id type); + + std::map<__u64, std::string> GetSupportEvents(perf_type_id type); + + struct CountEvent { + bool userOnly = false; + bool kernelOnly = false; + __u64 eventCount = 0; + __u64 time_enabled = 0; + __u64 time_running = 0; + __u64 id = 0; + double used_cpus = 0; + }; + using StatCallBack = + std::function> &)>; + using RecordCallBack = std::function)>; + + void SetStatCallBack(StatCallBack reportCallBack); + void SetRecordCallBack(RecordCallBack recordCallBack); + void GetLostSamples(size_t &lostSamples, size_t &lostNonSamples) + { + lostSamples = lostSamples_; + lostNonSamples = lostNonSamples_; + } + + // review: remove this function. + static const std::string GetStaticConfigName(perf_type_id type_id, __u64 config_id) + { + auto typeConfigs = TYPE_CONFIGS.find(type_id); + if (typeConfigs != TYPE_CONFIGS.end()) { + auto configs = typeConfigs->second; + auto config = configs.find(config_id); + if (config != configs.end()) { + return config->second; + } else { + HLOGW("config not found for %u:%lld in %zu:%zu", type_id, config_id, + TYPE_CONFIGS.size(), configs.size()); + // dump all config size + for (auto types : TYPE_CONFIGS) { + HLOGV("type id %d %zu", types.first, types.second.size()); + } + } + } else { + HLOGW("type not found for %d in %zu", type_id, TYPE_CONFIGS.size()); + } + return ""; + }; + + const std::string GetTraceConfigName(__u64 config_id) + { + auto config = traceConfigTable.find(config_id); + if (config != traceConfigTable.end()) { + return config->second; + } else { + HLOGW("config not found for %lld in traceConfigTable.", config_id); + } + return ""; + }; + + static const std::string GetTypeName(perf_type_id type_id); + bool ParseEventName(const std::string &nameStr, std::string &name, bool &excludeUser, + bool &excludeKernel, bool &isTracePoint); + + // mmap one fd for each cpu + struct MmapFd { + int fd; + perf_event_mmap_page *mmapPage = nullptr; + uint8_t *buf = nullptr; + size_t bufSize = 0; + // for read and sort + size_t dataSize = 0; + perf_event_header header; + uint64_t timestamp = 0; + const perf_event_attr *attr = nullptr; + size_t posCallChain = 0; + }; + +private: + size_t recordEventCount_ = 0; // only for debug time +#ifdef HIPERF_DEBUG_TIME + std::chrono::microseconds recordCallBackTime_ = std::chrono::microseconds::zero(); + std::chrono::microseconds recordWaitDataTime_ = std::chrono::microseconds::zero(); + std::chrono::microseconds recordSleepTime_ = std::chrono::microseconds::zero(); + std::chrono::microseconds recordKernelReadTime_ = std::chrono::microseconds::zero(); +#endif + size_t lostSamples_ = 0; + size_t lostNonSamples_ = 0; + + std::unique_ptr recordBuf_ {nullptr}; + std::mutex mtxRrecordBuf_; + std::condition_variable cvRecordBuf_; + std::thread readRecordBufThread_; + std::atomic_bool readRecordThreadRunning_ = false; + bool startedTracking_ = false; + bool isLowPriorityThread_ = false; + void RecordLoop(); + void StatLoop(); + bool IsRecordInMmap(); + void ReadRecordsFromMmaps(); + bool GetRecordFromMmap(MmapFd &mmap); + void GetRecordFieldFromMmap(MmapFd &mmap, void *dest, size_t pos, size_t size); + void MoveRecordToBuf(MmapFd &mmap); + size_t GetCallChainPosInSampleRecord(const perf_event_attr &attr); + size_t GetStackSizePosInSampleRecord(MmapFd &mmap); + bool CutStackAndMove(MmapFd &mmap); + void ReadRecordFromBuf(); + size_t CalcBufferSize(); + bool PrepareRecordThread(); + void WaitRecordThread(); + bool HaveTargetsExit(const std::chrono::steady_clock::time_point &startTime); + void ExitReadRecordBufThread(); + + enum EventSpaceType { + UNKNOW = 0, + USER = 1, + KERNEL = 2, + USER_KERNEL = 3, + }; + uint8_t eventSpaceType_ = EventSpaceType::UNKNOW; + + PerfEventParanoid requestPermission_ = PerfEventParanoid::USER; + bool CheckPermissions(PerfEventParanoid request = KERNEL_USER_CPU); + bool CheckOhosPermissions(); + + static PerfEventParanoid perfEventParanoid_; + + bool inherit_ = false; + std::vector pids_; + std::vector cpus_; + std::vector groups_; + std::chrono::milliseconds timeOut_; // milliseconds + std::chrono::milliseconds timeReport_; // means same as timeOut + bool verboseReport_ = false; + bool prepared_ = false; + ConfigTable traceConfigTable; + + unsigned int samplePeriod_ = 0; + unsigned int sampleFreq_ = 0; + + struct FdItem { + OHOS::UniqueFd fd; + int cpu; + pid_t pid; + __u64 eventCount; + mutable uint64_t perf_id_ = 0; + uint64_t GetPrefId() const + { + if (perf_id_ == 0) { + read_format_no_group readNoGroupValue; + if (read(fd, &readNoGroupValue, sizeof(readNoGroupValue)) > 0) { + perf_id_ = readNoGroupValue.id; + } else { + HLOGW("read failed with fd %d", fd.Get()); + } + } + return perf_id_; + } + }; + struct EventItem { + std::string typeName; + std::string configName; + perf_event_attr attr = {}; + std::vector fdItems; + }; + struct EventGroupItem { + std::vector eventItems; + }; + std::vector eventGroupItem_; + + std::map cpuMmap_; + std::vector MmapRecordHeap_; + +#if !is_mingw + std::vector pollFds_; +#endif + const int pollTimeOut_ = 100; // ms + size_t pageSize_ = 4096; + bool systemTarget_ = false; + bool excludeHiperf_ = false; + pid_t selfPid_ = -1; + unsigned int mmapPages_ = 0; + int clockId_ = -1; + uint64_t branchSampleType_ = 0; + + SampleStackType sampleStackType_ = SampleStackType::NONE; + uint32_t dwarfSampleStackSize_ = MAX_SAMPLE_STACK_SIZE; + + // read records from the ring buffer singleton + void ReadRecordFromBuffer(); + void ReadRecordFromBufferThread(); + + std::unique_ptr trackedCommand_ = {}; + + StatCallBack reportCallBack_; + RecordCallBack recordCallBack_; + + void LoadTracepointEventTypesFromSystem(); + bool PerfEventsEnable(bool); + bool AddEvent(perf_type_id type, __u64 config, bool excludeUser = false, + bool excludeKernel = false, bool followGroup = false); + bool AddEvent(const std::string &eventString, bool followGroup = false); + bool IsEventSupport(perf_type_id type, __u64 config); + bool IsEventAttrSupport(perf_event_attr &attr); + + std::chrono::time_point trackingStartTime_; + std::chrono::time_point trackingEndTime_; + std::chrono::time_point readingStartTime_; + + std::map> countEvents_; + + void PutAllCpus(); + bool PrepareFdEvents(); + bool CreateFdEvents(); + bool StatReport(const __u64 &durationInSec); + bool CreateMmap(const FdItem &item, const perf_event_attr &attr); + + const perf_event_attr *GetDefaultAttr() + { + HLOG_ASSERT(eventGroupItem_.size() > 0); + HLOG_ASSERT(eventGroupItem_[0].eventItems.size() > 0); + return &(eventGroupItem_.at(0).eventItems.at(0).attr); + }; + + OHOS::UniqueFd Open(perf_event_attr &attr, pid_t pid = 0, int cpu = -1, int group_fd = -1, + unsigned long flags = 0); + std::unique_ptr CreateDefaultAttr(perf_type_id type, __u64 config); +}; +} // namespace HiPerf +} // namespace Developtools +} // namespace OHOS +#endif // HIPERF_PERF_EVENTS_H diff --git a/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/perf_file_format.h b/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/perf_file_format.h new file mode 100644 index 0000000000000000000000000000000000000000..84f28f9a451f9721e467f4d7c7d5c6716696079c --- /dev/null +++ b/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/perf_file_format.h @@ -0,0 +1,260 @@ +/* + * Copyright (c) 2021-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. + */ +#ifndef HIPERF_PERF_FILE_FORMAT_H +#define HIPERF_PERF_FILE_FORMAT_H + +#include + +#include "perf_event_record.h" + +namespace OHOS { +namespace Developtools { +namespace HiPerf { +enum class FEATURE { + RESERVED = 0, /* always cleared */ + FIRST_FEATURE = 1, + TRACING_DATA = 1, + BUILD_ID, // build_id_event + + HOSTNAME, // A perf_header_string with the hostname where the data was collected (uname -n) + OSRELEASE, // A perf_header_string with the os release where the data was collected (uname -r) + VERSION, // A perf_header_string with the perf user tool version where the data was collected. + // This is the same as the version of the source tree the perf tool was built from. + ARCH, // A perf_header_string with the CPU architecture (uname -m) + NRCPUS, // A structure defining the number of CPUs. + CPUDESC, // A perf_header_string with description of the CPU. On x86 this is the model name + // in /proc/cpuinfo + CPUID, // A perf_header_string with the exact CPU type. On x86 this is + // vendor,family,model,stepping. For example: GenuineIntel,6,69,1 + TOTAL_MEM, // An uint64_t with the total memory in kilobytes. + CMDLINE, // A perf_header_string_list with the perf arg-vector used to collect the data. + EVENT_DESC, // Another description of the perf_event_attrs + CPU_TOPOLOGY, // + NUMA_TOPOLOGY, // A list of NUMA node descriptions + BRANCH_STACK, // Not implemented in perf. + PMU_MAPPINGS, // A list of PMU structures, defining the different PMUs supported by perf. + GROUP_DESC, // Description of counter groups ({...} in perf syntax) + AUXTRACE, // Define additional auxtrace areas in the perf.data. auxtrace is used to store + // undecoded hardware tracing information, such as Intel Processor Trace data. + STAT, + CACHE, + SAMPLE_TIME, + MEM_TOPOLOGY, + LAST_FEATURE, + + HIPERF_FIRST_FEATURE = 192, + HIPERF_FILES_SYMBOL = HIPERF_FIRST_FEATURE, + HIPERF_WORKLOAD_CMD, + HIPERF_RECORD_TIME, + HIPERF_CPU_OFF, + HIPERF_LAST_FEATURE = HIPERF_CPU_OFF, + + FEATURE_MAX_BITS = 256, +}; + +const static std::vector FeatureStrings = { + FEATURE::HOSTNAME, + FEATURE::OSRELEASE, + FEATURE::VERSION, + FEATURE::ARCH, + FEATURE::CPUDESC, + FEATURE::CPUID, + FEATURE::CMDLINE, + + FEATURE::HIPERF_WORKLOAD_CMD, + FEATURE::HIPERF_RECORD_TIME, +}; + +struct perf_file_section { + uint64_t offset; + uint64_t size; +}; + +struct perf_file_attr { + perf_event_attr attr; + perf_file_section ids; +}; + +struct perf_header_string { + uint32_t len; + char string[0]; /* zero terminated */ +}; + +constexpr char PERF_MAGIC[] = "PERFILE2"; +constexpr int BITS_IN_BYTE = 8; +constexpr int NUM_FEATURES_FILE_HEADER = 256; + +struct perf_file_header { + char magic[8] = {'P', 'E', 'R', 'F', 'I', 'L', 'E', '2'}; + uint64_t size = sizeof(perf_file_header); + uint64_t attrSize = sizeof(perf_file_attr); + perf_file_section attrs; + perf_file_section data; + perf_file_section eventTypes; + uint8_t features[NUM_FEATURES_FILE_HEADER / BITS_IN_BYTE] = {0}; +}; + +static const std::vector extFeatureNames = { + "hiperf_files_symbol", + "hiperf_workloader_cmd", + "hiperf_record_time", + "hiperf_cpu_off", +}; +static const std::vector featureNames = { + "unknown_feature", "tracing_data", "build_id", "hostname", "osrelease", + "version", "arch", "nrcpus", "cpudesc", "cpuid", + "total_mem", "cmdline", "event_desc", "cpu_topology", "numa_topology", + "branch_stack", "pmu_mappings", "group_desc", "auxtrace", "stat", + "cache", "sample_time", "mem_topology", "last_feature", +}; + +class PerfFileSection { +public: + struct perf_file_section header; + const FEATURE featureId_; + + virtual bool GetBinary(char *buf, size_t size) = 0; + virtual size_t GetSize() = 0; + virtual ~PerfFileSection() {} + explicit PerfFileSection(const FEATURE featureId) : featureId_(featureId) + { + header.size = 0; + header.offset = 0; + } + static std::string GetFeatureName(FEATURE featureId); + +protected: + const char *rBuffer_ = nullptr; + char *wBuffer_ = nullptr; + size_t maxSize_ = 0; + size_t offset_ = 0; + + // for read + void Init(const char *buffer, size_t maxSize); + // for write + void Init(char *buffer, size_t maxSize); + bool Write(uint32_t u32); + bool Write(uint64_t u64); + bool Write(const std::string &str); + + bool Write(const char *buf, size_t size); + bool Write(const char *buf, size_t size, size_t max); + + bool Read(uint32_t &value); + bool Read(uint64_t &value); + bool Read(std::string &value); + bool Read(char *buf, size_t size); + void Skip(size_t size); + + uint32_t SizeOf(std::string &string); +}; + +class PerfFileSectionString : public PerfFileSection { + std::string stdString_; + +public: + // convert buff to PerfFileSectionString, used to read file + // if the data in buf is incorrect, ...... + PerfFileSectionString(FEATURE id, const char *buf, size_t size); + PerfFileSectionString(FEATURE id, const std::string &charString); + + bool GetBinary(char *buf, size_t size); + size_t GetSize(); + const std::string toString() const; +}; + +// ref struct +struct SymbolStruct { + uint64_t vaddr_ = 0; + uint32_t len_ = 0; + std::string symbolName_ = EMPTY_STRING; + SymbolStruct() {} + SymbolStruct(uint64_t vaddr, uint32_t len, const std::string &symbolName) + : vaddr_(vaddr), len_(len), symbolName_(symbolName) + { + } +}; + +struct SymbolFileStruct { + std::string filePath_ = EMPTY_STRING; + uint32_t symbolType_; + uint64_t textExecVaddr_; + uint64_t textExecVaddrFileOffset_; + std::string buildId_; + std::vector symbolStructs_; +}; + +class PerfFileSectionSymbolsFiles : public PerfFileSection { +public: + std::vector symbolFileStructs_; + + size_t GetSize(); + PerfFileSectionSymbolsFiles(FEATURE id, const std::vector &symbolFileStructs) + : PerfFileSection(id), symbolFileStructs_(symbolFileStructs) + { + } + // if the data in buf is incorrect, ...... + PerfFileSectionSymbolsFiles(FEATURE id, const char *buf, size_t size); + + bool GetBinary(char *buf, size_t size); + +private: + // issue from fuzz test + const size_t MAX_SYMBOLS_FILE_NUMBER = 300; + const size_t MAX_SYMBOLS_NUMBER = 3000; +}; + +// NRCPUS: A structure defining the number of CPUs. +class PerfFileSectionNrCpus : public PerfFileSection { + uint32_t nrCpusAvailable_; /* CPUs not yet onlined */ + uint32_t nrCpusOnline_; + +public: + PerfFileSectionNrCpus(FEATURE id, const char *buf, size_t size); + PerfFileSectionNrCpus(FEATURE id, uint32_t nrCpusAvailable, uint32_t nrCpusOnline); + + bool GetBinary(char *buf, size_t size); + size_t GetSize(); + void GetValue(uint32_t &nrCpusAvailable, uint32_t &nrCpusOnline) const; +}; + +class PerfFileSectionU64 : public PerfFileSection { + uint64_t value_; + +public: + PerfFileSectionU64(FEATURE id, const char *buf, size_t size); + PerfFileSectionU64(FEATURE id, uint64_t v); + + bool GetBinary(char *buf, size_t size); + size_t GetSize(); + void GetValue(uint64_t &v) const; +}; + +struct AttrWithId; +class PerfFileSectionEventDesc : public PerfFileSection { +public: + std::vector eventDesces_; + + PerfFileSectionEventDesc(FEATURE id, const char *buf, size_t size); + PerfFileSectionEventDesc(FEATURE id, const std::vector &eventDesces); + + bool GetBinary(char *buf, size_t size); + size_t GetSize(); + void GetValue(std::vector &eventDesces) const; +}; +} // namespace HiPerf +} // namespace Developtools +} // namespace OHOS +#endif // HIPERF_PERF_FILE_FORMAT_H diff --git a/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/perf_file_reader.h b/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/perf_file_reader.h new file mode 100644 index 0000000000000000000000000000000000000000..fb68017252c46b17d03030d877ab7138dd1c455a --- /dev/null +++ b/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/perf_file_reader.h @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2021-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. + */ + +#ifndef HIPERF_FILE_READER +#define HIPERF_FILE_READER + +#include +#include +#include +#include "perf_event_record.h" +#include "perf_file_format.h" + +namespace OHOS { +namespace Developtools { +namespace HiPerf { +using ProcessRecordCB = const std::function record)>; +// read record from data file, like perf.data. +// format of file follow +// tools/perf/Documentation/perf.data-file-format.txt +class PerfFileReader { +public: + virtual ~PerfFileReader(); + + static std::unique_ptr Instance(const std::string &fileName, size_t begin = 0); + static std::unique_ptr Instance(const uint8_t *buff, size_t size); + + const perf_file_header &GetHeader() const; + + std::vector GetAttrSection() const; + + // read data section, construct record, call callback for each record + bool ReadDataSection(ProcessRecordCB &callback); + + bool ReadFeatureSection(); + const std::vector &GetFeatures() const; + const std::vector> &GetFeatureSections() const; + const PerfFileSection *GetFeatureSection(FEATURE feature) const; + explicit PerfFileReader(const std::string &fileName, FILE *fp, size_t begin = 0); + explicit PerfFileReader(const uint8_t *buff, size_t size); + + const std::string GetFeatureString(const FEATURE feature) const; + + bool IsFeatrureStringSection(const FEATURE featureId) const + { + return find(FeatureStrings.begin(), FeatureStrings.end(), featureId) != + FeatureStrings.end(); + } + + // fuzz user this +protected: + virtual bool Read(void *buf, size_t len); + virtual bool Read(char *buf, uint64_t offset, size_t len); + FILE *fp_ = nullptr; + bool ReadFileHeader(); + bool ReadAttrSection(); + +private: + bool ReadRecord(ProcessRecordCB &callback); + bool IsValidDataFile(); + bool IsGzipFile(); + + // file header must be read first + + bool ReadIdsForAttr(const perf_file_attr &attr, std::vector *ids); + + const perf_event_attr *GetDefaultAttr(); + + const std::string fileName_; + uint64_t dataSectionSize_; + bool compressData_ = false; + + perf_file_header header_; + std::vector vecAttr_; + std::vector> vecAttrIds_; + + std::unordered_map mapId2Attr_; + uint64_t featureSectionOffset_; + std::vector features_; + std::vector> perfFileSections_; + + size_t fileSize_ = 0; + size_t fileBegin_ = 0; + bool isMemory_ = false; + const uint8_t *buff_ = nullptr; + const size_t buffSize_ = 0; + size_t buffCurrent_ = 0; + + bool SeekFromBegin(size_t offset) + { + if (isMemory_) { + if (offset > buffSize_) { + HLOGE("seek offset(%zu) >= buffer size(%zu)", offset, buffSize_); + return false; + } + buffCurrent_ = offset; + } else { + if (fseek(fp_, fileBegin_ + offset, SEEK_SET) != 0) { + HLOGE("fseek(%zu) failed", offset); + return false; + } + } + + return true; + } + +#ifdef HIPERF_DEBUG_TIME + std::chrono::microseconds readRecordTime_ = std::chrono::microseconds::zero(); + std::chrono::microseconds readCallbackTime_ = std::chrono::microseconds::zero(); +#endif +}; +} // namespace HiPerf +} // namespace Developtools +} // namespace OHOS +#endif // HIPERF_FILE_READER diff --git a/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/perf_record_format.h b/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/perf_record_format.h new file mode 100644 index 0000000000000000000000000000000000000000..6a1fc90d7bd9e63d38907e5951358160552e32d0 --- /dev/null +++ b/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/perf_record_format.h @@ -0,0 +1,358 @@ +/* + * Copyright (c) 2021-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. + */ +#ifndef HIPERF_PERF_RECORD_FORMAT_H +#define HIPERF_PERF_RECORD_FORMAT_H + +#include +#include "utilities.h" + +namespace OHOS { +namespace Developtools { +namespace HiPerf { +// description from https://man7.org/linux/man-pages/man2/perf_event_open.2.html + +#define SAMPLE_ID_ALL 0 + +struct sample_id { + u32 pid; + u32 tid; /* if PERF_SAMPLE_TID set */ + u64 time; /* if PERF_SAMPLE_TIME set */ + u64 id; /* if PERF_SAMPLE_ID set */ + u64 stream_id; /* if PERF_SAMPLE_STREAM_ID set */ + u32 cpu, res; /* if PERF_SAMPLE_CPU set */ + u64 id2; /* if PERF_SAMPLE_IDENTIFIER set */ +}; + +// If PERF_FORMAT_GROUP was not specified +struct read_format { + __u64 value; /* The value of the event */ + __u64 time_enabled; /* if PERF_FORMAT_TOTAL_TIME_ENABLED */ + __u64 time_running; /* if PERF_FORMAT_TOTAL_TIME_RUNNING */ + __u64 id; /* if PERF_FORMAT_ID */ +}; + +/* + The MMAP events record the PROT_EXEC mappings so that + we can correlate user-space IPs to code. They have + the following structure: + pid is the process ID. + tid is the thread ID. + addr is the address of the allocated memory. + len is the length of the allocated memory. + pgoff is the page offset of the allocated memory. + filename + is a string describing the backing of + the allocated memory. +*/ +struct PerfRecordMmapData { + u32 pid, tid; + u64 addr; + u64 len; + u64 pgoff; + char filename[KILO]; +#if SAMPLE_ID_ALL + struct sample_id sample_id; +#endif +}; + +/* + This record includes extended information on mmap(2) + calls returning executable mappings. The format is + similar to that of the PERF_RECORD_MMAP record, but + includes extra values that allow uniquely identifying + shared mappings. + + pid is the process ID. + tid is the thread ID. + addr is the address of the allocated memory. + len is the length of the allocated memory. + pgoff is the page offset of the allocated memory. + maj is the major ID of the underlying device. + min is the minor ID of the underlying device. + ino is the inode number. + ino_generation + is the inode generation. + prot is the protection information. + flags is the flags information. + filename + is a string describing the backing of the + allocated memory. +*/ +struct PerfRecordMmap2Data { + u32 pid; + u32 tid; + u64 addr; + u64 len; + u64 pgoff; + u32 maj; + u32 min; + u64 ino; + u64 ino_generation; + u32 prot; + u32 flags; + char filename[KILO]; +#if SAMPLE_ID_ALL + struct sample_id sample_id; +#endif +}; + +/* + This record indicates when events are lost. + id is the unique event ID for the samples that were lost. + lost is the number of events that were lost. +*/ +struct PerfRecordLostData { + u64 id; + u64 lost; +#if SAMPLE_ID_ALL + struct sample_id sample_id; +#endif +}; + +/* + This record indicates a change in the process name. + pid is the process ID. + tid is the thread ID. + comm is a string containing the new name of the process. +*/ +struct PerfRecordCommData { + u32 pid; + u32 tid; + char comm[KILO]; +#if SAMPLE_ID_ALL + struct sample_id sample_id; +#endif +}; + +// This record indicates a sample. +struct PerfRecordSampleData { + u64 sample_id; /* if PERF_SAMPLE_IDENTIFIER */ + u64 ip; /* if PERF_SAMPLE_IP */ + u32 pid, tid; /* if PERF_SAMPLE_TID */ + u64 time; /* if PERF_SAMPLE_TIME */ + u64 addr; /* if PERF_SAMPLE_ADDR */ + u64 id; /* if PERF_SAMPLE_ID */ + u64 stream_id; /* if PERF_SAMPLE_STREAM_ID */ + u32 cpu, res; /* if PERF_SAMPLE_CPU */ + u64 period; /* if PERF_SAMPLE_PERIOD */ + struct read_format v; + /* if PERF_SAMPLE_READ */ + u64 nr; /* if PERF_SAMPLE_CALLCHAIN */ + u64 *ips; /* if PERF_SAMPLE_CALLCHAIN */ + u32 raw_size; /* if PERF_SAMPLE_RAW */ + u8 *raw_data; /* if PERF_SAMPLE_RAW */ + u64 bnr; /* if PERF_SAMPLE_BRANCH_STACK */ + struct perf_branch_entry *lbr; /* if PERF_SAMPLE_BRANCH_STACK */ + u64 user_abi; /* if PERF_SAMPLE_REGS_USER */ + u64 reg_mask; + u64 reg_nr; + u64 *user_regs; /* if PERF_SAMPLE_REGS_USER */ + u64 stack_size; /* if PERF_SAMPLE_STACK_USER */ + u8 *stack_data; /* if PERF_SAMPLE_STACK_USER */ + u64 dyn_size; /* if PERF_SAMPLE_STACK_USER && stack_size != 0 */ + u64 weight; /* if PERF_SAMPLE_WEIGHT */ + u64 data_src; /* if PERF_SAMPLE_DATA_SRC */ + u64 transaction; /* if PERF_SAMPLE_TRANSACTION */ + u64 intr_abi; /* if PERF_SAMPLE_REGS_INTR */ + u64 intr_regs[0]; /* if PERF_SAMPLE_REGS_INTR */ + u64 phys_addr; /* if PERF_SAMPLE_PHYS_ADDR */ + u64 cgroup; /* if PERF_SAMPLE_CGROUP */ +}; + +/* + This record indicates a process exit event. +*/ +struct PerfRecordExitData { + u32 pid, ppid; + u32 tid, ptid; + u64 time; +#if SAMPLE_ID_ALL + struct sample_id sample_id; +#endif +}; + +/* + This record indicates a throttle/unthrottle event. +*/ +struct PerfRecordThrottleData { + u64 time; + u64 id; + u64 stream_id; +#if SAMPLE_ID_ALL + struct sample_id sample_id; +#endif +}; + +/* + This record indicates a fork event. +*/ +struct PerfRecordForkData { + u32 pid, ppid; + u32 tid, ptid; + u64 time; +#if SAMPLE_ID_ALL + struct sample_id sample_id; +#endif +}; + +/* + When using hardware sampling (such as Intel PEBS) this + record indicates some number of samples that may have + been lost. +*/ +struct PerfRecordLostSamplesData { + u64 lost; +#if SAMPLE_ID_ALL + struct sample_id sample_id; +#endif +}; + +/* + This record indicates which process has initiated an + instruction trace event, allowing tools to properly + correlate the instruction addresses in the AUX buffer + with the proper executable. + + pid process ID of the thread starting an + instruction trace. + tid thread ID of the thread starting an instruction + trace. +*/ +struct PerfRecordItraceStartData { + u32 pid; + u32 tid; +}; + +/* + This record reports that new data is available in the + separate AUX buffer region. + + aux_offset + offset in the AUX mmap region where the new + data begins. + aux_size + size of the data made available. + flags describes the AUX update. + PERF_AUX_FLAG_TRUNCATED + if set, then the data returned was + truncated to fit the available buffer + size. + + PERF_AUX_FLAG_OVERWRITE + if set, then the data returned has + overwritten previous data. +*/ +struct PerfRecordAuxData { + u64 aux_offset; + u64 aux_size; + u64 flags; +#if SAMPLE_ID_ALL + struct sample_id sample_id; +#endif +}; + +/* + This record indicates a read event. +*/ +struct PerfRecordReadData { + u32 pid, tid; + read_format values; +#if SAMPLE_ID_ALL + struct sample_id sample_id; +#endif +}; + +/* + This record indicates a context switch has happened. + The PERF_RECORD_MISC_SWITCH_OUT bit in the misc field + indicates whether it was a context switch into or away + from the current process. +*/ +struct PerfRecordSwitchData { +#if SAMPLE_ID_ALL + struct sample_id sample_id; +#endif +}; + +/* + As with PERF_RECORD_SWITCH this record indicates a + context switch has happened, but it only occurs when + sampling in CPU-wide mode and provides additional + information on the process being switched to/from. + The PERF_RECORD_MISC_SWITCH_OUT bit in the misc field + indicates whether it was a context switch into or away + from the current process. + + next_prev_pid + The process ID of the previous (if switching + in) or next (if switching out) process on the + CPU. + + next_prev_tid + The thread ID of the previous (if switching in) + or next (if switching out) thread on the CPU. +*/ +struct PerfRecordSwitchCpuWideData { + u32 next_prev_pid; + u32 next_prev_tid; +#if SAMPLE_ID_ALL + struct sample_id sample_id; +#endif +}; + +/* + This record includes various namespace information of + a process. + + pid is the process ID + tid is the thread ID + + nr_namespace + is the number of namespaces in this record + + Each namespace has dev and inode fields and is + recorded in the fixed position like below: + + NET_NS_INDEX=0 + Network namespace + UTS_NS_INDEX=1 + UTS namespace + IPC_NS_INDEX=2 + IPC namespace + PID_NS_INDEX=3 + PID namespace + USER_NS_INDEX=4 + User namespace + MNT_NS_INDEX=5 + Mount namespace + CGROUP_NS_INDEX=6 + Cgroup namespace +*/ +struct PerfRecordNamespacesData { + u32 pid; + u32 tid; + u64 nr_namespaces; + struct name_space { + u64 dev; + u64 inode; + } namespaces[0]; +#if SAMPLE_ID_ALL + struct sample_id sample_id; +#endif +}; +} // namespace HiPerf +} // namespace Developtools +} // namespace OHOS +#endif // HIPERF_PERF_RECORD_FORMAT_H diff --git a/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/register.h b/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/register.h new file mode 100644 index 0000000000000000000000000000000000000000..116136d51987dee33f8b30607aca9ac5d3b47db1 --- /dev/null +++ b/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/register.h @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2021 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. + */ +#ifndef HIPERF_REGISTER_H +#define HIPERF_REGISTER_H + +#include + +#include +#include + +#include "utilities.h" + +namespace OHOS { +namespace Developtools { +namespace HiPerf { +// these define copy from kernel uapi +enum perf_event_x86_regs { + PERF_REG_X86_AX, + PERF_REG_X86_BX, + PERF_REG_X86_CX, + PERF_REG_X86_DX, + PERF_REG_X86_SI, + PERF_REG_X86_DI, + PERF_REG_X86_BP, + PERF_REG_X86_SP, + PERF_REG_X86_IP, + PERF_REG_X86_FLAGS, + PERF_REG_X86_CS, + PERF_REG_X86_SS, + PERF_REG_X86_DS, + PERF_REG_X86_ES, + PERF_REG_X86_FS, + PERF_REG_X86_GS, + PERF_REG_X86_R8, + PERF_REG_X86_R9, + PERF_REG_X86_R10, + PERF_REG_X86_R11, + PERF_REG_X86_R12, + PERF_REG_X86_R13, + PERF_REG_X86_R14, + PERF_REG_X86_R15, + PERF_REG_X86_32_MAX = PERF_REG_X86_GS + 1, + PERF_REG_X86_64_MAX = PERF_REG_X86_R15 + 1, +}; + +enum perf_event_arm64_regs { + PERF_REG_ARM64_X0, + PERF_REG_ARM64_X1, + PERF_REG_ARM64_X2, + PERF_REG_ARM64_X3, + PERF_REG_ARM64_X4, + PERF_REG_ARM64_X5, + PERF_REG_ARM64_X6, + PERF_REG_ARM64_X7, + PERF_REG_ARM64_X8, + PERF_REG_ARM64_X9, + PERF_REG_ARM64_X10, + PERF_REG_ARM64_X11, + PERF_REG_ARM64_X12, + PERF_REG_ARM64_X13, + PERF_REG_ARM64_X14, + PERF_REG_ARM64_X15, + PERF_REG_ARM64_X16, + PERF_REG_ARM64_X17, + PERF_REG_ARM64_X18, + PERF_REG_ARM64_X19, + PERF_REG_ARM64_X20, + PERF_REG_ARM64_X21, + PERF_REG_ARM64_X22, + PERF_REG_ARM64_X23, + PERF_REG_ARM64_X24, + PERF_REG_ARM64_X25, + PERF_REG_ARM64_X26, + PERF_REG_ARM64_X27, + PERF_REG_ARM64_X28, + PERF_REG_ARM64_X29, + PERF_REG_ARM64_LR, + PERF_REG_ARM64_SP, + PERF_REG_ARM64_PC, + PERF_REG_ARM64_MAX, +}; + +enum perf_event_arm_regs { + PERF_REG_ARM_R0, + PERF_REG_ARM_R1, + PERF_REG_ARM_R2, + PERF_REG_ARM_R3, + PERF_REG_ARM_R4, + PERF_REG_ARM_R5, + PERF_REG_ARM_R6, + PERF_REG_ARM_R7, + PERF_REG_ARM_R8, + PERF_REG_ARM_R9, + PERF_REG_ARM_R10, + PERF_REG_ARM_FP = 11, + PERF_REG_ARM_IP = 12, + PERF_REG_ARM_SP = 13, + PERF_REG_ARM_LR = 14, + PERF_REG_ARM_PC = 15, + PERF_REG_ARM_MAX, +}; + +enum ArchType { + X86_32, + X86_64, + ARM, + ARM64, + UNSUPPORT, +}; + +// order is IP , SP for ut +static const std::map PERF_REG_NAME_MAP = { +#if defined(target_cpu_x64) + {PERF_REG_X86_IP, "PERF_REG_X86_IP"}, + {PERF_REG_X86_SP, "PERF_REG_X86_SP"}, +#elif defined(target_cpu_arm) + {PERF_REG_ARM_PC, "PERF_REG_ARM_PC"}, + {PERF_REG_ARM_SP, "PERF_REG_ARM_SP"}, +#elif defined(target_cpu_arm64) + {PERF_REG_ARM64_PC, "PERF_REG_ARM64_PC"}, + {PERF_REG_ARM64_SP, "PERF_REG_ARM64_SP"}, +#endif +}; + +// context name +static const std::map PERF_CONTEXT_NAME = { + {PERF_CONTEXT_HV, "PERF_CONTEXT_HV"}, + {PERF_CONTEXT_KERNEL, "PERF_CONTEXT_KERNEL"}, + {PERF_CONTEXT_USER, "PERF_CONTEXT_USER"}, + {PERF_CONTEXT_GUEST, "PERF_CONTEXT_GUEST"}, + {PERF_CONTEXT_GUEST_KERNEL, "PERF_CONTEXT_GUEST_KERNEL"}, + {PERF_CONTEXT_GUEST_USER, "PERF_CONTEXT_GUEST_USER"}, + {PERF_CONTEXT_MAX, "PERF_CONTEXT_MAX"}, +}; + +constexpr ArchType buildArchType = ArchType::X86_64; +const std::string UpdatePerfContext(uint64_t addr, perf_callchain_context &perfCallchainContext); +const std::string GetArchName(ArchType arch); +uint64_t GetSupportedRegMask(ArchType arch); + +// this is only for debug +const std::string RegisterGetName(size_t registerIndex); + +bool RegisterGetValue(uint64_t &value, const u64 registers[], const size_t registerIndex, + const size_t registerNumber); + +size_t RegisterGetSP(ArchType arch); +size_t RegisterGetIP(ArchType arch); + +inline bool RegisterGetSPValue(uint64_t &value, ArchType arch, const u64 registers[], + const size_t registerNumber) +{ + return RegisterGetValue(value, registers, RegisterGetSP(arch), registerNumber); +} + +inline bool RegisterGetIPValue(uint64_t &value, ArchType arch, const u64 registers[], + const size_t registerNumber) +{ + return RegisterGetValue(value, registers, RegisterGetIP(arch), registerNumber); +} + +int LibunwindRegIdToPerfReg(int regnum); + +ArchType GetDeviceArch(); +ArchType SetDeviceArch(ArchType arch); +ArchType GetArchTypeFromUname(const std::string &machine); +ArchType GetArchTypeFromABI(bool abi32); +void UpdateRegForABI(ArchType arch, u64 registers[]); +} // namespace HiPerf +} // namespace Developtools +} // namespace OHOS +#endif // HIPERF_REGISTER_H diff --git a/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/report.h b/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/report.h new file mode 100644 index 0000000000000000000000000000000000000000..d208130f1eb3bf8d5eb8fb7b8ed865d03507efcd --- /dev/null +++ b/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/report.h @@ -0,0 +1,559 @@ +/* + * Copyright (c) 2021-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. + */ + +#ifndef REPORT_H +#define REPORT_H + +#include +#include +#include + +#include "debug_logger.h" +#include "utilities.h" +#include "virtual_runtime.h" + +namespace OHOS { +namespace Developtools { +namespace HiPerf { +class ReportItemCallFrame { +public: + std::string_view func_; + uint64_t vaddr_; + std::string_view dso_; + uint64_t eventCount_ = 0; // call chain event + uint64_t selfEventCount_ = 0; // call chain event end in this function + std::vector childs; + ReportItemCallFrame(std::string_view func, uint64_t vaddr, std::string_view dso, + uint64_t eventCount, uint64_t selfEventCount) + : func_(func), + vaddr_(vaddr), + dso_(dso), + eventCount_(eventCount), + selfEventCount_(selfEventCount) + { + } + + bool operator==(const ReportItemCallFrame &b) const + { + return Same(b); + } + + bool operator!=(const ReportItemCallFrame &b) const + { + return !Same(b); + } + + static int CompareSortingEventCount(const ReportItemCallFrame &a, const ReportItemCallFrame &b) + { + return a.eventCount_ > b.eventCount_; + } + + static void OrderCallFrames(std::vector &callframes, int indent = 2) + { + int i = 2; + if (callframes.size() > 0) { + std::sort(callframes.begin(), callframes.end(), + &ReportItemCallFrame::CompareSortingEventCount); + + for (auto &callframe : callframes) { + HLOGDUMMY("%*s%s", indent, "", callframe.ToDebugString().c_str()); + if (callframe.childs.size() > 0) { + OrderCallFrames(callframe.childs, indent + i); + } + } + } + } + + // just a log + static void DumpCallFrames(std::vector &callframes, int indent = 2) + { + int y = 2; + if (callframes.size() > 0) { + for (auto &callframe : callframes) { + HLOGV("%*s%s", indent, "", callframe.ToDebugString().c_str()); + if (callframe.childs.size() > 0) { + DumpCallFrames(callframe.childs, indent + y); + } + } + } + } + + const std::string ToDebugString() const + { + return StringPrintf("%" PRIu64 "(%" PRIu64 ")%s(%s+0x%" PRIx64 ") child %zu", eventCount_, + selfEventCount_, func_.data(), dso_.data(), vaddr_, childs.size()); + } + +private: + bool Same(const ReportItemCallFrame &b) const + { + return (func_ == b.func_) and (vaddr_ == b.vaddr_) and (dso_ == b.dso_); + } +}; + +// one item or one line in report +class ReportItem { +public: + pid_t pid_ = 0; + pid_t tid_ = 0; + std::string_view comm_ = ""; + std::string_view dso_ = ""; + std::string_view fromDso_ = ""; + std::string_view fromFunc_ = ""; + std::string_view func_ = ""; + uint64_t vaddr_ = 0; + uint64_t eventCount_ = 0; // event count + std::vector callStacks_; + float heat = 0.0f; + static unsigned long long allIndex_; // debug only + unsigned long long index_; + + // only for ut test + ReportItem(pid_t pid, pid_t tid, const char *comm, const char *dso, const char *func, + uint64_t vaddr, uint64_t eventCount) + : pid_(pid), + tid_(tid), + comm_(comm), + dso_(dso), + func_(func), + vaddr_(vaddr), + eventCount_(eventCount) + { + HLOG_ASSERT(comm != nullptr); + index_ = allIndex_++; + } + + ReportItem(pid_t pid, pid_t tid, std::string &comm, const std::string_view &dso, + const std::string_view &func, uint64_t vaddr, uint64_t eventCount) + : pid_(pid), + tid_(tid), + comm_(comm), + dso_(dso), + func_(func), + vaddr_(vaddr), + eventCount_(eventCount) + { + HLOG_ASSERT(!comm.empty()); + index_ = allIndex_++; + } + + bool operator==(const ReportItem &b) const + { + return Same(b); + } + + bool operator!=(const ReportItem &b) const + { + return !Same(b); + } + + // debug only + const std::string ToDebugString() const + { + return StringPrintf("%d:%d:%s-%s(%s):%zu i:%llu", pid_, tid_, comm_.data(), func_.data(), + dso_.data(), eventCount_, index_); + } + + // Count + static int CompareEventCount(const ReportItem &a, const ReportItem &b) + { + if (a.eventCount_ != b.eventCount_) { + return (a.eventCount_ > b.eventCount_) ? 1 : -1; + } else { + return 0; + } + } + + static int CompareSortingEventCount(const ReportItem &a, const ReportItem &b) + { + return a.eventCount_ > b.eventCount_; + } + + static const std::string GetEventCount(const ReportItem &a, size_t len, + const std::string &format) + { + return StringPrintf(format.c_str(), len, a.eventCount_); + } + + // Pid + static int ComparePid(const ReportItem &a, const ReportItem &b) + { + if (a.pid_ != b.pid_) { + return (a.pid_ > b.pid_) ? 1 : -1; + } else { + return 0; + } + } + static const std::string GetPid(const ReportItem &a, size_t len, const std::string &format) + { + return StringPrintf(format.c_str(), len, a.pid_); + } + + // Tid + static int CompareTid(const ReportItem &a, const ReportItem &b) + { + if (a.tid_ != b.tid_) { + return (a.tid_ > b.tid_) ? 1 : -1; + } else { + return 0; + } + } + static const std::string GetTid(const ReportItem &a, size_t len, const std::string &format) + { + return StringPrintf(format.c_str(), len, a.tid_); + } + + // Comm + static int CompareComm(const ReportItem &a, const ReportItem &b) + { + int result = a.comm_.compare(b.comm_); + return result; + } + static const std::string GetComm(const ReportItem &a, size_t len, const std::string &format) + { + return StringPrintf(format.c_str(), len, a.comm_.data()); + } + + // Func + static int CompareFunc(const ReportItem &a, const ReportItem &b) + { + return a.func_.compare(b.func_); + } + static const std::string GetFunc(const ReportItem &a, size_t len, const std::string &format) + { + return StringPrintf(format.c_str(), len, a.func_.data()); + } + + // Dso + static int CompareDso(const ReportItem &a, const ReportItem &b) + { + return a.dso_.compare(b.dso_); + } + static const std::string GetDso(const ReportItem &a, size_t len, const std::string &format) + { + return StringPrintf(format.c_str(), len, a.dso_.data()); + } + + // fromDso + static int CompareFromDso(const ReportItem &a, const ReportItem &b) + { + return a.fromDso_.compare(b.fromDso_); + } + static const std::string GetFromDso(const ReportItem &a, size_t len, const std::string &format) + { + return StringPrintf(format.c_str(), len, a.fromDso_.data()); + } + + // fromFunc + static int CompareFromFunc(const ReportItem &a, const ReportItem &b) + { + return a.fromFunc_.compare(b.fromFunc_); + } + static const std::string GetFromFunc(const ReportItem &a, size_t len, const std::string &format) + { + return StringPrintf(format.c_str(), len, a.fromFunc_.data()); + } + +private: + bool Same(const ReportItem &b) const + { + return (comm_ == b.comm_) && (pid_ == b.pid_) && (tid_ == b.tid_) && (func_ == b.func_) && + (dso_ == b.dso_) && (vaddr_ == b.vaddr_); + } +}; + +using ReportKeyCompareFunction = int(const ReportItem &, const ReportItem &); +using ReportKeyGetFunction = const std::string(const ReportItem &, size_t, const std::string &); + +constexpr const int MAX_FILED_LEN = 20; +constexpr const int CALLSTACK_INDENT = 4; +struct ReportKey { + const std::string keyName_; + const std::string valueFormat_; + size_t maxLen_ = 0u; + std::string maxValue_; + ReportKeyCompareFunction &compareFunction_; + ReportKeyGetFunction &GetFunction_; + const std::vector &displayFilter_; + + ReportKey(const std::string keyName, ReportKeyCompareFunction &compareFunction, + ReportKeyGetFunction &GetFunction, const std::string valueFormat, + const std::vector &displayFilter) + : keyName_(keyName), + valueFormat_(valueFormat), + compareFunction_(compareFunction), + GetFunction_(GetFunction), + displayFilter_(displayFilter) + { + maxLen_ = keyName.size(); + } + + void UpdateValueMaxLen(const std::string &value) + { + size_t newMaxLen = std::max(maxLen_, value.size()); + if (maxLen_ < newMaxLen) { + maxValue_ = value; + maxLen_ = newMaxLen; + } + } + + void UpdateValueMaxLen(size_t value) + { + size_t newMaxLen = std::max(maxLen_, std::to_string(value).size()); + if (maxLen_ < newMaxLen) { + maxValue_ = std::to_string(value); + maxLen_ = newMaxLen; + } + } + + std::string GetValue(const ReportItem &i) + { + return GetFunction_(i, maxLen_, valueFormat_); + } + + bool ShouldDisplay(const ReportItem &i) + { + if (displayFilter_.size() == 0) { + return true; + } else { + std::string value = GetFunction_(i, 0, valueFormat_); + auto it = find(displayFilter_.begin(), displayFilter_.end(), value); + if (it == displayFilter_.end()) { + HLOGV(" not found '%s' in %s", value.c_str(), + VectorToString(displayFilter_).c_str()); + } + return (it != displayFilter_.end()); + } + } +}; + +using ReportItems = std::vector; +using ReportItemsIt = ReportItems::iterator; +using ReportItemsConstIt = ReportItems::const_iterator; + +struct ReportOption { + float heatLimit_ = 0.0f; + float callStackHeatLimit_ = 0.0f; + + // display filter + std::vector displayComms_ {}; + std::vector displayPids_ {}; + std::vector displayTids_ {}; + std::vector displayDsos_ {}; + std::vector displayFromDsos_ {}; + std::vector displayFuncs_ {}; + std::vector displayFromFuncs_ {}; + std::vector displayDummy_ {}; + + std::vector sortKeys_ = {"comm", "pid", "tid", "dso", "func"}; + + bool debug_ = false; + bool hideCount_ = false; +}; + +class Report { +public: + Report() : option_(defaultOption_), virtualRuntime_(false) + { + // works for ut test + } + Report(ReportOption &option) : option_(option), virtualRuntime_(false) {} + bool MultiLevelSame(const ReportItem &a, const ReportItem &b); + void AdjustReportItems(); + void AddReportItem(const PerfRecordSample &sample, bool includeCallStack); + void AddReportItemBranch(const PerfRecordSample &sample); + void OutputStd(FILE *output); + void OutputStdDiff(FILE *output, Report &other); + + ReportOption &option_; + + VirtualRuntime virtualRuntime_; + + std::map reportKeyMap_ = { + { + "count", + { + "count", + ReportItem::CompareEventCount, + ReportItem::GetEventCount, + "%*" PRIu64 "", + option_.displayDummy_, + }, + }, + { + "comm", + { + "comm", + ReportItem::CompareComm, + ReportItem::GetComm, + "%-*s", + option_.displayComms_, + }, + }, + { + "pid", + { + "pid", + ReportItem::ComparePid, + ReportItem::GetPid, + "%*d", + option_.displayPids_, + }, + }, + { + "tid", + { + "tid", + ReportItem::CompareTid, + ReportItem::GetTid, + "%*d", + option_.displayTids_, + }, + }, + { + "dso", + { + "dso", + ReportItem::CompareDso, + ReportItem::GetDso, + "%-*s", + option_.displayDsos_, + }, + }, + { + "from_dso", + { + "from_dso", + ReportItem::CompareFromDso, + ReportItem::GetFromDso, + "%-*s", + option_.displayFromDsos_, + }, + }, + { + "func", + { + "func", + ReportItem::CompareFunc, + ReportItem::GetFunc, + "%-*s", + option_.displayFuncs_, + }, + }, + { + "from_func", + { + "from_func", + ReportItem::CompareFromFunc, + ReportItem::GetFromFunc, + "%-*s", + option_.displayFromFuncs_, + }, + }, + }; + struct ReportEventConfigItem { + ReportEventConfigItem(const ReportEventConfigItem &) = delete; + ReportEventConfigItem &operator=(const ReportEventConfigItem &) = delete; + ReportEventConfigItem(ReportEventConfigItem &&) = default; + std::string eventName_; + uint64_t sampleCount_ = 0; + uint64_t eventCount_ = 0; + std::vector reportItems_; + uint32_t type_; + uint64_t config_; + std::vector ids_; + + bool coutMode_ = true; // use cout or time ? + bool operator==(const ReportEventConfigItem &o) const + { + return (type_ == o.type_) && (config_ == o.config_); + } + bool operator!=(const ReportEventConfigItem &o) const + { + return !(operator==(o)); + } + std::string toDebugString() + { + return StringPrintf("%s(%" PRIu32 "-%" PRIu64 "):PRIu64", eventName_.c_str(), type_, + config_, sampleCount_); + } + ReportEventConfigItem(std::string eventName, uint32_t type, uint64_t config, + bool coutMode = true) + : eventName_(eventName), type_(type), config_(config), coutMode_(coutMode) + { + } + }; + std::vector configs_; + virtual ~Report() {} + + std::map configIdIndexMaps_; // index of configNames_ + std::string GetConfigName(uint64_t id) + { + return configs_[GetConfigIndex(id)].eventName_; + } + size_t GetConfigIndex(uint64_t id) + { + HLOG_ASSERT_MESSAGE(configIdIndexMaps_.find(id) != configIdIndexMaps_.end(), + "unable found id %" PRIx64 "", id); + return configIdIndexMaps_.at(id); + } + +private: + FILE *output_ = nullptr; + const std::string TEXT_RED = "\x1b[31m"; + const std::string TEXT_GREEN = "\x1b[32m"; + const std::string TEXT_RESET = "\033[0m"; + const unsigned int ConsoleDefaultWidth = 80; + + // sometime caller don't give the option + ReportOption defaultOption_; + + std::vector displayKeyNames_; + + // use virtual only for gmock test + bool MultiLevelSorting(const ReportItem &a, const ReportItem &b); + bool MultiLevelSameAndUpdateCount(ReportItem &l, ReportItem &r); + void MergeCallFrameCount(ReportItem &l, ReportItem &r); + virtual int MultiLevelCompare(const ReportItem &a, const ReportItem &b); + + void StatisticsRecords(); + void FilterDisplayRecords(); + void UpdateReportItemsAfterAdjust(); + + // std out + unsigned int consoleWidth_ = 0; + void PrepareConsole(); + + void OutputStdStatistics(ReportEventConfigItem &); + bool OutputStdStatistics(ReportEventConfigItem &config, ReportEventConfigItem &otherConfig); + + void OutputStdHead(ReportEventConfigItem &, bool diffMode = false); + + void OutputStdContent(ReportEventConfigItem &); + void OutputStdContentDiff(ReportEventConfigItem &, ReportEventConfigItem &); + + void OutputStdContentItem(const ReportItem &reportItem); + void OutputStdContentDiffOneSide(bool leftOnly, ReportItem &reportItem); + + void OutputStdCallFrames(int indent, const ReportItemCallFrame &callFrames, + uint64_t totalEventCount); + bool OutputStdCallFrame(int indent, const std::string_view &funcName, uint64_t eventCount, + uint64_t totalEventCount); + void OutputStdItemHeating(float heat, float heat2); +}; +} // namespace HiPerf +} // namespace Developtools +} // namespace OHOS +#endif // REPORT_H diff --git a/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/ring_buffer.h b/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/ring_buffer.h new file mode 100644 index 0000000000000000000000000000000000000000..3a839310a74a09401dc206f626c423a23b665e6a --- /dev/null +++ b/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/ring_buffer.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2021-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. + */ +#ifndef HIPERF_RING_BUFFER_H +#define HIPERF_RING_BUFFER_H + +// #ifdef target_cpu_x64 +#include +// #endif +#include + +namespace OHOS { +namespace Developtools { +namespace HiPerf { +class RingBuffer { +public: + // little endian, perf_event_header.type is less than 0xff, so set it + static constexpr uint8_t MARGIN_BYTE = 0xFF; + + explicit RingBuffer(size_t size); + ~RingBuffer(); + // get size of the writable space + size_t GetFreeSize() const; + + // before writing data to rbuff, alloc space first + uint8_t *AllocForWrite(size_t writeSize); + // after writing data, move head pointer + void EndWrite(); + // get data from buff, return nullptr if no readable data + uint8_t *GetReadData(); + // after reading, move tail pointer + void EndRead(); + +private: + std::unique_ptr buf_ = nullptr; + const size_t size_; + std::atomic head_ {0}; + // std::atomic_size_t head_ = 0; // write after this, always increase + // std::atomic_size_t tail_ = 0; // read from this, always increase + std::atomic tail_ {0}; + size_t writeSize_ = 0; + size_t readSize_ = 0; +}; +} // namespace HiPerf +} // namespace Developtools +} // namespace OHOS +#endif // HIPERF_RING_BUFFER_H diff --git a/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/subcommand_dump.h b/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/subcommand_dump.h new file mode 100644 index 0000000000000000000000000000000000000000..e2cf826d2c722f455bca9b066f9458d97ecaf746 --- /dev/null +++ b/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/subcommand_dump.h @@ -0,0 +1,119 @@ +/* + * 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. + */ +#ifndef SUBCOMMAND_DUMP_H +#define SUBCOMMAND_DUMP_H + +#include "perf_file_reader.h" + +#include + +#if HAVE_PROTOBUF +#include "report_protobuf_file.h" +#endif +#include "subcommand.h" +#include "symbols_file.h" +#include "virtual_runtime.h" + +namespace OHOS { +namespace Developtools { +namespace HiPerf { +static const std::string DEFAULT_DUMP_FILENAME = "perf.data"; + +class SubCommandDump : public SubCommand { +public: + SubCommandDump() + // clang-format off + : SubCommand("dump", "Dump content of a perf data file, like perf.data", + + "Usage: hiperf dump [option] \n" + " Dump specific parts of specified file .\n" + " --head\n" + " Dump header and attrs only.\n" + " -d\n" + " Dump data section only.\n" + " -f\n" + " Dump addtional features only.\n" + " --sympath \n" + " use symbols path to find symbols.\n" + " --elf \n" + " dump elf not perf data.\n" +#if HAVE_PROTOBUF + " --proto \n" + " dump perf data from protobuf file.\n" +#endif + " --export \n" + " also export the user stack data to some split file,\n" + " use this command to produce ut data." + " named with sample index(0 base):\n" + " hiperf___user_regs_.dump\n" + " hiperf___user_data_.dump\n" + " \n" + " perf data file to dump, default is perf.data\n\n" + ) + // clang-format on + { + } + ~SubCommandDump() override; + + bool OnSubCommand(std::vector &args) override; + bool ParseOption(std::vector &args) override; + + static bool RegisterSubCommandDump(void); + + static void DumpPrintEventAttr(const perf_event_attr &attr, int indent = 0); + std::unique_ptr reader_; + +private: + static void DumpSampleType(uint64_t sampleType, int indent); + int exportSampleIndex_ = -1; + int currectSampleIndex_ = 0; + std::string dumpFileName_; + std::string elfFileName_; + std::string protobufDumpFileName_; + int indent_ = 0; +#if HAVE_PROTOBUF + std::unique_ptr protobufInputFileReader_ = nullptr; +#endif + + std::vector attrIds_; + + bool dumpHeader_ = false; + bool dumpFeatures_ = false; + bool dumpData_ = false; + bool dumpAll_ = true; + + std::vector dumpSymbolsPaths_; + + bool CheckInputFile(); + bool DumpElfFile(); +#if HAVE_PROTOBUF + bool DumpProtoFile(); +#endif + void DumpPrintFileHeader(int indent = 0); + void DumpAttrPortion(int indent = 0); + void DumpDataPortion(int indent = 0); + void DumpCallChain(int indent, std::unique_ptr &sample); + void DumpFeaturePortion(int indent = 0); + void ExprotUserData(std::unique_ptr &record); + void ExprotUserStack(const PerfRecordSample &recordSample); + void PrintHeaderInfo(const int &indent); + void PrintSymbolFile(const int &indent, const SymbolFileStruct &symbolFileStruct); + void PrintFeatureEventdesc(int indent, const PerfFileSectionEventDesc §ionEventdesc); + VirtualRuntime vr_; +}; +} // namespace HiPerf +} // namespace Developtools +} // namespace OHOS +#endif // SUBCOMMAND_DUMP_H diff --git a/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/subcommand_help.h b/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/subcommand_help.h new file mode 100644 index 0000000000000000000000000000000000000000..18a6eb2da302c92133f96f0ca5911f157db183c6 --- /dev/null +++ b/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/subcommand_help.h @@ -0,0 +1,45 @@ +/* + * 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. + */ +#ifndef HIPERF_SUBCOMMAND_HELP_H_ +#define HIPERF_SUBCOMMAND_HELP_H_ + +#include "option.h" +#include "subcommand.h" +namespace OHOS { +namespace Developtools { +namespace HiPerf { +class SubCommandHelp : public SubCommand { +public: + SubCommandHelp() + // clang-format off + : SubCommand("help", "Show more help information for hiperf", + "Usage: hiperf help [subcommand]\n" + " By default, all options help information and subcommand brief information are output.\n" + " If you provide a subcommand, only the help information for this command will be output.\n\n" + ) + // clang-format on + { + Option::RegisterMainOption("--help", "show help", OnHelp); + Option::RegisterMainOption("-h", "show help", OnHelp); + } + + bool OnSubCommand(std::vector &args) override; + static void RegisterSubCommandHelp(void); + static bool OnHelp(std::vector &args); +}; +} // namespace HiPerf +} // namespace Developtools +} // namespace OHOS +#endif // HIPERF_SUBCOMMAND_HELP_H_ diff --git a/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/symbols_file.h b/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/symbols_file.h new file mode 100644 index 0000000000000000000000000000000000000000..f6670c0fecdae522111352321ad2d5194f8d711c --- /dev/null +++ b/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/symbols_file.h @@ -0,0 +1,351 @@ +/* + * Copyright (c) 2021-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. + */ + +#ifndef HIPERF_SYMBOLS_H +#define HIPERF_SYMBOLS_H + +#include +#include +#include +#include + +#include "perf_file_format.h" +#include "utilities.h" + +#define HIPERF_ELF_READ_USE_MMAP + +namespace OHOS { +namespace Developtools { +namespace HiPerf { +constexpr const char KERNEL_MMAP_NAME[] = "[kernel.kallsyms]"; +constexpr const char KERNEL_MODULES_EXT_NAME[] = ".ko"; +constexpr const char KERNEL_ELF_NAME[] = "vmlinux"; +constexpr const char MMAP_VDSO_NAME[] = "[vdso]"; +constexpr const char MMAP_ANONYMOUS_NAME[] = "[anon]"; +constexpr const char MMAP_ANONYMOUS_OHOS_NAME[] = "//anon"; + +const std::string NOTE_GNU_BUILD_ID = ".note.gnu.build-id"; +const std::string EH_FRAME_HR = ".eh_frame_hdr"; +const std::string EH_FRAME = ".eh_frame"; +const std::string ARM_EXIDX = ".ARM.exidx"; +const std::string SYMTAB = ".symtab"; +const std::string DYNSYM = ".dynsym"; +const std::string GNU_DEBUGDATA = ".gnu_debugdata"; +const std::string PLT = ".plt"; +const std::string LINKER_PREFIX = "__dl_"; +const std::string LINKER_PREFIX_NAME = "[linker]"; + +const int MAX_SYMBOLS_TYPE_NAME_LEN = 10; + +class FileSymbol { + [[maybe_unused]] uint64_t vaddr_ = 0; + [[maybe_unused]] uint64_t len_ = 0; + std::string name_ = ""; + std::string demangle_ = ""; // demangle string + FileSymbol(uint64_t vaddr, uint64_t len, const char *name, const char *demangle) + : vaddr_(vaddr), len_(len), name_(name), demangle_(demangle) + { + } +}; + +struct Symbol { + uint64_t funcVaddr_ = 0; + uint64_t fileVaddr_ = 0; + uint64_t taskVaddr_ = 0; + uint64_t len_ = 0; + int32_t index_ = -1; + std::string_view name_ = ""; + std::string_view demangle_ = ""; // demangle string + std::string_view module_ = ""; // maybe empty + std::string_view comm_ = ""; // we need a comm name like comm@0x1234 + mutable std::string_view unknow_ = ""; + mutable bool matched_ = false; // if some callstack match this + int32_t hit_ = 0; + + // elf use this + Symbol(uint64_t vaddr, uint64_t len, const std::string &name, const std::string &demangle, + const std::string module) + : funcVaddr_(vaddr), + fileVaddr_(vaddr), + len_(len), + name_(MemoryHold::Get().HoldStringView(name)), + demangle_(MemoryHold::Get().HoldStringView(demangle)), + module_(MemoryHold::Get().HoldStringView(module)) {} + Symbol(uint64_t vaddr, uint64_t len, const std::string &name, const std::string &module) + : Symbol(vaddr, len, name, name, module) {} + + // kernel use this + Symbol(uint64_t vaddr, const std::string &name, const std::string &module) + : Symbol(vaddr, 0, name, name, module) {} + + // Symbolic use this + Symbol(uint64_t taskVaddr = 0, const std::string &comm = "") + : taskVaddr_(taskVaddr), comm_(comm) + { + } + + // copy + Symbol(const Symbol &other) = default; + + static bool SameVaddr(const Symbol &a, const Symbol &b) + { + return (a.funcVaddr_ == b.funcVaddr_); + } + bool Same(const Symbol &b) const + { + return (funcVaddr_ == b.funcVaddr_ and demangle_ == b.demangle_); + } + bool operator==(const Symbol &b) const + { + return Same(b); + } + + bool operator!=(const Symbol &b) const + { + return !Same(b); + } + + bool isValid() const + { + return !module_.empty(); + } + + void SetMatchFlag() const + { + matched_ = true; + } + + inline bool HasMatched() const + { + return matched_; + } + + std::string_view Name() const + { + if (!demangle_.empty()) { + return demangle_; + } + if (!name_.empty()) { + return name_; + } + if (unknow_.empty()) { + std::stringstream sstream; + if (!module_.empty()) { + sstream << module_ << "+0x" << std::hex << fileVaddr_; + } else { + sstream << comm_ << "@0x" << std::hex << taskVaddr_; + } + std::string hold = sstream.str(); + unknow_ = MemoryHold::Get().HoldStringView(hold); + } + return unknow_; + } + + std::string ToString() const + { + std::stringstream sstream; + if (fileVaddr_ != 0) { + sstream << "0x" << std::hex << fileVaddr_; + } else { + sstream << "0x" << std::hex << taskVaddr_; + } + sstream << " " << Name(); + return sstream.str(); + }; + + std::string ToDebugString() const + { + std::stringstream sstream; + sstream << "0x" << std::setfill('0') << std::setw(sizeof(funcVaddr_) * BYTE_PRINT_WIDTH) + << std::hex << funcVaddr_; + sstream << "|"; + sstream << std::setfill('0') << std::setw(sizeof(len_)) << len_; + sstream << "|"; + sstream << demangle_ << "|"; + sstream << name_ << "|"; + sstream << (matched_ ? "matched" : ""); + sstream << " unknowname:" << unknow_.size(); + sstream << " task:" << (comm_.size() > 0 ? comm_ : ""); + sstream << "@" << taskVaddr_; + sstream << " file:" << (module_.size() > 0 ? module_ : ""); + sstream << "@" << fileVaddr_; + + return sstream.str(); + }; + + bool Contain(uint64_t addr) const + { + if (len_ == 0) { + return funcVaddr_ <= addr; + } else { + return (funcVaddr_ <= addr) and ((funcVaddr_ + len_) > addr); + } + } + + // The range [first, last) must be partitioned with respect to the expression !(value < element) + // or !comp(value, element) + static bool ValueLessThen(uint64_t vaddr, const Symbol &a) + { + return vaddr < a.funcVaddr_; + } + static bool ValueLessEqual(uint64_t vaddr, const Symbol &a) + { + return vaddr <= a.funcVaddr_; + } + static bool CompareLessThen(const Symbol &a, const Symbol &b) + { + return a.funcVaddr_ < b.funcVaddr_; // we should use vaddr to sort + }; + static bool CompareByPointer(const Symbol *a, const Symbol *b) + { + return a->funcVaddr_ < b->funcVaddr_; // we should use vaddr to sort + }; +}; + +enum SymbolsFileType { + SYMBOL_KERNEL_FILE, + SYMBOL_KERNEL_MODULE_FILE, + SYMBOL_ELF_FILE, + SYMBOL_JAVA_FILE, + SYMBOL_JS_FILE, + SYMBOL_UNKNOW_FILE, +}; + +class SymbolsFile { +public: + SymbolsFileType symbolFileType_; + std::string filePath_ = ""; + + // [14] .text PROGBITS 00000000002c5000 000c5000 + // min exec addr , general it point to .text + // we make a default value for min compare + static const uint64_t maxVaddr = std::numeric_limits::max(); + + uint64_t textExecVaddr_ = maxVaddr; + uint64_t textExecVaddrFileOffset_ = 0; + uint64_t textExecVaddrRange_ = maxVaddr; + + SymbolsFile(SymbolsFileType symbolType, const std::string path) + : symbolFileType_(symbolType), filePath_(path) {}; + virtual ~SymbolsFile(); + + // create the symbols file object + static std::unique_ptr CreateSymbolsFile( + SymbolsFileType = SYMBOL_UNKNOW_FILE, const std::string symbolFilePath = EMPTY_STRING); + static std::unique_ptr CreateSymbolsFile(const std::string &symbolFilePath); + + // set symbols path + bool setSymbolsFilePath(const std::string &symbolsSearchPath) + { + std::vector symbolsSearchPaths = {symbolsSearchPath}; + return setSymbolsFilePath(symbolsSearchPaths); + }; + bool setSymbolsFilePath(const std::vector &); + + // load symbol from file + virtual bool LoadSymbols([[maybe_unused]] const std::string &symbolFilePath = EMPTY_STRING) + { + HLOGV("virtual dummy function called"); + symbolsLoaded_ = true; + return false; + }; + // load debug info for unwind + virtual bool LoadDebugInfo([[maybe_unused]] const std::string &symbolFilePath = EMPTY_STRING) + { + HLOGV("virtual dummy function called"); + debugInfoLoaded_ = true; + return false; + }; + // get the build if from symbols + const std::string GetBuildId() const; + + // get the symbols vector + const std::vector &GetSymbols(); + const std::vector &GetMatchedSymbols(); + + // get vaddr(in symbol) from ip(real addr , after mmap reloc) + virtual uint64_t GetVaddrInSymbols(uint64_t ip, uint64_t mapStart, uint64_t mapOffset) const; + + // get symbols from vaddr + const Symbol GetSymbolWithVaddr(uint64_t vaddr); + + // read the .text section and .eh_frame section (RO) memory from elf mmap + // unwind use this to check the DWARF and so on + virtual size_t ReadRoMemory(uint64_t, uint8_t * const, size_t) const + { + HLOGV("virtual dummy function called"); + return 0; // default not support + } + + // get the section info , like .ARM.exidx + virtual bool GetSectionInfo([[maybe_unused]] const std::string &name, + [[maybe_unused]] uint64_t §ionVaddr, + [[maybe_unused]] uint64_t §ionSize, + [[maybe_unused]] uint64_t §ionFileOffset) const + { + HLOGV("virtual dummy function called"); + return false; + } +#ifndef target_cpu_arm + // get hdr info for unwind , need provide the fde table location and entry count + virtual bool GetHDRSectionInfo([[maybe_unused]] uint64_t &ehFrameHdrElfOffset, + [[maybe_unused]] uint64_t &fdeTableElfOffset, + [[maybe_unused]] uint64_t &fdeTableSize) const + { + HLOGV("virtual dummy function called"); + return false; + } +#endif + // load from symbols from the perf.data format + static std::unique_ptr LoadSymbolsFromSaved(const SymbolFileStruct &); + // save the symbols to perf.data format + void ExportSymbolToFileFormat(SymbolFileStruct &symbolFileStruct); + + bool SymbolsLoaded() + { + return symbolsLoaded_; + } + + // this means we are in recording + // will try read some elf in runtime path + static bool onRecording_; + +protected: + bool symbolsLoaded_ = false; + bool debugInfoLoaded_ = false; + const std::string FindSymbolFile(const std::vector &, + std::string symboleFilePath = EMPTY_STRING) const; + + std::string SearchReadableFile(const std::vector &searchPaths, + const std::string &filePath) const; + bool UpdateBuildIdIfMatch(std::string buildId); + std::string buildId_; + std::vector symbolsFileSearchPaths_; + std::vector symbols_{}; + std::vector matchedSymbols_{}; + std::vector fileSymbols_{}; + + void AdjustSymbols(); + void SortMatchedSymbols(); + bool CheckPathReadable(const std::string& path) const; + + friend class VirtualRuntimeTest; + + friend class ReportProtobufFileTest; +}; +} // namespace HiPerf +} // namespace Developtools +} // namespace OHOS +#endif // HIPERF_SYMBOLS_H diff --git a/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/tracked_command.h b/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/tracked_command.h new file mode 100644 index 0000000000000000000000000000000000000000..628128b8027d14cc1d3da9125e7944225913fe20 --- /dev/null +++ b/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/tracked_command.h @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2021-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. + */ +#ifndef HIPERF_TRACKED_COMMAND_H_ +#define HIPERF_TRACKED_COMMAND_H_ + +#include +#include +#include +namespace OHOS { +namespace Developtools { +namespace HiPerf { +class TrackedCommand : public Noncopyable { +public: + enum class State { + COMMAND_WAITING, // child process blocked to execute command + COMMAND_STARTED, // child process executing command + COMMAND_FAILURE, // command failed to start + COMMAND_STOPPED // no child process or command execution + }; + + static std::unique_ptr CreateInstance(const std::vector &args); + + ~TrackedCommand(); + + bool CreateChildProcess(); + bool StartCommand(); + bool WaitCommand(int &wstatus); + void Stop(); + + inline std::string GetCommandName() + { + if (!command_.empty()) { + return command_[0]; + } + return EMPTY_STRING; + } + + inline State GetState() + { + return state_; + } + + inline pid_t GetChildPid() + { + return childPid_; + } + +private: + explicit TrackedCommand(const std::vector &args); + + bool InitSignalPipes(int &startFd, int &ackFd); + void ExecuteCommand(const int &startFd, const int &ackFd); + void MakeInvalid(); + + std::vector command_ {}; + int startFd_ {-1}; + int ackFd_ {-1}; + pid_t childPid_ {-1}; + State state_ {State::COMMAND_STOPPED}; +}; +} // namespace HiPerf +} // namespace Developtools +} // namespace OHOS +#endif // HIPERF_TRACKED_COMMAND_H_ diff --git a/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/utilities.h b/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/utilities.h new file mode 100644 index 0000000000000000000000000000000000000000..ce40061361d6e2fb69d181206ae879ae686be6f2 --- /dev/null +++ b/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/utilities.h @@ -0,0 +1,350 @@ +/* + * Copyright (c) 2021-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. + */ +#ifndef HIPERF_UTILITIES_H_ +#define HIPERF_UTILITIES_H_ + +// for security function +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#if !is_mingw +#include +#endif +#include + +#include "debug_logger.h" +#include "noncopyable.h" +#include "string_help.h" + +#ifndef __ASSEMBLY__ +/* + * __xx is ok: it doesn't pollute the POSIX namespace. Use these in the + * header files exported to user space + */ + +typedef __signed__ char __s8; +typedef unsigned char __u8; + +typedef __signed__ short __s16; +typedef unsigned short __u16; + +typedef __signed__ int __s32; +typedef unsigned int __u32; + +#ifdef __GNUC__ +__extension__ typedef __signed__ long long __s64; +__extension__ typedef unsigned long long __u64; +#else +typedef __signed__ long long __s64; +typedef unsigned long long __u64; +#endif + +#endif /* __ASSEMBLY__ */ + +// data and value +/* +long long always 64 only in ILP64, int is 64 otherwise int is always 32 +*/ +using s8 = __s8; +using u8 = __u8; +using s16 = __s16; +using u16 = __u16; +using s32 = __s32; +using u32 = __u32; +using s64 = __s64; +using u64 = __u64; + +constexpr const int NUMBER_FORMAT_HEX_BASE = 16; +constexpr const int BYTE_PRINT_WIDTH = 2; +constexpr const int UINT64_PRINT_WIDTH = BYTE_PRINT_WIDTH * 8; +constexpr const int BITS_OF_BYTE = 8; +constexpr const int BITS_OF_TWO_BYTE = 2 * BITS_OF_BYTE; +constexpr const int BITS_OF_FOUR_BYTE = 4 * BITS_OF_BYTE; +constexpr const int FULL_PERCENTAGE = 100; +constexpr const int FULL_PERCENTAGE_NUM_LEN = 5; // 100.00 +constexpr const int FULL_PERCENTAGE_DIFF_NUM_LEN = 6; // +100.00 +constexpr const int FULL_PERCENTAGE_LEN = 6; // 100.00% +constexpr const int FULL_PERCENTAGE_DIFF_LEN = 7; // +100.00% +constexpr const int THOUSANDS = 1000; +constexpr const int HUNDREDS = 100; +constexpr const int DEFAULT_STRING_BUF_SIZE = 4096; +constexpr const int FIVE_THOUSANDS = 5000; +#if !is_mingw +#ifndef O_BINARY +#define O_BINARY 0 +#endif +#endif + +constexpr const double MS_DUARTION = + static_cast(std::chrono::milliseconds::duration::period::den); + +constexpr uint64_t KILO = 1024; + +namespace OHOS { +namespace Developtools { +namespace HiPerf { +std::string CanonicalizeSpecPath(const char* src); +const std::string EMPTY_STRING = ""; +const ssize_t ERRINFOLEN = 512; + +// string function +class MemoryHold { +public: + ~MemoryHold() + { + Clean(); + } + const char *HoldStringView(std::string_view view); + // only use in UT + void Clean() + { + for (auto &p : holder_) { + delete[] p; + } + holder_.clear(); + } + static MemoryHold &Get() + { + static MemoryHold instance; + return instance; + } + +private: + std::vector holder_; +}; + +std::string StringReplace(std::string source, const std::string &from, const std::string &to); + +template +std::string VectorToString(const std::vector &items) +{ + if constexpr (std::is_same>::value) { + std::vector stringItems; + for (auto item : items) { + stringItems.push_back("[" + VectorToString(item) + "]"); + } + return VectorToString(stringItems); + } else { + std::string itemsString; + const std::string split = ","; + for (auto item : items) { + if (!itemsString.empty()) + itemsString.append(split); + if constexpr (std::is_same::value) { + itemsString.append(item); + } else { + itemsString.append(std::to_string(item)); + } + } + if (itemsString.empty()) + itemsString.append(""); + return itemsString; + } +} + +std::string BufferToHexString(const std::vector &vec); +std::string BufferToHexString(const unsigned char buf[], size_t size); +void HexDump(const void *buf, size_t size, size_t max_size = 0); + +std::string &StringTrim(std::string &s); + +std::vector StringSplit(std::string source, std::string split = ","); + +size_t SubStringCount(const std::string &source, const std::string &sub); + +bool StringStartsWith(const std::string &string, const std::string &with); + +bool StringEndsWith(const std::string &string, const std::string &with); + +bool IsSameCommand(const std::string &cmdLine, const std::string &cmdName); + +std::vector GetSubthreadIDs(const pid_t pid); + +bool IsDigits(const std::string &str); + +bool IsHexDigits(const std::string &str); + +constexpr const int COMPRESS_READ_BUF_SIZE = 4096; +// compress specified dataFile into gzip file +bool CompressFile(const std::string &dataFile, const std::string &destFile); +// uncompress specified gzip file into dataFile +bool UncompressFile(const std::string &gzipFile, const std::string &dataFile); + +template +std::string StringPrintf(const char *stringFormat, VA... args) +{ + // check howmany bytes we need + char bytes[DEFAULT_STRING_BUF_SIZE]; + bytes[DEFAULT_STRING_BUF_SIZE - 1] = '\0'; + + if (stringFormat == nullptr) { + return EMPTY_STRING; + } + + // print it to bytes + if (snprintf_s(bytes, sizeof(bytes), sizeof(bytes) - 1, stringFormat, + args...) < 0) { + return EMPTY_STRING; + } + + // make a string return + return std::string(bytes); +} + +// path check +std::vector GetEntriesInDir(const std::string &basePath); + +std::vector GetSubDirs(const std::string &basePath); + +bool IsDir(const std::string &path); + +bool IsPath(const std::string &fileName); + +#if is_mingw +const char PATH_SEPARATOR = '\\'; +#else +const char PATH_SEPARATOR = '/'; +#endif +const std::string PATH_SEPARATOR_STR = std::string(1, PATH_SEPARATOR); + +std::string PlatformPathConvert(const std::string &path); + +// attribute +#define PACKED __attribute__((packed)) + +// data align + +// some time u will meet signal 7 (SIGBUS), code 1 (BUS_ADRALN) in 32 or 64 arch cpu +#define HIPERF_BUF_ALIGN alignas(64) + +#define ALIGN(size, align) (((size) + (align) - 1) & (~((align) - 1))) + +uint32_t RoundUp(uint32_t x, const int align); + +// data convert function +template +std::string ToHex(const T &source, int size = sizeof(T), bool prefix = false) +{ + std::stringstream ss; + if (prefix) { + ss << "0x"; + } + ss << std::hex << std::setw(BYTE_PRINT_WIDTH * size) << std::setfill('0') << (uint64_t)source; + return ss.str(); +} + +// data move and copy +template +size_t inline CopyFromBufferAndMove(S *&buffer, T *dest, size_t size = 0) +{ + if (size == 0) { + size = sizeof(T); + } + if (memcpy_s(dest, size, buffer, size) != EOK) { + return size; + } + buffer = buffer + size; + return size; +} + +// file read write +bool ReadIntFromProcFile(const std::string &path, int &value); +bool WriteIntToProcFile(const std::string &path, int value); +std::string ReadFileToString(const std::string &fileName); +bool ReadFileToString(const std::string &fileName, std::string &content, size_t fileSize = 0); +bool WriteStringToFile(const std::string &fileName, const std::string &value); + +// stdout +class StdoutRecord { +public: + ~StdoutRecord() + { + Stop(); // stdout need restore + } + StdoutRecord(const std::string &tempFile = EMPTY_STRING, + const std::string &mode = EMPTY_STRING); + + bool Start(); + std::string Stop(); + +private: + OHOS::UniqueFd stdoutFile_; // back and restore stdout + std::FILE *recordFile_ = nullptr; // save the output + bool stop_ = true; + std::string content_ = EMPTY_STRING; +}; + +// misc +template +float Percentage(const T &a, const T &b) +{ + return static_cast(a) / static_cast(b) * FULL_PERCENTAGE; +} + +bool IsRoot(); +bool PowerOfTwo(uint64_t n); + +#define INDENT_ONE_LEVEL (indent + 1) +#define INDENT_TWO_LEVEL (indent + 2) + +#define PrintIndent(indent, format, ...) \ + if (indent >= 0) { \ + printf("%*s" format, (indent)*2, "", ##__VA_ARGS__); \ + } else { \ + HLOGV("%s" format, "", ##__VA_ARGS__); \ + } + +#ifndef MMAP_FAILED +#define MMAP_FAILED reinterpret_cast(-1) +#endif +#ifndef MAP_FAILED +#define MAP_FAILED MMAP_FAILED +#endif +} // namespace HiPerf +} // namespace Developtools +} // namespace OHOS + +// this will also used for libunwind head (out of namespace) +#if is_mingw +#if !is_double_framework +#define HAVE_MMAP 1 +#define MAP_PRIVATE 0x02 +#define PROT_NONE 0 +#define PROT_READ 1 +#define PROT_WRITE 2 +#define PROT_EXEC 4 +void *mmap(void *addr, size_t length, int prot, int flags, int fd, size_t offset); +int munmap(void *addr, size_t); +#endif +#endif + +#endif // HIPERF_UTILITIES_H_ diff --git a/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/virtual_runtime.h b/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/virtual_runtime.h new file mode 100644 index 0000000000000000000000000000000000000000..ff81c99eb24931a45328c1ca96054220b5ec1382 --- /dev/null +++ b/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/virtual_runtime.h @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2021-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. + */ +#ifndef HIPERF_VIRTUAL_RUNTIME_H +#define HIPERF_VIRTUAL_RUNTIME_H + +#include + +#include "callstack.h" +#include "perf_event_record.h" +#include "symbols_file.h" +#include "virtual_thread.h" + +namespace OHOS { +namespace Developtools { +namespace HiPerf { +/* +This Class contains userspace thread objects. and kernel space objects +It represents a virtual operating environment, mainly referring to the relationship between pid, +mmaps, and symbols. + +It mainly receives data is ip pointer (virtual address), pid +According to these data, it will find the corresponding mmap and its corresponding elf (also called +DSO) + +Then find the corresponding symbol in the corresponding elf symbol file according to the offset +recorded in the corresponding mmap. +*/ + +class VirtualRuntime { +public: + VirtualRuntime(bool onDevice = true); + + // thread need hook the record + // from the record , it will call back to write some Simulated Record + // case 1. some mmap will be create when it read mmaps for each new process (from record sample) + + using RecordCallBack = std::function)>; + void SetRecordMode(RecordCallBack recordCallBack); + + // this both used in report and record follow + // it process the record, and rebuild the trhread maps + // It internally determines whether to go to the Record process (which will generate virtual + // events) or the Report process by judging whether SetRecordMode has been passed. + void UpdateFromRecord(PerfEventRecord &reocrd); + + // in reocrd mode + // we make a kernel symbols from some proc file + void UpdateKernelSpaceMaps(); + void UpdateKernelModulesSpaceMaps(); + // load vdso + void LoadVdso(); + + void UpdateKernelSymbols(); + void UpdateKernelModulesSymbols(); + + // set symbols path , it will send to every symobile file for search + bool SetSymbolsPaths(const std::vector &symbolsPaths); + + // any mode + static_assert(sizeof(pid_t) == sizeof(int)); + + const std::vector> &GetSymbolsFiles() const + { + return symbolsFiles_; + } + + void SetCallStackExpend(size_t mergeLevel = 0) + { + callstackMergeLevel_ = mergeLevel; + } + + void SetDisableUnwind(bool disableUnwind) + { + HLOGV("disableUnwind change to %d", disableUnwind); + disableUnwind_ = disableUnwind; + } + + const Symbol GetSymbol(uint64_t ip, pid_t pid, pid_t tid, + const perf_callchain_context &context = PERF_CONTEXT_MAX); + + VirtualThread &GetThread(pid_t pid, pid_t tid); + const std::map &GetThreads() const + { + return userSpaceThreadMap_; + } + void SymbolicRecord(PerfRecordSample &recordSample); + + // report use + void UpdateFromPerfData(const std::vector &); + void UnwindFromRecord(PerfRecordSample &recordSample); + + // debug time +#ifdef HIPERF_DEBUG_TIME + std::chrono::microseconds updateSymbolsTimes_ = std::chrono::microseconds::zero(); + std::chrono::microseconds unwindFromRecordTimes_ = std::chrono::microseconds::zero(); + std::chrono::microseconds unwindCallStackTimes_ = std::chrono::microseconds::zero(); + std::chrono::microseconds symbolicRecordTimes_ = std::chrono::microseconds::zero(); + std::chrono::microseconds updateThreadTimes_ = std::chrono::microseconds::zero(); + std::chrono::microseconds prcessSampleRecordTimes_ = std::chrono::microseconds::zero(); + std::chrono::microseconds prcessMmapRecordTimes_ = std::chrono::microseconds::zero(); + std::chrono::microseconds prcessMmap2RecordTimes_ = std::chrono::microseconds::zero(); + std::chrono::microseconds prcessCommRecordTimes_ = std::chrono::microseconds::zero(); + std::chrono::microseconds threadParseMapsTimes_ = std::chrono::microseconds::zero(); + std::chrono::microseconds threadCreateMmapTimes_ = std::chrono::microseconds::zero(); +#endif + const bool loadSymboleWhenNeeded_ = true; // this is a feature config + +private: + bool disableUnwind_ = true; + size_t callstackMergeLevel_ = 1; + CallStack callstack_; + // pid map with user space thread + std::map userSpaceThreadMap_; + // not pid , just memmap + std::vector kernelSpaceMemMaps_; + RecordCallBack recordCallBack_; + std::vector> symbolsFiles_; + enum SymbolCacheLimit : std::size_t { + KERNEL_SYMBOL_CACHE_LIMIT = 4000, + THREAD_SYMBOL_CACHE_LIMIT = 2000, + }; + std::unordered_map> threadSymbolCache_; + HashList kernelSymbolCache_ {KERNEL_SYMBOL_CACHE_LIMIT}; + bool GetSymbolCache(uint64_t ip, pid_t pid, pid_t tid, Symbol &symbol, + const perf_callchain_context &context); + // find synbols function name + void MakeCallFrame(Symbol &symbol, CallFrame &callFrame); + // records + void UpdateSymbols(std::string filename); + void UpdateFromRecord(PerfRecordSample &recordSample); + void UpdateFromRecord(PerfRecordMmap &recordMmap); + void UpdateFromRecord(PerfRecordMmap2 &recordMmap2); + void UpdateFromRecord(PerfRecordComm &recordComm); + + // threads + VirtualThread &UpdateThread(pid_t pid, pid_t tid, const std::string name = ""); + std::string ReadThreadName(pid_t tid); + VirtualThread &CreateThread(pid_t pid, pid_t tid); + + // maps + void UpdateThreadMaps(pid_t pid, pid_t tid, const std::string filename, uint64_t begin, + uint64_t len, uint64_t offset); + void UpdatekernelMap(uint64_t begin, uint64_t end, uint64_t offset, std::string filename); + + const Symbol GetKernelSymbol(uint64_t ip, const std::vector &memMaps, + const VirtualThread &thread); + const Symbol GetUserSymbol(uint64_t ip, const VirtualThread &thread); +#ifdef HIPERF_DEBUG + std::unordered_set missedRuntimeVaddr_; +#endif + void SymbolicCallFrame(PerfRecordSample& recordSample, uint64_t ip, perf_callchain_context context); + std::vector symbolsPaths_; + friend class VirtualRuntimeTest; +}; +} // namespace HiPerf +} // namespace Developtools +} // namespace OHOS +#endif // HIPERF_VIRTUAL_RUNTIME_H diff --git a/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/virtual_thread.h b/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/virtual_thread.h new file mode 100644 index 0000000000000000000000000000000000000000..5c2c85f120304bfa44973f3e8d468927b2e52989 --- /dev/null +++ b/host/trace_streamer/src/parser/hiperf_parser/hiperf/include/virtual_thread.h @@ -0,0 +1,111 @@ +/* + * 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. + */ +#ifndef HIPERF_VIRTUAL_THREAD_H +#define HIPERF_VIRTUAL_THREAD_H + +#include +#include + +#include "debug_logger.h" +#include "mem_map_item.h" +#include "perf_event_record.h" +#include "symbols_file.h" + +namespace OHOS { +namespace Developtools { +namespace HiPerf { +/* +03284000-03289000 r--p 00000000 b3:05 289 /system/bin/sh +032b7000-032b9000 rw-p 00000000 00:00 0 +aff60000-aff96000 r--p 00000000 b3:05 923 /system/lib/libc++.so +affeb000-affed000 rw-p 00000000 00:00 0 +b0023000-b0024000 r--p 00000000 b3:05 959 /system/lib/libdl.so +*/ +const std::string MMAP_NAME_HEAP = "[heap]"; +const std::string MMAP_NAME_ANON = "[anon]"; + +class VirtualThread { +public: + VirtualThread(const VirtualThread &) = delete; + VirtualThread &operator=(const VirtualThread &) = delete; + + VirtualThread(pid_t pid, const std::vector> &symbolsFiles) + : pid_(pid), + tid_(pid), + symbolsFiles_(symbolsFiles), + processMemMaps_(), + memMaps_(processMemMaps_), + parent_(*this) {} + + VirtualThread(pid_t pid, pid_t tid, VirtualThread &thread, + const std::vector> &symbolsFiles) + : pid_(pid), + tid_(tid), + symbolsFiles_(symbolsFiles), + processMemMaps_(), + memMaps_(thread.processMemMaps_), + parent_(thread) + { + HLOG_ASSERT(pid != tid); + HLOGV("%d %d map from parent size is %zu", pid, tid, memMaps_.size()); + }; + + pid_t pid_; + pid_t tid_; + std::string name_; + + const std::vector &GetMaps() const + { + return memMaps_; + } + + void ParseMap(); + void CreateMapItem(const std::string filename, uint64_t begin, uint64_t len, uint64_t offset); + const MemMapItem *FindMapByAddr(uint64_t addr) const; + const MemMapItem *FindMapByAddr2(uint64_t addr) const; + const MemMapItem *FindMapByFileInfo(const std::string name, uint64_t offset) const; + SymbolsFile *FindSymbolsFileByMap(const MemMapItem &inMap) const; + bool ReadRoMemory(uint64_t vaddr, uint8_t *data, size_t size) const; +// #ifdef HIPERF_DEBUG + void ReportVaddrMapMiss(uint64_t vaddr) const; +// #endif + // caller want to check if new mmap is legal + static bool IsLegalFileName(const std::string &filename); + +private: + void SortMemMaps(); +#ifdef DEBUG_TIME + bool IsSorted() const; +#endif + const std::vector> &symbolsFiles_; + + // proc/xx/map + // use to put the parent thread's map + // only process have memmap + std::vector processMemMaps_; + // thread must use ref from process + std::vector &memMaps_; + VirtualThread &parent_; +#ifdef HIPERF_DEBUG + mutable std::unordered_set missedRuntimeVaddr_; +#endif +#ifdef DEBUG_MISS_SYMBOL + mutable std::vector missedSymbolFile_; +#endif +}; +} // namespace HiPerf +} // namespace Developtools +} // namespace OHOS +#endif // HIPERF_VIRTUAL_THREAD_H diff --git a/host/trace_streamer/src/parser/hiperf_parser/hiperf/linux/file_ex.h b/host/trace_streamer/src/parser/hiperf_parser/hiperf/linux/file_ex.h new file mode 100644 index 0000000000000000000000000000000000000000..65ae00ab25b7c280d7942f7ba7226847cff0d2c9 --- /dev/null +++ b/host/trace_streamer/src/parser/hiperf_parser/hiperf/linux/file_ex.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2021 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. + */ + +#ifndef UTILS_BASE_FILE_EX_H +#define UTILS_BASE_FILE_EX_H + +#include +#include + +namespace OHOS { +bool LoadStringFromFile(const std::string& filePath, std::string& content); +bool SaveStringToFile(const std::string& filePath, const std::string& content, bool truncated = true); +bool LoadStringFromFd(int fd, std::string& content); +bool SaveStringToFd(int fd, const std::string& content); +bool LoadBufferFromFile(const std::string& filePath, std::vector& content); +bool SaveBufferToFile(const std::string& filePath, const std::vector& content, bool truncated = true); +bool FileExists(const std::string& fileName); +bool StringExistsInFile(const std::string& fileName, const std::string& subStr, bool caseSensitive = true); +int CountStrInFile(const std::string& fileName, const std::string& subStr, bool caseSensitive = true); +} + +#endif diff --git a/host/trace_streamer/src/parser/hiperf_parser/hiperf/linux/securec.h b/host/trace_streamer/src/parser/hiperf_parser/hiperf/linux/securec.h new file mode 100644 index 0000000000000000000000000000000000000000..8d83e4417de290dff0a93ad431dcb8df977deee6 --- /dev/null +++ b/host/trace_streamer/src/parser/hiperf_parser/hiperf/linux/securec.h @@ -0,0 +1,564 @@ +/* + * Copyright (c) 2021 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. + */ + +#ifndef __SECUREC_H__5D13A042_DC3F_4ED9_A8D1_882811274C27 +#define __SECUREC_H__5D13A042_DC3F_4ED9_A8D1_882811274C27 + +/* Compile in kernel under macro control */ +#ifndef SECUREC_IN_KERNEL +#ifdef __KERNEL__ +#define SECUREC_IN_KERNEL 1 +#else +#define SECUREC_IN_KERNEL 0 +#endif +#endif + +/* If you need high performance, enable the SECUREC_WITH_PERFORMANCE_ADDONS macro, default is enable . + * The macro is automatically closed on the windows platform in securectyp.h. + */ +#ifndef SECUREC_WITH_PERFORMANCE_ADDONS +#if SECUREC_IN_KERNEL +#define SECUREC_WITH_PERFORMANCE_ADDONS 0 +#else +#define SECUREC_WITH_PERFORMANCE_ADDONS 1 +#endif +#endif + +#include +#include "securectype.h" + +#ifndef SECUREC_HAVE_ERRNO_H +#if SECUREC_IN_KERNEL +#define SECUREC_HAVE_ERRNO_H 0 +#else +#define SECUREC_HAVE_ERRNO_H 1 +#endif +#endif + +/* EINVAL ERANGE may defined in errno.h */ +#if SECUREC_HAVE_ERRNO_H +#include +#endif + +/* If stack size on some embedded platform is limited, you can define the following macro + * which will put some variables on heap instead of stack. + * SECUREC_STACK_SIZE_LESS_THAN_1K + */ + +/* define error code */ +#if !defined(__STDC_WANT_LIB_EXT1__) || (defined(__STDC_WANT_LIB_EXT1__) && (__STDC_WANT_LIB_EXT1__ == 0)) +#ifndef SECUREC_DEFINED_ERRNO_TYPE +#define SECUREC_DEFINED_ERRNO_TYPE +/* just check whether macrodefinition exists. */ +#ifndef errno_t +typedef int errno_t; +#endif +#endif +#endif + +/* success */ +#ifndef EOK +#define EOK (0) +#endif + +#ifndef EINVAL +/* The src buffer is not correct and destination buffer can't not be reset */ +#define EINVAL (22) +#endif + +#ifndef EINVAL_AND_RESET +/* Once the error is detected, the dest buffer must be rest! */ +#define EINVAL_AND_RESET (22 | 128) +#endif + +#ifndef ERANGE +/* The destination buffer is not long enough and destination buffer can not be reset */ +#define ERANGE (34) +#endif + +#ifndef ERANGE_AND_RESET +/* Once the error is detected, the dest buffer must be rest! */ +#define ERANGE_AND_RESET (34 | 128) +#endif + +#ifndef EOVERLAP_AND_RESET +/* Once the buffer overlap is detected, the dest buffer must be rest! */ +#define EOVERLAP_AND_RESET (54 | 128) +#endif + +/* if you need export the function of this library in Win32 dll, use __declspec(dllexport) */ +#ifdef SECUREC_IS_DLL_LIBRARY +#ifdef SECUREC_DLL_EXPORT +#define SECUREC_API __declspec(dllexport) +#else +#define SECUREC_API __declspec(dllimport) +#endif +#else +/* Standardized function declaration . If a security function is declared in the your code, + * it may cause a compilation alarm,Please delete the security function you declared + */ +#define SECUREC_API extern +#endif + +#ifndef SECUREC_SNPRINTF_TRUNCATED +#define SECUREC_SNPRINTF_TRUNCATED 1 +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @Description:The memset_s function copies the value of c (converted to an unsigned char) into each of the first count + * characters of the object pointed to by dest. + * @param dest - destination address + * @param destMax -The maximum length of destination buffer + * @param c - the value to be copied + * @param count -copies first count characters of dest + * @return EOK if there was no runtime-constraint violation + */ + +/* The memset_s security function is not provided in Windows system, but other security functions are provided. In this + * case, can only use the memset_s function */ +#ifndef SECUREC_ONLY_DECLARE_MEMSET + +/** + * @Description:The wmemcpy_s function copies n successive wide characters from the object pointed to by src into the + * object pointed to by dest. + * @param dest - destination address + * @param destMax -The maximum length of destination buffer + * @param src -source address + * @param count -copies count wide characters from the src + * @return EOK if there was no runtime-constraint violation + */ +#if SECUREC_IN_KERNEL == 0 + SECUREC_API errno_t wmemcpy_s(wchar_t *dest, size_t destMax, const wchar_t *src, size_t count); +#endif + /** + * @Description:The memmove_s function copies n characters from the object pointed to by src into the object pointed + * to by dest. + * @param dest - destination address + * @param destMax -The maximum length of destination buffer + * @param src -source address + * @param count -copies count wide characters from the src + * @return EOK if there was no runtime-constraint violation + */ + SECUREC_API errno_t memmove_s(void *dest, size_t destMax, const void *src, size_t count); +#if SECUREC_IN_KERNEL == 0 + /** + * @Description:The wmemmove_s function copies n successive wide characters from the object pointed to by src into + * the object pointed to by dest. + * @param dest - destination address + * @param destMax -The maximum length of destination buffer + * @param src -source address + * @param count -copies count wide characters from the src + * @return EOK if there was no runtime-constraint violation + */ + SECUREC_API errno_t wmemmove_s(wchar_t *dest, size_t destMax, const wchar_t *src, size_t count); + + /** + * @Description:The wcscpy_s function copies the wide string pointed to by strSrc (including theterminating null + * wide character) into the array pointed to by strDest + * @param strDest - destination address + * @param destMax -The maximum length of destination buffer + * @param strSrc -source address + * @return EOK if there was no runtime-constraint violation + */ + SECUREC_API errno_t wcscpy_s(wchar_t *strDest, size_t destMax, const wchar_t *strSrc); + + /** + * @Description:The wcsncpy_s function copies not more than n successive wide characters (not including the + * terminating null wide character) from the array pointed to by strSrc to the array pointed to by strDest + * @param strDest - destination address + * @param destMax -The maximum length of destination buffer(including the terminating wide character) + * @param strSrc -source address + * @param count -copies count wide characters from the src + * @return EOK if there was no runtime-constraint violation + */ + SECUREC_API errno_t wcsncpy_s(wchar_t *strDest, size_t destMax, const wchar_t *strSrc, size_t count); + + /** + * @Description:The wcscat_s function appends a copy of the wide string pointed to by strSrc (including the + * terminating null wide character) to the end of the wide string pointed to by strDest + * @param strDest - destination address + * @param destMax -The maximum length of destination buffer(including the terminating wide character) + * @param strSrc -source address + * @return EOK if there was no runtime-constraint violation + */ + SECUREC_API errno_t wcscat_s(wchar_t *strDest, size_t destMax, const wchar_t *strSrc); + + /** + * @Description:The wcsncat_s function appends not more than n successive wide characters (not including the + * terminating null wide character) from the array pointed to by strSrc to the end of the wide string pointed to by + * strDest. + * @param strDest - destination address + * @param destMax -The maximum length of destination buffer(including the terminating wide character) + * @param strSrc -source address + * @param count -copies count wide characters from the src + * @return EOK if there was no runtime-constraint violation + */ + SECUREC_API errno_t wcsncat_s(wchar_t *strDest, size_t destMax, const wchar_t *strSrc, size_t count); + + /** + * @Description: The strtok_s function parses a string into a sequence of tokens,On the first call to strtok_s the + * string to be parsed should be specified in strToken. In each subsequent call that should parse the same string, + * strToken should be NULL + * @param strToken - the string to be delimited + * @param strDelimit -specifies a set of characters that delimit the tokens in the parsed string + * @param context -is a pointer to a char * variable that is used internally by strtok_s function + * @return:returns a pointer to the first character of a token, or a null pointer if there is no token or there is a + * runtime-constraint violation. + */ + SECUREC_API char *strtok_s(char *strToken, const char *strDelimit, char **context); + + /** + * @Description: The wcstok_s function is the wide-character equivalent of the strtok_s function + * @param strToken - the string to be delimited + * @param strDelimit -specifies a set of characters that delimit the tokens in the parsed string + * @param context -is a pointer to a char * variable that is used internally by strtok_s function + * @return:returns a pointer to the first character of a token, or a null pointer if there is no token or there is a + * runtime-constraint violation. + */ + SECUREC_API wchar_t *wcstok_s(wchar_t *strToken, const wchar_t *strDelimit, wchar_t **context); + + /** + * @Description: The sprintf_s function is equivalent to the sprintf function except for the parameter destMax and + * the explicit runtime-constraints violation + * @param strDest - produce output according to a format ,write to the character string strDest + * @param destMax - The maximum length of destination buffer(including the terminating null byte ('\0')) + * @param format - format string + * @return:success the number of characters printed(not including the terminating null byte ('\0')), If an error + * occurred return -1. + */ + + /** + * @Description: The swprintf_s function is the wide-character equivalent of the sprintf_s function + * @param strDest - produce output according to a format ,write to the character string strDest + * @param destMax - The maximum length of destination buffer(including the terminating null ) + * @param format - format string + * @return:success the number of characters printed(not including the terminating null wide characte), If an error + * occurred return -1. + */ + SECUREC_API int swprintf_s(wchar_t *strDest, size_t destMax, const wchar_t *format, ...); + + /** + * @Description: The vsprintf_s function is equivalent to the vsprintf function except for the parameter destMax and + * the explicit runtime-constraints violation + * @param strDest - produce output according to a format ,write to the character string strDest + * @param destMax - The maximum length of destination buffer(including the terminating null wide characte) + * @param format - format string + * @param arglist - instead of a variable number of arguments + * @return:return the number of characters printed(not including the terminating null byte ('\0')), If an error + * occurred return -1. + */ + SECUREC_API int vsprintf_s(char* strDest, size_t destMax, const char* format, va_list arglist) + SECUREC_ATTRIBUTE(3, 0); + + /** + * @Description: The vswprintf_s function is the wide-character equivalent of the vsprintf_s function + * @param strDest - produce output according to a format ,write to the character string strDest + * @param destMax - The maximum length of destination buffer(including the terminating null ) + * @param format - format string + * @param arglist - instead of a variable number of arguments + * @return:return the number of characters printed(not including the terminating null wide characte), If an error + * occurred return -1. + */ + SECUREC_API int vswprintf_s(wchar_t *strDest, size_t destMax, const wchar_t *format, va_list arglist); + + /** + * @Description: The vsnprintf_s function is equivalent to the vsnprintf function except for the parameter + * destMax/count and the explicit runtime-constraints violation + * @param strDest - produce output according to a format ,write to the character string strDest + * @param destMax - The maximum length of destination buffer(including the terminating null byte ('\0')) + * @param count - do not write more than count bytes to strDest(not including the terminating null byte ('\0')) + * @param format - format string + * @param arglist - instead of a variable number of arguments + * @return:return the number of characters printed(not including the terminating null byte ('\0')), If an error + * occurred return -1.Pay special attention to returning -1 when truncation occurs + */ + SECUREC_API int vsnprintf_s(char* strDest, size_t destMax, size_t count, const char* format, va_list arglist) + SECUREC_ATTRIBUTE(4, 0); + + /** + * @Description: The snprintf_s function is equivalent to the snprintf function except for the parameter + * destMax/count and the explicit runtime-constraints violation + * @param strDest - produce output according to a format ,write to the character string strDest + * @param destMax - The maximum length of destination buffer(including the terminating null byte ('\0')) + * @param count - do not write more than count bytes to strDest(not including the terminating null byte ('\0')) + * @param format - format string + * @return:return the number of characters printed(not including the terminating null byte ('\0')), If an error + * occurred return -1.Pay special attention to returning -1 when truncation occurs + */ + +#if SECUREC_SNPRINTF_TRUNCATED + /** + * @Description: The vsnprintf_truncated_s function is equivalent to the vsnprintf_s function except no count + * parameter and return value + * @param strDest - produce output according to a format ,write to the character string strDest + * @param destMax - The maximum length of destination buffer(including the terminating null byte ('\0')) + * @param format - format string + * @param arglist - instead of a variable number of arguments + * @return:return the number of characters printed(not including the terminating null byte ('\0')), If an error + * occurred return -1.Pay special attention to returning destMax - 1 when truncation occurs + */ + SECUREC_API int vsnprintf_truncated_s(char* strDest, size_t destMax, const char* format, va_list arglist) + SECUREC_ATTRIBUTE(3, 0); + + /** + * @Description: The snprintf_truncated_s function is equivalent to the snprintf_2 function except no count + * parameter and return value + * @param strDest - produce output according to a format ,write to the character string strDest + * @param destMax - The maximum length of destination buffer(including the terminating null byte ('\0')) + * @param format - format string + * @return:return the number of characters printed(not including the terminating null byte ('\0')), If an error + * occurred return -1.Pay special attention to returning destMax - 1 when truncation occurs + */ + SECUREC_API int snprintf_truncated_s(char* strDest, size_t destMax, const char* format, ...) + SECUREC_ATTRIBUTE(3, 4); +#endif + /** + * @Description: The scanf_s function is equivalent to fscanf_s with the argument stdin interposed before the + * arguments to scanf_s + * @param format - format string + * @return:returns the number of input items assigned, If an error occurred return -1. + */ + SECUREC_API int scanf_s(const char *format, ...); + + /** + * @Description: The wscanf_s function is the wide-character equivalent of the scanf_s function + * @param format - format string + * @return:returns the number of input items assigned, If an error occurred return -1. + */ + SECUREC_API int wscanf_s(const wchar_t *format, ...); + + /** + * @Description: The vscanf_s function is equivalent to scanf_s, with the variable argument list replaced by arglist + * @param format - format string + * @param arglist - instead of a variable number of arguments + * @return:returns the number of input items assigned, If an error occurred return -1. + */ + SECUREC_API int vscanf_s(const char *format, va_list arglist); + + /** + * @Description: The vwscanf_s function is the wide-character equivalent of the vscanf_s function + * @param format - format string + * @param arglist - instead of a variable number of arguments + * @return:returns the number of input items assigned, If an error occurred return -1. + */ + SECUREC_API int vwscanf_s(const wchar_t *format, va_list arglist); + + /** + * @Description: The fscanf_s function is equivalent to fscanf except that the c, s, and [ conversion specifiers + * apply to a pair of arguments (unless assignment suppression is indicated by a*) + * @param stream - stdio file stream + * @param format - format string + * @return:returns the number of input items assigned, If an error occurred return -1. + */ + SECUREC_API int fscanf_s(FILE *stream, const char *format, ...); + + /** + * @Description: The fwscanf_s function is the wide-character equivalent of the fscanf_s function + * @param stream - stdio file stream + * @param format - format string + * @return:returns the number of input items assigned, If an error occurred return -1. + */ + SECUREC_API int fwscanf_s(FILE *stream, const wchar_t *format, ...); + + /** + * @Description: The vfscanf_s function is equivalent to fscanf_s, with the variable argument list replaced by + * arglist + * @param stream - stdio file stream + * @param format - format string + * @param arglist - instead of a variable number of arguments + * @return:returns the number of input items assigned, If an error occurred return -1. + */ + SECUREC_API int vfscanf_s(FILE *stream, const char *format, va_list arglist); + + /** + * @Description: The vfwscanf_s function is the wide-character equivalent of the vfscanf_s function + * @param stream - stdio file stream + * @param format - format string + * @param arglist - instead of a variable number of arguments + * @return:returns the number of input items assigned, If an error occurred return -1. + */ + SECUREC_API int vfwscanf_s(FILE *stream, const wchar_t *format, va_list arglist); + + /** + * @Description: The sscanf_s function is equivalent to fscanf_s, except that input is obtained from a string + * (specified by the argument buffer) rather than from a stream + * @param buffer - read character from buffer + * @param format - format string + * @return:returns the number of input items assigned, If an error occurred return -1. + */ + + /** + * @Description: The swscanf_s function is the wide-character equivalent of the sscanf_s function + * @param buffer - read character from buffer + * @param format - format string + * @return:returns the number of input items assigned, If an error occurred return -1. + */ + SECUREC_API int swscanf_s(const wchar_t *buffer, const wchar_t *format, ...); + + /** + * @Description: The vsscanf_s function is equivalent to sscanf_s, with the variable argument list replaced by + * arglist + * @param buffer - read character from buffer + * @param format - format string + * @param arglist - instead of a variable number of arguments + * @return:returns the number of input items assigned, If an error occurred return -1. + */ + SECUREC_API int vsscanf_s(const char *buffer, const char *format, va_list arglist); + + /** + * @Description: The vswscanf_s function is the wide-character equivalent of the vsscanf_s function + * @param buffer - read character from buffer + * @param format - format string + * @param arglist - instead of a variable number of arguments + * @return:returns the number of input items assigned, If an error occurred return -1. + */ + SECUREC_API int vswscanf_s(const wchar_t *buffer, const wchar_t *format, va_list arglist); + + /** + * @Description:The gets_s function reads at most one less than the number of characters specified by destMax from + * the stream pointed to by stdin, into the array pointed to by buffer + * @param buffer - destination address + * @param destMax -The maximum length of destination buffer(including the terminating null character) + * @return buffer if there was no runtime-constraint violation,If an error occurred return NULL. + */ + SECUREC_API char *gets_s(char *buffer, size_t destMax); +#endif + + /** + * @Description:The memcpy_s function copies n characters from the object pointed to by src into the object pointed + * to by dest. + * @param dest - destination address + * @param destMax -The maximum length of destination buffer + * @param src -source address + * @param count -copies count characters from the src + * @return EOK if there was no runtime-constraint violation + */ + + /** + * @Description:The strcpy_s function copies the string pointed to by strSrc (including the terminating null + * character) into the array pointed to by strDest + * @param strDest - destination address + * @param destMax -The maximum length of destination buffer(including the terminating null character) + * @param strSrc -source address + * @return EOK if there was no runtime-constraint violation + */ + SECUREC_API errno_t strcpy_s(char *strDest, size_t destMax, const char *strSrc); + + /** + * @Description:The strncpy_s function copies not more than n successive characters (not including the terminating + * null character) from the array pointed to by strSrc to the array pointed to by strDest + * @param strDest - destination address + * @param destMax -The maximum length of destination buffer(including the terminating null character) + * @param strSrc -source address + * @param count -copies count characters from the src + * @return EOK if there was no runtime-constraint violation + */ + + /** + * @Description:The strcat_s function appends a copy of the string pointed to by strSrc (including the terminating + * null character) to the end of the string pointed to by strDest + * @param strDest - destination address + * @param destMax -The maximum length of destination buffer(including the terminating null wide character) + * @param strSrc -source address + * @return EOK if there was no runtime-constraint violation + */ + SECUREC_API errno_t strcat_s(char *strDest, size_t destMax, const char *strSrc); + + /** + * @Description:The strncat_s function appends not more than n successive characters (not including the terminating + * null character) from the array pointed to by strSrc to the end of the string pointed to by strDest. + * @param strDest - destination address + * @param destMax -The maximum length of destination buffer(including the terminating null character) + * @param strSrc -source address + * @param count -copies count characters from the src + * @return EOK if there was no runtime-constraint violation + */ + SECUREC_API errno_t strncat_s(char *strDest, size_t destMax, const char *strSrc, size_t count); +#if SECUREC_IN_KERNEL == 0 + /* those functions are used by macro ,must declare hare , also for without function declaration warning */ + extern errno_t strncpy_error(char *strDest, size_t destMax, const char *strSrc, size_t count); + extern errno_t strcpy_error(char *strDest, size_t destMax, const char *strSrc); +#endif +#endif + +#if SECUREC_WITH_PERFORMANCE_ADDONS + /* those functions are used by macro */ + extern errno_t memset_sOptAsm(void *dest, size_t destMax, int c, size_t count); + extern errno_t memset_sOptTc(void *dest, size_t destMax, int c, size_t count); + extern errno_t memcpy_sOptAsm(void *dest, size_t destMax, const void *src, size_t count); + extern errno_t memcpy_sOptTc(void *dest, size_t destMax, const void *src, size_t count); + +/* strcpy_sp is a macro, NOT a function in performance optimization mode. */ +#define strcpy_sp(dest, destMax, src) ((__builtin_constant_p((destMax)) && \ + __builtin_constant_p((src))) ? \ + SECUREC_STRCPY_SM((dest), (destMax), (src)) : \ + strcpy_s((dest), (destMax), (src))) + +/* strncpy_sp is a macro, NOT a function in performance optimization mode. */ +#define strncpy_sp(dest, destMax, src, count) ((__builtin_constant_p((count)) && \ + __builtin_constant_p((destMax)) && \ + __builtin_constant_p((src))) ? \ + SECUREC_STRNCPY_SM((dest), (destMax), (src), (count)) : \ + strncpy_s((dest), (destMax), (src), (count))) + +/* strcat_sp is a macro, NOT a function in performance optimization mode. */ +#define strcat_sp(dest, destMax, src) ((__builtin_constant_p((destMax)) && \ + __builtin_constant_p((src))) ? \ + SECUREC_STRCAT_SM((dest), (destMax), (src)) : \ + strcat_s((dest), (destMax), (src))) + + /* strncat_sp is a macro, NOT a function in performance optimization mode. */ +#define strncat_sp(dest, destMax, src, count) ((__builtin_constant_p((count)) && \ + __builtin_constant_p((destMax)) && \ + __builtin_constant_p((src))) ? \ + SECUREC_STRNCAT_SM((dest), (destMax), (src), (count)) : \ + strncat_s((dest), (destMax), (src), (count))) + +/* memcpy_sp is a macro, NOT a function in performance optimization mode. */ +#define memcpy_sp(dest, destMax, src, count) (__builtin_constant_p((count)) ? \ + (SECUREC_MEMCPY_SM((dest), (destMax), (src), (count))) : \ + (__builtin_constant_p((destMax)) ? \ + (((size_t)(destMax) > 0 && \ + (((unsigned long long)(destMax) & \ + (unsigned long long)(-2)) < SECUREC_MEM_MAX_LEN)) ? \ + memcpy_sOptTc((dest), (destMax), (src), (count)) : ERANGE ) : \ + memcpy_sOptAsm((dest), (destMax), (src), (count)))) + +/* memset_sp is a macro, NOT a function in performance optimization mode. */ +#define memset_sp(dest, destMax, c, count) (__builtin_constant_p((count)) ? \ + (SECUREC_MEMSET_SM((dest), (destMax), (c), (count))) : \ + (__builtin_constant_p((destMax)) ? \ + (((size_t)(destMax) > 0 && \ + (((unsigned long long)(destMax) & \ + (unsigned long long)(-2)) < SECUREC_MEM_MAX_LEN)) ? \ + memset_sOptTc((dest), (destMax), (c), (count)) : ERANGE ) : \ + memset_sOptAsm((dest), (destMax), (c), (count)))) +#else +#define strcpy_sp strcpy_s +#define strncpy_sp strncpy_s +#define strcat_sp strcat_s +#define strncat_sp strncat_s +#define memcpy_sp memcpy_s +#define memset_sp memset_s +#endif + +#ifdef __cplusplus +} +#endif /* __cplusplus */ +#endif /* __SECUREC_H__5D13A042_DC3F_4ED9_A8D1_882811274C27 */ diff --git a/host/trace_streamer/src/parser/hiperf_parser/hiperf/linux/securectype.h b/host/trace_streamer/src/parser/hiperf_parser/hiperf/linux/securectype.h new file mode 100644 index 0000000000000000000000000000000000000000..df57d99fdfe3b7d0d4635521ef61aabb2893def3 --- /dev/null +++ b/host/trace_streamer/src/parser/hiperf_parser/hiperf/linux/securectype.h @@ -0,0 +1,281 @@ +/* + * Copyright (c) 2021 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. + */ +/* [Standardize-exceptions]: Performance-sensitive + * [reason]: Strict parameter verification has been done before use + */ + +#ifndef __SECURECTYPE_H__A7BBB686_AADA_451B_B9F9_44DACDAE18A7 +#define __SECURECTYPE_H__A7BBB686_AADA_451B_B9F9_44DACDAE18A7 + +#ifndef SECUREC_ONLY_DECLARE_MEMSET +/* Shielding VC symbol redefinition warning */ +#if defined(_MSC_VER) && (_MSC_VER >= 1400) +#ifdef __STDC_WANT_SECURE_LIB__ +#undef __STDC_WANT_SECURE_LIB__ +#endif +#define __STDC_WANT_SECURE_LIB__ 0 +#ifdef _CRTIMP_ALTERNATIVE +#undef _CRTIMP_ALTERNATIVE +#endif +#define _CRTIMP_ALTERNATIVE // comment microsoft *_s function +#endif +#endif + +#if SECUREC_IN_KERNEL +#include +#include +#else +#include +#include +#include +#endif + +/* if enable SECUREC_COMPATIBLE_WIN_FORMAT, the output format will be compatible to Windows. */ +#if (defined(_WIN32) || defined(_WIN64) || defined(_MSC_VER)) +#define SECUREC_COMPATIBLE_WIN_FORMAT +#endif + +#if defined(SECUREC_COMPATIBLE_WIN_FORMAT) +/* in windows platform, can't use optimized function for there is no __builtin_constant_p like function */ +/* If need optimized macro, can define this: define __builtin_constant_p(x) 0 */ +#ifdef SECUREC_WITH_PERFORMANCE_ADDONS +#undef SECUREC_WITH_PERFORMANCE_ADDONS +#define SECUREC_WITH_PERFORMANCE_ADDONS 0 +#endif +#endif + +#if defined(__VXWORKS__) || defined(__vxworks) || defined(__VXWORKS) || defined(_VXWORKS_PLATFORM_) || \ + defined(SECUREC_VXWORKS_VERSION_5_4) +#if !defined(SECUREC_VXWORKS_PLATFORM) +#define SECUREC_VXWORKS_PLATFORM +#endif +#endif + +/* if enable SECUREC_COMPATIBLE_LINUX_FORMAT, the output format will be compatible to Linux. */ +#if !(defined(SECUREC_COMPATIBLE_WIN_FORMAT) || defined(SECUREC_VXWORKS_PLATFORM)) +#define SECUREC_COMPATIBLE_LINUX_FORMAT +#endif +#ifdef SECUREC_COMPATIBLE_LINUX_FORMAT +#include +#endif + +/* add the -DSECUREC_SUPPORT_FORMAT_WARNING compiler option to supoort -Wformat. + * default does not check the format is that the same data type in the actual code + * in the product is different in the original data type definition of VxWorks and Linux. + */ +#ifndef SECUREC_SUPPORT_FORMAT_WARNING +#define SECUREC_SUPPORT_FORMAT_WARNING 0 +#endif + +/* SECUREC_PCLINT for tool do not recognize __attribute__ just for pclint */ +#if SECUREC_SUPPORT_FORMAT_WARNING && !defined(SECUREC_PCLINT) +#define SECUREC_ATTRIBUTE(x, y) __attribute__((format(printf, (x), (y)))) +#else +#define SECUREC_ATTRIBUTE(x, y) +#endif + +/* SECUREC_PCLINT for tool do not recognize __builtin_expect ,just for pclint */ +#if defined(__GNUC__) && \ + ((__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 3))) && /* above 3.4 */ \ + !defined(SECUREC_PCLINT) +/* This is a built-in function that can be used without a declaration, if you encounter an undeclared compilation alarm, + * you can add -DSECUREC_NEED_BUILTIN_EXPECT_DECLARE to compiler options + */ +#if defined(SECUREC_NEED_BUILTIN_EXPECT_DECLARE) +long __builtin_expect(long exp, long c); +#endif +#define SECUREC_LIKELY(x) __builtin_expect(!!(x), 1) +#define SECUREC_UNLIKELY(x) __builtin_expect(!!(x), 0) +#else +#define SECUREC_LIKELY(x) (x) +#define SECUREC_UNLIKELY(x) (x) +#endif + +/* define the max length of the string */ +#define SECUREC_STRING_MAX_LEN (0x7fffffffUL) +#define SECUREC_WCHAR_STRING_MAX_LEN (SECUREC_STRING_MAX_LEN / sizeof(wchar_t)) + +/* add SECUREC_MEM_MAX_LEN for memcpy and memmove */ +#define SECUREC_MEM_MAX_LEN (0x7fffffffUL) +#define SECUREC_WCHAR_MEM_MAX_LEN (SECUREC_MEM_MAX_LEN / sizeof(wchar_t)) + +#if SECUREC_STRING_MAX_LEN > 0x7fffffff +#error "max string is 2G" +#endif + +#if (defined(__GNUC__ ) && defined(__SIZEOF_POINTER__ )) +#if (__SIZEOF_POINTER__ != 4) && (__SIZEOF_POINTER__ != 8) +#error "unsupported system" +#endif +#endif + +#ifndef SECUREC_MALLOC +#define SECUREC_MALLOC(x) malloc((size_t)(x)) +#endif + +#ifndef SECUREC_FREE +#define SECUREC_FREE(x) free((void *)(x)) +#endif + +#if defined(_WIN64) || defined(WIN64) || defined(__LP64__) || defined(_LP64) +#define SECUREC_ON_64BITS +#endif + +#if (!defined(SECUREC_ON_64BITS) && defined(__GNUC__ ) && defined(__SIZEOF_POINTER__ )) +#if __SIZEOF_POINTER__ == 8 +#define SECUREC_ON_64BITS +#endif +#endif + +#if defined(__SVR4) || defined(__svr4__) +#define SECUREC_ON_SOLARIS +#endif + +#if (defined(__hpux) || defined(_AIX) || defined(SECUREC_ON_SOLARIS)) +#define SECUREC_ON_UNIX +#endif + +/* codes should run under the macro SECUREC_COMPATIBLE_LINUX_FORMAT in unknown system on default, + * and strtold. The function + * strtold is referenced first at ISO9899:1999(C99), and some old compilers can + * not support these functions. Here provides a macro to open these functions: + * SECUREC_SUPPORT_STRTOLD -- if defined, strtold will be used + */ +#ifndef SECUREC_SUPPORT_STRTOLD +#define SECUREC_SUPPORT_STRTOLD 0 +#if (defined(SECUREC_COMPATIBLE_LINUX_FORMAT)) +#if defined(__USE_ISOC99) || \ + (defined(_AIX) && defined(_ISOC99_SOURCE)) || \ + (defined(__hpux) && defined(__ia64)) || \ + (defined(SECUREC_ON_SOLARIS) && (!defined(_STRICT_STDC) && !defined(__XOPEN_OR_POSIX)) || \ + defined(_STDC_C99) || defined(__EXTENSIONS__)) +#undef SECUREC_SUPPORT_STRTOLD +#define SECUREC_SUPPORT_STRTOLD 1 +#endif +#endif +#if ((defined(SECUREC_WRLINUX_BELOW4) || defined(_WRLINUX_BELOW4_))) +#undef SECUREC_SUPPORT_STRTOLD +#define SECUREC_SUPPORT_STRTOLD 0 +#endif +#endif + +#if SECUREC_WITH_PERFORMANCE_ADDONS + +#ifndef SECUREC_TWO_MIN +#define SECUREC_TWO_MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif + +/* for strncpy_s performance optimization */ +#define SECUREC_STRNCPY_SM(dest, destMax, src, count) \ + (((void*)dest != NULL && (void*)src != NULL && (size_t)destMax > 0 && \ + (((unsigned long long)(destMax) & (unsigned long long)(-2)) < SECUREC_STRING_MAX_LEN) && \ + (SECUREC_TWO_MIN(count, strlen(src)) + 1) <= (size_t)destMax) \ + ? ((count < strlen(src)) ? (memcpy(dest, src, count), *((char*)dest + count) = '\0', EOK) \ + : (memcpy(dest, src, strlen(src) + 1), EOK)) \ + : (strncpy_error(dest, destMax, src, count))) + +#define SECUREC_STRCPY_SM(dest, destMax, src) \ + (((void*)dest != NULL && (void*)src != NULL && (size_t)destMax > 0 && \ + (((unsigned long long)(destMax) & (unsigned long long)(-2)) < SECUREC_STRING_MAX_LEN) && \ + (strlen(src) + 1) <= (size_t)destMax) \ + ? (memcpy(dest, src, strlen(src) + 1), EOK) \ + : (strcpy_error(dest, destMax, src))) + +/* for strcat_s performance optimization */ +#if defined(__GNUC__) +#define SECUREC_STRCAT_SM(dest, destMax, src) \ + ({ \ + int catRet = EOK; \ + if ((void*)dest != NULL && (void*)src != NULL && (size_t)(destMax) > 0 && \ + (((unsigned long long)(destMax) & (unsigned long long)(-2)) < SECUREC_STRING_MAX_LEN)) { \ + char* catTmpDst = (dest); \ + size_t catRestSize = (destMax); \ + while (catRestSize > 0 && *catTmpDst) { \ + ++catTmpDst; \ + --catRestSize; \ + } \ + if (catRestSize == 0) { \ + catRet = EINVAL; \ + } else if ((strlen(src) + 1) <= catRestSize) { \ + memcpy(catTmpDst, (src), strlen(src) + 1); \ + catRet = EOK; \ + } else { \ + catRet = ERANGE; \ + } \ + if (catRet != EOK) { \ + catRet = strcat_s((dest), (destMax), (src)); \ + } \ + } else { \ + catRet = strcat_s((dest), (destMax), (src)); \ + } \ + catRet; \ + }) +#else +#define SECUREC_STRCAT_SM(dest, destMax, src) strcat_s(dest, destMax, src) +#endif + +/* for strncat_s performance optimization */ +#if defined(__GNUC__) +#define SECUREC_STRNCAT_SM(dest, destMax, src, count) \ + ({ \ + int ncatRet = EOK; \ + if ((void*)dest != NULL && (void*)src != NULL && (size_t)destMax > 0 && \ + (((unsigned long long)(destMax) & (unsigned long long)(-2)) < SECUREC_STRING_MAX_LEN) && \ + (((unsigned long long)(count) & (unsigned long long)(-2)) < SECUREC_STRING_MAX_LEN)) { \ + char* ncatTmpDest = (dest); \ + size_t ncatRestSize = (destMax); \ + while (ncatRestSize > 0 && *ncatTmpDest) { \ + ++ncatTmpDest; \ + --ncatRestSize; \ + } \ + if (ncatRestSize == 0) { \ + ncatRet = EINVAL; \ + } else if ((SECUREC_TWO_MIN((count), strlen(src)) + 1) <= ncatRestSize) { \ + if ((count) < strlen(src)) { \ + memcpy(ncatTmpDest, (src), (count)); \ + *(ncatTmpDest + (count)) = '\0'; \ + } else { \ + memcpy(ncatTmpDest, (src), strlen(src) + 1); \ + } \ + } else { \ + ncatRet = ERANGE; \ + } \ + if (ncatRet != EOK) { \ + ncatRet = strncat_s((dest), (destMax), (src), (count)); \ + } \ + } else { \ + ncatRet = strncat_s((dest), (destMax), (src), (count)); \ + } \ + ncatRet; \ + }) +#else +#define SECUREC_STRNCAT_SM(dest, destMax, src, count) strncat_s(dest, destMax, src, count) +#endif + +/* SECUREC_MEMCPY_SM do NOT check buffer overlap by default */ +#define SECUREC_MEMCPY_SM(dest, destMax, src, count) \ + (!(((size_t)destMax == 0) || (((unsigned long long)(destMax) & (unsigned long long)(-2)) > SECUREC_MEM_MAX_LEN) || \ + ((size_t)count > (size_t)destMax) || ((void*)dest) == NULL || ((void*)src == NULL)) \ + ? (memcpy(dest, src, count), EOK) \ + : (memcpy_s(dest, destMax, src, count))) + +#define SECUREC_MEMSET_SM(dest, destMax, c, count) \ + (!(((size_t)destMax == 0) || (((unsigned long long)(destMax) & (unsigned long long)(-2)) > SECUREC_MEM_MAX_LEN) || \ + ((void*)dest == NULL) || ((size_t)count > (size_t)destMax)) \ + ? (memset(dest, c, count), EOK) \ + : (memset_s(dest, destMax, c, count))) + +#endif +#endif /* __SECURECTYPE_H__A7BBB686_AADA_451B_B9F9_44DACDAE18A7 */ diff --git a/host/trace_streamer/src/parser/hiperf_parser/hiperf/linux/unique_fd.h b/host/trace_streamer/src/parser/hiperf_parser/hiperf/linux/unique_fd.h new file mode 100644 index 0000000000000000000000000000000000000000..f48a68dcd6d771b094682ec1006e79f48a285ace --- /dev/null +++ b/host/trace_streamer/src/parser/hiperf_parser/hiperf/linux/unique_fd.h @@ -0,0 +1,191 @@ +/* + * Copyright (c) 2021 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. + */ + +#ifndef UNIQUE_FD_H +#define UNIQUE_FD_H + +#include + +namespace OHOS { +class DefaultDeleter { +public: + static void Close(int fd) + { + if (fd >= 0) { + close(fd); + } + } +}; + +template +class UniqueFdAddDeletor; +template +bool operator==(const int& lhs, const UniqueFdAddDeletor& rhs); +template +bool operator!=(const int& lhs, const UniqueFdAddDeletor& rhs); +template +bool operator>=(const int& lhs, const UniqueFdAddDeletor& rhs); +template +bool operator>(const int& lhs, const UniqueFdAddDeletor& rhs); +template +bool operator<=(const int& lhs, const UniqueFdAddDeletor& rhs); +template +bool operator<(const int& lhs, const UniqueFdAddDeletor& rhs); + +template +class UniqueFdAddDeletor final { + friend bool operator==(const int& lhs, const UniqueFdAddDeletor& rhs); + + friend bool operator!=(const int& lhs, const UniqueFdAddDeletor& rhs); + + friend bool operator>=(const int& lhs, const UniqueFdAddDeletor& rhs); + + friend bool operator>(const int& lhs, const UniqueFdAddDeletor& rhs); + + friend bool operator<=(const int& lhs, const UniqueFdAddDeletor& rhs); + + friend bool operator< (const int& lhs, const UniqueFdAddDeletor& rhs); + +public: + explicit UniqueFdAddDeletor(const int& value) + : fd_(value) + { + } + UniqueFdAddDeletor() + : fd_(-1) + { + } + ~UniqueFdAddDeletor() + { + Reset(-1); + } + + // get fd out + int Release() + { + int tmp = fd_; + fd_ = -1; + return tmp; + } + + // this is dangerous, when you use it , you should know it, donot operator on the ret + operator int() const + { + return Get(); + } // NOLINT + // this is dangerous, when you use it , you should know it, donot operator on the ret + int Get() const + { + return fd_; + } + + // we need move fd from one to another + UniqueFdAddDeletor(UniqueFdAddDeletor&& rhs) + { + int rhsfd = rhs.Release(); + fd_ = rhsfd; + } + + UniqueFdAddDeletor& operator=(UniqueFdAddDeletor&& rhs) + { + int rhsfd = rhs.Release(); + Reset(rhsfd); + return *this; + } + + bool operator==(const int& rhs) const + { + return fd_ == rhs; + } + + bool operator!=(const int& rhs) const + { + return !(fd_ == rhs); + } + bool operator>=(const int& rhs) const + { + return fd_ >= rhs; + } + + bool operator>(const int& rhs) const + { + return fd_ > rhs; + } + + bool operator<=(const int& rhs) const + { + return fd_ <= rhs; + } + + bool operator<(const int& rhs) const + { + return fd_ < rhs; + } + +private: + int fd_ = -1; + + void Reset(int newValue) + { + if (fd_ >= 0) { + Deleter::Close(fd_); + } + fd_ = newValue; + } + + // disallow copy ctor and copy assign + UniqueFdAddDeletor(const UniqueFdAddDeletor& rhs) = delete; + UniqueFdAddDeletor& operator=(const UniqueFdAddDeletor& rhs) = delete; +}; + +template +bool operator==(const int& lhs, const UniqueFdAddDeletor& uniqueFd) +{ + return lhs == uniqueFd.fd_; +} + +template +bool operator!=(const int& lhs, const UniqueFdAddDeletor& uniqueFd) +{ + return !(lhs == uniqueFd.fd_); +} + +template +bool operator>=(const int& lhs, const UniqueFdAddDeletor& uniqueFd) +{ + return lhs >= uniqueFd.fd_; +} + +template +bool operator>(const int& lhs, const UniqueFdAddDeletor& uniqueFd) +{ + return lhs > uniqueFd.fd_; +} + +template +bool operator<=(const int& lhs, const UniqueFdAddDeletor& uniqueFd) +{ + return lhs <= uniqueFd.fd_; +} + +template +bool operator<(const int& lhs, const UniqueFdAddDeletor& uniqueFd) +{ + return lhs < uniqueFd.fd_; +} + +using UniqueFd = UniqueFdAddDeletor; +} // namespace OHOS +#endif diff --git a/host/trace_streamer/src/parser/hiperf_parser/hiperf/option.cpp b/host/trace_streamer/src/parser/hiperf_parser/hiperf/option.cpp new file mode 100644 index 0000000000000000000000000000000000000000..1be40759e2eb9b6844d9e4e35439021b2f74a27f --- /dev/null +++ b/host/trace_streamer/src/parser/hiperf_parser/hiperf/option.cpp @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2021 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. + */ + +#include "option.h" + +namespace OHOS { +namespace Developtools { +namespace HiPerf { +namespace Option { +static std::map> g_MainOptions; + +bool CheckOptionFormat(const std::string &optionName) +{ + if (optionName.empty()) { + HLOGE("unable to use empty option name!"); + return false; + } + if (optionName.front() != '-') { + HLOGE("must use '-' at the begin of option name!"); + return false; + } + + return true; +} + +const std::map> &GetMainOptions() +{ + return g_MainOptions; +} + +const MainOption *FindMainOption(std::string argName) +{ + HLOGV("%s", argName.c_str()); + auto found = g_MainOptions.find(argName); + if (found != g_MainOptions.end()) { + // remove the subcmd itself + return found->second.get(); + } else { + return nullptr; + } +} + +std::vector::iterator FindOption(std::vector &args, + const std::string &optionName) +{ + HLOGV("try find '%s' in args: %s", optionName.c_str(), VectorToString(args).c_str()); + auto tmpit = args.begin(); + std::string::size_type position; + for (; tmpit != args.end(); tmpit++) { + position = (*tmpit).find("hiperf"); + if (position != (*tmpit).npos && (*tmpit)[(position + strlen("hiperf"))] == '\0') { + break; + } + } + auto it = find(args.begin(), args.end(), optionName); + if (it != args.end()) { + if (tmpit != args.end() && it > tmpit) { + it = args.end(); + } else { + // we found it , we remove it for next process + HLOGD("have found '%s'", optionName.c_str()); + } + } + return it; +} + +bool GetValueFromString(const std::string &optionValue, const std::string &optionName, bool &value) +{ + value = true; + HLOGD("get bool result:'%s':'%d'", optionName.c_str(), value); + return true; +} + +bool GetValueFromString(const std::string &optionValue, const std::string &optionName, int &value) +{ + try { + value = std::stoi(optionValue); + HLOGD("get int result:'%s':'%d'", optionName.c_str(), value); + return true; + } catch (...) { + // what can we do here ? + } + return false; +} + +bool GetValueFromString(const std::string &optionValue, const std::string &optionName, float &value) +{ + try { + value = std::stof(optionValue); + HLOGD("get float result:'%s':'%f'", optionName.c_str(), value); + return true; + } catch (...) { + // what can we do here ? + } + return false; +} + +bool GetValueFromString(const std::string &optionValue, const std::string &optionName, + std::string &value) +{ + value = optionValue; + return true; // every thing done +} + +bool GetValueFromString(const std::string &optionValue, const std::string &optionName, + std::vector &values) +{ + std::vector stringValues = StringSplit(optionValue, ","); + HLOGD("split int result:'%s':'%s'", optionName.c_str(), VectorToString(stringValues).c_str()); + try { + while (!stringValues.empty()) { + values.push_back(std::stoi(stringValues.front())); + stringValues.erase(stringValues.begin()); // remove for next process + } + return values.size() > 0; // convert successed ? + } catch (...) { + // what can we do here ? + HLOGD("stoi failed with %s", stringValues.front().c_str()); + } + return false; +} + +bool GetValueFromString(const std::string &optionValue, const std::string &optionName, + std::vector &values) +{ + values = StringSplit(optionValue, ","); + HLOGD("split string result:'%s':'%s' from '%s'", optionName.c_str(), + VectorToString(values).c_str(), optionValue.c_str()); + return values.size() > 0; // convert successed ? +} + +bool GetOptionTrackedCommand(std::vector &args, + std::vector &trackedCommand) +{ + if (!args.empty()) { + trackedCommand.insert(trackedCommand.begin(), args.begin(), args.end()); + args.clear(); + } + return true; +} + +void ClearMainOptions() +{ + g_MainOptions.clear(); +} + +bool RegisterMainOption(const std::string &optionName, const std::string &help, + std::function &)> callBackFunction) +{ + HLOGV("%s", optionName.c_str()); + if (!CheckOptionFormat(optionName)) { + return false; + } + + if (g_MainOptions.count(optionName) == 0) { + g_MainOptions[optionName] = std::make_unique(); + g_MainOptions[optionName].get()->help = help; + g_MainOptions[optionName].get()->callBackFunction = std::move(callBackFunction); + return true; + } else { + HLOGE("main args %s already registered!", optionName.c_str()); + return false; + } +} +} // namespace Option +} // namespace HiPerf +} // namespace Developtools +} // namespace OHOS diff --git a/host/trace_streamer/src/parser/hiperf_parser/hiperf/perf_event_record.cpp b/host/trace_streamer/src/parser/hiperf_parser/hiperf/perf_event_record.cpp new file mode 100644 index 0000000000000000000000000000000000000000..60d5ba81c77ccd170eb3d999686843e3ae685508 --- /dev/null +++ b/host/trace_streamer/src/parser/hiperf_parser/hiperf/perf_event_record.cpp @@ -0,0 +1,892 @@ +/* + * Copyright (c) 2021-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. + */ +#define HILOG_TAG "PerfRecord" + +#include "perf_event_record.h" +#include +#include "string_help.h" +#include "utilities.h" + + +using namespace std; +namespace OHOS { +namespace Developtools { +namespace HiPerf { +std::unique_ptr GetPerfEventRecord(const int type, uint8_t *p, + const perf_event_attr &attr) +{ + HLOG_ASSERT(p); + uint8_t *data = p; + + // check kernel + switch (type) { + case PERF_RECORD_SAMPLE: + return std::make_unique(data, attr); + case PERF_RECORD_MMAP: + return std::make_unique(data); + case PERF_RECORD_MMAP2: + return std::make_unique(data); + case PERF_RECORD_LOST: + return std::make_unique(data); + case PERF_RECORD_COMM: + return std::make_unique(data); + case PERF_RECORD_EXIT: + return std::make_unique(data); + case PERF_RECORD_THROTTLE: + return std::make_unique(data); + case PERF_RECORD_UNTHROTTLE: + return std::make_unique(data); + case PERF_RECORD_FORK: + return std::make_unique(data); + case PERF_RECORD_READ: + return std::make_unique(data); + case PERF_RECORD_AUX: + return std::make_unique(data); + case PERF_RECORD_ITRACE_START: + return std::make_unique(data); + case PERF_RECORD_LOST_SAMPLES: + return std::make_unique(data); + case PERF_RECORD_SWITCH: + return std::make_unique(data); + case PERF_RECORD_SWITCH_CPU_WIDE: + return std::make_unique(data); + default: + HLOGE("unknown record type %d\n", type); + return nullptr; + } +} + +template +inline void PushToBinary(bool condition, uint8_t *&p, const T &v) +{ + if (condition) { + *(reinterpret_cast(p)) = v; + p += sizeof(T); + } +} + +template +inline void PushToBinary2(bool condition, uint8_t *&p, const T1 &v1, const T2 &v2) +{ + if (condition) { + *(reinterpret_cast(p)) = v1; + p += sizeof(T1); + *(reinterpret_cast(p)) = v2; + p += sizeof(T2); + } +} + +template +inline void PopFromBinary(bool condition, uint8_t *&p, T &v) +{ + if (condition) { + v = *(reinterpret_cast(p)); + p += sizeof(T); + } +} + +template +inline void PopFromBinary2(bool condition, uint8_t *&p, T1 &v1, T2 &v2) +{ + if (condition) { + v1 = *(reinterpret_cast(p)); + p += sizeof(T1); + v2 = *(reinterpret_cast(p)); + p += sizeof(T2); + } +} + +// PerfEventRecord +PerfEventRecord::PerfEventRecord(perf_event_type type, bool in_kernel, const std::string &name) + : name_(name) +{ + header.type = type; + header.misc = in_kernel ? PERF_RECORD_MISC_KERNEL : PERF_RECORD_MISC_USER; + header.size = sizeof(header); +} + +PerfEventRecord::PerfEventRecord(perf_event_hiperf_ext_type type, const std::string &name) + : name_(name) +{ + header.type = type; + header.misc = PERF_RECORD_MISC_USER; + header.size = sizeof(header); +} + +PerfEventRecord::PerfEventRecord(uint8_t *p, const std::string &name) : name_(name) +{ + header = *(reinterpret_cast(p)); +} + +void PerfEventRecord::GetHeaderBinary(std::vector &buf) const +{ + if (buf.size() < GetHeaderSize()) { + buf.resize(GetHeaderSize()); + } + uint8_t *p = buf.data(); + *(reinterpret_cast(p)) = header; +} + +void PerfEventRecord::Dump(int indent) const +{ + PrintIndent(indent, "\n"); + PrintIndent(indent, "record %s: type %u, misc %u, size %zu\n", GetName().c_str(), GetType(), + GetMisc(), GetSize()); + DumpData(indent + 1); +} + +void PerfEventRecord::DumpLog(const std::string &prefix) const +{ + HLOGV("%s: record %s: type %u, misc %u, size %zu\n", prefix.c_str(), GetName().c_str(), + GetType(), GetMisc(), GetSize()); +} + +void PerfRecordSample::DumpLog(const std::string &prefix) const +{ + HLOGV("%s: SAMPLE: id= %llu size %d pid %u tid %u ips %llu regs %llu, stacks %llu time %llu", + prefix.c_str(), data_.sample_id, header.size, data_.pid, data_.tid, data_.nr, + data_.reg_nr, data_.dyn_size, data_.time); +} + +void PerfRecordSample::ReplaceWithCallStack(size_t originalSize) +{ + // first we check if we have some user unwind stack need to merge ? + if (callFrames_.size() != 0) { + // when we have some kernel ips , we cp it first + // new size is user call frames + kernel call frames + // + PERF_CONTEXT_USER(last + 1) + expand mark(also PERF_CONTEXT_USER) + const unsigned int perfContextSize = 2; + ips_.reserve(data_.nr + callFrames_.size() + perfContextSize); + if (data_.nr > 0) { + ips_.assign(data_.ips, data_.ips + data_.nr); + } + // add user context mark + ips_.emplace_back(PERF_CONTEXT_USER); + // we also need make a expand mark just for debug only + const size_t beginIpsSize = ips_.size(); + bool ret = std::all_of(callFrames_.begin(), callFrames_.end(), [&](const CallFrame &frame) { + ips_.emplace_back(frame.ip_); + if (originalSize != 0 and (originalSize != callFrames_.size()) and + ips_.size() == (originalSize + beginIpsSize)) { + // just for debug + // so we can see which frame begin is expand call frames + ips_.emplace_back(PERF_CONTEXT_USER); + } + return true; + }); + if (ret) { + HLOGV("combed %zu", callFrames_.size()); + } else { + HLOGV("failed to combed %zu", callFrames_.size()); + } + + if (sampleType_ & PERF_SAMPLE_REGS_USER) { + data_.reg_nr = 0; + header.size -= data_.reg_nr * sizeof(u64); + } + + if (sampleType_ & PERF_SAMPLE_STACK_USER) { + // 1. remove the user stack + header.size -= data_.stack_size; + + // 2. clean the size + data_.user_abi = 0; + data_.stack_size = 0; + data_.dyn_size = 0; + } + + if (sampleType_ & PERF_SAMPLE_CALLCHAIN) { + HLOGV("ips change from %llu -> %zu", data_.nr, ips_.size()); + + // 3. remove the nr size + header.size -= data_.nr * sizeof(u64); + + // 4. add new nr size + data_.nr = ips_.size(); + header.size += data_.nr * sizeof(u64); + + // 5. change ips potin to our ips array and hold it. + data_.ips = ips_.data(); + } + } else { + // nothing need change + return; + } +} + +PerfRecordSample::PerfRecordSample(uint8_t *p, const perf_event_attr &attr) + : PerfEventRecord(p, "sample") +{ + if (p == nullptr) { + HLOG_ASSERT(p); + return; + } + sampleType_ = attr.sample_type; + + p += sizeof(header); + + // parse record according SAMPLE_TYPE + PopFromBinary(sampleType_ & PERF_SAMPLE_IDENTIFIER, p, data_.sample_id); + PopFromBinary(sampleType_ & PERF_SAMPLE_IP, p, data_.ip); + PopFromBinary2(sampleType_ & PERF_SAMPLE_TID, p, data_.pid, data_.tid); + PopFromBinary(sampleType_ & PERF_SAMPLE_TIME, p, data_.time); + PopFromBinary(sampleType_ & PERF_SAMPLE_ADDR, p, data_.addr); + PopFromBinary(sampleType_ & PERF_SAMPLE_ID, p, data_.id); + PopFromBinary(sampleType_ & PERF_SAMPLE_STREAM_ID, p, data_.stream_id); + PopFromBinary2(sampleType_ & PERF_SAMPLE_CPU, p, data_.cpu, data_.res); + PopFromBinary(sampleType_ & PERF_SAMPLE_PERIOD, p, data_.period); + PopFromBinary(sampleType_ & PERF_SAMPLE_CALLCHAIN, p, data_.nr); + if (data_.nr > 0) { + // the pointer is from input(p), require caller keep input(p) with *this together + // think it in next time + data_.ips = reinterpret_cast(p); + p += data_.nr * sizeof(u64); + } + PopFromBinary(sampleType_ & PERF_SAMPLE_RAW, p, data_.raw_size); + if (data_.raw_size > 0) { + data_.raw_data = p; + p += data_.raw_size * sizeof(u8); + } + PopFromBinary(sampleType_ & PERF_SAMPLE_BRANCH_STACK, p, data_.bnr); + if (data_.bnr > 0) { + data_.lbr = reinterpret_cast(p); + p += data_.bnr * sizeof(perf_branch_entry); + } + PopFromBinary(sampleType_ & PERF_SAMPLE_REGS_USER, p, data_.user_abi); + if (data_.user_abi > 0) { + data_.reg_mask = attr.sample_regs_user; + data_.reg_nr = __builtin_popcountll(data_.reg_mask); + data_.user_regs = reinterpret_cast(p); + p += data_.reg_nr * sizeof(u64); + } + PopFromBinary(sampleType_ & PERF_SAMPLE_STACK_USER, p, data_.stack_size); + if (data_.stack_size > 0) { + data_.stack_data = p; + p += data_.stack_size; + PopFromBinary(true, p, data_.dyn_size); + } +} + +bool PerfRecordSample::GetBinary(std::vector &buf) const +{ + if (buf.size() < GetSize()) { + buf.resize(GetSize()); + } + + GetHeaderBinary(buf); + uint8_t *p = buf.data() + GetHeaderSize(); + + PushToBinary(sampleType_ & PERF_SAMPLE_IDENTIFIER, p, data_.sample_id); + PushToBinary(sampleType_ & PERF_SAMPLE_IP, p, data_.ip); + PushToBinary2(sampleType_ & PERF_SAMPLE_TID, p, data_.pid, data_.tid); + PushToBinary(sampleType_ & PERF_SAMPLE_TIME, p, data_.time); + PushToBinary(sampleType_ & PERF_SAMPLE_ADDR, p, data_.addr); + PushToBinary(sampleType_ & PERF_SAMPLE_ID, p, data_.id); + PushToBinary(sampleType_ & PERF_SAMPLE_STREAM_ID, p, data_.stream_id); + PushToBinary2(sampleType_ & PERF_SAMPLE_CPU, p, data_.cpu, data_.res); + PushToBinary(sampleType_ & PERF_SAMPLE_PERIOD, p, data_.period); + PushToBinary(sampleType_ & PERF_SAMPLE_CALLCHAIN, p, data_.nr); + if (data_.nr > 0) { + std::copy(data_.ips, data_.ips + data_.nr, reinterpret_cast(p)); + p += data_.nr * sizeof(u64); + } + PushToBinary(sampleType_ & PERF_SAMPLE_RAW, p, data_.raw_size); + if (data_.raw_size > 0) { + std::copy(data_.raw_data, data_.raw_data + data_.raw_size, p); + p += data_.raw_size * sizeof(u8); + } + PushToBinary(sampleType_ & PERF_SAMPLE_BRANCH_STACK, p, data_.bnr); + if (data_.bnr > 0) { + std::copy(data_.lbr, data_.lbr + data_.bnr, reinterpret_cast(p)); + p += data_.bnr * sizeof(perf_branch_entry); + } + PushToBinary(sampleType_ & PERF_SAMPLE_REGS_USER, p, data_.user_abi); + if (data_.user_abi > 0 && data_.reg_nr > 0) { + std::copy(data_.user_regs, data_.user_regs + data_.reg_nr, reinterpret_cast(p)); + p += data_.reg_nr * sizeof(u64); + } + PushToBinary(sampleType_ & PERF_SAMPLE_STACK_USER, p, data_.stack_size); + if (data_.stack_size > 0) { + std::copy(data_.stack_data, data_.stack_data + data_.stack_size, p); + p += data_.stack_size * sizeof(u8); + PushToBinary(true, p, data_.dyn_size); + } + + return true; +} + +void PerfRecordSample::DumpData(int indent) const +{ + PrintIndent(indent, "sample_type: 0x%" PRIx64 "\n", sampleType_); + + // dump record according sampleType + if (sampleType_ & (PERF_SAMPLE_ID | PERF_SAMPLE_IDENTIFIER)) { + PrintIndent(indent, "ID %lld\n", data_.sample_id); + } + if (sampleType_ & PERF_SAMPLE_IP) { + PrintIndent(indent, "ip %llx\n", data_.ip); + } + if (sampleType_ & PERF_SAMPLE_TID) { + PrintIndent(indent, "pid %u, tid %u\n", data_.pid, data_.tid); + } + if (sampleType_ & PERF_SAMPLE_TIME) { + PrintIndent(indent, "time %llu\n", data_.time); + } + if (sampleType_ & PERF_SAMPLE_ADDR) { + PrintIndent(indent, "addr %p\n", reinterpret_cast(data_.addr)); + } + if (sampleType_ & PERF_SAMPLE_STREAM_ID) { + PrintIndent(indent, "stream_id %lld\n", data_.stream_id); + } + if (sampleType_ & PERF_SAMPLE_CPU) { + PrintIndent(indent, "cpu %u, res %u\n", data_.cpu, data_.res); + } + if (sampleType_ & PERF_SAMPLE_PERIOD) { + PrintIndent(indent, "period %lld\n", data_.period); + } + if (sampleType_ & PERF_SAMPLE_CALLCHAIN) { + bool userContext = false; + PrintIndent(indent, "callchain nr=%lld\n", data_.nr); + for (uint64_t i = 0; i < data_.nr; ++i) { + std::string_view supplement = ""; + if ((sampleType_ & PERF_SAMPLE_STACK_USER) == 0 || data_.ips[i] != PERF_CONTEXT_USER) { + PrintIndent(indent + 1, "0x%llx%s\n", data_.ips[i], supplement.data()); + continue; + } + // is PERF_SAMPLE_STACK_USER type and is PERF_CONTEXT_USER + if (!userContext) { + userContext = true; + supplement = " "; + } else { + supplement = " "; + } + PrintIndent(indent + 1, "0x%llx%s\n", data_.ips[i], supplement.data()); + } + } + if (sampleType_ & PERF_SAMPLE_RAW) { + PrintIndent(indent, "raw size=%u\n", data_.raw_size); + const uint32_t *data = reinterpret_cast(data_.raw_data); + size_t size = data_.raw_size / sizeof(uint32_t); + for (size_t i = 0; i < size; ++i) { + PrintIndent(indent + 1, "0x%08x (%x)\n", data[i], data[i]); + } + } + if (sampleType_ & PERF_SAMPLE_BRANCH_STACK) { + PrintIndent(indent, "branch_stack nr=%lld\n", data_.bnr); + for (uint64_t i = 0; i < data_.bnr; ++i) { + auto &item = data_.lbr[i]; + PrintIndent(indent + 1, "from 0x%llx, to 0x%llx %s%s\n", item.from, item.to, + item.mispred ? "mispred" : "", item.predicted ? "predicted" : ""); + } + } + if (sampleType_ & PERF_SAMPLE_REGS_USER) { + PrintIndent(indent, "user regs: abi=%lld, reg_nr=%lld\n", data_.user_abi, data_.reg_nr); + for (uint64_t i = 0; i < data_.reg_nr; ++i) { + PrintIndent(indent + 1, "0x%llx\n", data_.user_regs[i]); + } + } + if (sampleType_ & PERF_SAMPLE_STACK_USER) { + PrintIndent(indent, "user stack: size %llu dyn_size %lld\n", data_.stack_size, + data_.dyn_size); + } +} + +inline pid_t PerfRecordSample::GetPid() const +{ + return data_.pid; +} + +PerfRecordMmap::PerfRecordMmap(uint8_t *p) : PerfEventRecord(p, "mmap") +{ + size_t copySize = GetSize() - sizeof(header); + if (memcpy_s((uint8_t *)&data_, sizeof(data_), p + sizeof(header), copySize) != 0) { + HLOGE("memcpy_s retren failed !!!"); + } +} + +PerfRecordMmap::PerfRecordMmap(bool inKernel, u32 pid, u32 tid, u64 addr, u64 len, u64 pgoff, + const std::string &filename) + : PerfEventRecord(PERF_RECORD_MMAP, inKernel, "mmap") +{ + data_.pid = pid; + data_.tid = tid; + data_.addr = addr; + data_.len = len; + data_.pgoff = pgoff; + if (strncpy_s(data_.filename, KILO, filename.c_str(), filename.size()) != 0) { + HLOGE("strncpy_s failed"); + } + + header.size = sizeof(header) + sizeof(data_) - KILO + filename.size() + 1; +} + +bool PerfRecordMmap::GetBinary(std::vector &buf) const +{ + if (buf.size() < GetSize()) { + buf.resize(GetSize()); + } + + GetHeaderBinary(buf); + uint8_t *p = buf.data() + GetHeaderSize(); + + // data_.filename[] is variable-length + std::copy((uint8_t *)&data_, (uint8_t *)&data_ + GetSize() - GetHeaderSize(), p); + return true; +} + +void PerfRecordMmap::DumpData(int indent) const +{ + PrintIndent(indent, "pid %u, tid %u, addr 0x%llx, len 0x%llx\n", data_.pid, data_.tid, + data_.addr, data_.len); + PrintIndent(indent, "pgoff 0x%llx, filename %s\n", data_.pgoff, data_.filename); +} + +void PerfRecordMmap::DumpLog(const std::string &prefix) const +{ + HLOGV("%s: MMAP: size %d pid %u tid %u dso '%s' (0x%llx-0x%llx)@0x%llx", prefix.c_str(), + header.size, data_.pid, data_.tid, data_.filename, data_.addr, data_.addr + data_.len, + data_.pgoff); +} + +PerfRecordMmap2::PerfRecordMmap2(uint8_t *p) : PerfEventRecord(p, "mmap2") +{ + size_t copySize = GetSize() - sizeof(header); + if (memcpy_s((uint8_t *)&data_, sizeof(data_), p + sizeof(header), copySize) != 0) { + HLOGE("memcpy_s retren failed !!!"); + } +} + +PerfRecordMmap2::PerfRecordMmap2(bool inKernel, u32 pid, u32 tid, u64 addr, u64 len, u64 pgoff, + u32 maj, u32 min, u64 ino, u32 prot, u32 flags, + const std::string &filename) + : PerfEventRecord(PERF_RECORD_MMAP2, inKernel, "mmap2") +{ + data_.pid = pid; + data_.tid = tid; + data_.addr = addr; + data_.len = len; + data_.pgoff = pgoff; + data_.maj = maj; + data_.min = min; + data_.ino = ino; + data_.ino_generation = 0; + data_.prot = prot; + data_.flags = flags; + if (strncpy_s(data_.filename, KILO, filename.c_str(), filename.size()) != 0) { + HLOGE("strncpy_s failed"); + } + + header.size = sizeof(header) + sizeof(data_) - KILO + filename.size() + 1; +} + +PerfRecordMmap2::PerfRecordMmap2(bool inKernel, u32 pid, u32 tid, const MemMapItem &item) + : PerfEventRecord(PERF_RECORD_MMAP2, inKernel, "mmap2") +{ + data_.pid = pid; + data_.tid = tid; + data_.addr = item.begin_; + data_.len = item.end_ - item.begin_; + data_.pgoff = item.pageoffset_; + data_.maj = item.major_; + data_.min = item.minor_; + data_.ino = item.inode; + data_.ino_generation = 0; + data_.prot = item.type_; + data_.flags = item.flags; + if (strncpy_s(data_.filename, KILO, item.name_.c_str(), item.name_.size()) != 0) { + HLOGE("strncpy_s failed"); + } + + header.size = sizeof(header) + sizeof(data_) - KILO + item.name_.size() + 1; +} + +bool PerfRecordMmap2::GetBinary(std::vector &buf) const +{ + if (buf.size() < GetSize()) { + buf.resize(GetSize()); + } + + GetHeaderBinary(buf); + uint8_t *p = buf.data() + GetHeaderSize(); + + // data_.filename[] is variable-length + std::copy((uint8_t *)&data_, (uint8_t *)&data_ + GetSize() - GetHeaderSize(), p); + return true; +} + +void PerfRecordMmap2::DumpData(int indent) const +{ + PrintIndent(indent, "pid %u, tid %u, addr 0x%llx, len 0x%llx\n", data_.pid, data_.tid, + data_.addr, data_.len); + PrintIndent(indent, "pgoff 0x%llx, maj %u, min %u, ino %llu, ino_generation %llu\n", + data_.pgoff, data_.maj, data_.min, data_.ino, data_.ino_generation); + PrintIndent(indent, "prot %u, flags %u, filename %s\n", data_.prot, data_.flags, + data_.filename); +} +void PerfRecordMmap2::DumpLog(const std::string &prefix) const +{ + HLOGV("%s: MMAP2: size %d pid %u tid %u dso '%s' (0x%llx-0x%llx)@0x%llx", prefix.c_str(), + header.size, data_.pid, data_.tid, data_.filename, data_.addr, data_.addr + data_.len, + data_.pgoff); +} + +PerfRecordLost::PerfRecordLost(uint8_t *p) : PerfEventRecord(p, "lost") +{ + size_t copySize = GetSize() - sizeof(header); + if (memcpy_s((uint8_t *)&data_, sizeof(data_), p + sizeof(header), copySize) != 0) { + HLOGE("memcpy_s retren failed !!!"); + } +} + +bool PerfRecordLost::GetBinary(std::vector &buf) const +{ + if (buf.size() < GetSize()) { + buf.resize(GetSize()); + } + + GetHeaderBinary(buf); + uint8_t *p = buf.data() + GetHeaderSize(); + + auto pDest = reinterpret_cast(p); + *pDest = data_; + + return true; +} + +void PerfRecordLost::DumpData(int indent) const +{ + PrintIndent(indent, "id %llu, lost %llu\n", data_.id, data_.lost); +} + +PerfRecordComm::PerfRecordComm(uint8_t *p) : PerfEventRecord(p, "comm") +{ + size_t copySize = GetSize() - sizeof(header); + if (memcpy_s((uint8_t *)&data_, sizeof(data_), p + sizeof(header), copySize) != 0) { + HLOGE("memcpy_s retren failed !!!"); + } +} + +PerfRecordComm::PerfRecordComm(bool inKernel, u32 pid, u32 tid, const std::string &comm) + : PerfEventRecord(PERF_RECORD_COMM, inKernel, "comm") +{ + data_.pid = pid; + data_.tid = tid; + if (strncpy_s(data_.comm, KILO, comm.c_str(), comm.size()) != 0) { + HLOGE("strncpy_s failed !!!"); + } + + header.size = sizeof(header) + sizeof(data_) - KILO + comm.size() + 1; +} + +bool PerfRecordComm::GetBinary(std::vector &buf) const +{ + if (buf.size() < GetSize()) { + buf.resize(GetSize()); + } + + GetHeaderBinary(buf); + uint8_t *p = buf.data() + GetHeaderSize(); + + // data_.comm[] is variable-length + std::copy((uint8_t *)&data_, (uint8_t *)&data_ + GetSize() - GetHeaderSize(), p); + + return true; +} + +void PerfRecordComm::DumpData(int indent) const +{ + PrintIndent(indent, "pid %u, tid %u, comm %s\n", data_.pid, data_.tid, data_.comm); +} + +void PerfRecordComm::DumpLog(const std::string &prefix) const +{ + HLOGV("pid %u, tid %u, comm %s\n", data_.pid, data_.tid, data_.comm); +} + +PerfRecordExit::PerfRecordExit(uint8_t *p) : PerfEventRecord(p, "exit") +{ + size_t copySize = GetSize() - sizeof(header); + if (memcpy_s((uint8_t *)&data_, sizeof(data_), p + sizeof(header), copySize) != 0) { + HLOGE("memcpy_s retren failed !!!"); + } +} + +bool PerfRecordExit::GetBinary(std::vector &buf) const +{ + if (buf.size() < GetSize()) { + buf.resize(GetSize()); + } + + GetHeaderBinary(buf); + uint8_t *p = buf.data() + GetHeaderSize(); + + auto pDest = reinterpret_cast(p); + *pDest = data_; + return true; +} + +void PerfRecordExit::DumpData(int indent) const +{ + PrintIndent(indent, "pid %u, ppid %u, tid %u, ptid %u time 0x%llx\n", data_.pid, data_.ppid, + data_.tid, data_.ptid, data_.time); +} + +PerfRecordThrottle::PerfRecordThrottle(uint8_t *p) : PerfEventRecord(p, "throttle") +{ + size_t copySize = GetSize() - sizeof(header); + if (memcpy_s((uint8_t *)&data_, sizeof(data_), p + sizeof(header), copySize) != 0) { + HLOGE("memcpy_s retren failed !!!"); + } +} + +bool PerfRecordThrottle::GetBinary(std::vector &buf) const +{ + if (buf.size() < GetSize()) { + buf.resize(GetSize()); + } + + GetHeaderBinary(buf); + uint8_t *p = buf.data() + GetHeaderSize(); + + auto pDest = reinterpret_cast(p); + *pDest = data_; + return true; +} + +void PerfRecordThrottle::DumpData(int indent) const +{ + PrintIndent(indent, "time 0x%llx, id %llx, stream_id %llx\n", data_.time, data_.id, + data_.stream_id); +} + +PerfRecordUnthrottle::PerfRecordUnthrottle(uint8_t *p) : PerfEventRecord(p, "unthrottle") +{ + size_t copySize = GetSize() - sizeof(header); + if (memcpy_s((uint8_t *)&data_, sizeof(data_), p + sizeof(header), copySize) != 0) { + HLOGE("memcpy_s retren failed !!!"); + } +} + +bool PerfRecordUnthrottle::GetBinary(std::vector &buf) const +{ + if (buf.size() < GetSize()) { + buf.resize(GetSize()); + } + + GetHeaderBinary(buf); + uint8_t *p = buf.data() + GetHeaderSize(); + + auto pDest = reinterpret_cast(p); + *pDest = data_; + return true; +} +void PerfRecordUnthrottle::DumpData(int indent) const +{ + PrintIndent(indent, "time 0x%llx, id %llx, stream_id %llx\n", data_.time, data_.id, + data_.stream_id); +} + +PerfRecordFork::PerfRecordFork(uint8_t *p) : PerfEventRecord(p, "fork") +{ + size_t copySize = GetSize() - sizeof(header); + if (memcpy_s((uint8_t *)&data_, sizeof(data_), p + sizeof(header), copySize) != 0) { + HLOGE("memcpy_s retren failed !!!"); + } +} + +bool PerfRecordFork::GetBinary(std::vector &buf) const +{ + if (buf.size() < GetSize()) { + buf.resize(GetSize()); + } + + GetHeaderBinary(buf); + uint8_t *p = buf.data() + GetHeaderSize(); + + auto pDest = reinterpret_cast(p); + *pDest = data_; + return true; +} + +void PerfRecordFork::DumpData(int indent) const +{ + PrintIndent(indent, "pid %u, ppid %u, tid %u, ptid %u\n", data_.pid, data_.ppid, data_.tid, + data_.ptid); +} + +PerfRecordRead::PerfRecordRead(uint8_t *p) : PerfEventRecord(p, "read") +{ + size_t copySize = GetSize() - sizeof(header); + if (memcpy_s((uint8_t *)&data_, sizeof(data_), p + sizeof(header), copySize) != 0) { + HLOGE("memcpy_s retren failed !!!"); + } +} + +bool PerfRecordRead::GetBinary(std::vector &buf) const +{ + if (buf.size() < GetSize()) { + buf.resize(GetSize()); + } + + GetHeaderBinary(buf); + uint8_t *p = buf.data() + GetHeaderSize(); + + auto pDest = reinterpret_cast(p); + *pDest = data_; + return true; +} + +void PerfRecordRead::DumpData(int indent) const +{ + PrintIndent(indent, "pid %u, tid %u\n", data_.pid, data_.tid); + PrintIndent(indent, "values: value %llx, time_enabled %llx, time_running %llx, id %llx\n", + data_.values.value, data_.values.time_enabled, data_.values.time_running, + data_.values.id); +} + +PerfRecordAux::PerfRecordAux(uint8_t *p) : PerfEventRecord(p, "aux") +{ + size_t copySize = GetSize() - sizeof(header); + if (memcpy_s((void *)&data_, sizeof(data_), p + sizeof(header), copySize) != 0) { + HLOGE("memcpy_s retren failed !!!"); + } +} + +bool PerfRecordAux::GetBinary(std::vector &buf) const +{ + if (buf.size() < GetSize()) { + buf.resize(GetSize()); + } + + GetHeaderBinary(buf); + uint8_t *p = buf.data() + GetHeaderSize(); + + auto pDest = reinterpret_cast(p); + *pDest = data_; + return true; +} + +void PerfRecordAux::DumpData(int indent) const +{ + PrintIndent(indent, "aux_offset %llx, aux_size %llx, flags %llx\n", data_.aux_offset, + data_.aux_size, data_.flags); +} + +PerfRecordItraceStart::PerfRecordItraceStart(uint8_t *p) : PerfEventRecord(p, "itraceStart") +{ + size_t copySize = GetSize() - sizeof(header); + if (memcpy_s((uint8_t *)&data_, sizeof(data_), p + sizeof(header), copySize) != 0) { + HLOGE("memcpy_s retren failed !!!"); + } +} + +bool PerfRecordItraceStart::GetBinary(std::vector &buf) const +{ + if (buf.size() < GetSize()) { + buf.resize(GetSize()); + } + + GetHeaderBinary(buf); + uint8_t *p = buf.data() + GetHeaderSize(); + + auto pDest = reinterpret_cast(p); + *pDest = data_; + return true; +} + +void PerfRecordItraceStart::DumpData(int indent) const +{ + PrintIndent(indent, "pid %u, tid %u\n", data_.pid, data_.tid); +} + +PerfRecordLostSamples::PerfRecordLostSamples(uint8_t *p) : PerfEventRecord(p, "lostSamples") +{ + size_t copySize = GetSize() - sizeof(header); + if (memcpy_s((uint8_t *)&data_, sizeof(data_), p + sizeof(header), copySize) != 0) { + HLOGE("memcpy_s retren failed !!!"); + } +} + +bool PerfRecordLostSamples::GetBinary(std::vector &buf) const +{ + if (buf.size() < GetSize()) { + buf.resize(GetSize()); + } + + GetHeaderBinary(buf); + uint8_t *p = buf.data() + GetHeaderSize(); + + auto pDest = reinterpret_cast(p); + *pDest = data_; + return true; +} + +void PerfRecordLostSamples::DumpData(int indent) const +{ + PrintIndent(indent, "lost %llu\n", data_.lost); +} + +PerfRecordSwitch::PerfRecordSwitch(uint8_t *p) : PerfEventRecord(p, "switch") +{ + size_t copySize = GetSize() - sizeof(header); + if (memcpy_s((uint8_t *)&data_, sizeof(data_), p + sizeof(header), copySize) != 0) { + HLOGE("memcpy_s retren failed !!!"); + } +} + +bool PerfRecordSwitch::GetBinary(std::vector &buf) const +{ + if (buf.size() < GetSize()) { + buf.resize(GetSize()); + } + + GetHeaderBinary(buf); + uint8_t *p = buf.data() + GetHeaderSize(); + + auto pDest = reinterpret_cast(p); + *pDest = data_; + return true; +} + +PerfRecordSwitchCpuWide::PerfRecordSwitchCpuWide(uint8_t *p) : PerfEventRecord(p, "switchCpuWide") +{ + size_t copySize = GetSize() - sizeof(header); + if (memcpy_s((uint8_t *)&data_, sizeof(data_), p + sizeof(header), copySize) != 0) { + HLOGE("memcpy_s retren failed !!!"); + } +} + +bool PerfRecordSwitchCpuWide::GetBinary(std::vector &buf) const +{ + if (buf.size() < GetSize()) { + buf.resize(GetSize()); + } + + GetHeaderBinary(buf); + uint8_t *p = buf.data() + GetHeaderSize(); + + auto pDest = reinterpret_cast(p); + *pDest = data_; + return true; +} + +void PerfRecordSwitchCpuWide::DumpData(int indent) const +{ + PrintIndent(indent, "next_prev_pid %u, next_prev_tid %u\n", data_.next_prev_pid, + data_.next_prev_tid); +} +} // namespace HiPerf +} // namespace Developtools +} // namespace OHOS diff --git a/host/trace_streamer/src/parser/hiperf_parser/hiperf/perf_events.cpp b/host/trace_streamer/src/parser/hiperf_parser/hiperf/perf_events.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d53d2a0e58e2bd36ff1f3583ec99fb4270f349d0 --- /dev/null +++ b/host/trace_streamer/src/parser/hiperf_parser/hiperf/perf_events.cpp @@ -0,0 +1,1645 @@ +/* + * Copyright (c) 2021-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. + */ +#include "perf_events.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if defined(CONFIG_HAS_SYSPARA) +#include +#endif + +#include "debug_logger.h" +#include "register.h" +#include "subcommand_dump.h" +#include "symbols_file.h" +#include "utilities.h" +#include "tracked_command.h" + +using namespace std; +using namespace std::chrono; +namespace OHOS { +namespace Developtools { +namespace HiPerf { +static std::atomic_bool g_trackRunning = false; + +OHOS::UniqueFd PerfEvents::Open(perf_event_attr &attr, pid_t pid, int cpu, int group_fd, + unsigned long flags) +{ + if (perfEventParanoid_ >= PerfEventParanoid::USER) { + attr.exclude_kernel = true; // kernel restrict + } + OHOS::UniqueFd fd = UniqueFd(syscall(__NR_perf_event_open, &attr, pid, cpu, group_fd, flags)); + if (fd < 0) { + HLOGEP("syscall perf_event_open failed. "); + // dump when open failed. + SubCommandDump::DumpPrintEventAttr(attr, std::numeric_limits::min()); + } + HLOGV("perf_event_open: got fd %d for pid %d cpu %d group %d flags %lu perfEventParanoid %d", + fd.Get(), pid, cpu, group_fd, flags, perfEventParanoid_); + return fd; +} + +PerfEvents::PerfEvents() : timeOut_(DEFAULT_TIMEOUT * THOUSANDS), timeReport_(0) +{ + pageSize_ = sysconf(_SC_PAGESIZE); + HLOGI("BuildArch %s", GetArchName(buildArchType).c_str()); +} + +PerfEvents::~PerfEvents() +{ + // close mmap + for (auto it = cpuMmap_.begin(); it != cpuMmap_.end();) { + const MmapFd &mmapItem = it->second; + munmap(mmapItem.mmapPage, (1 + mmapPages_) * pageSize_); + it = cpuMmap_.erase(it); + } + + // close file descriptor of perf_event_open() created + for (auto eventGroupItem = eventGroupItem_.begin(); eventGroupItem != eventGroupItem_.end();) { + for (const auto &eventItem : eventGroupItem->eventItems) { + for (const auto &fdItem : eventItem.fdItems) { + close(fdItem.fd); + } + } + eventGroupItem = eventGroupItem_.erase(eventGroupItem); + } + + ExitReadRecordBufThread(); +} + +PerfEventParanoid PerfEvents::perfEventParanoid_ = PerfEventParanoid::UNKNOW; + +bool PerfEvents::CheckOhosPermissions() +{ +#if defined(CONFIG_HAS_SYSPARA) + std::string perfHarden = "0"; + perfHarden = OHOS::system::GetParameter(PERF_DISABLE_PARAM, perfHarden); + HLOGD("%s is %s", PERF_DISABLE_PARAM.c_str(), perfHarden.c_str()); + if (perfHarden == "1") { + printf("param '%s' is disabled, try to enable it\n", PERF_DISABLE_PARAM.c_str()); + // we will try to set it as 0 + perfHarden = OHOS::system::SetParameter(PERF_DISABLE_PARAM, "0"); + // wait init config the param + std::this_thread::sleep_for(1s); + if (OHOS::system::GetParameter(PERF_DISABLE_PARAM, perfHarden) == "1") { + printf("setparam failed. pls try setparam %s 0\n", PERF_DISABLE_PARAM.c_str()); + } + } + return perfHarden == "0"; +#else + return true; // not ohos +#endif +} + +bool PerfEvents::CheckPermissions(PerfEventParanoid request) +{ + // check the ohos param "security.perf_harden" + + if (getuid() == 0) { + // we are root perfEventParanoid as -1 + perfEventParanoid_ = PerfEventParanoid::NOLIMIT; + printf("this is root mode, perfEventParanoid assume as -1\n"); + return true; + } + + std::string perfEventParanoid = ReadFileToString(PERF_EVENT_PARANOID); + if (perfEventParanoid.empty()) { + printf("unable to read %s, assume as 2\n", PERF_EVENT_PARANOID.c_str()); + perfEventParanoid_ = PerfEventParanoid::USER; + } else { + perfEventParanoid_ = static_cast(stoi(perfEventParanoid)); + } + +#if is_ohos + // not root and in ohos + if (!CheckOhosPermissions()) { + return false; + } +#endif + + if (perfEventParanoid_ == PerfEventParanoid::NOLIMIT) { + return true; + } + printf("%s is %d\n", PERF_EVENT_PARANOID.c_str(), perfEventParanoid_); + if (perfEventParanoid_ >= PerfEventParanoid::USER) { + printf("allow only user-space measurements (default since Linux 4.6).\n"); + } else if (perfEventParanoid_ == PerfEventParanoid::KERNEL_USER) { + printf("allow both kernel and user measurements (default before Linux 4.6).\n"); + } else if (perfEventParanoid_ == PerfEventParanoid::KERNEL_USER_CPU) { + printf("allow access to CPU-specific data but not raw tracepoint samples.\n"); + } else if (perfEventParanoid_ <= PerfEventParanoid::NOLIMIT) { + printf("unable to read anything\n"); + } + printf("request level is %d\n", request); + return perfEventParanoid_ <= request; +} + +bool PerfEvents::IsEventSupport(perf_type_id type, __u64 config) +{ + HLOGV("enter"); + unique_ptr attr = PerfEvents::CreateDefaultAttr(type, config); + UniqueFd fd = Open(*attr.get()); + if (fd < 0) { + printf("event not support %s\n", GetStaticConfigName(type, config).c_str()); + return false; + } else { + return true; + } +} +bool PerfEvents::IsEventAttrSupport(perf_event_attr &attr) +{ + HLOGV("enter"); + UniqueFd fd = Open(attr); + if (fd < 0) { + return false; + } else { + return true; + } +} + +bool PerfEvents::SetBranchSampleType(uint64_t value) +{ + if (value != 0) { + // cpu-clcles event must be supported + unique_ptr attr = + PerfEvents::CreateDefaultAttr(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES); + attr->sample_type |= PERF_SAMPLE_BRANCH_STACK; + attr->branch_sample_type = value; + if (!IsEventAttrSupport(*attr.get())) { + return false; + } + } + branchSampleType_ = value; + return true; +} + +bool PerfEvents::AddDefaultEvent(perf_type_id type) +{ + HLOGV("enter"); + auto it = DEFAULT_TYPE_CONFIGS.find(type); + if (it != DEFAULT_TYPE_CONFIGS.end()) { + for (auto config : it->second) { + AddEvent(type, config); + } + } + return true; +} + +bool PerfEvents::AddOffCpuEvent() +{ + std::string eventName = "sched:sched_switch"; + if (eventSpaceType_ == EventSpaceType::USER) { + eventName += ":u"; + } else if (eventSpaceType_ == EventSpaceType::KERNEL) { + eventName += ":k"; + } + return AddEvent(eventName); +} + +bool PerfEvents::AddEvents(const std::vector &eventStrings, bool group) +{ + bool followGroup = false; + HLOGV(" %s %s", VectorToString(eventStrings).c_str(), followGroup ? "followGroup" : ""); + + for (std::string eventString : eventStrings) { + if (!AddEvent(eventString, followGroup)) { + return false; + } + // this is group request , Follow-up events need to follow the previous group + if (group) { + followGroup = true; + } + } + return true; +} + +// event name can have :k or :u suffix +// tracepoint event name is like sched:sched_switch +// clang-format off +bool PerfEvents::ParseEventName(const std::string &nameStr, + std::string &name, bool &excludeUser, bool &excludeKernel, bool &isTracePoint) +// clang-format on +{ + name = nameStr; + excludeUser = false; + excludeKernel = false; + isTracePoint = false; + if (nameStr.find(":") != std::string::npos) { + static constexpr size_t maxNumberTokensNoTracePoint = 2; + static constexpr size_t maxNumberTokensTracePoint = 3; + std::vector eventTokens = StringSplit(nameStr, ":"); + if (eventTokens.size() == maxNumberTokensTracePoint) { + // tracepoint event with :u or :k + if (eventTokens.back() == "k") { + excludeUser = true; + HLOGV("kernelOnly event"); + } else if (eventTokens.back() == "u") { + excludeKernel = true; + HLOGV("userOnly event"); + } else { + HLOGV("unknown event name %s", nameStr.c_str()); + return false; + } + name = eventTokens[0] + ":" + eventTokens[1]; + isTracePoint = true; + } else if (eventTokens.size() == maxNumberTokensNoTracePoint) { + name = eventTokens[0]; + if (eventTokens.back() == "k") { + excludeUser = true; + HLOGV("kernelOnly event"); + } else if (eventTokens.back() == "u") { + excludeKernel = true; + HLOGV("userOnly event"); + } else { + name = nameStr; + isTracePoint = true; + HLOGV("tracepoint event is in form of xx:xxx"); + } + } else { + printf("unknown ':' format:'%s'\n", nameStr.c_str()); + return false; + } + if (reportCallBack_) { + if ((eventTokens[0] == "sw-task-clock" || eventTokens[0] == "sw-cpu-clock") && + (excludeUser || excludeKernel)) { + printf( + "event type %s with modifier u and modifier k is not supported by the kernel.", + eventTokens[0].c_str()); + return false; + } + } + } + return true; +} + +bool PerfEvents::AddEvent(const std::string &eventString, bool followGroup) +{ + std::string eventName; + bool excludeUser = false; + bool excludeKernel = false; + bool isTracePointEvent = false; + if (!ParseEventName(eventString, eventName, excludeUser, excludeKernel, isTracePointEvent)) { + return false; + } + if (excludeUser) { + if (requestPermission_ > PerfEventParanoid::KERNEL_USER) { + requestPermission_ = PerfEventParanoid::KERNEL_USER; + } + + eventSpaceType_ |= EventSpaceType::KERNEL; + } else if (excludeKernel) { + eventSpaceType_ |= EventSpaceType::USER; + } else { + eventSpaceType_ |= EventSpaceType::USER_KERNEL; + } + + if (isTracePointEvent) { + if (PERF_TRACEPOINT_CONFIGS.empty()) { + LoadTracepointEventTypesFromSystem(); + } + } + + // find if + if (isTracePointEvent) { + for (auto traceType : traceConfigTable) { + if (traceType.second == eventName) { + return AddEvent(PERF_TYPE_TRACEPOINT, traceType.first, excludeUser, excludeKernel, + followGroup); + } + } + } else { + for (auto type : TYPE_CONFIGS) { + for (auto config : (type.second)) { + if (config.second == eventName) { + return AddEvent(type.first, config.first, excludeUser, excludeKernel, + followGroup); + } + } + } + } + + printf("%s event is not supported by the kernel.\n", eventName.c_str()); + return false; +} + +bool PerfEvents::AddEvent(perf_type_id type, __u64 config, bool excludeUser, bool excludeKernel, + bool followGroup) +{ + HLOG_ASSERT(!excludeUser or !excludeKernel); + if (followGroup && eventGroupItem_.empty()) { + HLOGE("no group leader create before"); + return false; + } + // found the event name + if (!IsEventSupport(type, config)) { + return false; + } + HLOGV("type %d config %llu excludeUser %d excludeKernel %d followGroup %d", type, config, + excludeUser, excludeKernel, followGroup); + + // if use follow ? + EventGroupItem &eventGroupItem = followGroup ? eventGroupItem_.back() + : eventGroupItem_.emplace_back(); + // always new item + EventItem &eventItem = eventGroupItem.eventItems.emplace_back(); + + eventItem.typeName = GetTypeName(type); + if (type == PERF_TYPE_TRACEPOINT) { + eventItem.configName = GetTraceConfigName(config); + } else { + eventItem.configName = GetStaticConfigName(type, config); + } + + // attr + if (memset_s(&eventItem.attr, sizeof(perf_event_attr), 0, sizeof(perf_event_attr)) != EOK) { + HLOGE("memset_s failed in PerfEvents::AddEvent"); + return false; + } + eventItem.attr.size = sizeof(perf_event_attr); + eventItem.attr.type = type; + eventItem.attr.config = config; + eventItem.attr.disabled = 1; + eventItem.attr.read_format = + PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING | PERF_FORMAT_ID; + + eventItem.attr.inherit = (inherit_ ? 1 : 0); + eventItem.attr.exclude_kernel = excludeKernel; + eventItem.attr.exclude_user = excludeUser; + + // we also need mmap for record + if (recordCallBack_) { + if (samplePeriod_ > 0) { + eventItem.attr.freq = 0; + eventItem.attr.sample_period = samplePeriod_; + } else if (sampleFreq_ > 0) { + eventItem.attr.freq = 1; + eventItem.attr.sample_freq = sampleFreq_; + } else { + if (type == PERF_TYPE_TRACEPOINT) { + eventItem.attr.freq = 0; + eventItem.attr.sample_period = DEFAULT_SAMPLE_PERIOD; + } else { + eventItem.attr.freq = 1; + eventItem.attr.sample_freq = DEFAULT_SAMPLE_FREQUNCY; + } + } + + eventItem.attr.watermark = 1; + if (eventItem.attr.watermark == 1) { + eventItem.attr.wakeup_watermark = (mmapPages_ * pageSize_) >> 1; + static constexpr unsigned int maxWakeupMark = 1024 * 1024; + if (eventItem.attr.wakeup_watermark > maxWakeupMark) { + eventItem.attr.wakeup_watermark = maxWakeupMark; + } + } + + // for a group of events, only enable comm/mmap on the first event + if (!followGroup) { + eventItem.attr.comm = 1; + eventItem.attr.mmap = 1; + eventItem.attr.mmap2 = 1; + eventItem.attr.mmap_data = 1; + } + + if (sampleStackType_ == SampleStackType::DWARF) { + eventItem.attr.sample_type = SAMPLE_TYPE | PERF_SAMPLE_CALLCHAIN | + PERF_SAMPLE_STACK_USER | PERF_SAMPLE_REGS_USER; + eventItem.attr.exclude_callchain_user = 1; + eventItem.attr.sample_regs_user = GetSupportedRegMask(GetDeviceArch()); + eventItem.attr.sample_stack_user = dwarfSampleStackSize_; + } else if (sampleStackType_ == SampleStackType::FP) { + eventItem.attr.sample_type = SAMPLE_TYPE | PERF_SAMPLE_CALLCHAIN; + } else { + eventItem.attr.sample_type = SAMPLE_TYPE; + } + } + + // set clock id + if (clockId_ != -1) { + eventItem.attr.use_clockid = 1; + eventItem.attr.clockid = clockId_; + } + if (branchSampleType_ != 0) { + eventItem.attr.sample_type |= PERF_SAMPLE_BRANCH_STACK; + eventItem.attr.branch_sample_type = branchSampleType_; + } + + HLOGV("Add Event: '%s':'%s' %s %s %s", eventItem.typeName.c_str(), eventItem.configName.c_str(), + excludeUser ? "excludeUser" : "", excludeKernel ? "excludeKernel" : "", + followGroup ? "" : "group leader"); + + return true; +} + +std::unique_ptr PerfEvents::CreateDefaultAttr(perf_type_id type, __u64 config) +{ + unique_ptr attr = make_unique(); + if (memset_s(attr.get(), sizeof(perf_event_attr), 0, sizeof(perf_event_attr)) != EOK) { + HLOGE("memset_s failed in PerfEvents::CreateDefaultAttr"); + return nullptr; + } + attr->size = sizeof(perf_event_attr); + attr->type = type; + attr->config = config; + attr->disabled = 1; + return attr; +} + +// should move to upper caller +static struct sigaction g_oldSig { +}; +static bool CaptureSig() +{ + HLOGD("capture Ctrl + C to end sampling decently"); + struct sigaction sig { + }; + + sig.sa_handler = [](int sig) { + printf("\n Ctrl + C detected.\n"); + g_trackRunning = false; + }; + + sig.sa_flags = 0; + if (sigaction(SIGINT, &sig, &g_oldSig) < 0) { + perror("Fail to call sigaction for SIGINT"); + return false; + } + return true; +} + +static void RecoverCaptureSig() +{ + if (sigaction(SIGINT, &g_oldSig, nullptr) < 0) { + perror("Fail to call sigaction for SIGINT"); + } +} + +// split to two part +// because WriteAttrAndId need fd id before start tracking +bool PerfEvents::PrepareTracking(void) +{ + HLOGV("enter"); + + if (!CheckPermissions(requestPermission_)) { + return false; + } + + // 1. prepare cpu pid + if (!PrepareFdEvents()) { + HLOGE("PrepareFdEvents() failed"); + return false; + } + + // 2. create events + if (!CreateFdEvents()) { + HLOGE("CreateFdEvents() failed"); + return false; + } + + prepared_ = true; + return true; +} + +void PerfEvents::ExitReadRecordBufThread() +{ + if (isLowPriorityThread_) { + if (setpriority(PRIO_PROCESS, gettid(), 0) != 0) { + HLOGW("failed to decrease priority of reading kernel"); + } + } + if (readRecordBufThread_.joinable()) { + readRecordThreadRunning_ = false; + __sync_synchronize(); + cvRecordBuf_.notify_one(); + readRecordBufThread_.join(); + } +} + +bool PerfEvents::PrepareRecordThread() +{ + try { + recordBuf_ = std::make_unique(CalcBufferSize()); + } catch (const std::exception &e) { + printf("create record buffer(size %zu) failed: %s\n", CalcBufferSize(), e.what()); + return false; + } + readRecordThreadRunning_ = true; + readRecordBufThread_ = std::thread(&PerfEvents::ReadRecordFromBuf, this); + + rlimit rlim; + int result = getrlimit(RLIMIT_NICE, &rlim); + const rlim_t lowPriority = 40; + if (result == 0 && rlim.rlim_cur == lowPriority) { + const int highPriority = -20; + result = setpriority(PRIO_PROCESS, gettid(), highPriority); + if (result != 0) { + HLOGW("failed to increase priority of reading kernel"); + } else { + isLowPriorityThread_ = true; + } + } + + return true; +} + +void PerfEvents::WaitRecordThread() +{ + printf("Process and Saving data...\n"); + ExitReadRecordBufThread(); + + const auto usedTimeMsTick = duration_cast(steady_clock::now() - trackingEndTime_); + if (verboseReport_) { + printf("Record Process Completed (wait %" PRId64 " ms)\n", (uint64_t)usedTimeMsTick.count()); + } + HLOGV("Record Process Completed (wait %" PRId64 " ms)\n", (uint64_t)usedTimeMsTick.count()); +#ifdef HIPERF_DEBUG_TIME + printf("%zu record processed, used %0.3f ms(%4.2f us/record)\n", recordEventCount_, + recordCallBackTime_.count() / MS_DUARTION, + recordCallBackTime_.count() / static_cast(recordEventCount_)); + printf("total wait sleep time %0.3f ms.\n", recordSleepTime_.count() / MS_DUARTION); + printf("read from kernel time %0.3f ms.\n", recordKernelReadTime_.count() / MS_DUARTION); +#endif +} + +bool PerfEvents::StartTracking(bool immediately) +{ + if (!prepared_) { + return false; + } + + HLOGD("step: 1. enable event"); + trackingStartTime_ = steady_clock::now(); + if (immediately) { + if (!EnableTracking()) { + HLOGE("PerfEvents::EnableTracking() failed"); + return false; + } + } + + if (recordCallBack_) { + if (!PrepareRecordThread()) { + return false; + } + } + + if (immediately) { + printf("Profiling duration is %.3f seconds.\n", float(timeOut_.count()) / THOUSANDS); + printf("Start Profiling...\n"); + } + + g_trackRunning = true; + if (!CaptureSig()) { + HLOGE("captureSig() failed"); + g_trackRunning = false; + ExitReadRecordBufThread(); + return false; + } + + HLOGD("step: 2. thread loop"); + if (recordCallBack_) { + RecordLoop(); + } else { + StatLoop(); + } + + HLOGD("step: 3. disable event"); + if (!PerfEventsEnable(false)) { + HLOGE("PerfEvents::PerfEventsEnable() failed"); + } + trackingEndTime_ = steady_clock::now(); + + RecoverCaptureSig(); + + if (recordCallBack_) { + WaitRecordThread(); + } + + HLOGD("step: 4. exit"); + return true; +} + +bool PerfEvents::StopTracking(void) +{ + if (g_trackRunning) { + printf("some one called StopTracking\n"); + g_trackRunning = false; + if (trackedCommand_) { + if (trackedCommand_->GetState() == TrackedCommand::State::COMMAND_STARTED) { + trackedCommand_->Stop(); + } + } + if (!PerfEventsEnable(false)) { + HLOGE("StopTracking : PerfEventsEnable(false) failed"); + return false; + } + } + return true; +} + +bool PerfEvents::PauseTracking(void) +{ + if (!startedTracking_) { + return false; + } + return PerfEventsEnable(false); +} + +bool PerfEvents::ResumeTracking(void) +{ + if (!startedTracking_) { + return false; + } + return PerfEventsEnable(true); +} + +bool PerfEvents::EnableTracking() +{ + if (startedTracking_) { + return true; + } + if (!PerfEventsEnable(true)) { + HLOGE("PerfEvents::PerfEventsEnable() failed"); + return false; + } + + if (trackedCommand_) { + // start tracked Command + if (trackedCommand_->GetState() == TrackedCommand::State::COMMAND_WAITING) { + if (!trackedCommand_->StartCommand()) { + int wstatus; + if (!trackedCommand_->WaitCommand(wstatus)) { + trackedCommand_->Stop(); + } + std::string commandName = trackedCommand_->GetCommandName(); + printf("failed to execute command: %zu: %s\n", commandName.size(), commandName.c_str()); + return false; + } + } else if (trackedCommand_->GetState() != TrackedCommand::State::COMMAND_STARTED) { + return false; + } + } + startedTracking_ = true; + return true; +} + +bool PerfEvents::IsTrackRunning() +{ + return g_trackRunning; +} + +void PerfEvents::SetSystemTarget(bool systemTarget) +{ + systemTarget_ = systemTarget; +} + +void PerfEvents::SetCpu(std::vector cpus) +{ + cpus_ = cpus; + + if (!cpus_.empty()) { + if (requestPermission_ > PerfEventParanoid::KERNEL_USER_CPU) { + requestPermission_ = PerfEventParanoid::KERNEL_USER_CPU; + } + } +} + +void PerfEvents::SetPid(std::vector pids) +{ + pids_ = pids; +} + +void PerfEvents::SetTimeOut(float timeOut) +{ + if (timeOut > 0) { + timeOut_ = milliseconds(static_cast(timeOut * THOUSANDS)); + } +} + +void PerfEvents::SetTimeReport(int timeReport) +{ + static constexpr int minMsReportInterval = 100; + if (timeReport < minMsReportInterval && timeReport != 0) { + timeReport = minMsReportInterval; + printf("time report min value is %d.\n", timeReport); + } + + timeReport_ = milliseconds(timeReport); +} + +std::map<__u64, std::string> PerfEvents::GetSupportEvents(perf_type_id type) +{ + if (type == PERF_TYPE_TRACEPOINT) { + LoadTracepointEventTypesFromSystem(); + } + + std::map<__u64, std::string> eventConfigs; + auto configTable = TYPE_CONFIGS.find(type); + if (configTable != TYPE_CONFIGS.end()) { + auto configs = configTable->second; + for (auto config : configs) { + if (type == PERF_TYPE_TRACEPOINT || IsEventSupport(type, (__u64)config.first)) { + eventConfigs.insert(config); + } else { + HLOGD("'%s' not support", config.second.c_str()); + } + } + } + return eventConfigs; +} + +void PerfEvents::LoadTracepointEventTypesFromSystem() +{ + if (PERF_TRACEPOINT_CONFIGS.empty()) { + std::string basePath {"/sys/kernel/tracing/events"}; + if (access(basePath.c_str(), R_OK) != 0) { + basePath = "/sys/kernel/debug/tracing/events"; + } + for (const auto &eventName : GetSubDirs(basePath)) { + std::string eventPath = basePath + "/" + eventName; + for (const auto &concreteEvent : GetSubDirs(eventPath)) { + std::string idPath = eventPath + "/" + concreteEvent + "/id"; + { + std::ifstream ifs {idPath}; + // clang-format off + const std::string idStr = { + std::istreambuf_iterator(ifs), + std::istreambuf_iterator() + }; + // clang-format on + __u64 id {0}; + try { + id = std::stoul(idStr, nullptr); + } catch (...) { + continue; + } + auto typeConfigs = TYPE_CONFIGS.find(PERF_TYPE_TRACEPOINT); + HLOG_ASSERT(typeConfigs != TYPE_CONFIGS.end()); + auto configPair = typeConfigs->second.insert( + std::make_pair(id, eventName + ":" + concreteEvent)); + traceConfigTable.insert(std::make_pair(id, eventName + ":" + concreteEvent)); + ConfigTable::iterator it = configPair.first; + HLOGV("TYPE_CONFIGS add %llu:%s in %zu", it->first, it->second.c_str(), + typeConfigs->second.size()); + } + } + } + } +} + +void PerfEvents::SetVerboseReport(bool verboseReport) +{ + verboseReport_ = verboseReport; +} + +void PerfEvents::SetSampleFrequency(unsigned int frequency) +{ + if (frequency > 0) { + sampleFreq_ = frequency; + } +} + +void PerfEvents::SetSamplePeriod(unsigned int period) +{ + if (period > 0) { + samplePeriod_ = period; + } +} + +void PerfEvents::SetMmapPages(size_t mmapPages) +{ + mmapPages_ = mmapPages; +} + +void PerfEvents::SetSampleStackType(SampleStackType type) +{ + sampleStackType_ = type; +} + +void PerfEvents::SetDwarfSampleStackSize(uint32_t stackSize) +{ + HLOGD("request stack size is %u", stackSize); + dwarfSampleStackSize_ = stackSize; +} + +bool PerfEvents::PerfEventsEnable(bool enable) +{ + HLOGV("%s", std::to_string(enable).c_str()); + for (const auto &eventGroupItem : eventGroupItem_) { + for (const auto &eventItem : eventGroupItem.eventItems) { + for (const auto &fdItem : eventItem.fdItems) { + int result = + ioctl(fdItem.fd, enable ? PERF_EVENT_IOC_ENABLE : PERF_EVENT_IOC_DISABLE, 0); + if (result < 0) { + printf("Cannot '%s' perf fd! type config name: '%s:%s'\n", + enable ? "enable" : "disable", eventItem.typeName.c_str(), + eventItem.configName.c_str()); + return false; + } + } + } + } + return true; +} + +void PerfEvents::SetStatCallBack(StatCallBack reportCallBack) +{ + reportCallBack_ = reportCallBack; +} +void PerfEvents::SetRecordCallBack(RecordCallBack recordCallBack) +{ + recordCallBack_ = recordCallBack; +} + +inline void PerfEvents::PutAllCpus() +{ + int cpuConfigs = sysconf(_SC_NPROCESSORS_CONF); + for (int i = 0; i < cpuConfigs; i++) { + cpus_.push_back(i); // put all cpu + } +} + +bool PerfEvents::PrepareFdEvents(void) +{ + HLOGV("enter"); + /* + https://man7.org/linux/man-pages/man2/perf_event_open.2.html + pid == 0 and cpu == -1 + This measures the calling process/thread on any CPU. + + pid == 0 and cpu >= 0 + This measures the calling process/thread only when running + on the specified CPU. + + pid > 0 and cpu == -1 + This measures the specified process/thread on any CPU. + + pid > 0 and cpu >= 0 + This measures the specified process/thread only when + running on the specified CPU. + + pid == -1 and cpu >= 0 + This measures all processes/threads on the specified CPU. + This requires CAP_PERFMON (since Linux 5.8) or + CAP_SYS_ADMIN capability or a + /proc/sys/kernel/perf_event_paranoid value of less than 1. + + pid == -1 and cpu == -1 + This setting is invalid and will return an error. + */ + if (systemTarget_) { + pids_.clear(); + pids_.push_back(-1); + + if (cpus_.empty()) { + PutAllCpus(); + } + } else { + if (trackedCommand_) { + pids_.push_back(trackedCommand_->GetChildPid()); + } + if (pids_.empty()) { + pids_.push_back(0); // no pid means use 0 as self pid + } + if (cpus_.empty()) { + // new review . if perfEventParanoid_ < CPU, how should be CreateMmap work? + if (perfEventParanoid_ <= PerfEventParanoid::KERNEL_USER_CPU) { + // PERF_EVENT_IOC_SET_OUTPUT doesn't support using -1 as all cpu + PutAllCpus(); + } else { + cpus_.push_back(-1); // no cpu as all cpu + } + } + } + + // print info tell user which cpu and process we will select. + if (pids_.size() == 1 && pids_[0] == -1) { + HLOGI("target process: system scope \n"); + } else { + HLOGI("target process: %zu (%s)\n", pids_.size(), + (pids_[0] == 0) ? std::to_string(gettid()).c_str() : VectorToString(pids_).c_str()); + } + if (cpus_.size() == 1 && cpus_[0] == -1) { + HLOGI("target cpus: %ld \n", sysconf(_SC_NPROCESSORS_CONF)); + } else { + HLOGI("target cpus: %zu / %ld (%s)\n", cpus_.size(), sysconf(_SC_NPROCESSORS_CONF), + VectorToString(cpus_).c_str()); + } + + return true; +} + +bool PerfEvents::CreateFdEvents(void) +{ + HLOGV("enter"); + + // must be some events , or will failed + if (eventGroupItem_.empty()) { + printf("no event select.\n"); + return false; + } + + // create each fd by cpu and process user select + /* + https://man7.org/linux/man-pages/man2/perf_event_open.2.html + + (A single event on its own is created with group_fd = -1 and is + considered to be a group with only 1 member.) + */ + // Even if there is only one event, it is counted as a group. + + uint fdNumber = 0; + uint eventNumber = 0; + uint groupNumber = 0; + for (auto &eventGroupItem : eventGroupItem_) { + /* + Explain what is the configuration of the group: + Suppose we have 2 Event, 2 PID, and 3 CPU settings + According to verification, + Group's fd requires the pid to be the same as the cpu, the only difference is event + In other words, if you want to bind E1 and E2 to the same group + That can only be like this: + + event E1 pid P1 cpu C1 [Group 1] + event E1 pid P1 cpu C2 [Group 2] + event E1 pid P1 cpu C3 [Group 3] + + event E1 pid P2 cpu C1 [Group 4] + event E1 pid P2 cpu C2 [Group 5] + event E1 pid P2 cpu C3 [Group 6] + + event E2 pid P1 cpu C1 [Group 1] + event E2 pid P1 cpu C2 [Group 2] + event E2 pid P1 cpu C3 [Group 3] + + event E2 pid P2 cpu C1 [Group 4] + event E2 pid P2 cpu C2 [Group 5] + event E2 pid P2 cpu C3 [Group 6] + */ + HLOGV("group %2u. eventGroupItem leader: '%s':", groupNumber++, + eventGroupItem.eventItems[0].configName.c_str()); + + int groupFdCache[cpus_.size()][pids_.size()]; + for (size_t i = 0; i < cpus_.size(); i++) { // each cpu + for (size_t j = 0; j < pids_.size(); j++) { // each pid + // The leader is created first, with group_fd = -1. + groupFdCache[i][j] = -1; + } + } + + uint eventIndex = 0; + for (auto &eventItem : eventGroupItem.eventItems) { + HLOGV(" - event %2u. eventName: '%s:%s'", eventIndex++, eventItem.typeName.c_str(), + eventItem.configName.c_str()); + + for (size_t icpu = 0; icpu < cpus_.size(); icpu++) { // each cpu + for (size_t ipid = 0; ipid < pids_.size(); ipid++) { // each pid + // one fd event group must match same cpu and same pid config (event can be + // different) + // clang-format off + UniqueFd fd = Open(eventItem.attr, pids_[ipid], cpus_[icpu], + groupFdCache[icpu][ipid], 0); + // clang-format on + if (fd < 0) { + if (errno == ESRCH) { + if (verboseReport_) { + printf("pid %d does not exist.\n", pids_[ipid]); + } + HLOGE("pid %d does not exist.\n", pids_[ipid]); + continue; + } else { + // clang-format off + if (verboseReport_) { + char errInfo[ERRINFOLEN] = { 0 }; + strerror_r(errno, errInfo, ERRINFOLEN); + printf("%s event is not supported by the kernel on cpu %d. reason: %d:%s\n", + eventItem.configName.c_str(), cpus_[icpu], errno, errInfo); + } + char errInfo[ERRINFOLEN] = { 0 }; + strerror_r(errno, errInfo, ERRINFOLEN); + HLOGE("%s event is not supported by the kernel on cpu %d. reason: %d:%s\n", + eventItem.configName.c_str(), cpus_[icpu], errno, errInfo); + // clang-format on + break; // jump to next cpu + } + } + // after open successed , fill the result + // make a new FdItem + FdItem &fdItem = eventItem.fdItems.emplace_back(); + fdItem.fd = move(fd); + fdItem.cpu = cpus_[icpu]; + fdItem.pid = pids_[ipid]; + fdNumber++; + + // if sampling, mmap ring buffer + if (recordCallBack_) { + CreateMmap(fdItem, eventItem.attr); + } + // update group leader + if (groupFdCache[icpu][ipid] == -1) { + groupFdCache[icpu][ipid] = fd.Get(); + } + } + } + eventNumber++; + } + } + + if (fdNumber == 0) { + HLOGE("open %d fd for %d events", fdNumber, eventNumber); + return false; + } + + HLOGD("will try read %u events from %u fd (%zu groups):", eventNumber, fdNumber, + eventGroupItem_.size()); + + return true; +} + +bool PerfEvents::StatReport(const __u64 &durationInSec) +{ + read_format_no_group readNoGroupValue; + + // only need read when need report + HLOGM("eventGroupItem_:%zu", eventGroupItem_.size()); + __u64 groupId = 0; + // clear countEvents data + countEvents_.clear(); + for (const auto &eventGroupItem : eventGroupItem_) { + HLOGM("eventItems:%zu", eventGroupItem.eventItems.size()); + groupId++; + for (const auto &eventItem : eventGroupItem.eventItems) { + // count event info together (every cpu , every pid) + std::string configName = ""; + if (eventItem.attr.exclude_kernel) { + configName = eventItem.configName + ":u"; + } else if (eventItem.attr.exclude_user) { + configName = eventItem.configName + ":k"; + } else { + configName = eventItem.configName; + } + if (countEvents_.count(configName) == 0) { + auto countEvent = make_unique(CountEvent {}); + countEvents_[configName] = std::move(countEvent); + countEvents_[configName]->userOnly = eventItem.attr.exclude_kernel; + countEvents_[configName]->kernelOnly = eventItem.attr.exclude_user; + } + std::unique_ptr &countEvent = countEvents_[configName]; + HLOGM("eventItem.fdItems:%zu", eventItem.fdItems.size()); + for (const auto &fditem : eventItem.fdItems) { + if (read(fditem.fd, &readNoGroupValue, sizeof(readNoGroupValue)) > 0) { + countEvent->eventCount += readNoGroupValue.value; + countEvent->time_enabled += readNoGroupValue.time_enabled; + countEvent->time_running += readNoGroupValue.time_running; + countEvent->id = groupId; + if (durationInSec != 0) { + countEvent->used_cpus = + (countEvent->eventCount / 1e9) / (durationInSec / THOUSANDS); + } + if (verboseReport_) { + printf("%s id:%llu(c%d:p%d) time_enabled:%llu time_running:%llu " + "value:%llu\n", + eventItem.configName.c_str(), readNoGroupValue.id, fditem.cpu, + fditem.pid, readNoGroupValue.time_enabled, + readNoGroupValue.time_running, readNoGroupValue.value); + } + } else { + printf("read failed from event '%s'\n", eventItem.configName.c_str()); + } + } + } + } + + reportCallBack_(countEvents_); + + return true; +} + +bool PerfEvents::CreateMmap(const FdItem &item, const perf_event_attr &attr) +{ + auto it = cpuMmap_.find(item.cpu); + if (it == cpuMmap_.end()) { + void *rbuf = mmap(nullptr, (1 + mmapPages_) * pageSize_, PROT_READ | PROT_WRITE, MAP_SHARED, + item.fd.Get(), 0); + if (rbuf == MMAP_FAILED) { + perror("Fail to call mmap \n"); + return false; + } + MmapFd mmapItem; + mmapItem.fd = item.fd.Get(); + mmapItem.mmapPage = reinterpret_cast(rbuf); + mmapItem.buf = reinterpret_cast(rbuf) + pageSize_; + mmapItem.bufSize = mmapPages_ * pageSize_; + mmapItem.attr = &attr; + mmapItem.posCallChain = GetCallChainPosInSampleRecord(attr); + + cpuMmap_[item.cpu] = mmapItem; + pollFds_.emplace_back(pollfd {mmapItem.fd, POLLIN, 0}); + HLOGD("CreateMmap success cpu %d fd %d", item.cpu, mmapItem.fd); + } else { + const MmapFd &mmapItem = it->second; + int rc = ioctl(item.fd.Get(), PERF_EVENT_IOC_SET_OUTPUT, mmapItem.fd); + if (rc != 0) { + HLOGEP("ioctl PERF_EVENT_IOC_SET_OUTPUT (%d -> %d) ", item.fd.Get(), mmapItem.fd); + perror("failed to share mapped buffer\n"); + return false; + } + } + return true; +} + +std::vector PerfEvents::GetAttrWithId() const +{ + std::vector result; + HLOGV("eventGroupItem_ %zu :", eventGroupItem_.size()); + + for (const auto &eventGroupItem : eventGroupItem_) { + HLOGV(" eventItems %zu eventItems:", eventGroupItem.eventItems.size()); + for (const auto &eventItem : eventGroupItem.eventItems) { + AttrWithId attrId; + attrId.attr = eventItem.attr; + attrId.name = eventItem.configName; + HLOGV(" fdItems %zu fdItems:", eventItem.fdItems.size()); + for (const auto &fdItem : eventItem.fdItems) { + auto &id = attrId.ids.emplace_back(fdItem.GetPrefId()); + HLOGV(" eventItem.fdItems GetPrefId %" PRIu64 "", id); + } + result.emplace_back(attrId); + } + } + return result; +} + +size_t PerfEvents::CalcBufferSize() +{ + size_t bufferSize = MAX_BUFFER_SIZE; + if (!systemTarget_) { + // suppose ring buffer is 4 times as much as mmap + static constexpr int TIMES = 4; + bufferSize = cpuMmap_.size() * mmapPages_ * pageSize_ * TIMES; + if (bufferSize < MIN_BUFFER_SIZE) { + bufferSize = MIN_BUFFER_SIZE; + } else if (bufferSize > MAX_BUFFER_SIZE) { + bufferSize = MAX_BUFFER_SIZE; + } + } + HLOGD("CalcBufferSize return %zu", bufferSize); + return bufferSize; +} + +inline bool PerfEvents::IsRecordInMmap() +{ + if (pollFds_.size() > 0) { + if (poll((struct pollfd *)pollFds_.data(), pollFds_.size(), pollTimeOut_) <= 0) { + // time out try again + return false; + } + } + return true; +} + +static bool CompareRecordTime(const PerfEvents::MmapFd *left, const PerfEvents::MmapFd *right) +{ + return left->timestamp > right->timestamp; +} + +void PerfEvents::ReadRecordsFromMmaps() +{ +#ifdef HIPERF_DEBUG_TIME + const auto readKenelStartTime = steady_clock::now(); +#endif + // get readable mmap at this time + for (auto &it : cpuMmap_) { + ssize_t dataSize = it.second.mmapPage->data_head - it.second.mmapPage->data_tail; + __sync_synchronize(); // this same as rmb in gcc, after reading mmapPage->data_head + if (dataSize <= 0) { + continue; + } + it.second.dataSize = dataSize; + MmapRecordHeap_.push_back(&(it.second)); + } + if (MmapRecordHeap_.empty()) { + return; + } + + if (MmapRecordHeap_.size() > 1) { + for (auto &it : MmapRecordHeap_) { + GetRecordFromMmap(*it); + } + std::make_heap(MmapRecordHeap_.begin(), MmapRecordHeap_.end(), CompareRecordTime); + + size_t heapSize = MmapRecordHeap_.size(); + while (heapSize > 1) { + std::pop_heap(MmapRecordHeap_.begin(), MmapRecordHeap_.begin() + heapSize, + CompareRecordTime); + MoveRecordToBuf(*MmapRecordHeap_[heapSize - 1]); + if (GetRecordFromMmap(*MmapRecordHeap_[heapSize - 1])) { + std::push_heap(MmapRecordHeap_.begin(), MmapRecordHeap_.begin() + heapSize, + CompareRecordTime); + } else { + heapSize--; + } + } + } + + while (GetRecordFromMmap(*MmapRecordHeap_.front())) { + MoveRecordToBuf(*MmapRecordHeap_.front()); + } + MmapRecordHeap_.clear(); + cvRecordBuf_.notify_one(); + +#ifdef HIPERF_DEBUG_TIME + recordKernelReadTime_ += duration_cast(steady_clock::now() - readKenelStartTime); +#endif +} + +bool PerfEvents::GetRecordFromMmap(MmapFd &mmap) +{ + if (mmap.dataSize <= 0) { + return false; + } + + GetRecordFieldFromMmap(mmap, &(mmap.header), mmap.mmapPage->data_tail, sizeof(mmap.header)); + if (mmap.header.type != PERF_RECORD_SAMPLE) { + mmap.timestamp = 0; + return true; + } + // in PERF_RECORD_SAMPLE : header + u64 sample_id + u64 ip + u32 pid + u32 tid + u64 time + constexpr size_t timePos = sizeof(perf_event_header) + sizeof(uint64_t) + sizeof(uint64_t) + + sizeof(uint32_t) + sizeof(uint32_t); + GetRecordFieldFromMmap(mmap, &(mmap.timestamp), mmap.mmapPage->data_tail + timePos, + sizeof(mmap.timestamp)); + return true; +} + +void PerfEvents::GetRecordFieldFromMmap(MmapFd &mmap, void *dest, size_t pos, size_t size) +{ + pos = pos % mmap.bufSize; + size_t tailSize = mmap.bufSize - pos; + size_t copySize = std::min(size, tailSize); + if (memcpy_s(dest, copySize, mmap.buf + pos, copySize) != 0) { + HLOGEP("memcpy_s %p to %p failed. size %zd", mmap.buf + pos, dest, copySize); + } + if (copySize < size) { + size -= copySize; + if (memcpy_s(static_cast(dest) + copySize, size, mmap.buf, size) != 0) { + HLOGEP("memcpy_s %p to %p failed. size %zd", mmap.buf, + static_cast(dest) + copySize, size); + } + } +} + +size_t PerfEvents::GetCallChainPosInSampleRecord(const perf_event_attr &attr) +{ + // reference struct PerfRecordSampleData + int fixedFieldNumber = __builtin_popcountll( + attr.sample_type & (PERF_SAMPLE_IDENTIFIER | PERF_SAMPLE_IP | PERF_SAMPLE_TID | + PERF_SAMPLE_TIME | PERF_SAMPLE_ADDR | PERF_SAMPLE_ID | + PERF_SAMPLE_STREAM_ID | PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD)); + size_t pos = sizeof(perf_event_header) + sizeof(uint64_t) * fixedFieldNumber; + if (attr.sample_type & PERF_SAMPLE_READ) { + pos += sizeof(read_format); + } + return pos; +} + +size_t PerfEvents::GetStackSizePosInSampleRecord(MmapFd &mmap) +{ + size_t pos = mmap.posCallChain; + if (mmap.attr->sample_type & PERF_SAMPLE_CALLCHAIN) { + uint64_t nr = 0; + GetRecordFieldFromMmap(mmap, &nr, mmap.mmapPage->data_tail + pos, sizeof(nr)); + pos += (sizeof(nr) + nr * sizeof(uint64_t)); + } + if (mmap.attr->sample_type & PERF_SAMPLE_RAW) { + uint32_t raw_size = 0; + GetRecordFieldFromMmap(mmap, &raw_size, mmap.mmapPage->data_tail + pos, sizeof(raw_size)); + pos += (sizeof(raw_size) + raw_size); + } + if (mmap.attr->sample_type & PERF_SAMPLE_BRANCH_STACK) { + uint64_t bnr = 0; + GetRecordFieldFromMmap(mmap, &bnr, mmap.mmapPage->data_tail + pos, sizeof(bnr)); + pos += (sizeof(bnr) + bnr * sizeof(perf_branch_entry)); + } + if (mmap.attr->sample_type & PERF_SAMPLE_REGS_USER) { + uint64_t user_abi = 0; + GetRecordFieldFromMmap(mmap, &user_abi, mmap.mmapPage->data_tail + pos, sizeof(user_abi)); + pos += sizeof(user_abi); + if (user_abi > 0) { + uint64_t reg_nr = __builtin_popcountll(mmap.attr->sample_regs_user); + pos += reg_nr * sizeof(uint64_t); + } + } + return pos; +} + +bool PerfEvents::CutStackAndMove(MmapFd &mmap) +{ + constexpr uint32_t alignSize = 64; + if (!(mmap.attr->sample_type & PERF_SAMPLE_STACK_USER)) { + return false; + } + size_t stackSizePos = GetStackSizePosInSampleRecord(mmap); + uint64_t stackSize = 0; + GetRecordFieldFromMmap(mmap, &stackSize, mmap.mmapPage->data_tail + stackSizePos, + sizeof(stackSize)); + if (stackSize == 0) { + return false; + } + size_t dynSizePos = stackSizePos + sizeof(uint64_t) + stackSize; + uint64_t dynSize = 0; + GetRecordFieldFromMmap(mmap, &dynSize, mmap.mmapPage->data_tail + dynSizePos, sizeof(dynSize)); + uint64_t newStackSize = std::min(ALIGN(dynSize, alignSize), stackSize); + if (newStackSize >= stackSize) { + return false; + } + HLOGM("stackSize %" PRIx64 " dynSize %" PRIx64 " newStackSize %" PRIx64 "\n", stackSize, dynSize, newStackSize); + // move and cut stack_data + // mmap: |<+++copy1+++>|<++++++copy2++++++>|<---------------cut--------------->|<+++copy3+++>| + // ^ ^ ^ ^ + // new_header stackSizePos dynSizePos + uint16_t recordSize = mmap.header.size; + mmap.header.size -= stackSize - newStackSize; // reduce the stack size + uint8_t *buf = recordBuf_->AllocForWrite(mmap.header.size); + // copy1: new_header + if (memcpy_s(buf, sizeof(perf_event_header), &(mmap.header), sizeof(perf_event_header)) != 0) { + HLOGEP("memcpy_s %p to %p failed. size %zd", &(mmap.header), buf, + sizeof(perf_event_header)); + } + size_t copyPos = sizeof(perf_event_header); + size_t copySize = stackSizePos - sizeof(perf_event_header) + sizeof(stackSize) + newStackSize; + // copy2: copy stack_size, data[stack_size], + GetRecordFieldFromMmap(mmap, buf + copyPos, mmap.mmapPage->data_tail + copyPos, copySize); + copyPos += copySize; + // copy3: copy dyn_size + GetRecordFieldFromMmap(mmap, buf + copyPos, mmap.mmapPage->data_tail + dynSizePos, + recordSize - dynSizePos); + // update stack_size + if (memcpy_s(buf + stackSizePos, sizeof(stackSize), &(newStackSize), sizeof(newStackSize)) != 0) { + HLOGEP("memcpy_s %p to %p failed. size %zd", &(newStackSize), buf + stackSizePos, sizeof(newStackSize)); + } + recordBuf_->EndWrite(); + __sync_synchronize(); + mmap.mmapPage->data_tail += recordSize; + mmap.dataSize -= recordSize; + return true; +} + +void PerfEvents::MoveRecordToBuf(MmapFd &mmap) +{ + uint8_t *buf = nullptr; + if (mmap.header.type == PERF_RECORD_SAMPLE) { + if (recordBuf_->GetFreeSize() <= BUFFER_CRITICAL_LEVEL) { + lostSamples_++; + HLOGD("BUFFER_CRITICAL_LEVEL: lost sample record"); + goto RETURN; + } + if (CutStackAndMove(mmap)) { + return; + } + } else if (mmap.header.type == PERF_RECORD_LOST) { + // in PERF_RECORD_LOST : header + u64 id + u64 lost + constexpr size_t lostPos = sizeof(perf_event_header) + sizeof(uint64_t); + uint64_t lost = 0; + GetRecordFieldFromMmap(mmap, &lost, mmap.mmapPage->data_tail + lostPos, sizeof(lost)); + lostSamples_ += lost; + HLOGD("PERF_RECORD_LOST: lost sample record"); + goto RETURN; + } + + if ((buf = recordBuf_->AllocForWrite(mmap.header.size)) == nullptr) { + // this record type must be Non-Sample + lostNonSamples_++; + HLOGD("alloc buffer failed: lost non-sample record"); + goto RETURN; + } + + GetRecordFieldFromMmap(mmap, buf, mmap.mmapPage->data_tail, mmap.header.size); + recordBuf_->EndWrite(); +RETURN: + __sync_synchronize(); + mmap.mmapPage->data_tail += mmap.header.size; + mmap.dataSize -= mmap.header.size; +} + +void PerfEvents::ReadRecordFromBuf() +{ + HLOGV("enter"); + + const perf_event_attr *attr = GetDefaultAttr(); + uint8_t *p = nullptr; + + while (readRecordThreadRunning_) { + { + std::unique_lock lk(mtxRrecordBuf_); + cvRecordBuf_.wait(lk); + } + while ((p = recordBuf_->GetReadData()) != nullptr) { + uint32_t *type = reinterpret_cast(p); +#ifdef HIPERF_DEBUG_TIME + const auto readingStartTime_ = steady_clock::now(); +#endif +#if !HIDEBUG_SKIP_CALLBACK + recordCallBack_(GetPerfEventRecord(*type, p, *attr)); +#endif + recordEventCount_++; +#ifdef HIPERF_DEBUG_TIME + recordCallBackTime_ += + duration_cast(steady_clock::now() - readingStartTime_); +#endif + recordBuf_->EndRead(); + } + } + HLOGD("exit because trackStoped"); + + // read the data left over in buffer + while ((p = recordBuf_->GetReadData()) != nullptr) { + uint32_t *type = reinterpret_cast(p); +#ifdef HIPERF_DEBUG_TIME + const auto readingStartTime_ = steady_clock::now(); +#endif +#if !HIDEBUG_SKIP_CALLBACK + recordCallBack_(GetPerfEventRecord(*type, p, *attr)); +#endif + recordEventCount_++; +#ifdef HIPERF_DEBUG_TIME + recordCallBackTime_ += duration_cast(steady_clock::now() - readingStartTime_); +#endif + recordBuf_->EndRead(); + } + HLOGD("read all records from buffer"); +} + +bool PerfEvents::HaveTargetsExit(const std::chrono::steady_clock::time_point &startTime) +{ + if (systemTarget_) { + return false; + } + if (trackedCommand_) { + if (trackedCommand_->GetState() < TrackedCommand::State::COMMAND_STARTED) { + return false; // not start yet + } + int wstatus; + if (trackedCommand_->WaitCommand(wstatus)) { + milliseconds usedMsTick = duration_cast(steady_clock::now() - startTime); + printf("tracked command(%s) has exited (total %" PRId64 " ms)\n", + trackedCommand_->GetCommandName().c_str(), (uint64_t)usedMsTick.count()); + return true; + } + return false; + } + + for (auto it = pids_.begin(); it != pids_.end();) { + int rc = kill(*it, 0); + if (rc == -1 or rc == ESRCH) { + it = pids_.erase(it); + } else { + ++it; + } + } + if (pids_.empty()) { + milliseconds usedMsTick = duration_cast(steady_clock::now() - startTime); + printf("tracked processes have exited (total %" PRId64 " ms)\n", (uint64_t)usedMsTick.count()); + return true; + } + return false; +} + +void PerfEvents::RecordLoop() +{ + HLOGV("enter"); + + // calc the time + const auto startTime = steady_clock::now(); + const auto endTime = startTime + timeOut_; + milliseconds usedTimeMsTick {}; + + while (g_trackRunning) { + // time check point + const auto thisTime = steady_clock::now(); + + if (IsRecordInMmap()) { + ReadRecordsFromMmaps(); + } + + if (HaveTargetsExit(startTime)) { + break; + } + + if (thisTime >= endTime) { + usedTimeMsTick = duration_cast(thisTime - startTime); + printf("Timeout exit (total %" PRId64 " ms)\n", (uint64_t)usedTimeMsTick.count()); + if (trackedCommand_) { + trackedCommand_->Stop(); + } + break; + } + } + ReadRecordsFromMmaps(); + + if (!g_trackRunning) { + // for user interrupt situation, print time statistic + usedTimeMsTick = duration_cast(steady_clock::now() - startTime); + printf("User interrupt exit (total %" PRId64 " ms)\n", (uint64_t)usedTimeMsTick.count()); + } +} + +void PerfEvents::StatLoop() +{ + HLOGV("enter"); + + // calc the time + const auto startTime = steady_clock::now(); + const auto endTime = startTime + timeOut_; + auto nextReportTime = startTime + timeReport_; + milliseconds usedTimeMsTick {}; + __u64 durationInSec = 0; + int64_t thesholdTimeInMs = 2 * HUNDREDS; + + while (g_trackRunning) { + // time check point + const auto thisTime = steady_clock::now(); + if (timeReport_ != milliseconds::zero()) { + // stat cmd + if (thisTime >= nextReportTime) { + // only for log or debug? + usedTimeMsTick = duration_cast(thisTime - startTime); + durationInSec = usedTimeMsTick.count(); + auto lefTimeMsTick = duration_cast(endTime - thisTime); + printf("\nReport at %" PRId64 " ms (%" PRId64 " ms left):\n", + (uint64_t)usedTimeMsTick.count(), (uint64_t)lefTimeMsTick.count()); + // end of comments + nextReportTime += timeReport_; + StatReport(durationInSec); + } + } + + if (HaveTargetsExit(startTime)) { + break; + } + + if (thisTime >= endTime) { + usedTimeMsTick = duration_cast(thisTime - startTime); + durationInSec = usedTimeMsTick.count(); + printf("Timeout exit (total %" PRId64 " ms)\n", (uint64_t)usedTimeMsTick.count()); + if (trackedCommand_) { + trackedCommand_->Stop(); + } + break; + } + + // lefttime > 200ms sleep 100ms, else sleep 200us + uint64_t defaultSleepUs = 2 * HUNDREDS; // 200us + if (timeReport_ == milliseconds::zero() + && (timeOut_.count() * THOUSANDS) > thesholdTimeInMs) { + milliseconds leftTimeMsTmp = duration_cast(endTime - thisTime); + if (leftTimeMsTmp.count() > thesholdTimeInMs) { + defaultSleepUs = HUNDREDS * THOUSANDS; // 100ms + } + } + std::this_thread::sleep_for(microseconds(defaultSleepUs)); + } + + if (!g_trackRunning) { + // for user interrupt situation, print time statistic + usedTimeMsTick = duration_cast(steady_clock::now() - startTime); + printf("User interrupt exit (total %" PRId64 " ms)\n", (uint64_t)usedTimeMsTick.count()); + } + + if (timeReport_ == milliseconds::zero()) { + StatReport(durationInSec); + } +} + +const std::string PerfEvents::GetTypeName(perf_type_id type_id) +{ + auto it = PERF_TYPES.find(type_id); + if (it != PERF_TYPES.end()) { + return it->second; + } else { + return ""; + } +} +} // namespace HiPerf +} // namespace Developtools +} // namespace OHOS diff --git a/host/trace_streamer/src/parser/hiperf_parser/hiperf/perf_file_format.cpp b/host/trace_streamer/src/parser/hiperf_parser/hiperf/perf_file_format.cpp new file mode 100644 index 0000000000000000000000000000000000000000..a860dbd43a665163b252f279bd4f23c9b14a5bd5 --- /dev/null +++ b/host/trace_streamer/src/parser/hiperf_parser/hiperf/perf_file_format.cpp @@ -0,0 +1,488 @@ +/* + * Copyright (c) 2021-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. + */ +#include "perf_file_format.h" + +#include "debug_logger.h" + +namespace OHOS { +namespace Developtools { +namespace HiPerf { +std::string PerfFileSection::GetFeatureName(FEATURE featureId) +{ + unsigned int index = static_cast(featureId); + if (featureId >= FEATURE::HIPERF_FIRST_FEATURE) { + index -= static_cast(FEATURE::HIPERF_FIRST_FEATURE); + if (index >= extFeatureNames.size()) { + return featureNames[0]; + } + return extFeatureNames[index]; + } else { + if (index >= featureNames.size()) { + return featureNames[0]; + } + return featureNames[index]; + } +} + +// for read +void PerfFileSection::Init(const char *buffer, size_t maxSize) +{ + rBuffer_ = buffer; + maxSize_ = maxSize; + offset_ = 0; +} + +// for write +void PerfFileSection::Init(char *buffer, size_t maxSize) +{ + wBuffer_ = buffer; + maxSize_ = maxSize; + offset_ = 0; +} + +bool PerfFileSection::Write(uint32_t u32) +{ + uint32_t value = u32; + return Write((char *)&value, sizeof(uint32_t)); +} + +bool PerfFileSection::Write(uint64_t u64) +{ + uint64_t value = u64; + return Write((char *)&value, sizeof(uint64_t)); +} + +bool PerfFileSection::Write(const std::string &str) +{ + if (Write((uint32_t)str.size() + 1)) { // include the ending \0 + return Write(str.c_str(), str.size(), str.size() + 1); + } else { + return false; + } +} + +bool PerfFileSection::Write(const char *buf, size_t size) +{ + return Write(buf, size, size); +} + +bool PerfFileSection::Write(const char *buf, size_t size, size_t max) +{ + if (offset_ + size > maxSize_) { + HLOGE("write out of size!!! offset_ %zu size %zu max %zu", offset_, size, maxSize_); + return false; + } + if (offset_ + max > maxSize_) { + HLOGE("write out of size!!! offset_ %zu size %zu max %zu", offset_, size, maxSize_); + return false; + } + std::copy(buf, buf + size, wBuffer_ + offset_); + if (size >= max) { + offset_ += size; + } else { + offset_ += max; + } + return true; +} + +bool PerfFileSection::Read(uint32_t &value) +{ + static_assert(sizeof(uint32_t) == 4); + return Read((char *)&value, sizeof(uint32_t)); +} + +bool PerfFileSection::Read(uint64_t &value) +{ + static_assert(sizeof(uint64_t) == 8); + + return Read((char *)&value, sizeof(uint64_t)); +} + +bool PerfFileSection::Read(std::string &value) +{ + uint32_t size = 0; + if (!Read(size)) { + return false; + } + // if size large than buf size or 0 size ? + // don't assert for fuzz test + if (size == 0 or size > maxSize_) { + return false; + } + char buf[size]; + if (!Read(buf, size)) { + return false; + } + if (buf[size - 1] != 0) { + return false; + } + value = buf; + HLOGDUMMY("Read String size %u buf : %s", size, value.c_str()); + return true; +} +void PerfFileSection::Skip(size_t size) +{ + offset_ += size; +} + +bool PerfFileSection::Read(char *buf, size_t size) +{ + HLOG_ASSERT(buf != nullptr); + if (size == 0) { + HLOGE("read zero size!!! offset_ %zu size %zu max %zu", offset_, size, maxSize_); + return false; + } else if (offset_ + size > maxSize_) { + HLOGE("read out of size!!! offset_ %zu size %zu max %zu", offset_, size, maxSize_); + if (memset_s(buf, size, 0, size) != EOK) { // make sure the content return is 0 when failed + HLOGE("memset_s failed in PerfFileSection::Read"); + return false; + } + return false; + } + HLOGD("PerfFileSection::Read offset_ %zu size %zu maxSize_ %zu", offset_, size, maxSize_); + std::copy((rBuffer_ + offset_), (rBuffer_ + offset_ + size), buf); + offset_ += size; + HLOGDUMMY("after read offset_ %zx size %zu buf %x", offset_, size, buf[0]); + return true; +} + +uint32_t PerfFileSection::SizeOf(std::string &string) +{ + return sizeof(uint32_t) + string.size() + 1; /* '\0' */ +} + +PerfFileSectionString::PerfFileSectionString(FEATURE id, const char *buf, size_t size) + : PerfFileSection(id) +{ + Init(buf, size); + if (!Read(stdString_)) { + return; // or throw ... + } +} + +PerfFileSectionString::PerfFileSectionString(FEATURE id, const std::string &charString) + : PerfFileSection(id) +{ + stdString_ = charString; +} + +bool PerfFileSectionString::GetBinary(char *buf, size_t size) +{ + if (size < GetSize()) { + return false; + } + + Init(buf, size); + Write(stdString_); + return true; +} + +size_t PerfFileSectionString::GetSize() +{ + return SizeOf(stdString_); +} + +const std::string PerfFileSectionString::toString() const +{ + return stdString_; +} + +size_t PerfFileSectionSymbolsFiles::GetSize() +{ + size_t size = 0; + + size += sizeof(uint32_t); // how many SymbolFileStruct + for (auto &symbolFileStruct : symbolFileStructs_) { + size += SizeOf(symbolFileStruct.filePath_); + size += sizeof(symbolFileStruct.symbolType_); + size += sizeof(symbolFileStruct.textExecVaddr_); + size += sizeof(symbolFileStruct.textExecVaddrFileOffset_); + size += SizeOf(symbolFileStruct.buildId_); + + size += sizeof(uint32_t); // how many SymbolStruct + for (auto &symbolStruct : symbolFileStruct.symbolStructs_) { + size += sizeof(symbolStruct.vaddr_); + size += sizeof(symbolStruct.len_); + size += SizeOf(symbolStruct.symbolName_); + } + } + return size; +} + +PerfFileSectionSymbolsFiles::PerfFileSectionSymbolsFiles(FEATURE id, const char *buf, size_t size) + : PerfFileSection(id) +{ + Init(buf, size); + uint32_t symbolFileNumber = 0; + if (!Read(symbolFileNumber)) { + HLOGE(" symbolFileNumber read failed"); + return; + } else if (symbolFileNumber > MAX_SYMBOLS_FILE_NUMBER) { + HLOGE(" symbolFileNumber %u too large", symbolFileNumber); + return; + } else { + HLOGV(" symbolFileNumber %u", symbolFileNumber); + } + + for (uint32_t i = symbolFileNumber; i > 0; i--) { + auto &symbolFileStruct = symbolFileStructs_.emplace_back(); + + Read(symbolFileStruct.filePath_); + HLOGV(" symbolFileStruct.filePath_ %s", symbolFileStruct.filePath_.c_str()); + + Read(symbolFileStruct.symbolType_); + Read(symbolFileStruct.textExecVaddr_); + Read(symbolFileStruct.textExecVaddrFileOffset_); + Read(symbolFileStruct.buildId_); + + uint32_t symbolsNumber = 0; + if (!Read(symbolsNumber)) { + HLOGE(" symbols read failed"); + return; + } else if (symbolsNumber > MAX_SYMBOLS_NUMBER) { + HLOGE(" symbols %u too large", symbolsNumber); + return; + } else { + HLOGV(" symbols %u", symbolsNumber); + } + for (; symbolsNumber > 0; symbolsNumber--) { + auto &symbolStruct = symbolFileStruct.symbolStructs_.emplace_back(); + Read(symbolStruct.vaddr_); + Read(symbolStruct.len_); + Read(symbolStruct.symbolName_); + } + HLOGV(" %zu SymbolStruct read.", symbolFileStruct.symbolStructs_.size()); + } + HLOGV(" %zu SymbolFileStruct read.", symbolFileStructs_.size()); +} + +bool PerfFileSectionSymbolsFiles::GetBinary(char *buf, size_t size) +{ + HLOGV("PerfFileSectionSymbolsFiles get buffer size %zu.", size); + HLOG_ASSERT(size >= GetSize()); + + Init(buf, size); + if (!Write((uint32_t)symbolFileStructs_.size())) { + HLOGE("PerfFileSectionSymbolsFiles write failed with %zu.", symbolFileStructs_.size()); + return false; + } + for (auto &symbolFileStruct : symbolFileStructs_) { + Write(symbolFileStruct.filePath_); + Write(symbolFileStruct.symbolType_); + Write(symbolFileStruct.textExecVaddr_); + Write(symbolFileStruct.textExecVaddrFileOffset_); + Write(symbolFileStruct.buildId_); + + Write((uint32_t)symbolFileStruct.symbolStructs_.size()); + for (auto &symbolStruct : symbolFileStruct.symbolStructs_) { + Write(symbolStruct.vaddr_); + Write(symbolStruct.len_); + Write(symbolStruct.symbolName_); + } + HLOGV(" %zu SymbolStruct writed. for %s at 0x%016" PRIx64 "@0x%08" PRIx64 ": %s", + symbolFileStruct.symbolStructs_.size(), symbolFileStruct.filePath_.c_str(), + symbolFileStruct.textExecVaddr_, symbolFileStruct.textExecVaddrFileOffset_, + symbolFileStruct.buildId_.c_str()); + } + HLOGV("%zu SymbolFileStruct writed.", symbolFileStructs_.size()); + + return true; +} + +PerfFileSectionNrCpus::PerfFileSectionNrCpus(FEATURE id, const char *buf, size_t size) + : PerfFileSection(id) +{ + Init(buf, size); + if (!Read(nrCpusAvailable_) || !Read(nrCpusOnline_)) { + return; + } +} + +PerfFileSectionNrCpus::PerfFileSectionNrCpus(FEATURE id, uint32_t nrCpusAvailable, + uint32_t nrCpusOnline) + : PerfFileSection(id), nrCpusAvailable_(nrCpusAvailable), nrCpusOnline_(nrCpusOnline) +{ +} + +bool PerfFileSectionNrCpus::GetBinary(char *buf, size_t size) +{ + if (size < GetSize()) { + return false; + } + + Init(buf, size); + Write(nrCpusAvailable_); + Write(nrCpusOnline_); + return true; +} + +size_t PerfFileSectionNrCpus::GetSize() +{ + return (sizeof(nrCpusAvailable_) + sizeof(nrCpusOnline_)); +} + +void PerfFileSectionNrCpus::GetValue(uint32_t &nrCpusAvailable, uint32_t &nrCpusOnline) const +{ + nrCpusAvailable = nrCpusAvailable_; + nrCpusOnline = nrCpusOnline_; +} + +PerfFileSectionU64::PerfFileSectionU64(FEATURE id, const char *buf, size_t size) + : PerfFileSection(id) +{ + Init(buf, size); + if (!Read(value_)) { + return; + } +} + +PerfFileSectionU64::PerfFileSectionU64(FEATURE id, uint64_t v) : PerfFileSection(id) +{ + value_ = v; +} + +bool PerfFileSectionU64::GetBinary(char *buf, size_t size) +{ + if (size < GetSize()) { + return false; + } + + Init(buf, size); + Write(value_); + return true; +} + +size_t PerfFileSectionU64::GetSize() +{ + return sizeof(value_); +} + +void PerfFileSectionU64::GetValue(uint64_t &v) const +{ + v = value_; +} + +PerfFileSectionEventDesc::PerfFileSectionEventDesc(FEATURE id, + const std::vector &eventDesces) + : PerfFileSection(id) +{ + eventDesces_ = eventDesces; +} + +PerfFileSectionEventDesc::PerfFileSectionEventDesc(FEATURE id, const char *buf, size_t size) + : PerfFileSection(id) +{ + constexpr uint32_t maxIds = 500; + Init(buf, size); + uint32_t nr = 0; + if (!Read(nr)) { + return; + } + uint32_t attrSize = 0; + if (!Read(attrSize)) { + return; + } + if (attrSize != sizeof(perf_event_attr)) { // only for log or debug + HLOGW("perf_event_attr version is different, attrSize %d vs %zu", attrSize, + sizeof(perf_event_attr)); + } + + for (; nr > 0; nr--) { + AttrWithId eventDesc; + // compatible with the different version of 'perf_event_attr' + if (attrSize > sizeof(perf_event_attr)) { + if (!Read((char *)&(eventDesc.attr), sizeof(perf_event_attr))) { + return; + } + // skip tail bytes + HLOGW("skip %zu byte for diff attr size", attrSize - sizeof(perf_event_attr)); + Skip(attrSize - sizeof(perf_event_attr)); + } else if (!Read((char *)&(eventDesc.attr), attrSize)) { + return; + } + + uint32_t nrIds = 0; + if (!Read(nrIds)) { + return; + } else if (nrIds == 0 or nrIds > maxIds) { + HLOGW("nrIds is not correct ! %u", nrIds); + return; + } + if (!Read(eventDesc.name)) { + return; + } + eventDesc.ids.resize(nrIds, 0); + if (!Read((char *)eventDesc.ids.data(), sizeof(uint64_t) * nrIds)) { + return; + } + eventDesces_.emplace_back(std::move(eventDesc)); + } + HLOGV("read complete. %zu events", eventDesces_.size()); +} + +bool PerfFileSectionEventDesc::GetBinary(char *buf, size_t size) +{ + if (size < GetSize()) { + return false; + } + Init(buf, size); + + if (!Write((uint32_t)eventDesces_.size())) { + return false; + } + if (!Write((uint32_t)sizeof(perf_event_attr))) { + return false; + } + for (auto &eventDesc : eventDesces_) { + if (!Write((char *)&(eventDesc.attr), sizeof(perf_event_attr))) { + return false; + } + if (!Write((uint32_t)eventDesc.ids.size())) { + return false; + } + if (!Write(eventDesc.name)) { + return false; + } + // clang-format off + if (!Write((char *)eventDesc.ids.data(), + sizeof(uint64_t) * eventDesc.ids.size())) { + // clang-format on + return false; + } + } + return true; +} + +size_t PerfFileSectionEventDesc::GetSize() +{ + size_t size = sizeof(uint32_t); // nr + size += sizeof(uint32_t); // attr_size + + size += (eventDesces_.size() * sizeof(perf_event_attr)); + size += (eventDesces_.size() * sizeof(uint32_t)); // nr_ids + for (auto &eventDesc : eventDesces_) { + size += SizeOf(eventDesc.name); + size += (sizeof(uint64_t) * eventDesc.ids.size()); + } + return size; +} + +void PerfFileSectionEventDesc::GetValue(std::vector &eventDesces) const +{ + eventDesces = eventDesces_; +} +} // namespace HiPerf +} // namespace Developtools +} // namespace OHOS diff --git a/host/trace_streamer/src/parser/hiperf_parser/hiperf/perf_file_reader.cpp b/host/trace_streamer/src/parser/hiperf_parser/hiperf/perf_file_reader.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d60700f10ed72026ca7b2bcd0a8826028cfe9909 --- /dev/null +++ b/host/trace_streamer/src/parser/hiperf_parser/hiperf/perf_file_reader.cpp @@ -0,0 +1,487 @@ +/* + * Copyright (c) 2021-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. + */ +#include "perf_file_reader.h" + +#include +#include +#include +#include + +#include +#include + +#include "utilities.h" + +using namespace std::chrono; +namespace OHOS { +namespace Developtools { +namespace HiPerf { +const int FETURE_MAX = 256; +const int SIZE_FETURE_COUNT = 8; + +std::unique_ptr PerfFileReader::Instance(const std::string &fileName, size_t begin) +{ + std::string resolvedPath = CanonicalizeSpecPath(fileName.c_str()); + FILE *fp = fopen(resolvedPath.c_str(), "rb"); + if (fp == nullptr) { + HLOGE("fail to open file %s", fileName.c_str()); + return nullptr; + } + + std::unique_ptr reader = std::make_unique(fileName, fp, begin); + if (!reader->ReadFileHeader()) { + // Fail to read header, maybe its compressed + if (reader->IsGzipFile()) { + fclose(fp); + reader->fp_ = nullptr; + + if (!UncompressFile(fileName, ".perf.data")) { + HLOGE("Fail to UncompressFile(%s)", fileName.c_str()); + return nullptr; + } + + // open the uncompressed hidden file .perf.data + FILE *fp2 = fopen(".perf.data", "rb"); + if (fp2 == nullptr) { + HLOGE("fail to open uncompressed file .perf.data"); + return nullptr; + } + + reader->fp_ = fp2; + reader->compressData_ = true; + + if (!reader->ReadFileHeader()) { + HLOGE("fail to read header of file .perf.data"); + return nullptr; + } + goto end; + } + return nullptr; + } +end: + if (!reader->ReadAttrSection()) { + return nullptr; + } + return reader; +} + +std::unique_ptr PerfFileReader::Instance(const uint8_t *buff, size_t size) +{ + std::unique_ptr reader = std::make_unique(buff, size); + if (!reader->ReadFileHeader()) { + return nullptr; + } + if (!reader->ReadAttrSection()) { + return nullptr; + } + return reader; +} + +PerfFileReader::PerfFileReader(const std::string &fileName, FILE *fp, size_t begin) + : fp_(fp), fileName_(fileName), fileBegin_(begin) +{ + isMemory_ = false; + featureSectionOffset_ = 0; + struct stat fileStat; + if (fp != nullptr) { + if (fstat(fileno(fp), &fileStat) != -1 and fileStat.st_size > 0) { + fileSize_ = fileStat.st_size - fileBegin_; + } + } + + if (fseek(fp_, fileBegin_, SEEK_SET) != 0) { + HLOGE("fseek() failed"); + } +} + +PerfFileReader::PerfFileReader(const uint8_t *buff, size_t size) : buff_(buff), buffSize_(size) +{ + isMemory_ = true; + buffCurrent_ = 0; +} + +PerfFileReader::~PerfFileReader() +{ + if (isMemory_) { + return; + } + // if file was not closed properly + if (fp_ != nullptr) { + fclose(fp_); + fp_ = nullptr; + } + + // remove the uncompressed .perf.data + if (compressData_) { + if (remove(".perf.data") != 0) { + HLOGE("Fail to remove uncompressed file .perf.data"); + perror("Fail to remove temp file"); + } + } +} + +bool PerfFileReader::IsValidDataFile() +{ + return (memcmp(header_.magic, PERF_MAGIC, sizeof(header_.magic)) == 0); +} + +bool PerfFileReader::IsGzipFile() +{ + return header_.magic[0] == '\x1f' and header_.magic[1] == '\x8b'; +} + +bool PerfFileReader::ReadFileHeader() +{ + if (Read(&header_, sizeof(header_))) { + dataSectionSize_ = header_.data.size; + if (IsValidDataFile()) { + featureSectionOffset_ = header_.data.offset + header_.data.size; + for (int i = 0; i < FETURE_MAX / SIZE_FETURE_COUNT; i++) { + std::bitset features(header_.features[i]); + for (int j = 0; j < SIZE_FETURE_COUNT; j++) { + if (features.test(j)) { + features_.emplace_back((FEATURE)(((uint64_t)i) * SIZE_FETURE_COUNT + j)); + } + } + } + return true; + } + } + return false; +} + +bool PerfFileReader::ReadAttrSection() +{ + if (header_.attrSize != sizeof(perf_file_attr)) { + // 4.19 and 5.1 use diff size , 128 vs 136 + HLOGW("attr size %" PRId64 " doesn't match expected size %zu", header_.attrSize, + sizeof(perf_file_attr)); + } + + int attrCount = header_.attrs.size / header_.attrSize; + if (attrCount == 0) { + HLOGE("no attr in file"); + return false; + } + if (!SeekFromBegin(header_.attrs.offset)) { + return false; + } + for (int i = 0; i < attrCount; ++i) { + std::vector buf(header_.attrSize); + if (!Read(buf.data(), buf.size())) { + return false; + } + // size of perf_event_attr change between different linux kernel versions. + // can not memcpy to perf_file_attr as a whole + perf_file_attr attr {}; + size_t attr_size = header_.attrSize - sizeof(attr.ids); + + // If the size is smaller, you can use a pointer to point directly. + // Our UAPI is 4.19. is less than 5.1 + if (sizeof(perf_event_attr) > header_.attrSize) { + HLOGE("size not match, ptr of perf_event_attr maybe overfollow %zu vs %zu", + sizeof(perf_event_attr), attr_size); + } + + attr.attr = *(reinterpret_cast(&buf[0])); + attr.ids = *(reinterpret_cast(&buf[attr_size])); + vecAttr_.push_back(attr); + } + + // read ids for attr + for (size_t i = 0; i < vecAttr_.size(); ++i) { + std::vector ids; + if (!ReadIdsForAttr(vecAttr_[i], &ids)) { + return false; + } + vecAttrIds_.push_back(ids); + + // map ids to attr index + for (auto id : ids) { + mapId2Attr_[id] = i; + } + } + + return true; +} + +bool PerfFileReader::ReadIdsForAttr(const perf_file_attr &attr, std::vector *ids) +{ + if (attr.ids.size > 0) { + size_t count = attr.ids.size / sizeof(uint64_t); + if (!SeekFromBegin(attr.ids.offset)) { + return false; + } + + ids->resize(count); + if (!Read(ids->data(), attr.ids.size)) { + return false; + } + } + return true; +} + +std::vector PerfFileReader::GetAttrSection() const +{ + std::vector result(vecAttr_.size()); + + for (size_t i = 0; i < vecAttr_.size(); ++i) { + result[i].attr = vecAttr_[i].attr; + result[i].ids = vecAttrIds_[i]; + } + return result; +} + +bool PerfFileReader::ReadDataSection(ProcessRecordCB &callback) +{ + if (!SeekFromBegin(header_.data.offset)) { + return false; + } + + HLOGD("dataSection_ at offset %" PRId64 " + %" PRId64 "", header_.data.offset, + header_.data.size); + + if (!ReadRecord(callback)) { + printf("some record format is error!\n"); + return false; + }; + +#ifdef HIPERF_DEBUG_TIME + printf("readRecordTime: %" PRId64 " ms\n", + duration_cast(readRecordTime_).count()); + printf("readCallbackTime: %" PRId64 " ms\n", + duration_cast(readCallbackTime_).count()); +#endif + return dataSectionSize_ == 0; +} + +const perf_event_attr *PerfFileReader::GetDefaultAttr() +{ + if (vecAttr_.empty()) + return nullptr; + + return &(vecAttr_[0].attr); +} + +bool PerfFileReader::ReadRecord(ProcessRecordCB &callback) +{ +#ifdef HIPERF_DEBUG_TIME + const auto startReadTime = steady_clock::now(); +#endif + // record size can not exceed 64K + HIPERF_BUF_ALIGN uint8_t buf[RECORD_SIZE_LIMIT]; + // diff with reader + uint64_t remainingSize = header_.data.size; + size_t recordNumber = 0; + while (remainingSize > 0) { + if (remainingSize < sizeof(perf_event_header)) { + HLOGW("not enough sizeof perf_event_header"); + return false; + } else if (!Read(buf, sizeof(perf_event_header))) { + HLOGW("read perf_event_header failed."); + return false; + } else { + perf_event_header *header = reinterpret_cast(buf); + if (header->size > sizeof(buf)) { + HLOGE("read record header size error %hu", header->size); + return false; + } + if (remainingSize >= header->size) { + size_t headerSize = sizeof(perf_event_header); + if (Read(buf + headerSize, header->size - headerSize)) { + uint8_t *data = buf; + std::unique_ptr record = GetPerfEventRecord( + static_cast(header->type), data, *GetDefaultAttr()); + // unknown record , break the process + if (!record) { + return false; + } else { + HLOGV("record type %u", record->GetType()); + } + remainingSize -= header->size; +#ifdef HIPERF_DEBUG_TIME + const auto startCallbackTime = steady_clock::now(); +#endif + // call callback to process, then destroy record + callback(std::move(record)); + recordNumber++; +#ifdef HIPERF_DEBUG_TIME + readCallbackTime_ += + duration_cast(steady_clock::now() - startCallbackTime); +#endif + } else { + HLOGE("read record data size failed %zu", header->size - headerSize); + return false; + } + } else { + HLOGE("not enough header->size."); + return false; + } + } + } + HLOGD("read back %zu records", recordNumber); +#ifdef HIPERF_DEBUG_TIME + readRecordTime_ += duration_cast(steady_clock::now() - startReadTime); +#endif + return true; +} + +bool PerfFileReader::Read(void *buf, size_t len) +{ + if (buf == nullptr || len == 0) { + HLOG_ASSERT(buf != nullptr); + HLOG_ASSERT(len > 0); + return false; + } + + if (isMemory_) { + if (buffCurrent_ + len > buffSize_) { + return false; + } + std::copy(buff_ + buffCurrent_, buff_ + buffCurrent_ + len, reinterpret_cast(buf)); + buffCurrent_ += len; + } else if (fread(buf, len, 1, fp_) != 1) { + printf("failed to read file: %d", errno); + return false; + } + return true; +} + +const perf_file_header &PerfFileReader::GetHeader() const +{ + return header_; +} + +bool PerfFileReader::Read(char *buf, uint64_t offset, size_t len) +{ + if (buf == nullptr || len == 0) { + HLOG_ASSERT(buf != nullptr); + HLOG_ASSERT(len > 0); + return false; + } + if (!SeekFromBegin(offset)) { + return false; + } + + if (isMemory_) { + if (buffCurrent_ + len > buffSize_) { + return false; + } + std::copy(buff_ + buffCurrent_, buff_ + buffCurrent_ + len, reinterpret_cast(buf)); + buffCurrent_ += len; + } else if (fread(buf, len, 1, fp_) != 1) { + printf("failed to read file: %d", errno); + return false; + } + HLOGM("offset %" PRIx64 " len %zu buf %x %x %x %x", offset, len, buf[0], buf[1], buf[2], + buf[3]); + return true; +} +const std::vector &PerfFileReader::GetFeatures() const +{ + return features_; +} + +const std::vector> &PerfFileReader::GetFeatureSections() const +{ + return perfFileSections_; +} + +const std::string PerfFileReader::GetFeatureString(const FEATURE feature) const +{ + std::string featureName = PerfFileSection::GetFeatureName(feature); + HLOGV("GetFeatureSection %s", featureName.c_str()); + if (!IsFeatrureStringSection(feature)) { + HLOGV("not a string feature: %s", featureName.c_str()); + } else { + const PerfFileSection *featureSection = GetFeatureSection(feature); + if (featureSection != nullptr) { + const PerfFileSectionString *sectionString = + static_cast(featureSection); + return sectionString->toString(); + } else { + HLOGV("have not found: %s", featureName.c_str()); + } + } + return EMPTY_STRING; +} + +const PerfFileSection *PerfFileReader::GetFeatureSection(FEATURE feature) const +{ + HLOGV("enter"); + for (auto const &it : perfFileSections_) { + HLOGV("perfFileSections %p", it.get()); + if (it->featureId_ == feature) { + return it.get(); + } + } + return nullptr; +} + +bool PerfFileReader::ReadFeatureSection() +{ + uint64_t featureSectionOffsetRead = featureSectionOffset_; + HLOGV(" ReadDataSection data offset '0x%" PRIx64 " ", featureSectionOffset_); + + for (FEATURE feature : features_) { + perf_file_section sectionHeader; + if (!Read((char *)§ionHeader, featureSectionOffsetRead, sizeof(sectionHeader))) { + // read failed ?? + printf("file format not correct. featureSectionOffsetRead '0x%" PRIx64 "\n", + featureSectionOffsetRead); + return false; + } + + HLOGV("process feature %d:%s", feature, PerfFileSection::GetFeatureName(feature).c_str()); + HLOGV(" sectionHeader -> read offset '0x%" PRIx64 " size '0x%" PRIx64 "'", + sectionHeader.offset, sectionHeader.size); + if (isMemory_) { + if (sectionHeader.size == 0 or sectionHeader.size > buffSize_) { + HLOGE("sectionHeader.size %" PRIu64 " is not correct", sectionHeader.size); + return false; + } + } else { + if (sectionHeader.size == 0 or sectionHeader.size > fileSize_) { + HLOGE("sectionHeader.size %" PRIu64 " is not correct", sectionHeader.size); + return false; + } + } + std::vector buf(sectionHeader.size); + if (!Read(&buf[0], sectionHeader.offset, buf.size())) { + // read failed ?? + printf("file format not correct. featureSectionDataOffset '0x%" PRIx64 "\n", + sectionHeader.offset); + return false; + } + if (IsFeatrureStringSection(feature)) { + perfFileSections_.emplace_back( + std::make_unique(feature, (char *)&buf[0], buf.size())); + } else if (feature == FEATURE::HIPERF_FILES_SYMBOL) { + perfFileSections_.emplace_back(std::make_unique( + feature, (char *)&buf[0], buf.size())); + } else if (feature == FEATURE::EVENT_DESC) { + perfFileSections_.emplace_back( + std::make_unique(feature, (char *)&buf[0], buf.size())); + } else { + HLOGW("still not imp how to process with feature %d", feature); + } + + featureSectionOffsetRead += sizeof(sectionHeader); // next feaure + } + return true; +} +} // namespace HiPerf +} // namespace Developtools +} // namespace OHOS diff --git a/host/trace_streamer/src/parser/hiperf_parser/hiperf/program_header.cpp b/host/trace_streamer/src/parser/hiperf_parser/hiperf/program_header.cpp new file mode 100644 index 0000000000000000000000000000000000000000..636ac74934becf670b375484a0236fb8bdd476ae --- /dev/null +++ b/host/trace_streamer/src/parser/hiperf_parser/hiperf/program_header.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2021-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. + */ + +#include + +using namespace OHOS::Developtools::HiPerf::ELF; +namespace OHOS { +namespace Developtools { +namespace HiPerf { +std::unique_ptr ProgramHeader::MakeUnique(char * const phdrBuf, const size_t bufSize) +{ + std::unique_ptr phdr {new (std::nothrow) ProgramHeader()}; + if (phdr == nullptr) { + HLOGE("ProgramHeader() failed"); + return nullptr; + } + if (!phdr->Init(phdrBuf, bufSize)) { + HLOGE("ProgramHeader::Init(phdrBuf, bufSize) failed"); + DumpPhdrBuf(phdrBuf, bufSize); + return nullptr; + } + return phdr; +} + +bool ProgramHeader::ParsePrgHeader32(char * const phdrBuf) +{ + uint32_t *u4Buf = reinterpret_cast(phdrBuf); + size_t index {0}; + type_ = u4Buf[index]; + ++index; + offset_ = u4Buf[index]; + ++index; + vaddr_ = u4Buf[index]; + ++index; + paddr_ = u4Buf[index]; + ++index; + fileSize_ = u4Buf[index]; + ++index; + memSize_ = u4Buf[index]; + ++index; + flags_ = u4Buf[index]; + ++index; + secAlign_ = u4Buf[index]; + return true; +} + +bool ProgramHeader::ParsePrgHeader64(char * const phdrBuf) +{ + uint32_t *u4Buf = reinterpret_cast(phdrBuf); + size_t index {0}; + type_ = u4Buf[index]; + ++index; + flags_ = u4Buf[index]; + + uint64_t *u8Buf = reinterpret_cast(phdrBuf); + offset_ = u8Buf[index]; + ++index; + vaddr_ = u8Buf[index]; + ++index; + paddr_ = u8Buf[index]; + ++index; + fileSize_ = u8Buf[index]; + ++index; + memSize_ = u8Buf[index]; + ++index; + secAlign_ = u8Buf[index]; + return true; +} +} // namespace HiPerf +} // namespace Developtools +} // namespace OHOS diff --git a/host/trace_streamer/src/parser/hiperf_parser/hiperf/register.cpp b/host/trace_streamer/src/parser/hiperf_parser/hiperf/register.cpp new file mode 100644 index 0000000000000000000000000000000000000000..248572b2b5b195b8db0d335e032fa393f8fd8571 --- /dev/null +++ b/host/trace_streamer/src/parser/hiperf_parser/hiperf/register.cpp @@ -0,0 +1,273 @@ +/* + * Copyright (c) 2021-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. + */ + +// for libunwind.h empty struct has size 0 in c, size 1 in c++ +#define UNW_EMPTY_STRUCT uint8_t unused + +#include "register.h" + +#if !is_mingw +#include +#endif + +#if HAVE_LIBUNWIND +#include +#endif + +#include "debug_logger.h" + +namespace OHOS { +namespace Developtools { +namespace HiPerf { +static ArchType deviceArchType = ArchType::UNSUPPORT; + +// these copy from kerne uapi perf_regs.h +uint64_t GetSupportedRegMask(ArchType arch) +{ + uint64_t result = 0; + switch (arch) { + case ArchType::X86_32: + result = ((1ULL << PERF_REG_X86_32_MAX) - 1); + break; + case ArchType::X86_64: + result = ((1ULL << PERF_REG_X86_64_MAX) - 1); + result &= ~((1ULL << PERF_REG_X86_DS) | (1ULL << PERF_REG_X86_ES) | + (1ULL << PERF_REG_X86_FS) | (1ULL << PERF_REG_X86_GS)); + break; + case ArchType::ARM: + result = ((1ULL << PERF_REG_ARM_MAX) - 1); + break; + case ArchType::ARM64: + result = ((1ULL << PERF_REG_ARM64_MAX) - 1); + break; + default: + result = std::numeric_limits::max(); + HLOGE("unsupport arch %d", arch); + break; + } + return result; +} + +#if HAVE_LIBUNWIND +const std::map LibUnwindRegMap = { +#if defined(target_cpu_x64) + {UNW_X86_64_RAX, PERF_REG_X86_AX}, {UNW_X86_64_RDX, PERF_REG_X86_DX}, + {UNW_X86_64_RCX, PERF_REG_X86_CX}, {UNW_X86_64_RBX, PERF_REG_X86_BX}, + {UNW_X86_64_RSI, PERF_REG_X86_SI}, {UNW_X86_64_RDI, PERF_REG_X86_DI}, + {UNW_X86_64_RBP, PERF_REG_X86_BP}, {UNW_X86_64_RSP, PERF_REG_X86_SP}, + {UNW_X86_64_R8, PERF_REG_X86_R8}, {UNW_X86_64_R9, PERF_REG_X86_R9}, + {UNW_X86_64_R10, PERF_REG_X86_R10}, {UNW_X86_64_R11, PERF_REG_X86_R11}, + {UNW_X86_64_R12, PERF_REG_X86_R12}, {UNW_X86_64_R13, PERF_REG_X86_R13}, + {UNW_X86_64_R14, PERF_REG_X86_R14}, {UNW_X86_64_R15, PERF_REG_X86_R15}, + {UNW_X86_64_RIP, PERF_REG_X86_IP}, +#elif defined(target_cpu_arm64) + {UNW_AARCH64_X0, PERF_REG_ARM64_X0}, {UNW_AARCH64_X1, PERF_REG_ARM64_X1}, + {UNW_AARCH64_X2, PERF_REG_ARM64_X2}, {UNW_AARCH64_X3, PERF_REG_ARM64_X3}, + {UNW_AARCH64_X4, PERF_REG_ARM64_X4}, {UNW_AARCH64_X5, PERF_REG_ARM64_X5}, + {UNW_AARCH64_X6, PERF_REG_ARM64_X6}, {UNW_AARCH64_X7, PERF_REG_ARM64_X7}, + {UNW_AARCH64_X8, PERF_REG_ARM64_X8}, {UNW_AARCH64_X9, PERF_REG_ARM64_X9}, + {UNW_AARCH64_X10, PERF_REG_ARM64_X10}, {UNW_AARCH64_X11, PERF_REG_ARM64_X11}, + {UNW_AARCH64_X12, PERF_REG_ARM64_X12}, {UNW_AARCH64_X13, PERF_REG_ARM64_X13}, + {UNW_AARCH64_X14, PERF_REG_ARM64_X14}, {UNW_AARCH64_X15, PERF_REG_ARM64_X15}, + {UNW_AARCH64_X16, PERF_REG_ARM64_X16}, {UNW_AARCH64_X17, PERF_REG_ARM64_X17}, + {UNW_AARCH64_X18, PERF_REG_ARM64_X18}, {UNW_AARCH64_X19, PERF_REG_ARM64_X19}, + {UNW_AARCH64_X20, PERF_REG_ARM64_X20}, {UNW_AARCH64_X21, PERF_REG_ARM64_X21}, + {UNW_AARCH64_X22, PERF_REG_ARM64_X22}, {UNW_AARCH64_X23, PERF_REG_ARM64_X23}, + {UNW_AARCH64_X24, PERF_REG_ARM64_X24}, {UNW_AARCH64_X25, PERF_REG_ARM64_X25}, + {UNW_AARCH64_X26, PERF_REG_ARM64_X26}, {UNW_AARCH64_X27, PERF_REG_ARM64_X27}, + {UNW_AARCH64_X28, PERF_REG_ARM64_X28}, {UNW_AARCH64_X29, PERF_REG_ARM64_X29}, + {UNW_AARCH64_X30, PERF_REG_ARM64_LR}, {UNW_AARCH64_SP, PERF_REG_ARM64_SP}, + {UNW_AARCH64_PC, PERF_REG_ARM64_PC}, +#elif defined(target_cpu_arm) + {UNW_ARM_R0, PERF_REG_ARM_R0}, {UNW_ARM_R1, PERF_REG_ARM_R1}, {UNW_ARM_R2, PERF_REG_ARM_R2}, + {UNW_ARM_R3, PERF_REG_ARM_R3}, {UNW_ARM_R4, PERF_REG_ARM_R4}, {UNW_ARM_R5, PERF_REG_ARM_R5}, + {UNW_ARM_R6, PERF_REG_ARM_R6}, {UNW_ARM_R7, PERF_REG_ARM_R7}, {UNW_ARM_R8, PERF_REG_ARM_R8}, + {UNW_ARM_R9, PERF_REG_ARM_R9}, {UNW_ARM_R10, PERF_REG_ARM_R10}, {UNW_ARM_R11, PERF_REG_ARM_FP}, + {UNW_ARM_R12, PERF_REG_ARM_IP}, {UNW_ARM_R13, PERF_REG_ARM_SP}, {UNW_ARM_R14, PERF_REG_ARM_LR}, + {UNW_ARM_R15, PERF_REG_ARM_PC}, +#else +#error not support +#endif +}; + +int LibunwindRegIdToPerfReg(int libUnwindReg) +{ + if (LibUnwindRegMap.count(libUnwindReg)) { + return LibUnwindRegMap.at(libUnwindReg); + } else { + HLOGE("unwind: invalid reg id %d", libUnwindReg); + return -EINVAL; + } +} +#endif + +const std::string UpdatePerfContext(uint64_t addr, perf_callchain_context &perfCallchainContext) +{ + if (PERF_CONTEXT_NAME.count(addr) != 0) { + perfCallchainContext = static_cast(addr); + return StringPrintf("%s: %" PRIx64 "", PERF_CONTEXT_NAME.at(addr).c_str(), addr); + } else { + perfCallchainContext = PERF_CONTEXT_MAX; + return StringPrintf("unknow context: %" PRIx64 "", addr); + } +} + +const std::string GetArchName(ArchType arch) +{ + switch (arch) { + case ArchType::X86_32: + return "X86_32"; + case ArchType::X86_64: + return "X86_64"; + case ArchType::ARM: + return "ARM"; + case ArchType::ARM64: + return "ARM64"; + default: + return "Unsupport"; + } +} + +size_t RegisterGetIP(ArchType arch) +{ + switch (arch) { + case ArchType::X86_32: + case ArchType::X86_64: + return PERF_REG_X86_IP; + case ArchType::ARM: + return PERF_REG_ARM_PC; + case ArchType::ARM64: + return PERF_REG_ARM64_PC; + default: + return std::numeric_limits::max(); + } +} + +size_t RegisterGetSP(ArchType arch) +{ + switch (arch) { + case ArchType::X86_32: + case ArchType::X86_64: + return PERF_REG_X86_SP; + case ArchType::ARM: + return PERF_REG_ARM_SP; + case ArchType::ARM64: + return PERF_REG_ARM64_SP; + default: + return std::numeric_limits::max(); + } +} + +const std::string RegisterGetName(size_t registerIndex) +{ + std::string name; + name.append("PerfReg["); + name.append(std::to_string(registerIndex)); + if (PERF_REG_NAME_MAP.count(registerIndex) > 0) { + name.append(":"); + name.append(PERF_REG_NAME_MAP.at(registerIndex)); + } + name.append("]"); + return name; +} + +bool RegisterGetValue(uint64_t &value, const u64 registers[], const size_t registerIndex, + const size_t registerNumber) +{ + if (registerIndex >= registerNumber) { + HLOGE("registerIndex is %zu, max is %zu", registerIndex, registerNumber); + return false; + } + value = registers[registerIndex]; + return true; +} + +ArchType GetArchTypeFromUname(const std::string &machine) +{ + if (StringStartsWith(machine, "arm")) { + if (machine == "armv8l") { + // 32 bit elf run in 64 bit cpu + return ArchType::ARM64; + } + return ArchType::ARM; + } else if (machine == "aarch64") { + return ArchType::ARM64; + } else if (machine == "x86_64") { + return ArchType::X86_64; + } else if (machine == "x86" || machine == "i686") { + return ArchType::X86_32; + } else { + HLOGE("unsupport machine %s", machine.c_str()); + return ArchType::UNSUPPORT; + } +} + +ArchType GetArchTypeFromABI(bool abi32) +{ + if (deviceArchType == ArchType::UNSUPPORT) { + deviceArchType = GetDeviceArch(); + } + if (abi32) { + if (deviceArchType == ArchType::ARM64) { + return ArchType::ARM; + } else if (deviceArchType == ArchType::X86_64) { + return ArchType::X86_32; + } + } + return deviceArchType; +} + +ArchType SetDeviceArch(ArchType arch) +{ + HLOGD("deviceArchType change to %s", GetArchName(arch).c_str()); + deviceArchType = arch; + return deviceArchType; +} + +ArchType GetDeviceArch() +{ +#if is_mingw + return deviceArchType; +#else + if (deviceArchType != ArchType::UNSUPPORT) { + return deviceArchType; + } else { + utsname systemName; + if ((uname(&systemName)) != 0) { + // fallback + deviceArchType = buildArchType; + } else { + deviceArchType = GetArchTypeFromUname(systemName.machine); + HLOGD("machine arch is %s : %s", systemName.machine, + GetArchName(deviceArchType).c_str()); + if (deviceArchType == ArchType::UNSUPPORT) { + deviceArchType = buildArchType; + } + } + } + return deviceArchType; +#endif +} + +void UpdateRegForABI(ArchType arch, u64 *regs) +{ + if (deviceArchType == ArchType::ARM64 and arch == ArchType::ARM) { + // arm in arm64 + regs[PERF_REG_ARM_PC] = regs[PERF_REG_ARM64_PC]; + } +} +} // namespace HiPerf +} // namespace Developtools +} // namespace OHOS diff --git a/host/trace_streamer/src/parser/hiperf_parser/hiperf/report.cpp b/host/trace_streamer/src/parser/hiperf_parser/hiperf/report.cpp new file mode 100644 index 0000000000000000000000000000000000000000..e5b0ed61a48de5a7ec0c1bec0677f8e705c95f5e --- /dev/null +++ b/host/trace_streamer/src/parser/hiperf_parser/hiperf/report.cpp @@ -0,0 +1,656 @@ +/* + * Copyright (c) 2021-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. + */ +#define HILOG_TAG "Report" + +#include "report.h" + +#include +#include +#include + +#if is_mingw +#include +#else +#include +#endif + +using namespace std::placeholders; +namespace OHOS { +namespace Developtools { +namespace HiPerf { +unsigned long long ReportItem::allIndex_ = 0; +void Report::AddReportItem(const PerfRecordSample &sample, bool includeCallStack) +{ + size_t configIndex = GetConfigIndex(sample.data_.id); + HLOG_ASSERT_MESSAGE(configs_.size() > configIndex, + "in %zu configs found index %zu, from ids %llu", configs_.size(), + configIndex, sample.data_.id); + VirtualThread &thread = virtualRuntime_.GetThread(sample.data_.pid, sample.data_.tid); + HLOG_ASSERT(sample.callFrames_.size() > 0); + if (sample.callFrames_.size() > 0) { + // if we need callstack ? + if (includeCallStack) { + // we will use caller mode , from last to first + auto frameIt = sample.callFrames_.rbegin(); + ReportItem &item = configs_[configIndex].reportItems_.emplace_back( + sample.data_.pid, sample.data_.tid, thread.name_, frameIt->filePath_, + frameIt->symbolName_, frameIt->vaddrInFile_, sample.data_.period); + HLOGV("%s", item.ToDebugString().c_str()); + HLOG_ASSERT(!item.func_.empty()); + + std::vector *currentCallFrames = &item.callStacks_; + for (frameIt = sample.callFrames_.rbegin(); frameIt != sample.callFrames_.rend(); + frameIt++) { + HLOG_ASSERT(frameIt->ip_ < PERF_CONTEXT_MAX); + // in add items case , right one should only have 1 callstack + // so just new callfames and move to next level + ReportItemCallFrame &nextCallFrame = currentCallFrames->emplace_back( + frameIt->symbolName_, frameIt->vaddrInFile_, frameIt->filePath_, + sample.data_.period, + (std::next(frameIt) == sample.callFrames_.rend()) ? sample.data_.period : 0); + HLOGV("add callframe %s", nextCallFrame.ToDebugString().c_str()); + currentCallFrames = &nextCallFrame.childs; + } + HLOGV("callstack %zu", item.callStacks_.size()); + if (item.callStacks_.size() > 0) { + HLOGV("callstack 2nd level %zu", item.callStacks_[0].childs.size()); + } + } else { + auto frameIt = sample.callFrames_.begin(); + HLOG_ASSERT(frameIt->ip_ < PERF_CONTEXT_MAX); + ReportItem &item = configs_[configIndex].reportItems_.emplace_back( + sample.data_.pid, sample.data_.tid, thread.name_, frameIt->filePath_, + frameIt->symbolName_, frameIt->vaddrInFile_, sample.data_.period); + HLOGV("%s", item.ToDebugString().c_str()); + HLOG_ASSERT(!item.func_.empty()); + } + } + configs_[configIndex].sampleCount_++; + configs_[configIndex].eventCount_ += sample.data_.period; +} + +void Report::AddReportItemBranch(const PerfRecordSample &sample) +{ + size_t configIndex = GetConfigIndex(sample.data_.id); + HLOG_ASSERT(configs_.size() > configIndex); + VirtualThread &thread = virtualRuntime_.GetThread(sample.data_.pid, sample.data_.tid); + for (u64 i = 0; i < sample.data_.bnr; i++) { + Symbol symbol_to = + virtualRuntime_.GetSymbol(sample.data_.lbr[i].to, sample.data_.pid, sample.data_.tid); + Symbol symbol_from = + virtualRuntime_.GetSymbol(sample.data_.lbr[i].from, sample.data_.pid, sample.data_.tid); + + // branch only have 1 time only for period + ReportItem &item = configs_[configIndex].reportItems_.emplace_back( + sample.data_.pid, sample.data_.tid, thread.name_, symbol_to.module_, symbol_to.Name(), + symbol_to.funcVaddr_, 1u); + + item.fromDso_ = symbol_from.module_; + item.fromFunc_ = symbol_from.Name(); + + HLOGV("%s 0x%" PRIx64 "", item.ToDebugString().c_str(), symbol_to.taskVaddr_); + } + configs_[configIndex].sampleCount_++; + configs_[configIndex].eventCount_ += sample.data_.bnr; +} + +void Report::StatisticsRecords() +{ + for (auto &config : configs_) { + size_t duplicates = 0; + size_t totalReportCount = config.reportItems_.size(); + // merge duplicate + HLOGD("uniquing %zu", totalReportCount); + auto last = std::unique(config.reportItems_.begin(), config.reportItems_.end(), + std::bind(&Report::MultiLevelSameAndUpdateCount, this, _1, _2)); + + config.reportItems_.erase(last, config.reportItems_.end()); + + duplicates = totalReportCount - config.reportItems_.size(); + HLOGD("duplicates %zu, %zu -> %zu", duplicates, totalReportCount, + config.reportItems_.size()); + } +} + +void Report::FilterDisplayRecords() +{ + // remove the item with not in fliter + for (auto &config : configs_) { + size_t filterOuts = 0; + size_t totalReportCount = config.reportItems_.size(); + for (auto &reportKeyPair : reportKeyMap_) { + auto reportKey = reportKeyPair.second; + if (reportKey.displayFilter_.size() != 0) { + auto itemIt = config.reportItems_.begin(); + while (itemIt != config.reportItems_.end()) { + if (!reportKey.ShouldDisplay(*itemIt)) { + HLOGM("filter out %s", itemIt->ToDebugString().c_str()); + + // we need recalc the heating ,so also remove in total count + config.eventCount_ -= itemIt->eventCount_; + + // after update total eventCount remove this + itemIt = config.reportItems_.erase(itemIt); + filterOuts++; + } else { + itemIt++; + } + } + } + } + HLOGD("filter out %zu, %zu -> %zu", filterOuts, totalReportCount, + config.reportItems_.size()); + } +} + +void Report::UpdateReportItemsAfterAdjust() +{ + for (auto &config : configs_) { + HLOGV("percentage %zu items", config.reportItems_.size()); + uint64_t totalEventCount = 0; // just for debug check + for (auto &item : config.reportItems_) { + item.heat = Percentage(item.eventCount_, config.eventCount_); + totalEventCount += item.eventCount_; + HLOGM("%s percentage from %5.2f%% %" PRIu64 "/ %" PRIu64 "", + item.ToDebugString().c_str(), item.heat, item.eventCount_, config.eventCount_); + for (auto keyPair : reportKeyMap_) { + reportKeyMap_.at(keyPair.first).UpdateValueMaxLen(keyPair.second.GetValue(item)); + } + } + // check again + HLOGV("recalc totalEventCount is %" PRIu64 " old totalEventCount is %" PRIu64 "", + totalEventCount, config.eventCount_); + HLOG_ASSERT(totalEventCount == config.eventCount_); + } +} + +void Report::AdjustReportItems() +{ + HLOGD("Adjust Record Order ...."); + for (auto &config : configs_) { + uint64_t totalReportCount = config.reportItems_.size(); + if (option_.debug_) { + for (auto &reportItem : config.reportItems_) { + HLOGV("reportItem %s", reportItem.ToDebugString().c_str()); + } + } + // sort first. + HLOGD("MultiLevelSorting %" PRIu64 "", totalReportCount); + std::sort(config.reportItems_.begin(), config.reportItems_.end(), + std::bind(&Report::MultiLevelSorting, this, _1, _2)); + HLOGD("MultiLevelSorting %" PRIu64 " done", totalReportCount); + // reorder the callstack + if (option_.debug_) { + for (auto &reportItem : config.reportItems_) { + HLOGV("reportItem %s", reportItem.ToDebugString().c_str()); + } + } + StatisticsRecords(); + FilterDisplayRecords(); + + // reorder by count + std::sort(config.reportItems_.begin(), config.reportItems_.end(), + &ReportItem::CompareSortingEventCount); + + // reorder the callstack + for (auto &reportItem : config.reportItems_) { + ReportItemCallFrame::OrderCallFrames(reportItem.callStacks_); + } + HLOGD("afater sorting and unique, we have %zu report items,", config.reportItems_.size()); + } + // udpate percentage + UpdateReportItemsAfterAdjust(); +} + +int Report::MultiLevelCompare(const ReportItem &a, const ReportItem &b) +{ + HLOGM("MultiLevelCompare %s vs %s sort order %s", a.ToDebugString().c_str(), + b.ToDebugString().c_str(), VectorToString(option_.sortKeys_).c_str()); + + // check each key user care + for (auto it = option_.sortKeys_.begin(); it != option_.sortKeys_.end(); ++it) { + int result = reportKeyMap_.at(*it).compareFunction_(a, b); + if (result == 0) { + // this key is same , check the next one + continue; + } else { + // if onekey is not same , returl as not same + HLOGM("not same because %s %d : %s vs %s", it->c_str(), result, + reportKeyMap_.at(*it).GetValue(a).c_str(), + reportKeyMap_.at(*it).GetValue(b).c_str()); + return result; + } + } + // all the key is same + return 0; +} + +bool Report::MultiLevelSame(const ReportItem &a, const ReportItem &b) +{ + return MultiLevelCompare(a, b) == 0; +} + +void Report::MergeCallFrameCount(ReportItem &leftItem, ReportItem &rightItem) +{ + // add to left (right to left) + std::vector *leftCallFrames = &leftItem.callStacks_; + const std::vector *rightCallFrames = &rightItem.callStacks_; + uint64_t maxEventCount = leftItem.eventCount_; + // right should only have one call stack + int level = 0; + while (rightCallFrames->size() != 0) { + HLOG_ASSERT(rightCallFrames->size() == 1u); + const ReportItemCallFrame &rightFrame = rightCallFrames->at(0); + auto leftFrameIt = std::find(leftCallFrames->begin(), leftCallFrames->end(), rightFrame); + if (leftFrameIt == leftCallFrames->end()) { + // new callfames + auto &leftCallFrame = leftCallFrames->emplace_back(rightFrame); + HLOGV("%*s create frame %s in %s", level, "", leftCallFrame.ToDebugString().c_str(), + leftItem.ToDebugString().c_str()); + HLOG_ASSERT(leftCallFrame.eventCount_ <= maxEventCount); + // this is a new call stack , + // all the child in rightFrame has been copy to left. + break; + } else { + // already have , add count + leftFrameIt->eventCount_ += rightFrame.eventCount_; + leftFrameIt->selfEventCount_ += rightFrame.selfEventCount_; + // left move to next + leftCallFrames = &(leftFrameIt->childs); + HLOGM("%*s udpate frame +%" PRIu64 " %s in %s", level, "", rightFrame.eventCount_, + leftFrameIt->ToDebugString().c_str(), leftItem.ToDebugString().c_str()); + HLOG_ASSERT_MESSAGE(leftFrameIt->eventCount_ <= maxEventCount, + " maxEventCount is %" PRIu64 "", maxEventCount); + maxEventCount = leftFrameIt->eventCount_; + } + // move to next level + rightCallFrames = &(rightFrame.childs); + level++; + } +} + +bool Report::MultiLevelSameAndUpdateCount(ReportItem &l, ReportItem &r) +{ + if (MultiLevelCompare(l, r) == 0) { + l.eventCount_ += r.eventCount_; + HLOGM("l %" PRIu64 " %s c:%zu vs r %" PRIu64 " %s c:%zu", l.eventCount_, l.func_.data(), + l.callStacks_.size(), r.eventCount_, r.func_.data(), r.callStacks_.size()); + // if it have call stack? + if (r.callStacks_.size() != 0) { + // add to left (right to left) + MergeCallFrameCount(l, r); + } + return true; + } else { + return false; + } +} + +bool Report::MultiLevelSorting(const ReportItem &a, const ReportItem &b) +{ + /* + The value returned indicates whether the element passed as first argument is + considered to go before the second in the specific strict weak ordering it defines. + */ + bool result = MultiLevelCompare(a, b) > 0; +#ifdef HIPERF_DEBUG + if (DebugLogger::GetInstance()->GetLogLevel() <= LEVEL_VERBOSE) { + bool result2 = MultiLevelCompare(b, a) > 0; + if (result and result == result2) { + HLOGE("MultiLevelSorting a->b %d vs b->a %d", result, result2); + HLOGE("left %s", a.ToDebugString().c_str()); + HLOGE("right %s", b.ToDebugString().c_str()); + HLOG_ASSERT(false); + } + } +#endif + return result; +} + +void Report::OutputStdStatistics(ReportEventConfigItem &config) +{ + if (fprintf(output_, "\n") < 0) { + return; + } // make a blank line for new event + if (fprintf(output_, "Event: %s (type %" PRIu32 " id %" PRIu64 ")\n", config.eventName_.c_str(), + config.type_, config.config_) < 0) { + return; + } + if (fprintf(output_, "Samples Count: %" PRIu64 "\n", config.sampleCount_) < 0) { + return; + } + if (!config.coutMode_) { + fprintf(output_, "Time in ns: "); + } else { + fprintf(output_, "Event Count: "); + } + fprintf(output_, "%" PRIu64 "\n", config.eventCount_); +} + +bool Report::OutputStdStatistics(ReportEventConfigItem &config, ReportEventConfigItem &otherConfig) +{ + if (config != otherConfig) { + fprintf(output_, "diff config unable compare\n"); + return false; + } + fprintf(output_, "Event: %s (type %" PRIu32 " id %" PRIu64 ")", config.eventName_.c_str(), + config.type_, config.config_); + fprintf(output_, "Samples Count: %" PRIu64 " vs %" PRIu64 "\n", config.sampleCount_, + otherConfig.sampleCount_); + if (config.coutMode_) { + fprintf(output_, "Time in ns: "); + } else { + fprintf(output_, "Event Count: "); + } + fprintf(output_, "%" PRIu64 " vs %" PRIu64 "\n", config.eventCount_, otherConfig.eventCount_); + return true; +} + +void Report::OutputStdHead(ReportEventConfigItem &config, bool diffMode) +{ + // head print + const std::string head = "Heating"; + if (fprintf(output_, "%-*s ", FULL_PERCENTAGE_LEN, head.c_str()) < 0) { + return; + } + + if (diffMode) { + const std::string diff = "Diff"; + fprintf(output_, "%-*s ", FULL_PERCENTAGE_DIFF_LEN, diff.c_str()); + } + + // merge sort key and no-sort key (like count) + + displayKeyNames_ = option_.sortKeys_; + if (!option_.hideCount_) { + displayKeyNames_.insert(displayKeyNames_.begin(), "count"); + } + + unsigned int remainingWidth = consoleWidth_; + // sort key head + for (auto &keyName : displayKeyNames_) { + auto &key = reportKeyMap_.at(keyName); + remainingWidth -= key.maxLen_; + if (remainingWidth <= 0) { + key.maxLen_ = 0; + } + if (fprintf(output_, "%-*s ", (remainingWidth > 0) ? static_cast(key.maxLen_) : 0, + key.keyName_.c_str()) < 0) { + return; + } + HLOGD("'%s' max len %zu(from '%s') console width %d", key.keyName_.c_str(), key.maxLen_, + key.maxValue_.c_str(), remainingWidth); + } + if (fprintf(output_, "\n") < 0) { + return; + } +} + +bool Report::OutputStdCallFrame(int indent, const std::string_view &funcName, uint64_t eventCount, + uint64_t totalEventCount) +{ + float heat = Percentage(eventCount, totalEventCount); + float num = 100.0; + HLOGV("frame %f indent %d at %s", heat, indent, funcName.data()); + + if (heat < option_.callStackHeatLimit_) { + // don't print this three anymore + return false; + } + + if (heat == num) { + fprintf(output_, "%*s", indent, " "); + fprintf(output_, "%*s ", FULL_PERCENTAGE_NUM_LEN, " "); + } else { + fprintf(output_, "%*s", indent, "|- "); + fprintf(output_, "%*.2f%% ", FULL_PERCENTAGE_NUM_LEN, heat); + } + if (option_.debug_) { + fprintf(output_, "%" PRIu64 "/%" PRIu64 " %s\n", eventCount, totalEventCount, + funcName.data()); + } else { + fprintf(output_, "%s\n", funcName.data()); + } + return true; +} + +void Report::PrepareConsole() +{ +#if is_mingw + CONSOLE_SCREEN_BUFFER_INFO csbi; + GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi); + consoleWidth_ = static_cast(csbi.srWindow.Right - csbi.srWindow.Left + 1); + const auto handle = GetStdHandle(STD_OUTPUT_HANDLE); + DWORD mode; + GetConsoleMode(handle, &mode); + mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING; + SetConsoleMode(handle, mode); +#else + struct winsize w = {0, 0, 0, 0}; + ioctl(fileno(stdout), TIOCGWINSZ, &w); + consoleWidth_ = static_cast(w.ws_col); +#endif + if (consoleWidth_ == 0) { + consoleWidth_ = ConsoleDefaultWidth; + } + HLOGD("consoleWidth_:%d", consoleWidth_); +} + +void Report::OutputStdCallFrames(int indent, const ReportItemCallFrame &callFrame, + uint64_t totalEventCount) +{ + /* + 90% a + |- 80% b + c + d + |- 50% e + |- 50% f + g + */ + // this is the first call frame + if (!OutputStdCallFrame(indent, callFrame.func_, callFrame.eventCount_, totalEventCount)) { + // this tree will skipped. + return; + } + + // print it self + if (callFrame.selfEventCount_ != 0 and callFrame.selfEventCount_ != callFrame.eventCount_) { + OutputStdCallFrame(indent + CALLSTACK_INDENT, "[run in self function]", + callFrame.selfEventCount_, callFrame.eventCount_); + } + + // printf children + // if only one children + if (callFrame.childs.size() == 1u and + callFrame.childs[0].eventCount_ == callFrame.eventCount_) { + HLOGV("childCallFream %*c %s", indent, ' ', callFrame.childs[0].func_.data()); + // don't indent if same count (only one 100% children) + OutputStdCallFrames(indent, callFrame.childs[0], callFrame.eventCount_); + } else { + // else a lot children + for (const ReportItemCallFrame &childCallFrame : callFrame.childs) { + HLOGV("childCallFream %*c %s", indent, ' ', childCallFrame.func_.data()); + OutputStdCallFrames(indent + CALLSTACK_INDENT, childCallFrame, callFrame.eventCount_); + } + } +} + +void Report::OutputStdContent(ReportEventConfigItem &config) +{ + // content print + auto it = config.reportItems_.begin(); + while (it != config.reportItems_.end()) { + const ReportItem &reportItem = it.operator*(); + // if we need skip it ? + if (reportItem.heat < option_.heatLimit_) { + it++; + continue; // below limit + } else { + fprintf(output_, "%*.2f%% ", FULL_PERCENTAGE_NUM_LEN, reportItem.heat); + } + OutputStdContentItem(reportItem); + if (reportItem.callStacks_.size() != 0) { + HLOGV("reportItem.callStacks_ %zu %s", reportItem.callStacks_.size(), + reportItem.ToDebugString().c_str()); + HLOG_ASSERT(reportItem.callStacks_.size() == 1u); + for (auto &callFrame : reportItem.callStacks_) { + OutputStdCallFrames(CALLSTACK_INDENT, callFrame, reportItem.eventCount_); + } + } + it++; + } +} + +void Report::OutputStdContentItem(const ReportItem &reportItem) +{ + // output by sort keys + for (auto sortKey : displayKeyNames_) { + ReportKey &reportKey = Report::reportKeyMap_.at(sortKey); + if (fprintf(output_, "%s ", reportKey.GetValue(reportItem).c_str()) < 0) { + return; + } + } + if (fprintf(output_, "\n") < 0) { + return; + } +} + +void Report::OutputStdItemHeating(float heat, float heat2) +{ + if (heat == heat2 and heat == 0.0f) { + fprintf(output_, "something error , all it is end.\n"); + } else if (heat2 == 0) { + // only have first + fprintf(output_, "%*.2f%% ", FULL_PERCENTAGE_NUM_LEN, heat); + fprintf(output_, "%*s ", FULL_PERCENTAGE_DIFF_LEN, ""); + } else if (heat == 0) { + // only have second + fprintf(output_, "%*s ", FULL_PERCENTAGE_LEN, ""); + fprintf(output_, "%+*.2f%% ", FULL_PERCENTAGE_DIFF_NUM_LEN, heat2); + } else if (heat2 > heat) { + fprintf(output_, "%s%*.2f%%%s ", TEXT_RED.c_str(), FULL_PERCENTAGE_NUM_LEN, heat, + TEXT_RESET.c_str()); + fprintf(output_, "%s%+*.2f%%%s ", TEXT_GREEN.c_str(), FULL_PERCENTAGE_DIFF_NUM_LEN, + heat2 - heat, TEXT_RESET.c_str()); + } else if (heat2 < heat) { + fprintf(output_, "%s%*.2f%%%s ", TEXT_GREEN.c_str(), FULL_PERCENTAGE_NUM_LEN, heat, + TEXT_RESET.c_str()); + fprintf(output_, "%s%+*.2f%%%s ", TEXT_RED.c_str(), FULL_PERCENTAGE_DIFF_NUM_LEN, + heat2 - heat, TEXT_RESET.c_str()); + } else { + // same heating + fprintf(output_, "%*.2f%% ", FULL_PERCENTAGE_NUM_LEN, heat); + fprintf(output_, "%+*.2f%% ", FULL_PERCENTAGE_DIFF_NUM_LEN, heat2 - heat); + } +} + +void Report::OutputStdContentDiff(ReportEventConfigItem &left, ReportEventConfigItem &right) +{ + // first we need found the match config + HLOGD("first count %zu second count %zu", left.reportItems_.size(), right.reportItems_.size()); + ReportItemsConstIt it = left.reportItems_.begin(); + ReportItemsConstIt it2 = right.reportItems_.begin(); + while (it != left.reportItems_.end()) { + // still have it2 ? + if (it2 != right.reportItems_.end()) { + // find the same item in it2 by same sort key + while (it2 != right.reportItems_.end()) { + if (MultiLevelSame(*it, *it2)) { + // we found the same item + // output the diff heating + if (it->heat > option_.heatLimit_ and it2->heat > option_.heatLimit_) { + OutputStdItemHeating(it->heat, it2->heat); + OutputStdContentItem(*it); + } + it++; + it2++; + break; // next it + } else { + // only print it2 item + if (it2->heat > option_.heatLimit_) { + OutputStdItemHeating(0.0f, it2->heat); + OutputStdContentItem(*it2); + } + it2++; + continue; // next it2 + } + } + } else { + // no more it2, go on print all the it + if (it->heat > option_.heatLimit_) { + OutputStdItemHeating(it->heat, 0.0f); + OutputStdContentItem(*it); + } + it++; + continue; // next it + } + } + while (it2 != right.reportItems_.end()) { + // if diff still have some item in it2 ,print it + OutputStdItemHeating(0, it2->heat); + OutputStdContentItem(*it2); + it2++; + continue; // next it2 + } +} + +void Report::OutputStdContentDiffOneSide(bool leftOnly, ReportItem &reportItem) +{ + if (reportItem.heat > option_.heatLimit_) { + if (leftOnly) { + OutputStdItemHeating(reportItem.heat, 0.0f); + } else { + OutputStdItemHeating(0.0f, reportItem.heat); + } + OutputStdContentItem(reportItem); + } +} + +void Report::OutputStd(FILE *output) +{ + output_ = output; + PrepareConsole(); + + for (auto &config : configs_) { + OutputStdStatistics(config); + OutputStdHead(config); + OutputStdContent(config); + } +} + +void Report::OutputStdDiff(FILE *output, Report &other) +{ + output_ = output; + PrepareConsole(); + + auto left = configs_.begin(); + while (left != configs_.end()) { + auto right = other.configs_.begin(); + while (right != other.configs_.end()) { + if (*left == *right) { + OutputStdStatistics(*left); + OutputStdHead(*left, true); + OutputStdContentDiff(*left, *right); + break; // check next left + } + right++; + } + left++; // go on left + } +} +} // namespace HiPerf +} // namespace Developtools +} // namespace OHOS diff --git a/host/trace_streamer/src/parser/hiperf_parser/hiperf/ring_buffer.cpp b/host/trace_streamer/src/parser/hiperf_parser/hiperf/ring_buffer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..4aa2dbcc056ee193bde521bab1a244fbd9096e04 --- /dev/null +++ b/host/trace_streamer/src/parser/hiperf_parser/hiperf/ring_buffer.cpp @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2021 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. + */ +#define HILOG_TAG "RingBuffer" + +#include "ring_buffer.h" + +namespace OHOS { +namespace Developtools { +namespace HiPerf { +RingBuffer::RingBuffer(size_t size) : size_(size) +{ + if (size > 0) { + buf_ = std::make_unique(size); + } +} + +RingBuffer::~RingBuffer() {} + +// get size of the writable space +size_t RingBuffer::GetFreeSize() const +{ + return size_ - (head_.load(std::memory_order_relaxed) - tail_.load(std::memory_order_relaxed)); +} + +uint8_t *RingBuffer::AllocForWrite(size_t writeSize) +{ + size_t writeHead = head_.load(std::memory_order_relaxed); + size_t readHead = tail_.load(std::memory_order_acquire); + size_t writePos = writeHead % size_; + size_t readPos = readHead % size_; + writeSize_ = writeSize; + if (writePos < readPos) { + // |---writePos<---writeSize--->readPos---| + if (writePos + writeSize > readPos) { + return nullptr; + } + } else if (writePos == readPos and writeHead != readHead) { + // writePos catch up with readPos, but buffer is full + return nullptr; + } else { + // two cases: 1, writePos catch up with readPos, but buffer is empty + // 2, |---readPos---writePos<---writeSize--->| + if (writePos + writeSize > size_) { + // no enough space at the end + if (readPos < writeSize) { + return nullptr; + } + // wrap to the start, set mark byte + buf_.get()[writePos] = MARGIN_BYTE; + writeSize_ += (size_ - writePos); + writePos = 0; + } + } + + return buf_.get() + writePos; +} + +void RingBuffer::EndWrite() +{ + size_t head = head_.load(std::memory_order_relaxed); + head += writeSize_; + head_.store(head, std::memory_order_release); +} + +uint8_t *RingBuffer::GetReadData() +{ + size_t writeHead = head_.load(std::memory_order_acquire); + size_t readHead = tail_.load(std::memory_order_relaxed); + if (writeHead == readHead) { + return nullptr; + } + + readSize_ = 0; + size_t writePos = writeHead % size_; + size_t readPos = readHead % size_; + if (writePos <= readPos) { + // |<---data2--->writePos---readPos<---data1--->| + if (buf_.get()[readPos] == MARGIN_BYTE) { + if (writePos == 0) { + return nullptr; + } + readSize_ = (size_ - readPos); + readPos = 0; + } + } + // else |---readPos<---data--->writePos---| + perf_event_header *header = reinterpret_cast(buf_.get() + readPos); + readSize_ += header->size; + return buf_.get() + readPos; +} + +void RingBuffer::EndRead() +{ + size_t tail = tail_.load(std::memory_order_relaxed); + tail += readSize_; + tail_.store(tail, std::memory_order_release); +} +} // namespace HiPerf +} // namespace Developtools +} // namespace OHOS diff --git a/host/trace_streamer/src/parser/hiperf_parser/hiperf/section_header.cpp b/host/trace_streamer/src/parser/hiperf_parser/hiperf/section_header.cpp new file mode 100644 index 0000000000000000000000000000000000000000..fa3d0afa11a2ebd569fd803919b7558cdeb48e1f --- /dev/null +++ b/host/trace_streamer/src/parser/hiperf_parser/hiperf/section_header.cpp @@ -0,0 +1,106 @@ +/* + * Copyright (c) 2021-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. + */ + +#include + +using namespace OHOS::Developtools::HiPerf::ELF; +namespace OHOS { +namespace Developtools { +namespace HiPerf { +enum class NUMBER : int { + ZERO = 0, + ONE = 1, + TWO = 2, + THREE = 3, + FOUR = 4, + FIVE = 5, + SIX = 6, + SEVEN = 7, + EIGHT = 8, + NINE = 9, + TEN = 10, + ELEVEN = 11, + TWELVE = 12, +}; + +std::unique_ptr SectionHeader::MakeUnique(char * const shdrBuf, const size_t bufSize, + const size_t index) +{ + std::unique_ptr shdr {new (std::nothrow) SectionHeader()}; + if (shdr == nullptr) { + return nullptr; + } + if (!shdr->Init(shdrBuf, bufSize, index)) { + HLOGE("SectionHeader::Init(shdrBuf, bufSize, index) failed"); + DumpShdrBuf(shdrBuf, bufSize); + return nullptr; + } + return shdr; +} + +bool SectionHeader::ParseSecHeader32(char * const shdrBuf) +{ + uint32_t *u4Buf = reinterpret_cast(shdrBuf); + int index {0}; + nameIndex_ = u4Buf[index]; + index = static_cast(NUMBER::ONE); + secType_ = u4Buf[index]; + index = static_cast(NUMBER::TWO); + secFlags_ = u4Buf[index]; + index = static_cast(NUMBER::SIX); + link_ = u4Buf[index]; + index = static_cast(NUMBER::SEVEN); + info_ = u4Buf[index]; + index = static_cast(NUMBER::THREE); + secVaddr_ = u4Buf[index]; + index = static_cast(NUMBER::FOUR); + fileOffset_ = u4Buf[index]; + index = static_cast(NUMBER::FIVE); + secSize_ = u4Buf[index]; + index = static_cast(NUMBER::EIGHT); + secAddrAlign_ = u4Buf[index]; + index = static_cast(NUMBER::NINE); + secEntrySize_ = u4Buf[index]; + return true; +} + +bool SectionHeader::ParseSecHeader64(char * const shdrBuf) +{ + uint64_t *u8Buf = reinterpret_cast(shdrBuf); + uint32_t *u4Buf = reinterpret_cast(shdrBuf); + size_t index {0}; + nameIndex_ = u4Buf[index]; + index = static_cast(NUMBER::ONE); + secType_ = u4Buf[index]; + secFlags_ = u8Buf[index]; + index = static_cast(NUMBER::TEN); + link_ = u4Buf[index]; + index = static_cast(NUMBER::ELEVEN); + info_ = u4Buf[index]; + index = static_cast(NUMBER::TWO); + secVaddr_ = u8Buf[index]; + index = static_cast(NUMBER::THREE); + fileOffset_ = u8Buf[index]; + index = static_cast(NUMBER::FOUR); + secSize_ = u8Buf[index]; + index = static_cast(NUMBER::SIX); + secAddrAlign_ = u8Buf[index]; + index = static_cast(NUMBER::SEVEN); + secEntrySize_ = u8Buf[index]; + return true; +} +} // namespace HiPerf +} // namespace Developtools +} // namespace OHOS diff --git a/host/trace_streamer/src/parser/hiperf_parser/hiperf/subcommand.cpp b/host/trace_streamer/src/parser/hiperf_parser/hiperf/subcommand.cpp new file mode 100644 index 0000000000000000000000000000000000000000..de86194ab8b34823dee549859236219f56de034c --- /dev/null +++ b/host/trace_streamer/src/parser/hiperf_parser/hiperf/subcommand.cpp @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2021-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. + */ + +#include "subcommand.h" + +#include "debug_logger.h" +#include "option.h" +#include "subcommand_help.h" +#include "utilities.h" + +using namespace std; +namespace OHOS { +namespace Developtools { +namespace HiPerf { +static std::map> g_SubCommandsMap; + +// parse option first +bool SubCommand::OnSubCommandOptions(std::vector args) +{ + // parse common first + if (!Option::GetOptionValue(args, "--dumpoptions", dumpOptions_)) { + return false; + } + if (!Option::GetOptionValue(args, "--help", showHelp_) + || !Option::GetOptionValue(args, "-h", showHelp_)) { + return false; + } + + if (showHelp_) { + if (!args.empty()) { + printf("unknown option '%s'\n", args.front().c_str()); + return false; + } + if (OnPreSubCommand()) { + return false; + } + } + + if (ParseOption(args)) { + if (dumpOptions_) { + DumpOptions(); + } + HLOGD(" args left over: (%zu): %s", args.size(), VectorToString(args).c_str()); + if (!args.empty()) { + printf("unknown option '%s'\n", args.front().c_str()); + return false; + } + } else { + HLOGD("incorrect option(s)\n"); + return false; + } + return true; +} + +bool SubCommand::RegisterSubCommand(std::string cmdName, std::unique_ptr subCommand) +{ + HLOGV("%s", cmdName.c_str()); + if (cmdName.empty()) { + HLOGE("unable to register empty subcommand!"); + return false; + } + if (cmdName.front() == '-') { + HLOGE("unable use '-' at the begin of subcommand '%s'", cmdName.c_str()); + return false; + } + + if (g_SubCommandsMap.count(cmdName) == 0) { + g_SubCommandsMap.insert(std::make_pair(cmdName, std::move(subCommand))); + return true; + } else { + HLOGE("subcommand '%s' already registered!", cmdName.c_str()); + return false; + } +} + +void SubCommand::ClearSubCommands() +{ + g_SubCommandsMap.clear(); +} + +const std::map> &SubCommand::GetSubCommands() +{ + HLOGV("enter"); + return g_SubCommandsMap; +} + +SubCommand *SubCommand::FindSubCommand(std::string cmdName) +{ + HLOGV("%s", cmdName.c_str()); + auto found = g_SubCommandsMap.find(cmdName); + if (found != g_SubCommandsMap.end()) { + // remove the subcmd itself + return found->second.get(); + } else { + return nullptr; + } +} +} // namespace HiPerf +} // namespace Developtools +} // namespace OHOS diff --git a/host/trace_streamer/src/parser/hiperf_parser/hiperf/subcommand.h b/host/trace_streamer/src/parser/hiperf_parser/hiperf/subcommand.h new file mode 100644 index 0000000000000000000000000000000000000000..5f5a683b57a83d90671f363fc21407f88e5822b3 --- /dev/null +++ b/host/trace_streamer/src/parser/hiperf_parser/hiperf/subcommand.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2021-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. + */ +#ifndef HIPERF_SUBCOMMAND_H_ +#define HIPERF_SUBCOMMAND_H_ + +#include +#include +#include "utilities.h" + +namespace OHOS { +namespace Developtools { +namespace HiPerf { +class SubCommand { +public: + SubCommand(const std::string &name, const std::string &brief, const std::string &help) + : name_(name), brief_(brief), help_(help) + { + } + + virtual ~SubCommand() {} + + const std::string &Name() const + { + return name_; + } + const std::string &Brief() const + { + return brief_; + } + const std::string &Help() const + { + return help_; + } + + // parse option first + bool OnSubCommandOptions(std::vector args); + + // some help cmd + bool OnPreSubCommand() + { + if (showHelp_) { + printf("%s\n", Help().c_str()); + return true; + } + return false; + }; + + virtual void DumpOptions() const {} + + // args should be empty after all the args processed + virtual bool ParseOption(std::vector &args) + { + args.clear(); // all the args is processed + return true; + } + + // return false means cmd failed + virtual bool OnSubCommand(std::vector &args) = 0; + // some test code will use this for simple + bool OnSubCommand(std::string stringArgs) + { + auto args = StringSplit(stringArgs, " "); + return OnSubCommand(args); + }; + + // called from main + static bool RegisterSubCommand(std::string, std::unique_ptr); + + // get some cmd + static const std::map> &GetSubCommands(); + static SubCommand *FindSubCommand(std::string); + + // for test code + static void ClearSubCommands(); + +protected: + const std::string name_; + const std::string brief_; + std::string help_; + bool dumpOptions_ = false; + bool showHelp_ = false; +}; +} // namespace HiPerf +} // namespace Developtools +} // namespace OHOS +#endif // HIPERF_SUBCOMMAND_H_ diff --git a/host/trace_streamer/src/parser/hiperf_parser/hiperf/subcommand_dump.cpp b/host/trace_streamer/src/parser/hiperf_parser/hiperf/subcommand_dump.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c41c02c79dca07beb29d7de7db0c9bfede3870c6 --- /dev/null +++ b/host/trace_streamer/src/parser/hiperf_parser/hiperf/subcommand_dump.cpp @@ -0,0 +1,530 @@ +/* + * Copyright (c) 2021-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. + */ +#define HILOG_TAG "Dump" + +#include "subcommand_dump.h" + +#include +#include +#include +#include +#include + +#include "debug_logger.h" +#include "option.h" +#include "perf_event_record.h" +#include "perf_events.h" +#include "symbols_file.h" +#include "utilities.h" +#include "virtual_runtime.h" + +namespace OHOS { +namespace Developtools { +namespace HiPerf { +#define LEVEL1 (indent + 1) +#define LEVEL2 (indent + 2) +#define LEVEL3 (indent + 3) + +bool SubCommandDump::CheckInputFile() +{ + if (!dumpFileName_.empty()) { + if (elfFileName_.empty() && protobufDumpFileName_.empty()) { + return true; + } + } else if (!elfFileName_.empty()) { + if (protobufDumpFileName_.empty()) { + return true; + } + } else if (!protobufDumpFileName_.empty()) { + return true; + } else { // all is empty + dumpFileName_ = DEFAULT_DUMP_FILENAME; + return true; + } + + printf("options conflict, please check usage\n"); + return false; +} + +bool SubCommandDump::ParseOption(std::vector &args) +{ + HLOGV("enter"); + + if (!Option::GetOptionValue(args, "--head", dumpHeader_)) { + HLOGD("get option --head failed"); + return false; + } + if (!Option::GetOptionValue(args, "-f", dumpFeatures_)) { + HLOGD("get option -f failed"); + return false; + } + if (!Option::GetOptionValue(args, "-d", dumpData_)) { + HLOGD("get option -d failed"); + return false; + } + if (!Option::GetOptionValue(args, "--sympath", dumpSymbolsPaths_)) { + HLOGD("get option --sympath failed"); + return false; + } + if (!Option::GetOptionValue(args, "--elf", elfFileName_)) { + HLOGD("get option --elf failed"); + return false; + } +#if HAVE_PROTOBUF + if (!Option::GetOptionValue(args, "--proto", protobufDumpFileName_)) { + HLOGD("get option --proto failed"); + return false; + } +#endif + if (!Option::GetOptionValue(args, "--export", exportSampleIndex_)) { + HLOGD("get option --export failed"); + return false; + } + + if (dumpHeader_ || dumpFeatures_ || dumpData_) { + dumpAll_ = false; + } + + if (args.size() > 1) { + printf("unknown option %s\n", args[0].c_str()); + return false; + } + if (args.size() == 1) { + dumpFileName_ = args[0]; + args.clear(); + } + + return CheckInputFile(); +} + +SubCommandDump::~SubCommandDump() +{ + SymbolsFile::onRecording_ = true; // back to default for UT +} + +bool SubCommandDump::OnSubCommand(std::vector &args) +{ + HLOGV("enter"); + + if (!elfFileName_.empty()) { + return DumpElfFile(); + } + +#if HAVE_PROTOBUF + if (!protobufDumpFileName_.empty()) { + return DumpProtoFile(); + } +#endif + + if (access(dumpFileName_.c_str(), F_OK) != 0) { + printf("Can not access data file %s\n", dumpFileName_.c_str()); + return false; + } + // only one file should created + HLOG_ASSERT_MESSAGE(reader_ == nullptr, " reader_ %p\n", reader_.get()); + reader_ = PerfFileReader::Instance(dumpFileName_); + if (reader_ == nullptr) { + HLOGE("HiperfFileReader::Instance(%s) return null", dumpFileName_.c_str()); + return false; + } + + // any way tell symbols this is not on device + SymbolsFile::onRecording_ = false; + // we need unwind it (for function name match) even not give us path + vr_.SetDisableUnwind(false); + + if (!dumpSymbolsPaths_.empty()) { + // user give us path , we enable unwind + if (!vr_.SetSymbolsPaths(dumpSymbolsPaths_)) { + printf("Failed to set symbol path(%s)\n", VectorToString(dumpSymbolsPaths_).c_str()); + return false; + } + } + + if (dumpHeader_ || dumpAll_) { + DumpPrintFileHeader(indent_); + DumpAttrPortion(indent_); + } + + if (dumpAll_ || dumpData_) { + DumpDataPortion(indent_); + } + + if (dumpFeatures_ || dumpAll_) { + DumpFeaturePortion(indent_); + } + + return true; +} + +bool SubCommandDump::DumpElfFile() +{ + printf("dump elf: '%s'\n", elfFileName_.c_str()); + auto elf = SymbolsFile::CreateSymbolsFile(elfFileName_); + if (!elf->LoadSymbols("")) { + printf("load elf failed.\n"); + return false; + } else { + printf("load elf succeed.\n"); + } + return true; +} +#if HAVE_PROTOBUF +bool SubCommandDump::DumpProtoFile() +{ + printf("dump protobuf file: '%s'\n", protobufDumpFileName_.c_str()); + protobufInputFileReader_ = std::make_unique(); + if (!protobufInputFileReader_->Dump(protobufDumpFileName_)) { + printf("load proto failed.\n"); + return false; + } + return true; +} +#endif + +void SubCommandDump::PrintHeaderInfo(const int &indent) +{ + const perf_file_header &header = reader_->GetHeader(); + // magic + PrintIndent(indent, "magic: "); + for (size_t i = 0; i < sizeof(header.magic); ++i) { + PrintIndent(indent, "%c", header.magic[i]); + } + PrintIndent(indent, "\n"); + PrintIndent(indent, "header_size: %" PRId64 "\n", header.size); + if (header.size != sizeof(header)) { + HLOGW("record file header size doesn't match"); + } + PrintIndent(indent, "attr_size: %" PRId64 "\n", header.attrSize); + if (header.attrSize != sizeof(perf_file_attr)) { + HLOGW("attr size doesn't match"); + } + // attr + PrintIndent(indent, "attrs[file section]: offset %" PRId64 ", size %" PRId64 "\n", + header.attrs.offset, header.attrs.size); + // data + PrintIndent(indent, "data[file section]: offset %" PRId64 ", size %" PRId64 "\n", + header.data.offset, header.data.size); + PrintIndent(indent, "event_types[file section]: offset %" PRId64 ", size %" PRId64 "\n", + header.eventTypes.offset, header.eventTypes.size); + // feature + PrintIndent(indent, + "adds_features[]: 0x%" PRIX64 " 0x%" PRIX64 " 0x%" PRIX64 " 0x%" PRIX64 "\n", + *(reinterpret_cast(&header.features[0])), + *(reinterpret_cast(&header.features[8])), + *(reinterpret_cast(&header.features[16])), + *(reinterpret_cast(&header.features[24]))); +} + +void SubCommandDump::DumpPrintFileHeader(int indent) +{ + // print header + PrintHeaderInfo(indent); + + // print feature + auto features = reader_->GetFeatures(); + for (auto feature : features) { + PrintIndent(indent, "feature: %s\n", PerfFileSection::GetFeatureName(feature).c_str()); + } + + // read here , because we need found symbols + reader_->ReadFeatureSection(); + + SetDeviceArch(GetArchTypeFromUname(reader_->GetFeatureString(FEATURE::ARCH))); + + // found symbols in file + for (auto &featureSection : reader_->GetFeatureSections()) { + if (featureSection.get()->featureId_ == FEATURE::HIPERF_FILES_SYMBOL) { + const PerfFileSectionSymbolsFiles *sectionSymbolsFiles = + static_cast(featureSection.get()); + vr_.UpdateFromPerfData(sectionSymbolsFiles->symbolFileStructs_); + } + } +} + +static std::map g_sampleTypeNames = { + {PERF_SAMPLE_IP, "ip"}, + {PERF_SAMPLE_TID, "tid"}, + {PERF_SAMPLE_TIME, "time"}, + {PERF_SAMPLE_ADDR, "addr"}, + {PERF_SAMPLE_READ, "read"}, + {PERF_SAMPLE_CALLCHAIN, "callchain"}, + {PERF_SAMPLE_ID, "id"}, + {PERF_SAMPLE_CPU, "cpu"}, + {PERF_SAMPLE_PERIOD, "period"}, + {PERF_SAMPLE_STREAM_ID, "stream_id"}, + {PERF_SAMPLE_RAW, "raw"}, + {PERF_SAMPLE_BRANCH_STACK, "stack"}, + {PERF_SAMPLE_REGS_USER, "regs_user"}, + {PERF_SAMPLE_STACK_USER, "stack_user"}, + {PERF_SAMPLE_WEIGHT, "weight"}, + {PERF_SAMPLE_DATA_SRC, "data_src"}, + {PERF_SAMPLE_IDENTIFIER, "identifier"}, + {PERF_SAMPLE_TRANSACTION, "transaction"}, + {PERF_SAMPLE_REGS_INTR, "reg_intr"}, +}; + +void SubCommandDump::DumpSampleType(uint64_t sampleType, int indent) +{ + std::string names; + for (auto &pair : g_sampleTypeNames) { + if (sampleType & pair.first) { + if (!names.empty()) { + names.append(","); + } + names.append(pair.second); + } + } + PrintIndent(LEVEL1, "sample_type names: %s\n", names.c_str()); +} + +void SubCommandDump::DumpPrintEventAttr(const perf_event_attr &attr, int indent) +{ + PrintIndent(indent, "event_attr: \n"); + + PrintIndent(LEVEL1, "type %u, size %u, config %llu\n", attr.type, attr.size, attr.config); + + if (attr.freq != 0) { + PrintIndent(LEVEL1, "sample_freq %llu\n", attr.sample_freq); + } else { + PrintIndent(LEVEL1, "sample_period %llu\n", attr.sample_period); + } + + PrintIndent(LEVEL1, "sample_type (0x%llx) \n", attr.sample_type); + DumpSampleType(attr.sample_type, indent); + + PrintIndent(LEVEL1, "read_format (0x%llx) \n", attr.read_format); + + PrintIndent(LEVEL1, "disabled %u, inherit %u, pinned %u, exclusive %u\n", attr.disabled, + attr.inherit, attr.pinned, attr.exclusive); + + PrintIndent(LEVEL1, "exclude_user %u, exclude_kernel %u, exclude_hv %u, exclude_idle %u\n", + attr.exclude_user, attr.exclude_kernel, attr.exclude_hv, attr.exclude_idle); + + PrintIndent(LEVEL1, "mmap %u, mmap2 %u, comm %u, comm_exec %u, freq %u\n", attr.mmap, + attr.mmap2, attr.comm, attr.comm_exec, attr.freq); + + PrintIndent(LEVEL1, "inherit_stat %u, enable_on_exec %u, task %u, use_clockid %u\n", + attr.inherit_stat, attr.enable_on_exec, attr.task, attr.use_clockid); + + PrintIndent(LEVEL1, "watermark %u, precise_ip %u, mmap_data %u, clockid %u\n", attr.watermark, + attr.precise_ip, attr.mmap_data, attr.clockid); + + PrintIndent(LEVEL1, "sample_id_all %u, exclude_host %u, exclude_guest %u\n", attr.sample_id_all, + attr.exclude_host, attr.exclude_guest); + PrintIndent(LEVEL1, "branch_sample_type 0x%llx\n", attr.branch_sample_type); + PrintIndent(LEVEL1, "exclude_callchain_kernel %u, exclude_callchain_user %u\n", + attr.exclude_callchain_kernel, attr.exclude_callchain_user); + PrintIndent(LEVEL1, "sample_regs_user 0x%llx\n", attr.sample_regs_user); + PrintIndent(LEVEL1, "sample_stack_user 0x%x\n", attr.sample_stack_user); +} + +void SubCommandDump::DumpAttrPortion(int indent) +{ + attrIds_ = reader_->GetAttrSection(); + for (size_t i = 0; i < attrIds_.size(); ++i) { + const AttrWithId &attr = attrIds_[i]; + PrintIndent(indent, "attr %zu:\n", i + 1); + DumpPrintEventAttr(attr.attr, indent_ + 1); + if (!attr.ids.empty()) { + PrintIndent(indent, " ids:"); + for (const auto &id : attr.ids) { + PrintIndent(indent, " %" PRId64, id); + } + PrintIndent(indent, "\n"); + } + } +} + +void SubCommandDump::ExprotUserStack(const PerfRecordSample &recordSample) +{ + if (recordSample.data_.reg_nr > 0 and recordSample.data_.dyn_size > 0) { + // __user_regs_