From 3673078b119258ef8ef1e8ca88e5002c9a0913f0 Mon Sep 17 00:00:00 2001 From: Andrey Sobolev Date: Fri, 21 Feb 2025 19:46:13 +0700 Subject: [PATCH] UBERF-9501: Fix use of Date.now() (#8069) --- dev/tool/src/benchmark.ts | 16 +++++++----- dev/tool/src/clean.ts | 14 +++++----- packages/core/src/client.ts | 6 ++--- packages/core/src/measurements/context.ts | 16 ++++++------ packages/core/src/measurements/metrics.ts | 11 ++++---- packages/core/src/operations.ts | 10 +++---- packages/core/src/utils.ts | 10 +++++++ packages/platform-rig/bin/compile.js | 12 ++++----- packages/platform-rig/bin/do-svelte-check.js | 4 +-- packages/query/src/index.ts | 9 ++++--- plugins/client-resources/src/index.ts | 7 ++--- plugins/devmodel-resources/src/index.ts | 14 +++++----- .../src/components/OptimizeSkills.svelte | 6 ++--- .../src/components/CreateToDoPopup.svelte | 2 +- .../components/ServerManagerGeneral.svelte | 18 ++++++------- .../components/statistics/MetricsInfo.svelte | 18 +++++++------ pods/green/src/index.ts | 8 +++--- server/mongo/src/storage.ts | 19 +++++++------- server/postgres/src/client.ts | 6 ++--- server/postgres/src/utils.ts | 6 +++-- server/server/src/sessionManager.ts | 12 +++++---- server/tool/src/index.ts | 26 ++++++++++--------- server/ws/src/server_http.ts | 20 ++++++-------- workers/transactor/src/transactor.ts | 6 +++-- 24 files changed, 150 insertions(+), 126 deletions(-) diff --git a/dev/tool/src/benchmark.ts b/dev/tool/src/benchmark.ts index 2b5041adf1..3f0108d1c9 100644 --- a/dev/tool/src/benchmark.ts +++ b/dev/tool/src/benchmark.ts @@ -31,7 +31,9 @@ import core, { type Ref, type WorkspaceUuid, SocialIdType, - type PersonUuid + type PersonUuid, + platformNow, + platformNowDiff } from '@hcengineering/core' import { generateToken } from '@hcengineering/server-token' import { connect } from '@hcengineering/server-tool' @@ -214,7 +216,7 @@ export async function benchmark ( let timer: any if (isMainThread && monitorConnection !== undefined) { timer = setInterval(() => { - const st = Date.now() + const st = platformNow() try { const fetchUrl = endpoint.replace('ws:/', 'http:/') + '/api/v1/statistics?token=' + token @@ -269,7 +271,7 @@ export async function benchmark ( } }) .then((res) => { - const cur = Date.now() - st + const cur = platformNow() - st opTime += cur moment = cur ops++ @@ -518,7 +520,7 @@ export async function testFindAll (endpoint: string, workspace: WorkspaceUuid, a const connection = await connect(endpoint, workspace, account) try { const client = new TxOperations(connection, core.account.System) - const start = Date.now() + const start = platformNow() const res = await client.findAll( recruit.class.Applicant, {}, @@ -529,7 +531,7 @@ export async function testFindAll (endpoint: string, workspace: WorkspaceUuid, a } } ) - console.log('Find all', res.length, 'time', Date.now() - start) + console.log('Find all', res.length, 'time', platformNow() - start) } finally { await connection.close() } @@ -550,7 +552,7 @@ export async function generateWorkspaceData ( throw new Error('User not found') } const employees: PersonId[] = [emailSocialString] - const start = Date.now() + const start = platformNow() for (let i = 0; i < 100; i++) { const socialString = await generateEmployee(client) employees.push(socialString) @@ -566,7 +568,7 @@ export async function generateWorkspaceData ( await generateVacancy(client, employees) } } - console.log('Generate', Date.now() - start) + console.log('Generate', platformNowDiff(start)) } finally { await connection.close() } diff --git a/dev/tool/src/clean.ts b/dev/tool/src/clean.ts index fc51c64523..a42bddc9f4 100644 --- a/dev/tool/src/clean.ts +++ b/dev/tool/src/clean.ts @@ -58,7 +58,9 @@ import core, { generateId, getObjectValue, toIdMap, - updateAttribute + updateAttribute, + platformNow, + platformNowDiff } from '@hcengineering/core' import activity, { DOMAIN_ACTIVITY } from '@hcengineering/model-activity' import { DOMAIN_SPACE } from '@hcengineering/model-core' @@ -104,11 +106,10 @@ export async function cleanWorkspace ( for (const c of part) { await op.remove(c) } - const t = Date.now() + const t = platformNow() console.log('remove:', part.map((it) => it.name).join(', ')) await op.commit() - const t2 = Date.now() - console.log('remove time:', t2 - t, filter.length) + console.log('remove time:', platformNowDiff(t), filter.length) } } @@ -122,10 +123,9 @@ export async function cleanWorkspace ( for (const c of part) { await op.remove(c) } - const t = Date.now() + const t = platformNow() await op.commit() - const t2 = Date.now() - console.log('remove time:', t2 - t, issues.length) + console.log('remove time:', platformNowDiff(t), issues.length) } } diff --git a/packages/core/src/client.ts b/packages/core/src/client.ts index 70abad3f7d..7c15731353 100644 --- a/packages/core/src/client.ts +++ b/packages/core/src/client.ts @@ -23,7 +23,7 @@ import { ModelDb } from './memdb' import type { DocumentQuery, FindOptions, FindResult, FulltextStorage, Storage, TxResult, WithLookup } from './storage' import { SearchOptions, SearchQuery, SearchResult } from './storage' import { Tx, TxCUD, WorkspaceEvent, type TxWorkspaceEvent } from './tx' -import { toFindResult } from './utils' +import { platformNow, platformNowDiff, toFindResult } from './utils' /** * @public @@ -345,7 +345,7 @@ async function loadModel ( conn: ClientConnection, persistence?: TxPersistenceStore ): Promise<{ mode: 'same' | 'addition' | 'upgrade', current: Tx[], addition: Tx[] }> { - const t = Date.now() + const t = platformNow() const current = (await ctx.with('persistence-load', {}, () => persistence?.load())) ?? { full: true, @@ -385,7 +385,7 @@ async function loadModel ( }) if (typeof window !== 'undefined') { - console.log('find' + (result.full ? 'full model' : 'model diff'), result.transactions.length, Date.now() - t) + console.log('find' + (result.full ? 'full model' : 'model diff'), result.transactions.length, platformNowDiff(t)) } if (result.full) { return { mode: 'upgrade', current: result.transactions, addition: [] } diff --git a/packages/core/src/measurements/context.ts b/packages/core/src/measurements/context.ts index 59d0297e63..8883d8af87 100644 --- a/packages/core/src/measurements/context.ts +++ b/packages/core/src/measurements/context.ts @@ -1,6 +1,6 @@ // Basic performance metrics suite. -import { generateId } from '../utils' +import { generateId, platformNow, platformNowDiff } from '../utils' import { childMetrics, newMetrics, updateMeasure } from './metrics' import { FullParamsType, @@ -61,7 +61,7 @@ export class MeasureMetricsContext implements MeasureContext { metrics: Metrics id?: string - st = Date.now() + st = platformNow() contextData: object = {} private done (value?: number, override?: boolean): void { updateMeasure(this.metrics, this.st, this.params, this.fullParams, (spend) => {}, value, override) @@ -166,10 +166,10 @@ export class MeasureMetricsContext implements MeasureContext { op: (ctx: MeasureContext) => T | Promise, fullParams?: ParamsType ): Promise { - const st = Date.now() + const st = platformNow() const r = this.with(name, params, op, fullParams) void r.finally(() => { - this.logger.logOperation(name, Date.now() - st, { ...params, ...fullParams }) + this.logger.logOperation(name, platformNowDiff(st), { ...params, ...fullParams }) }) return r } @@ -284,7 +284,7 @@ export function registerOperationLog (ctx: MeasureContext): { opLogMetrics?: Met if (!operationProfiling) { return {} } - const op: OperationLog = { start: Date.now(), ops: [], end: -1 } + const op: OperationLog = { start: platformNow(), ops: [], end: -1 } let opLogMetrics: Metrics | undefined if (ctx.id === undefined) { @@ -305,7 +305,7 @@ export function updateOperationLog (opLogMetrics: Metrics | undefined, op: Opera return } if (op !== undefined) { - op.end = Date.now() + op.end = platformNow() } // We should keep only longest one entry if (opLogMetrics?.opLog !== undefined) { @@ -352,7 +352,7 @@ export function addOperation ( if (opLog !== undefined) { opEntry = { op: name, - start: Date.now(), + start: performance.now(), params: {}, end: -1 } @@ -361,7 +361,7 @@ export function addOperation ( if (opEntry !== undefined && opLog !== undefined) { void result.finally(() => { if (opEntry !== undefined && opLog !== undefined) { - opEntry.end = Date.now() + opEntry.end = performance.now() opEntry.params = { ...params, ...(typeof fullParams === 'function' ? fullParams() : fullParams) } opLog.ops.push(opEntry) } diff --git a/packages/core/src/measurements/metrics.ts b/packages/core/src/measurements/metrics.ts index 49d6591804..09ab8fb7e0 100644 --- a/packages/core/src/measurements/metrics.ts +++ b/packages/core/src/measurements/metrics.ts @@ -1,6 +1,7 @@ // Basic performance metrics suite. import { MetricsData } from '.' +import { platformNow } from '../utils' import { FullParamsType, Metrics, ParamsType } from './types' /** @@ -65,7 +66,7 @@ export function measure ( fullParams: FullParamsType | (() => FullParamsType) = {}, endOp?: (spend: number) => void ): () => void { - const st = Date.now() + const st = platformNow() return () => { updateMeasure(metrics, st, params, fullParams, endOp) } @@ -79,7 +80,7 @@ export function updateMeasure ( value?: number, override?: boolean ): void { - const ed = Date.now() + const ed = platformNow() const fParams = typeof fullParams === 'function' ? fullParams() : fullParams // Update params if required @@ -136,7 +137,7 @@ export function childMetrics (root: Metrics, path: string[]): Metrics { /** * @public */ -export function metricsAggregate (m: Metrics, limit: number = -1): Metrics { +export function metricsAggregate (m: Metrics, limit: number = -1, roundMath: boolean = false): Metrics { let ms = aggregateMetrics(m.measurements, limit) // Use child overage, if there is no top level value specified. @@ -237,7 +238,7 @@ function toString (name: string, m: Metrics, offset: number, length: number): st * @public */ export function metricsToString (metrics: Metrics, name = 'System', length: number): string { - return toString(name, metricsAggregate(metrics, 50), 0, length) + return toString(name, metricsAggregate(metrics, 50, true), 0, length) } function printMetricsParamsRows ( @@ -287,5 +288,5 @@ function toStringRows (name: string, m: Metrics, offset: number): (number | stri * @public */ export function metricsToRows (metrics: Metrics, name = 'System'): (number | string)[][] { - return toStringRows(name, metricsAggregate(metrics, 50), 0) + return toStringRows(name, metricsAggregate(metrics, 50, true), 0) } diff --git a/packages/core/src/operations.ts b/packages/core/src/operations.ts index 6557986ed0..5c0af58b31 100644 --- a/packages/core/src/operations.ts +++ b/packages/core/src/operations.ts @@ -1,6 +1,6 @@ import { Analytics } from '@hcengineering/analytics' import { deepEqual } from 'fast-equals' -import { DocumentUpdate, DOMAIN_MODEL, Hierarchy, MixinData, MixinUpdate, ModelDb, toFindResult } from '.' +import { DocumentUpdate, DOMAIN_MODEL, Hierarchy, MixinData, MixinUpdate, ModelDb, platformNow, toFindResult } from '.' import type { PersonId, AnyAttribute, @@ -481,10 +481,10 @@ export class ApplyOperations extends TxOperations { this.notMatches.length === 0 && this.measureName == null ) { - const st = Date.now() + const st = platformNow() // Individual update, no need for apply await this.ops.tx(this.txes[0]) - const time = Date.now() - st + const time = platformNow() - st this.txes = [] return { result: true, @@ -493,7 +493,7 @@ export class ApplyOperations extends TxOperations { } } if (this.txes.length > 0) { - const st = Date.now() + const st = platformNow() const aop = this.ops.txFactory.createTxApplyIf( core.space.Tx, this.scope, @@ -505,7 +505,7 @@ export class ApplyOperations extends TxOperations { extraNotify ) const result = (await this.ops.tx(aop)) as TxApplyResult - const dnow = Date.now() + const dnow = platformNow() if (typeof window === 'object' && window !== null && this.measureName != null) { console.log(`measure ${this.measureName}`, dnow - st, 'server time', result.serverTime) } diff --git a/packages/core/src/utils.ts b/packages/core/src/utils.ts index 1e322c4c1d..4cc075f84e 100644 --- a/packages/core/src/utils.ts +++ b/packages/core/src/utils.ts @@ -928,3 +928,13 @@ export function pickPrimarySocialId (socialIds: SocialId[]): SocialId { export function notEmpty (id: T | undefined | null): id is T { return id !== undefined && id !== null && id !== '' } + +/** + * Return a current performance timestamp + */ +export const platformNow: () => number = () => performance.now() + +/** + * Return a diff with previous performance snapshot with 2 digits after . max. + */ +export const platformNowDiff = (old: number): number => Math.round((performance.now() - old) * 100) / 100 diff --git a/packages/platform-rig/bin/compile.js b/packages/platform-rig/bin/compile.js index 79b6ce8785..07ebe3e9cd 100755 --- a/packages/platform-rig/bin/compile.js +++ b/packages/platform-rig/bin/compile.js @@ -127,28 +127,28 @@ switch (args[0]) { } case 'transpile': { const filesToTranspile = collectFiles(join(process.cwd(), args[1])) - let st = Date.now() + let st = performance.now() const before = {} const after = {} collectFileStats('lib', before) performESBuild(filesToTranspile) .then(() => { - console.log("Transpile time: ", Date.now() - st) + console.log("Transpile time: ", Math.round((performance.now() - st) * 100) / 100) collectFileStats('lib', after) cleanNonModified(before, after) }) break } case 'validate': { - let st = Date.now() + let st = performance.now() validateTSC(st).then(() => { - console.log("Validate time: ", Date.now() - st) + console.log("Validate time: ", Math.round((performance.now() - st) * 100) / 100) }) break } default: { - let st = Date.now() + let st = performance.now() const filesToTranspile = collectFiles(join(process.cwd(), 'src')) Promise.all( [ @@ -157,7 +157,7 @@ switch (args[0]) { ] ) .then(() => { - console.log("Full build time: ", Date.now() - st) + console.log("Full build time: ", Math.round((performance.now() - st) * 100) / 100) }) break } diff --git a/packages/platform-rig/bin/do-svelte-check.js b/packages/platform-rig/bin/do-svelte-check.js index 3865c185da..bafa9f4b7a 100755 --- a/packages/platform-rig/bin/do-svelte-check.js +++ b/packages/platform-rig/bin/do-svelte-check.js @@ -77,7 +77,7 @@ for(const a of process.argv.slice(2)) { args.push(a) } } -let st = Date.now() +let st = performance.now() execProcess( 'svelte-check', 'svelte-check', [ @@ -85,6 +85,6 @@ execProcess( ...args ], useConsole) .then(() => { - console.log("Svelte check time: ", Date.now() - st) + console.log("Svelte check time: ", Math.round((performance.now() - st) * 100) / 100) }) diff --git a/packages/query/src/index.ts b/packages/query/src/index.ts index 536dfe664c..4f23ae8690 100644 --- a/packages/query/src/index.ts +++ b/packages/query/src/index.ts @@ -55,6 +55,7 @@ import core, { generateId, getObjectValue, matchQuery, + platformNow, reduceCalls, shouldShowArchived, toFindResult @@ -187,7 +188,7 @@ export class LiveQuery implements WithTx, Client { options?: FindOptions ): Query { const q = this.createQuery(_class, query, undefined, options) - this.queue.set(q.id, { ...q, lastUsed: Date.now() }) + this.queue.set(q.id, { ...q, lastUsed: platformNow() }) if (!(q.result instanceof Promise)) { q.result.clean() } @@ -223,7 +224,7 @@ export class LiveQuery implements WithTx, Client { q.result = await q.result } if (this.removeFromQueue(q, false)) { - this.queue.set(q.id, { ...q, lastUsed: Date.now() }) + this.queue.set(q.id, { ...q, lastUsed: platformNow() }) q.result.clean() } return toFindResult(q.result.getClone(), q.total) @@ -265,7 +266,7 @@ export class LiveQuery implements WithTx, Client { q.result = await q.result } if (this.removeFromQueue(q, false)) { - this.queue.set(q.id, { ...q, lastUsed: Date.now() }) + this.queue.set(q.id, { ...q, lastUsed: platformNow() }) q.result.clean() } return q.result.getClone>().shift() @@ -443,7 +444,7 @@ export class LiveQuery implements WithTx, Client { if (!(q.result instanceof Promise)) { q.result.clean() } - this.queue.set(q.id, { ...q, lastUsed: Date.now() }) + this.queue.set(q.id, { ...q, lastUsed: platformNow() }) } } } diff --git a/plugins/client-resources/src/index.ts b/plugins/client-resources/src/index.ts index c2266fca7a..61d8bfc9ec 100644 --- a/plugins/client-resources/src/index.ts +++ b/plugins/client-resources/src/index.ts @@ -35,7 +35,8 @@ import core, { type ModelFilter, type PluginConfiguration, type Ref, - type TxCUD + type TxCUD, + platformNow } from '@hcengineering/core' import platform, { Severity, Status, getMetadata, getPlugins, setPlatformStatus } from '@hcengineering/platform' import { connect } from './connection' @@ -46,7 +47,7 @@ let dbRequest: IDBOpenDBRequest | undefined let dbPromise: Promise = Promise.resolve(undefined) if (typeof localStorage !== 'undefined') { - const st = Date.now() + const st = platformNow() dbPromise = new Promise((resolve) => { dbRequest = indexedDB.open('model.db.persistence', 2) @@ -58,7 +59,7 @@ if (typeof localStorage !== 'undefined') { } dbRequest.onsuccess = function () { const db = (dbRequest as IDBOpenDBRequest).result - console.log('init DB complete', Date.now() - st) + console.log('init DB complete', platformNow() - st) resolve(db) } }) diff --git a/plugins/devmodel-resources/src/index.ts b/plugins/devmodel-resources/src/index.ts index 55bcf44b36..5d06878b96 100644 --- a/plugins/devmodel-resources/src/index.ts +++ b/plugins/devmodel-resources/src/index.ts @@ -16,6 +16,8 @@ import core, { DOMAIN_MODEL, cutObjectArray, + platformNow, + platformNowDiff, type Class, type Client, type Doc, @@ -86,7 +88,7 @@ export class PresentationClientHook implements ClientHook { query: DocumentQuery, options?: FindOptions ): Promise | undefined> { - const startTime = Date.now() + const startTime = platformNow() const isModel = client.getHierarchy().findDomain(_class) === DOMAIN_MODEL const result = await client.findOne(_class, query, options) if (this.notifyEnabled && !isModel) { @@ -100,7 +102,7 @@ export class PresentationClientHook implements ClientHook { ' =>model', client.getModel(), getMetadata(devmodel.metadata.DevModel), - Date.now() - startTime, + platformNow() - startTime, this.stackLine() ) } @@ -113,7 +115,7 @@ export class PresentationClientHook implements ClientHook { query: DocumentQuery, options?: FindOptions ): Promise> { - const startTime = Date.now() + const startTime = platformNow() const isModel = client.getHierarchy().findDomain(_class) === DOMAIN_MODEL const result = await client.findAll(_class, query, options) if (this.notifyEnabled && !isModel) { @@ -127,7 +129,7 @@ export class PresentationClientHook implements ClientHook { ' =>model', client.getModel(), getMetadata(devmodel.metadata.DevModel), - Date.now() - startTime, + platformNow() - startTime, JSON.stringify(result).length, this.stackLine() ) @@ -150,7 +152,7 @@ export class PresentationClientHook implements ClientHook { } async tx (client: Client, tx: Tx): Promise { - const startTime = Date.now() + const startTime = platformNow() const result = await client.tx(tx) if (this.notifyEnabled && (tx as any).objectClass !== core.class.BenchmarkDoc) { console.debug( @@ -158,7 +160,7 @@ export class PresentationClientHook implements ClientHook { testing ? JSON.stringify(cutObjectArray(tx)).slice(0, 160) : tx, result, getMetadata(devmodel.metadata.DevModel), - Date.now() - startTime, + platformNowDiff(startTime), this.stackLine() ) } diff --git a/plugins/recruit-resources/src/components/OptimizeSkills.svelte b/plugins/recruit-resources/src/components/OptimizeSkills.svelte index 2b726016cd..b781a484bc 100644 --- a/plugins/recruit-resources/src/components/OptimizeSkills.svelte +++ b/plugins/recruit-resources/src/components/OptimizeSkills.svelte @@ -13,7 +13,7 @@ // limitations under the License. -->