diff --git a/sample/profiles/pmcstat/simple-with-invalids.txt b/sample/profiles/pmcstat/simple-with-invalids.txt new file mode 100644 index 0000000..835f78f --- /dev/null +++ b/sample/profiles/pmcstat/simple-with-invalids.txt @@ -0,0 +1,38 @@ +@ inst_retired.any [35705 samples] + +# comment ok +// ignored + +20.86% [7447] zfs_lz4_compress @ /boot/kernel/zfs.ko + 100.0% [7447] zio_compress_data + 100.0% [7447] zio_write_compress + 100.0% [7447] zio_execute + 100.0% [7447] taskqueue_run_locked @ /boot/kernel/kernel + 100.0% [7447] taskqueue_thread_loop + 100.0% [7447] fork_exit + +14.44% [5156] fletcher_2_native @ /boot/kernel/zfs.ko + 50.62% [2610] arc_cksum_verify + 66.02% [1723] arc_buf_thaw + 86.48% [1490] dmu_buf_will_dirty_impl + 99.93% [1489] dmu_write_uio_dnode + 100.0% [1489] zfs_write + 100.0% [1489] zfs_freebsd_write + 100.0% [1489] VOP_WRITE_APV @ /boot/kernel/kernel + 100.0% [1489] vn_write + 100.0% [1489] vn_io_fault_doio + 100.0% [1489] vn_io_fault1 + 100.0% [1489] vn_io_fault + 100.0% [1489] dofilewrite + 100.0% [1489] kern_pwritev + 100.0% [1489] sys_pwrite + 100.0% [1489] amd64_syscall + 00.07% [1] dmu_write_impl @ /boot/kernel/zfs.ko + 100.0% [1] dmu_write + 100.0% [1] metaslab_set_unflushed_txg + 100.0% [1] metaslab_unflushed_bump + 100.0% [1] spa_flush_metaslabs + 100.0% [1] spa_sync + 100.0% [1] txg_sync_thread + 100.0% [1] fork_exit @ /boot/kernel/kernel +invalid line diff --git a/sample/profiles/pmcstat/simple.txt b/sample/profiles/pmcstat/simple.txt new file mode 100644 index 0000000..32fe4cb --- /dev/null +++ b/sample/profiles/pmcstat/simple.txt @@ -0,0 +1,34 @@ +@ inst_retired.any [35705 samples] + +20.86% [7447] zfs_lz4_compress @ /boot/kernel/zfs.ko + 100.0% [7447] zio_compress_data + 100.0% [7447] zio_write_compress + 100.0% [7447] zio_execute + 100.0% [7447] taskqueue_run_locked @ /boot/kernel/kernel + 100.0% [7447] taskqueue_thread_loop + 100.0% [7447] fork_exit + +14.44% [5156] fletcher_2_native @ /boot/kernel/zfs.ko + 50.62% [2610] arc_cksum_verify + 66.02% [1723] arc_buf_thaw + 86.48% [1490] dmu_buf_will_dirty_impl + 99.93% [1489] dmu_write_uio_dnode + 100.0% [1489] zfs_write + 100.0% [1489] zfs_freebsd_write + 100.0% [1489] VOP_WRITE_APV @ /boot/kernel/kernel + 100.0% [1489] vn_write + 100.0% [1489] vn_io_fault_doio + 100.0% [1489] vn_io_fault1 + 100.0% [1489] vn_io_fault + 100.0% [1489] dofilewrite + 100.0% [1489] kern_pwritev + 100.0% [1489] sys_pwrite + 100.0% [1489] amd64_syscall + 00.07% [1] dmu_write_impl @ /boot/kernel/zfs.ko + 100.0% [1] dmu_write + 100.0% [1] metaslab_set_unflushed_txg + 100.0% [1] metaslab_unflushed_bump + 100.0% [1] spa_flush_metaslabs + 100.0% [1] spa_sync + 100.0% [1] txg_sync_thread + 100.0% [1] fork_exit @ /boot/kernel/kernel diff --git a/scripts/test-setup.sh b/scripts/test-setup.sh index 6b11a56..00edd24 100755 --- a/scripts/test-setup.sh +++ b/scripts/test-setup.sh @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/sh set -e for f in `find sample/profiles -name '*.zip' | grep -v Instruments`; do diff --git a/src/import/__snapshots__/pmcstat-callgraph.test.ts.snap b/src/import/__snapshots__/pmcstat-callgraph.test.ts.snap new file mode 100644 index 0000000..65a340a --- /dev/null +++ b/src/import/__snapshots__/pmcstat-callgraph.test.ts.snap @@ -0,0 +1,575 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`importFromPMCStatCallGraph 1`] = ` +Object { + "frames": Array [ + Frame { + "col": undefined, + "file": "/boot/kernel/kernel", + "key": "fork_exit", + "line": undefined, + "name": "fork_exit", + "selfWeight": 0, + "totalWeight": 7448, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/kernel", + "key": "taskqueue_thread_loop", + "line": undefined, + "name": "taskqueue_thread_loop", + "selfWeight": 0, + "totalWeight": 7447, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/kernel", + "key": "taskqueue_run_locked", + "line": undefined, + "name": "taskqueue_run_locked", + "selfWeight": 0, + "totalWeight": 7447, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/zfs.ko", + "key": "zio_execute", + "line": undefined, + "name": "zio_execute", + "selfWeight": 0, + "totalWeight": 7447, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/zfs.ko", + "key": "zio_write_compress", + "line": undefined, + "name": "zio_write_compress", + "selfWeight": 0, + "totalWeight": 7447, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/zfs.ko", + "key": "zio_compress_data", + "line": undefined, + "name": "zio_compress_data", + "selfWeight": 0, + "totalWeight": 7447, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/zfs.ko", + "key": "zfs_lz4_compress", + "line": undefined, + "name": "zfs_lz4_compress", + "selfWeight": 7447, + "totalWeight": 7447, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/kernel", + "key": "amd64_syscall", + "line": undefined, + "name": "amd64_syscall", + "selfWeight": 0, + "totalWeight": 1489, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/kernel", + "key": "sys_pwrite", + "line": undefined, + "name": "sys_pwrite", + "selfWeight": 0, + "totalWeight": 1489, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/kernel", + "key": "kern_pwritev", + "line": undefined, + "name": "kern_pwritev", + "selfWeight": 0, + "totalWeight": 1489, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/kernel", + "key": "dofilewrite", + "line": undefined, + "name": "dofilewrite", + "selfWeight": 0, + "totalWeight": 1489, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/kernel", + "key": "vn_io_fault", + "line": undefined, + "name": "vn_io_fault", + "selfWeight": 0, + "totalWeight": 1489, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/kernel", + "key": "vn_io_fault1", + "line": undefined, + "name": "vn_io_fault1", + "selfWeight": 0, + "totalWeight": 1489, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/kernel", + "key": "vn_io_fault_doio", + "line": undefined, + "name": "vn_io_fault_doio", + "selfWeight": 0, + "totalWeight": 1489, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/kernel", + "key": "vn_write", + "line": undefined, + "name": "vn_write", + "selfWeight": 0, + "totalWeight": 1489, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/kernel", + "key": "VOP_WRITE_APV", + "line": undefined, + "name": "VOP_WRITE_APV", + "selfWeight": 0, + "totalWeight": 1489, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/zfs.ko", + "key": "zfs_freebsd_write", + "line": undefined, + "name": "zfs_freebsd_write", + "selfWeight": 0, + "totalWeight": 1489, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/zfs.ko", + "key": "zfs_write", + "line": undefined, + "name": "zfs_write", + "selfWeight": 0, + "totalWeight": 1489, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/zfs.ko", + "key": "dmu_write_uio_dnode", + "line": undefined, + "name": "dmu_write_uio_dnode", + "selfWeight": 0, + "totalWeight": 1489, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/zfs.ko", + "key": "dmu_buf_will_dirty_impl", + "line": undefined, + "name": "dmu_buf_will_dirty_impl", + "selfWeight": 0, + "totalWeight": 1490, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/zfs.ko", + "key": "arc_buf_thaw", + "line": undefined, + "name": "arc_buf_thaw", + "selfWeight": 0, + "totalWeight": 1490, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/zfs.ko", + "key": "arc_cksum_verify", + "line": undefined, + "name": "arc_cksum_verify", + "selfWeight": 0, + "totalWeight": 1490, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/zfs.ko", + "key": "fletcher_2_native", + "line": undefined, + "name": "fletcher_2_native", + "selfWeight": 1490, + "totalWeight": 1490, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/zfs.ko", + "key": "txg_sync_thread", + "line": undefined, + "name": "txg_sync_thread", + "selfWeight": 0, + "totalWeight": 1, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/zfs.ko", + "key": "spa_sync", + "line": undefined, + "name": "spa_sync", + "selfWeight": 0, + "totalWeight": 1, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/zfs.ko", + "key": "spa_flush_metaslabs", + "line": undefined, + "name": "spa_flush_metaslabs", + "selfWeight": 0, + "totalWeight": 1, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/zfs.ko", + "key": "metaslab_unflushed_bump", + "line": undefined, + "name": "metaslab_unflushed_bump", + "selfWeight": 0, + "totalWeight": 1, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/zfs.ko", + "key": "metaslab_set_unflushed_txg", + "line": undefined, + "name": "metaslab_set_unflushed_txg", + "selfWeight": 0, + "totalWeight": 1, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/zfs.ko", + "key": "dmu_write", + "line": undefined, + "name": "dmu_write", + "selfWeight": 0, + "totalWeight": 1, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/zfs.ko", + "key": "dmu_write_impl", + "line": undefined, + "name": "dmu_write_impl", + "selfWeight": 0, + "totalWeight": 1, + }, + ], + "name": "simple.txt", + "stacks": Array [ + "fork_exit;taskqueue_thread_loop;taskqueue_run_locked;zio_execute;zio_write_compress;zio_compress_data;zfs_lz4_compress 7,447", + "amd64_syscall;sys_pwrite;kern_pwritev;dofilewrite;vn_io_fault;vn_io_fault1;vn_io_fault_doio;vn_write;VOP_WRITE_APV;zfs_freebsd_write;zfs_write;dmu_write_uio_dnode;dmu_buf_will_dirty_impl;arc_buf_thaw;arc_cksum_verify;fletcher_2_native 1,489", + "fork_exit;txg_sync_thread;spa_sync;spa_flush_metaslabs;metaslab_unflushed_bump;metaslab_set_unflushed_txg;dmu_write;dmu_write_impl;dmu_buf_will_dirty_impl;arc_buf_thaw;arc_cksum_verify;fletcher_2_native 1", + ], +} +`; + +exports[`importFromPMCStatCallGraph with invalid lines 1`] = ` +Object { + "frames": Array [ + Frame { + "col": undefined, + "file": "/boot/kernel/kernel", + "key": "fork_exit", + "line": undefined, + "name": "fork_exit", + "selfWeight": 0, + "totalWeight": 7448, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/kernel", + "key": "taskqueue_thread_loop", + "line": undefined, + "name": "taskqueue_thread_loop", + "selfWeight": 0, + "totalWeight": 7447, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/kernel", + "key": "taskqueue_run_locked", + "line": undefined, + "name": "taskqueue_run_locked", + "selfWeight": 0, + "totalWeight": 7447, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/zfs.ko", + "key": "zio_execute", + "line": undefined, + "name": "zio_execute", + "selfWeight": 0, + "totalWeight": 7447, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/zfs.ko", + "key": "zio_write_compress", + "line": undefined, + "name": "zio_write_compress", + "selfWeight": 0, + "totalWeight": 7447, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/zfs.ko", + "key": "zio_compress_data", + "line": undefined, + "name": "zio_compress_data", + "selfWeight": 0, + "totalWeight": 7447, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/zfs.ko", + "key": "zfs_lz4_compress", + "line": undefined, + "name": "zfs_lz4_compress", + "selfWeight": 7447, + "totalWeight": 7447, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/kernel", + "key": "amd64_syscall", + "line": undefined, + "name": "amd64_syscall", + "selfWeight": 0, + "totalWeight": 1489, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/kernel", + "key": "sys_pwrite", + "line": undefined, + "name": "sys_pwrite", + "selfWeight": 0, + "totalWeight": 1489, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/kernel", + "key": "kern_pwritev", + "line": undefined, + "name": "kern_pwritev", + "selfWeight": 0, + "totalWeight": 1489, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/kernel", + "key": "dofilewrite", + "line": undefined, + "name": "dofilewrite", + "selfWeight": 0, + "totalWeight": 1489, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/kernel", + "key": "vn_io_fault", + "line": undefined, + "name": "vn_io_fault", + "selfWeight": 0, + "totalWeight": 1489, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/kernel", + "key": "vn_io_fault1", + "line": undefined, + "name": "vn_io_fault1", + "selfWeight": 0, + "totalWeight": 1489, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/kernel", + "key": "vn_io_fault_doio", + "line": undefined, + "name": "vn_io_fault_doio", + "selfWeight": 0, + "totalWeight": 1489, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/kernel", + "key": "vn_write", + "line": undefined, + "name": "vn_write", + "selfWeight": 0, + "totalWeight": 1489, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/kernel", + "key": "VOP_WRITE_APV", + "line": undefined, + "name": "VOP_WRITE_APV", + "selfWeight": 0, + "totalWeight": 1489, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/zfs.ko", + "key": "zfs_freebsd_write", + "line": undefined, + "name": "zfs_freebsd_write", + "selfWeight": 0, + "totalWeight": 1489, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/zfs.ko", + "key": "zfs_write", + "line": undefined, + "name": "zfs_write", + "selfWeight": 0, + "totalWeight": 1489, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/zfs.ko", + "key": "dmu_write_uio_dnode", + "line": undefined, + "name": "dmu_write_uio_dnode", + "selfWeight": 0, + "totalWeight": 1489, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/zfs.ko", + "key": "dmu_buf_will_dirty_impl", + "line": undefined, + "name": "dmu_buf_will_dirty_impl", + "selfWeight": 0, + "totalWeight": 1490, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/zfs.ko", + "key": "arc_buf_thaw", + "line": undefined, + "name": "arc_buf_thaw", + "selfWeight": 0, + "totalWeight": 1490, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/zfs.ko", + "key": "arc_cksum_verify", + "line": undefined, + "name": "arc_cksum_verify", + "selfWeight": 0, + "totalWeight": 1490, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/zfs.ko", + "key": "fletcher_2_native", + "line": undefined, + "name": "fletcher_2_native", + "selfWeight": 1490, + "totalWeight": 1490, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/zfs.ko", + "key": "txg_sync_thread", + "line": undefined, + "name": "txg_sync_thread", + "selfWeight": 0, + "totalWeight": 1, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/zfs.ko", + "key": "spa_sync", + "line": undefined, + "name": "spa_sync", + "selfWeight": 0, + "totalWeight": 1, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/zfs.ko", + "key": "spa_flush_metaslabs", + "line": undefined, + "name": "spa_flush_metaslabs", + "selfWeight": 0, + "totalWeight": 1, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/zfs.ko", + "key": "metaslab_unflushed_bump", + "line": undefined, + "name": "metaslab_unflushed_bump", + "selfWeight": 0, + "totalWeight": 1, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/zfs.ko", + "key": "metaslab_set_unflushed_txg", + "line": undefined, + "name": "metaslab_set_unflushed_txg", + "selfWeight": 0, + "totalWeight": 1, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/zfs.ko", + "key": "dmu_write", + "line": undefined, + "name": "dmu_write", + "selfWeight": 0, + "totalWeight": 1, + }, + Frame { + "col": undefined, + "file": "/boot/kernel/zfs.ko", + "key": "dmu_write_impl", + "line": undefined, + "name": "dmu_write_impl", + "selfWeight": 0, + "totalWeight": 1, + }, + ], + "name": "simple-with-invalids.txt", + "stacks": Array [ + "fork_exit;taskqueue_thread_loop;taskqueue_run_locked;zio_execute;zio_write_compress;zio_compress_data;zfs_lz4_compress 7,447", + "amd64_syscall;sys_pwrite;kern_pwritev;dofilewrite;vn_io_fault;vn_io_fault1;vn_io_fault_doio;vn_write;VOP_WRITE_APV;zfs_freebsd_write;zfs_write;dmu_write_uio_dnode;dmu_buf_will_dirty_impl;arc_buf_thaw;arc_cksum_verify;fletcher_2_native 1,489", + "fork_exit;txg_sync_thread;spa_sync;spa_flush_metaslabs;metaslab_unflushed_bump;metaslab_set_unflushed_txg;dmu_write;dmu_write_impl;dmu_buf_will_dirty_impl;arc_buf_thaw;arc_cksum_verify;fletcher_2_native 1", + ], +} +`; + +exports[`importFromPMCStatCallGraph with invalid lines: indexToView 1`] = `0`; + +exports[`importFromPMCStatCallGraph with invalid lines: profileGroup.name 1`] = `"simple-with-invalids.txt"`; + +exports[`importFromPMCStatCallGraph: indexToView 1`] = `0`; + +exports[`importFromPMCStatCallGraph: profileGroup.name 1`] = `"simple.txt"`; diff --git a/src/import/index.ts b/src/import/index.ts index 47ff7f9..f66a6ca 100644 --- a/src/import/index.ts +++ b/src/import/index.ts @@ -23,6 +23,7 @@ import {importFromChromeHeapProfile} from './v8heapalloc' import {isTraceEventFormatted, importTraceEvents} from './trace-event' import {importFromCallgrind} from './callgrind' import {importFromPapyrus} from './papyrus' +import {importFromPMCStatCallGraph} from './pmcstat-callgraph' export async function importProfileGroupFromText( fileName: string, @@ -123,6 +124,9 @@ async function _importProfileGroup(dataSource: ProfileDataSource): Promise { + await checkProfileSnapshot('./sample/profiles/pmcstat/simple.txt') +}) + +test('importFromPMCStatCallGraph with invalid lines', async () => { + await checkProfileSnapshot('./sample/profiles/pmcstat/simple-with-invalids.txt') +}) diff --git a/src/import/pmcstat-callgraph.ts b/src/import/pmcstat-callgraph.ts new file mode 100644 index 0000000..a30eb2e --- /dev/null +++ b/src/import/pmcstat-callgraph.ts @@ -0,0 +1,30 @@ +import {Profile, FrameInfo, StackListProfileBuilder} from '../lib/profile' +import {TextFileContent} from './utils' + +export function importFromPMCStatCallGraph(contents: TextFileContent): Profile | null { + const profile = new StackListProfileBuilder() + const stack: FrameInfo[] = [] + let file: string | undefined + let prevDuration = '0' + let prevIndent = -1 + for (const line of contents.splitLines()) { + const match = /^( *)[\d.]+% \[(\d+)\]\s*(\S+)(?: @ (.*))?$/gm.exec(line) + if (!match) continue + const indent = match[1].length + if (indent <= prevIndent) { + const frames = stack.slice(0, prevIndent + 1).reverse() + const duration = parseInt(prevDuration, 10) + profile.appendSampleWithWeight(frames, duration) + } + const name = match[3] + file = match[4] || file + stack[indent] = {key: name, name: name, file: file} + prevDuration = match[2] + prevIndent = indent + } + if (prevIndent == -1) return null + const frames = stack.slice(0, prevIndent + 1).reverse() + const duration = parseInt(prevDuration, 10) + profile.appendSampleWithWeight(frames, duration) + return profile.build() +}