From 5cc74905a5368fa4d75c1691b87423908d223a82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=A9o=20Boury?= Date: Mon, 3 Jun 2024 10:51:40 +0200 Subject: [PATCH 01/29] Add node interface --- src/TreeParser-Tests/TreeParserTest.class.st | 317 +++++++++++++++++-- src/TreeParser/TreeChildren.class.st | 73 ++++- src/TreeParser/TreeNode.class.st | 66 ++++ src/TreeParser/TreeNodes.class.st | 86 +++-- src/TreeParser/TreeParse.class.st | 34 -- src/TreeParser/TreeParser.class.st | 51 +++ src/TreeParser/TreeTrace.class.st | 33 ++ 7 files changed, 578 insertions(+), 82 deletions(-) create mode 100644 src/TreeParser/TreeNode.class.st delete mode 100644 src/TreeParser/TreeParse.class.st create mode 100644 src/TreeParser/TreeParser.class.st create mode 100644 src/TreeParser/TreeTrace.class.st diff --git a/src/TreeParser-Tests/TreeParserTest.class.st b/src/TreeParser-Tests/TreeParserTest.class.st index ad2c4ad..995459a 100644 --- a/src/TreeParser-Tests/TreeParserTest.class.st +++ b/src/TreeParser-Tests/TreeParserTest.class.st @@ -18,10 +18,61 @@ Class { { #category : #running } TreeParserTest >> setUp [ + "Commands ran:" + "sudo perf record -g --call-graph=dwarf -- ./script2.sh --all-user" + "sudo perf report --header --stdio > perf_example.txt" super setUp. memoryFS := FileSystem memory. - memoryFS / ('perf_stock_simple.txt') writeStreamDo: [:stream | stream nextPutAll: '# To display the perf.data header info, please use --header/--header-only options. + memoryFS / ('perf_stock_simple.txt') writeStreamDo: [:stream | stream nextPutAll: '# ======== +# captured on : Wed May 29 09:28:58 2024 +# header version : 1 +# data offset : 352 +# data size : 16366888 +# feat offset : 16367240 +# hostname : matburnx-laptop +# os release : 6.8.0-76060800daily20240311-generic +# perf version : 6.8.0 +# arch : x86_64 +# nrcpus online : 12 +# nrcpus avail : 12 +# cpudesc : AMD Ryzen 5 4600H with Radeon Graphics +# cpuid : AuthenticAMD,23,96,1 +# total memory : 15776888 kB +# cmdline : /usr/lib/linux-tools-6.8.0-76060800daily20240311/perf record -g --call-graph=dwarf -- ./script2.sh --all-user +# event : name = cycles:P, , id = { 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287 }, type = 0 (PERF_TYPE_HARDWARE), size = 136, config = 0 (PERF_COUNT_HW_CPU_CYCLES), { sample_period, sample_freq } = 4000, sample_type = IP|TID|TIME|ADDR|CALLCHAIN|PERIOD|REGS_USER|STACK_USER|DATA_SRC, read_format = ID|LOST, disabled = 1, inherit = 1, mmap = 1, comm = 1, freq = 1, enable_on_exec = 1, task = 1, precise_ip = 2, mmap_data = 1, sample_id_all = 1, exclude_callchain_user = 1, mmap2 = 1, comm_exec = 1, ksymbol = 1, bpf_event = 1, sample_regs_user = 0xff0fff, sample_stack_user = 8192 +# CPU_TOPOLOGY info available, use -I to display +# NUMA_TOPOLOGY info available, use -I to display +# pmu mappings: cpu = 4, amd_iommu_0 = 12, breakpoint = 5, ibs_fetch = 10, ibs_op = 11, kprobe = 8, msr = 13, power = 14, software = 1, tracepoint = 2, uprobe = 9 +# CACHE info available, use -I to display +# time of first sample : 924.754662 +# time of last sample : 925.152255 +# sample duration : 397.592 ms +# MEM_TOPOLOGY info available, use -I to display +# bpf_prog_info 2: bpf_prog_7cc47bbf07148bfe_hid_tail_call addr 0xffffffffc0314954 size 110 +# bpf_prog_info 5: bpf_prog_e3dbd137be8d6168 addr 0xffffffffc0314b30 size 313 +# bpf_prog_info 6: bpf_prog_6deef7357e7b4530 addr 0xffffffffc0314c9c size 58 +# bpf_prog_info 7: bpf_prog_6deef7357e7b4530 addr 0xffffffffc0314d2c size 58 +# bpf_prog_info 8: bpf_prog_0ecd07b7b633809f addr 0xffffffffc0316e30 size 777 +# bpf_prog_info 9: bpf_prog_6deef7357e7b4530 addr 0xffffffffc0317158 size 95 +# bpf_prog_info 10: bpf_prog_6deef7357e7b4530 addr 0xffffffffc03171d8 size 95 +# bpf_prog_info 11: bpf_prog_ee0e253c78993a24 addr 0xffffffffc031eb10 size 675 +# bpf_prog_info 12: bpf_prog_ee0e253c78993a24 addr 0xffffffffc031f018 size 671 +# bpf_prog_info 13: bpf_prog_8b9c33f36f812014 addr 0xffffffffc03214a4 size 1109 +# bpf_prog_info 14: bpf_prog_6deef7357e7b4530 addr 0xffffffffc0321914 size 95 +# bpf_prog_info 15: bpf_prog_6deef7357e7b4530 addr 0xffffffffc0321994 size 94 +# bpf_prog_info 19: bpf_prog_6deef7357e7b4530 addr 0xffffffffc0328bdc size 94 +# bpf_prog_info 20: bpf_prog_6deef7357e7b4530 addr 0xffffffffc0328c48 size 95 +# bpf_prog_info 21: bpf_prog_28a890580b33b0dc addr 0xffffffffc032b50c size 872 +# bpf_prog_info 22: bpf_prog_ee0e253c78993a24 addr 0xffffffffc032d4d0 size 673 +# bpf_prog_info 29: bpf_prog_6be0d743674e5faa_syscall__execve addr 0xffffffffc034c570 size 5360 +# bpf_prog_info 30: bpf_prog_a43530058ef998f5_do_ret_sys_execve addr 0xffffffffc034daa0 size 589 +# btf info of id 5 +# btf info of id 176 +# cpu pmu capabilities: max_precise=0 +# AMD systems uses ibs_op// PMU for some precise events, e.g.: cycles:p, see the ''perf list'' man page for further details. +# missing features: (null) BRANCH_STACK GROUP_DESC AUXTRACE STAT CLOCKID DIR_FORMAT COMPRESSED CLOCK_DATA HYBRID_TOPOLOGY +# ======== # # # Total Lost Samples: 0 @@ -41,7 +92,55 @@ TreeParserTest >> setUp [ |--36.78%--__x64_sys_read ']. - memoryFS / ('perf_stock_same_percentage.txt') writeStreamDo: [:stream | stream nextPutAll: '# To display the perf.data header info, please use --header/--header-only options. + memoryFS / ('perf_stock_same_percentage.txt') writeStreamDo: [:stream | stream nextPutAll: '# ======== +# captured on : Wed May 29 09:28:58 2024 +# header version : 1 +# data offset : 352 +# data size : 16366888 +# feat offset : 16367240 +# hostname : matburnx-laptop +# os release : 6.8.0-76060800daily20240311-generic +# perf version : 6.8.0 +# arch : x86_64 +# nrcpus online : 12 +# nrcpus avail : 12 +# cpudesc : AMD Ryzen 5 4600H with Radeon Graphics +# cpuid : AuthenticAMD,23,96,1 +# total memory : 15776888 kB +# cmdline : /usr/lib/linux-tools-6.8.0-76060800daily20240311/perf record -g --call-graph=dwarf -- ./script2.sh --all-user +# event : name = cycles:P, , id = { 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287 }, type = 0 (PERF_TYPE_HARDWARE), size = 136, config = 0 (PERF_COUNT_HW_CPU_CYCLES), { sample_period, sample_freq } = 4000, sample_type = IP|TID|TIME|ADDR|CALLCHAIN|PERIOD|REGS_USER|STACK_USER|DATA_SRC, read_format = ID|LOST, disabled = 1, inherit = 1, mmap = 1, comm = 1, freq = 1, enable_on_exec = 1, task = 1, precise_ip = 2, mmap_data = 1, sample_id_all = 1, exclude_callchain_user = 1, mmap2 = 1, comm_exec = 1, ksymbol = 1, bpf_event = 1, sample_regs_user = 0xff0fff, sample_stack_user = 8192 +# CPU_TOPOLOGY info available, use -I to display +# NUMA_TOPOLOGY info available, use -I to display +# pmu mappings: cpu = 4, amd_iommu_0 = 12, breakpoint = 5, ibs_fetch = 10, ibs_op = 11, kprobe = 8, msr = 13, power = 14, software = 1, tracepoint = 2, uprobe = 9 +# CACHE info available, use -I to display +# time of first sample : 924.754662 +# time of last sample : 925.152255 +# sample duration : 397.592 ms +# MEM_TOPOLOGY info available, use -I to display +# bpf_prog_info 2: bpf_prog_7cc47bbf07148bfe_hid_tail_call addr 0xffffffffc0314954 size 110 +# bpf_prog_info 5: bpf_prog_e3dbd137be8d6168 addr 0xffffffffc0314b30 size 313 +# bpf_prog_info 6: bpf_prog_6deef7357e7b4530 addr 0xffffffffc0314c9c size 58 +# bpf_prog_info 7: bpf_prog_6deef7357e7b4530 addr 0xffffffffc0314d2c size 58 +# bpf_prog_info 8: bpf_prog_0ecd07b7b633809f addr 0xffffffffc0316e30 size 777 +# bpf_prog_info 9: bpf_prog_6deef7357e7b4530 addr 0xffffffffc0317158 size 95 +# bpf_prog_info 10: bpf_prog_6deef7357e7b4530 addr 0xffffffffc03171d8 size 95 +# bpf_prog_info 11: bpf_prog_ee0e253c78993a24 addr 0xffffffffc031eb10 size 675 +# bpf_prog_info 12: bpf_prog_ee0e253c78993a24 addr 0xffffffffc031f018 size 671 +# bpf_prog_info 13: bpf_prog_8b9c33f36f812014 addr 0xffffffffc03214a4 size 1109 +# bpf_prog_info 14: bpf_prog_6deef7357e7b4530 addr 0xffffffffc0321914 size 95 +# bpf_prog_info 15: bpf_prog_6deef7357e7b4530 addr 0xffffffffc0321994 size 94 +# bpf_prog_info 19: bpf_prog_6deef7357e7b4530 addr 0xffffffffc0328bdc size 94 +# bpf_prog_info 20: bpf_prog_6deef7357e7b4530 addr 0xffffffffc0328c48 size 95 +# bpf_prog_info 21: bpf_prog_28a890580b33b0dc addr 0xffffffffc032b50c size 872 +# bpf_prog_info 22: bpf_prog_ee0e253c78993a24 addr 0xffffffffc032d4d0 size 673 +# bpf_prog_info 29: bpf_prog_6be0d743674e5faa_syscall__execve addr 0xffffffffc034c570 size 5360 +# bpf_prog_info 30: bpf_prog_a43530058ef998f5_do_ret_sys_execve addr 0xffffffffc034daa0 size 589 +# btf info of id 5 +# btf info of id 176 +# cpu pmu capabilities: max_precise=0 +# AMD systems uses ibs_op// PMU for some precise events, e.g.: cycles:p, see the ''perf list'' man page for further details. +# missing features: (null) BRANCH_STACK GROUP_DESC AUXTRACE STAT CLOCKID DIR_FORMAT COMPRESSED CLOCK_DATA HYBRID_TOPOLOGY +# ======== # # # Total Lost Samples: 0 @@ -66,7 +165,55 @@ TreeParserTest >> setUp [ | | ']. - memoryFS / ('perf_stock_multiple_children.txt') writeStreamDo: [:stream | stream nextPutAll: '# To display the perf.data header info, please use --header/--header-only options. + memoryFS / ('perf_stock_multiple_children.txt') writeStreamDo: [:stream | stream nextPutAll: '# ======== +# captured on : Wed May 29 09:28:58 2024 +# header version : 1 +# data offset : 352 +# data size : 16366888 +# feat offset : 16367240 +# hostname : matburnx-laptop +# os release : 6.8.0-76060800daily20240311-generic +# perf version : 6.8.0 +# arch : x86_64 +# nrcpus online : 12 +# nrcpus avail : 12 +# cpudesc : AMD Ryzen 5 4600H with Radeon Graphics +# cpuid : AuthenticAMD,23,96,1 +# total memory : 15776888 kB +# cmdline : /usr/lib/linux-tools-6.8.0-76060800daily20240311/perf record -g --call-graph=dwarf -- ./script2.sh --all-user +# event : name = cycles:P, , id = { 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287 }, type = 0 (PERF_TYPE_HARDWARE), size = 136, config = 0 (PERF_COUNT_HW_CPU_CYCLES), { sample_period, sample_freq } = 4000, sample_type = IP|TID|TIME|ADDR|CALLCHAIN|PERIOD|REGS_USER|STACK_USER|DATA_SRC, read_format = ID|LOST, disabled = 1, inherit = 1, mmap = 1, comm = 1, freq = 1, enable_on_exec = 1, task = 1, precise_ip = 2, mmap_data = 1, sample_id_all = 1, exclude_callchain_user = 1, mmap2 = 1, comm_exec = 1, ksymbol = 1, bpf_event = 1, sample_regs_user = 0xff0fff, sample_stack_user = 8192 +# CPU_TOPOLOGY info available, use -I to display +# NUMA_TOPOLOGY info available, use -I to display +# pmu mappings: cpu = 4, amd_iommu_0 = 12, breakpoint = 5, ibs_fetch = 10, ibs_op = 11, kprobe = 8, msr = 13, power = 14, software = 1, tracepoint = 2, uprobe = 9 +# CACHE info available, use -I to display +# time of first sample : 924.754662 +# time of last sample : 925.152255 +# sample duration : 397.592 ms +# MEM_TOPOLOGY info available, use -I to display +# bpf_prog_info 2: bpf_prog_7cc47bbf07148bfe_hid_tail_call addr 0xffffffffc0314954 size 110 +# bpf_prog_info 5: bpf_prog_e3dbd137be8d6168 addr 0xffffffffc0314b30 size 313 +# bpf_prog_info 6: bpf_prog_6deef7357e7b4530 addr 0xffffffffc0314c9c size 58 +# bpf_prog_info 7: bpf_prog_6deef7357e7b4530 addr 0xffffffffc0314d2c size 58 +# bpf_prog_info 8: bpf_prog_0ecd07b7b633809f addr 0xffffffffc0316e30 size 777 +# bpf_prog_info 9: bpf_prog_6deef7357e7b4530 addr 0xffffffffc0317158 size 95 +# bpf_prog_info 10: bpf_prog_6deef7357e7b4530 addr 0xffffffffc03171d8 size 95 +# bpf_prog_info 11: bpf_prog_ee0e253c78993a24 addr 0xffffffffc031eb10 size 675 +# bpf_prog_info 12: bpf_prog_ee0e253c78993a24 addr 0xffffffffc031f018 size 671 +# bpf_prog_info 13: bpf_prog_8b9c33f36f812014 addr 0xffffffffc03214a4 size 1109 +# bpf_prog_info 14: bpf_prog_6deef7357e7b4530 addr 0xffffffffc0321914 size 95 +# bpf_prog_info 15: bpf_prog_6deef7357e7b4530 addr 0xffffffffc0321994 size 94 +# bpf_prog_info 19: bpf_prog_6deef7357e7b4530 addr 0xffffffffc0328bdc size 94 +# bpf_prog_info 20: bpf_prog_6deef7357e7b4530 addr 0xffffffffc0328c48 size 95 +# bpf_prog_info 21: bpf_prog_28a890580b33b0dc addr 0xffffffffc032b50c size 872 +# bpf_prog_info 22: bpf_prog_ee0e253c78993a24 addr 0xffffffffc032d4d0 size 673 +# bpf_prog_info 29: bpf_prog_6be0d743674e5faa_syscall__execve addr 0xffffffffc034c570 size 5360 +# bpf_prog_info 30: bpf_prog_a43530058ef998f5_do_ret_sys_execve addr 0xffffffffc034daa0 size 589 +# btf info of id 5 +# btf info of id 176 +# cpu pmu capabilities: max_precise=0 +# AMD systems uses ibs_op// PMU for some precise events, e.g.: cycles:p, see the ''perf list'' man page for further details. +# missing features: (null) BRANCH_STACK GROUP_DESC AUXTRACE STAT CLOCKID DIR_FORMAT COMPRESSED CLOCK_DATA HYBRID_TOPOLOGY +# ======== # # # Total Lost Samples: 0 @@ -97,16 +244,16 @@ TreeParserTest >> setUp [ ']. fileSimple := memoryFS / ('perf_stock_simple.txt'). - treeSimple := TreeParse fromFile: fileSimple. - testNodeSimple := treeSimple asNodes. + treeSimple := TreeParser fromFile: fileSimple. + testNodeSimple := TreeNodes fromContent: treeSimple. fileSamePercentage := memoryFS / ('perf_stock_same_percentage.txt'). - treeSamePercentage := TreeParse fromFile: fileSamePercentage. - testNodeSamePercentage := treeSamePercentage asNodes. + treeSamePercentage := TreeParser fromFile: fileSamePercentage. + testNodeSamePercentage := TreeNodes fromContent: treeSamePercentage. fileMultipleChildren := memoryFS / ('perf_stock_multiple_children.txt'). - treeMultipleChildren := TreeParse fromFile: fileMultipleChildren. - testNodeMultipleChildren := treeMultipleChildren asNodes. + treeMultipleChildren := TreeParser fromFile: fileMultipleChildren. + testNodeMultipleChildren := TreeNodes fromContent: treeMultipleChildren. ] @@ -126,14 +273,23 @@ TreeParserTest >> testClassify [ family := testNodeMultipleChildren classify. example := (family firstChildrenOf: 2) children. - self assert: example size equals: 3. - self assert: example first name equals: '__x64_sys_read'. self assert: example second name equals: 'syscall_exit_to_user_mode'. self assert: example third name equals: '__x64_sys_openat'. +] + +{ #category : #tests } +TreeParserTest >> testClassifySameParent [ + + | family example | + family := testNodeMultipleChildren classify. + example := (family firstChildrenOf: 2) children. + + self assert: family children first children first equals: example first parent. + self assert: example first parent equals: example second parent ] @@ -150,29 +306,110 @@ TreeParserTest >> testEstimatePercentage [ ] { #category : #tests } -TreeParserTest >> testFindChildrenOf [ - +TreeParserTest >> testFindChildrenIndexOf [ + "Two cases that shouldn't happen." self assert: - (testNodeMultipleChildren findChildrenOf: 3) first equals: 4. - + (testNodeMultipleChildren findChildrenIndexOfIndex: 0) isNil. + self assert: - (testNodeMultipleChildren findChildrenOf: 3) second equals: 5. - + (testNodeMultipleChildren findChildrenIndexOfIndex: 10) isNil. + + "Case where 2 functions have the same number of spaces." + self assert: + (testNodeSimple findChildrenIndexOfIndex: 3) equals: {4} asOrderedCollection. + + "Classical case" + self assert: + (testNodeSamePercentage findChildrenIndexOfIndex: 5) equals: {6} asOrderedCollection. + + "Multiple children" self assert: - (testNodeMultipleChildren findChildrenOf: 3) third equals: 8 + (testNodeMultipleChildren findChildrenIndexOfIndex: 3) equals: {4 . 5 . 8} asOrderedCollection. +] + +{ #category : #tests } +TreeParserTest >> testFindChildrenOf [ + + | aNode | + aNode := testNodeMultipleChildren nodeAtIndex: 3. + + self + assert: aNode children first name + equals: (testNodeMultipleChildren nameOf: 4). + self + assert: aNode children second name + equals: (testNodeMultipleChildren nameOf: 5). + self + assert: aNode children third name + equals: (testNodeMultipleChildren nameOf: 8) +] + +{ #category : #tests } +TreeParserTest >> testFindChildrenOfRecursive [ + + | aNode | + aNode := testNodeMultipleChildren nodeAtIndex: 3. + + self + assert: aNode children second children first name + equals: (testNodeMultipleChildren nameOf: 6). + self + assert: aNode children second children first children first name + equals: (testNodeMultipleChildren nameOf: 7) +] + +{ #category : #tests } +TreeParserTest >> testFindParentIndexOf [ + + "Two cases that shouldn't happen." + self assert: (testNodeMultipleChildren findParentIndexOfIndex: 0) isNil. + + self assert: (testNodeMultipleChildren findParentIndexOfIndex: 11) isNil. + + "The first doesn't have a parent." + self assert: (testNodeMultipleChildren findParentIndexOfIndex: 1) isNil. + + "Two classical cases." + self assert: (testNodeMultipleChildren findParentIndexOfIndex: 5) equals: 3. + + self assert: (testNodeMultipleChildren findParentIndexOfIndex: 6) equals: 5 ] { #category : #tests } TreeParserTest >> testFindParentOf [ + + "Two cases that shouldn't happen." + self assert: (testNodeMultipleChildren findParentOfIndex: 0) isNil. + + self assert: (testNodeMultipleChildren findParentOfIndex: 11) isNil. + + "The first doesn't have a parent." + self assert: (testNodeMultipleChildren findParentOfIndex: 1) isNil. + + "Two classical cases." + self assert: (testNodeMultipleChildren findParentOfIndex: 5) name equals: (testNodeMultipleChildren nameOf: 3). + + self assert: (testNodeMultipleChildren findParentOfIndex: 6) name equals: (testNodeMultipleChildren nameOf: 5) +] - self assert: (testNodeMultipleChildren findParentOf: 4) equals: 3. +{ #category : #tests } +TreeParserTest >> testIsLeaf [ + + | family example | + family := testNodeSimple classify. + example := (family firstChildrenOf: 2). - self assert: (testNodeMultipleChildren findParentOf: 6) equals: 5 + self assert: example isLeaf not. + self assert: example isNotLeaf. + + self assert: example children first isLeaf. + self assert: example children first isNotLeaf not. ] { #category : #tests } TreeParserTest >> testNameOf [ + "Three cases where the parsing is different." self assert: (testNodeSimple nameOf: 1) equals: 'entry_SYSCALL_64_after_hwframe'. self assert: (testNodeSamePercentage nameOf: 4) equals: '__x64_sys_read'. @@ -201,5 +438,43 @@ TreeParserTest >> testReadALine [ { #category : #tests } TreeParserTest >> testSimplePercentageOf [ - self assert: (testNodeSimple percentageOf: 3) equals: 45.91 + "Case with 4 digits." + self assert: (testNodeSimple percentageOf: 3) equals: 45.91. + + "Case with 3 digits." + self assert: (testNodeMultipleChildren percentageOf: 8) equals: 0.53 +] + +{ #category : #tests } +TreeParserTest >> testTime [ + + self assert: treeSimple time equals: 397.0. + + self assert: testNodeSimple time equals: 397.0. + + self assert: testNodeSimple classify time equals: 397.0. +] + +{ #category : #tests } +TreeParserTest >> testTraces [ + + | family traces | + family := testNodeSimple classify. + traces := family traces. + + self assert: traces size equals: 1. + + self assert: traces first name equals: '__x64_sys_read'. + + self assert: traces first weight equals: 146.017. +] + +{ #category : #tests } +TreeParserTest >> testWeight [ + + | family example | + family := testNodeMultipleChildren classify. + example := family firstChildrenOf: 2. + + self assert: example weight equals: 6.829. ] diff --git a/src/TreeParser/TreeChildren.class.st b/src/TreeParser/TreeChildren.class.st index 797575c..8cdc9e4 100644 --- a/src/TreeParser/TreeChildren.class.st +++ b/src/TreeParser/TreeChildren.class.st @@ -5,7 +5,10 @@ Class { 'parent', 'children', 'name', - 'percentage' + 'percentage', + 'estimatedPercentage', + 'time', + 'weight' ], #category : #TreeParser } @@ -24,15 +27,16 @@ TreeChildren >> children: aTreeChildren [ { #category : #accessing } TreeChildren >> estimatePercentage [ + "Estimate the real percentage of the function." + "The instance variable percentage is the percentage of the function and its children." | sumOfPercents | sumOfPercents := 0. - self children collect: [ :n | - sumOfPercents := n percentage + sumOfPercents ]. - - percentage - sumOfPercents >= 0 - ifTrue: [ percentage := (percentage - sumOfPercents) roundUpTo: 0.01 ]. - ^ percentage + 1 to: self children size do: [ :i | + sumOfPercents := sumOfPercents + (self children at: i) percentage ]. + estimatedPercentage := percentage - sumOfPercents roundUpTo: 0.01. + + ^ estimatedPercentage ] { #category : #accessing } @@ -45,6 +49,29 @@ TreeChildren >> firstChildrenOf: aNumber [ ^ child ] +{ #category : #accessing } +TreeChildren >> isLeaf [ + + ^ self children isEmpty +] + +{ #category : #accessing } +TreeChildren >> isNotLeaf [ + + ^ self children isNotEmpty +] + +{ #category : #accessing } +TreeChildren >> leaves: leaves [ + + self isLeaf + ifTrue: [ leaves add: self. + ^ leaves ]. + + ^ (1 to: self children size do: [:i | (self children at: i) leaves: leaves ] ) + +] + { #category : #accessing } TreeChildren >> name [ @@ -80,3 +107,35 @@ TreeChildren >> percentage: aFloat [ percentage := aFloat ] + +{ #category : #accessing } +TreeChildren >> time [ + + ^ time +] + +{ #category : #accessing } +TreeChildren >> time: aFloat [ + + time := aFloat. +] + +{ #category : #accessing } +TreeChildren >> traces [ + + | leaves | + leaves := OrderedCollection new. + self leaves: leaves. + + ^ leaves collect: [:l | + TreeTrace new + name: l name; + weight: l weight ] +] + +{ #category : #accessing } +TreeChildren >> weight [ + + weight := ( self time * estimatedPercentage / 100 ) roundUpTo: 0.001. + ^ weight +] diff --git a/src/TreeParser/TreeNode.class.st b/src/TreeParser/TreeNode.class.st new file mode 100644 index 0000000..5dcf25c --- /dev/null +++ b/src/TreeParser/TreeNode.class.st @@ -0,0 +1,66 @@ +Class { + #name : #TreeNode, + #superclass : #Object, + #instVars : [ + 'name', + 'weight', + 'parser', + 'index' + ], + #category : #TreeParser +} + +{ #category : #accessing } +TreeNode >> children [ + + ^ (parser findChildrenIndexOfIndex: index) collect: [ :childIndex | + parser nodeAtIndex: childIndex ] +] + +{ #category : #accessing } +TreeNode >> index [ + + ^ index +] + +{ #category : #accessing } +TreeNode >> index: anObject [ + + index := anObject +] + +{ #category : #accessing } +TreeNode >> name [ + + ^ name +] + +{ #category : #accessing } +TreeNode >> name: anObject [ + + name := anObject +] + +{ #category : #accessing } +TreeNode >> parser [ + + ^ parser +] + +{ #category : #accessing } +TreeNode >> parser: anObject [ + + parser := anObject +] + +{ #category : #accessing } +TreeNode >> weight [ + + ^ weight +] + +{ #category : #accessing } +TreeNode >> weight: anObject [ + + weight := anObject +] diff --git a/src/TreeParser/TreeNodes.class.st b/src/TreeParser/TreeNodes.class.st index 696a389..3ad3fe1 100644 --- a/src/TreeParser/TreeNodes.class.st +++ b/src/TreeParser/TreeNodes.class.st @@ -2,11 +2,20 @@ Class { #name : #TreeNodes, #superclass : #Object, #instVars : [ - 'nodes' + 'time', + 'nodeStrings' ], #category : #TreeParser } +{ #category : #'instance creation' } +TreeNodes class >> fromContent: aTreeParse [ + + ^ self new + nodes: aTreeParse content; + time: aTreeParse time. +] + { #category : #accessing } TreeNodes >> classify [ "Establish every parent/child links given by the file." @@ -22,9 +31,12 @@ TreeNodes >> classify: aLine withParent: aParent [ child := TreeChildren new name: (self nameOf: aLine); percentage: (self percentageOf: aLine); + time: self time; parent: aParent. - child children: ((self findChildrenOf: aLine) collect: [ :c | + child children: ((self findChildrenIndexOfIndex: aLine) collect: [ :c | self classify: c withParent: child ]). + child estimatePercentage. + child weight. ^ child ] @@ -32,12 +44,13 @@ TreeNodes >> classify: aLine withParent: aParent [ TreeNodes >> differenceOfSpacesAt: aNode [ "Gives the difference of the number of spaces between 2 followed lines." + self assert: aNode > 0. self assert: aNode < self numberOfFunctions. ^ (self numberOfSpacesAt: aNode + 1) - (self numberOfSpacesAt: aNode) ] { #category : #accessing } -TreeNodes >> findChildrenOf: aNode [ +TreeNodes >> findChildrenIndexOfIndex: aNode [ "Gives an ordered collection of every indexes of the lines where there is a child." | lastNode everyChildren | @@ -45,6 +58,7 @@ TreeNodes >> findChildrenOf: aNode [ everyChildren := OrderedCollection new. aNode = lastNode ifTrue: [ ^ everyChildren ]. + ( aNode < 1 or: aNode > lastNode ) ifTrue: [ ^ nil ]. ((self differenceOfSpacesAt: aNode) <= 10 and: (self differenceOfSpacesAt: aNode) >= 0) ifTrue: [ everyChildren add: aNode + 1. @@ -58,28 +72,27 @@ TreeNodes >> findChildrenOf: aNode [ ] { #category : #accessing } -TreeNodes >> findParentOf: aNode [ +TreeNodes >> findParentIndexOfIndex: aNodeIndex [ "Gives the index of the line where the parent is." | i | - i := aNode-1. - [ i > 1 and: [ ( (self numberOfSpacesAt: aNode) - (self numberOfSpacesAt: i) ) < 0 ] ] + + i := aNodeIndex-1. + [ (i > 1 and: i <= self numberOfFunctions) and: [ ( (self numberOfSpacesAt: aNodeIndex) - (self numberOfSpacesAt: i) ) <= 0 ] ] whileTrue: [ i := i - 1 ]. - (i > 0) + ((i > 0) and: i <= self numberOfFunctions) ifTrue: [ ^ i ] ifFalse: [ ^ nil ] ] { #category : #accessing } -TreeNodes >> lastNodeOf: aNode [ - "Give the index of the last node starting from a given node." +TreeNodes >> findParentOfIndex: aNodeIndex [ + "Gives the node representing the parent of the node at aNodeIndex." - | lastNode | - lastNode := self numberOfFunctions. - aNode to: lastNode - 1 do: [ :i | - (self differenceOfSpacesAt: i) < 0 ifTrue: [ ^ i ] ]. - ^ aNode + | parentIndex | + parentIndex := self findParentIndexOfIndex: aNodeIndex. + ^ self nodeAtIndex: parentIndex ] { #category : #accessing } @@ -87,7 +100,10 @@ TreeNodes >> lastSpaceAt: aLine [ "Gives the index of the last space at a given line." | lastSpace line| - line := nodes at: aLine. + self assert: aLine >= 1. + self assert: aLine <= self numberOfFunctions. + + line := nodeStrings at: aLine. lastSpace := line size. 1 to: (line size) do: [:i | ( ( (line at: i) = Character space) or: ( (line at: i) = $-) ) @@ -100,21 +116,38 @@ TreeNodes >> nameOf: aLine [ "Gets the name of a function at a given line." | line | + self assert: aLine >= 1. + self assert: aLine <= self numberOfFunctions. + line := (self withoutSpaces at: aLine) copyWithout: $-. ^ line last: (self lastSpaceAt: aLine) ] +{ #category : #accessing } +TreeNodes >> nodeAtIndex: aNodeIndex [ + "Gives the node representing the node at aNodeIndex." + + aNodeIndex ifNil: [ ^ nil ]. + ^ TreeNode new + parser: self; + index: aNodeIndex; + name: (self nameOf: aNodeIndex); + weight: 0; + yourself +] + { #category : #accessing } TreeNodes >> nodes [ - ^ nodes + ^ nodeStrings ] { #category : #accessing } TreeNodes >> nodes: aContent [ - nodes := aContent select: [ :c | - ((c copyWithout: Character space) copyWithout: $|) + "Ignore all lines that are empty or have useless information" + nodeStrings := aContent select: [ :line | + ((line copyWithout: Character space) copyWithout: $|) isNotEmpty ] ] @@ -122,7 +155,7 @@ TreeNodes >> nodes: aContent [ TreeNodes >> numberOfFunctions [ "Gives the number of non-unique functions mentioned in the file." - ^ nodes size + ^ nodeStrings size ] { #category : #accessing } @@ -146,7 +179,8 @@ TreeNodes >> percentageOf: aLine [ "In the case of multiples functions for one percentage, it gives the same percentage to every functions." | line numbers | - self assert: aLine >= 1. + self assert: aLine > 0. + self assert: aLine <= self numberOfFunctions. line := self nodes at: aLine. numbers := (((self withoutSpaces at: aLine) copyWithout: $-) first: 5) @@ -160,6 +194,18 @@ TreeNodes >> percentageOf: aLine [ ifFalse: [ ^ ((numbers first: 3) asInteger / 100) asFloat ] ] +{ #category : #accessing } +TreeNodes >> time [ + + ^ time +] + +{ #category : #accessing } +TreeNodes >> time: aFloat [ + + time := aFloat. +] + { #category : #accessing } TreeNodes >> withoutSpaces [ "Gives a line without the characters that are not interesting." diff --git a/src/TreeParser/TreeParse.class.st b/src/TreeParser/TreeParse.class.st deleted file mode 100644 index 024306a..0000000 --- a/src/TreeParser/TreeParse.class.st +++ /dev/null @@ -1,34 +0,0 @@ -Class { - #name : #TreeParse, - #superclass : #Object, - #instVars : [ - 'content' - ], - #category : #TreeParser -} - -{ #category : #'instance creation' } -TreeParse class >> fromFile: aFile [ - self assert: aFile class = FileReference. - ^ self new - content: aFile. -] - -{ #category : #accessing } -TreeParse >> asNodes [ - - ^ TreeNodes new nodes: content -] - -{ #category : #accessing } -TreeParse >> content: aFile [ - - content := aFile contents lines reject: [ :line | - line beginsWith: '#' ] -] - -{ #category : #accessing } -TreeParse >> readLine: pos [ - - ^ content at: pos -] diff --git a/src/TreeParser/TreeParser.class.st b/src/TreeParser/TreeParser.class.st new file mode 100644 index 0000000..29f4021 --- /dev/null +++ b/src/TreeParser/TreeParser.class.st @@ -0,0 +1,51 @@ +Class { + #name : #TreeParser, + #superclass : #Object, + #instVars : [ + 'content', + 'time' + ], + #category : #TreeParser +} + +{ #category : #'instance creation' } +TreeParser class >> fromFile: aFile [ + + ^ self new content: aFile asFileReference +] + +{ #category : #accessing } +TreeParser >> asNodes [ + + ^ TreeNodes new nodes: content +] + +{ #category : #accessing } +TreeParser >> content [ + + ^ content +] + +{ #category : #accessing } +TreeParser >> content: aFile [ + + | timeFromFile fileContents | + fileContents := aFile contents. + + timeFromFile := (fileContents lines at: 24) asInteger. + time := timeFromFile asFloat. + + content := fileContents lines reject: [ :line | line beginsWith: '#' ] +] + +{ #category : #accessing } +TreeParser >> readLine: pos [ + + ^ content at: pos +] + +{ #category : #accessing } +TreeParser >> time [ + + ^ time +] diff --git a/src/TreeParser/TreeTrace.class.st b/src/TreeParser/TreeTrace.class.st new file mode 100644 index 0000000..f4c5667 --- /dev/null +++ b/src/TreeParser/TreeTrace.class.st @@ -0,0 +1,33 @@ +Class { + #name : #TreeTrace, + #superclass : #Object, + #instVars : [ + 'name', + 'weight' + ], + #category : #TreeParser +} + +{ #category : #accessing } +TreeTrace >> name [ + + ^ name +] + +{ #category : #accessing } +TreeTrace >> name: aName [ + + name := aName +] + +{ #category : #accessing } +TreeTrace >> weight [ + + ^ weight +] + +{ #category : #accessing } +TreeTrace >> weight: aFloat [ + + weight := aFloat +] From 35acde5d54f047739d66cb854c20e9dabaf6f79b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=A9o=20Boury?= Date: Tue, 4 Jun 2024 16:43:48 +0200 Subject: [PATCH 02/29] Simplified and rearranged the classes to have a clearer purpose. Modified most methods and tests to improve mutation tests score, which is around 80% --- src/TreeParser-Tests/TreeParserTest.class.st | 233 +++++++++++------- src/TreeParser/TreeChildren.class.st | 141 ----------- src/TreeParser/TreeNode.class.st | 84 +++++-- src/TreeParser/TreeNodes.class.st | 215 ---------------- src/TreeParser/TreeParser.class.st | 245 +++++++++++++++++-- 5 files changed, 442 insertions(+), 476 deletions(-) delete mode 100644 src/TreeParser/TreeChildren.class.st delete mode 100644 src/TreeParser/TreeNodes.class.st diff --git a/src/TreeParser-Tests/TreeParserTest.class.st b/src/TreeParser-Tests/TreeParserTest.class.st index 995459a..a9f915c 100644 --- a/src/TreeParser-Tests/TreeParserTest.class.st +++ b/src/TreeParser-Tests/TreeParserTest.class.st @@ -6,9 +6,6 @@ Class { 'fileSimple', 'fileSamePercentage', 'fileMultipleChildren', - 'treeSimple', - 'treeSamePercentage', - 'treeMultipleChildren', 'testNodeSimple', 'testNodeSamePercentage', 'testNodeMultipleChildren' @@ -244,16 +241,13 @@ TreeParserTest >> setUp [ ']. fileSimple := memoryFS / ('perf_stock_simple.txt'). - treeSimple := TreeParser fromFile: fileSimple. - testNodeSimple := TreeNodes fromContent: treeSimple. + testNodeSimple := TreeParser fromFile: fileSimple. fileSamePercentage := memoryFS / ('perf_stock_same_percentage.txt'). - treeSamePercentage := TreeParser fromFile: fileSamePercentage. - testNodeSamePercentage := TreeNodes fromContent: treeSamePercentage. + testNodeSamePercentage := TreeParser fromFile: fileSamePercentage. fileMultipleChildren := memoryFS / ('perf_stock_multiple_children.txt'). - treeMultipleChildren := TreeParser fromFile: fileMultipleChildren. - testNodeMultipleChildren := TreeNodes fromContent: treeMultipleChildren. + testNodeMultipleChildren := TreeParser fromFile: fileMultipleChildren. ] @@ -267,52 +261,13 @@ TreeParserTest >> tearDown [ ] { #category : #tests } -TreeParserTest >> testClassify [ - - | family example | - family := testNodeMultipleChildren classify. - example := (family firstChildrenOf: 2) children. - - self assert: example first name equals: '__x64_sys_read'. - - self assert: example second name equals: 'syscall_exit_to_user_mode'. - - self assert: example third name equals: '__x64_sys_openat'. - -] - -{ #category : #tests } -TreeParserTest >> testClassifySameParent [ - - | family example | - family := testNodeMultipleChildren classify. - example := (family firstChildrenOf: 2) children. - - self assert: family children first children first equals: example first parent. - - self assert: example first parent equals: example second parent -] - -{ #category : #tests } -TreeParserTest >> testEstimatePercentage [ - - | family example | - family := testNodeSamePercentage classify. - example := family firstChildrenOf: 2. - - self assert: example estimatePercentage equals: 9.13. - - self assert: example children first estimatePercentage equals: 0.0 -] - -{ #category : #tests } -TreeParserTest >> testFindChildrenIndexOf [ +TreeParserTest >> testFindChildrenIndexOfIndex [ "Two cases that shouldn't happen." self assert: - (testNodeMultipleChildren findChildrenIndexOfIndex: 0) isNil. + (testNodeSimple findChildrenIndexOfIndex: 0) isZero. self assert: - (testNodeMultipleChildren findChildrenIndexOfIndex: 10) isNil. + (testNodeSimple findChildrenIndexOfIndex: 5) isZero. "Case where 2 functions have the same number of spaces." self assert: @@ -328,19 +283,19 @@ TreeParserTest >> testFindChildrenIndexOf [ ] { #category : #tests } -TreeParserTest >> testFindChildrenOf [ +TreeParserTest >> testFindChildrenOfIndex [ | aNode | - aNode := testNodeMultipleChildren nodeAtIndex: 3. + aNode := testNodeMultipleChildren findChildrenOfIndex: 3. self - assert: aNode children first name + assert: aNode first name equals: (testNodeMultipleChildren nameOf: 4). self - assert: aNode children second name + assert: aNode second name equals: (testNodeMultipleChildren nameOf: 5). self - assert: aNode children third name + assert: aNode third name equals: (testNodeMultipleChildren nameOf: 8) ] @@ -348,7 +303,8 @@ TreeParserTest >> testFindChildrenOf [ TreeParserTest >> testFindChildrenOfRecursive [ | aNode | - aNode := testNodeMultipleChildren nodeAtIndex: 3. + aNode := testNodeMultipleChildren nodes. + aNode := aNode firstChildrenOf: 2. self assert: aNode children second children first name @@ -359,44 +315,65 @@ TreeParserTest >> testFindChildrenOfRecursive [ ] { #category : #tests } -TreeParserTest >> testFindParentIndexOf [ +TreeParserTest >> testFindParentIndexOfIndex [ "Two cases that shouldn't happen." - self assert: (testNodeMultipleChildren findParentIndexOfIndex: 0) isNil. + self assert: (testNodeSimple findParentIndexOfIndex: 0) isZero. - self assert: (testNodeMultipleChildren findParentIndexOfIndex: 11) isNil. + self assert: (testNodeSimple findParentIndexOfIndex: 5) isZero. "The first doesn't have a parent." - self assert: (testNodeMultipleChildren findParentIndexOfIndex: 1) isNil. + self assert: (testNodeMultipleChildren findParentIndexOfIndex: 1) isZero. "Two classical cases." self assert: (testNodeMultipleChildren findParentIndexOfIndex: 5) equals: 3. - self assert: (testNodeMultipleChildren findParentIndexOfIndex: 6) equals: 5 + self assert: (testNodeMultipleChildren findParentIndexOfIndex: 9) equals: 8 ] { #category : #tests } -TreeParserTest >> testFindParentOf [ - +TreeParserTest >> testFindParentOfIndex [ "Two cases that shouldn't happen." - self assert: (testNodeMultipleChildren findParentOfIndex: 0) isNil. - - self assert: (testNodeMultipleChildren findParentOfIndex: 11) isNil. - + + self assert: (testNodeSimple findParentOfIndex: 0) isNil. + + self assert: (testNodeSimple findParentOfIndex: 5) isNil. + "The first doesn't have a parent." self assert: (testNodeMultipleChildren findParentOfIndex: 1) isNil. - + "Two classical cases." - self assert: (testNodeMultipleChildren findParentOfIndex: 5) name equals: (testNodeMultipleChildren nameOf: 3). - - self assert: (testNodeMultipleChildren findParentOfIndex: 6) name equals: (testNodeMultipleChildren nameOf: 5) + self + assert: (testNodeMultipleChildren findParentOfIndex: 5) name + equals: (testNodeMultipleChildren nameOf: 3). + + self + assert: (testNodeMultipleChildren findParentOfIndex: 6) name + equals: (testNodeMultipleChildren nameOf: 5) +] + +{ #category : #tests } +TreeParserTest >> testFindParentOfRecursive [ + + | aNode | + aNode := testNodeMultipleChildren nodes. + aNode := aNode firstChildrenOf: 2. + + self + assert: aNode parent name + equals: (testNodeMultipleChildren nameOf: 2). + + self + assert: + (testNodeMultipleChildren findParentOfIndex: 2) children first name + equals: (testNodeMultipleChildren findParentOfIndex: 3) name ] { #category : #tests } TreeParserTest >> testIsLeaf [ | family example | - family := testNodeSimple classify. + family := testNodeSimple nodes. example := (family firstChildrenOf: 2). self assert: example isLeaf not. @@ -409,6 +386,11 @@ TreeParserTest >> testIsLeaf [ { #category : #tests } TreeParserTest >> testNameOf [ + "Limit cases" + self assert: (testNodeSimple nameOf: 0) isNil. + + self assert: (testNodeSimple nameOf: 5) isNil. + "Three cases where the parsing is different." self assert: (testNodeSimple nameOf: 1) equals: 'entry_SYSCALL_64_after_hwframe'. @@ -417,6 +399,33 @@ TreeParserTest >> testNameOf [ self assert: (testNodeSamePercentage nameOf: 6) equals: 'vfs_read' ] +{ #category : #tests } +TreeParserTest >> testNodes [ + + | family example | + family := testNodeMultipleChildren nodes. + example := (family firstChildrenOf: 2) children. + + self assert: example first name equals: '__x64_sys_read'. + + self assert: example second name equals: 'syscall_exit_to_user_mode'. + + self assert: example third name equals: '__x64_sys_openat'. + +] + +{ #category : #tests } +TreeParserTest >> testNodesSameParent [ + + | family example | + family := testNodeMultipleChildren nodes. + example := (family firstChildrenOf: 2) children. + + self assert: family children first children first equals: example first parent. + + self assert: example first parent equals: example second parent +] + { #category : #tests } TreeParserTest >> testNumberOfFunctions [ @@ -424,57 +433,105 @@ TreeParserTest >> testNumberOfFunctions [ ] { #category : #tests } -TreeParserTest >> testNumberOfSpaces [ +TreeParserTest >> testNumberOfSpacesAt [ + + + self assert: (testNodeSimple numberOfSpacesAt: 0) isZero. + + self assert: (testNodeSimple numberOfSpacesAt: 5) isZero. self assert: (testNodeSimple numberOfSpacesAt: 1) equals: 4 ] { #category : #tests } -TreeParserTest >> testReadALine [ +TreeParserTest >> testPercentageOf [ + "Limit cases" + + self assert: (testNodeSimple percentageOf: 0) isZero. - self assert: (treeSimple readLine: 3) equals: ' ---entry_SYSCALL_64_after_hwframe' + self assert: (testNodeSimple percentageOf: 5) isZero. + + "Cases with 4 digits." + self assert: (testNodeSimple percentageOf: 3) equals: 45.91. + + self assert: (testNodeSimple percentageOf: 1) equals: 46.02. + + + "Case with 3 digits." + self assert: (testNodeMultipleChildren percentageOf: 8) equals: 0.53. + + "Case with same percentage" + self + assert: (testNodeSamePercentage percentageOf: 4) + equals: (testNodeSamePercentage percentageOf: 5) ] { #category : #tests } -TreeParserTest >> testSimplePercentageOf [ +TreeParserTest >> testReadLine [ - "Case with 4 digits." - self assert: (testNodeSimple percentageOf: 3) equals: 45.91. + "Limit cases." + self assert: (testNodeSimple readLine: 0) isNil. - "Case with 3 digits." - self assert: (testNodeMultipleChildren percentageOf: 8) equals: 0.53 + self assert: (testNodeSimple readLine: 5) isNil. + + self assert: (testNodeSimple readLine: 3) equals: ' --45.91%--do_syscall_64' ] { #category : #tests } -TreeParserTest >> testTime [ +TreeParserTest >> testRealPercentageOf [ + + "Limit cases." + self assert: (testNodeSimple realPercentageOf: 0) isZero. + + self assert: (testNodeSimple realPercentageOf: 5) isZero. - self assert: treeSimple time equals: 397.0. + self + assert: (testNodeSamePercentage realPercentageOf: 3) + equals: 9.13. + + self assert: (testNodeSamePercentage realPercentageOf: 4) equals: 0.0 +] + +{ #category : #tests } +TreeParserTest >> testTime [ self assert: testNodeSimple time equals: 397.0. - self assert: testNodeSimple classify time equals: 397.0. + self assert: testNodeSimple nodes time equals: 397.0. ] { #category : #tests } TreeParserTest >> testTraces [ | family traces | - family := testNodeSimple classify. + family := testNodeSimple nodes. traces := family traces. self assert: traces size equals: 1. self assert: traces first name equals: '__x64_sys_read'. - self assert: traces first weight equals: 146.017. + self assert: traces first weight equals: 146.02. ] { #category : #tests } TreeParserTest >> testWeight [ | family example | - family := testNodeMultipleChildren classify. + family := testNodeMultipleChildren nodes. example := family firstChildrenOf: 2. - self assert: example weight equals: 6.829. + self assert: example weight equals: 6.83. +] + +{ #category : #tests } +TreeParserTest >> testWeightOf [ + + "Limit cases" + self assert: (testNodeSimple weightOf: 0) isZero. + + self assert: (testNodeSimple weightOf: 5) isZero. + + "Classical case" + self assert: (testNodeSimple weightOf: 3) equals: 36.25. ] diff --git a/src/TreeParser/TreeChildren.class.st b/src/TreeParser/TreeChildren.class.st deleted file mode 100644 index 8cdc9e4..0000000 --- a/src/TreeParser/TreeChildren.class.st +++ /dev/null @@ -1,141 +0,0 @@ -Class { - #name : #TreeChildren, - #superclass : #Object, - #instVars : [ - 'parent', - 'children', - 'name', - 'percentage', - 'estimatedPercentage', - 'time', - 'weight' - ], - #category : #TreeParser -} - -{ #category : #accessing } -TreeChildren >> children [ - - ^ children -] - -{ #category : #accessing } -TreeChildren >> children: aTreeChildren [ - - children := aTreeChildren. -] - -{ #category : #accessing } -TreeChildren >> estimatePercentage [ - "Estimate the real percentage of the function." - "The instance variable percentage is the percentage of the function and its children." - - | sumOfPercents | - sumOfPercents := 0. - 1 to: self children size do: [ :i | - sumOfPercents := sumOfPercents + (self children at: i) percentage ]. - estimatedPercentage := percentage - sumOfPercents roundUpTo: 0.01. - - ^ estimatedPercentage -] - -{ #category : #accessing } -TreeChildren >> firstChildrenOf: aNumber [ - "Gives the children of the first children of each generations a given times." - - | child | - child := self. - 1 to: aNumber do: [:c | child := child children first ]. - ^ child -] - -{ #category : #accessing } -TreeChildren >> isLeaf [ - - ^ self children isEmpty -] - -{ #category : #accessing } -TreeChildren >> isNotLeaf [ - - ^ self children isNotEmpty -] - -{ #category : #accessing } -TreeChildren >> leaves: leaves [ - - self isLeaf - ifTrue: [ leaves add: self. - ^ leaves ]. - - ^ (1 to: self children size do: [:i | (self children at: i) leaves: leaves ] ) - -] - -{ #category : #accessing } -TreeChildren >> name [ - - ^ name -] - -{ #category : #accessing } -TreeChildren >> name: aName [ - - name := aName -] - -{ #category : #accessing } -TreeChildren >> parent [ - - ^ parent -] - -{ #category : #accessing } -TreeChildren >> parent: aTreeNode [ - - parent := aTreeNode -] - -{ #category : #accessing } -TreeChildren >> percentage [ - - ^ percentage -] - -{ #category : #accessing } -TreeChildren >> percentage: aFloat [ - - percentage := aFloat -] - -{ #category : #accessing } -TreeChildren >> time [ - - ^ time -] - -{ #category : #accessing } -TreeChildren >> time: aFloat [ - - time := aFloat. -] - -{ #category : #accessing } -TreeChildren >> traces [ - - | leaves | - leaves := OrderedCollection new. - self leaves: leaves. - - ^ leaves collect: [:l | - TreeTrace new - name: l name; - weight: l weight ] -] - -{ #category : #accessing } -TreeChildren >> weight [ - - weight := ( self time * estimatedPercentage / 100 ) roundUpTo: 0.001. - ^ weight -] diff --git a/src/TreeParser/TreeNode.class.st b/src/TreeParser/TreeNode.class.st index 5dcf25c..da6d95c 100644 --- a/src/TreeParser/TreeNode.class.st +++ b/src/TreeParser/TreeNode.class.st @@ -4,8 +4,9 @@ Class { #instVars : [ 'name', 'weight', - 'parser', - 'index' + 'children', + 'parent', + 'totalTime' ], #category : #TreeParser } @@ -13,20 +14,45 @@ Class { { #category : #accessing } TreeNode >> children [ - ^ (parser findChildrenIndexOfIndex: index) collect: [ :childIndex | - parser nodeAtIndex: childIndex ] + ^ children ] { #category : #accessing } -TreeNode >> index [ +TreeNode >> children: aCollectionOfTreeNode [ - ^ index + children:= aCollectionOfTreeNode ] { #category : #accessing } -TreeNode >> index: anObject [ +TreeNode >> firstChildrenOf: aNumber [ + "Gives the children of the first children of each generations a given times." - index := anObject + | child | + child := self. + 1 to: aNumber do: [ :c | child := child children first ]. + ^ child +] + +{ #category : #accessing } +TreeNode >> isLeaf [ + + ^ self children isEmpty +] + +{ #category : #accessing } +TreeNode >> isNotLeaf [ + + ^ self children isNotEmpty +] + +{ #category : #accessing } +TreeNode >> leaves: leaves [ + + self isLeaf ifTrue: [ + leaves add: self. + ^ leaves ]. + + ^ self children collect: [ :child | child leaves: leaves ] ] { #category : #accessing } @@ -36,21 +62,47 @@ TreeNode >> name [ ] { #category : #accessing } -TreeNode >> name: anObject [ +TreeNode >> name: aString [ - name := anObject + name := aString ] { #category : #accessing } -TreeNode >> parser [ +TreeNode >> parent [ - ^ parser + ^ parent ] { #category : #accessing } -TreeNode >> parser: anObject [ +TreeNode >> parent: aTreeNode [ + + parent := aTreeNode +] + +{ #category : #accessing } +TreeNode >> time [ + + ^ totalTime +] + +{ #category : #accessing } +TreeNode >> time: aFloat [ + + totalTime := aFloat +] + +{ #category : #accessing } +TreeNode >> traces [ + + | leaves | + leaves := OrderedCollection new. + self leaves: leaves. - parser := anObject + ^ leaves collect: [ :l | + TreeTrace new + name: l name; + weight: l weight; + yourself ] ] { #category : #accessing } @@ -60,7 +112,7 @@ TreeNode >> weight [ ] { #category : #accessing } -TreeNode >> weight: anObject [ +TreeNode >> weight: aFloat [ - weight := anObject + weight := aFloat ] diff --git a/src/TreeParser/TreeNodes.class.st b/src/TreeParser/TreeNodes.class.st deleted file mode 100644 index 3ad3fe1..0000000 --- a/src/TreeParser/TreeNodes.class.st +++ /dev/null @@ -1,215 +0,0 @@ -Class { - #name : #TreeNodes, - #superclass : #Object, - #instVars : [ - 'time', - 'nodeStrings' - ], - #category : #TreeParser -} - -{ #category : #'instance creation' } -TreeNodes class >> fromContent: aTreeParse [ - - ^ self new - nodes: aTreeParse content; - time: aTreeParse time. -] - -{ #category : #accessing } -TreeNodes >> classify [ - "Establish every parent/child links given by the file." - - ^ (self classify: 1 withParent: nil) -] - -{ #category : #accessing } -TreeNodes >> classify: aLine withParent: aParent [ - "Establish the parent/child links, starting from a given line and optionally a parent." - - | child | - child := TreeChildren new - name: (self nameOf: aLine); - percentage: (self percentageOf: aLine); - time: self time; - parent: aParent. - child children: ((self findChildrenIndexOfIndex: aLine) collect: [ :c | - self classify: c withParent: child ]). - child estimatePercentage. - child weight. - ^ child -] - -{ #category : #accessing } -TreeNodes >> differenceOfSpacesAt: aNode [ - "Gives the difference of the number of spaces between 2 followed lines." - - self assert: aNode > 0. - self assert: aNode < self numberOfFunctions. - ^ (self numberOfSpacesAt: aNode + 1) - (self numberOfSpacesAt: aNode) -] - -{ #category : #accessing } -TreeNodes >> findChildrenIndexOfIndex: aNode [ - "Gives an ordered collection of every indexes of the lines where there is a child." - - | lastNode everyChildren | - lastNode := self numberOfFunctions. - everyChildren := OrderedCollection new. - - aNode = lastNode ifTrue: [ ^ everyChildren ]. - ( aNode < 1 or: aNode > lastNode ) ifTrue: [ ^ nil ]. - - ((self differenceOfSpacesAt: aNode) <= 10 and: (self differenceOfSpacesAt: aNode) >= 0) - ifTrue: [ everyChildren add: aNode + 1. - ^ everyChildren ]. - - aNode to: lastNode do: [ :i | - (self numberOfSpacesAt: i) - (self numberOfSpacesAt: aNode) = 11 - ifTrue: [ everyChildren add: i ] ]. - - ^ everyChildren -] - -{ #category : #accessing } -TreeNodes >> findParentIndexOfIndex: aNodeIndex [ - "Gives the index of the line where the parent is." - - | i | - - i := aNodeIndex-1. - [ (i > 1 and: i <= self numberOfFunctions) and: [ ( (self numberOfSpacesAt: aNodeIndex) - (self numberOfSpacesAt: i) ) <= 0 ] ] - whileTrue: [ i := i - 1 ]. - - ((i > 0) and: i <= self numberOfFunctions) - ifTrue: [ ^ i ] - ifFalse: [ ^ nil ] -] - -{ #category : #accessing } -TreeNodes >> findParentOfIndex: aNodeIndex [ - "Gives the node representing the parent of the node at aNodeIndex." - - | parentIndex | - parentIndex := self findParentIndexOfIndex: aNodeIndex. - ^ self nodeAtIndex: parentIndex -] - -{ #category : #accessing } -TreeNodes >> lastSpaceAt: aLine [ - "Gives the index of the last space at a given line." - - | lastSpace line| - self assert: aLine >= 1. - self assert: aLine <= self numberOfFunctions. - - line := nodeStrings at: aLine. - lastSpace := line size. - - 1 to: (line size) do: [:i | ( ( (line at: i) = Character space) or: ( (line at: i) = $-) ) - ifTrue: [ lastSpace := line size - i ] ]. - ^ lastSpace -] - -{ #category : #accessing } -TreeNodes >> nameOf: aLine [ - "Gets the name of a function at a given line." - - | line | - self assert: aLine >= 1. - self assert: aLine <= self numberOfFunctions. - - line := (self withoutSpaces at: aLine) copyWithout: $-. - ^ line last: (self lastSpaceAt: aLine) -] - -{ #category : #accessing } -TreeNodes >> nodeAtIndex: aNodeIndex [ - "Gives the node representing the node at aNodeIndex." - - aNodeIndex ifNil: [ ^ nil ]. - ^ TreeNode new - parser: self; - index: aNodeIndex; - name: (self nameOf: aNodeIndex); - weight: 0; - yourself -] - -{ #category : #accessing } -TreeNodes >> nodes [ - - ^ nodeStrings -] - -{ #category : #accessing } -TreeNodes >> nodes: aContent [ - - "Ignore all lines that are empty or have useless information" - nodeStrings := aContent select: [ :line | - ((line copyWithout: Character space) copyWithout: $|) - isNotEmpty ] -] - -{ #category : #accessing } -TreeNodes >> numberOfFunctions [ - "Gives the number of non-unique functions mentioned in the file." - - ^ nodeStrings size -] - -{ #category : #accessing } -TreeNodes >> numberOfSpacesAt: aNode [ - "Gives the number of spaces at a certain line." - - | count spacesAreEnded | - count := 0. - spacesAreEnded := false. - (self nodes at: aNode) do: [ :c | - (c ~= Character space and: c ~= $|) - ifFalse: [ spacesAreEnded ifFalse: [ count := count + 1 ] ] - ifTrue: [ spacesAreEnded := true ] ]. - ^ count -] - -{ #category : #accessing } -TreeNodes >> percentageOf: aLine [ - "Gives the percentage from a function at a given line" - - "In the case of multiples functions for one percentage, it gives the same percentage to every functions." - - | line numbers | - self assert: aLine > 0. - self assert: aLine <= self numberOfFunctions. - line := self nodes at: aLine. - - numbers := (((self withoutSpaces at: aLine) copyWithout: $-) first: 5) - select: [ :c | - { $0. $1. $2. $3. $4. $5. $6. $7. $8. $9 } asSet - includes: c ]. - (aLine > 1 and: numbers isEmpty) ifTrue: [ - ^ self percentageOf: aLine - 1 ]. - numbers size >= 4 - ifTrue: [ ^ ((numbers first: 4) asInteger / 100) asFloat ] - ifFalse: [ ^ ((numbers first: 3) asInteger / 100) asFloat ] -] - -{ #category : #accessing } -TreeNodes >> time [ - - ^ time -] - -{ #category : #accessing } -TreeNodes >> time: aFloat [ - - time := aFloat. -] - -{ #category : #accessing } -TreeNodes >> withoutSpaces [ - "Gives a line without the characters that are not interesting." - - ^ self nodes collect: [ :n | - (n copyWithout: Character space) copyWithout: $| ] -] diff --git a/src/TreeParser/TreeParser.class.st b/src/TreeParser/TreeParser.class.st index 29f4021..2dc62ef 100644 --- a/src/TreeParser/TreeParser.class.st +++ b/src/TreeParser/TreeParser.class.st @@ -3,7 +3,7 @@ Class { #superclass : #Object, #instVars : [ 'content', - 'time' + 'totalTime' ], #category : #TreeParser } @@ -11,41 +11,254 @@ Class { { #category : #'instance creation' } TreeParser class >> fromFile: aFile [ - ^ self new content: aFile asFileReference -] - -{ #category : #accessing } -TreeParser >> asNodes [ - - ^ TreeNodes new nodes: content + ^ self new + content: aFile asFileReference; + yourself ] { #category : #accessing } TreeParser >> content [ - + ^ content ] { #category : #accessing } TreeParser >> content: aFile [ + "Extract the interesting content from the file." | timeFromFile fileContents | fileContents := aFile contents. - + timeFromFile := (fileContents lines at: 24) asInteger. - time := timeFromFile asFloat. + self time: timeFromFile asFloat. + + content := fileContents lines reject: [ :line | line beginsWith: '#' ]. + content := content select: [ :line | + ((line copyWithout: Character space) copyWithout: $|) + isNotEmpty ] +] + +{ #category : #accessing } +TreeParser >> differenceOfSpacesAt: aNodeIndex [ + "Gives the difference of the number of spaces between 2 followed lines." + + (aNodeIndex between: 1 and: self numberOfFunctions - 1) ifTrue: [ + ^ (self numberOfSpacesAt: aNodeIndex + 1) + - (self numberOfSpacesAt: aNodeIndex) ] +] + +{ #category : #accessing } +TreeParser >> findChildrenIndexOfIndex: aNode [ + "Gives an ordered collection of every indexes of the lines where there is a child." + + | lastNode everyChildren | + lastNode := self numberOfFunctions. + everyChildren := OrderedCollection new. + + aNode = lastNode ifTrue: [ ^ everyChildren ]. + (aNode between: 1 and: lastNode) ifFalse: [ ^ 0 ]. + + (((self differenceOfSpacesAt: aNode) between: 1 and: 10) or: [ + (self percentageOf: aNode) = (self percentageOf: aNode + 1) ]) + ifTrue: [ + everyChildren add: aNode + 1. + ^ everyChildren ]. + + aNode to: lastNode do: [ :i | + (self numberOfSpacesAt: i) - (self numberOfSpacesAt: aNode) = 11 + ifTrue: [ everyChildren add: i ] ]. + + ^ everyChildren +] + +{ #category : #accessing } +TreeParser >> findChildrenOfIndex: aNodeIndex [ + "Gives the nodes representing every children at the node aNodeIndex." + + | collectionOfChildrenIndexes | + collectionOfChildrenIndexes := self findChildrenIndexOfIndex: aNodeIndex. + ^ collectionOfChildrenIndexes collect: [ :childIndex | + self nodeAtIndex: childIndex withParent: self ] +] + +{ #category : #accessing } +TreeParser >> findParentIndexOfIndex: aNodeIndex [ + "Gives the index of the line where the parent is." + + | i size | + size := self numberOfFunctions. + + i := aNodeIndex - 1. + [ + (i between: 1 and: size) and: [ + (self numberOfSpacesAt: aNodeIndex) - (self numberOfSpacesAt: i) + <= 0 ] ] whileTrue: [ i := i - 1 ]. + + (i > 0 and: i <= self numberOfFunctions) + ifTrue: [ ^ i ] + ifFalse: [ ^ 0 ] +] + +{ #category : #accessing } +TreeParser >> findParentOfIndex: aNodeIndex [ + "Gives the node representing the parent of the node at aNodeIndex." + + | parentIndex parent | + parentIndex := self findParentIndexOfIndex: aNodeIndex. + parent := (aNodeIndex - 1 between: 1 and: self numberOfFunctions) + ifTrue: [ self findParentOfIndex: aNodeIndex - 1 ] + ifFalse: [ nil ]. + ^ self nodeAtIndex: parentIndex withParent: parent +] + +{ #category : #accessing } +TreeParser >> lastSpaceAt: aLine [ + "Gives the index of the last space at a given line." + + | lastSpace line | + (aLine between: 1 and: self numberOfFunctions) ifFalse: [ ^ nil ]. + + line := self readLine: aLine. + lastSpace := line size. + + 1 to: line size do: [ :i | + ((line at: i) = Character space or: [ (line at: i) = $- ]) ifTrue: [ + lastSpace := line size - i ] ]. + ^ lastSpace +] + +{ #category : #accessing } +TreeParser >> nameOf: aNodeIndex [ + "Gives the name of a function at aNodeIndex." + + | aLine | + (aNodeIndex between: 1 and: self numberOfFunctions) ifFalse: [ ^ nil ]. + + aLine := (self withoutSpaces at: aNodeIndex) copyWithout: $-. + ^ aLine last: (self lastSpaceAt: aNodeIndex) +] + +{ #category : #accessing } +TreeParser >> nodeAtIndex: aNodeIndex withParent: aTreeNode [ + "Gives the node representing the node at aNodeIndex." + + | child | + (aNodeIndex between: 1 and: self numberOfFunctions) ifFalse: [ ^ nil ]. + + child := TreeNode new + name: (self nameOf: aNodeIndex); + weight: (self weightOf: aNodeIndex); + time: self time; + parent: aTreeNode; + yourself. + child children: (self findChildrenOfIndex: aNodeIndex). + child children do: [ :grandchild | grandchild parent: child ]. + ^ child +] + +{ #category : #accessing } +TreeParser >> nodes [ + "Gives the first parent of the nodes" + + ^ (self nodeAtIndex: 1 withParent: nil) +] + +{ #category : #accessing } +TreeParser >> numberOfFunctions [ + "Gives the number of functions present in the file." + + ^ content size +] + +{ #category : #accessing } +TreeParser >> numberOfSpacesAt: aNodeIndex [ + "Gives the number of spaces at a certain line." + + | count spacesAreEnded | + count := 0. + spacesAreEnded := false. + + (aNodeIndex between: 1 and: self numberOfFunctions) ifFalse: [ ^ 0 ]. - content := fileContents lines reject: [ :line | line beginsWith: '#' ] + (self content at: aNodeIndex) do: [ :c | + (c ~= Character space and: [ c ~= $| ]) + ifFalse: [ spacesAreEnded ifFalse: [ count := count + 1 ] ] + ifTrue: [ spacesAreEnded := true ] ]. + ^ count ] { #category : #accessing } -TreeParser >> readLine: pos [ +TreeParser >> percentageOf: aLine [ + "Gives the percentage from a function at a given line" - ^ content at: pos + "In the case of multiples functions for one percentage, it gives the same percentage to every functions." + + | numbers | + (aLine between: 1 and: self numberOfFunctions) ifFalse: [ ^ 0 ]. + + numbers := (((self withoutSpaces at: aLine) copyWithout: $-) first: 5) + select: [ :c | + { $0. $1. $2. $3. $4. $5. $6. $7. $8. $9 } asSet + includes: c ]. + (aLine > 1 and: [ numbers isEmpty ]) ifTrue: [ + ^ self percentageOf: aLine - 1 ]. + numbers size >= 4 + ifTrue: [ ^ ((numbers first: 4) asInteger / 100) asFloat ] + ifFalse: [ ^ ((numbers first: 3) asInteger / 100) asFloat ] +] + +{ #category : #accessing } +TreeParser >> readLine: anIndex [ + "Reads a line from the file without the commentaries." + + (anIndex between: 1 and: self numberOfFunctions) + ifTrue: [ ^ self content at: anIndex ] + ifFalse: [ ^ nil ] +] + +{ #category : #accessing } +TreeParser >> realPercentageOf: aNodeIndex [ + + | children childrenPercentage | + children := self findChildrenIndexOfIndex: aNodeIndex. + children isCollection ifFalse: [ ^ 0 ]. + childrenPercentage := 0. + + 1 to: children size do: [ :childIndex | + childrenPercentage := childrenPercentage + + + (self percentageOf: (children at: childIndex)) ]. + + ^ (self percentageOf: aNodeIndex) - childrenPercentage roundUpTo: + 0.01 ] { #category : #accessing } TreeParser >> time [ - - ^ time + + ^ totalTime +] + +{ #category : #accessing } +TreeParser >> time: aFloat [ + + totalTime := aFloat. +] + +{ #category : #accessing } +TreeParser >> weightOf: aNodeIndex [ + + | newPercentage | + (aNodeIndex between: 1 and: self numberOfFunctions) ifFalse: [ ^ 0 ]. + newPercentage := self realPercentageOf: aNodeIndex. + + ^ totalTime * (newPercentage / 100) asFloat roundUpTo: 0.01 +] + +{ #category : #accessing } +TreeParser >> withoutSpaces [ + "Gives a line without the characters that are not interesting." + + ^ self content collect: [ :c | + (c copyWithout: Character space) copyWithout: $| ] ] From c438888228d66b2a6d6b81e52649fb016a6b70d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=A9o=20Boury?= Date: Wed, 5 Jun 2024 16:31:24 +0200 Subject: [PATCH 03/29] Corrected some issues and increased mutation score to ~90% Added tests to methods that still didn't have one Removed methods that were not used Changed `firstChildrenOf` for `firstChild` Added class method `parseFile:` to directly have the nodes from the file without needing to use `TreeParser` methods Changed the way `time` and `percentageOf`worked to be more precise and optimized Renamed some methods to be clearer Renamed tests instance variables to be clearer --- src/TreeParser-Tests/TreeParserTest.class.st | 261 +++++++++---------- src/TreeParser/TreeNode.class.st | 30 +-- src/TreeParser/TreeParser.class.st | 104 +++----- 3 files changed, 185 insertions(+), 210 deletions(-) diff --git a/src/TreeParser-Tests/TreeParserTest.class.st b/src/TreeParser-Tests/TreeParserTest.class.st index a9f915c..4275913 100644 --- a/src/TreeParser-Tests/TreeParserTest.class.st +++ b/src/TreeParser-Tests/TreeParserTest.class.st @@ -6,6 +6,9 @@ Class { 'fileSimple', 'fileSamePercentage', 'fileMultipleChildren', + 'testParserSimple', + 'testParserSamePercentage', + 'testParserMultipleChildren', 'testNodeSimple', 'testNodeSamePercentage', 'testNodeMultipleChildren' @@ -241,13 +244,16 @@ TreeParserTest >> setUp [ ']. fileSimple := memoryFS / ('perf_stock_simple.txt'). - testNodeSimple := TreeParser fromFile: fileSimple. + testParserSimple := TreeParser fromFile: fileSimple. + testNodeSimple := TreeParser parseFile: fileSimple. fileSamePercentage := memoryFS / ('perf_stock_same_percentage.txt'). - testNodeSamePercentage := TreeParser fromFile: fileSamePercentage. + testParserSamePercentage := TreeParser fromFile: fileSamePercentage. + testNodeSamePercentage := TreeParser parseFile: fileSamePercentage. fileMultipleChildren := memoryFS / ('perf_stock_multiple_children.txt'). - testNodeMultipleChildren := TreeParser fromFile: fileMultipleChildren. + testParserMultipleChildren := TreeParser fromFile: fileMultipleChildren. + testNodeMultipleChildren := TreeParser parseFile: fileMultipleChildren. ] @@ -261,120 +267,84 @@ TreeParserTest >> tearDown [ ] { #category : #tests } -TreeParserTest >> testFindChildrenIndexOfIndex [ - "Two cases that shouldn't happen." - self assert: - (testNodeSimple findChildrenIndexOfIndex: 0) isZero. - - self assert: - (testNodeSimple findChildrenIndexOfIndex: 5) isZero. +TreeParserTest >> testDifferenceOfSpacesAt [ + + self assert: (testParserSimple differenceOfSpacesAt: 0) isZero. - "Case where 2 functions have the same number of spaces." - self assert: - (testNodeSimple findChildrenIndexOfIndex: 3) equals: {4} asOrderedCollection. + self assert: (testParserSimple differenceOfSpacesAt: 5) isZero. "Classical case" - self assert: - (testNodeSamePercentage findChildrenIndexOfIndex: 5) equals: {6} asOrderedCollection. + self assert: (testParserSamePercentage differenceOfSpacesAt: 6) equals: 1. - "Multiple children" - self assert: - (testNodeMultipleChildren findChildrenIndexOfIndex: 3) equals: {4 . 5 . 8} asOrderedCollection. + self assert: (testParserSamePercentage differenceOfSpacesAt: 1) equals: 8. + + self assert: (testParserSamePercentage differenceOfSpacesAt: 5) isZero. ] { #category : #tests } -TreeParserTest >> testFindChildrenOfIndex [ +TreeParserTest >> testFindChildrenIndexOfIndex [ + "Two cases that shouldn't happen." - | aNode | - aNode := testNodeMultipleChildren findChildrenOfIndex: 3. + self assert: (testParserSimple findChildrenIndexOfIndex: 0) isZero. - self - assert: aNode first name - equals: (testNodeMultipleChildren nameOf: 4). - self - assert: aNode second name - equals: (testNodeMultipleChildren nameOf: 5). - self - assert: aNode third name - equals: (testNodeMultipleChildren nameOf: 8) -] + self assert: (testParserSimple findChildrenIndexOfIndex: 5) isZero. -{ #category : #tests } -TreeParserTest >> testFindChildrenOfRecursive [ + "The last has no children" - | aNode | - aNode := testNodeMultipleChildren nodes. - aNode := aNode firstChildrenOf: 2. + self assert: (testParserSimple findChildrenIndexOfIndex: 4) isEmpty. + "Case where 2 functions have the same number of spaces." self - assert: aNode children second children first name - equals: (testNodeMultipleChildren nameOf: 6). + assert: (testParserSimple findChildrenIndexOfIndex: 3) + equals: { 4 } asOrderedCollection. + + "Classical case" self - assert: aNode children second children first children first name - equals: (testNodeMultipleChildren nameOf: 7) -] + assert: (testParserSamePercentage findChildrenIndexOfIndex: 5) + equals: { 6 } asOrderedCollection. -{ #category : #tests } -TreeParserTest >> testFindParentIndexOfIndex [ - - "Two cases that shouldn't happen." - self assert: (testNodeSimple findParentIndexOfIndex: 0) isZero. - - self assert: (testNodeSimple findParentIndexOfIndex: 5) isZero. - - "The first doesn't have a parent." - self assert: (testNodeMultipleChildren findParentIndexOfIndex: 1) isZero. - - "Two classical cases." - self assert: (testNodeMultipleChildren findParentIndexOfIndex: 5) equals: 3. - - self assert: (testNodeMultipleChildren findParentIndexOfIndex: 9) equals: 8 + "Multiple children" + self + assert: (testParserMultipleChildren findChildrenIndexOfIndex: 3) + equals: { 4. 5. 8 } asOrderedCollection ] { #category : #tests } -TreeParserTest >> testFindParentOfIndex [ - "Two cases that shouldn't happen." - - self assert: (testNodeSimple findParentOfIndex: 0) isNil. - - self assert: (testNodeSimple findParentOfIndex: 5) isNil. +TreeParserTest >> testFindChildrenOfIndex [ - "The first doesn't have a parent." - self assert: (testNodeMultipleChildren findParentOfIndex: 1) isNil. + | aNode | + aNode := testParserMultipleChildren findChildrenOfIndex: 3. - "Two classical cases." self - assert: (testNodeMultipleChildren findParentOfIndex: 5) name - equals: (testNodeMultipleChildren nameOf: 3). - + assert: aNode first name + equals: (testParserMultipleChildren nameOf: 4). + self + assert: aNode second name + equals: (testParserMultipleChildren nameOf: 5). self - assert: (testNodeMultipleChildren findParentOfIndex: 6) name - equals: (testNodeMultipleChildren nameOf: 5) + assert: aNode third name + equals: (testParserMultipleChildren nameOf: 8) ] { #category : #tests } -TreeParserTest >> testFindParentOfRecursive [ +TreeParserTest >> testFindChildrenOfRecursive [ | aNode | - aNode := testNodeMultipleChildren nodes. - aNode := aNode firstChildrenOf: 2. + aNode := testNodeMultipleChildren firstChild firstChild. self - assert: aNode parent name - equals: (testNodeMultipleChildren nameOf: 2). - + assert: aNode children second children first name + equals: (testParserMultipleChildren nameOf: 6). self - assert: - (testNodeMultipleChildren findParentOfIndex: 2) children first name - equals: (testNodeMultipleChildren findParentOfIndex: 3) name + assert: aNode children second children first children first name + equals: (testParserMultipleChildren nameOf: 7) ] { #category : #tests } TreeParserTest >> testIsLeaf [ - | family example | - family := testNodeSimple nodes. - example := (family firstChildrenOf: 2). + | example | + example := testNodeSimple firstChild firstChild. self assert: example isLeaf not. self assert: example isNotLeaf. @@ -383,45 +353,64 @@ TreeParserTest >> testIsLeaf [ self assert: example children first isNotLeaf not. ] +{ #category : #tests } +TreeParserTest >> testLastSpaceAt [ + + self assert: (testParserSimple lastSpaceAt: 0) isNil. + + self assert: (testParserSimple lastSpaceAt: 5) isNil. + + self assert: (testParserSimple lastSpaceAt: 1) equals: 86. + + self assert: (testParserSimple lastSpaceAt: 2) equals: 15. +] + { #category : #tests } TreeParserTest >> testNameOf [ "Limit cases" - self assert: (testNodeSimple nameOf: 0) isNil. + self assert: (testParserSimple nameOf: 0) isNil. - self assert: (testNodeSimple nameOf: 5) isNil. + self assert: (testParserSimple nameOf: 5) isNil. "Three cases where the parsing is different." - self assert: (testNodeSimple nameOf: 1) equals: 'entry_SYSCALL_64_after_hwframe'. + self assert: (testParserSimple nameOf: 1) equals: 'entry_SYSCALL_64_after_hwframe'. - self assert: (testNodeSamePercentage nameOf: 4) equals: '__x64_sys_read'. + self assert: (testParserSamePercentage nameOf: 4) equals: '__x64_sys_read'. - self assert: (testNodeSamePercentage nameOf: 6) equals: 'vfs_read' + self assert: (testParserSamePercentage nameOf: 6) equals: 'vfs_read' ] { #category : #tests } -TreeParserTest >> testNodes [ +TreeParserTest >> testNodeAtIndexWithParent [ + + self assert: (testParserSimple nodeAtIndex: 0 withParent: nil) isNil. - | family example | - family := testNodeMultipleChildren nodes. - example := (family firstChildrenOf: 2) children. + self assert: (testParserSimple nodeAtIndex: 5 withParent: nil) isNil. + "Needs more tests!!!" +] + +{ #category : #tests } +TreeParserTest >> testNodes [ + + | example | + example := testNodeMultipleChildren firstChild firstChild children. + self assert: example first name equals: '__x64_sys_read'. - + self assert: example second name equals: 'syscall_exit_to_user_mode'. - - self assert: example third name equals: '__x64_sys_openat'. - + + self assert: example third name equals: '__x64_sys_openat' ] { #category : #tests } TreeParserTest >> testNodesSameParent [ - | family example | - family := testNodeMultipleChildren nodes. - example := (family firstChildrenOf: 2) children. + | example | + example := (testNodeMultipleChildren firstChild firstChild) children. - self assert: family children first children first equals: example first parent. + self assert: testNodeMultipleChildren children first children first equals: example first parent. self assert: example first parent equals: example second parent ] @@ -429,109 +418,119 @@ TreeParserTest >> testNodesSameParent [ { #category : #tests } TreeParserTest >> testNumberOfFunctions [ - self assert: (testNodeSimple numberOfFunctions) equals: 4 + self assert: (testParserSimple numberOfFunctions) equals: 4 ] { #category : #tests } TreeParserTest >> testNumberOfSpacesAt [ - self assert: (testNodeSimple numberOfSpacesAt: 0) isZero. + self assert: (testParserSimple numberOfSpacesAt: 0) isZero. - self assert: (testNodeSimple numberOfSpacesAt: 5) isZero. + self assert: (testParserSimple numberOfSpacesAt: 5) isZero. - self assert: (testNodeSimple numberOfSpacesAt: 1) equals: 4 + self assert: (testParserSimple numberOfSpacesAt: 1) equals: 4. + + self assert: (testParserSimple numberOfSpacesAt: 3) equals: 16 ] { #category : #tests } TreeParserTest >> testPercentageOf [ "Limit cases" - self assert: (testNodeSimple percentageOf: 0) isZero. + self assert: (testParserSimple percentageOf: 0) isZero. - self assert: (testNodeSimple percentageOf: 5) isZero. + self assert: (testParserSimple percentageOf: 5) isZero. "Cases with 4 digits." - self assert: (testNodeSimple percentageOf: 3) equals: 45.91. - - self assert: (testNodeSimple percentageOf: 1) equals: 46.02. + self assert: (testParserSimple percentageOf: 3) equals: 45.91. + self assert: (testParserSimple percentageOf: 1) equals: 46.02. "Case with 3 digits." - self assert: (testNodeMultipleChildren percentageOf: 8) equals: 0.53. + self assert: (testParserMultipleChildren percentageOf: 8) equals: 0.53. "Case with same percentage" self - assert: (testNodeSamePercentage percentageOf: 4) - equals: (testNodeSamePercentage percentageOf: 5) + assert: (testParserSamePercentage percentageOf: 4) + equals: (testParserSamePercentage percentageOf: 5). + + self + assert: (testParserSamePercentage percentageOf: 5) + equals: (testParserSamePercentage percentageOf: 6) + ] { #category : #tests } TreeParserTest >> testReadLine [ "Limit cases." - self assert: (testNodeSimple readLine: 0) isNil. + self assert: (testParserSimple readLine: 0) isNil. - self assert: (testNodeSimple readLine: 5) isNil. + self assert: (testParserSimple readLine: 5) isNil. - self assert: (testNodeSimple readLine: 3) equals: ' --45.91%--do_syscall_64' + self assert: (testParserSimple readLine: 3) equals: ' --45.91%--do_syscall_64' ] { #category : #tests } TreeParserTest >> testRealPercentageOf [ "Limit cases." - self assert: (testNodeSimple realPercentageOf: 0) isZero. + self assert: (testParserSimple realPercentageOf: 0) isZero. - self assert: (testNodeSimple realPercentageOf: 5) isZero. + self assert: (testParserSimple realPercentageOf: 5) isZero. self - assert: (testNodeSamePercentage realPercentageOf: 3) + assert: (testParserSamePercentage realPercentageOf: 3) equals: 9.13. - self assert: (testNodeSamePercentage realPercentageOf: 4) equals: 0.0 + self assert: (testParserSamePercentage realPercentageOf: 4) equals: 0.0 ] { #category : #tests } TreeParserTest >> testTime [ - self assert: testNodeSimple time equals: 397.0. + self assert: testParserSimple time equals: 397.592. - self assert: testNodeSimple nodes time equals: 397.0. + self assert: testParserSimple root time equals: 397.592. ] { #category : #tests } TreeParserTest >> testTraces [ - | family traces | - family := testNodeSimple nodes. - traces := family traces. + | traces | + traces := testNodeSimple traces. self assert: traces size equals: 1. self assert: traces first name equals: '__x64_sys_read'. - self assert: traces first weight equals: 146.02. + self assert: traces first weight equals: 146.24. ] { #category : #tests } TreeParserTest >> testWeight [ - | family example | - family := testNodeMultipleChildren nodes. - example := family firstChildrenOf: 2. + | example | + example := testNodeMultipleChildren firstChild firstChild. - self assert: example weight equals: 6.83. + self assert: example weight equals: 6.84. ] { #category : #tests } TreeParserTest >> testWeightOf [ "Limit cases" - self assert: (testNodeSimple weightOf: 0) isZero. + self assert: (testParserSimple weightOf: 0) isZero. - self assert: (testNodeSimple weightOf: 5) isZero. + self assert: (testParserSimple weightOf: 5) isZero. "Classical case" - self assert: (testNodeSimple weightOf: 3) equals: 36.25. + self assert: (testParserSimple weightOf: 3) equals: 36.31. +] + +{ #category : #tests } +TreeParserTest >> testWithoutSpaces [ + + self assert: (testParserMultipleChildren withoutSpaces at: 6) equals: '--6.86%--arch_do_signal_or_restart' ] diff --git a/src/TreeParser/TreeNode.class.st b/src/TreeParser/TreeNode.class.st index da6d95c..14ff1d2 100644 --- a/src/TreeParser/TreeNode.class.st +++ b/src/TreeParser/TreeNode.class.st @@ -24,35 +24,31 @@ TreeNode >> children: aCollectionOfTreeNode [ ] { #category : #accessing } -TreeNode >> firstChildrenOf: aNumber [ - "Gives the children of the first children of each generations a given times." +TreeNode >> collectLeavesIn: leaves [ - | child | - child := self. - 1 to: aNumber do: [ :c | child := child children first ]. - ^ child + self isLeaf ifTrue: [ + leaves add: self. + ^ leaves ]. + + ^ self children collect: [ :child | child collectLeavesIn: leaves ] ] { #category : #accessing } -TreeNode >> isLeaf [ +TreeNode >> firstChild [ - ^ self children isEmpty + ^ self children first ] { #category : #accessing } -TreeNode >> isNotLeaf [ +TreeNode >> isLeaf [ - ^ self children isNotEmpty + ^ self children isEmpty ] { #category : #accessing } -TreeNode >> leaves: leaves [ - - self isLeaf ifTrue: [ - leaves add: self. - ^ leaves ]. +TreeNode >> isNotLeaf [ - ^ self children collect: [ :child | child leaves: leaves ] + ^ self children isNotEmpty ] { #category : #accessing } @@ -96,7 +92,7 @@ TreeNode >> traces [ | leaves | leaves := OrderedCollection new. - self leaves: leaves. + self collectLeavesIn: leaves. ^ leaves collect: [ :l | TreeTrace new diff --git a/src/TreeParser/TreeParser.class.st b/src/TreeParser/TreeParser.class.st index 2dc62ef..031f590 100644 --- a/src/TreeParser/TreeParser.class.st +++ b/src/TreeParser/TreeParser.class.st @@ -16,6 +16,12 @@ TreeParser class >> fromFile: aFile [ yourself ] +{ #category : #'instance creation' } +TreeParser class >> parseFile: aFile [ + + ^ (self fromFile: aFile) root +] + { #category : #accessing } TreeParser >> content [ @@ -26,13 +32,16 @@ TreeParser >> content [ TreeParser >> content: aFile [ "Extract the interesting content from the file." - | timeFromFile fileContents | - fileContents := aFile contents. + | fileContents i | + fileContents := aFile contents lines. + i := 1. - timeFromFile := (fileContents lines at: 24) asInteger. - self time: timeFromFile asFloat. + [ (fileContents at: i) beginsWith: '# sample duration' ] whileFalse: [ + i := i + 1 ]. - content := fileContents lines reject: [ :line | line beginsWith: '#' ]. + self time: (((fileContents at: i) last: 10) first: 7) asNumber. + + content := fileContents reject: [ :line | line beginsWith: '#' ]. content := content select: [ :line | ((line copyWithout: Character space) copyWithout: $|) isNotEmpty ] @@ -42,9 +51,11 @@ TreeParser >> content: aFile [ TreeParser >> differenceOfSpacesAt: aNodeIndex [ "Gives the difference of the number of spaces between 2 followed lines." - (aNodeIndex between: 1 and: self numberOfFunctions - 1) ifTrue: [ - ^ (self numberOfSpacesAt: aNodeIndex + 1) - - (self numberOfSpacesAt: aNodeIndex) ] + ^ (aNodeIndex between: 1 and: self numberOfFunctions) + ifTrue: [ + (self numberOfSpacesAt: aNodeIndex + 1) + - (self numberOfSpacesAt: aNodeIndex) ] + ifFalse: [ ^ 0 ] ] { #category : #accessing } @@ -78,42 +89,12 @@ TreeParser >> findChildrenOfIndex: aNodeIndex [ | collectionOfChildrenIndexes | collectionOfChildrenIndexes := self findChildrenIndexOfIndex: aNodeIndex. ^ collectionOfChildrenIndexes collect: [ :childIndex | - self nodeAtIndex: childIndex withParent: self ] -] - -{ #category : #accessing } -TreeParser >> findParentIndexOfIndex: aNodeIndex [ - "Gives the index of the line where the parent is." - - | i size | - size := self numberOfFunctions. - - i := aNodeIndex - 1. - [ - (i between: 1 and: size) and: [ - (self numberOfSpacesAt: aNodeIndex) - (self numberOfSpacesAt: i) - <= 0 ] ] whileTrue: [ i := i - 1 ]. - - (i > 0 and: i <= self numberOfFunctions) - ifTrue: [ ^ i ] - ifFalse: [ ^ 0 ] -] - -{ #category : #accessing } -TreeParser >> findParentOfIndex: aNodeIndex [ - "Gives the node representing the parent of the node at aNodeIndex." - - | parentIndex parent | - parentIndex := self findParentIndexOfIndex: aNodeIndex. - parent := (aNodeIndex - 1 between: 1 and: self numberOfFunctions) - ifTrue: [ self findParentOfIndex: aNodeIndex - 1 ] - ifFalse: [ nil ]. - ^ self nodeAtIndex: parentIndex withParent: parent + self nodeAtIndex: childIndex withParent: nil ] ] { #category : #accessing } TreeParser >> lastSpaceAt: aLine [ - "Gives the index of the last space at a given line." + "Gives the index of the last space or '-' at a given line." | lastSpace line | (aLine between: 1 and: self numberOfFunctions) ifFalse: [ ^ nil ]. @@ -123,7 +104,7 @@ TreeParser >> lastSpaceAt: aLine [ 1 to: line size do: [ :i | ((line at: i) = Character space or: [ (line at: i) = $- ]) ifTrue: [ - lastSpace := line size - i ] ]. + lastSpace := i ] ]. ^ lastSpace ] @@ -134,8 +115,8 @@ TreeParser >> nameOf: aNodeIndex [ | aLine | (aNodeIndex between: 1 and: self numberOfFunctions) ifFalse: [ ^ nil ]. - aLine := (self withoutSpaces at: aNodeIndex) copyWithout: $-. - ^ aLine last: (self lastSpaceAt: aNodeIndex) + aLine := self readLine: aNodeIndex. + ^ aLine last: aLine size - (self lastSpaceAt: aNodeIndex) ] { #category : #accessing } @@ -156,13 +137,6 @@ TreeParser >> nodeAtIndex: aNodeIndex withParent: aTreeNode [ ^ child ] -{ #category : #accessing } -TreeParser >> nodes [ - "Gives the first parent of the nodes" - - ^ (self nodeAtIndex: 1 withParent: nil) -] - { #category : #accessing } TreeParser >> numberOfFunctions [ "Gives the number of functions present in the file." @@ -180,7 +154,7 @@ TreeParser >> numberOfSpacesAt: aNodeIndex [ (aNodeIndex between: 1 and: self numberOfFunctions) ifFalse: [ ^ 0 ]. - (self content at: aNodeIndex) do: [ :c | + (self readLine: aNodeIndex) do: [ :c | (c ~= Character space and: [ c ~= $| ]) ifFalse: [ spacesAreEnded ifFalse: [ count := count + 1 ] ] ifTrue: [ spacesAreEnded := true ] ]. @@ -193,18 +167,18 @@ TreeParser >> percentageOf: aLine [ "In the case of multiples functions for one percentage, it gives the same percentage to every functions." - | numbers | + | stringLine numbers | (aLine between: 1 and: self numberOfFunctions) ifFalse: [ ^ 0 ]. - numbers := (((self withoutSpaces at: aLine) copyWithout: $-) first: 5) - select: [ :c | - { $0. $1. $2. $3. $4. $5. $6. $7. $8. $9 } asSet - includes: c ]. - (aLine > 1 and: [ numbers isEmpty ]) ifTrue: [ + stringLine := ((self content at: aLine) copyUpTo: $%) last: 5. + + stringLine = ((self content at: aLine) last: 5) ifTrue: [ ^ self percentageOf: aLine - 1 ]. - numbers size >= 4 - ifTrue: [ ^ ((numbers first: 4) asInteger / 100) asFloat ] - ifFalse: [ ^ ((numbers first: 3) asInteger / 100) asFloat ] + + numbers := stringLine asNumber. + numbers < 0 ifTrue: [ numbers := numbers negated ]. + + ^ numbers ] { #category : #accessing } @@ -233,6 +207,13 @@ TreeParser >> realPercentageOf: aNodeIndex [ 0.01 ] +{ #category : #accessing } +TreeParser >> root [ + "Gives the first parent of the nodes" + + ^ self nodeAtIndex: 1 withParent: nil +] + { #category : #accessing } TreeParser >> time [ @@ -249,10 +230,9 @@ TreeParser >> time: aFloat [ TreeParser >> weightOf: aNodeIndex [ | newPercentage | - (aNodeIndex between: 1 and: self numberOfFunctions) ifFalse: [ ^ 0 ]. newPercentage := self realPercentageOf: aNodeIndex. - ^ totalTime * (newPercentage / 100) asFloat roundUpTo: 0.01 + ^ totalTime * (newPercentage/100) roundUpTo: 0.01 ] { #category : #accessing } From a8f339167c73826fa8d8f5422a031ebe008b9481 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=A9o=20Boury?= Date: Thu, 6 Jun 2024 12:37:36 +0200 Subject: [PATCH 04/29] Changed methods and improved the mutation score Replaced `nodeAtIndex:withParent:` for `nodeAtIndex:` as giving the information of who is the parent is actually useless Simplified `numberOfSpacesAt` Removed useless conditions in `findChildrenIndexOfIndex:` --- src/TreeParser-Tests/TreeParserTest.class.st | 28 +++++++-------- src/TreeParser/TreeParser.class.st | 36 ++++++++++---------- 2 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/TreeParser-Tests/TreeParserTest.class.st b/src/TreeParser-Tests/TreeParserTest.class.st index 4275913..2e111af 100644 --- a/src/TreeParser-Tests/TreeParserTest.class.st +++ b/src/TreeParser-Tests/TreeParserTest.class.st @@ -269,9 +269,9 @@ TreeParserTest >> tearDown [ { #category : #tests } TreeParserTest >> testDifferenceOfSpacesAt [ - self assert: (testParserSimple differenceOfSpacesAt: 0) isZero. + self assert: (testParserSimple differenceOfSpacesAt: 0) isNil. - self assert: (testParserSimple differenceOfSpacesAt: 5) isZero. + self assert: (testParserSimple differenceOfSpacesAt: (testParserSimple numberOfFunctions + 1)) isNil. "Classical case" self assert: (testParserSamePercentage differenceOfSpacesAt: 6) equals: 1. @@ -287,11 +287,11 @@ TreeParserTest >> testFindChildrenIndexOfIndex [ self assert: (testParserSimple findChildrenIndexOfIndex: 0) isZero. - self assert: (testParserSimple findChildrenIndexOfIndex: 5) isZero. + self assert: (testParserSimple findChildrenIndexOfIndex: (testParserSimple numberOfFunctions + 1)) isZero. "The last has no children" - self assert: (testParserSimple findChildrenIndexOfIndex: 4) isEmpty. + self assert: (testParserSimple findChildrenIndexOfIndex: (testParserSimple numberOfFunctions)) isEmpty. "Case where 2 functions have the same number of spaces." self @@ -358,7 +358,7 @@ TreeParserTest >> testLastSpaceAt [ self assert: (testParserSimple lastSpaceAt: 0) isNil. - self assert: (testParserSimple lastSpaceAt: 5) isNil. + self assert: (testParserSimple lastSpaceAt: (testParserSimple numberOfFunctions + 1)) isNil. self assert: (testParserSimple lastSpaceAt: 1) equals: 86. @@ -371,7 +371,7 @@ TreeParserTest >> testNameOf [ "Limit cases" self assert: (testParserSimple nameOf: 0) isNil. - self assert: (testParserSimple nameOf: 5) isNil. + self assert: (testParserSimple nameOf: (testParserSimple numberOfFunctions + 1)) isNil. "Three cases where the parsing is different." self assert: (testParserSimple nameOf: 1) equals: 'entry_SYSCALL_64_after_hwframe'. @@ -382,11 +382,11 @@ TreeParserTest >> testNameOf [ ] { #category : #tests } -TreeParserTest >> testNodeAtIndexWithParent [ +TreeParserTest >> testNodeAtIndex [ - self assert: (testParserSimple nodeAtIndex: 0 withParent: nil) isNil. + self assert: (testParserSimple nodeAtIndex: 0) isNil. - self assert: (testParserSimple nodeAtIndex: 5 withParent: nil) isNil. + self assert: (testParserSimple nodeAtIndex: (testParserSimple numberOfFunctions + 1)) isNil. "Needs more tests!!!" ] @@ -427,7 +427,7 @@ TreeParserTest >> testNumberOfSpacesAt [ self assert: (testParserSimple numberOfSpacesAt: 0) isZero. - self assert: (testParserSimple numberOfSpacesAt: 5) isZero. + self assert: (testParserSimple numberOfSpacesAt: (testParserSimple numberOfFunctions + 1)) isZero. self assert: (testParserSimple numberOfSpacesAt: 1) equals: 4. @@ -440,7 +440,7 @@ TreeParserTest >> testPercentageOf [ self assert: (testParserSimple percentageOf: 0) isZero. - self assert: (testParserSimple percentageOf: 5) isZero. + self assert: (testParserSimple percentageOf: (testParserSimple numberOfFunctions + 1)) isZero. "Cases with 4 digits." self assert: (testParserSimple percentageOf: 3) equals: 45.91. @@ -467,7 +467,7 @@ TreeParserTest >> testReadLine [ "Limit cases." self assert: (testParserSimple readLine: 0) isNil. - self assert: (testParserSimple readLine: 5) isNil. + self assert: (testParserSimple readLine: (testParserSimple numberOfFunctions + 1)) isNil. self assert: (testParserSimple readLine: 3) equals: ' --45.91%--do_syscall_64' ] @@ -478,7 +478,7 @@ TreeParserTest >> testRealPercentageOf [ "Limit cases." self assert: (testParserSimple realPercentageOf: 0) isZero. - self assert: (testParserSimple realPercentageOf: 5) isZero. + self assert: (testParserSimple realPercentageOf: (testParserSimple numberOfFunctions + 1)) isZero. self assert: (testParserSamePercentage realPercentageOf: 3) @@ -523,7 +523,7 @@ TreeParserTest >> testWeightOf [ "Limit cases" self assert: (testParserSimple weightOf: 0) isZero. - self assert: (testParserSimple weightOf: 5) isZero. + self assert: (testParserSimple weightOf: (testParserSimple numberOfFunctions + 1)) isZero. "Classical case" self assert: (testParserSimple weightOf: 3) equals: 36.31. diff --git a/src/TreeParser/TreeParser.class.st b/src/TreeParser/TreeParser.class.st index 031f590..52fc904 100644 --- a/src/TreeParser/TreeParser.class.st +++ b/src/TreeParser/TreeParser.class.st @@ -52,10 +52,10 @@ TreeParser >> differenceOfSpacesAt: aNodeIndex [ "Gives the difference of the number of spaces between 2 followed lines." ^ (aNodeIndex between: 1 and: self numberOfFunctions) + ifFalse: [ nil ] ifTrue: [ (self numberOfSpacesAt: aNodeIndex + 1) - (self numberOfSpacesAt: aNodeIndex) ] - ifFalse: [ ^ 0 ] ] { #category : #accessing } @@ -66,7 +66,6 @@ TreeParser >> findChildrenIndexOfIndex: aNode [ lastNode := self numberOfFunctions. everyChildren := OrderedCollection new. - aNode = lastNode ifTrue: [ ^ everyChildren ]. (aNode between: 1 and: lastNode) ifFalse: [ ^ 0 ]. (((self differenceOfSpacesAt: aNode) between: 1 and: 10) or: [ @@ -89,7 +88,7 @@ TreeParser >> findChildrenOfIndex: aNodeIndex [ | collectionOfChildrenIndexes | collectionOfChildrenIndexes := self findChildrenIndexOfIndex: aNodeIndex. ^ collectionOfChildrenIndexes collect: [ :childIndex | - self nodeAtIndex: childIndex withParent: nil ] + self nodeAtIndex: childIndex ] ] { #category : #accessing } @@ -100,7 +99,7 @@ TreeParser >> lastSpaceAt: aLine [ (aLine between: 1 and: self numberOfFunctions) ifFalse: [ ^ nil ]. line := self readLine: aLine. - lastSpace := line size. + lastSpace := 0. 1 to: line size do: [ :i | ((line at: i) = Character space or: [ (line at: i) = $- ]) ifTrue: [ @@ -120,7 +119,7 @@ TreeParser >> nameOf: aNodeIndex [ ] { #category : #accessing } -TreeParser >> nodeAtIndex: aNodeIndex withParent: aTreeNode [ +TreeParser >> nodeAtIndex: aNodeIndex [ "Gives the node representing the node at aNodeIndex." | child | @@ -130,7 +129,6 @@ TreeParser >> nodeAtIndex: aNodeIndex withParent: aTreeNode [ name: (self nameOf: aNodeIndex); weight: (self weightOf: aNodeIndex); time: self time; - parent: aTreeNode; yourself. child children: (self findChildrenOfIndex: aNodeIndex). child children do: [ :grandchild | grandchild parent: child ]. @@ -148,17 +146,18 @@ TreeParser >> numberOfFunctions [ TreeParser >> numberOfSpacesAt: aNodeIndex [ "Gives the number of spaces at a certain line." - | count spacesAreEnded | + | count lineRead | count := 0. - spacesAreEnded := false. - - (aNodeIndex between: 1 and: self numberOfFunctions) ifFalse: [ ^ 0 ]. - - (self readLine: aNodeIndex) do: [ :c | - (c ~= Character space and: [ c ~= $| ]) - ifFalse: [ spacesAreEnded ifFalse: [ count := count + 1 ] ] - ifTrue: [ spacesAreEnded := true ] ]. - ^ count + + (aNodeIndex between: 1 and: self numberOfFunctions) ifFalse: [ + ^ count ]. + + lineRead := self readLine: aNodeIndex. + count := 1. + + [(lineRead at: count) = Character space or: [ + (lineRead at: count) = $| ] ] whileTrue: [ count := count + 1 ]. + ^ count - 1 ] { #category : #accessing } @@ -195,8 +194,9 @@ TreeParser >> realPercentageOf: aNodeIndex [ | children childrenPercentage | children := self findChildrenIndexOfIndex: aNodeIndex. - children isCollection ifFalse: [ ^ 0 ]. childrenPercentage := 0. + children isCollection ifFalse: [ ^ self percentageOf: aNodeIndex ]. + 1 to: children size do: [ :childIndex | childrenPercentage := childrenPercentage @@ -211,7 +211,7 @@ TreeParser >> realPercentageOf: aNodeIndex [ TreeParser >> root [ "Gives the first parent of the nodes" - ^ self nodeAtIndex: 1 withParent: nil + ^ self nodeAtIndex: 1 ] { #category : #accessing } From 64cc4fec67820a8b977e1a85738228ac3624750d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=A9o=20Boury?= <39924046+matburnx@users.noreply.github.com> Date: Thu, 6 Jun 2024 12:42:03 +0000 Subject: [PATCH 05/29] Update smalltalkCI.yml Renamed the CI The CI now ignores when non-code files are modified by pushes or PR --- .github/workflows/smalltalkCI.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/smalltalkCI.yml b/.github/workflows/smalltalkCI.yml index fe86f88..cc9a259 100644 --- a/.github/workflows/smalltalkCI.yml +++ b/.github/workflows/smalltalkCI.yml @@ -1,14 +1,20 @@ # This is a basic workflow to help you get started with Actions -name: CI +name: pharoCI # Controls when the workflow will run on: # Triggers the workflow on push or pull request events but only for the "main" branch push: branches: [ "main" ] + paths-ignore: + - 'README.md' + - 'resources/**' pull_request: branches: [ "main" ] + paths-ignore: + - 'README.md' + - 'resources/**' # Allows you to run this workflow manually from the Actions tab workflow_dispatch: From c592815709d7c07f9f252001396e278de92563b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=A9o=20Boury?= <39924046+matburnx@users.noreply.github.com> Date: Thu, 6 Jun 2024 12:46:05 +0000 Subject: [PATCH 06/29] Create mutalkCI.yml First try to integrate mutalkCI to the repo to have a mutation score after each push or PR --- .github/workflows/mutalkCI.yml | 86 ++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 .github/workflows/mutalkCI.yml diff --git a/.github/workflows/mutalkCI.yml b/.github/workflows/mutalkCI.yml new file mode 100644 index 0000000..82e9682 --- /dev/null +++ b/.github/workflows/mutalkCI.yml @@ -0,0 +1,86 @@ +name: MutalkCI + +on: + push: + branches: [ master ] + paths-ignore: + - 'README.md' + - 'resources/**' + pull_request: + branches: [ master ] + paths-ignore: + - 'README.md' + - 'resources/**' + + workflow_dispatch: + inputs: + mode: + description: 'modes: full (run on all project), diff (run on the last commit diff), commit (especify a commit to calculate diff)' + required: true + default: 'diff' + commit: + description: 'If mode == commit, here you enter the Commid id/name/shortId to evaluate the diff' + required: false + default: '' + +jobs: + eventBased: + runs-on: ubuntu-latest + if: github.event_name != 'workflow_dispatch' + steps: + - uses: actions/checkout@v2 + + - uses: hpi-swa/setup-smalltalkCI@v1 + id: smalltalkci + with: + smalltalk-version: Pharo64-stable + + - run: smalltalkci -s ${{ steps.smalltalkci.outputs.smalltalk-version }} + shell: bash + timeout-minutes: 15 + + - run: ${{env.SMALLTALK_CI_VM}} ${{env.SMALLTALK_CI_IMAGE}} metacello install "github://pavel-krivanek/mutalk/src" BaselineOfMuTalk + shell: bash + + - run: ${{env.SMALLTALK_CI_VM}} ${{env.SMALLTALK_CI_IMAGE}} mutalk --project=${{github.event.repository.name}} --diff + shell: bash + + - uses: actions/upload-artifact@v2 + with: + name: mutation-testing-output + path: ${{env.SMALLTALK_CI_BUILD_BASE}}/__mutalk_export.json + + manual: + runs-on: ubuntu-latest + if: github.event_name == 'workflow_dispatch' + steps: + - uses: actions/checkout@v2 + + - uses: hpi-swa/setup-smalltalkCI@v1 + id: smalltalkci + with: + smalltalk-version: Pharo64-stable + + - run: smalltalkci -s ${{ steps.smalltalkci.outputs.smalltalk-version }} + shell: bash + timeout-minutes: 15 + + - run: ${{env.SMALLTALK_CI_VM}} ${{env.SMALLTALK_CI_IMAGE}} metacello install "github://pavel-krivanek/mutalk/src" BaselineOfMuTalk + shell: bash + + - name: full mutation testing + if: github.event.inputs.mode == 'full' + run: ${{env.SMALLTALK_CI_VM}} ${{env.SMALLTALK_CI_IMAGE}} mutalk --project=${{github.event.repository.name}} + + - name: diff mutation testing + if: github.event.inputs.mode == 'diff' + run: ${{env.SMALLTALK_CI_VM}} ${{env.SMALLTALK_CI_IMAGE}} mutalk --project=${{github.event.repository.name}} --diff + + - name: commit mutation testing + if: github.event.inputs.mode == 'commit' + run: ${{env.SMALLTALK_CI_VM}} ${{env.SMALLTALK_CI_IMAGE}} mutalk --project=${{github.event.repository.name}} --commit=${{github.event.inputs.commit}} + + - uses: actions/upload-artifact@v2 + with: + name: mutation-testing-output + path: ${{env.SMALLTALK_CI_BUILD_BASE}}/__mutalk_export.json From 65a4c9d26bfa4113c6716825f202eb8b1b374ef9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=A9o=20Boury?= <39924046+matburnx@users.noreply.github.com> Date: Thu, 6 Jun 2024 12:48:35 +0000 Subject: [PATCH 07/29] Update mutalkCI.yml --- .github/workflows/mutalkCI.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/mutalkCI.yml b/.github/workflows/mutalkCI.yml index 82e9682..c141cca 100644 --- a/.github/workflows/mutalkCI.yml +++ b/.github/workflows/mutalkCI.yml @@ -2,12 +2,12 @@ name: MutalkCI on: push: - branches: [ master ] + branches: [ main ] paths-ignore: - 'README.md' - 'resources/**' pull_request: - branches: [ master ] + branches: [ main ] paths-ignore: - 'README.md' - 'resources/**' From b7fab39c8219ca34bb4b696198dd5151b6373ea0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=A9o=20Boury?= <39924046+matburnx@users.noreply.github.com> Date: Thu, 6 Jun 2024 12:59:14 +0000 Subject: [PATCH 08/29] Update mutalkCI.yml --- .github/workflows/mutalkCI.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/mutalkCI.yml b/.github/workflows/mutalkCI.yml index c141cca..6806260 100644 --- a/.github/workflows/mutalkCI.yml +++ b/.github/workflows/mutalkCI.yml @@ -42,7 +42,7 @@ jobs: - run: ${{env.SMALLTALK_CI_VM}} ${{env.SMALLTALK_CI_IMAGE}} metacello install "github://pavel-krivanek/mutalk/src" BaselineOfMuTalk shell: bash - - run: ${{env.SMALLTALK_CI_VM}} ${{env.SMALLTALK_CI_IMAGE}} mutalk --project=${{github.event.repository.name}} --diff + - run: ${{env.SMALLTALK_CI_VM}} ${{env.SMALLTALK_CI_IMAGE}} mutalk --project=${{github.event.repository.name}} shell: bash - uses: actions/upload-artifact@v2 From bbd09814c094005642a7b1ddf5c1dcf9b45c4b76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=A9o=20Boury?= <39924046+matburnx@users.noreply.github.com> Date: Thu, 6 Jun 2024 13:09:04 +0000 Subject: [PATCH 09/29] Update mutalkCI.yml --- .github/workflows/mutalkCI.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/mutalkCI.yml b/.github/workflows/mutalkCI.yml index 6806260..866311c 100644 --- a/.github/workflows/mutalkCI.yml +++ b/.github/workflows/mutalkCI.yml @@ -39,7 +39,7 @@ jobs: shell: bash timeout-minutes: 15 - - run: ${{env.SMALLTALK_CI_VM}} ${{env.SMALLTALK_CI_IMAGE}} metacello install "github://pavel-krivanek/mutalk/src" BaselineOfMuTalk + - run: ${{env.SMALLTALK_CI_VM}} ${{env.SMALLTALK_CI_IMAGE}} metacello install "github://pharo-contributions/mutalk/src" BaselineOfMuTalk shell: bash - run: ${{env.SMALLTALK_CI_VM}} ${{env.SMALLTALK_CI_IMAGE}} mutalk --project=${{github.event.repository.name}} @@ -65,7 +65,7 @@ jobs: shell: bash timeout-minutes: 15 - - run: ${{env.SMALLTALK_CI_VM}} ${{env.SMALLTALK_CI_IMAGE}} metacello install "github://pavel-krivanek/mutalk/src" BaselineOfMuTalk + - run: ${{env.SMALLTALK_CI_VM}} ${{env.SMALLTALK_CI_IMAGE}} metacello install "github://pharo-contributions/mutalk/src" BaselineOfMuTalk shell: bash - name: full mutation testing From a0e90cb1e91f85617e0a32f6ed4a9122c6b067a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=A9o=20Boury?= <39924046+matburnx@users.noreply.github.com> Date: Thu, 6 Jun 2024 13:25:18 +0000 Subject: [PATCH 10/29] Update mutalkCI.yml --- .github/workflows/mutalkCI.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/mutalkCI.yml b/.github/workflows/mutalkCI.yml index 866311c..9c059a2 100644 --- a/.github/workflows/mutalkCI.yml +++ b/.github/workflows/mutalkCI.yml @@ -42,7 +42,7 @@ jobs: - run: ${{env.SMALLTALK_CI_VM}} ${{env.SMALLTALK_CI_IMAGE}} metacello install "github://pharo-contributions/mutalk/src" BaselineOfMuTalk shell: bash - - run: ${{env.SMALLTALK_CI_VM}} ${{env.SMALLTALK_CI_IMAGE}} mutalk --project=${{github.event.repository.name}} + - run: ${{env.SMALLTALK_CI_VM}} ${{env.SMALLTALK_CI_IMAGE}} mutalk --project=TreeParser shell: bash - uses: actions/upload-artifact@v2 From 075f80a12a237ef613934acd2ea34cf3502da711 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=A9o=20Boury?= <39924046+matburnx@users.noreply.github.com> Date: Thu, 6 Jun 2024 13:31:33 +0000 Subject: [PATCH 11/29] Update mutalkCI.yml --- .github/workflows/mutalkCI.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/mutalkCI.yml b/.github/workflows/mutalkCI.yml index 9c059a2..a838542 100644 --- a/.github/workflows/mutalkCI.yml +++ b/.github/workflows/mutalkCI.yml @@ -42,7 +42,7 @@ jobs: - run: ${{env.SMALLTALK_CI_VM}} ${{env.SMALLTALK_CI_IMAGE}} metacello install "github://pharo-contributions/mutalk/src" BaselineOfMuTalk shell: bash - - run: ${{env.SMALLTALK_CI_VM}} ${{env.SMALLTALK_CI_IMAGE}} mutalk --project=TreeParser + - run: ${{env.SMALLTALK_CI_VM}} ${{env.SMALLTALK_CI_IMAGE}} mutalk --project=XCTrace shell: bash - uses: actions/upload-artifact@v2 From f9a69d3aa17cbc44b1ba300263b2a304a27c6088 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=A9o=20Boury?= <39924046+matburnx@users.noreply.github.com> Date: Thu, 6 Jun 2024 13:34:13 +0000 Subject: [PATCH 12/29] Update mutalkCI.yml Changed `smalltalk-version` to `smalltalk-image` --- .github/workflows/mutalkCI.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/mutalkCI.yml b/.github/workflows/mutalkCI.yml index a838542..26fdbef 100644 --- a/.github/workflows/mutalkCI.yml +++ b/.github/workflows/mutalkCI.yml @@ -33,9 +33,9 @@ jobs: - uses: hpi-swa/setup-smalltalkCI@v1 id: smalltalkci with: - smalltalk-version: Pharo64-stable + smalltalk-image: Pharo64-stable - - run: smalltalkci -s ${{ steps.smalltalkci.outputs.smalltalk-version }} + - run: smalltalkci -s ${{ steps.smalltalkci.outputs.smalltalk-image }} shell: bash timeout-minutes: 15 @@ -59,9 +59,9 @@ jobs: - uses: hpi-swa/setup-smalltalkCI@v1 id: smalltalkci with: - smalltalk-version: Pharo64-stable + smalltalk-image: Pharo64-stable - - run: smalltalkci -s ${{ steps.smalltalkci.outputs.smalltalk-version }} + - run: smalltalkci -s ${{ steps.smalltalkci.outputs.smalltalk-image }} shell: bash timeout-minutes: 15 From 395bdcfcd5fbf5fde4a76a75a8a2cfc5fca69fe1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=A9o=20Boury?= <39924046+matburnx@users.noreply.github.com> Date: Thu, 6 Jun 2024 13:40:35 +0000 Subject: [PATCH 13/29] Update mutalkCI.yml --- .github/workflows/mutalkCI.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/mutalkCI.yml b/.github/workflows/mutalkCI.yml index 26fdbef..cc49875 100644 --- a/.github/workflows/mutalkCI.yml +++ b/.github/workflows/mutalkCI.yml @@ -42,7 +42,7 @@ jobs: - run: ${{env.SMALLTALK_CI_VM}} ${{env.SMALLTALK_CI_IMAGE}} metacello install "github://pharo-contributions/mutalk/src" BaselineOfMuTalk shell: bash - - run: ${{env.SMALLTALK_CI_VM}} ${{env.SMALLTALK_CI_IMAGE}} mutalk --project=XCTrace + - run: ${{env.SMALLTALK_CI_VM}} ${{env.SMALLTALK_CI_IMAGE}} mutalk --project=${{github.event.repository.name}} shell: bash - uses: actions/upload-artifact@v2 From 577a478d5060807d1124dceb7792089bd5b5aa81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=A9o=20Boury?= Date: Fri, 7 Jun 2024 11:10:03 +0200 Subject: [PATCH 14/29] Renamed packages and classes to `PerfTree` instead of `Tree` --- .../BaselineOfPerfTreeParser.class.st | 20 +++++++ src/BaselineOfPerfTreeParser/package.st | 1 + .../BaselineOfTreeParser.class.st | 20 ------- src/BaselineOfTreeParser/package.st | 1 - .../PerfTreeParserTest.class.st} | 60 +++++++++---------- src/PerfTreeParser-Tests/package.st | 1 + .../PerfTreeNode.class.st} | 36 +++++------ .../PerfTreeParser.class.st} | 46 +++++++------- .../PerfTreeTrace.class.st} | 12 ++-- src/PerfTreeParser/package.st | 1 + src/TreeParser-Tests/package.st | 1 - src/TreeParser/package.st | 1 - 12 files changed, 100 insertions(+), 100 deletions(-) create mode 100644 src/BaselineOfPerfTreeParser/BaselineOfPerfTreeParser.class.st create mode 100644 src/BaselineOfPerfTreeParser/package.st delete mode 100644 src/BaselineOfTreeParser/BaselineOfTreeParser.class.st delete mode 100644 src/BaselineOfTreeParser/package.st rename src/{TreeParser-Tests/TreeParserTest.class.st => PerfTreeParser-Tests/PerfTreeParserTest.class.st} (93%) create mode 100644 src/PerfTreeParser-Tests/package.st rename src/{TreeParser/TreeNode.class.st => PerfTreeParser/PerfTreeNode.class.st} (67%) rename src/{TreeParser/TreeParser.class.st => PerfTreeParser/PerfTreeParser.class.st} (85%) rename src/{TreeParser/TreeTrace.class.st => PerfTreeParser/PerfTreeTrace.class.st} (59%) create mode 100644 src/PerfTreeParser/package.st delete mode 100644 src/TreeParser-Tests/package.st delete mode 100644 src/TreeParser/package.st diff --git a/src/BaselineOfPerfTreeParser/BaselineOfPerfTreeParser.class.st b/src/BaselineOfPerfTreeParser/BaselineOfPerfTreeParser.class.st new file mode 100644 index 0000000..2606b70 --- /dev/null +++ b/src/BaselineOfPerfTreeParser/BaselineOfPerfTreeParser.class.st @@ -0,0 +1,20 @@ +Class { + #name : #BaselineOfPerfTreeParser, + #superclass : #BaselineOf, + #category : #BaselineOfPerfTreeParser +} + +{ #category : #baselines } +BaselineOfPerfTreeParser >> baseline: spec [ + + spec for: #common do: [ + "Packages" + spec + package: #PerfTreeParser; + package: 'PerfTreeParser-Tests' with: [ spec requires: #PerfTreeParser ] ] +] + +{ #category : #accessing } +BaselineOfPerfTreeParser >> projectClass [ + ^ MetacelloCypressBaselineProject +] diff --git a/src/BaselineOfPerfTreeParser/package.st b/src/BaselineOfPerfTreeParser/package.st new file mode 100644 index 0000000..2dc44c9 --- /dev/null +++ b/src/BaselineOfPerfTreeParser/package.st @@ -0,0 +1 @@ +Package { #name : #BaselineOfPerfTreeParser } diff --git a/src/BaselineOfTreeParser/BaselineOfTreeParser.class.st b/src/BaselineOfTreeParser/BaselineOfTreeParser.class.st deleted file mode 100644 index be5629d..0000000 --- a/src/BaselineOfTreeParser/BaselineOfTreeParser.class.st +++ /dev/null @@ -1,20 +0,0 @@ -Class { - #name : #BaselineOfTreeParser, - #superclass : #BaselineOf, - #category : #BaselineOfTreeParser -} - -{ #category : #baselines } -BaselineOfTreeParser >> baseline: spec [ - - spec for: #common do: [ - "Packages" - spec - package: #TreeParser; - package: 'TreeParser-Tests' with: [ spec requires: #TreeParser ] ] -] - -{ #category : #accessing } -BaselineOfTreeParser >> projectClass [ - ^ MetacelloCypressBaselineProject -] diff --git a/src/BaselineOfTreeParser/package.st b/src/BaselineOfTreeParser/package.st deleted file mode 100644 index 3aa26e5..0000000 --- a/src/BaselineOfTreeParser/package.st +++ /dev/null @@ -1 +0,0 @@ -Package { #name : #BaselineOfTreeParser } diff --git a/src/TreeParser-Tests/TreeParserTest.class.st b/src/PerfTreeParser-Tests/PerfTreeParserTest.class.st similarity index 93% rename from src/TreeParser-Tests/TreeParserTest.class.st rename to src/PerfTreeParser-Tests/PerfTreeParserTest.class.st index 2e111af..387dd82 100644 --- a/src/TreeParser-Tests/TreeParserTest.class.st +++ b/src/PerfTreeParser-Tests/PerfTreeParserTest.class.st @@ -1,5 +1,5 @@ Class { - #name : #TreeParserTest, + #name : #PerfTreeParserTest, #superclass : #TestCase, #instVars : [ 'memoryFS', @@ -13,11 +13,11 @@ Class { 'testNodeSamePercentage', 'testNodeMultipleChildren' ], - #category : #'TreeParser-Tests' + #category : #'PerfTreeParser-Tests' } { #category : #running } -TreeParserTest >> setUp [ +PerfTreeParserTest >> setUp [ "Commands ran:" "sudo perf record -g --call-graph=dwarf -- ./script2.sh --all-user" "sudo perf report --header --stdio > perf_example.txt" @@ -244,21 +244,21 @@ TreeParserTest >> setUp [ ']. fileSimple := memoryFS / ('perf_stock_simple.txt'). - testParserSimple := TreeParser fromFile: fileSimple. - testNodeSimple := TreeParser parseFile: fileSimple. + testParserSimple := PerfTreeParser fromFile: fileSimple. + testNodeSimple := PerfTreeParser parseFile: fileSimple. fileSamePercentage := memoryFS / ('perf_stock_same_percentage.txt'). - testParserSamePercentage := TreeParser fromFile: fileSamePercentage. - testNodeSamePercentage := TreeParser parseFile: fileSamePercentage. + testParserSamePercentage := PerfTreeParser fromFile: fileSamePercentage. + testNodeSamePercentage := PerfTreeParser parseFile: fileSamePercentage. fileMultipleChildren := memoryFS / ('perf_stock_multiple_children.txt'). - testParserMultipleChildren := TreeParser fromFile: fileMultipleChildren. - testNodeMultipleChildren := TreeParser parseFile: fileMultipleChildren. + testParserMultipleChildren := PerfTreeParser fromFile: fileMultipleChildren. + testNodeMultipleChildren := PerfTreeParser parseFile: fileMultipleChildren. ] { #category : #running } -TreeParserTest >> tearDown [ +PerfTreeParserTest >> tearDown [ fileSimple ensureDelete. fileSamePercentage ensureDelete. @@ -267,7 +267,7 @@ TreeParserTest >> tearDown [ ] { #category : #tests } -TreeParserTest >> testDifferenceOfSpacesAt [ +PerfTreeParserTest >> testDifferenceOfSpacesAt [ self assert: (testParserSimple differenceOfSpacesAt: 0) isNil. @@ -282,7 +282,7 @@ TreeParserTest >> testDifferenceOfSpacesAt [ ] { #category : #tests } -TreeParserTest >> testFindChildrenIndexOfIndex [ +PerfTreeParserTest >> testFindChildrenIndexOfIndex [ "Two cases that shouldn't happen." self assert: (testParserSimple findChildrenIndexOfIndex: 0) isZero. @@ -310,7 +310,7 @@ TreeParserTest >> testFindChildrenIndexOfIndex [ ] { #category : #tests } -TreeParserTest >> testFindChildrenOfIndex [ +PerfTreeParserTest >> testFindChildrenOfIndex [ | aNode | aNode := testParserMultipleChildren findChildrenOfIndex: 3. @@ -327,7 +327,7 @@ TreeParserTest >> testFindChildrenOfIndex [ ] { #category : #tests } -TreeParserTest >> testFindChildrenOfRecursive [ +PerfTreeParserTest >> testFindChildrenOfRecursive [ | aNode | aNode := testNodeMultipleChildren firstChild firstChild. @@ -341,7 +341,7 @@ TreeParserTest >> testFindChildrenOfRecursive [ ] { #category : #tests } -TreeParserTest >> testIsLeaf [ +PerfTreeParserTest >> testIsLeaf [ | example | example := testNodeSimple firstChild firstChild. @@ -354,7 +354,7 @@ TreeParserTest >> testIsLeaf [ ] { #category : #tests } -TreeParserTest >> testLastSpaceAt [ +PerfTreeParserTest >> testLastSpaceAt [ self assert: (testParserSimple lastSpaceAt: 0) isNil. @@ -366,7 +366,7 @@ TreeParserTest >> testLastSpaceAt [ ] { #category : #tests } -TreeParserTest >> testNameOf [ +PerfTreeParserTest >> testNameOf [ "Limit cases" self assert: (testParserSimple nameOf: 0) isNil. @@ -382,7 +382,7 @@ TreeParserTest >> testNameOf [ ] { #category : #tests } -TreeParserTest >> testNodeAtIndex [ +PerfTreeParserTest >> testNodeAtIndex [ self assert: (testParserSimple nodeAtIndex: 0) isNil. @@ -392,7 +392,7 @@ TreeParserTest >> testNodeAtIndex [ ] { #category : #tests } -TreeParserTest >> testNodes [ +PerfTreeParserTest >> testNodes [ | example | example := testNodeMultipleChildren firstChild firstChild children. @@ -405,7 +405,7 @@ TreeParserTest >> testNodes [ ] { #category : #tests } -TreeParserTest >> testNodesSameParent [ +PerfTreeParserTest >> testNodesSameParent [ | example | example := (testNodeMultipleChildren firstChild firstChild) children. @@ -416,13 +416,13 @@ TreeParserTest >> testNodesSameParent [ ] { #category : #tests } -TreeParserTest >> testNumberOfFunctions [ +PerfTreeParserTest >> testNumberOfFunctions [ self assert: (testParserSimple numberOfFunctions) equals: 4 ] { #category : #tests } -TreeParserTest >> testNumberOfSpacesAt [ +PerfTreeParserTest >> testNumberOfSpacesAt [ self assert: (testParserSimple numberOfSpacesAt: 0) isZero. @@ -435,7 +435,7 @@ TreeParserTest >> testNumberOfSpacesAt [ ] { #category : #tests } -TreeParserTest >> testPercentageOf [ +PerfTreeParserTest >> testPercentageOf [ "Limit cases" self assert: (testParserSimple percentageOf: 0) isZero. @@ -462,7 +462,7 @@ TreeParserTest >> testPercentageOf [ ] { #category : #tests } -TreeParserTest >> testReadLine [ +PerfTreeParserTest >> testReadLine [ "Limit cases." self assert: (testParserSimple readLine: 0) isNil. @@ -473,7 +473,7 @@ TreeParserTest >> testReadLine [ ] { #category : #tests } -TreeParserTest >> testRealPercentageOf [ +PerfTreeParserTest >> testRealPercentageOf [ "Limit cases." self assert: (testParserSimple realPercentageOf: 0) isZero. @@ -488,7 +488,7 @@ TreeParserTest >> testRealPercentageOf [ ] { #category : #tests } -TreeParserTest >> testTime [ +PerfTreeParserTest >> testTime [ self assert: testParserSimple time equals: 397.592. @@ -496,7 +496,7 @@ TreeParserTest >> testTime [ ] { #category : #tests } -TreeParserTest >> testTraces [ +PerfTreeParserTest >> testTraces [ | traces | traces := testNodeSimple traces. @@ -509,7 +509,7 @@ TreeParserTest >> testTraces [ ] { #category : #tests } -TreeParserTest >> testWeight [ +PerfTreeParserTest >> testWeight [ | example | example := testNodeMultipleChildren firstChild firstChild. @@ -518,7 +518,7 @@ TreeParserTest >> testWeight [ ] { #category : #tests } -TreeParserTest >> testWeightOf [ +PerfTreeParserTest >> testWeightOf [ "Limit cases" self assert: (testParserSimple weightOf: 0) isZero. @@ -530,7 +530,7 @@ TreeParserTest >> testWeightOf [ ] { #category : #tests } -TreeParserTest >> testWithoutSpaces [ +PerfTreeParserTest >> testWithoutSpaces [ self assert: (testParserMultipleChildren withoutSpaces at: 6) equals: '--6.86%--arch_do_signal_or_restart' ] diff --git a/src/PerfTreeParser-Tests/package.st b/src/PerfTreeParser-Tests/package.st new file mode 100644 index 0000000..cc140e3 --- /dev/null +++ b/src/PerfTreeParser-Tests/package.st @@ -0,0 +1 @@ +Package { #name : #'PerfTreeParser-Tests' } diff --git a/src/TreeParser/TreeNode.class.st b/src/PerfTreeParser/PerfTreeNode.class.st similarity index 67% rename from src/TreeParser/TreeNode.class.st rename to src/PerfTreeParser/PerfTreeNode.class.st index 14ff1d2..420cb8e 100644 --- a/src/TreeParser/TreeNode.class.st +++ b/src/PerfTreeParser/PerfTreeNode.class.st @@ -1,5 +1,5 @@ Class { - #name : #TreeNode, + #name : #PerfTreeNode, #superclass : #Object, #instVars : [ 'name', @@ -8,23 +8,23 @@ Class { 'parent', 'totalTime' ], - #category : #TreeParser + #category : #PerfTreeParser } { #category : #accessing } -TreeNode >> children [ +PerfTreeNode >> children [ ^ children ] { #category : #accessing } -TreeNode >> children: aCollectionOfTreeNode [ +PerfTreeNode >> children: aCollectionOfTreeNode [ children:= aCollectionOfTreeNode ] { #category : #accessing } -TreeNode >> collectLeavesIn: leaves [ +PerfTreeNode >> collectLeavesIn: leaves [ self isLeaf ifTrue: [ leaves add: self. @@ -34,81 +34,81 @@ TreeNode >> collectLeavesIn: leaves [ ] { #category : #accessing } -TreeNode >> firstChild [ +PerfTreeNode >> firstChild [ ^ self children first ] { #category : #accessing } -TreeNode >> isLeaf [ +PerfTreeNode >> isLeaf [ ^ self children isEmpty ] { #category : #accessing } -TreeNode >> isNotLeaf [ +PerfTreeNode >> isNotLeaf [ ^ self children isNotEmpty ] { #category : #accessing } -TreeNode >> name [ +PerfTreeNode >> name [ ^ name ] { #category : #accessing } -TreeNode >> name: aString [ +PerfTreeNode >> name: aString [ name := aString ] { #category : #accessing } -TreeNode >> parent [ +PerfTreeNode >> parent [ ^ parent ] { #category : #accessing } -TreeNode >> parent: aTreeNode [ +PerfTreeNode >> parent: aTreeNode [ parent := aTreeNode ] { #category : #accessing } -TreeNode >> time [ +PerfTreeNode >> time [ ^ totalTime ] { #category : #accessing } -TreeNode >> time: aFloat [ +PerfTreeNode >> time: aFloat [ totalTime := aFloat ] { #category : #accessing } -TreeNode >> traces [ +PerfTreeNode >> traces [ | leaves | leaves := OrderedCollection new. self collectLeavesIn: leaves. ^ leaves collect: [ :l | - TreeTrace new + PerfTreeTrace new name: l name; weight: l weight; yourself ] ] { #category : #accessing } -TreeNode >> weight [ +PerfTreeNode >> weight [ ^ weight ] { #category : #accessing } -TreeNode >> weight: aFloat [ +PerfTreeNode >> weight: aFloat [ weight := aFloat ] diff --git a/src/TreeParser/TreeParser.class.st b/src/PerfTreeParser/PerfTreeParser.class.st similarity index 85% rename from src/TreeParser/TreeParser.class.st rename to src/PerfTreeParser/PerfTreeParser.class.st index 52fc904..50110fc 100644 --- a/src/TreeParser/TreeParser.class.st +++ b/src/PerfTreeParser/PerfTreeParser.class.st @@ -1,15 +1,15 @@ Class { - #name : #TreeParser, + #name : #PerfTreeParser, #superclass : #Object, #instVars : [ 'content', 'totalTime' ], - #category : #TreeParser + #category : #PerfTreeParser } { #category : #'instance creation' } -TreeParser class >> fromFile: aFile [ +PerfTreeParser class >> fromFile: aFile [ ^ self new content: aFile asFileReference; @@ -17,19 +17,19 @@ TreeParser class >> fromFile: aFile [ ] { #category : #'instance creation' } -TreeParser class >> parseFile: aFile [ +PerfTreeParser class >> parseFile: aFile [ ^ (self fromFile: aFile) root ] { #category : #accessing } -TreeParser >> content [ +PerfTreeParser >> content [ ^ content ] { #category : #accessing } -TreeParser >> content: aFile [ +PerfTreeParser >> content: aFile [ "Extract the interesting content from the file." | fileContents i | @@ -48,7 +48,7 @@ TreeParser >> content: aFile [ ] { #category : #accessing } -TreeParser >> differenceOfSpacesAt: aNodeIndex [ +PerfTreeParser >> differenceOfSpacesAt: aNodeIndex [ "Gives the difference of the number of spaces between 2 followed lines." ^ (aNodeIndex between: 1 and: self numberOfFunctions) @@ -59,7 +59,7 @@ TreeParser >> differenceOfSpacesAt: aNodeIndex [ ] { #category : #accessing } -TreeParser >> findChildrenIndexOfIndex: aNode [ +PerfTreeParser >> findChildrenIndexOfIndex: aNode [ "Gives an ordered collection of every indexes of the lines where there is a child." | lastNode everyChildren | @@ -82,7 +82,7 @@ TreeParser >> findChildrenIndexOfIndex: aNode [ ] { #category : #accessing } -TreeParser >> findChildrenOfIndex: aNodeIndex [ +PerfTreeParser >> findChildrenOfIndex: aNodeIndex [ "Gives the nodes representing every children at the node aNodeIndex." | collectionOfChildrenIndexes | @@ -92,7 +92,7 @@ TreeParser >> findChildrenOfIndex: aNodeIndex [ ] { #category : #accessing } -TreeParser >> lastSpaceAt: aLine [ +PerfTreeParser >> lastSpaceAt: aLine [ "Gives the index of the last space or '-' at a given line." | lastSpace line | @@ -108,7 +108,7 @@ TreeParser >> lastSpaceAt: aLine [ ] { #category : #accessing } -TreeParser >> nameOf: aNodeIndex [ +PerfTreeParser >> nameOf: aNodeIndex [ "Gives the name of a function at aNodeIndex." | aLine | @@ -119,13 +119,13 @@ TreeParser >> nameOf: aNodeIndex [ ] { #category : #accessing } -TreeParser >> nodeAtIndex: aNodeIndex [ +PerfTreeParser >> nodeAtIndex: aNodeIndex [ "Gives the node representing the node at aNodeIndex." | child | (aNodeIndex between: 1 and: self numberOfFunctions) ifFalse: [ ^ nil ]. - child := TreeNode new + child := PerfTreeNode new name: (self nameOf: aNodeIndex); weight: (self weightOf: aNodeIndex); time: self time; @@ -136,14 +136,14 @@ TreeParser >> nodeAtIndex: aNodeIndex [ ] { #category : #accessing } -TreeParser >> numberOfFunctions [ +PerfTreeParser >> numberOfFunctions [ "Gives the number of functions present in the file." ^ content size ] { #category : #accessing } -TreeParser >> numberOfSpacesAt: aNodeIndex [ +PerfTreeParser >> numberOfSpacesAt: aNodeIndex [ "Gives the number of spaces at a certain line." | count lineRead | @@ -161,7 +161,7 @@ TreeParser >> numberOfSpacesAt: aNodeIndex [ ] { #category : #accessing } -TreeParser >> percentageOf: aLine [ +PerfTreeParser >> percentageOf: aLine [ "Gives the percentage from a function at a given line" "In the case of multiples functions for one percentage, it gives the same percentage to every functions." @@ -181,7 +181,7 @@ TreeParser >> percentageOf: aLine [ ] { #category : #accessing } -TreeParser >> readLine: anIndex [ +PerfTreeParser >> readLine: anIndex [ "Reads a line from the file without the commentaries." (anIndex between: 1 and: self numberOfFunctions) @@ -190,7 +190,7 @@ TreeParser >> readLine: anIndex [ ] { #category : #accessing } -TreeParser >> realPercentageOf: aNodeIndex [ +PerfTreeParser >> realPercentageOf: aNodeIndex [ | children childrenPercentage | children := self findChildrenIndexOfIndex: aNodeIndex. @@ -208,26 +208,26 @@ TreeParser >> realPercentageOf: aNodeIndex [ ] { #category : #accessing } -TreeParser >> root [ +PerfTreeParser >> root [ "Gives the first parent of the nodes" ^ self nodeAtIndex: 1 ] { #category : #accessing } -TreeParser >> time [ +PerfTreeParser >> time [ ^ totalTime ] { #category : #accessing } -TreeParser >> time: aFloat [ +PerfTreeParser >> time: aFloat [ totalTime := aFloat. ] { #category : #accessing } -TreeParser >> weightOf: aNodeIndex [ +PerfTreeParser >> weightOf: aNodeIndex [ | newPercentage | newPercentage := self realPercentageOf: aNodeIndex. @@ -236,7 +236,7 @@ TreeParser >> weightOf: aNodeIndex [ ] { #category : #accessing } -TreeParser >> withoutSpaces [ +PerfTreeParser >> withoutSpaces [ "Gives a line without the characters that are not interesting." ^ self content collect: [ :c | diff --git a/src/TreeParser/TreeTrace.class.st b/src/PerfTreeParser/PerfTreeTrace.class.st similarity index 59% rename from src/TreeParser/TreeTrace.class.st rename to src/PerfTreeParser/PerfTreeTrace.class.st index f4c5667..7827068 100644 --- a/src/TreeParser/TreeTrace.class.st +++ b/src/PerfTreeParser/PerfTreeTrace.class.st @@ -1,33 +1,33 @@ Class { - #name : #TreeTrace, + #name : #PerfTreeTrace, #superclass : #Object, #instVars : [ 'name', 'weight' ], - #category : #TreeParser + #category : #PerfTreeParser } { #category : #accessing } -TreeTrace >> name [ +PerfTreeTrace >> name [ ^ name ] { #category : #accessing } -TreeTrace >> name: aName [ +PerfTreeTrace >> name: aName [ name := aName ] { #category : #accessing } -TreeTrace >> weight [ +PerfTreeTrace >> weight [ ^ weight ] { #category : #accessing } -TreeTrace >> weight: aFloat [ +PerfTreeTrace >> weight: aFloat [ weight := aFloat ] diff --git a/src/PerfTreeParser/package.st b/src/PerfTreeParser/package.st new file mode 100644 index 0000000..288bfac --- /dev/null +++ b/src/PerfTreeParser/package.st @@ -0,0 +1 @@ +Package { #name : #PerfTreeParser } diff --git a/src/TreeParser-Tests/package.st b/src/TreeParser-Tests/package.st deleted file mode 100644 index 54eece2..0000000 --- a/src/TreeParser-Tests/package.st +++ /dev/null @@ -1 +0,0 @@ -Package { #name : #'TreeParser-Tests' } diff --git a/src/TreeParser/package.st b/src/TreeParser/package.st deleted file mode 100644 index 9748a44..0000000 --- a/src/TreeParser/package.st +++ /dev/null @@ -1 +0,0 @@ -Package { #name : #TreeParser } From 35183b40eb48d252d029f4ca91e593213c4a369c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=A9o=20Boury?= <39924046+matburnx@users.noreply.github.com> Date: Fri, 7 Jun 2024 09:34:04 +0000 Subject: [PATCH 15/29] Added a quick description on how to use the packages --- README.md | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0a032ff..813e8f0 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,43 @@ # XCVMProfiler -VM Profiler based on instruments +VM Profiler based on instruments (and soon perf) + +## Install +```smalltalk +Metacello new + baseline: 'PerfTreeParser'; + repository: 'github://Alamvic/XCVMProfiler/src'; + load. + + +Metacello new + baseline: 'XCTrace'; + repository: 'github://Alamvic/XCVMProfiler/src'; + load. +``` + +## Example of use +### Perf parser +```smalltalk +fr := (FileLocator home / 'path/to/XCVMProfiler/resources/perf_stock_multiple_children.txt') asFileReference. + +"Use `parseFile:` to directly get the head of the node with all the parsing done" +node := TreeParser parseFile: fr. + +"To get the traces of the nodes:" +traces := node traces. + +"You can use `fromFile:` if you want to play with the parser" +parser := TreeParser fromFile: fr +``` + +### XC parser +```smalltalk +fr := (FileLocator home / 'path/to/XCVMProfiler/resources/test-profile.trace.txt') asFileReference. +"To get the XML data" +tree := XCTraceTree fromTimeProfileFileReference: fr. +samples := tree samples. + +"To directly get the different classified profiles" +primitiveProfiles := (XCVMDifferentialPrimitiveProfiler onFiles: {fr}) profiles. +profiles := (XCVMDifferentialProfiler onFiles: {fr}) profiles. +``` From 5ea5daf836fa4cda57e38afc66c3f4efd0e48f11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=A9o=20Boury?= <39924046+matburnx@users.noreply.github.com> Date: Fri, 7 Jun 2024 09:35:43 +0000 Subject: [PATCH 16/29] Added tiny and chopped perf files as examples --- resources/perf_stock_multiple_children.txt | 78 ++++++++++++++++++++++ resources/perf_stock_same_percentage.txt | 72 ++++++++++++++++++++ resources/perf_stock_simple.txt | 67 +++++++++++++++++++ 3 files changed, 217 insertions(+) create mode 100644 resources/perf_stock_multiple_children.txt create mode 100644 resources/perf_stock_same_percentage.txt create mode 100644 resources/perf_stock_simple.txt diff --git a/resources/perf_stock_multiple_children.txt b/resources/perf_stock_multiple_children.txt new file mode 100644 index 0000000..07cf843 --- /dev/null +++ b/resources/perf_stock_multiple_children.txt @@ -0,0 +1,78 @@ +# ======== +# captured on : Wed May 29 09:28:58 2024 +# header version : 1 +# data offset : 352 +# data size : 16366888 +# feat offset : 16367240 +# hostname : matburnx-laptop +# os release : 6.8.0-76060800daily20240311-generic +# perf version : 6.8.0 +# arch : x86_64 +# nrcpus online : 12 +# nrcpus avail : 12 +# cpudesc : AMD Ryzen 5 4600H with Radeon Graphics +# cpuid : AuthenticAMD,23,96,1 +# total memory : 15776888 kB +# cmdline : /usr/lib/linux-tools-6.8.0-76060800daily20240311/perf record -g --call-graph=dwarf -- ./script2.sh --all-user +# event : name = cycles:P, , id = { 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287 }, type = 0 (PERF_TYPE_HARDWARE), size = 136, config = 0 (PERF_COUNT_HW_CPU_CYCLES), { sample_period, sample_freq } = 4000, sample_type = IP|TID|TIME|ADDR|CALLCHAIN|PERIOD|REGS_USER|STACK_USER|DATA_SRC, read_format = ID|LOST, disabled = 1, inherit = 1, mmap = 1, comm = 1, freq = 1, enable_on_exec = 1, task = 1, precise_ip = 2, mmap_data = 1, sample_id_all = 1, exclude_callchain_user = 1, mmap2 = 1, comm_exec = 1, ksymbol = 1, bpf_event = 1, sample_regs_user = 0xff0fff, sample_stack_user = 8192 +# CPU_TOPOLOGY info available, use -I to display +# NUMA_TOPOLOGY info available, use -I to display +# pmu mappings: cpu = 4, amd_iommu_0 = 12, breakpoint = 5, ibs_fetch = 10, ibs_op = 11, kprobe = 8, msr = 13, power = 14, software = 1, tracepoint = 2, uprobe = 9 +# CACHE info available, use -I to display +# time of first sample : 924.754662 +# time of last sample : 925.152255 +# sample duration : 397.592 ms +# MEM_TOPOLOGY info available, use -I to display +# bpf_prog_info 2: bpf_prog_7cc47bbf07148bfe_hid_tail_call addr 0xffffffffc0314954 size 110 +# bpf_prog_info 5: bpf_prog_e3dbd137be8d6168 addr 0xffffffffc0314b30 size 313 +# bpf_prog_info 6: bpf_prog_6deef7357e7b4530 addr 0xffffffffc0314c9c size 58 +# bpf_prog_info 7: bpf_prog_6deef7357e7b4530 addr 0xffffffffc0314d2c size 58 +# bpf_prog_info 8: bpf_prog_0ecd07b7b633809f addr 0xffffffffc0316e30 size 777 +# bpf_prog_info 9: bpf_prog_6deef7357e7b4530 addr 0xffffffffc0317158 size 95 +# bpf_prog_info 10: bpf_prog_6deef7357e7b4530 addr 0xffffffffc03171d8 size 95 +# bpf_prog_info 11: bpf_prog_ee0e253c78993a24 addr 0xffffffffc031eb10 size 675 +# bpf_prog_info 12: bpf_prog_ee0e253c78993a24 addr 0xffffffffc031f018 size 671 +# bpf_prog_info 13: bpf_prog_8b9c33f36f812014 addr 0xffffffffc03214a4 size 1109 +# bpf_prog_info 14: bpf_prog_6deef7357e7b4530 addr 0xffffffffc0321914 size 95 +# bpf_prog_info 15: bpf_prog_6deef7357e7b4530 addr 0xffffffffc0321994 size 94 +# bpf_prog_info 19: bpf_prog_6deef7357e7b4530 addr 0xffffffffc0328bdc size 94 +# bpf_prog_info 20: bpf_prog_6deef7357e7b4530 addr 0xffffffffc0328c48 size 95 +# bpf_prog_info 21: bpf_prog_28a890580b33b0dc addr 0xffffffffc032b50c size 872 +# bpf_prog_info 22: bpf_prog_ee0e253c78993a24 addr 0xffffffffc032d4d0 size 673 +# bpf_prog_info 29: bpf_prog_6be0d743674e5faa_syscall__execve addr 0xffffffffc034c570 size 5360 +# bpf_prog_info 30: bpf_prog_a43530058ef998f5_do_ret_sys_execve addr 0xffffffffc034daa0 size 589 +# btf info of id 5 +# btf info of id 176 +# cpu pmu capabilities: max_precise=0 +# AMD systems uses ibs_op// PMU for some precise events, e.g.: cycles:p, see the 'perf list' man page for further details. +# missing features: (null) BRANCH_STACK GROUP_DESC AUXTRACE STAT CLOCKID DIR_FORMAT COMPRESSED CLOCK_DATA HYBRID_TOPOLOGY +# ======== +# +# +# Total Lost Samples: 0 +# +# Samples: 1K of event 'cycles:P' +# Event count (approx.): 963528052 +# +# Children Self Command Shared Object Symbol +# ........ ........ ............... ......................................... ......................................................... +# + 46.02% 0.00% pharo [kernel.kallsyms] [k] entry_SYSCALL_64_after_hwframe + | + ---entry_SYSCALL_64_after_hwframe + | + --45.91%--do_syscall_64 + | + |--36.78%--__x64_sys_read + | + | + |--6.88%--syscall_exit_to_user_mode + | | + | --6.86%--arch_do_signal_or_restart + | | + | --6.86%--get_signal + | + | + --0.53%--__x64_sys_openat + do_sys_openat2 + diff --git a/resources/perf_stock_same_percentage.txt b/resources/perf_stock_same_percentage.txt new file mode 100644 index 0000000..839183c --- /dev/null +++ b/resources/perf_stock_same_percentage.txt @@ -0,0 +1,72 @@ +# ======== +# captured on : Wed May 29 09:28:58 2024 +# header version : 1 +# data offset : 352 +# data size : 16366888 +# feat offset : 16367240 +# hostname : matburnx-laptop +# os release : 6.8.0-76060800daily20240311-generic +# perf version : 6.8.0 +# arch : x86_64 +# nrcpus online : 12 +# nrcpus avail : 12 +# cpudesc : AMD Ryzen 5 4600H with Radeon Graphics +# cpuid : AuthenticAMD,23,96,1 +# total memory : 15776888 kB +# cmdline : /usr/lib/linux-tools-6.8.0-76060800daily20240311/perf record -g --call-graph=dwarf -- ./script2.sh --all-user +# event : name = cycles:P, , id = { 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287 }, type = 0 (PERF_TYPE_HARDWARE), size = 136, config = 0 (PERF_COUNT_HW_CPU_CYCLES), { sample_period, sample_freq } = 4000, sample_type = IP|TID|TIME|ADDR|CALLCHAIN|PERIOD|REGS_USER|STACK_USER|DATA_SRC, read_format = ID|LOST, disabled = 1, inherit = 1, mmap = 1, comm = 1, freq = 1, enable_on_exec = 1, task = 1, precise_ip = 2, mmap_data = 1, sample_id_all = 1, exclude_callchain_user = 1, mmap2 = 1, comm_exec = 1, ksymbol = 1, bpf_event = 1, sample_regs_user = 0xff0fff, sample_stack_user = 8192 +# CPU_TOPOLOGY info available, use -I to display +# NUMA_TOPOLOGY info available, use -I to display +# pmu mappings: cpu = 4, amd_iommu_0 = 12, breakpoint = 5, ibs_fetch = 10, ibs_op = 11, kprobe = 8, msr = 13, power = 14, software = 1, tracepoint = 2, uprobe = 9 +# CACHE info available, use -I to display +# time of first sample : 924.754662 +# time of last sample : 925.152255 +# sample duration : 397.592 ms +# MEM_TOPOLOGY info available, use -I to display +# bpf_prog_info 2: bpf_prog_7cc47bbf07148bfe_hid_tail_call addr 0xffffffffc0314954 size 110 +# bpf_prog_info 5: bpf_prog_e3dbd137be8d6168 addr 0xffffffffc0314b30 size 313 +# bpf_prog_info 6: bpf_prog_6deef7357e7b4530 addr 0xffffffffc0314c9c size 58 +# bpf_prog_info 7: bpf_prog_6deef7357e7b4530 addr 0xffffffffc0314d2c size 58 +# bpf_prog_info 8: bpf_prog_0ecd07b7b633809f addr 0xffffffffc0316e30 size 777 +# bpf_prog_info 9: bpf_prog_6deef7357e7b4530 addr 0xffffffffc0317158 size 95 +# bpf_prog_info 10: bpf_prog_6deef7357e7b4530 addr 0xffffffffc03171d8 size 95 +# bpf_prog_info 11: bpf_prog_ee0e253c78993a24 addr 0xffffffffc031eb10 size 675 +# bpf_prog_info 12: bpf_prog_ee0e253c78993a24 addr 0xffffffffc031f018 size 671 +# bpf_prog_info 13: bpf_prog_8b9c33f36f812014 addr 0xffffffffc03214a4 size 1109 +# bpf_prog_info 14: bpf_prog_6deef7357e7b4530 addr 0xffffffffc0321914 size 95 +# bpf_prog_info 15: bpf_prog_6deef7357e7b4530 addr 0xffffffffc0321994 size 94 +# bpf_prog_info 19: bpf_prog_6deef7357e7b4530 addr 0xffffffffc0328bdc size 94 +# bpf_prog_info 20: bpf_prog_6deef7357e7b4530 addr 0xffffffffc0328c48 size 95 +# bpf_prog_info 21: bpf_prog_28a890580b33b0dc addr 0xffffffffc032b50c size 872 +# bpf_prog_info 22: bpf_prog_ee0e253c78993a24 addr 0xffffffffc032d4d0 size 673 +# bpf_prog_info 29: bpf_prog_6be0d743674e5faa_syscall__execve addr 0xffffffffc034c570 size 5360 +# bpf_prog_info 30: bpf_prog_a43530058ef998f5_do_ret_sys_execve addr 0xffffffffc034daa0 size 589 +# btf info of id 5 +# btf info of id 176 +# cpu pmu capabilities: max_precise=0 +# AMD systems uses ibs_op// PMU for some precise events, e.g.: cycles:p, see the 'perf list' man page for further details. +# missing features: (null) BRANCH_STACK GROUP_DESC AUXTRACE STAT CLOCKID DIR_FORMAT COMPRESSED CLOCK_DATA HYBRID_TOPOLOGY +# ======== +# +# +# Total Lost Samples: 0 +# +# Samples: 1K of event 'cycles:P' +# Event count (approx.): 963528052 +# +# Children Self Command Shared Object Symbol +# ........ ........ ............... ......................................... ......................................................... +# + 46.02% 0.00% pharo [kernel.kallsyms] [k] entry_SYSCALL_64_after_hwframe + | + ---entry_SYSCALL_64_after_hwframe + | + --45.91%--do_syscall_64 + | + |--36.78%--__x64_sys_read + | ksys_read + | vfs_read + | | + | --36.46%--ext4_file_read_iter + | | + diff --git a/resources/perf_stock_simple.txt b/resources/perf_stock_simple.txt new file mode 100644 index 0000000..d6d2bbc --- /dev/null +++ b/resources/perf_stock_simple.txt @@ -0,0 +1,67 @@ +# ======== +# captured on : Wed May 29 09:28:58 2024 +# header version : 1 +# data offset : 352 +# data size : 16366888 +# feat offset : 16367240 +# hostname : matburnx-laptop +# os release : 6.8.0-76060800daily20240311-generic +# perf version : 6.8.0 +# arch : x86_64 +# nrcpus online : 12 +# nrcpus avail : 12 +# cpudesc : AMD Ryzen 5 4600H with Radeon Graphics +# cpuid : AuthenticAMD,23,96,1 +# total memory : 15776888 kB +# cmdline : /usr/lib/linux-tools-6.8.0-76060800daily20240311/perf record -g --call-graph=dwarf -- ./script2.sh --all-user +# event : name = cycles:P, , id = { 276, 277, 278, 279, 280, 281, 282, 283, 284, 285, 286, 287 }, type = 0 (PERF_TYPE_HARDWARE), size = 136, config = 0 (PERF_COUNT_HW_CPU_CYCLES), { sample_period, sample_freq } = 4000, sample_type = IP|TID|TIME|ADDR|CALLCHAIN|PERIOD|REGS_USER|STACK_USER|DATA_SRC, read_format = ID|LOST, disabled = 1, inherit = 1, mmap = 1, comm = 1, freq = 1, enable_on_exec = 1, task = 1, precise_ip = 2, mmap_data = 1, sample_id_all = 1, exclude_callchain_user = 1, mmap2 = 1, comm_exec = 1, ksymbol = 1, bpf_event = 1, sample_regs_user = 0xff0fff, sample_stack_user = 8192 +# CPU_TOPOLOGY info available, use -I to display +# NUMA_TOPOLOGY info available, use -I to display +# pmu mappings: cpu = 4, amd_iommu_0 = 12, breakpoint = 5, ibs_fetch = 10, ibs_op = 11, kprobe = 8, msr = 13, power = 14, software = 1, tracepoint = 2, uprobe = 9 +# CACHE info available, use -I to display +# time of first sample : 924.754662 +# time of last sample : 925.152255 +# sample duration : 397.592 ms +# MEM_TOPOLOGY info available, use -I to display +# bpf_prog_info 2: bpf_prog_7cc47bbf07148bfe_hid_tail_call addr 0xffffffffc0314954 size 110 +# bpf_prog_info 5: bpf_prog_e3dbd137be8d6168 addr 0xffffffffc0314b30 size 313 +# bpf_prog_info 6: bpf_prog_6deef7357e7b4530 addr 0xffffffffc0314c9c size 58 +# bpf_prog_info 7: bpf_prog_6deef7357e7b4530 addr 0xffffffffc0314d2c size 58 +# bpf_prog_info 8: bpf_prog_0ecd07b7b633809f addr 0xffffffffc0316e30 size 777 +# bpf_prog_info 9: bpf_prog_6deef7357e7b4530 addr 0xffffffffc0317158 size 95 +# bpf_prog_info 10: bpf_prog_6deef7357e7b4530 addr 0xffffffffc03171d8 size 95 +# bpf_prog_info 11: bpf_prog_ee0e253c78993a24 addr 0xffffffffc031eb10 size 675 +# bpf_prog_info 12: bpf_prog_ee0e253c78993a24 addr 0xffffffffc031f018 size 671 +# bpf_prog_info 13: bpf_prog_8b9c33f36f812014 addr 0xffffffffc03214a4 size 1109 +# bpf_prog_info 14: bpf_prog_6deef7357e7b4530 addr 0xffffffffc0321914 size 95 +# bpf_prog_info 15: bpf_prog_6deef7357e7b4530 addr 0xffffffffc0321994 size 94 +# bpf_prog_info 19: bpf_prog_6deef7357e7b4530 addr 0xffffffffc0328bdc size 94 +# bpf_prog_info 20: bpf_prog_6deef7357e7b4530 addr 0xffffffffc0328c48 size 95 +# bpf_prog_info 21: bpf_prog_28a890580b33b0dc addr 0xffffffffc032b50c size 872 +# bpf_prog_info 22: bpf_prog_ee0e253c78993a24 addr 0xffffffffc032d4d0 size 673 +# bpf_prog_info 29: bpf_prog_6be0d743674e5faa_syscall__execve addr 0xffffffffc034c570 size 5360 +# bpf_prog_info 30: bpf_prog_a43530058ef998f5_do_ret_sys_execve addr 0xffffffffc034daa0 size 589 +# btf info of id 5 +# btf info of id 176 +# cpu pmu capabilities: max_precise=0 +# AMD systems uses ibs_op// PMU for some precise events, e.g.: cycles:p, see the 'perf list' man page for further details. +# missing features: (null) BRANCH_STACK GROUP_DESC AUXTRACE STAT CLOCKID DIR_FORMAT COMPRESSED CLOCK_DATA HYBRID_TOPOLOGY +# ======== +# +# +# Total Lost Samples: 0 +# +# Samples: 1K of event 'cycles:P' +# Event count (approx.): 963528052 +# +# Children Self Command Shared Object Symbol +# ........ ........ ............... ......................................... ......................................................... +# + 46.02% 0.00% pharo [kernel.kallsyms] [k] entry_SYSCALL_64_after_hwframe + | + ---entry_SYSCALL_64_after_hwframe + | + --45.91%--do_syscall_64 + | + |--36.78%--__x64_sys_read + From c071b76abc4f674af2b8389bb847524f181530e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=A9o=20Boury?= <39924046+matburnx@users.noreply.github.com> Date: Fri, 7 Jun 2024 09:39:12 +0000 Subject: [PATCH 17/29] Changed baseline name to fit the rename --- .smalltalk.ston | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.smalltalk.ston b/.smalltalk.ston index d29d713..5c019e9 100644 --- a/.smalltalk.ston +++ b/.smalltalk.ston @@ -6,7 +6,7 @@ SmalltalkCISpec { #platforms : [ #pharo ] }, SCIMetacelloLoadSpec { - #baseline : 'TreeParser', + #baseline : 'PerfTreeParser', #directory : 'src', #platforms : [ #pharo ] } From dc3f018cd133bd0011cf6f308c2d9e54f5250eff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=A9o=20Boury?= <39924046+matburnx@users.noreply.github.com> Date: Fri, 7 Jun 2024 11:57:34 +0000 Subject: [PATCH 18/29] Took out options that cannot work with Iceberg --- .github/workflows/mutalkCI.yml | 38 ++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/.github/workflows/mutalkCI.yml b/.github/workflows/mutalkCI.yml index cc49875..2c8c1b5 100644 --- a/.github/workflows/mutalkCI.yml +++ b/.github/workflows/mutalkCI.yml @@ -13,15 +13,15 @@ on: - 'resources/**' workflow_dispatch: - inputs: - mode: - description: 'modes: full (run on all project), diff (run on the last commit diff), commit (especify a commit to calculate diff)' - required: true - default: 'diff' - commit: - description: 'If mode == commit, here you enter the Commid id/name/shortId to evaluate the diff' - required: false - default: '' +# inputs: +# mode: +# description: 'modes: full (run on all project), diff (run on the last commit diff), commit (especify a commit to calculate diff)' +# required: true +# default: 'diff' +# commit: +# description: 'If mode == commit, here you enter the Commid id/name/shortId to evaluate the diff' +# required: false +# default: '' jobs: eventBased: @@ -68,17 +68,19 @@ jobs: - run: ${{env.SMALLTALK_CI_VM}} ${{env.SMALLTALK_CI_IMAGE}} metacello install "github://pharo-contributions/mutalk/src" BaselineOfMuTalk shell: bash - - name: full mutation testing - if: github.event.inputs.mode == 'full' - run: ${{env.SMALLTALK_CI_VM}} ${{env.SMALLTALK_CI_IMAGE}} mutalk --project=${{github.event.repository.name}} + - run: ${{env.SMALLTALK_CI_VM}} ${{env.SMALLTALK_CI_IMAGE}} mutalk --project=${{github.event.repository.name}} - - name: diff mutation testing - if: github.event.inputs.mode == 'diff' - run: ${{env.SMALLTALK_CI_VM}} ${{env.SMALLTALK_CI_IMAGE}} mutalk --project=${{github.event.repository.name}} --diff +# - name: full mutation testing +# if: github.event.inputs.mode == 'full' +# run: ${{env.SMALLTALK_CI_VM}} ${{env.SMALLTALK_CI_IMAGE}} mutalk --project=${{github.event.repository.name}} - - name: commit mutation testing - if: github.event.inputs.mode == 'commit' - run: ${{env.SMALLTALK_CI_VM}} ${{env.SMALLTALK_CI_IMAGE}} mutalk --project=${{github.event.repository.name}} --commit=${{github.event.inputs.commit}} +# - name: diff mutation testing +# if: github.event.inputs.mode == 'diff' +# run: ${{env.SMALLTALK_CI_VM}} ${{env.SMALLTALK_CI_IMAGE}} mutalk --project=${{github.event.repository.name}} --diff + +# - name: commit mutation testing +# if: github.event.inputs.mode == 'commit' +# run: ${{env.SMALLTALK_CI_VM}} ${{env.SMALLTALK_CI_IMAGE}} mutalk --project=${{github.event.repository.name}} --commit=${{github.event.inputs.commit}} - uses: actions/upload-artifact@v2 with: From 8c102f641d90ce9946450793bc8b37a2485ad063 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=A9o=20Boury?= <39924046+matburnx@users.noreply.github.com> Date: Thu, 13 Jun 2024 13:19:46 +0000 Subject: [PATCH 19/29] Changed repo URL This change will be reverted once the main repo will have the fixes --- .github/workflows/mutalkCI.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/mutalkCI.yml b/.github/workflows/mutalkCI.yml index 2c8c1b5..0f7bcdd 100644 --- a/.github/workflows/mutalkCI.yml +++ b/.github/workflows/mutalkCI.yml @@ -39,7 +39,7 @@ jobs: shell: bash timeout-minutes: 15 - - run: ${{env.SMALLTALK_CI_VM}} ${{env.SMALLTALK_CI_IMAGE}} metacello install "github://pharo-contributions/mutalk/src" BaselineOfMuTalk + - run: ${{env.SMALLTALK_CI_VM}} ${{env.SMALLTALK_CI_IMAGE}} metacello install "github://matburnx/mutalk/tree/-CI-not-working" BaselineOfMuTalk shell: bash - run: ${{env.SMALLTALK_CI_VM}} ${{env.SMALLTALK_CI_IMAGE}} mutalk --project=${{github.event.repository.name}} @@ -65,7 +65,7 @@ jobs: shell: bash timeout-minutes: 15 - - run: ${{env.SMALLTALK_CI_VM}} ${{env.SMALLTALK_CI_IMAGE}} metacello install "github://pharo-contributions/mutalk/src" BaselineOfMuTalk + - run: ${{env.SMALLTALK_CI_VM}} ${{env.SMALLTALK_CI_IMAGE}} metacello install "github://matburnx/mutalk/tree/-CI-not-working" BaselineOfMuTalk shell: bash - run: ${{env.SMALLTALK_CI_VM}} ${{env.SMALLTALK_CI_IMAGE}} mutalk --project=${{github.event.repository.name}} From 83051e0360b5808be4130054606a58e79800a5f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=A9o=20Boury?= <39924046+matburnx@users.noreply.github.com> Date: Mon, 17 Jun 2024 14:48:24 +0000 Subject: [PATCH 20/29] Changed branch --- .github/workflows/mutalkCI.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/mutalkCI.yml b/.github/workflows/mutalkCI.yml index 0f7bcdd..342f040 100644 --- a/.github/workflows/mutalkCI.yml +++ b/.github/workflows/mutalkCI.yml @@ -39,7 +39,7 @@ jobs: shell: bash timeout-minutes: 15 - - run: ${{env.SMALLTALK_CI_VM}} ${{env.SMALLTALK_CI_IMAGE}} metacello install "github://matburnx/mutalk/tree/-CI-not-working" BaselineOfMuTalk + - run: ${{env.SMALLTALK_CI_VM}} ${{env.SMALLTALK_CI_IMAGE}} metacello install "github://matburnx/mutalk:-CI-not-working" BaselineOfMuTalk shell: bash - run: ${{env.SMALLTALK_CI_VM}} ${{env.SMALLTALK_CI_IMAGE}} mutalk --project=${{github.event.repository.name}} @@ -65,7 +65,7 @@ jobs: shell: bash timeout-minutes: 15 - - run: ${{env.SMALLTALK_CI_VM}} ${{env.SMALLTALK_CI_IMAGE}} metacello install "github://matburnx/mutalk/tree/-CI-not-working" BaselineOfMuTalk + - run: ${{env.SMALLTALK_CI_VM}} ${{env.SMALLTALK_CI_IMAGE}} metacello install "github://matburnx/mutalk:-CI-not-working" BaselineOfMuTalk shell: bash - run: ${{env.SMALLTALK_CI_VM}} ${{env.SMALLTALK_CI_IMAGE}} mutalk --project=${{github.event.repository.name}} From 879b793c9ebd3612b69ec27850396f783c2de935 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=A9o=20Boury?= <39924046+matburnx@users.noreply.github.com> Date: Mon, 17 Jun 2024 14:52:58 +0000 Subject: [PATCH 21/29] Update mutalkCI.yml --- .github/workflows/mutalkCI.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/mutalkCI.yml b/.github/workflows/mutalkCI.yml index 342f040..3037186 100644 --- a/.github/workflows/mutalkCI.yml +++ b/.github/workflows/mutalkCI.yml @@ -29,6 +29,8 @@ jobs: if: github.event_name != 'workflow_dispatch' steps: - uses: actions/checkout@v2 + with: + fetch-depth: 0 - uses: hpi-swa/setup-smalltalkCI@v1 id: smalltalkci @@ -55,6 +57,8 @@ jobs: if: github.event_name == 'workflow_dispatch' steps: - uses: actions/checkout@v2 + with: + fetch-depth: 0 - uses: hpi-swa/setup-smalltalkCI@v1 id: smalltalkci From 7ac3407d85a7b8f1c090268ec3df6606e85f5c1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=A9o=20Boury?= <39924046+matburnx@users.noreply.github.com> Date: Tue, 18 Jun 2024 08:49:28 +0000 Subject: [PATCH 22/29] Update actions/checkout version --- .github/workflows/smalltalkCI.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/smalltalkCI.yml b/.github/workflows/smalltalkCI.yml index cc9a259..a2db122 100644 --- a/.github/workflows/smalltalkCI.yml +++ b/.github/workflows/smalltalkCI.yml @@ -29,7 +29,7 @@ jobs: # Steps represent a sequence of tasks that will be executed as part of the job steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - uses: hpi-swa/setup-smalltalkCI@v1 id: smalltalkci with: From 2b53c0c5b6e2550f4009a773f9521233ae6dea91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=A9o=20Boury?= <39924046+matburnx@users.noreply.github.com> Date: Tue, 18 Jun 2024 08:51:54 +0000 Subject: [PATCH 23/29] Update actions/... versions, file exports should be faster --- .github/workflows/mutalkCI.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/mutalkCI.yml b/.github/workflows/mutalkCI.yml index 3037186..a3034bb 100644 --- a/.github/workflows/mutalkCI.yml +++ b/.github/workflows/mutalkCI.yml @@ -28,7 +28,7 @@ jobs: runs-on: ubuntu-latest if: github.event_name != 'workflow_dispatch' steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: fetch-depth: 0 @@ -47,7 +47,7 @@ jobs: - run: ${{env.SMALLTALK_CI_VM}} ${{env.SMALLTALK_CI_IMAGE}} mutalk --project=${{github.event.repository.name}} shell: bash - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v4 with: name: mutation-testing-output path: ${{env.SMALLTALK_CI_BUILD_BASE}}/__mutalk_export.json @@ -56,7 +56,7 @@ jobs: runs-on: ubuntu-latest if: github.event_name == 'workflow_dispatch' steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: fetch-depth: 0 @@ -86,7 +86,7 @@ jobs: # if: github.event.inputs.mode == 'commit' # run: ${{env.SMALLTALK_CI_VM}} ${{env.SMALLTALK_CI_IMAGE}} mutalk --project=${{github.event.repository.name}} --commit=${{github.event.inputs.commit}} - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v4 with: name: mutation-testing-output path: ${{env.SMALLTALK_CI_BUILD_BASE}}/__mutalk_export.json From 6e1a5d4ca0236f5732ef3d9a30eb3d42356d210b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=A9o=20Boury?= <39924046+matburnx@users.noreply.github.com> Date: Wed, 19 Jun 2024 09:53:14 +0000 Subject: [PATCH 24/29] Update README.md Co-authored-by: Nahuel Palumbo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 813e8f0..47c998d 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # XCVMProfiler -VM Profiler based on instruments (and soon perf) +VM Profiler based on [instruments](https://help.apple.com/instruments/mac/current/#/dev7b09c84f5) and [perf](https://perf.wiki.kernel.org/) ## Install ```smalltalk From 3468950e740dc66090699b6330daf2cb31a8679f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=A9o=20Boury?= <39924046+matburnx@users.noreply.github.com> Date: Wed, 19 Jun 2024 10:17:46 +0000 Subject: [PATCH 25/29] Update README.md Changes as suggested [here](https://github.com/Alamvic/XCVMProfiler/pull/4#discussion_r1645705840) Specified to `main` branch as I experienced some issues where Iceberg would search for `master` instead --- README.md | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 47c998d..1c693f2 100644 --- a/README.md +++ b/README.md @@ -1,22 +1,37 @@ # XCVMProfiler VM Profiler based on [instruments](https://help.apple.com/instruments/mac/current/#/dev7b09c84f5) and [perf](https://perf.wiki.kernel.org/) -## Install +## Instruments 🍎 +### Install ```smalltalk Metacello new - baseline: 'PerfTreeParser'; - repository: 'github://Alamvic/XCVMProfiler/src'; + baseline: 'XCTrace'; + repository: 'github://Alamvic/XCVMProfiler:main/src'; load. +``` +### How to use +```smalltalk +fr := (FileLocator home / 'path/to/XCVMProfiler/resources/test-profile.trace.txt') asFileReference. +"To get the XML data" +tree := XCTraceTree fromTimeProfileFileReference: fr. +samples := tree samples. +"To directly get the different classified profiles" +primitiveProfiles := (XCVMDifferentialPrimitiveProfiler onFiles: {fr}) profiles. +profiles := (XCVMDifferentialProfiler onFiles: {fr}) profiles. +``` +--- +## perf 🐧 +### Install +```smalltalk Metacello new - baseline: 'XCTrace'; - repository: 'github://Alamvic/XCVMProfiler/src'; + baseline: 'PerfTreeParser'; + repository: 'github://Alamvic/XCVMProfiler:main/src'; load. ``` -## Example of use -### Perf parser +### How to use ```smalltalk fr := (FileLocator home / 'path/to/XCVMProfiler/resources/perf_stock_multiple_children.txt') asFileReference. @@ -29,15 +44,3 @@ traces := node traces. "You can use `fromFile:` if you want to play with the parser" parser := TreeParser fromFile: fr ``` - -### XC parser -```smalltalk -fr := (FileLocator home / 'path/to/XCVMProfiler/resources/test-profile.trace.txt') asFileReference. -"To get the XML data" -tree := XCTraceTree fromTimeProfileFileReference: fr. -samples := tree samples. - -"To directly get the different classified profiles" -primitiveProfiles := (XCVMDifferentialPrimitiveProfiler onFiles: {fr}) profiles. -profiles := (XCVMDifferentialProfiler onFiles: {fr}) profiles. -``` From 5c404ba5e94344fc9d8e9eea1ab511c9b6b947a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=A9o=20Boury?= <39924046+matburnx@users.noreply.github.com> Date: Wed, 19 Jun 2024 10:27:00 +0000 Subject: [PATCH 26/29] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1c693f2..c54972f 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Metacello new ### How to use ```smalltalk -fr := (FileLocator home / 'path/to/XCVMProfiler/resources/test-profile.trace.txt') asFileReference. +fr := (FileLocator home / 'path/to/XCVMProfiler/resources/test-profile.trace') asFileReference. "To get the XML data" tree := XCTraceTree fromTimeProfileFileReference: fr. samples := tree samples. @@ -36,11 +36,11 @@ Metacello new fr := (FileLocator home / 'path/to/XCVMProfiler/resources/perf_stock_multiple_children.txt') asFileReference. "Use `parseFile:` to directly get the head of the node with all the parsing done" -node := TreeParser parseFile: fr. +node := PerfTreeParser parseFile: fr. "To get the traces of the nodes:" traces := node traces. "You can use `fromFile:` if you want to play with the parser" -parser := TreeParser fromFile: fr +parser := PerfTreeParser fromFile: fr ``` From b6a1f5348c7827bdcfd0903ec6bc88dacb4b0041 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=A9o=20Boury?= Date: Wed, 19 Jun 2024 15:39:28 +0200 Subject: [PATCH 27/29] Corrected the code according to the suggestions made Deleted the checkings of wrong cases and their tests associated Modified `realPercentageOf` to use collections Modified `percentageOf` not to have this negative numbers problem Renamed `child` to `node` in `nodeAtIndex:` to be clearer Changed `findChildrenIndexOfIndex` to be a bit simpler Added `isNotAlreadyLeafIn:` to avoid duplicates when using `traces` --- .../PerfTreeParserTest.class.st | 180 +++++++++--------- src/PerfTreeParser-Tests/package.st | 2 +- src/PerfTreeParser/PerfTreeNode.class.st | 55 +++--- src/PerfTreeParser/PerfTreeParser.class.st | 127 ++++++------ src/PerfTreeParser/PerfTreeTrace.class.st | 15 +- src/PerfTreeParser/package.st | 2 +- 6 files changed, 188 insertions(+), 193 deletions(-) diff --git a/src/PerfTreeParser-Tests/PerfTreeParserTest.class.st b/src/PerfTreeParser-Tests/PerfTreeParserTest.class.st index 387dd82..4338c94 100644 --- a/src/PerfTreeParser-Tests/PerfTreeParserTest.class.st +++ b/src/PerfTreeParser-Tests/PerfTreeParserTest.class.st @@ -1,6 +1,6 @@ Class { - #name : #PerfTreeParserTest, - #superclass : #TestCase, + #name : 'PerfTreeParserTest', + #superclass : 'TestCase', #instVars : [ 'memoryFS', 'fileSimple', @@ -13,10 +13,11 @@ Class { 'testNodeSamePercentage', 'testNodeMultipleChildren' ], - #category : #'PerfTreeParser-Tests' + #category : 'PerfTreeParser-Tests', + #package : 'PerfTreeParser-Tests' } -{ #category : #running } +{ #category : 'running' } PerfTreeParserTest >> setUp [ "Commands ran:" "sudo perf record -g --call-graph=dwarf -- ./script2.sh --all-user" @@ -257,41 +258,37 @@ PerfTreeParserTest >> setUp [ ] -{ #category : #running } +{ #category : 'running' } PerfTreeParserTest >> tearDown [ - + fileSimple ensureDelete. fileSamePercentage ensureDelete. fileMultipleChildren ensureDelete. super tearDown ] -{ #category : #tests } +{ #category : 'tests' } PerfTreeParserTest >> testDifferenceOfSpacesAt [ - - self assert: (testParserSimple differenceOfSpacesAt: 0) isNil. - - self assert: (testParserSimple differenceOfSpacesAt: (testParserSimple numberOfFunctions + 1)) isNil. - "Classical case" - self assert: (testParserSamePercentage differenceOfSpacesAt: 6) equals: 1. - - self assert: (testParserSamePercentage differenceOfSpacesAt: 1) equals: 8. - - self assert: (testParserSamePercentage differenceOfSpacesAt: 5) isZero. -] -{ #category : #tests } -PerfTreeParserTest >> testFindChildrenIndexOfIndex [ - "Two cases that shouldn't happen." + self + assert: (testParserSamePercentage differenceOfSpacesAt: 6) + equals: 1. - self assert: (testParserSimple findChildrenIndexOfIndex: 0) isZero. + self + assert: (testParserSamePercentage differenceOfSpacesAt: 1) + equals: 8. - self assert: (testParserSimple findChildrenIndexOfIndex: (testParserSimple numberOfFunctions + 1)) isZero. + self assert: + (testParserSamePercentage differenceOfSpacesAt: 5) isZero +] +{ #category : 'tests' } +PerfTreeParserTest >> testFindChildrenIndexOfIndex [ "The last has no children" - self assert: (testParserSimple findChildrenIndexOfIndex: (testParserSimple numberOfFunctions)) isEmpty. + self assert: (testParserSimple findChildrenIndexOfIndex: + testParserSimple numberOfFunctions) isEmpty. "Case where 2 functions have the same number of spaces." self @@ -309,7 +306,7 @@ PerfTreeParserTest >> testFindChildrenIndexOfIndex [ equals: { 4. 5. 8 } asOrderedCollection ] -{ #category : #tests } +{ #category : 'tests' } PerfTreeParserTest >> testFindChildrenOfIndex [ | aNode | @@ -326,7 +323,7 @@ PerfTreeParserTest >> testFindChildrenOfIndex [ equals: (testParserMultipleChildren nameOf: 8) ] -{ #category : #tests } +{ #category : 'tests' } PerfTreeParserTest >> testFindChildrenOfRecursive [ | aNode | @@ -340,7 +337,7 @@ PerfTreeParserTest >> testFindChildrenOfRecursive [ equals: (testParserMultipleChildren nameOf: 7) ] -{ #category : #tests } +{ #category : 'tests' } PerfTreeParserTest >> testIsLeaf [ | example | @@ -353,45 +350,38 @@ PerfTreeParserTest >> testIsLeaf [ self assert: example children first isNotLeaf not. ] -{ #category : #tests } +{ #category : 'tests' } PerfTreeParserTest >> testLastSpaceAt [ - self assert: (testParserSimple lastSpaceAt: 0) isNil. - - self assert: (testParserSimple lastSpaceAt: (testParserSimple numberOfFunctions + 1)) isNil. + self assert: (testParserSimple lastSpaceAt: (testParserSimple numberOfFunctions)) equals: 37. self assert: (testParserSimple lastSpaceAt: 1) equals: 86. self assert: (testParserSimple lastSpaceAt: 2) equals: 15. ] -{ #category : #tests } +{ #category : 'tests' } PerfTreeParserTest >> testNameOf [ + "Three cases where the parsing is different." - "Limit cases" - self assert: (testParserSimple nameOf: 0) isNil. - - self assert: (testParserSimple nameOf: (testParserSimple numberOfFunctions + 1)) isNil. + self + assert: (testParserSimple nameOf: 1) + equals: 'entry_SYSCALL_64_after_hwframe'. - "Three cases where the parsing is different." - self assert: (testParserSimple nameOf: 1) equals: 'entry_SYSCALL_64_after_hwframe'. + self + assert: (testParserSamePercentage nameOf: 4) + equals: '__x64_sys_read'. - self assert: (testParserSamePercentage nameOf: 4) equals: '__x64_sys_read'. - self assert: (testParserSamePercentage nameOf: 6) equals: 'vfs_read' ] -{ #category : #tests } +{ #category : 'tests' } PerfTreeParserTest >> testNodeAtIndex [ - self assert: (testParserSimple nodeAtIndex: 0) isNil. - - self assert: (testParserSimple nodeAtIndex: (testParserSimple numberOfFunctions + 1)) isNil. - "Needs more tests!!!" ] -{ #category : #tests } +{ #category : 'tests' } PerfTreeParserTest >> testNodes [ | example | @@ -404,7 +394,7 @@ PerfTreeParserTest >> testNodes [ self assert: example third name equals: '__x64_sys_openat' ] -{ #category : #tests } +{ #category : 'tests' } PerfTreeParserTest >> testNodesSameParent [ | example | @@ -415,79 +405,81 @@ PerfTreeParserTest >> testNodesSameParent [ self assert: example first parent equals: example second parent ] -{ #category : #tests } +{ #category : 'tests' } PerfTreeParserTest >> testNumberOfFunctions [ self assert: (testParserSimple numberOfFunctions) equals: 4 ] -{ #category : #tests } +{ #category : 'tests' } PerfTreeParserTest >> testNumberOfSpacesAt [ - self assert: (testParserSimple numberOfSpacesAt: 0) isZero. - - self assert: (testParserSimple numberOfSpacesAt: (testParserSimple numberOfFunctions + 1)) isZero. + self assert: (testParserSimple numberOfSpacesAt: (testParserSimple numberOfFunctions)) equals: 27. self assert: (testParserSimple numberOfSpacesAt: 1) equals: 4. self assert: (testParserSimple numberOfSpacesAt: 3) equals: 16 ] -{ #category : #tests } +{ #category : 'tests' } PerfTreeParserTest >> testPercentageOf [ - "Limit cases" - - self assert: (testParserSimple percentageOf: 0) isZero. - - self assert: (testParserSimple percentageOf: (testParserSimple numberOfFunctions + 1)) isZero. - "Cases with 4 digits." + self assert: (testParserSimple percentageOf: 3) equals: 45.91. self assert: (testParserSimple percentageOf: 1) equals: 46.02. + self + assert: + (testParserSimple percentageOf: testParserSimple numberOfFunctions) + equals: 36.78. + "Case with 3 digits." - self assert: (testParserMultipleChildren percentageOf: 8) equals: 0.53. + self + assert: (testParserMultipleChildren percentageOf: 8) + equals: 0.53. "Case with same percentage" self assert: (testParserSamePercentage percentageOf: 4) equals: (testParserSamePercentage percentageOf: 5). - + self assert: (testParserSamePercentage percentageOf: 5) equals: (testParserSamePercentage percentageOf: 6) - ] -{ #category : #tests } +{ #category : 'tests' } PerfTreeParserTest >> testReadLine [ - "Limit cases." - self assert: (testParserSimple readLine: 0) isNil. + self + assert: (testParserSimple readLine: 3) + equals: ' --45.91%--do_syscall_64'. - self assert: (testParserSimple readLine: (testParserSimple numberOfFunctions + 1)) isNil. - - self assert: (testParserSimple readLine: 3) equals: ' --45.91%--do_syscall_64' + self assert: (testParserSimple readLine: (testParserSimple numberOfFunctions)) equals: ' |--36.78%--__x64_sys_read' ] -{ #category : #tests } +{ #category : 'tests' } PerfTreeParserTest >> testRealPercentageOf [ - "Limit cases." - self assert: (testParserSimple realPercentageOf: 0) isZero. - - self assert: (testParserSimple realPercentageOf: (testParserSimple numberOfFunctions + 1)) isZero. + self + assert: + (testParserSimple realPercentageOf: + testParserSimple numberOfFunctions) + equals: + (testParserSimple percentageOf: testParserSimple numberOfFunctions). self assert: (testParserSamePercentage realPercentageOf: 3) equals: 9.13. - self assert: (testParserSamePercentage realPercentageOf: 4) equals: 0.0 + self + assert: (testParserSamePercentage realPercentageOf: 4) + equals: 0.0 ] -{ #category : #tests } +{ #category : 'tests' } PerfTreeParserTest >> testTime [ self assert: testParserSimple time equals: 397.592. @@ -495,20 +487,29 @@ PerfTreeParserTest >> testTime [ self assert: testParserSimple root time equals: 397.592. ] -{ #category : #tests } +{ #category : 'tests' } PerfTreeParserTest >> testTraces [ - | traces | + | traces multipleTraces | traces := testNodeSimple traces. + multipleTraces := testNodeMultipleChildren traces. self assert: traces size equals: 1. - + self assert: traces first name equals: '__x64_sys_read'. - + self assert: traces first weight equals: 146.24. + + self assert: multipleTraces size equals: 3. + + self assert: multipleTraces first name equals: '__x64_sys_read'. + + self assert: multipleTraces last name equals: 'do_sys_openat2'. + + self assert: multipleTraces last weight equals: 2.11 ] -{ #category : #tests } +{ #category : 'tests' } PerfTreeParserTest >> testWeight [ | example | @@ -517,19 +518,18 @@ PerfTreeParserTest >> testWeight [ self assert: example weight equals: 6.84. ] -{ #category : #tests } +{ #category : 'tests' } PerfTreeParserTest >> testWeightOf [ - - "Limit cases" - self assert: (testParserSimple weightOf: 0) isZero. - - self assert: (testParserSimple weightOf: (testParserSimple numberOfFunctions + 1)) isZero. - - "Classical case" - self assert: (testParserSimple weightOf: 3) equals: 36.31. + + self + assert: + (testParserSimple weightOf: testParserSimple numberOfFunctions) + equals: 146.24. + + self assert: (testParserSimple weightOf: 3) equals: 36.31 ] -{ #category : #tests } +{ #category : 'tests' } PerfTreeParserTest >> testWithoutSpaces [ self assert: (testParserMultipleChildren withoutSpaces at: 6) equals: '--6.86%--arch_do_signal_or_restart' diff --git a/src/PerfTreeParser-Tests/package.st b/src/PerfTreeParser-Tests/package.st index cc140e3..312597f 100644 --- a/src/PerfTreeParser-Tests/package.st +++ b/src/PerfTreeParser-Tests/package.st @@ -1 +1 @@ -Package { #name : #'PerfTreeParser-Tests' } +Package { #name : 'PerfTreeParser-Tests' } diff --git a/src/PerfTreeParser/PerfTreeNode.class.st b/src/PerfTreeParser/PerfTreeNode.class.st index 420cb8e..b336edf 100644 --- a/src/PerfTreeParser/PerfTreeNode.class.st +++ b/src/PerfTreeParser/PerfTreeNode.class.st @@ -1,6 +1,6 @@ Class { - #name : #PerfTreeNode, - #superclass : #Object, + #name : 'PerfTreeNode', + #superclass : 'Object', #instVars : [ 'name', 'weight', @@ -8,86 +8,97 @@ Class { 'parent', 'totalTime' ], - #category : #PerfTreeParser + #category : 'PerfTreeParser', + #package : 'PerfTreeParser' } -{ #category : #accessing } +{ #category : 'accessing' } PerfTreeNode >> children [ ^ children ] -{ #category : #accessing } +{ #category : 'accessing' } PerfTreeNode >> children: aCollectionOfTreeNode [ children:= aCollectionOfTreeNode ] -{ #category : #accessing } +{ #category : 'accessing' } PerfTreeNode >> collectLeavesIn: leaves [ - self isLeaf ifTrue: [ - leaves add: self. - ^ leaves ]. + (self isLeaf and: [ self isNotAlreadyLeafIn: leaves ]) ifTrue: [ + leaves add: self ]. - ^ self children collect: [ :child | child collectLeavesIn: leaves ] + self children do: [ :child | child collectLeavesIn: leaves ]. + + ^ leaves ] -{ #category : #accessing } +{ #category : 'accessing' } PerfTreeNode >> firstChild [ ^ self children first ] -{ #category : #accessing } +{ #category : 'accessing' } PerfTreeNode >> isLeaf [ ^ self children isEmpty ] -{ #category : #accessing } +{ #category : 'accessing' } +PerfTreeNode >> isNotAlreadyLeafIn: leaves [ + + (leaves anySatisfy: [ :leaf | + leaf name = self name and: [ leaf weight = self weight ] ]) + ifTrue: [ ^ false ] + ifFalse: [ ^ true ] +] + +{ #category : 'accessing' } PerfTreeNode >> isNotLeaf [ ^ self children isNotEmpty ] -{ #category : #accessing } +{ #category : 'accessing' } PerfTreeNode >> name [ ^ name ] -{ #category : #accessing } +{ #category : 'accessing' } PerfTreeNode >> name: aString [ name := aString ] -{ #category : #accessing } +{ #category : 'accessing' } PerfTreeNode >> parent [ ^ parent ] -{ #category : #accessing } +{ #category : 'accessing' } PerfTreeNode >> parent: aTreeNode [ parent := aTreeNode ] -{ #category : #accessing } +{ #category : 'accessing' } PerfTreeNode >> time [ ^ totalTime ] -{ #category : #accessing } +{ #category : 'accessing' } PerfTreeNode >> time: aFloat [ totalTime := aFloat ] -{ #category : #accessing } +{ #category : 'accessing' } PerfTreeNode >> traces [ | leaves | @@ -101,13 +112,13 @@ PerfTreeNode >> traces [ yourself ] ] -{ #category : #accessing } +{ #category : 'accessing' } PerfTreeNode >> weight [ ^ weight ] -{ #category : #accessing } +{ #category : 'accessing' } PerfTreeNode >> weight: aFloat [ weight := aFloat diff --git a/src/PerfTreeParser/PerfTreeParser.class.st b/src/PerfTreeParser/PerfTreeParser.class.st index 50110fc..5da0300 100644 --- a/src/PerfTreeParser/PerfTreeParser.class.st +++ b/src/PerfTreeParser/PerfTreeParser.class.st @@ -1,14 +1,15 @@ Class { - #name : #PerfTreeParser, - #superclass : #Object, + #name : 'PerfTreeParser', + #superclass : 'Object', #instVars : [ 'content', 'totalTime' ], - #category : #PerfTreeParser + #category : 'PerfTreeParser', + #package : 'PerfTreeParser' } -{ #category : #'instance creation' } +{ #category : 'instance creation' } PerfTreeParser class >> fromFile: aFile [ ^ self new @@ -16,19 +17,19 @@ PerfTreeParser class >> fromFile: aFile [ yourself ] -{ #category : #'instance creation' } +{ #category : 'instance creation' } PerfTreeParser class >> parseFile: aFile [ ^ (self fromFile: aFile) root ] -{ #category : #accessing } +{ #category : 'accessing' } PerfTreeParser >> content [ ^ content ] -{ #category : #accessing } +{ #category : 'accessing' } PerfTreeParser >> content: aFile [ "Extract the interesting content from the file." @@ -39,7 +40,7 @@ PerfTreeParser >> content: aFile [ [ (fileContents at: i) beginsWith: '# sample duration' ] whileFalse: [ i := i + 1 ]. - self time: (((fileContents at: i) last: 10) first: 7) asNumber. + self time: ((((fileContents at: i) last: 10) first: 7) copyWithout: Character space) asNumber. content := fileContents reject: [ :line | line beginsWith: '#' ]. content := content select: [ :line | @@ -47,41 +48,38 @@ PerfTreeParser >> content: aFile [ isNotEmpty ] ] -{ #category : #accessing } +{ #category : 'accessing' } PerfTreeParser >> differenceOfSpacesAt: aNodeIndex [ "Gives the difference of the number of spaces between 2 followed lines." - ^ (aNodeIndex between: 1 and: self numberOfFunctions) - ifFalse: [ nil ] - ifTrue: [ - (self numberOfSpacesAt: aNodeIndex + 1) - - (self numberOfSpacesAt: aNodeIndex) ] + ^ (self numberOfSpacesAt: aNodeIndex + 1) + - (self numberOfSpacesAt: aNodeIndex) ] -{ #category : #accessing } -PerfTreeParser >> findChildrenIndexOfIndex: aNode [ +{ #category : 'accessing' } +PerfTreeParser >> findChildrenIndexOfIndex: aNodeIndex [ "Gives an ordered collection of every indexes of the lines where there is a child." - | lastNode everyChildren | - lastNode := self numberOfFunctions. + | lastNodeIndex everyChildren newBranch spaces nodeSpaces | + lastNodeIndex := self numberOfFunctions. everyChildren := OrderedCollection new. - (aNode between: 1 and: lastNode) ifFalse: [ ^ 0 ]. + (self percentageOf: aNodeIndex) = (self percentageOf: aNodeIndex + 1) ifTrue: [ + everyChildren add: aNodeIndex + 1. + ^ everyChildren ]. - (((self differenceOfSpacesAt: aNode) between: 1 and: 10) or: [ - (self percentageOf: aNode) = (self percentageOf: aNode + 1) ]) - ifTrue: [ - everyChildren add: aNode + 1. - ^ everyChildren ]. - - aNode to: lastNode do: [ :i | - (self numberOfSpacesAt: i) - (self numberOfSpacesAt: aNode) = 11 - ifTrue: [ everyChildren add: i ] ]. + newBranch := false. + nodeSpaces := self numberOfSpacesAt: aNodeIndex. + aNodeIndex + 1 to: lastNodeIndex do: [ :i | + spaces := self numberOfSpacesAt: i. + spaces <= nodeSpaces ifTrue: [ newBranch := true ]. + ((spaces - nodeSpaces between: 1 and: 11) and: [ + newBranch not ]) ifTrue: [ everyChildren add: i ] ]. ^ everyChildren ] -{ #category : #accessing } +{ #category : 'accessing' } PerfTreeParser >> findChildrenOfIndex: aNodeIndex [ "Gives the nodes representing every children at the node aNodeIndex." @@ -91,13 +89,11 @@ PerfTreeParser >> findChildrenOfIndex: aNodeIndex [ self nodeAtIndex: childIndex ] ] -{ #category : #accessing } +{ #category : 'accessing' } PerfTreeParser >> lastSpaceAt: aLine [ "Gives the index of the last space or '-' at a given line." | lastSpace line | - (aLine between: 1 and: self numberOfFunctions) ifFalse: [ ^ nil ]. - line := self readLine: aLine. lastSpace := 0. @@ -107,50 +103,42 @@ PerfTreeParser >> lastSpaceAt: aLine [ ^ lastSpace ] -{ #category : #accessing } +{ #category : 'accessing' } PerfTreeParser >> nameOf: aNodeIndex [ "Gives the name of a function at aNodeIndex." | aLine | - (aNodeIndex between: 1 and: self numberOfFunctions) ifFalse: [ ^ nil ]. - aLine := self readLine: aNodeIndex. ^ aLine last: aLine size - (self lastSpaceAt: aNodeIndex) ] -{ #category : #accessing } +{ #category : 'accessing' } PerfTreeParser >> nodeAtIndex: aNodeIndex [ "Gives the node representing the node at aNodeIndex." - | child | - (aNodeIndex between: 1 and: self numberOfFunctions) ifFalse: [ ^ nil ]. - - child := PerfTreeNode new + | node | + node := PerfTreeNode new name: (self nameOf: aNodeIndex); weight: (self weightOf: aNodeIndex); time: self time; yourself. - child children: (self findChildrenOfIndex: aNodeIndex). - child children do: [ :grandchild | grandchild parent: child ]. - ^ child + node children: (self findChildrenOfIndex: aNodeIndex). + node children do: [ :grandchild | grandchild parent: node ]. + ^ node ] -{ #category : #accessing } +{ #category : 'accessing' } PerfTreeParser >> numberOfFunctions [ "Gives the number of functions present in the file." ^ content size ] -{ #category : #accessing } +{ #category : 'accessing' } PerfTreeParser >> numberOfSpacesAt: aNodeIndex [ "Gives the number of spaces at a certain line." | count lineRead | - count := 0. - - (aNodeIndex between: 1 and: self numberOfFunctions) ifFalse: [ - ^ count ]. lineRead := self readLine: aNodeIndex. count := 1. @@ -160,7 +148,7 @@ PerfTreeParser >> numberOfSpacesAt: aNodeIndex [ ^ count - 1 ] -{ #category : #accessing } +{ #category : 'accessing' } PerfTreeParser >> percentageOf: aLine [ "Gives the percentage from a function at a given line" @@ -169,64 +157,59 @@ PerfTreeParser >> percentageOf: aLine [ | stringLine numbers | (aLine between: 1 and: self numberOfFunctions) ifFalse: [ ^ 0 ]. - stringLine := ((self content at: aLine) copyUpTo: $%) last: 5. + stringLine := (((self readLine: aLine) copyUpTo: $%) last: 5) + copyWithout: $-. - stringLine = ((self content at: aLine) last: 5) ifTrue: [ + stringLine = ((self readLine: aLine) last: 5) ifTrue: [ ^ self percentageOf: aLine - 1 ]. numbers := stringLine asNumber. - numbers < 0 ifTrue: [ numbers := numbers negated ]. ^ numbers ] -{ #category : #accessing } +{ #category : 'accessing' } PerfTreeParser >> readLine: anIndex [ "Reads a line from the file without the commentaries." - - (anIndex between: 1 and: self numberOfFunctions) - ifTrue: [ ^ self content at: anIndex ] - ifFalse: [ ^ nil ] + ^ self content at: anIndex ] -{ #category : #accessing } +{ #category : 'accessing' } PerfTreeParser >> realPercentageOf: aNodeIndex [ - | children childrenPercentage | + | nodePercentage children childrenPercentage | + nodePercentage := self percentageOf: aNodeIndex. children := self findChildrenIndexOfIndex: aNodeIndex. childrenPercentage := 0. - children isCollection ifFalse: [ ^ self percentageOf: aNodeIndex ]. + children ifEmpty: [ ^ nodePercentage ]. - 1 to: children size do: [ :childIndex | - childrenPercentage := childrenPercentage - + - (self percentageOf: (children at: childIndex)) ]. + childrenPercentage := children sum: [ :child | + self percentageOf: child ]. - ^ (self percentageOf: aNodeIndex) - childrenPercentage roundUpTo: - 0.01 + ^ nodePercentage - childrenPercentage roundUpTo: 0.01 ] -{ #category : #accessing } +{ #category : 'accessing' } PerfTreeParser >> root [ "Gives the first parent of the nodes" ^ self nodeAtIndex: 1 ] -{ #category : #accessing } +{ #category : 'accessing' } PerfTreeParser >> time [ ^ totalTime ] -{ #category : #accessing } +{ #category : 'accessing' } PerfTreeParser >> time: aFloat [ totalTime := aFloat. ] -{ #category : #accessing } +{ #category : 'accessing' } PerfTreeParser >> weightOf: aNodeIndex [ | newPercentage | @@ -235,7 +218,7 @@ PerfTreeParser >> weightOf: aNodeIndex [ ^ totalTime * (newPercentage/100) roundUpTo: 0.01 ] -{ #category : #accessing } +{ #category : 'accessing' } PerfTreeParser >> withoutSpaces [ "Gives a line without the characters that are not interesting." diff --git a/src/PerfTreeParser/PerfTreeTrace.class.st b/src/PerfTreeParser/PerfTreeTrace.class.st index 7827068..f369927 100644 --- a/src/PerfTreeParser/PerfTreeTrace.class.st +++ b/src/PerfTreeParser/PerfTreeTrace.class.st @@ -1,32 +1,33 @@ Class { - #name : #PerfTreeTrace, - #superclass : #Object, + #name : 'PerfTreeTrace', + #superclass : 'Object', #instVars : [ 'name', 'weight' ], - #category : #PerfTreeParser + #category : 'PerfTreeParser', + #package : 'PerfTreeParser' } -{ #category : #accessing } +{ #category : 'accessing' } PerfTreeTrace >> name [ ^ name ] -{ #category : #accessing } +{ #category : 'accessing' } PerfTreeTrace >> name: aName [ name := aName ] -{ #category : #accessing } +{ #category : 'accessing' } PerfTreeTrace >> weight [ ^ weight ] -{ #category : #accessing } +{ #category : 'accessing' } PerfTreeTrace >> weight: aFloat [ weight := aFloat diff --git a/src/PerfTreeParser/package.st b/src/PerfTreeParser/package.st index 288bfac..294aff7 100644 --- a/src/PerfTreeParser/package.st +++ b/src/PerfTreeParser/package.st @@ -1 +1 @@ -Package { #name : #PerfTreeParser } +Package { #name : 'PerfTreeParser' } From 8445475d3afcd80bcca34b37b22e3b18ef6f3d8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=A9o=20Boury?= <39924046+matburnx@users.noreply.github.com> Date: Thu, 20 Jun 2024 12:52:47 +0000 Subject: [PATCH 28/29] Added job summary --- .github/workflows/mutalkCI.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/mutalkCI.yml b/.github/workflows/mutalkCI.yml index a3034bb..cc622da 100644 --- a/.github/workflows/mutalkCI.yml +++ b/.github/workflows/mutalkCI.yml @@ -47,6 +47,8 @@ jobs: - run: ${{env.SMALLTALK_CI_VM}} ${{env.SMALLTALK_CI_IMAGE}} mutalk --project=${{github.event.repository.name}} shell: bash + - run: cp ${{env.SMALLTALK_CI_BUILD_BASE}}/__mutalk_summary.md $GITHUB_STEP_SUMMARY + - uses: actions/upload-artifact@v4 with: name: mutation-testing-output @@ -86,6 +88,8 @@ jobs: # if: github.event.inputs.mode == 'commit' # run: ${{env.SMALLTALK_CI_VM}} ${{env.SMALLTALK_CI_IMAGE}} mutalk --project=${{github.event.repository.name}} --commit=${{github.event.inputs.commit}} + - run: cp ${{env.SMALLTALK_CI_BUILD_BASE}}/__mutalk_summary.md $GITHUB_STEP_SUMMARY + - uses: actions/upload-artifact@v4 with: name: mutation-testing-output From 9dd83967c254b3c7b27d072f796771e1ce620ac6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mat=C3=A9o=20Boury?= Date: Fri, 21 Jun 2024 14:05:30 +0200 Subject: [PATCH 29/29] Added support for multiple trees, now works with full file Added `findTraces:` to have the traces of each tree directly just by giving the file --- .../PerfTreeParserTest.class.st | 8 ++--- src/PerfTreeParser/PerfTreeParser.class.st | 36 ++++++++++++++----- 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/src/PerfTreeParser-Tests/PerfTreeParserTest.class.st b/src/PerfTreeParser-Tests/PerfTreeParserTest.class.st index 4338c94..d7beb92 100644 --- a/src/PerfTreeParser-Tests/PerfTreeParserTest.class.st +++ b/src/PerfTreeParser-Tests/PerfTreeParserTest.class.st @@ -246,15 +246,15 @@ PerfTreeParserTest >> setUp [ fileSimple := memoryFS / ('perf_stock_simple.txt'). testParserSimple := PerfTreeParser fromFile: fileSimple. - testNodeSimple := PerfTreeParser parseFile: fileSimple. + testNodeSimple := (PerfTreeParser parseFile: fileSimple) first. fileSamePercentage := memoryFS / ('perf_stock_same_percentage.txt'). testParserSamePercentage := PerfTreeParser fromFile: fileSamePercentage. - testNodeSamePercentage := PerfTreeParser parseFile: fileSamePercentage. + testNodeSamePercentage := (PerfTreeParser parseFile: fileSamePercentage) first. fileMultipleChildren := memoryFS / ('perf_stock_multiple_children.txt'). testParserMultipleChildren := PerfTreeParser fromFile: fileMultipleChildren. - testNodeMultipleChildren := PerfTreeParser parseFile: fileMultipleChildren. + testNodeMultipleChildren := (PerfTreeParser parseFile: fileMultipleChildren) first. ] @@ -491,7 +491,7 @@ PerfTreeParserTest >> testTime [ PerfTreeParserTest >> testTraces [ | traces multipleTraces | - traces := testNodeSimple traces. + traces := (PerfTreeParser findTraces: fileSimple) first. multipleTraces := testNodeMultipleChildren traces. self assert: traces size equals: 1. diff --git a/src/PerfTreeParser/PerfTreeParser.class.st b/src/PerfTreeParser/PerfTreeParser.class.st index 5da0300..28f6eec 100644 --- a/src/PerfTreeParser/PerfTreeParser.class.st +++ b/src/PerfTreeParser/PerfTreeParser.class.st @@ -9,6 +9,12 @@ Class { #package : 'PerfTreeParser' } +{ #category : 'instance creation' } +PerfTreeParser class >> findTraces: aFile [ + + ^ (self parseFile: aFile) collect: [:tree | tree traces ] +] + { #category : 'instance creation' } PerfTreeParser class >> fromFile: aFile [ @@ -20,7 +26,7 @@ PerfTreeParser class >> fromFile: aFile [ { #category : 'instance creation' } PerfTreeParser class >> parseFile: aFile [ - ^ (self fromFile: aFile) root + ^ (self fromFile: aFile) roots ] { #category : 'accessing' } @@ -64,9 +70,10 @@ PerfTreeParser >> findChildrenIndexOfIndex: aNodeIndex [ lastNodeIndex := self numberOfFunctions. everyChildren := OrderedCollection new. - (self percentageOf: aNodeIndex) = (self percentageOf: aNodeIndex + 1) ifTrue: [ - everyChildren add: aNodeIndex + 1. - ^ everyChildren ]. + (self percentageOf: aNodeIndex) = (self percentageOf: aNodeIndex + 1) + ifTrue: [ + everyChildren add: aNodeIndex + 1. + ^ everyChildren ]. newBranch := false. nodeSpaces := self numberOfSpacesAt: aNodeIndex. @@ -74,7 +81,8 @@ PerfTreeParser >> findChildrenIndexOfIndex: aNodeIndex [ spaces := self numberOfSpacesAt: i. spaces <= nodeSpaces ifTrue: [ newBranch := true ]. ((spaces - nodeSpaces between: 1 and: 11) and: [ - newBranch not ]) ifTrue: [ everyChildren add: i ] ]. + (self percentageOf: i) ~= (self percentageOf: i - 1) and: [ + newBranch not ] ]) ifTrue: [ everyChildren add: i ] ]. ^ everyChildren ] @@ -123,7 +131,7 @@ PerfTreeParser >> nodeAtIndex: aNodeIndex [ time: self time; yourself. node children: (self findChildrenOfIndex: aNodeIndex). - node children do: [ :grandchild | grandchild parent: node ]. + node children do: [ :child | child parent: node ]. ^ node ] @@ -157,8 +165,8 @@ PerfTreeParser >> percentageOf: aLine [ | stringLine numbers | (aLine between: 1 and: self numberOfFunctions) ifFalse: [ ^ 0 ]. - stringLine := (((self readLine: aLine) copyUpTo: $%) last: 5) - copyWithout: $-. + stringLine := ((((self readLine: aLine) copyUpTo: $%) last: 5) + copyWithout: $-) copyWithout: Character space. stringLine = ((self readLine: aLine) last: 5) ifTrue: [ ^ self percentageOf: aLine - 1 ]. @@ -197,6 +205,18 @@ PerfTreeParser >> root [ ^ self nodeAtIndex: 1 ] +{ #category : 'accessing' } +PerfTreeParser >> roots [ + + | roots | + roots := OrderedCollection new. + + 1 to: self numberOfFunctions do: [:i | + (self numberOfSpacesAt: i) <= 5 ifTrue: [ roots add: (self nodeAtIndex: i) ] ]. + + ^ roots +] + { #category : 'accessing' } PerfTreeParser >> time [