Snap for 6357634 from 5bae2e6212a1b912472acf1ceca310c1422e98d1 to sdk-release
Change-Id: I362f060f743929fce0d9fb8de1a476273f20d66f
diff --git a/src/profiling/memory/malloc_hooks.cc b/src/profiling/memory/malloc_hooks.cc
index 1c9799d..62910bb 100644
--- a/src/profiling/memory/malloc_hooks.cc
+++ b/src/profiling/memory/malloc_hooks.cc
@@ -220,36 +220,21 @@
return prop_value;
}
-bool ShouldForkPrivateDaemon() {
- std::string build_type = ReadSystemProperty("ro.build.type");
- if (build_type.empty()) {
- PERFETTO_ELOG(
- "Cannot determine platform build type, proceeding in fork mode "
- "profiling.");
- return true;
- }
-
- // On development builds, we support both modes of profiling, depending on a
- // system property.
- if (build_type == "userdebug" || build_type == "eng") {
- // Note: if renaming the property, also update system_property.cc
- std::string mode = ReadSystemProperty("heapprofd.userdebug.mode");
- return mode == "fork";
- }
-
- // User/other builds - always fork private profiler.
- return true;
+bool ForceForkPrivateDaemon() {
+ // Note: if renaming the property, also update system_property.cc
+ std::string mode = ReadSystemProperty("heapprofd.userdebug.mode");
+ return mode == "fork";
}
std::shared_ptr<perfetto::profiling::Client> CreateClientForCentralDaemon(
UnhookedAllocator<perfetto::profiling::Client> unhooked_allocator) {
- PERFETTO_DLOG("Constructing client for central daemon.");
+ PERFETTO_LOG("Constructing client for central daemon.");
using perfetto::profiling::Client;
perfetto::base::Optional<perfetto::base::UnixSocketRaw> sock =
Client::ConnectToHeapprofd(perfetto::profiling::kHeapprofdSocketFile);
if (!sock) {
- PERFETTO_ELOG("Failed to connect to %s.",
+ PERFETTO_ELOG("Failed to connect to %s. This is benign on user builds.",
perfetto::profiling::kHeapprofdSocketFile);
return nullptr;
}
@@ -259,7 +244,7 @@
std::shared_ptr<perfetto::profiling::Client> CreateClientAndPrivateDaemon(
UnhookedAllocator<perfetto::profiling::Client> unhooked_allocator) {
- PERFETTO_DLOG("Setting up fork mode profiling.");
+ PERFETTO_LOG("Setting up fork mode profiling.");
perfetto::base::UnixSocketRaw parent_sock;
perfetto::base::UnixSocketRaw child_sock;
std::tie(parent_sock, child_sock) = perfetto::base::UnixSocketRaw::CreatePair(
@@ -405,10 +390,11 @@
// These factory functions use heap objects, so we need to run them without
// the spinlock held.
- std::shared_ptr<Client> client =
- ShouldForkPrivateDaemon()
- ? CreateClientAndPrivateDaemon(unhooked_allocator)
- : CreateClientForCentralDaemon(unhooked_allocator);
+ std::shared_ptr<Client> client;
+ if (!ForceForkPrivateDaemon())
+ client = CreateClientForCentralDaemon(unhooked_allocator);
+ if (!client)
+ client = CreateClientAndPrivateDaemon(unhooked_allocator);
if (!client) {
PERFETTO_LOG("%s: heapprofd_client not initialized, not installing hooks.",
diff --git a/src/traced/probes/ftrace/ftrace_config_muxer.cc b/src/traced/probes/ftrace/ftrace_config_muxer.cc
index fa53c36..144b804 100644
--- a/src/traced/probes/ftrace/ftrace_config_muxer.cc
+++ b/src/traced/probes/ftrace/ftrace_config_muxer.cc
@@ -390,6 +390,7 @@
events.insert(GroupAndName("kmem", "rss_stat"));
events.insert(GroupAndName("kmem", "ion_heap_grow"));
events.insert(GroupAndName("kmem", "ion_heap_shrink"));
+ events.insert(GroupAndName("mm_event", "mm_event_record"));
continue;
}
}
diff --git a/ui/src/assets/common.scss b/ui/src/assets/common.scss
index de9142a..6114874 100644
--- a/ui/src/assets/common.scss
+++ b/ui/src/assets/common.scss
@@ -262,6 +262,9 @@
&:hover {
background-color: hsl(214, 22%, 90%);
}
+ &[clickable] {
+ cursor: pointer;
+ }
}
}
diff --git a/ui/src/frontend/viewer_page.ts b/ui/src/frontend/viewer_page.ts
index b528f87..27d52c9 100644
--- a/ui/src/frontend/viewer_page.ts
+++ b/ui/src/frontend/viewer_page.ts
@@ -13,10 +13,11 @@
// limitations under the License.
import * as m from 'mithril';
+import {Row} from 'src/common/protos';
import {Actions} from '../common/actions';
import {QueryResponse} from '../common/queries';
-import {TimeSpan} from '../common/time';
+import {fromNs, TimeSpan} from '../common/time';
import {copyToClipboard} from './clipboard';
import {TRACK_SHELL_WIDTH} from './css_constants';
@@ -28,6 +29,10 @@
import {PanAndZoomHandler} from './pan_and_zoom_handler';
import {Panel} from './panel';
import {AnyAttrsVnode, PanelContainer} from './panel_container';
+import {
+ horizontalScrollAndZoomToRange,
+ verticalScrollToTrack
+} from './scroll_helper';
import {TickmarkPanel} from './tickmark_panel';
import {TimeAxisPanel} from './time_axis_panel';
import {computeZoom} from './time_scale';
@@ -39,12 +44,83 @@
const SIDEBAR_WIDTH = 256;
+interface QueryTableRowAttrs {
+ row: Row;
+ columns: string[];
+}
+
+class QueryTableRow implements m.ClassComponent<QueryTableRowAttrs> {
+ static columnsContainsSliceLocation(columns: string[]) {
+ const requiredColumns = ['ts', 'dur', 'track_id'];
+ for (const col of requiredColumns) {
+ if (!columns.includes(col)) return false;
+ }
+ return true;
+ }
+
+ static findUiTrackId(traceTrackId: number) {
+ for (const [uiTrackId, trackState] of Object.entries(
+ globals.state.tracks)) {
+ const config = trackState.config as {trackId: number};
+ if (config.trackId === traceTrackId) return uiTrackId;
+ }
+ return null;
+ }
+
+ static rowOnClickHandler(event: Event, row: Row) {
+ // If the click bubbles up to the pan and zoom handler that will deselect
+ // the slice.
+ event.stopPropagation();
+
+ const sliceStart = fromNs(row.ts as number);
+ // row.dur can be negative. Clamp to 1ns.
+ const sliceDur = fromNs(Math.max(row.dur as number, 1));
+ const sliceEnd = sliceStart + sliceDur;
+ const trackId = row.track_id as number;
+ const uiTrackId = this.findUiTrackId(trackId);
+ if (uiTrackId === null) return;
+ verticalScrollToTrack(uiTrackId, true);
+ horizontalScrollAndZoomToRange(sliceStart, sliceEnd);
+ const sliceId = row.slice_id as number | undefined;
+ if (sliceId !== undefined) {
+ globals.makeSelection(
+ Actions.selectChromeSlice({id: sliceId, trackId: uiTrackId}));
+ }
+ }
+
+ view(vnode: m.Vnode<QueryTableRowAttrs>) {
+ const cells = [];
+ const {row, columns} = vnode.attrs;
+ for (const col of columns) {
+ cells.push(m('td', row[col]));
+ }
+ const containsSliceLocation =
+ QueryTableRow.columnsContainsSliceLocation(columns);
+ const maybeOnClick = containsSliceLocation ?
+ (e: Event) => QueryTableRow.rowOnClickHandler(e, row) :
+ null;
+ return m(
+ 'tr',
+ {onclick: maybeOnClick, 'clickable': containsSliceLocation},
+ cells);
+ }
+}
+
class QueryTable extends Panel {
+ private previousResponse?: QueryResponse;
+
+ onbeforeupdate() {
+ const resp = globals.queryResults.get('command') as QueryResponse;
+ const res = resp !== this.previousResponse;
+ return res;
+ }
+
view() {
const resp = globals.queryResults.get('command') as QueryResponse;
if (resp === undefined) {
return m('');
}
+ this.previousResponse = resp;
const cols = [];
for (const col of resp.columns) {
cols.push(m('td', col));
@@ -53,43 +129,43 @@
const rows = [];
for (let i = 0; i < resp.rows.length; i++) {
- const cells = [];
- for (const col of resp.columns) {
- cells.push(m('td', resp.rows[i][col]));
- }
- rows.push(m('tr', cells));
+ rows.push(m(QueryTableRow, {row: resp.rows[i], columns: resp.columns}));
}
+
return m(
'div',
- m('header.overview',
- `Query result - ${Math.round(resp.durationMs)} ms`,
- m('span.code', resp.query),
- resp.error ? null :
- m('button.query-ctrl',
- {
- onclick: () => {
- const lines: string[][] = [];
- lines.push(resp.columns);
- for (const row of resp.rows) {
- const line = [];
- for (const col of resp.columns) {
- line.push(row[col].toString());
- }
- lines.push(line);
- }
- copyToClipboard(
- lines.map(line => line.join('\t')).join('\n'));
- },
- },
- 'Copy as .tsv'),
- m('button.query-ctrl',
- {
- onclick: () => {
- globals.queryResults.delete('command');
- globals.rafScheduler.scheduleFullRedraw();
- }
- },
- 'Close'), ),
+ m(
+ 'header.overview',
+ `Query result - ${Math.round(resp.durationMs)} ms`,
+ m('span.code', resp.query),
+ resp.error ?
+ null :
+ m('button.query-ctrl',
+ {
+ onclick: () => {
+ const lines: string[][] = [];
+ lines.push(resp.columns);
+ for (const row of resp.rows) {
+ const line = [];
+ for (const col of resp.columns) {
+ line.push(row[col].toString());
+ }
+ lines.push(line);
+ }
+ copyToClipboard(
+ lines.map(line => line.join('\t')).join('\n'));
+ },
+ },
+ 'Copy as .tsv'),
+ m('button.query-ctrl',
+ {
+ onclick: () => {
+ globals.queryResults.delete('command');
+ globals.rafScheduler.scheduleFullRedraw();
+ }
+ },
+ 'Close'),
+ ),
resp.error ?
m('.query-error', `SQL error: ${resp.error}`) :
m('table.query-table', m('thead', header), m('tbody', rows)));