Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Record CPU traces from screenshot runs #791

Merged
merged 1 commit into from
Jul 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,7 @@ Options:
-V, --viewport Viewport. [array] [default: ["800x600"]]
--disableCssAnimation Disable CSS animation and transition. [boolean] [default: true]
--disableWaitAssets Disable waiting for requested assets [boolean] [default: false]
--trace Emit Chromium trace files per screenshot. [boolean] [default: false]
--silent [boolean] [default: false]
--verbose [boolean] [default: false]
--forwardConsoleLogs Forward in-page console logs to the user's console. [boolean] [default: false]
Expand Down
28 changes: 27 additions & 1 deletion packages/storycap/src/node/capturing-browser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import {
InvalidVariantKeysReason,
} from '../shared/screenshot-options-helper';
import { Logger } from './logger';
import { FileSystem } from './file';

/**
*
Expand Down Expand Up @@ -349,6 +350,9 @@ export class CapturingBrowser extends StoryPreviewBrowser {
* @param requestId - Represents an identifier for the screenshot
* @param variantKey - Variant identifier for the screenshot
* @param retryCount - The number which represents how many attempting to capture this story and variant
* @param logger - Logger instance
* @param forwardConsoleLogs - Whether to forward logs from the page to the user's console
* @param trace - Whether to record a CPU trace per screenshot
*
* @returns PNG buffer, whether the capturing process is succeeded or not, additional variant keys if they are emitted, and file name suffix for default the default variant.
*
Expand All @@ -364,6 +368,8 @@ export class CapturingBrowser extends StoryPreviewBrowser {
retryCount: number,
logger: Logger,
forwardConsoleLogs: boolean,
trace: boolean,
fileSystem: FileSystem,
): Promise<ScreenshotResult> {
this.currentRequestId = requestId;
this.currentVariantKey = variantKey;
Expand Down Expand Up @@ -393,6 +399,14 @@ export class CapturingBrowser extends StoryPreviewBrowser {

this.page.on('console', onConsoleLog);

if (trace) {
// Begin CPU trace, don't write to file, store it in memory
await this.page.tracing.start();
}

// Capture this outside so it can be used for the filePath generation for the trace
let defaultVariantSuffix: string | undefined;

try {
await this.setCurrentStory(story, { forceRerender: true });

Expand All @@ -413,6 +427,9 @@ export class CapturingBrowser extends StoryPreviewBrowser {
emittedScreenshotOptions = pickupWithVariantKey(this.baseScreenshotOptions, this.currentVariantKey);
}

// Set defaultVariantSuffix as soon as it's known
defaultVariantSuffix = emittedScreenshotOptions.defaultVariantSuffix;

const mergedScreenshotOptions = mergeScreenshotOptions(this.baseScreenshotOptions, emittedScreenshotOptions);

// Get keys for variants included in the screenshot options in order to queue capturing them after this sequence.
Expand Down Expand Up @@ -467,10 +484,19 @@ export class CapturingBrowser extends StoryPreviewBrowser {
buffer,
succeeded: true,
variantKeysToPush,
defaultVariantSuffix: emittedScreenshotOptions.defaultVariantSuffix,
defaultVariantSuffix,
};
} finally {
this.page.off('console', onConsoleLog);

if (trace) {
// Finish CPU trace.
const traceBuffer = await this.page.tracing.stop();

// Calculate the suffix and save the trace to the file.
const suffix = variantKey.isDefault && defaultVariantSuffix ? [defaultVariantSuffix] : variantKey.keys;
await fileSystem.saveTrace(story.kind, story.story, suffix, traceBuffer);
}
}
}
}
3 changes: 3 additions & 0 deletions packages/storycap/src/node/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ function createOptions(): MainOptions {
default: false,
description: 'Disable waiting for requested assets',
})
.option('trace', { boolean: true, default: false, description: 'Emit Chromium trace files per screenshot.' })
.option('silent', { boolean: true, default: false })
.option('verbose', { boolean: true, default: false })
.option('forwardConsoleLogs', {
Expand Down Expand Up @@ -131,6 +132,7 @@ function createOptions(): MainOptions {
stateChangeDelay,
disableCssAnimation,
disableWaitAssets,
trace,
listDevices,
chromiumChannel,
chromiumPath,
Expand Down Expand Up @@ -185,6 +187,7 @@ function createOptions(): MainOptions {
stateChangeDelay,
disableCssAnimation,
disableWaitAssets,
trace,
forwardConsoleLogs,
chromiumChannel: chromiumChannel as ChromeChannel,
chromiumPath,
Expand Down
46 changes: 36 additions & 10 deletions packages/storycap/src/node/file.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,20 @@ import sanitize from 'sanitize-filename';
export class FileSystem {
constructor(private opt: MainOptions) {}

private getPath(kind: string, story: string, suffix: string[], extension: string) {
const name = this.opt.flat
? sanitize((kind + '_' + story).replace(/\//g, '_'))
: kind
.split('/')
.map(k => sanitize(k))
.join('/') +
'/' +
sanitize(story);
const filePath = path.join(this.opt.outDir, name + (suffix.length ? `_${suffix.join('_')}` : '') + extension);

return filePath;
}

/**
*
* Save captured buffer as a PNG image.
Expand All @@ -17,16 +31,28 @@ export class FileSystem {
* @returns Absolute file path
*
**/
async save(kind: string, story: string, suffix: string[], buffer: Buffer) {
const name = this.opt.flat
? sanitize((kind + '_' + story).replace(/\//g, '_'))
: kind
.split('/')
.map(k => sanitize(k))
.join('/') +
'/' +
sanitize(story);
const filePath = path.join(this.opt.outDir, name + (suffix.length ? `_${suffix.join('_')}` : '') + '.png');
async saveScreenshot(kind: string, story: string, suffix: string[], buffer: Buffer) {
const filePath = this.getPath(kind, story, suffix, '.png');

await fs.mkdir(path.dirname(filePath), { recursive: true });
await fs.writeFile(filePath, buffer);

return filePath;
}

/**
*
* Save captured tracing buffer as a json file.
*
* @param kind - Story kind
* @param story - Name of this story
* @param suffix - File name suffix
* @param buffer - PNG image buffer to save
* @returns Absolute file path
*
**/
async saveTrace(kind: string, story: string, suffix: string[], buffer: Buffer) {
const filePath = this.getPath(kind, story, [...suffix, 'trace'], '.json');

await fs.mkdir(path.dirname(filePath), { recursive: true });
await fs.writeFile(filePath, buffer);
Expand Down
1 change: 1 addition & 0 deletions packages/storycap/src/node/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ export async function main(mainOptions: MainOptions) {
fileSystem,
logger,
forwardConsoleLogs: mainOptions.forwardConsoleLogs,
trace: mainOptions.trace,
}).execute();
logger.debug('Ended ScreenshotService execution.');
return captured;
Expand Down
6 changes: 4 additions & 2 deletions packages/storycap/src/node/screenshot-service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export type ScreenshotServiceOptions = {
fileSystem: FileSystem;
stories: Story[];
forwardConsoleLogs: boolean;
trace: boolean;
};

/**
Expand All @@ -65,6 +66,7 @@ export function createScreenshotService({
stories,
workers,
forwardConsoleLogs,
trace,
}: ScreenshotServiceOptions): ScreenshotService {
const service = createExecutionService(
workers,
Expand All @@ -73,7 +75,7 @@ export function createScreenshotService({
async worker => {
// Delegate the request to the worker.
const [result, elapsedTime] = await time(
worker.screenshot(rid, story, variantKey, count, logger, forwardConsoleLogs),
worker.screenshot(rid, story, variantKey, count, logger, forwardConsoleLogs, trace, fileSystem),
);

const { succeeded, buffer, variantKeysToPush, defaultVariantSuffix } = result;
Expand All @@ -87,7 +89,7 @@ export function createScreenshotService({

if (buffer) {
const suffix = variantKey.isDefault && defaultVariantSuffix ? [defaultVariantSuffix] : variantKey.keys;
const path = await fileSystem.save(story.kind, story.story, suffix, buffer);
const path = await fileSystem.saveScreenshot(story.kind, story.story, suffix, buffer);
logger.log(`Screenshot stored: ${logger.color.magenta(path)} in ${elapsedTime} msec.`);
return true;
}
Expand Down
1 change: 1 addition & 0 deletions packages/storycap/src/node/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export interface MainOptions extends BaseBrowserOptions {
exclude: string[];
disableCssAnimation: boolean;
disableWaitAssets: boolean;
trace: boolean;
forwardConsoleLogs: boolean;
parallel: number;
shard: ShardOptions;
Expand Down
1 change: 1 addition & 0 deletions packages/storycap/src/shared/screenshot-options-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const defaultScreenshotOptions = {
captureBeyondViewport: true,
clip: null,
forwardConsoleLogs: false,
trace: false,
} as const;

/**
Expand Down