blob: e95f0f7ffd1e966ae34563ac3a7ac79620247a8a [file] [edit]
// 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 {Trace} from './trace';
// 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})`;
}