larry babby and threejs for glsl

This commit is contained in:
Sam
2024-06-24 21:24:00 +12:00
parent 87d5dc634d
commit 907ebae4c0
6474 changed files with 1279596 additions and 8 deletions

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017-present Devon Govett
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,8 @@
const fs = require('fs');
let contents = fs.readFileSync(__dirname + '/lib/Tracer.d.ts', 'utf8');
// Some fixups of typescript output
contents = contents.replace(/^\s*#private;\s*$/gm, '');
fs.writeFileSync(__dirname + '/lib/Tracer.d.ts', contents);

View File

@@ -0,0 +1,38 @@
/// <reference types="node" />
import type { Session } from "inspector";
export type Profile = {
nodes: Array<ProfileNode>;
startTime: number;
endTime: number;
samples?: Array<number>;
timeDeltas?: Array<number>;
};
type ProfileNode = {
id: number;
callFrame: CallFrame;
hitCount?: number;
children?: Array<number>;
deoptReason?: string;
positionTicks?: PositionTickInfo;
};
type CallFrame = {
functionName: string;
scriptId: string;
url: string;
lineNumber: string;
columnNumber: string;
};
type PositionTickInfo = {
line: number;
ticks: number;
};
export default class SamplingProfiler {
session: Session;
startProfiling(): Promise<unknown>;
sendCommand(method: string, params?: unknown): Promise<{
profile: Profile;
}>;
destroy(): void;
stopProfiling(): Promise<Profile>;
}
export {};

View File

@@ -0,0 +1,69 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
function _assert() {
const data = _interopRequireDefault(require("assert"));
_assert = function () {
return data;
};
return data;
}
function _diagnostic() {
const data = _interopRequireDefault(require("@parcel/diagnostic"));
_diagnostic = function () {
return data;
};
return data;
}
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
// https://chromedevtools.github.io/devtools-protocol/tot/Profiler#type-Profile
// https://chromedevtools.github.io/devtools-protocol/tot/Profiler#type-ProfileNode
// https://chromedevtools.github.io/devtools-protocol/tot/Runtime#type-CallFrame
// https://chromedevtools.github.io/devtools-protocol/tot/Profiler#type-PositionTickInfo
class SamplingProfiler {
startProfiling() {
let inspector;
try {
inspector = require('inspector');
} catch (err) {
throw new (_diagnostic().default)({
diagnostic: {
message: `The inspector module isn't available`,
origin: '@parcel/workers',
hints: ['Disable build profiling']
}
});
}
this.session = new inspector.Session();
this.session.connect();
return Promise.all([this.sendCommand('Profiler.setSamplingInterval', {
interval: 100
}), this.sendCommand('Profiler.enable'), this.sendCommand('Profiler.start')]);
}
sendCommand(method, params) {
(0, _assert().default)(this.session != null);
return new Promise((resolve, reject) => {
this.session.post(method, params, (err, p) => {
if (err == null) {
resolve(p);
} else {
reject(err);
}
});
});
}
destroy() {
if (this.session != null) {
this.session.disconnect();
}
}
async stopProfiling() {
let res = await this.sendCommand('Profiler.stop');
this.destroy();
return res.profile;
}
}
exports.default = SamplingProfiler;

View File

@@ -0,0 +1,15 @@
/// <reference types="node" />
import type { Profile } from "./SamplingProfiler";
import type { Writable } from "stream";
import { Tracer } from "chrome-trace-event";
export default class Trace {
tracer: Tracer;
tid: number;
eventId: number;
constructor();
getEventId(): number;
init(ts: number): void;
addCPUProfile(name: string, profile: Profile): void;
pipe(writable: Writable): Writable;
flush(): void;
}

View File

@@ -0,0 +1,119 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
function _chromeTraceEvent() {
const data = require("chrome-trace-event");
_chromeTraceEvent = function () {
return data;
};
return data;
}
class Trace {
constructor() {
this.tracer = new (_chromeTraceEvent().Tracer)();
this.tid = 0;
this.eventId = 0;
}
getEventId() {
return this.eventId++;
}
init(ts) {
this.tracer.instantEvent({
name: 'TracingStartedInPage',
id: this.getEventId(),
ts,
cat: ['disabled-by-default-devtools.timeline'],
args: {
data: {
sessionId: '-1',
page: '0xfff',
frames: [{
frame: '0xfff',
url: 'parcel',
name: ''
}]
}
}
});
this.tracer.instantEvent({
name: 'TracingStartedInBrowser',
id: this.getEventId(),
ts,
cat: ['disabled-by-default-devtools.timeline'],
args: {
data: {
sessionId: '-1'
}
}
});
}
addCPUProfile(name, profile) {
if (this.eventId === 0) {
this.init(profile.startTime);
}
const trace = this.tracer;
const tid = this.tid;
this.tid++;
const cpuStartTime = profile.startTime;
const cpuEndTime = profile.endTime;
trace.instantEvent({
tid,
id: this.getEventId(),
cat: ['toplevel'],
name: 'TaskQueueManager::ProcessTaskFromWorkQueue',
args: {
src_file: '../../ipc/ipc_moji_bootstrap.cc',
src_func: 'Accept'
},
ts: cpuStartTime
});
trace.completeEvent({
tid,
name: 'EvaluateScript',
id: this.getEventId(),
cat: ['devtools.timeline'],
ts: cpuStartTime,
dur: cpuEndTime - cpuStartTime,
args: {
data: {
url: 'parcel',
lineNumber: 1,
columnNumber: 1,
frame: '0xFFF'
}
}
});
trace.instantEvent({
tid,
ts: 0,
ph: 'M',
cat: ['__metadata'],
name: 'thread_name',
args: {
name
}
});
trace.instantEvent({
tid,
name: 'CpuProfile',
id: this.getEventId(),
cat: ['disabled-by-default-devtools.timeline'],
ts: cpuEndTime,
args: {
data: {
cpuProfile: profile
}
}
});
}
pipe(writable) {
return this.tracer.pipe(writable);
}
flush() {
this.tracer.push(null);
}
}
exports.default = Trace;

View File

@@ -0,0 +1,28 @@
import type { TraceEvent, IDisposable, PluginTracer as IPluginTracer } from "@parcel/types";
import type { TraceMeasurement as ITraceMeasurement } from "./types";
export default class Tracer {
onTrace(cb: (event: TraceEvent) => unknown): IDisposable;
wrap(name: string, fn: () => unknown): Promise<void>;
createMeasurement(name: string, category?: string, argumentName?: string, otherArgs?: Record<string, unknown>): ITraceMeasurement | null;
get enabled(): boolean;
enable(): void;
disable(): void;
trace(event: TraceEvent): void;
}
export declare const tracer: Tracer;
type TracerOpts = {
origin: string;
category: string;
};
export declare class PluginTracer implements IPluginTracer {
/** @private */
origin: string;
/** @private */
category: string;
/** @private */
constructor(opts: TracerOpts);
get enabled(): boolean;
createMeasurement(name: string, category?: string, argumentName?: string, otherArgs?: Record<string, unknown>): ITraceMeasurement | null;
}
export {};

View File

@@ -0,0 +1,131 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.tracer = exports.default = exports.PluginTracer = void 0;
function _events() {
const data = require("@parcel/events");
_events = function () {
return data;
};
return data;
}
function _perf_hooks() {
const data = require("perf_hooks");
_perf_hooks = function () {
return data;
};
return data;
}
// @ts-ignore
let tid;
try {
tid = require('worker_threads').threadId;
} catch {
tid = 0;
}
const pid = process.pid;
class TraceMeasurement {
#active = true;
#name;
#pid;
#tid;
#start;
// $FlowFixMe
#data;
constructor(tracer, name, pid, tid, data) {
this.#name = name;
this.#pid = pid;
this.#tid = tid;
this.#start = _perf_hooks().performance.now();
this.#data = data;
}
end() {
if (!this.#active) return;
const duration = _perf_hooks().performance.now() - this.#start;
tracer.trace({
type: 'trace',
name: this.#name,
pid: this.#pid,
tid: this.#tid,
duration,
ts: this.#start,
...this.#data
});
this.#active = false;
}
}
class Tracer {
#traceEmitter = new (_events().ValueEmitter)();
#enabled = false;
onTrace(cb) {
return this.#traceEmitter.addListener(cb);
}
async wrap(name, fn) {
let measurement = this.createMeasurement(name);
try {
await fn();
} finally {
measurement && measurement.end();
}
}
createMeasurement(name, category = 'Core', argumentName, otherArgs) {
if (!this.enabled) return null;
// We create `args` in a fairly verbose way to avoid object
// allocation where not required.
let args;
if (typeof argumentName === 'string') {
args = {
name: argumentName
};
}
if (typeof otherArgs === 'object') {
if (typeof args == 'undefined') {
args = {};
}
for (const [k, v] of Object.entries(otherArgs)) {
args[k] = v;
}
}
const data = {
categories: [category],
args
};
return new TraceMeasurement(this, name, pid, tid, data);
}
get enabled() {
return this.#enabled;
}
enable() {
this.#enabled = true;
}
disable() {
this.#enabled = false;
}
trace(event) {
if (!this.#enabled) return;
this.#traceEmitter.emit(event);
}
}
exports.default = Tracer;
const tracer = exports.tracer = new Tracer();
class PluginTracer {
/** @private */
/** @private */
/** @private */
constructor(opts) {
this.origin = opts.origin;
this.category = opts.category;
}
get enabled() {
return tracer.enabled;
}
createMeasurement(name, category, argumentName, otherArgs) {
return tracer.createMeasurement(name, `${this.category}:${this.origin}${typeof category === 'string' ? `:${category}` : ''}`, argumentName, otherArgs);
}
}
exports.PluginTracer = PluginTracer;

View File

@@ -0,0 +1,4 @@
export { default as SamplingProfiler } from "./SamplingProfiler";
export { default as Trace } from "./Trace";
export { tracer, PluginTracer } from "./Tracer";
export type { TraceMeasurement, TraceMeasurementData } from "./types";

View File

@@ -0,0 +1,33 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "PluginTracer", {
enumerable: true,
get: function () {
return _Tracer.PluginTracer;
}
});
Object.defineProperty(exports, "SamplingProfiler", {
enumerable: true,
get: function () {
return _SamplingProfiler.default;
}
});
Object.defineProperty(exports, "Trace", {
enumerable: true,
get: function () {
return _Trace.default;
}
});
Object.defineProperty(exports, "tracer", {
enumerable: true,
get: function () {
return _Tracer.tracer;
}
});
var _SamplingProfiler = _interopRequireDefault(require("./SamplingProfiler"));
var _Trace = _interopRequireDefault(require("./Trace"));
var _Tracer = require("./Tracer");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

View File

@@ -0,0 +1,7 @@
export interface TraceMeasurement {
end(): void;
}
export type TraceMeasurementData = {
readonly categories: string[];
readonly args?: Record<string, unknown>;
};

View File

@@ -0,0 +1 @@
"use strict";

View File

@@ -0,0 +1,32 @@
{
"name": "@parcel/profiler",
"version": "2.12.0",
"description": "Blazing fast, zero configuration web application bundler",
"license": "MIT",
"publishConfig": {
"access": "public"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/parcel"
},
"repository": {
"type": "git",
"url": "https://github.com/parcel-bundler/parcel.git"
},
"main": "lib/index.js",
"source": "src/index.js",
"engines": {
"node": ">= 12.0.0"
},
"scripts": {
"build-ts": "flow-to-ts src/*.js --write && tsc --emitDeclarationOnly --declaration --esModuleInterop --target es2015 --moduleResolution node16 --module node16 src/*.ts && mkdir -p lib && mv src/*.d.ts lib/. && rm src/*.ts && node build-ts.js",
"check-ts": "tsc --noEmit lib/index.d.ts"
},
"dependencies": {
"@parcel/diagnostic": "2.12.0",
"@parcel/events": "2.12.0",
"chrome-trace-event": "^1.0.2"
},
"gitHead": "2059029ee91e5f03a273b0954d3e629d7375f986"
}

View File

@@ -0,0 +1,96 @@
// @flow
import type {Session} from 'inspector';
import invariant from 'assert';
import ThrowableDiagnostic from '@parcel/diagnostic';
// https://chromedevtools.github.io/devtools-protocol/tot/Profiler#type-Profile
export type Profile = {|
nodes: Array<ProfileNode>,
startTime: number,
endTime: number,
samples?: Array<number>,
timeDeltas?: Array<number>,
|};
// https://chromedevtools.github.io/devtools-protocol/tot/Profiler#type-ProfileNode
type ProfileNode = {|
id: number,
callFrame: CallFrame,
hitCount?: number,
children?: Array<number>,
deoptReason?: string,
positionTicks?: PositionTickInfo,
|};
// https://chromedevtools.github.io/devtools-protocol/tot/Runtime#type-CallFrame
type CallFrame = {|
functionName: string,
scriptId: string,
url: string,
lineNumber: string,
columnNumber: string,
|};
// https://chromedevtools.github.io/devtools-protocol/tot/Profiler#type-PositionTickInfo
type PositionTickInfo = {|
line: number,
ticks: number,
|};
export default class SamplingProfiler {
session: Session;
startProfiling(): Promise<mixed> {
let inspector;
try {
inspector = require('inspector');
} catch (err) {
throw new ThrowableDiagnostic({
diagnostic: {
message: `The inspector module isn't available`,
origin: '@parcel/workers',
hints: ['Disable build profiling'],
},
});
}
this.session = new inspector.Session();
this.session.connect();
return Promise.all([
this.sendCommand('Profiler.setSamplingInterval', {
interval: 100,
}),
this.sendCommand('Profiler.enable'),
this.sendCommand('Profiler.start'),
]);
}
sendCommand(
method: string,
params?: mixed,
): Promise<{profile: Profile, ...}> {
invariant(this.session != null);
return new Promise((resolve, reject) => {
this.session.post(method, params, (err, p) => {
if (err == null) {
resolve((p: {profile: Profile, ...}));
} else {
reject(err);
}
});
});
}
destroy() {
if (this.session != null) {
this.session.disconnect();
}
}
async stopProfiling(): Promise<Profile> {
let res = await this.sendCommand('Profiler.stop');
this.destroy();
return res.profile;
}
}

View File

@@ -0,0 +1,125 @@
// @flow
import type {Profile} from './SamplingProfiler';
import type {Writable} from 'stream';
import {Tracer} from 'chrome-trace-event';
export default class Trace {
tracer: Tracer;
tid: number;
eventId: number;
constructor() {
this.tracer = new Tracer();
this.tid = 0;
this.eventId = 0;
}
getEventId(): number {
return this.eventId++;
}
init(ts: number) {
this.tracer.instantEvent({
name: 'TracingStartedInPage',
id: this.getEventId(),
ts,
cat: ['disabled-by-default-devtools.timeline'],
args: {
data: {
sessionId: '-1',
page: '0xfff',
frames: [
{
frame: '0xfff',
url: 'parcel',
name: '',
},
],
},
},
});
this.tracer.instantEvent({
name: 'TracingStartedInBrowser',
id: this.getEventId(),
ts,
cat: ['disabled-by-default-devtools.timeline'],
args: {
data: {
sessionId: '-1',
},
},
});
}
addCPUProfile(name: string, profile: Profile) {
if (this.eventId === 0) {
this.init(profile.startTime);
}
const trace = this.tracer;
const tid = this.tid;
this.tid++;
const cpuStartTime = profile.startTime;
const cpuEndTime = profile.endTime;
trace.instantEvent({
tid,
id: this.getEventId(),
cat: ['toplevel'],
name: 'TaskQueueManager::ProcessTaskFromWorkQueue',
args: {
src_file: '../../ipc/ipc_moji_bootstrap.cc',
src_func: 'Accept',
},
ts: cpuStartTime,
});
trace.completeEvent({
tid,
name: 'EvaluateScript',
id: this.getEventId(),
cat: ['devtools.timeline'],
ts: cpuStartTime,
dur: cpuEndTime - cpuStartTime,
args: {
data: {
url: 'parcel',
lineNumber: 1,
columnNumber: 1,
frame: '0xFFF',
},
},
});
trace.instantEvent({
tid,
ts: 0,
ph: 'M',
cat: ['__metadata'],
name: 'thread_name',
args: {name},
});
trace.instantEvent({
tid,
name: 'CpuProfile',
id: this.getEventId(),
cat: ['disabled-by-default-devtools.timeline'],
ts: cpuEndTime,
args: {
data: {
cpuProfile: profile,
},
},
});
}
pipe(writable: Writable): Writable {
return this.tracer.pipe(writable);
}
flush() {
this.tracer.push(null);
}
}

View File

@@ -0,0 +1,163 @@
// @flow strict-local
import type {
TraceEvent,
IDisposable,
PluginTracer as IPluginTracer,
} from '@parcel/types';
import type {
TraceMeasurement as ITraceMeasurement,
TraceMeasurementData,
} from './types';
// @ts-ignore
import {ValueEmitter} from '@parcel/events';
import {performance} from 'perf_hooks';
let tid;
try {
tid = require('worker_threads').threadId;
} catch {
tid = 0;
}
const pid = process.pid;
class TraceMeasurement implements ITraceMeasurement {
#active: boolean = true;
#name: string;
#pid: number;
#tid: number;
#start: number;
// $FlowFixMe
#data: any;
constructor(tracer: Tracer, name, pid, tid, data) {
this.#name = name;
this.#pid = pid;
this.#tid = tid;
this.#start = performance.now();
this.#data = data;
}
end() {
if (!this.#active) return;
const duration = performance.now() - this.#start;
tracer.trace({
type: 'trace',
name: this.#name,
pid: this.#pid,
tid: this.#tid,
duration,
ts: this.#start,
...this.#data,
});
this.#active = false;
}
}
export default class Tracer {
#traceEmitter: ValueEmitter<TraceEvent> = new ValueEmitter();
#enabled: boolean = false;
onTrace(cb: (event: TraceEvent) => mixed): IDisposable {
return this.#traceEmitter.addListener(cb);
}
async wrap(name: string, fn: () => mixed): Promise<void> {
let measurement = this.createMeasurement(name);
try {
await fn();
} finally {
measurement && measurement.end();
}
}
createMeasurement(
name: string,
category: string = 'Core',
argumentName?: string,
otherArgs?: {[key: string]: mixed},
): ITraceMeasurement | null {
if (!this.enabled) return null;
// We create `args` in a fairly verbose way to avoid object
// allocation where not required.
let args: {[key: string]: mixed};
if (typeof argumentName === 'string') {
args = {name: argumentName};
}
if (typeof otherArgs === 'object') {
if (typeof args == 'undefined') {
args = {};
}
for (const [k, v] of Object.entries(otherArgs)) {
args[k] = v;
}
}
const data: TraceMeasurementData = {
categories: [category],
args,
};
return new TraceMeasurement(this, name, pid, tid, data);
}
get enabled(): boolean {
return this.#enabled;
}
enable(): void {
this.#enabled = true;
}
disable(): void {
this.#enabled = false;
}
trace(event: TraceEvent): void {
if (!this.#enabled) return;
this.#traceEmitter.emit(event);
}
}
export const tracer: Tracer = new Tracer();
type TracerOpts = {|
origin: string,
category: string,
|};
export class PluginTracer implements IPluginTracer {
/** @private */
origin: string;
/** @private */
category: string;
/** @private */
constructor(opts: TracerOpts) {
this.origin = opts.origin;
this.category = opts.category;
}
get enabled(): boolean {
return tracer.enabled;
}
createMeasurement(
name: string,
category?: string,
argumentName?: string,
otherArgs?: {[key: string]: mixed},
): ITraceMeasurement | null {
return tracer.createMeasurement(
name,
`${this.category}:${this.origin}${
typeof category === 'string' ? `:${category}` : ''
}`,
argumentName,
otherArgs,
);
}
}

View File

@@ -0,0 +1,5 @@
// @flow
export {default as SamplingProfiler} from './SamplingProfiler';
export {default as Trace} from './Trace';
export {tracer, PluginTracer} from './Tracer';
export type {TraceMeasurement, TraceMeasurementData} from './types';

View File

@@ -0,0 +1,10 @@
// @flow
export interface TraceMeasurement {
end(): void;
}
export type TraceMeasurementData = {|
+categories: string[],
+args?: {[key: string]: mixed},
|};

View File

@@ -0,0 +1,78 @@
import {tracer, PluginTracer} from '../src/Tracer';
import sinon from 'sinon';
import assert from 'assert';
describe('Tracer', () => {
let onTrace;
let traceDisposable;
beforeEach(() => {
onTrace = sinon.spy();
traceDisposable = tracer.onTrace(onTrace);
tracer.enable();
});
afterEach(() => {
traceDisposable.dispose();
});
it('returns no measurement when disabled', () => {
tracer.disable();
const measurement = tracer.createMeasurement('test');
assert(measurement == null);
assert(onTrace.notCalled);
});
it('emits a basic trace event', () => {
const measurement = tracer.createMeasurement('test');
measurement.end();
sinon.assert.calledWith(
onTrace,
sinon.match({
type: 'trace',
name: 'test',
args: undefined,
duration: sinon.match.number,
}),
);
});
it('emits a complex trace event', () => {
const measurement = tracer.createMeasurement('test', 'myPlugin', 'aaargh', {
extra: 'data',
});
measurement.end();
sinon.assert.calledWith(
onTrace,
sinon.match({
type: 'trace',
name: 'test',
categories: ['myPlugin'],
args: {extra: 'data', name: 'aaargh'},
duration: sinon.match.number,
}),
);
});
it('calling end twice on measurment should be a no-op', () => {
const measurement = tracer.createMeasurement('test');
measurement.end();
measurement.end();
sinon.assert.calledOnce(onTrace);
});
describe('PluginTracer', () => {
it('emits events with proper origin/category', () => {
const pluginTracer = new PluginTracer({
origin: 'origin',
category: 'cat',
});
const measurement = pluginTracer.createMeasurement('test', 'customCat');
measurement.end();
sinon.assert.calledWith(
onTrace,
sinon.match({
type: 'trace',
name: 'test',
categories: ['cat:origin:customCat'],
duration: sinon.match.number,
}),
);
});
});
});