Merge "[ui] Put error message in omnibox attrs, not in the selector." into main
diff --git a/src/trace_processor/sqlite/sqlite_engine.cc b/src/trace_processor/sqlite/sqlite_engine.cc
index 2a76c53..9513182 100644
--- a/src/trace_processor/sqlite/sqlite_engine.cc
+++ b/src/trace_processor/sqlite/sqlite_engine.cc
@@ -19,9 +19,11 @@
#include <memory>
#include <optional>
#include <utility>
+#include <vector>
#include "perfetto/base/status.h"
#include "perfetto/ext/base/string_utils.h"
+#include "perfetto/public/compiler.h"
#include "src/trace_processor/sqlite/db_sqlite_table.h"
#include "src/trace_processor/sqlite/query_cache.h"
#include "src/trace_processor/sqlite/scoped_db.h"
@@ -104,7 +106,9 @@
}
for (const auto& drop : drop_stmts) {
int ret = sqlite3_exec(db(), drop.c_str(), nullptr, nullptr, nullptr);
- PERFETTO_CHECK(ret == SQLITE_OK);
+ if (PERFETTO_UNLIKELY(ret != SQLITE_OK)) {
+ PERFETTO_FATAL("Failed to execute statement: '%s'", drop.c_str());
+ }
}
// It is important to unregister any functions that have been registered with
@@ -114,7 +118,9 @@
int ret = sqlite3_create_function_v2(db_.get(), it.key().first.c_str(),
it.key().second, SQLITE_UTF8, nullptr,
nullptr, nullptr, nullptr, nullptr);
- PERFETTO_CHECK(ret == SQLITE_OK);
+ if (PERFETTO_UNLIKELY(ret != SQLITE_OK)) {
+ PERFETTO_FATAL("Failed to drop function: '%s'", it.key().first.c_str());
+ }
}
fn_ctx_.Clear();
@@ -127,7 +133,16 @@
saved_tables_.Clear();
// The above operations should have cleared all the tables.
- PERFETTO_CHECK(sqlite_tables_.size() == 0);
+ if (PERFETTO_UNLIKELY(sqlite_tables_.size() != 0)) {
+ std::vector<std::string> tables;
+ for (auto it = sqlite_tables_.GetIterator(); it; ++it) {
+ tables.push_back(it.key());
+ }
+ std::string joined = base::Join(tables, ",");
+ PERFETTO_FATAL(
+ "SqliteTable instances still exist: count='%zu', tables='[%s]'",
+ sqlite_tables_.size(), joined.c_str());
+ }
}
SqliteEngine::PreparedStatement SqliteEngine::PrepareStatement(SqlSource sql) {
diff --git a/ui/src/common/plugins.ts b/ui/src/common/plugins.ts
index cfdaf7e..dd4adf0 100644
--- a/ui/src/common/plugins.ts
+++ b/ui/src/common/plugins.ts
@@ -16,6 +16,7 @@
import {Disposable, Trash} from '../base/disposable';
import {assertFalse} from '../base/logging';
+import {time} from '../base/time';
import {globals} from '../frontend/globals';
import {
Command,
@@ -260,6 +261,11 @@
};
});
},
+
+ panToTimestamp(ts: time):
+ void {
+ globals.panToTimestamp(ts);
+ },
};
dispose(): void {
diff --git a/ui/src/frontend/app.ts b/ui/src/frontend/app.ts
index 025d5ff..1ce9074 100644
--- a/ui/src/frontend/app.ts
+++ b/ui/src/frontend/app.ts
@@ -580,7 +580,7 @@
return m(Omnibox, {
value: globals.state.omniboxState.omnibox,
- placeholder: 'Search...',
+ placeholder: 'Search or type \'>\' for commands or \':\' for SQL mode',
inputRef: App.OMNIBOX_INPUT_REF,
onInput: (value, prev) => {
if (prev === '') {
diff --git a/ui/src/frontend/globals.ts b/ui/src/frontend/globals.ts
index 0affaed..f81ceb3 100644
--- a/ui/src/frontend/globals.ts
+++ b/ui/src/frontend/globals.ts
@@ -52,6 +52,7 @@
import {BottomTabList} from './bottom_tab';
import {FrontendLocalState} from './frontend_local_state';
import {Router} from './router';
+import {horizontalScrollToTs} from './scroll_helper';
import {ServiceWorkerController} from './service_worker_controller';
import {SliceSqlId} from './sql_types';
import {createStore, Store} from './store';
@@ -861,6 +862,10 @@
openQuery(query: string, title: string, tag?: string) {
assertExists(this._openQueryHandler)(query, title, tag);
}
+
+ panToTimestamp(ts: time): void {
+ horizontalScrollToTs(ts);
+ }
}
export const globals = new Globals();
diff --git a/ui/src/plugins/dev.perfetto.CoreCommands/index.ts b/ui/src/plugins/dev.perfetto.CoreCommands/index.ts
index 7024520..083a848 100644
--- a/ui/src/plugins/dev.perfetto.CoreCommands/index.ts
+++ b/ui/src/plugins/dev.perfetto.CoreCommands/index.ts
@@ -12,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+import {Time, time} from '../../base/time';
+import {exists} from '../../base/utils';
import {
Plugin,
PluginContext,
@@ -172,9 +174,40 @@
});
},
});
+
+ ctx.registerCommand({
+ id: 'dev.perfetto.CoreCommands#PanToTimestamp',
+ name: 'Pan To Timestamp',
+ callback: (tsRaw: unknown) => {
+ if (exists(tsRaw)) {
+ if (typeof tsRaw !== 'bigint') {
+ throw Error(`${tsRaw} is not a bigint`);
+ }
+ ctx.timeline.panToTimestamp(Time.fromRaw(tsRaw));
+ } else {
+ // No args passed, probably run from the command palette.
+ const ts = promptForTimestamp('Enter a timestamp');
+ if (exists(ts)) {
+ ctx.timeline.panToTimestamp(Time.fromRaw(ts));
+ }
+ }
+ },
+ });
},
};
+function promptForTimestamp(message: string): time|undefined {
+ const tsStr = window.prompt(message);
+ if (tsStr !== null) {
+ try {
+ return Time.fromRaw(BigInt(tsStr));
+ } catch {
+ window.alert(`${tsStr} is not an integer`);
+ }
+ }
+ return undefined;
+}
+
export const plugin: PluginDescriptor = {
pluginId: 'dev.perfetto.CoreCommands',
plugin: coreCommands,
diff --git a/ui/src/public/index.ts b/ui/src/public/index.ts
index e0d7c9d..725c526 100644
--- a/ui/src/public/index.ts
+++ b/ui/src/public/index.ts
@@ -278,6 +278,9 @@
// Retrieve a list of tracks on the timeline.
tracks: TrackRef[];
+
+ // Bring a timestamp into view.
+ panToTimestamp(ts: time): void;
}
// Control over the bottom details pane.