diff --git a/ui/src/base/time.ts b/ui/src/base/time.ts index 8a3ce627b2..2837a2a486 100644 --- a/ui/src/base/time.ts +++ b/ui/src/base/time.ts @@ -28,6 +28,7 @@ export type duration = bigint; // The conversion factor for converting between different time units. const TIME_UNITS_PER_SEC = 1e9; const TIME_UNITS_PER_MILLISEC = 1e6; +const TIME_UNITS_PER_MICROSEC = 1e3; export class Time { // Negative time is never found in a trace - so -1 is commonly used as a flag @@ -87,6 +88,20 @@ export class Time { return Number(t) / TIME_UNITS_PER_MILLISEC; } + // Convert microseconds (number) to a time value. + // Note: number -> BigInt conversion is relatively slow. + static fromMicros(millis: number): time { + return Time.fromRaw(BigInt(Math.floor(millis * TIME_UNITS_PER_MICROSEC))); + } + + // Convert time value to microseconds and return as a number (i.e. float). + // Warning: This function is lossy, i.e. precision is lost when converting + // BigInt -> number. + // Note: BigInt -> number conversion is relatively slow. + static toMicros(t: time): number { + return Number(t) / TIME_UNITS_PER_MICROSEC; + } + // Convert a Date object to a time value, given an offset from the unix epoch. // Note: number -> BigInt conversion is relatively slow. static fromDate(d: Date, offset: duration): time { @@ -147,11 +162,18 @@ export class Time { return Time.fromRaw(BigintMath.quant(a, b)); } - // Format time as seconds. static formatSeconds(time: time): string { return Time.toSeconds(time).toString() + ' s'; } + static formatMilliseconds(time: time): string { + return Time.toMillis(time).toString() + ' ms'; + } + + static formatMicroseconds(time: time): string { + return Time.toMicros(time).toString() + ' us'; + } + static toTimecode(time: time): Timecode { return new Timecode(time); } @@ -199,6 +221,18 @@ export class Duration { return Number(d) / TIME_UNITS_PER_SEC; } + // Convert time to seconds as a number. + // Use this function with caution. It loses precision and is slow. + static toMilliseconds(d: duration) { + return Number(d) / TIME_UNITS_PER_MILLISEC; + } + + // Convert time to seconds as a number. + // Use this function with caution. It loses precision and is slow. + static toMicroSeconds(d: duration) { + return Number(d) / TIME_UNITS_PER_MICROSEC; + } + // Print duration as as human readable string - i.e. to only a handful of // significant figues. // Use this when readability is more desireable than precision. @@ -245,6 +279,14 @@ export class Duration { static formatSeconds(dur: duration): string { return Duration.toSeconds(dur).toString() + ' s'; } + + static formatMilliseconds(dur: duration): string { + return Duration.toMilliseconds(dur).toString() + ' s'; + } + + static formatMicroseconds(dur: duration): string { + return Duration.toMicroSeconds(dur).toString() + ' s'; + } } // This class takes a time and converts it to a set of strings representing a diff --git a/ui/src/core/timestamp_format.ts b/ui/src/core/timestamp_format.ts index bec1482f7e..f4d7d809a8 100644 --- a/ui/src/core/timestamp_format.ts +++ b/ui/src/core/timestamp_format.ts @@ -19,6 +19,8 @@ export enum TimestampFormat { TraceNs = 'traceNs', TraceNsLocale = 'traceNsLocale', Seconds = 'seconds', + Milliseoncds = 'milliseconds', + Microseconds = 'microseconds', UTC = 'utc', TraceTz = 'traceTz', } diff --git a/ui/src/frontend/globals.ts b/ui/src/frontend/globals.ts index f262ce7605..e650879882 100644 --- a/ui/src/frontend/globals.ts +++ b/ui/src/frontend/globals.ts @@ -645,6 +645,8 @@ class Globals { switch (fmt) { case TimestampFormat.Timecode: case TimestampFormat.Seconds: + case TimestampFormat.Milliseoncds: + case TimestampFormat.Microseconds: return this.traceContext.start; case TimestampFormat.TraceNs: case TimestampFormat.TraceNsLocale: diff --git a/ui/src/frontend/overview_timeline_panel.ts b/ui/src/frontend/overview_timeline_panel.ts index 118111ca4d..8da8813c5c 100644 --- a/ui/src/frontend/overview_timeline_panel.ts +++ b/ui/src/frontend/overview_timeline_panel.ts @@ -282,6 +282,12 @@ function renderTimestamp( case TimestampFormat.Seconds: ctx.fillText(Time.formatSeconds(time), x, y, minWidth); break; + case TimestampFormat.Milliseoncds: + ctx.fillText(Time.formatMilliseconds(time), x, y, minWidth); + break; + case TimestampFormat.Microseconds: + ctx.fillText(Time.formatMicroseconds(time), x, y, minWidth); + break; default: const z: never = fmt; throw new Error(`Invalid timestamp ${z}`); diff --git a/ui/src/frontend/time_axis_panel.ts b/ui/src/frontend/time_axis_panel.ts index 63d60e3698..8ca13dbffc 100644 --- a/ui/src/frontend/time_axis_panel.ts +++ b/ui/src/frontend/time_axis_panel.ts @@ -128,6 +128,22 @@ function renderTimestamp( return renderRawTimestamp(ctx, time.toLocaleString(), x, y, minWidth); case TimestampFormat.Seconds: return renderRawTimestamp(ctx, Time.formatSeconds(time), x, y, minWidth); + case TimestampFormat.Milliseoncds: + return renderRawTimestamp( + ctx, + Time.formatMilliseconds(time), + x, + y, + minWidth, + ); + case TimestampFormat.Microseconds: + return renderRawTimestamp( + ctx, + Time.formatMicroseconds(time), + x, + y, + minWidth, + ); default: const z: never = fmt; throw new Error(`Invalid timestamp ${z}`); diff --git a/ui/src/frontend/time_selection_panel.ts b/ui/src/frontend/time_selection_panel.ts index a00d7e40ce..cbfeaaef96 100644 --- a/ui/src/frontend/time_selection_panel.ts +++ b/ui/src/frontend/time_selection_panel.ts @@ -263,6 +263,10 @@ function stringifyTimestamp(time: time): string { return time.toLocaleString(); case TimestampFormat.Seconds: return Time.formatSeconds(time); + case TimestampFormat.Milliseoncds: + return Time.formatMilliseconds(time); + case TimestampFormat.Microseconds: + return Time.formatMicroseconds(time); default: const z: never = fmt; throw new Error(`Invalid timestamp ${z}`); diff --git a/ui/src/frontend/ui_main.ts b/ui/src/frontend/ui_main.ts index d1212a9762..da1fb304a8 100644 --- a/ui/src/frontend/ui_main.ts +++ b/ui/src/frontend/ui_main.ts @@ -100,6 +100,8 @@ export class UiMain implements m.ClassComponent { displayName: 'Realtime (Trace TZ)', }, {key: TimestampFormat.Seconds, displayName: 'Seconds'}, + {key: TimestampFormat.Milliseoncds, displayName: 'Milliseconds'}, + {key: TimestampFormat.Microseconds, displayName: 'Microseconds'}, {key: TimestampFormat.TraceNs, displayName: 'Trace nanoseconds'}, { key: TimestampFormat.TraceNsLocale, diff --git a/ui/src/frontend/widgets/duration.ts b/ui/src/frontend/widgets/duration.ts index cadbefd1ae..a6234061a4 100644 --- a/ui/src/frontend/widgets/duration.ts +++ b/ui/src/frontend/widgets/duration.ts @@ -60,6 +60,8 @@ export class DurationWidget implements m.ClassComponent { menuItemForFormat(TimestampFormat.UTC, 'Realtime (UTC)'), menuItemForFormat(TimestampFormat.TraceTz, 'Realtime (Trace TZ)'), menuItemForFormat(TimestampFormat.Seconds, 'Seconds'), + menuItemForFormat(TimestampFormat.Milliseoncds, 'Milliseconds'), + menuItemForFormat(TimestampFormat.Microseconds, 'Microseconds'), menuItemForFormat(TimestampFormat.TraceNs, 'Raw'), menuItemForFormat( TimestampFormat.TraceNsLocale, @@ -119,6 +121,10 @@ export function renderDuration(dur: duration): string { return dur.toLocaleString(); case TimestampFormat.Seconds: return Duration.formatSeconds(dur); + case TimestampFormat.Milliseoncds: + return Duration.formatMilliseconds(dur); + case TimestampFormat.Microseconds: + return Duration.formatMicroseconds(dur); default: const x: never = fmt; throw new Error(`Invalid format ${x}`); diff --git a/ui/src/frontend/widgets/timestamp.ts b/ui/src/frontend/widgets/timestamp.ts index 4ae3c8444d..a53a166d43 100644 --- a/ui/src/frontend/widgets/timestamp.ts +++ b/ui/src/frontend/widgets/timestamp.ts @@ -76,6 +76,8 @@ export class Timestamp implements m.ClassComponent { menuItemForFormat(TimestampFormat.UTC, 'Realtime (UTC)'), menuItemForFormat(TimestampFormat.TraceTz, 'Realtime (Trace TZ)'), menuItemForFormat(TimestampFormat.Seconds, 'Seconds'), + menuItemForFormat(TimestampFormat.Milliseoncds, 'Milliseconds'), + menuItemForFormat(TimestampFormat.Microseconds, 'Microseconds'), menuItemForFormat(TimestampFormat.TraceNs, 'Raw'), menuItemForFormat( TimestampFormat.TraceNsLocale, @@ -115,6 +117,10 @@ function renderTimestamp(time: time): m.Children { return domainTime.toLocaleString(); case TimestampFormat.Seconds: return Time.formatSeconds(domainTime); + case TimestampFormat.Milliseoncds: + return Time.formatMilliseconds(domainTime); + case TimestampFormat.Microseconds: + return Time.formatMicroseconds(domainTime); default: const x: never = fmt; throw new Error(`Invalid timestamp ${x}`);