Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class _ProgramExplorerRow extends StatelessWidget {

return DevToolsTooltip(
message: toolTip ?? node.name,
textStyle: theme.toolTipFixedFontStyle,
textStyle: theme.tooltipFixedFontStyle,
child: InkWell(
onTap: onTap,
child: Row(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,84 +5,40 @@
import 'package:flutter/material.dart';

import '../../shared/globals.dart';
import '../../shared/primitives/utils.dart';
import '../../shared/routing.dart';
import '../../shared/table/table.dart';
import '../../shared/table/table_data.dart';
import '../../shared/utils.dart';
import '../debugger/codeview_controller.dart';
import '../debugger/debugger_screen.dart';
import '../vm_developer/vm_developer_common_widgets.dart';
import 'cpu_profile_model.dart';

const timeColumnWidthPx = 180.0;

// TODO(kenz): clean up to use TimeAndPercentageColumn.
class SelfTimeColumn extends ColumnData<CpuStackFrame> {
SelfTimeColumn({String? titleTooltip})
: super(
'Self Time',
class SelfTimeColumn extends TimeAndPercentageColumn<CpuStackFrame> {
SelfTimeColumn({
String? titleTooltip,
RichTooltipBuilder<CpuStackFrame>? dataTooltipProvider,
}) : super(
title: 'Self Time',
titleTooltip: titleTooltip,
fixedWidthPx: scaleByFontFactor(timeColumnWidthPx),
timeProvider: (stackFrame) => stackFrame.selfTime,
percentAsDoubleProvider: (stackFrame) => stackFrame.selfTimeRatio,
richTooltipProvider: dataTooltipProvider,
secondaryCompare: (stackFrame) => stackFrame.name,
);

@override
bool get numeric => true;

@override
int compare(CpuStackFrame a, CpuStackFrame b) {
final int result = super.compare(a, b);
if (result == 0) {
return a.name.compareTo(b.name);
}
return result;
}

@override
int getValue(CpuStackFrame dataObject) => dataObject.selfTime.inMicroseconds;

@override
String getDisplayValue(CpuStackFrame dataObject) {
return '${msText(dataObject.selfTime, fractionDigits: 2)} '
'(${percent2(dataObject.selfTimeRatio)})';
}

@override
String getTooltip(CpuStackFrame dataObject) => '';
}

// TODO(kenz): clean up to use TimeAndPercentageColumn.
class TotalTimeColumn extends ColumnData<CpuStackFrame> {
TotalTimeColumn({String? titleTooltip})
: super(
'Total Time',
class TotalTimeColumn extends TimeAndPercentageColumn<CpuStackFrame> {
TotalTimeColumn({
String? titleTooltip,
RichTooltipBuilder<CpuStackFrame>? dataTooltipProvider,
}) : super(
title: 'Total Time',
titleTooltip: titleTooltip,
fixedWidthPx: scaleByFontFactor(timeColumnWidthPx),
timeProvider: (stackFrame) => stackFrame.totalTime,
percentAsDoubleProvider: (stackFrame) => stackFrame.totalTimeRatio,
richTooltipProvider: dataTooltipProvider,
secondaryCompare: (stackFrame) => stackFrame.name,
);

@override
bool get numeric => true;

@override
int compare(CpuStackFrame a, CpuStackFrame b) {
final int result = super.compare(a, b);
if (result == 0) {
return a.name.compareTo(b.name);
}
return result;
}

@override
int getValue(CpuStackFrame dataObject) => dataObject.totalTime.inMicroseconds;

@override
String getDisplayValue(CpuStackFrame dataObject) {
return '${msText(dataObject.totalTime, fractionDigits: 2)} '
'(${percent2(dataObject.totalTimeRatio)})';
}

@override
String getTooltip(CpuStackFrame dataObject) => '';
}

class MethodAndSourceColumn extends TreeColumnData<CpuStackFrame>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'package:flutter/material.dart';
import '../../../shared/primitives/utils.dart';
import '../../../shared/table/table.dart';
import '../../../shared/table/table_data.dart';
import '../../../shared/theme.dart';
import '../cpu_profile_columns.dart';
import '../cpu_profile_model.dart';

Expand All @@ -18,17 +19,27 @@ class CpuBottomUpTable extends StatelessWidget {
required bool displayTreeGuidelines,
}) {
final treeColumn = MethodAndSourceColumn();
final startingSortColumn = SelfTimeColumn(titleTooltip: selfTimeTooltip);
final selfTimeColumn = SelfTimeColumn(
titleTooltip: selfTimeTooltip,
dataTooltipProvider: (stackFrame, context) =>
_bottomUpTimeTooltipBuilder('Self', stackFrame, context),
);
final totalTimeColumn = TotalTimeColumn(
titleTooltip: totalTimeTooltip,
dataTooltipProvider: (stackFrame, context) =>
_bottomUpTimeTooltipBuilder('Total', stackFrame, context),
);
final columns = List<ColumnData<CpuStackFrame>>.unmodifiable([
TotalTimeColumn(titleTooltip: totalTimeTooltip),
startingSortColumn,
totalTimeColumn,
selfTimeColumn,
treeColumn,
]);

return CpuBottomUpTable._(
key,
bottomUpRoots,
treeColumn,
startingSortColumn,
selfTimeColumn,
columns,
displayTreeGuidelines,
);
Expand All @@ -49,16 +60,47 @@ class CpuBottomUpTable extends StatelessWidget {
final List<CpuStackFrame> bottomUpRoots;
final bool displayTreeGuidelines;

static const totalTimeTooltip =
'Time that a method spent executing its own code as well as the code for '
'the\nmethod that it called (which is displayed as an ancestor in the '
'bottom up tree).';
static const totalTimeTooltip = '''
For top-level methods in the bottom-up tree (stack frames that were at the top of at
least one CPU sample), this is the time the method spent executing its own code,
as well as the code for any methods that it called.

For children methods in the bottom-up tree (the callers), this is the total time of
the top-level method (the callee) when called through the child method (the caller).''';

static const selfTimeTooltip =
'For top-level methods in the bottom-up tree (leaf stack frames in the '
'CPU profile),\nthis is the time the method spent executing only its own '
'code. For sub nodes (the\ncallers in the CPU profile), this is the self '
'time of the callee when being called by\nthe caller. ';
static const selfTimeTooltip = '''
For top-level methods in the bottom-up tree (stack frames that were at the top of at
least one CPU sample), this is the time the method spent executing only its own code.

For children methods in the bottom-up tree (the callers), this is the self time of
the top-level method (the callee) when called through the child method (the caller).''';

static InlineSpan? _bottomUpTimeTooltipBuilder(
String type,
CpuStackFrame stackFrame,
BuildContext context,
) {
// TODO(kenz): consider adding a tooltip for root nodes as well if this is
// a point of confusion for the user.
if (stackFrame.isRoot) {
return null;
}
final fixedStyle = Theme.of(context).tooltipFixedFontStyle;
return TextSpan(
children: [
TextSpan(text: '$type time for '),
TextSpan(
text: stackFrame.root.name,
style: fixedStyle,
),
const TextSpan(text: '\nwhen called through '),
TextSpan(
text: stackFrame.name,
style: fixedStyle,
),
],
);
}

@override
Widget build(BuildContext context) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,19 @@ class CpuCallTreeTable extends StatelessWidget {
required bool displayTreeGuidelines,
}) {
final treeColumn = MethodAndSourceColumn();
final startingSortColumn = TotalTimeColumn(titleTooltip: totalTimeTooltip);
final selfTimeColumn = SelfTimeColumn(titleTooltip: selfTimeTooltip);
final totalTimeColumn = TotalTimeColumn(titleTooltip: totalTimeTooltip);
final columns = List<ColumnData<CpuStackFrame>>.unmodifiable([
startingSortColumn,
SelfTimeColumn(titleTooltip: selfTimeTooltip),
totalTimeColumn,
selfTimeColumn,
treeColumn,
]);

return CpuCallTreeTable._(
key,
dataRoots,
treeColumn,
startingSortColumn,
totalTimeColumn,
columns,
displayTreeGuidelines,
);
Expand Down
6 changes: 4 additions & 2 deletions packages/devtools_app/lib/src/shared/table/table.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1506,9 +1506,11 @@ class _TableRowState<T> extends State<TableRow<T>>
);

final tooltip = column.getTooltip(node);
if (tooltip.isNotEmpty) {
final richTooltip = column.getRichTooltip(node, context);
if (tooltip.isNotEmpty || richTooltip != null) {
content = DevToolsTooltip(
message: tooltip,
message: richTooltip == null ? tooltip : null,
richMessage: richTooltip,
waitDuration: tooltipWaitLong,
child: content,
);
Expand Down
21 changes: 19 additions & 2 deletions packages/devtools_app/lib/src/shared/table/table_data.dart
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,15 @@ abstract class ColumnData<T> {

String? getCaption(T dataObject) => null;

// TODO(kenz): this isn't hooked up to the table elements. Do this.
/// Get the cell's tooltip value from the given [dataObject].
String getTooltip(T dataObject) => getDisplayValue(dataObject);

/// Get the cell's rich tooltip span from the given [dataObject].
///
/// If both [getTooltip] and [getRichTooltip] are provided, the rich tooltip
/// will take precedence.
InlineSpan? getRichTooltip(T dataObject, BuildContext context) => null;

/// Get the cell's text color from the given [dataObject].
Color? getTextColor(T dataObject) => null;

Expand Down Expand Up @@ -161,6 +166,8 @@ extension ColumnDataExtension<T> on ColumnData<T> {
}
}

typedef RichTooltipBuilder<T> = InlineSpan? Function(T, BuildContext);

/// Column that, for each row, shows a time value in milliseconds and the
/// percentage that the time value is of the total time for this data set.
///
Expand All @@ -174,6 +181,8 @@ abstract class TimeAndPercentageColumn<T> extends ColumnData<T> {
required String title,
required this.percentAsDoubleProvider,
this.timeProvider,
this.tooltipProvider,
this.richTooltipProvider,
this.secondaryCompare,
this.percentageOnly = false,
double columnWidth = _defaultTimeColumnWidth,
Expand All @@ -190,6 +199,10 @@ abstract class TimeAndPercentageColumn<T> extends ColumnData<T> {

double Function(T) percentAsDoubleProvider;

String Function(T)? tooltipProvider;

RichTooltipBuilder<T>? richTooltipProvider;

Comparable Function(T)? secondaryCompare;

final bool percentageOnly;
Expand Down Expand Up @@ -221,5 +234,9 @@ abstract class TimeAndPercentageColumn<T> extends ColumnData<T> {
}

@override
String getTooltip(T dataObject) => '';
String getTooltip(T dataObject) => tooltipProvider?.call(dataObject) ?? '';

@override
InlineSpan? getRichTooltip(T dataObject, BuildContext context) =>
richTooltipProvider?.call(dataObject, context);
}
2 changes: 1 addition & 1 deletion packages/devtools_app/lib/src/shared/theme.dart
Original file line number Diff line number Diff line change
Expand Up @@ -422,7 +422,7 @@ extension ThemeDataExtension on ThemeData {
TextStyle get selectedFixedFontStyle =>
fixedFontStyle.copyWith(color: colorScheme.devtoolsSelectedLink);

TextStyle get toolTipFixedFontStyle => fixedFontStyle.copyWith(
TextStyle get tooltipFixedFontStyle => fixedFontStyle.copyWith(
color: colorScheme.tooltipTextColor,
);

Expand Down