/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // perf-benchmark-marker /** * Fixture for chat-simulation benchmarks. * Simplified from src/vs/base/common/async.ts for stable perf testing. */ import { IDisposable } from './lifecycle'; import { CancellationError } from './errors'; export class Throttler { private activePromise: Promise | null = null; private queuedPromiseFactory: (() => Promise) | null = null; queue(promiseFactory: () => Promise): Promise { if (this.activePromise) { this.queuedPromiseFactory = promiseFactory; return this.activePromise as Promise; } this.activePromise = promiseFactory(); return this.activePromise.finally(() => { this.activePromise = null; if (this.queuedPromiseFactory) { const factory = this.queuedPromiseFactory; this.queuedPromiseFactory = null; return this.queue(factory); } }); } } export class Delayer implements IDisposable { private timeout: any; private task: (() => T | Promise) | null = null; constructor(public defaultDelay: number) { } trigger(task: () => T | Promise, delay: number = this.defaultDelay): Promise { this.task = task; this.cancelTimeout(); return new Promise((resolve, reject) => { this.timeout = setTimeout(() => { this.timeout = null; try { resolve(this.task!()); } catch (e) { reject(e); } this.task = null; }, delay); }); } private cancelTimeout(): void { if (this.timeout !== null) { clearTimeout(this.timeout); this.timeout = null; } } dispose(): void { this.cancelTimeout(); } } export class RunOnceScheduler implements IDisposable { private runner: (() => void) | null; private timeout: any; constructor(runner: () => void, private delay: number) { this.runner = runner; } schedule(delay = this.delay): void { this.cancel(); this.timeout = setTimeout(() => { this.timeout = null; this.runner?.(); }, delay); } cancel(): void { if (this.timeout !== null) { clearTimeout(this.timeout); this.timeout = null; } } isScheduled(): boolean { return this.timeout !== null; } dispose(): void { this.cancel(); this.runner = null; } } export class Queue { private readonly queue: Array<() => Promise> = []; private running = false; async enqueue(factory: () => Promise): Promise { return new Promise((resolve, reject) => { this.queue.push(() => factory().then(resolve, reject)); if (!this.running) { this.processQueue(); } }); } private async processQueue(): Promise { this.running = true; while (this.queue.length > 0) { const task = this.queue.shift()!; await task(); } this.running = false; } get size(): number { return this.queue.length; } } export function timeout(millis: number): Promise { return new Promise(resolve => setTimeout(resolve, millis)); } export async function retry(task: () => Promise, delay: number, retries: number): Promise { let lastError: Error | undefined; for (let i = 0; i < retries; i++) { try { return await task(); } catch (error) { lastError = error as Error; await timeout(delay); } } throw lastError; }