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

Performance optimizations for alignments tracks, particularly those with many short reads #2523

Merged
merged 7 commits into from
Nov 17, 2021
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
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export class LayoutSession implements LayoutSessionProps {
maxHeight: readConfObject(this.config, 'maxHeight'),
displayMode: readConfObject(this.config, 'displayMode'),
pitchX: this.bpPerPx,
spacing: readConfObject(this.config, 'noSpacing') ? 0 : 2,
pitchY: readConfObject(this.config, 'noSpacing') ? 1 : 3,
})
}

Expand Down
8 changes: 5 additions & 3 deletions packages/core/rpc/WebWorkerRpcDriver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,14 @@ export default class WebWorkerRpcDriver extends BaseRpcDriver {
}

makeWorker() {
// note that we are making a Rpc.Client connection with a worker pool of one for each worker,
// because we want to do our own state-group-aware load balancing rather than using librpc's
// builtin round-robin
// note that we are making a Rpc.Client connection with a worker pool of
// one for each worker, because we want to do our own state-group-aware
// load balancing rather than using librpc's builtin round-robin
const worker = new WebWorkerHandle({ workers: [new this.WorkerClass()] })

// send the worker its boot configuration using info from the pluginManager
worker.workers[0].postMessage(this.workerBootConfiguration)

return worker
}
}
3 changes: 3 additions & 0 deletions packages/core/util/layouts/BaseLayout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export interface Rectangle<T> {
r: number
top: number | null
h: number
originalHeight: number
data?: Record<string, T>
}

Expand All @@ -22,6 +23,8 @@ export interface BaseLayout<T> {
data?: Record<string, T>,
): number | null
collides(rect: Rectangle<T>, top: number): boolean
addRectToBitmap(rect: Rectangle<T>, data: Record<string, T>): void
getRectangles(): Map<string, RectTuple>
discardRange(left: number, right: number): void
serializeRegion(region: { start: number; end: number }): SerializedLayout
getTotalHeight(): number
Expand Down
49 changes: 39 additions & 10 deletions packages/core/util/layouts/GranularRectLayout.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import Layout from './GranularRectLayout'

describe('GranularRectLayout', () => {
it('lays out non-overlapping features end to end', () => {
const l = new Layout()
const l = new Layout({ pitchX: 10, pitchY: 4 })
const testRects = [
['1,0', 4133, 5923, 16],
['1,1', 11299, 12389, 16],
Expand Down Expand Up @@ -46,7 +46,7 @@ describe('GranularRectLayout', () => {
})

it('stacks up overlapping features', () => {
const l = new Layout()
const l = new Layout({ pitchX: 10, pitchY: 4 })

const testRects = []
for (let i = 1; i <= 20; i += 1) {
Expand All @@ -55,26 +55,37 @@ describe('GranularRectLayout', () => {

for (let i = 0; i < testRects.length; i += 1) {
const top = l.addRect(...testRects[i])
expect(top).toEqual((i % 2) * 3)
expect(top).toEqual((i % 2) * 4)
}
})

it('discards regions', () => {
const l = new Layout()
const l = new Layout({ pitchX: 10, pitchY: 4 })
for (let i = 0; i < 20; i += 1) {
const top = l.addRect(
`feature-${i}`,
10000 * i + 4000,
10000 * i + 16000,
1,
)
expect(top).toEqual((i % 2) * 3)
expect(top).toEqual((i % 2) * 4)
}

expect(l.bitmap[0].rowState.bits.length).toBe(34812)
expect(l.bitmap[1].rowState.bits.length).toBe(34812)
l.discardRange(190000, 220000)
expect(l.bitmap[0].rowState.bits.length).toBe(24802)
expect(l.bitmap[1].rowState.bits.length).toBe(23802)
l.discardRange(0, 100000)
expect(l.bitmap[0].rowState.bits.length).toBe(19001)
expect(l.bitmap[1].rowState.bits.length).toBe(23802)
l.discardRange(0, 220000)
expect(l.bitmap[0].rowState).toBeUndefined()
})

// see issue #486
it('tests that adding +/- pitchX fixes resolution causing errors', () => {
const l = new Layout()
const l = new Layout({ pitchX: 91.21851599727707, pitchY: 3 })

l.addRect('test', 2581541, 2581542, 1)

Expand All @@ -83,16 +94,34 @@ describe('GranularRectLayout', () => {
).toBeTruthy()
})

it('tests reinitializing layout due to throwing away old one', () => {
const spy = jest.spyOn(console, 'warn').mockImplementation(() => {})
const l = new Layout({
pitchX: 1,
pitchY: 1,
maxHeight: 600,
})

l.addRect('test1', 0, 10000, 1)
l.addRect('test2', 1000000, 1000100, 1)
l.addRect('test3', 0, 10000, 1)
expect(l.rectangles.size).toBe(3)
expect(spy).toHaveBeenCalled()
spy.mockRestore()
})

it('tests adding a gigantic feature that fills entire row with another smaller added on top', () => {
const l = new Layout({
pitchX: 100,
pitchY: 1,
maxHeight: 600,
})

expect(l.getByCoord(50000, 0)).toEqual(undefined)
l.addRect('test1', 0, 10000000, 1)
expect(l.getByCoord(50000, 0)).toEqual('test1')
l.addRect('test2', 0, 1000, 1)
expect(l.getByCoord(500, 2)).toEqual('test2')
l.addRect('test1', 0, 100000000, 1, { id: 'feat1' })
expect(l.getByCoord(50000, 0)).toEqual({ id: 'feat1' })
l.addRect('test2', 0, 1000, 1, { id: 'feat2' })
expect(l.getByCoord(500, 1)).toEqual({ id: 'feat2' })
expect(l.rectangles.size).toBe(2)
})
})
Loading