| // Copyright (C) 2023 The Android Open Source Project | |
| // | |
| // 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 {TimeSpan} from '../base/time'; | |
| import {exists} from '../base/utils'; | |
| import type {Engine} from '../trace_processor/engine'; | |
| import {NUM} from '../trace_processor/query_result'; | |
| import type {App} from './app'; | |
| import type {Trace} from './trace'; | |
| export function getBugReportUrl(app: App): string { | |
| return app.isInternalUser | |
| ? 'https://goto.google.com/perfetto-ui-bug' | |
| : 'https://github.com/google/perfetto/issues/new'; | |
| } | |
| // Number of machines in the trace. Used to decide whether tracks should be | |
| // disambiguated with a "(machine N)" label: with a single machine there's no | |
| // ambiguity, so no label is shown. | |
| export async function getMachineCount(engine: Engine): Promise<number> { | |
| const res = await engine.query(`select count(*) as cnt from machine`); | |
| return res.firstRow({cnt: NUM}).cnt; | |
| } | |
| export function getTrackName( | |
| args: Partial<{ | |
| name: string | null; | |
| utid: number | null; | |
| processName: string | null; | |
| pid: number | bigint | null; | |
| threadName: string | null; | |
| tid: number | bigint | null; | |
| upid: number | null; | |
| userName: string | null; | |
| uid: number | null; | |
| kind: string; | |
| threadTrack: boolean; | |
| uidTrack: boolean; | |
| machineLabelIndex: number | null; | |
| machineName: string | null; | |
| numMachines: number | null; | |
| }>, | |
| ) { | |
| const { | |
| name, | |
| upid, | |
| utid, | |
| processName, | |
| threadName, | |
| pid, | |
| tid, | |
| userName, | |
| uid, | |
| kind, | |
| threadTrack, | |
| uidTrack, | |
| machineLabelIndex, | |
| machineName, | |
| numMachines, | |
| } = args; | |
| const hasName = name !== undefined && name !== null && name !== '[NULL]'; | |
| const hasUpid = upid !== undefined && upid !== null; | |
| const hasUtid = utid !== undefined && utid !== null; | |
| const hasProcessName = processName !== undefined && processName !== null; | |
| const hasThreadName = threadName !== undefined && threadName !== null; | |
| const hasUserName = userName !== undefined && userName !== null; | |
| const hasTid = tid !== undefined && tid !== null; | |
| const hasPid = pid !== undefined && pid !== null; | |
| const hasUid = uid !== undefined && uid !== null; | |
| const hasKind = kind !== undefined; | |
| const isThreadTrack = threadTrack !== undefined && threadTrack; | |
| const isUidTrack = uidTrack !== undefined && uidTrack; | |
| // If we don't have any useful information (better than | |
| // upid/utid) we show the track kind to help with tracking | |
| // down where this is coming from. | |
| const kindSuffix = hasKind ? ` (${kind})` : ''; | |
| const machineLabel = maybeMachineLabel( | |
| machineLabelIndex ?? undefined, | |
| machineName, | |
| numMachines ?? undefined, | |
| ); | |
| if (isThreadTrack && hasName && hasTid) { | |
| return `${name} (${tid})`; | |
| } else if (isUidTrack && hasName && hasUserName) { | |
| return `${name} (${userName})`; | |
| } else if (isUidTrack && hasName && hasUid) { | |
| return `${name} ${uid}`; | |
| } else if (hasName && !hasUpid && !hasUtid) { | |
| return `${name}${machineLabel}`; | |
| } else if (hasName) { | |
| return `${name}`; | |
| } else if (hasThreadName && hasTid) { | |
| return `${threadName} ${tid}`; | |
| } else if (hasTid) { | |
| return `Thread ${tid}`; | |
| } else if (hasUpid && hasPid && hasProcessName) { | |
| return `${processName} ${pid}${machineLabel}`; | |
| } else if (hasUpid && hasPid) { | |
| return `Process ${pid}${machineLabel}`; | |
| } else if (hasUpid) { | |
| return `upid: ${upid}${kindSuffix}`; | |
| } else if (hasUtid) { | |
| return `utid: ${utid}${kindSuffix}`; | |
| } else if (hasUid) { | |
| return `uid: ${uid}${kindSuffix}`; | |
| } else if (hasKind) { | |
| return `Unnamed ${kind}`; | |
| } | |
| return 'Unknown'; | |
| } | |
| export function getThreadOrProcUri( | |
| upid: number | null, | |
| utid: number | null, | |
| ): string { | |
| if (exists(upid)) { | |
| return `/process_${upid}`; | |
| } else if (exists(utid)) { | |
| return `/thread_${utid}`; | |
| } else { | |
| throw new Error('No upid or utid defined...'); | |
| } | |
| } | |
| export function getThreadUriPrefix(upid: number | null, utid: number): string { | |
| if (exists(upid)) { | |
| return `/process_${upid}/thread_${utid}`; | |
| } else { | |
| return `/thread_${utid}`; | |
| } | |
| } | |
| // Returns the time span of the current selection, or the visible window if | |
| // there is no current selection. | |
| export async function getTimeSpanOfSelectionOrVisibleWindow( | |
| trace: Trace, | |
| ): Promise<TimeSpan> { | |
| const range = await trace.selection.getTimeSpanOfSelection(); | |
| if (exists(range)) { | |
| return new TimeSpan(range.start, range.end); | |
| } else { | |
| return trace.timeline.visibleWindow.toTimeSpan(); | |
| } | |
| } | |
| export function maybeMachineLabel( | |
| labelIndex?: number, | |
| machineName?: string | null, | |
| numMachines?: number, | |
| ): string { | |
| // No label for: a single machine, or the host (index 0/null). With more than | |
| // one machine, every non-host machine is labelled. `label_index` is the | |
| // machine's 1-based index among non-host machines (see the `machine` table | |
| // view). | |
| if (numMachines === undefined || numMachines <= 1 || (labelIndex ?? 0) <= 0) { | |
| return ''; | |
| } | |
| // Prefer the human-readable machine name (machine.name) when the trace | |
| // provides one; otherwise use the 1-based machine index. | |
| if (machineName !== undefined && machineName !== null && machineName !== '') { | |
| return ` (${machineName})`; | |
| } | |
| return ` (machine ${labelIndex})`; | |
| } |