Skip to content

Commit

Permalink
convert android format to sampled
Browse files Browse the repository at this point in the history
  • Loading branch information
JonasBa committed Mar 5, 2025
1 parent 6d4aa34 commit 0f69da1
Show file tree
Hide file tree
Showing 7 changed files with 393 additions and 59 deletions.
5 changes: 5 additions & 0 deletions static/app/types/profiling.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,11 @@ declare namespace Profiling {
profile: ContinuousProfile;
}

interface SentryAndroidContinuousProfileChunk extends Omit<Schema, 'profiles'> {
profiles: ReadonlyArray<Readonly<Profiling.EventedProfile>>;
androidClock: string;
}

////////////////
interface RawProfileBase {
endValue: number;
Expand Down
13 changes: 11 additions & 2 deletions static/app/utils/profiling/guards/profile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,17 @@ export function isSentryContinuousProfile(

export function isSentryContinuousProfileChunk(
profile: any
): profile is Profiling.SentryContinousProfileChunk {
return 'chunk_id' in profile;
): profile is
| Profiling.SentryContinousProfileChunk
| Profiling.SentryAndroidContinuousProfileChunk {
// Temporary fix to check for profiler_id in the chunk
return 'chunk_id' in profile || 'profiler_id' in profile;
}

export function isSentryAndroidContinuousProfileChunk(
profile: any
): profile is Profiling.SentryAndroidContinuousProfileChunk {
return 'androidClock' in profile;
}

export function isContinuousProfileReference(
Expand Down
192 changes: 136 additions & 56 deletions static/app/utils/profiling/profile/continuousProfile.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,73 +1,153 @@
import {ContinuousProfile} from 'sentry/utils/profiling/profile/continuousProfile';
import {
eventedProfileToSampledProfile,
importAndroidContinuousProfileChunk,
} from 'sentry/utils/profiling/profile/importProfile';
import {createContinuousProfileFrameIndex} from 'sentry/utils/profiling/profile/utils';

import {makeSentryContinuousProfile, makeTestingBoilerplate} from './testUtils';
import {
makeSentryAndroidContinuousProfileChunk,
makeSentryContinuousProfile,
makeTestingBoilerplate,
} from './testUtils';

describe('ContinuousProfile', () => {
it('imports the base properties', () => {
const trace = makeSentryContinuousProfile({
profile: {
samples: [
{timestamp: Date.now() / 1e3, stack_id: 0, thread_id: '0'},
// 10ms later
{timestamp: Date.now() / 1e3 + 0.01, stack_id: 1, thread_id: '0'},
],
frames: [
{function: 'foo', in_app: true},
{function: 'bar', in_app: true},
],
stacks: [
[0, 1],
[0, 1],
],
},
describe('sampled profile', () => {
it('imports the base properties', () => {
const trace = makeSentryContinuousProfile({
profile: {
samples: [
{timestamp: Date.now() / 1e3, stack_id: 0, thread_id: '0'},
// 10ms later
{timestamp: Date.now() / 1e3 + 0.01, stack_id: 1, thread_id: '0'},
],
frames: [
{function: 'foo', in_app: true},
{function: 'bar', in_app: true},
],
stacks: [
[0, 1],
[0, 1],
],
},
});

const profile = ContinuousProfile.FromProfile(
trace.profile,
createContinuousProfileFrameIndex(trace.profile.frames, 'node'),
{minTimestamp: 0, type: 'flamechart'}
);

expect(Math.round(profile.duration)).toBe(10);
expect(profile.startedAt).toBe(1508208080 * 1e3);
expect(profile.endedAt).toBe(1508208080.01 * 1e3);
});

const profile = ContinuousProfile.FromProfile(
trace.profile,
createContinuousProfileFrameIndex(trace.profile.frames, 'node'),
{minTimestamp: 0, type: 'flamechart'}
);
it('rebuilds the stack', () => {
const trace = makeSentryContinuousProfile({
profile: {
samples: [
{timestamp: Date.now() / 1e3, stack_id: 0, thread_id: '0'},
// 10ms later
{timestamp: Date.now() / 1e3 + 0.01, stack_id: 1, thread_id: '0'},
],
frames: [
{function: 'foo', in_app: true, lineno: 0},
{function: 'bar', in_app: true, lineno: 1},
],
stacks: [
[0, 1],
[0, 1],
],
},
});

const {open, close, timings} = makeTestingBoilerplate();

const profile = ContinuousProfile.FromProfile(
trace.profile,
createContinuousProfileFrameIndex(trace.profile.frames, 'node'),
{minTimestamp: 0, type: 'flamechart'}
);

profile.forEach(open, close);

expect(Math.round(profile.duration)).toBe(10);
expect(profile.startedAt).toBe(1508208080 * 1e3);
expect(profile.endedAt).toBe(1508208080.01 * 1e3);
expect(timings).toEqual([
['bar', 'open'],
['foo', 'open'],
['foo', 'close'],
['bar', 'close'],
]);
});
});

it('rebuilds the stack', () => {
const trace = makeSentryContinuousProfile({
profile: {
samples: [
{timestamp: Date.now() / 1e3, stack_id: 0, thread_id: '0'},
// 10ms later
{timestamp: Date.now() / 1e3 + 0.01, stack_id: 1, thread_id: '0'},
],
frames: [
{function: 'foo', in_app: true, lineno: 0},
{function: 'bar', in_app: true, lineno: 1},
describe('android continuous profile chunk', () => {
it('imports the base properties', () => {
const trace = makeSentryAndroidContinuousProfileChunk({
shared: {
frames: [
{name: 'foo', line: 0},
{name: 'bar', line: 1},
],
},
profiles: [
{
endValue: 100,
events: [
{type: 'O', frame: 0, at: 0},
{type: 'O', frame: 1, at: 1},
{type: 'C', frame: 1, at: 2},
{type: 'C', frame: 0, at: 3},
],
name: 'main',
startValue: 0,
threadID: 1,
type: 'evented',
unit: 'nanoseconds',
},
],
stacks: [
[0, 1],
[0, 1],
],
},
});
});

const {open, close, timings} = makeTestingBoilerplate();
const profile = importAndroidContinuousProfileChunk(trace, '123', {
span: undefined,
type: 'flamechart',
frameFilter: undefined,
profileIds: undefined,
});

const profile = ContinuousProfile.FromProfile(
trace.profile,
createContinuousProfileFrameIndex(trace.profile.frames, 'node'),
{minTimestamp: 0, type: 'flamechart'}
);
expect(profile.profiles[0]!.duration).toBe(3000);
expect(profile.profiles[0]!.startedAt).toBe(0);
expect(profile.profiles[0]!.endedAt).toBe(3000);
});

profile.forEach(open, close);
it('assigns stacks', () => {
const trace = makeSentryAndroidContinuousProfileChunk({
shared: {
frames: [
{name: 'foo', line: 0},
{name: 'bar', line: 1},
],
},
profiles: [
{
endValue: 100,
events: [
{type: 'O', frame: 0, at: 0},
{type: 'O', frame: 1, at: 1},
{type: 'C', frame: 1, at: 2},
{type: 'C', frame: 0, at: 3},
],
name: 'main',
startValue: 0,
threadID: 1,
type: 'evented',
unit: 'nanoseconds',
},
],
});

expect(timings).toEqual([
['bar', 'open'],
['foo', 'open'],
['foo', 'close'],
['bar', 'close'],
]);
const profile = eventedProfileToSampledProfile(trace.profiles);
expect(profile.stacks).toEqual([[0], [0, 1], [0], []]);
});
});
});
Loading

0 comments on commit 0f69da1

Please sign in to comment.