1/* 2 * Copyright (C) 2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import {BaseElement, element} from "../../base-ui/BaseElement.js"; 17import "../../base-ui/popover/LitPopover.js" 18import {LitMainMenuGroup} from "../../base-ui/menu/LitMainMenuGroup.js"; 19import {LitMainMenuItem} from "../../base-ui/menu/LitMainMenuItem.js"; 20import {SpRecordSetting} from "./setting/SpRecordSetting.js"; 21import {MenuItem} from "../../base-ui/menu/LitMainMenu.js"; 22import {SpProbesConfig} from "./setting/SpProbesConfig.js"; 23import {SpTraceCommand} from "./setting/SpTraceCommand.js"; 24import { 25 CreateSessionRequest, FpsConfig, 26 HilogConfig, 27 levelFromJSON, 28 MemoryConfig, NativeHookConfig, 29 ProfilerPluginConfig, 30 ProfilerSessionConfig, 31 ProfilerSessionConfigBufferConfig, 32 ProfilerSessionConfigBufferConfigPolicy, 33 ProfilerSessionConfigMode, 34 sysMeminfoTypeFromJSON, 35 sysVMeminfoTypeFromJSON, 36 TracePluginConfig, 37 Type 38} from "./setting/bean/ProfilerServiceTypes.js"; 39import {PluginConvertUtils} from "./setting/utils/PluginConvertUtils.js"; 40import {SpAllocations} from "./setting/SpAllocations.js"; 41 42 43@element('sp-record-trace') 44export class SpRecordTrace extends BaseElement { 45 private _menuItems: Array<MenuItem> | undefined 46 47 schedulingEvents = [ 48 "sched/sched_switch", 49 "power/suspend_resume", 50 "sched/sched_wakeup", 51 "sched/sched_wakeup_new", 52 "sched/sched_waking", 53 "sched/sched_process_exit", 54 "sched/sched_process_free", 55 "task/task_newtask", 56 "task/task_rename" 57 ] 58 59 powerEvents = [ 60 "regulator/regulator_set_voltage", 61 "regulator/regulator_set_voltage_complete", 62 "power/clock_enable", 63 "power/clock_disable", 64 "power/clock_set_rate", 65 "power/suspend_resume" 66 ] 67 68 cpuFreqEvents = [ 69 "power/cpu_frequency", 70 "power/cpu_idle", 71 "power/suspend_resume" 72 ] 73 74 sysCallsEvents = [ 75 "raw_syscalls/sys_enter", 76 "raw_syscalls/sys_exit" 77 ] 78 79 highFrequencyEvents = [ 80 "mm_event/mm_event_record", 81 "kmem/rss_stat", 82 "ion/ion_stat", 83 "dmabuf_heap/dma_heap_stat", 84 "kmem/ion_heap_grow", 85 "kmem/ion_heap_shrink" 86 ] 87 88 advancedConfigEvents = ["sched/sched_switch", 89 "sched/sched_wakeup", 90 "sched/sched_wakeup_new", 91 "sched/sched_waking", 92 "sched/sched_process_exit", 93 "sched/sched_process_free", 94 "irq/irq_handler_entry", 95 "irq/irq_handler_exit", 96 "irq/softirq_entry", 97 "irq/softirq_exit", 98 "irq/softirq_raise", 99 "power/clock_disable", 100 "power/clock_enable", 101 "power/clock_set_rate", 102 "power/cpu_frequency", 103 "power/cpu_idle", 104 "clk/clk_disable", 105 "clk/clk_disable_complete", 106 "clk/clk_enable", 107 "clk/clk_enable_complete", 108 "clk/clk_set_rate", 109 "clk/clk_set_rate_complete", 110 "binder/binder_transaction", 111 "binder/binder_transaction_alloc_buf", 112 "binder/binder_transaction_received", 113 "binder/binder_lock", 114 "binder/binder_locked", 115 "binder/binder_unlock", 116 "workqueue/workqueue_execute_start", 117 "workqueue/workqueue_execute_end", 118 "oom/oom_score_adj_update", 119 "ftrace/print" 120 ] 121 122 static MEM_INFO = ["MEMINFO_ACTIVE", "MEMINFO_ACTIVE_ANON", "MEMINFO_ACTIVE_FILE", "MEMINFO_ANON_PAGES", "MEMINFO_BUFFERS", 123 "MEMINFO_CACHED", "MEMINFO_CMA_FREE", "MEMINFO_CMA_TOTAL", "MEMINFO_COMMIT_LIMIT", "MEMINFO_COMMITED_AS", 124 "MEMINFO_DIRTY", "MEMINFO_INACTIVE", "MEMINFO_INACTIVE_ANON", "MEMINFO_INACTIVE_FILE", 125 "MEMINFO_KERNEL_STACK", "MEMINFO_MAPPED", "MEMINFO_MEM_AVAILABLE", "MEMINFO_MEM_FREE", "MEMINFO_MEM_TOTAL", 126 "MEMINFO_MLOCKED", "MEMINFO_PAGE_TABLES", "MEMINFO_SHMEM", "MEMINFO_SLAB", "MEMINFO_SLAB_RECLAIMABLE", 127 "MEMINFO_SLAB_UNRECLAIMABLE", "MEMINFO_SWAP_CACHED", "MEMINFO_SWAP_FREE", "MEMINFO_SWAP_TOTAL", 128 "MEMINFO_UNEVICTABLE", "MEMINFO_VMALLOC_CHUNK", "MEMINFO_VMALLOC_TOTAL", "MEMINFO_VMALLOC_USED", 129 "MEMINFO_WRITEBACK"] 130 static VMEM_INFO = ["VMEMINFO_UNSPECIFIED", "VMEMINFO_NR_FREE_PAGES", "VMEMINFO_NR_ALLOC_BATCH", 131 "VMEMINFO_NR_INACTIVE_ANON", "VMEMINFO_NR_ACTIVE_ANON", "VMEMINFO_NR_INACTIVE_FILE", 132 "VMEMINFO_NR_ACTIVE_FILE", "VMEMINFO_NR_UNEVICTABLE", "VMEMINFO_NR_MLOCK", "VMEMINFO_NR_ANON_PAGES", 133 "VMEMINFO_NR_MAPPED", "VMEMINFO_NR_FILE_PAGES", "VMEMINFO_NR_DIRTY", "VMEMINFO_NR_WRITEBACK", 134 "VMEMINFO_NR_SLAB_RECLAIMABLE", "VMEMINFO_NR_SLAB_UNRECLAIMABLE", "VMEMINFO_NR_PAGE_TABLE_PAGES", 135 "VMEMINFO_NR_KERNEL_STACK", "VMEMINFO_NR_OVERHEAD", "VMEMINFO_NR_UNSTABLE", "VMEMINFO_NR_BOUNCE", 136 "VMEMINFO_NR_VMSCAN_WRITE", "VMEMINFO_NR_VMSCAN_IMMEDIATE_RECLAIM", "VMEMINFO_NR_WRITEBACK_TEMP", 137 "VMEMINFO_NR_ISOLATED_ANON", "VMEMINFO_NR_ISOLATED_FILE", "VMEMINFO_NR_SHMEM", "VMEMINFO_NR_DIRTIED", 138 "VMEMINFO_NR_WRITTEN", "VMEMINFO_NR_PAGES_SCANNED", "VMEMINFO_WORKINGSET_REFAULT", 139 "VMEMINFO_WORKINGSET_ACTIVATE", "VMEMINFO_WORKINGSET_NODERECLAIM", "VMEMINFO_NR_ANON_TRANSPARENT_HUGEPAGES", 140 "VMEMINFO_NR_FREE_CMA", "VMEMINFO_NR_SWAPCACHE", "VMEMINFO_NR_DIRTY_THRESHOLD", 141 "VMEMINFO_NR_DIRTY_BACKGROUND_THRESHOLD", "VMEMINFO_PGPGIN", "VMEMINFO_PGPGOUT", "VMEMINFO_PGPGOUTCLEAN", 142 "VMEMINFO_PSWPIN", "VMEMINFO_PSWPOUT", "VMEMINFO_PGALLOC_DMA"] 143 144 static VMEM_INFO_SECOND = ["VMEMINFO_PGALLOC_NORMAL", "VMEMINFO_PGALLOC_MOVABLE", "VMEMINFO_PGFREE", "VMEMINFO_PGACTIVATE", 145 "VMEMINFO_PGDEACTIVATE", "VMEMINFO_PGFAULT", "VMEMINFO_PGMAJFAULT", "VMEMINFO_PGREFILL_DMA", 146 "VMEMINFO_PGREFILL_NORMAL", "VMEMINFO_PGREFILL_MOVABLE", "VMEMINFO_PGSTEAL_KSWAPD_DMA", 147 "VMEMINFO_PGSTEAL_KSWAPD_NORMAL", "VMEMINFO_PGSTEAL_KSWAPD_MOVABLE", "VMEMINFO_PGSTEAL_DIRECT_DMA", 148 "VMEMINFO_PGSTEAL_DIRECT_NORMAL", "VMEMINFO_PGSTEAL_DIRECT_MOVABLE", "VMEMINFO_PGSCAN_KSWAPD_DMA", 149 "VMEMINFO_PGSCAN_KSWAPD_NORMAL", "VMEMINFO_PGSCAN_KSWAPD_MOVABLE", "VMEMINFO_PGSCAN_DIRECT_DMA", 150 "VMEMINFO_PGSCAN_DIRECT_NORMAL", "VMEMINFO_PGSCAN_DIRECT_MOVABLE", "VMEMINFO_PGSCAN_DIRECT_THROTTLE", 151 "VMEMINFO_PGINODESTEAL", "VMEMINFO_SLABS_SCANNED", "VMEMINFO_KSWAPD_INODESTEAL", 152 "VMEMINFO_KSWAPD_LOW_WMARK_HIT_QUICKLY", "VMEMINFO_KSWAPD_HIGH_WMARK_HIT_QUICKLY", "VMEMINFO_PAGEOUTRUN", 153 "VMEMINFO_ALLOCSTALL", "VMEMINFO_PGROTATED", "VMEMINFO_DROP_PAGECACHE", "VMEMINFO_DROP_SLAB", 154 "VMEMINFO_PGMIGRATE_SUCCESS", "VMEMINFO_PGMIGRATE_FAIL", "VMEMINFO_COMPACT_MIGRATE_SCANNED", 155 "VMEMINFO_COMPACT_FREE_SCANNED", "VMEMINFO_COMPACT_ISOLATED", "VMEMINFO_COMPACT_STALL", 156 "VMEMINFO_COMPACT_FAIL", "VMEMINFO_COMPACT_SUCCESS", "VMEMINFO_COMPACT_DAEMON_WAKE", 157 "VMEMINFO_UNEVICTABLE_PGS_CULLED", "VMEMINFO_UNEVICTABLE_PGS_SCANNED", "VMEMINFO_UNEVICTABLE_PGS_RESCUED", 158 "VMEMINFO_UNEVICTABLE_PGS_MLOCKED", "VMEMINFO_UNEVICTABLE_PGS_MUNLOCKED"] 159 160 static VMEM_INFO_THIRD = [ 161 "VMEMINFO_UNEVICTABLE_PGS_CLEARED", "VMEMINFO_UNEVICTABLE_PGS_STRANDED", "VMEMINFO_NR_ZSPAGES", 162 "VMEMINFO_NR_ION_HEAP", "VMEMINFO_NR_GPU_HEAP", "VMEMINFO_ALLOCSTALL_DMA", "VMEMINFO_ALLOCSTALL_MOVABLE", 163 "VMEMINFO_ALLOCSTALL_NORMAL", "VMEMINFO_COMPACT_DAEMON_FREE_SCANNED", 164 "VMEMINFO_COMPACT_DAEMON_MIGRATE_SCANNED", "VMEMINFO_NR_FASTRPC", "VMEMINFO_NR_INDIRECTLY_RECLAIMABLE", 165 "VMEMINFO_NR_ION_HEAP_POOL", "VMEMINFO_NR_KERNEL_MISC_RECLAIMABLE", "VMEMINFO_NR_SHADOW_CALL_STACK_BYTES", 166 "VMEMINFO_NR_SHMEM_HUGEPAGES", "VMEMINFO_NR_SHMEM_PMDMAPPED", "VMEMINFO_NR_UNRECLAIMABLE_PAGES", 167 "VMEMINFO_NR_ZONE_ACTIVE_ANON", "VMEMINFO_NR_ZONE_ACTIVE_FILE", "VMEMINFO_NR_ZONE_INACTIVE_ANON", 168 "VMEMINFO_NR_ZONE_INACTIVE_FILE", "VMEMINFO_NR_ZONE_UNEVICTABLE", "VMEMINFO_NR_ZONE_WRITE_PENDING", 169 "VMEMINFO_OOM_KILL", "VMEMINFO_PGLAZYFREE", "VMEMINFO_PGLAZYFREED", "VMEMINFO_PGREFILL", 170 "VMEMINFO_PGSCAN_DIRECT", "VMEMINFO_PGSCAN_KSWAPD", "VMEMINFO_PGSKIP_DMA", "VMEMINFO_PGSKIP_MOVABLE", 171 "VMEMINFO_PGSKIP_NORMAL", "VMEMINFO_PGSTEAL_DIRECT", "VMEMINFO_PGSTEAL_KSWAPD", "VMEMINFO_SWAP_RA", 172 "VMEMINFO_SWAP_RA_HIT", "VMEMINFO_WORKINGSET_RESTORE" 173 ] 174 175 initElements(): void { 176 let that = this 177 let parentElement = this.parentNode as HTMLElement; 178 parentElement.style.overflow = 'hidden' 179 let recordSetting = new SpRecordSetting(); 180 let probesConfig = new SpProbesConfig(); 181 let traceCommand = new SpTraceCommand(); 182 let spAllocations = new SpAllocations(); 183 let menuGroup = this.shadowRoot?.querySelector('#menu-group') as LitMainMenuGroup 184 let appContent = this.shadowRoot?.querySelector('#app-content') as HTMLElement 185 appContent.append(recordSetting) 186 this._menuItems = [ 187 { 188 title: "Record setting", 189 icon: "properties", 190 fileChoose: false, 191 clickHandler: function (ev: InputEvent) { 192 appContent!.innerHTML = "" 193 appContent.append(recordSetting) 194 } 195 }, 196 { 197 title: "Trace command", 198 icon: "dbsetbreakpoint", 199 fileChoose: false, 200 clickHandler: function (ev: InputEvent) { 201 let maxDur = recordSetting.maxDur; 202 let bufferConfig: ProfilerSessionConfigBufferConfig = { 203 pages: 1000, 204 policy: ProfilerSessionConfigBufferConfigPolicy.RECYCLE 205 } 206 let sessionConfig: ProfilerSessionConfig = { 207 buffers: [bufferConfig], 208 sessionMode: ProfilerSessionConfigMode.OFFLINE, 209 resultFile: "/data/local/tmp/hiprofiler_data.htrace", 210 resultMaxSize: 0, 211 sampleDuration: maxDur * 1000, 212 keepAliveTime: 0 213 } 214 let request: CreateSessionRequest = { 215 requestId: 1, 216 sessionConfig: sessionConfig, 217 pluginConfigs: [] 218 } 219 if (probesConfig.traceConfig.length > 0) { 220 request.pluginConfigs.push(that.createHtracePluginConfig(that, probesConfig, recordSetting)) 221 if (probesConfig.traceConfig.indexOf("FPS") != -1) { 222 request.pluginConfigs.push(that.createFpsPluginConfig()) 223 } 224 } 225 let reportingFrequency: number; 226 if (maxDur > 20) { 227 reportingFrequency = 5 228 } else { 229 reportingFrequency = 2 230 } 231 if (probesConfig.memoryConfig.length > 0) { 232 request.pluginConfigs.push(that.createMemoryPluginConfig(probesConfig, that, reportingFrequency)) 233 } 234 if (spAllocations.pid != -1) { 235 request.pluginConfigs.push(that.createNativePluginConfig(spAllocations, reportingFrequency)) 236 } 237 appContent!.innerHTML = "" 238 appContent.append(traceCommand) 239 traceCommand.hdcCommon = 240 PluginConvertUtils.createHdcCmd( 241 PluginConvertUtils.BeanToCmdTxt(request, false), maxDur) 242 } 243 }, 244 { 245 title: "Probes config", icon: "realIntentionBulb", fileChoose: false, 246 clickHandler: function (ev: InputEvent) { 247 appContent!.innerHTML = "" 248 appContent.append(probesConfig) 249 } 250 }, 251 { 252 title: "Allocations", 253 icon: "externaltools", 254 fileChoose: false, 255 clickHandler: function (ev: InputEvent) { 256 appContent!.innerHTML = "" 257 appContent.append(spAllocations) 258 } 259 } 260 ] 261 this._menuItems?.forEach(item => { 262 let th = new LitMainMenuItem(); 263 th.setAttribute('icon', item.icon || ""); 264 th.setAttribute('title', item.title || ""); 265 th.style.height = "60px" 266 th.style.fontFamily = "Helvetica-Bold" 267 th.style.fontSize = "16px" 268 th.style.lineHeight = "28px" 269 th.style.fontWeight = "700" 270 th.style.opacity = "0.9" 271 th.removeAttribute('file'); 272 th.addEventListener('click', e => { 273 if (item.clickHandler) { 274 item.clickHandler(item) 275 } 276 }) 277 menuGroup.appendChild(th); 278 }) 279 } 280 281 private createHilogConfig(probesConfig: SpProbesConfig, reportingFrequency: number) { 282 let hilogConfig: HilogConfig = { 283 deviceType: Type.HI3516, 284 logLevel: levelFromJSON(probesConfig.hilogConfig[0]), 285 needClear: true 286 } 287 let hilogConfigProfilerPluginConfig: ProfilerPluginConfig<HilogConfig> = { 288 pluginName: "hilog-plugin", 289 sampleInterval: reportingFrequency * 1000, 290 configData: hilogConfig, 291 } 292 return hilogConfigProfilerPluginConfig; 293 } 294 295 private createNativePluginConfig(spAllocations: SpAllocations, reportingFrequency: number) { 296 let nativeConfig: NativeHookConfig = { 297 pid: spAllocations.pid, 298 saveFile: false, 299 fileName: "", 300 filterSize: spAllocations.filter, 301 smbPages: spAllocations.shared, 302 maxStackDepth: spAllocations.unwind, 303 processName: "" 304 } 305 let nativePluginConfig: ProfilerPluginConfig<NativeHookConfig> = { 306 pluginName: "nativehook", 307 sampleInterval: reportingFrequency * 1000, 308 configData: nativeConfig, 309 } 310 return nativePluginConfig; 311 } 312 313 private createMemoryPluginConfig(probesConfig: SpProbesConfig, that: this, reportingFrequency: number) { 314 let memoryconfig: MemoryConfig = { 315 reportProcessTree: true, 316 reportSysmemMemInfo: true, 317 sysMeminfoCounters: [], 318 reportSysmemVmemInfo: true, 319 sysVmeminfoCounters: [], 320 reportProcessMemInfo: true, 321 reportAppMemInfo: false, 322 reportAppMemByMemoryService: false, 323 pid: [] 324 } 325 probesConfig.memoryConfig.forEach(value => { 326 if (value.indexOf("Kernel meminfo") != -1) { 327 SpRecordTrace.MEM_INFO.forEach(va => { 328 memoryconfig.sysMeminfoCounters.push(sysMeminfoTypeFromJSON(va)); 329 }) 330 } 331 if (value.indexOf("Virtual memory stats") != -1) { 332 SpRecordTrace.VMEM_INFO.forEach((me => { 333 memoryconfig.sysVmeminfoCounters.push(sysVMeminfoTypeFromJSON(me)) 334 })) 335 SpRecordTrace.VMEM_INFO_SECOND.forEach((me => { 336 memoryconfig.sysVmeminfoCounters.push(sysVMeminfoTypeFromJSON(me)) 337 })) 338 SpRecordTrace.VMEM_INFO_THIRD.forEach((me => { 339 memoryconfig.sysVmeminfoCounters.push(sysVMeminfoTypeFromJSON(me)) 340 })) 341 } 342 }) 343 let profilerPluginConfig: ProfilerPluginConfig<MemoryConfig> = { 344 pluginName: "memory-plugin", 345 sampleInterval: reportingFrequency * 1000, 346 configData: memoryconfig, 347 } 348 return profilerPluginConfig; 349 } 350 351 private createFpsPluginConfig() { 352 let fpsConfig: FpsConfig = { 353 reportFps: true 354 } 355 let fpsPlugin: ProfilerPluginConfig<FpsConfig> = { 356 pluginName: "hidump-plugin", 357 sampleInterval: 1000, 358 configData: fpsConfig 359 } 360 return fpsPlugin; 361 } 362 363 private createHtracePluginConfig(that: this, probesConfig: SpProbesConfig, recordSetting: SpRecordSetting) { 364 let tracePluginConfig: TracePluginConfig = { 365 ftraceEvents: that.createTraceEvents(probesConfig.traceConfig), 366 hitraceCategories: [], 367 hitraceApps: [], 368 bufferSizeKb: recordSetting.bufferSize * 1024, 369 flushIntervalMs: 1000, 370 flushThresholdKb: 4096, 371 parseKsyms: true, 372 clock: "mono", 373 tracePeriodMs: 200, 374 rawDataPrefix: "", 375 traceDurationMs: 0, 376 debugOn: false, 377 } 378 if (probesConfig.traceEvents.length > 0) { 379 tracePluginConfig.hitraceCategories = probesConfig.traceEvents 380 } 381 let htraceProfilerPluginConfig: ProfilerPluginConfig<TracePluginConfig> = { 382 pluginName: "ftrace-plugin", 383 sampleInterval: 1000, 384 configData: tracePluginConfig 385 } 386 return htraceProfilerPluginConfig; 387 } 388 389 createTraceEvents(traceConfig: Array<string>): Array<string> { 390 let traceEvents = new Set<string>(); 391 traceConfig.forEach(config => { 392 switch (config) { 393 case "Scheduling details": 394 this.schedulingEvents.forEach((eve: string) => { 395 traceEvents.add(eve) 396 }); 397 break; 398 case "CPU Frequency and idle states": 399 this.cpuFreqEvents.forEach((eve: string) => { 400 traceEvents.add(eve) 401 }); 402 break; 403 case "High frequency memory": 404 this.highFrequencyEvents.forEach((eve: string) => { 405 traceEvents.add(eve) 406 }); 407 break; 408 case "Advanced ftrace config": 409 this.advancedConfigEvents.forEach((eve: string) => { 410 traceEvents.add(eve) 411 }); 412 break; 413 case "Syscalls": 414 this.sysCallsEvents.forEach((eve: string) => { 415 traceEvents.add(eve) 416 }); 417 break; 418 case "Board voltages & frequency": 419 this.powerEvents.forEach((eve: string) => { 420 traceEvents.add(eve) 421 }); 422 break; 423 } 424 } 425 ) 426 let ftraceEventsArray: string[] = []; 427 for (const ftraceEvent of traceEvents) { 428 ftraceEventsArray.push(ftraceEvent) 429 } 430 return ftraceEventsArray 431 } 432 433 initHtml(): string { 434 return ` 435<style> 436:host{ 437 display: block; 438 width: 100%; 439 height: 100%; 440 background-color: var(--dark-background5,#F6F6F6); 441} 442.container { 443 display: grid; 444 grid-template-columns: 1fr; 445 grid-template-rows:1fr; 446 background-color: var(--dark-background5,#F6F6F6); 447 min-height: 100%; 448} 449 450.header { 451 display: grid; 452 grid-template-columns: 1fr 1fr; 453 grid-template-rows: 1fr 1fr; 454 grid-gap: 10px; 455 padding-left: 20px; 456 padding-top: 30px; 457 padding-bottom: 20px; 458 background-color: #FFFFFF; 459 width: 100%; 460} 461 462.span-col-2{ 463 grid-column: span 2 / auto; 464 height: 15px; 465} 466 467.header-right { 468 display: flex; 469 margin-left: auto; 470 margin-right: 5%; 471} 472.header-des{ 473 font-family: PingFangSC-Regular; 474 font-size: 1em; 475 color: var(--dark-background3,#999999); 476 text-align: left; 477 font-weight: 400; 478} 479 480.target { 481 font-family: Helvetica; 482 font-size: 1em; 483 color: #212121; 484 line-height: 16px; 485 font-weight: 400; 486} 487 488.select{ 489 width: 196px; 490 height: 32px; 491 margin-left: 14px; 492 margin-right: 24px; 493 border: 1px solid #D5D5D5; 494} 495.add { 496 width: 164px; 497 height: 32px; 498 border: 1px solid cornflowerblue 499} 500.record { 501 background: #3391FF; 502 border-radius: 1px; 503 border-color:rgb(0,0,0,0.1); 504 width: 96px; 505 height: 32px; 506 margin-right: 0px; 507 font-family: Helvetica; 508 font-size: 1em; 509 color: #FFFFFF; 510 text-align: center; 511 line-height: 20px; 512 font-weight: 400; 513} 514 515.body{ 516 width: 90%; 517 margin-left: 3%; 518 margin-top: 2%; 519 margin-bottom: 2%; 520 display: grid; 521 grid-template-columns: min-content 1fr; 522 background-color: var(--dark-background3,#FFFFFF); 523 border-radius: 16px 16px 16px 16px; 524} 525 526.menugroup{ 527 height: 100%; 528 background: var(--dark-background3,#FFFFFF); 529} 530.menuitem{ 531 background: var(--dark-background3,#FFFFFF); 532} 533.content{ 534 background: var(--dark-background3,#FFFFFF); 535 border-style: none none none solid; 536 border-width: 1px; 537 border-color: rgba(166,164,164,0.2); 538 border-radius: 0px 16px 16px 0px; 539} 540</style> 541<div class="container"> 542 <div class="header" style="display: none"> 543 <div> 544 <span class="target">Target Platform:<span> 545 <select class="select"> 546 <option class="select" value="volvo">Volvo</option> 547 <option class="select" value="saab">Saab</option> 548 <option class="select" value="opel">Opel</option> 549 <option class="select" value="audi">Audi</option> 550 </select> 551 <button class="add">Add Device</button> 552 </div> 553 <div class="header-right"> 554 <button class="record">Record</button> 555 </div> 556 <div class="span-col-2" > 557 <span class="header-des">It looks like you didn’t add any probes. Please add at least one to get a non-empty trace.</span> 558 </div> 559 </div> 560 <div class="body"> 561 <lit-main-menu-group class="menugroup" id= "menu-group" title="" nocollapsed radius></lit-main-menu-group> 562 <div id="app-content" class="content"> 563 </div> 564 </div> 565</div> 566`; 567 } 568 569}