Skip to content

Commit

Permalink
chore(profiling): Move profiling types to types and cache to utils (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
krystofwoldrich authored Jun 20, 2023
1 parent 50ead24 commit 9d8464b
Show file tree
Hide file tree
Showing 8 changed files with 162 additions and 138 deletions.
72 changes: 2 additions & 70 deletions packages/browser/src/profiling/cache.ts
Original file line number Diff line number Diff line change
@@ -1,72 +1,4 @@
import type { Event } from '@sentry/types';
import { makeFifoCache } from '@sentry/utils';

/**
* Creates a cache that evicts keys in fifo order
* @param size {Number}
*/
export function makeProfilingCache<Key extends string, Value extends Event>(
size: number,
): {
get: (key: Key) => Value | undefined;
add: (key: Key, value: Value) => void;
delete: (key: Key) => boolean;
clear: () => void;
size: () => number;
} {
// Maintain a fifo queue of keys, we cannot rely on Object.keys as the browser may not support it.
let evictionOrder: Key[] = [];
let cache: Record<string, Value> = {};

return {
add(key: Key, value: Value) {
while (evictionOrder.length >= size) {
// shift is O(n) but this is small size and only happens if we are
// exceeding the cache size so it should be fine.
const evictCandidate = evictionOrder.shift();

if (evictCandidate !== undefined) {
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete cache[evictCandidate];
}
}

// in case we have a collision, delete the old key.
if (cache[key]) {
this.delete(key);
}

evictionOrder.push(key);
cache[key] = value;
},
clear() {
cache = {};
evictionOrder = [];
},
get(key: Key): Value | undefined {
return cache[key];
},
size() {
return evictionOrder.length;
},
// Delete cache key and return true if it existed, false otherwise.
delete(key: Key): boolean {
if (!cache[key]) {
return false;
}

// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete cache[key];

for (let i = 0; i < evictionOrder.length; i++) {
if (evictionOrder[i] === key) {
evictionOrder.splice(i, 1);
break;
}
}

return true;
},
};
}

export const PROFILING_EVENT_CACHE = makeProfilingCache<string, Event>(20);
export const PROFILING_EVENT_CACHE = makeFifoCache<string, Event>(20);
60 changes: 0 additions & 60 deletions packages/browser/src/profiling/jsSelfProfiling.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,63 +53,3 @@ declare global {
export interface RawThreadCpuProfile extends JSSelfProfile {
profile_id: string;
}
export interface ThreadCpuProfile {
samples: {
stack_id: number;
thread_id: string;
elapsed_since_start_ns: string;
}[];
stacks: number[][];
frames: {
function: string;
file: string | undefined;
line: number | undefined;
column: number | undefined;
}[];
thread_metadata: Record<string, { name?: string; priority?: number }>;
queue_metadata?: Record<string, { label: string }>;
}

export interface SentryProfile {
event_id: string;
version: string;
os: {
name: string;
version: string;
build_number: string;
};
runtime: {
name: string;
version: string;
};
device: {
architecture: string;
is_emulator: boolean;
locale: string;
manufacturer: string;
model: string;
};
timestamp: string;
release: string;
environment: string;
platform: string;
profile: ThreadCpuProfile;
debug_meta?: {
images: {
debug_id: string;
image_addr: string;
code_file: string;
type: string;
image_size: number;
image_vmaddr: string;
}[];
};
transactions: {
name: string;
trace_id: string;
id: string;
active_thread_id: string;
relative_start_ns: string;
relative_end_ns: string;
}[];
}
10 changes: 3 additions & 7 deletions packages/browser/src/profiling/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,15 @@ import type {
EventEnvelope,
EventEnvelopeHeaders,
EventItem,
Profile as SentryProfile,
SdkInfo,
SdkMetadata,
ThreadCpuProfile,
} from '@sentry/types';
import { createEnvelope, dropUndefinedKeys, dsnToString, logger, uuid4 } from '@sentry/utils';

import { WINDOW } from '../helpers';
import type {
JSSelfProfile,
JSSelfProfileStack,
RawThreadCpuProfile,
SentryProfile,
ThreadCpuProfile,
} from './jsSelfProfiling';
import type { JSSelfProfile, JSSelfProfileStack, RawThreadCpuProfile } from './jsSelfProfiling';

const MS_TO_NS = 1e6;
// Use 0 as main thread id which is identical to threadId in node:worker_threads
Expand Down
3 changes: 2 additions & 1 deletion packages/hub/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@
"lint:eslint": "eslint . --format stylish",
"lint:prettier": "prettier --check \"{src,test,scripts}/**/**.ts\"",
"test": "jest",
"test:watch": "jest --watch"
"test:watch": "jest --watch",
"yalc:publish": "ts-node ../../scripts/prepack.ts && yalc publish build --push"
},
"volta": {
"extends": "../../package.json"
Expand Down
10 changes: 10 additions & 0 deletions packages/types/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,16 @@ export type { ExtractedNodeRequestData, HttpHeaderValue, Primitive, WorkerLocati
export type { ClientOptions, Options } from './options';
export type { Package } from './package';
export type { PolymorphicEvent, PolymorphicRequest } from './polymorphics';
export type {
ThreadId,
FrameId,
StackId,
ThreadCpuSample,
ThreadCpuStack,
ThreadCpuFrame,
ThreadCpuProfile,
Profile,
} from './profiling';
export type { ReplayEvent, ReplayRecordingData, ReplayRecordingMode } from './replay';
export type { QueryParams, Request, SanitizedRequestData } from './request';
export type { Runtime } from './runtime';
Expand Down
76 changes: 76 additions & 0 deletions packages/types/src/profiling.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
export type ThreadId = string;
export type FrameId = number;
export type StackId = number;

export interface ThreadCpuSample {
stack_id: StackId;
thread_id: ThreadId;
elapsed_since_start_ns: string;
}

export type ThreadCpuStack = FrameId[];

export type ThreadCpuFrame = {
function: string;
file?: string;
line?: number;
column?: number;
};

export interface ThreadCpuProfile {
samples: ThreadCpuSample[];
stacks: ThreadCpuStack[];
frames: ThreadCpuFrame[];
thread_metadata: Record<ThreadId, { name?: string; priority?: number }>;
queue_metadata?: Record<string, { label: string }>;
}

export interface Profile {
event_id: string;
version: string;
os: {
name: string;
version: string;
build_number?: string;
};
runtime: {
name: string;
version: string;
};
device: {
architecture: string;
is_emulator: boolean;
locale: string;
manufacturer: string;
model: string;
};
timestamp: string;
release: string;
environment: string;
platform: string;
profile: ThreadCpuProfile;
debug_meta?: {
images: {
debug_id: string;
image_addr: string;
code_file: string;
type: string;
image_size: number;
image_vmaddr: string;
}[];
};
transaction?: {
name: string;
id: string;
trace_id: string;
active_thread_id: string;
};
transactions?: {
name: string;
id: string;
trace_id: string;
active_thread_id: string;
relative_start_ns: string;
relative_end_ns: string;
}[];
}
68 changes: 68 additions & 0 deletions packages/utils/src/cache.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/**
* Creates a cache that evicts keys in fifo order
* @param size {Number}
*/
export function makeFifoCache<Key extends string, Value>(
size: number,
): {
get: (key: Key) => Value | undefined;
add: (key: Key, value: Value) => void;
delete: (key: Key) => boolean;
clear: () => void;
size: () => number;
} {
// Maintain a fifo queue of keys, we cannot rely on Object.keys as the browser may not support it.
let evictionOrder: Key[] = [];
let cache: Record<string, Value> = {};

return {
add(key: Key, value: Value) {
while (evictionOrder.length >= size) {
// shift is O(n) but this is small size and only happens if we are
// exceeding the cache size so it should be fine.
const evictCandidate = evictionOrder.shift();

if (evictCandidate !== undefined) {
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete cache[evictCandidate];
}
}

// in case we have a collision, delete the old key.
if (cache[key]) {
this.delete(key);
}

evictionOrder.push(key);
cache[key] = value;
},
clear() {
cache = {};
evictionOrder = [];
},
get(key: Key): Value | undefined {
return cache[key];
},
size() {
return evictionOrder.length;
},
// Delete cache key and return true if it existed, false otherwise.
delete(key: Key): boolean {
if (!cache[key]) {
return false;
}

// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete cache[key];

for (let i = 0; i < evictionOrder.length; i++) {
if (evictionOrder[i] === key) {
evictionOrder.splice(i, 1);
break;
}
}

return true;
},
};
}
1 change: 1 addition & 0 deletions packages/utils/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,4 @@ export * from './ratelimit';
export * from './baggage';
export * from './url';
export * from './userIntegrations';
export * from './cache';

0 comments on commit 9d8464b

Please sign in to comment.