• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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}