diff --git a/.github/workflows/mutalkCI.yml b/.github/workflows/mutalkCI.yml
new file mode 100644
index 0000000..cc622da
--- /dev/null
+++ b/.github/workflows/mutalkCI.yml
@@ -0,0 +1,96 @@
+name: MutalkCI
+
+on:
+ push:
+ branches: [ main ]
+ paths-ignore:
+ - 'README.md'
+ - 'resources/**'
+ pull_request:
+ branches: [ main ]
+ 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@v4
+ with:
+ fetch-depth: 0
+
+ - uses: hpi-swa/setup-smalltalkCI@v1
+ id: smalltalkci
+ with:
+ smalltalk-image: Pharo64-stable
+
+ - run: smalltalkci -s ${{ steps.smalltalkci.outputs.smalltalk-image }}
+ shell: bash
+ timeout-minutes: 15
+
+ - 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}}
+ 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
+ path: ${{env.SMALLTALK_CI_BUILD_BASE}}/__mutalk_export.json
+
+ manual:
+ runs-on: ubuntu-latest
+ if: github.event_name == 'workflow_dispatch'
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ - uses: hpi-swa/setup-smalltalkCI@v1
+ id: smalltalkci
+ with:
+ smalltalk-image: Pharo64-stable
+
+ - run: smalltalkci -s ${{ steps.smalltalkci.outputs.smalltalk-image }}
+ shell: bash
+ timeout-minutes: 15
+
+ - 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}}
+
+# - 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}}
+
+ - run: cp ${{env.SMALLTALK_CI_BUILD_BASE}}/__mutalk_summary.md $GITHUB_STEP_SUMMARY
+
+ - uses: actions/upload-artifact@v4
+ with:
+ name: mutation-testing-output
+ path: ${{env.SMALLTALK_CI_BUILD_BASE}}/__mutalk_export.json
diff --git a/.github/workflows/smalltalkCI.yml b/.github/workflows/smalltalkCI.yml
index fe86f88..a2db122 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:
@@ -23,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:
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 ]
}
diff --git a/README.md b/README.md
index 0a032ff..c54972f 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,46 @@
# XCVMProfiler
-VM Profiler based on instruments
+VM Profiler based on [instruments](https://help.apple.com/instruments/mac/current/#/dev7b09c84f5) and [perf](https://perf.wiki.kernel.org/)
+
+## Instruments 🍎
+### Install
+```smalltalk
+Metacello new
+ baseline: 'XCTrace';
+ repository: 'github://Alamvic/XCVMProfiler:main/src';
+ load.
+```
+
+### How to use
+```smalltalk
+fr := (FileLocator home / 'path/to/XCVMProfiler/resources/test-profile.trace') 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: 'PerfTreeParser';
+ repository: 'github://Alamvic/XCVMProfiler:main/src';
+ load.
+```
+
+### How to use
+```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 := 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 := PerfTreeParser fromFile: fr
+```
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
+
diff --git a/resources/test-empty-profile.trace b/resources/test-empty-profile.trace
new file mode 100644
index 0000000..ca9ba50
--- /dev/null
+++ b/resources/test-empty-profile.trace
@@ -0,0 +1,4 @@
+
+
+timeSample Timesample-timethreadThreadthreadprocessProcessprocesscoreCorecorethread-stateStatethread-stateweightWeightweightstackBacktracebacktrace
+
diff --git a/resources/test-profile.trace b/resources/test-profile.trace
new file mode 100644
index 0000000..37820de
--- /dev/null
+++ b/resources/test-profile.trace
@@ -0,0 +1,46 @@
+
+
+time
+Sample Timesample-time
+threadThreadthread
+processProcessprocess
+coreCorecore
+thread-stateStatethread-state
+weightWeightweight
+stackBacktracebacktrace
+383060916
+
+1515263
+
+86036
+TODO
+0
+Running
+1000000
+
+
+
+
+
+
+384060375
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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/PerfTreeParser-Tests/PerfTreeParserTest.class.st b/src/PerfTreeParser-Tests/PerfTreeParserTest.class.st
new file mode 100644
index 0000000..d7beb92
--- /dev/null
+++ b/src/PerfTreeParser-Tests/PerfTreeParserTest.class.st
@@ -0,0 +1,536 @@
+Class {
+ #name : 'PerfTreeParserTest',
+ #superclass : 'TestCase',
+ #instVars : [
+ 'memoryFS',
+ 'fileSimple',
+ 'fileSamePercentage',
+ 'fileMultipleChildren',
+ 'testParserSimple',
+ 'testParserSamePercentage',
+ 'testParserMultipleChildren',
+ 'testNodeSimple',
+ 'testNodeSamePercentage',
+ 'testNodeMultipleChildren'
+ ],
+ #category : 'PerfTreeParser-Tests',
+ #package : 'PerfTreeParser-Tests'
+}
+
+{ #category : 'running' }
+PerfTreeParserTest >> 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: '# ========
+# 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
+'].
+
+ 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
+#
+# 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
+ | |
+'].
+
+ 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
+#
+# 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
+'].
+
+ fileSimple := memoryFS / ('perf_stock_simple.txt').
+ testParserSimple := PerfTreeParser fromFile: fileSimple.
+ testNodeSimple := (PerfTreeParser parseFile: fileSimple) first.
+
+ fileSamePercentage := memoryFS / ('perf_stock_same_percentage.txt').
+ testParserSamePercentage := PerfTreeParser fromFile: fileSamePercentage.
+ testNodeSamePercentage := (PerfTreeParser parseFile: fileSamePercentage) first.
+
+ fileMultipleChildren := memoryFS / ('perf_stock_multiple_children.txt').
+ testParserMultipleChildren := PerfTreeParser fromFile: fileMultipleChildren.
+ testNodeMultipleChildren := (PerfTreeParser parseFile: fileMultipleChildren) first.
+
+]
+
+{ #category : 'running' }
+PerfTreeParserTest >> tearDown [
+
+ fileSimple ensureDelete.
+ fileSamePercentage ensureDelete.
+ fileMultipleChildren ensureDelete.
+ super tearDown
+]
+
+{ #category : 'tests' }
+PerfTreeParserTest >> testDifferenceOfSpacesAt [
+ "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 [
+ "The last has no children"
+
+ self assert: (testParserSimple findChildrenIndexOfIndex:
+ testParserSimple numberOfFunctions) isEmpty.
+
+ "Case where 2 functions have the same number of spaces."
+ self
+ assert: (testParserSimple findChildrenIndexOfIndex: 3)
+ equals: { 4 } asOrderedCollection.
+
+ "Classical case"
+ self
+ assert: (testParserSamePercentage findChildrenIndexOfIndex: 5)
+ equals: { 6 } asOrderedCollection.
+
+ "Multiple children"
+ self
+ assert: (testParserMultipleChildren findChildrenIndexOfIndex: 3)
+ equals: { 4. 5. 8 } asOrderedCollection
+]
+
+{ #category : 'tests' }
+PerfTreeParserTest >> testFindChildrenOfIndex [
+
+ | aNode |
+ aNode := testParserMultipleChildren findChildrenOfIndex: 3.
+
+ self
+ assert: aNode first name
+ equals: (testParserMultipleChildren nameOf: 4).
+ self
+ assert: aNode second name
+ equals: (testParserMultipleChildren nameOf: 5).
+ self
+ assert: aNode third name
+ equals: (testParserMultipleChildren nameOf: 8)
+]
+
+{ #category : 'tests' }
+PerfTreeParserTest >> testFindChildrenOfRecursive [
+
+ | aNode |
+ aNode := testNodeMultipleChildren firstChild firstChild.
+
+ self
+ assert: aNode children second children first name
+ equals: (testParserMultipleChildren nameOf: 6).
+ self
+ assert: aNode children second children first children first name
+ equals: (testParserMultipleChildren nameOf: 7)
+]
+
+{ #category : 'tests' }
+PerfTreeParserTest >> testIsLeaf [
+
+ | example |
+ example := testNodeSimple firstChild firstChild.
+
+ self assert: example isLeaf not.
+ self assert: example isNotLeaf.
+
+ self assert: example children first isLeaf.
+ self assert: example children first isNotLeaf not.
+]
+
+{ #category : 'tests' }
+PerfTreeParserTest >> testLastSpaceAt [
+
+ self assert: (testParserSimple lastSpaceAt: (testParserSimple numberOfFunctions)) equals: 37.
+
+ self assert: (testParserSimple lastSpaceAt: 1) equals: 86.
+
+ self assert: (testParserSimple lastSpaceAt: 2) equals: 15.
+]
+
+{ #category : 'tests' }
+PerfTreeParserTest >> testNameOf [
+ "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: 6) equals: 'vfs_read'
+]
+
+{ #category : 'tests' }
+PerfTreeParserTest >> testNodeAtIndex [
+
+ "Needs more tests!!!"
+]
+
+{ #category : 'tests' }
+PerfTreeParserTest >> 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'
+]
+
+{ #category : 'tests' }
+PerfTreeParserTest >> testNodesSameParent [
+
+ | example |
+ example := (testNodeMultipleChildren firstChild firstChild) children.
+
+ self assert: testNodeMultipleChildren children first children first equals: example first parent.
+
+ self assert: example first parent equals: example second parent
+]
+
+{ #category : 'tests' }
+PerfTreeParserTest >> testNumberOfFunctions [
+
+ self assert: (testParserSimple numberOfFunctions) equals: 4
+]
+
+{ #category : 'tests' }
+PerfTreeParserTest >> testNumberOfSpacesAt [
+
+
+ self assert: (testParserSimple numberOfSpacesAt: (testParserSimple numberOfFunctions)) equals: 27.
+
+ self assert: (testParserSimple numberOfSpacesAt: 1) equals: 4.
+
+ self assert: (testParserSimple numberOfSpacesAt: 3) equals: 16
+]
+
+{ #category : 'tests' }
+PerfTreeParserTest >> testPercentageOf [
+ "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.
+
+ "Case with same percentage"
+ self
+ assert: (testParserSamePercentage percentageOf: 4)
+ equals: (testParserSamePercentage percentageOf: 5).
+
+ self
+ assert: (testParserSamePercentage percentageOf: 5)
+ equals: (testParserSamePercentage percentageOf: 6)
+]
+
+{ #category : 'tests' }
+PerfTreeParserTest >> testReadLine [
+
+ 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' }
+PerfTreeParserTest >> testRealPercentageOf [
+
+ 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
+]
+
+{ #category : 'tests' }
+PerfTreeParserTest >> testTime [
+
+ self assert: testParserSimple time equals: 397.592.
+
+ self assert: testParserSimple root time equals: 397.592.
+]
+
+{ #category : 'tests' }
+PerfTreeParserTest >> testTraces [
+
+ | traces multipleTraces |
+ traces := (PerfTreeParser findTraces: fileSimple) first.
+ 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' }
+PerfTreeParserTest >> testWeight [
+
+ | example |
+ example := testNodeMultipleChildren firstChild firstChild.
+
+ self assert: example weight equals: 6.84.
+]
+
+{ #category : 'tests' }
+PerfTreeParserTest >> testWeightOf [
+
+ self
+ assert:
+ (testParserSimple weightOf: testParserSimple numberOfFunctions)
+ equals: 146.24.
+
+ self assert: (testParserSimple weightOf: 3) equals: 36.31
+]
+
+{ #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
new file mode 100644
index 0000000..312597f
--- /dev/null
+++ b/src/PerfTreeParser-Tests/package.st
@@ -0,0 +1 @@
+Package { #name : 'PerfTreeParser-Tests' }
diff --git a/src/PerfTreeParser/PerfTreeNode.class.st b/src/PerfTreeParser/PerfTreeNode.class.st
new file mode 100644
index 0000000..b336edf
--- /dev/null
+++ b/src/PerfTreeParser/PerfTreeNode.class.st
@@ -0,0 +1,125 @@
+Class {
+ #name : 'PerfTreeNode',
+ #superclass : 'Object',
+ #instVars : [
+ 'name',
+ 'weight',
+ 'children',
+ 'parent',
+ 'totalTime'
+ ],
+ #category : 'PerfTreeParser',
+ #package : 'PerfTreeParser'
+}
+
+{ #category : 'accessing' }
+PerfTreeNode >> children [
+
+ ^ children
+]
+
+{ #category : 'accessing' }
+PerfTreeNode >> children: aCollectionOfTreeNode [
+
+ children:= aCollectionOfTreeNode
+]
+
+{ #category : 'accessing' }
+PerfTreeNode >> collectLeavesIn: leaves [
+
+ (self isLeaf and: [ self isNotAlreadyLeafIn: leaves ]) ifTrue: [
+ leaves add: self ].
+
+ self children do: [ :child | child collectLeavesIn: leaves ].
+
+ ^ leaves
+]
+
+{ #category : 'accessing' }
+PerfTreeNode >> firstChild [
+
+ ^ self children first
+]
+
+{ #category : 'accessing' }
+PerfTreeNode >> isLeaf [
+
+ ^ self children isEmpty
+]
+
+{ #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' }
+PerfTreeNode >> name [
+
+ ^ name
+]
+
+{ #category : 'accessing' }
+PerfTreeNode >> name: aString [
+
+ name := aString
+]
+
+{ #category : 'accessing' }
+PerfTreeNode >> parent [
+
+ ^ parent
+]
+
+{ #category : 'accessing' }
+PerfTreeNode >> parent: aTreeNode [
+
+ parent := aTreeNode
+]
+
+{ #category : 'accessing' }
+PerfTreeNode >> time [
+
+ ^ totalTime
+]
+
+{ #category : 'accessing' }
+PerfTreeNode >> time: aFloat [
+
+ totalTime := aFloat
+]
+
+{ #category : 'accessing' }
+PerfTreeNode >> traces [
+
+ | leaves |
+ leaves := OrderedCollection new.
+ self collectLeavesIn: leaves.
+
+ ^ leaves collect: [ :l |
+ PerfTreeTrace new
+ name: l name;
+ weight: l weight;
+ yourself ]
+]
+
+{ #category : 'accessing' }
+PerfTreeNode >> weight [
+
+ ^ weight
+]
+
+{ #category : 'accessing' }
+PerfTreeNode >> weight: aFloat [
+
+ weight := aFloat
+]
diff --git a/src/PerfTreeParser/PerfTreeParser.class.st b/src/PerfTreeParser/PerfTreeParser.class.st
new file mode 100644
index 0000000..28f6eec
--- /dev/null
+++ b/src/PerfTreeParser/PerfTreeParser.class.st
@@ -0,0 +1,247 @@
+Class {
+ #name : 'PerfTreeParser',
+ #superclass : 'Object',
+ #instVars : [
+ 'content',
+ 'totalTime'
+ ],
+ #category : 'PerfTreeParser',
+ #package : 'PerfTreeParser'
+}
+
+{ #category : 'instance creation' }
+PerfTreeParser class >> findTraces: aFile [
+
+ ^ (self parseFile: aFile) collect: [:tree | tree traces ]
+]
+
+{ #category : 'instance creation' }
+PerfTreeParser class >> fromFile: aFile [
+
+ ^ self new
+ content: aFile asFileReference;
+ yourself
+]
+
+{ #category : 'instance creation' }
+PerfTreeParser class >> parseFile: aFile [
+
+ ^ (self fromFile: aFile) roots
+]
+
+{ #category : 'accessing' }
+PerfTreeParser >> content [
+
+ ^ content
+]
+
+{ #category : 'accessing' }
+PerfTreeParser >> content: aFile [
+ "Extract the interesting content from the file."
+
+ | fileContents i |
+ fileContents := aFile contents lines.
+ i := 1.
+
+ [ (fileContents at: i) beginsWith: '# sample duration' ] whileFalse: [
+ i := i + 1 ].
+
+ self time: ((((fileContents at: i) last: 10) first: 7) copyWithout: Character space) asNumber.
+
+ content := fileContents reject: [ :line | line beginsWith: '#' ].
+ content := content select: [ :line |
+ ((line copyWithout: Character space) copyWithout: $|)
+ isNotEmpty ]
+]
+
+{ #category : 'accessing' }
+PerfTreeParser >> differenceOfSpacesAt: aNodeIndex [
+ "Gives the difference of the number of spaces between 2 followed lines."
+
+ ^ (self numberOfSpacesAt: aNodeIndex + 1)
+ - (self numberOfSpacesAt: aNodeIndex)
+]
+
+{ #category : 'accessing' }
+PerfTreeParser >> findChildrenIndexOfIndex: aNodeIndex [
+ "Gives an ordered collection of every indexes of the lines where there is a child."
+
+ | lastNodeIndex everyChildren newBranch spaces nodeSpaces |
+ lastNodeIndex := self numberOfFunctions.
+ everyChildren := OrderedCollection new.
+
+ (self percentageOf: aNodeIndex) = (self percentageOf: aNodeIndex + 1)
+ ifTrue: [
+ everyChildren add: aNodeIndex + 1.
+ ^ everyChildren ].
+
+ 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: [
+ (self percentageOf: i) ~= (self percentageOf: i - 1) and: [
+ newBranch not ] ]) ifTrue: [ everyChildren add: i ] ].
+
+ ^ everyChildren
+]
+
+{ #category : 'accessing' }
+PerfTreeParser >> findChildrenOfIndex: aNodeIndex [
+ "Gives the nodes representing every children at the node aNodeIndex."
+
+ | collectionOfChildrenIndexes |
+ collectionOfChildrenIndexes := self findChildrenIndexOfIndex: aNodeIndex.
+ ^ collectionOfChildrenIndexes collect: [ :childIndex |
+ self nodeAtIndex: childIndex ]
+]
+
+{ #category : 'accessing' }
+PerfTreeParser >> lastSpaceAt: aLine [
+ "Gives the index of the last space or '-' at a given line."
+
+ | lastSpace line |
+ line := self readLine: aLine.
+ lastSpace := 0.
+
+ 1 to: line size do: [ :i |
+ ((line at: i) = Character space or: [ (line at: i) = $- ]) ifTrue: [
+ lastSpace := i ] ].
+ ^ lastSpace
+]
+
+{ #category : 'accessing' }
+PerfTreeParser >> nameOf: aNodeIndex [
+ "Gives the name of a function at aNodeIndex."
+
+ | aLine |
+ aLine := self readLine: aNodeIndex.
+ ^ aLine last: aLine size - (self lastSpaceAt: aNodeIndex)
+]
+
+{ #category : 'accessing' }
+PerfTreeParser >> nodeAtIndex: aNodeIndex [
+ "Gives the node representing the node at aNodeIndex."
+
+ | node |
+ node := PerfTreeNode new
+ name: (self nameOf: aNodeIndex);
+ weight: (self weightOf: aNodeIndex);
+ time: self time;
+ yourself.
+ node children: (self findChildrenOfIndex: aNodeIndex).
+ node children do: [ :child | child parent: node ].
+ ^ node
+]
+
+{ #category : 'accessing' }
+PerfTreeParser >> numberOfFunctions [
+ "Gives the number of functions present in the file."
+
+ ^ content size
+]
+
+{ #category : 'accessing' }
+PerfTreeParser >> numberOfSpacesAt: aNodeIndex [
+ "Gives the number of spaces at a certain line."
+
+ | count lineRead |
+
+ lineRead := self readLine: aNodeIndex.
+ count := 1.
+
+ [(lineRead at: count) = Character space or: [
+ (lineRead at: count) = $| ] ] whileTrue: [ count := count + 1 ].
+ ^ count - 1
+]
+
+{ #category : 'accessing' }
+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."
+
+ | stringLine numbers |
+ (aLine between: 1 and: self numberOfFunctions) ifFalse: [ ^ 0 ].
+
+ stringLine := ((((self readLine: aLine) copyUpTo: $%) last: 5)
+ copyWithout: $-) copyWithout: Character space.
+
+ stringLine = ((self readLine: aLine) last: 5) ifTrue: [
+ ^ self percentageOf: aLine - 1 ].
+
+ numbers := stringLine asNumber.
+
+ ^ numbers
+]
+
+{ #category : 'accessing' }
+PerfTreeParser >> readLine: anIndex [
+ "Reads a line from the file without the commentaries."
+ ^ self content at: anIndex
+]
+
+{ #category : 'accessing' }
+PerfTreeParser >> realPercentageOf: aNodeIndex [
+
+ | nodePercentage children childrenPercentage |
+ nodePercentage := self percentageOf: aNodeIndex.
+ children := self findChildrenIndexOfIndex: aNodeIndex.
+ childrenPercentage := 0.
+ children ifEmpty: [ ^ nodePercentage ].
+
+
+ childrenPercentage := children sum: [ :child |
+ self percentageOf: child ].
+
+ ^ nodePercentage - childrenPercentage roundUpTo: 0.01
+]
+
+{ #category : 'accessing' }
+PerfTreeParser >> root [
+ "Gives the first parent of the nodes"
+
+ ^ 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 [
+
+ ^ totalTime
+]
+
+{ #category : 'accessing' }
+PerfTreeParser >> time: aFloat [
+
+ totalTime := aFloat.
+]
+
+{ #category : 'accessing' }
+PerfTreeParser >> weightOf: aNodeIndex [
+
+ | newPercentage |
+ newPercentage := self realPercentageOf: aNodeIndex.
+
+ ^ totalTime * (newPercentage/100) roundUpTo: 0.01
+]
+
+{ #category : 'accessing' }
+PerfTreeParser >> withoutSpaces [
+ "Gives a line without the characters that are not interesting."
+
+ ^ self content collect: [ :c |
+ (c copyWithout: Character space) copyWithout: $| ]
+]
diff --git a/src/PerfTreeParser/PerfTreeTrace.class.st b/src/PerfTreeParser/PerfTreeTrace.class.st
new file mode 100644
index 0000000..f369927
--- /dev/null
+++ b/src/PerfTreeParser/PerfTreeTrace.class.st
@@ -0,0 +1,34 @@
+Class {
+ #name : 'PerfTreeTrace',
+ #superclass : 'Object',
+ #instVars : [
+ 'name',
+ 'weight'
+ ],
+ #category : 'PerfTreeParser',
+ #package : 'PerfTreeParser'
+}
+
+{ #category : 'accessing' }
+PerfTreeTrace >> name [
+
+ ^ name
+]
+
+{ #category : 'accessing' }
+PerfTreeTrace >> name: aName [
+
+ name := aName
+]
+
+{ #category : 'accessing' }
+PerfTreeTrace >> weight [
+
+ ^ weight
+]
+
+{ #category : 'accessing' }
+PerfTreeTrace >> weight: aFloat [
+
+ weight := aFloat
+]
diff --git a/src/PerfTreeParser/package.st b/src/PerfTreeParser/package.st
new file mode 100644
index 0000000..294aff7
--- /dev/null
+++ b/src/PerfTreeParser/package.st
@@ -0,0 +1 @@
+Package { #name : 'PerfTreeParser' }
diff --git a/src/TreeParser-Tests/TreeParserTest.class.st b/src/TreeParser-Tests/TreeParserTest.class.st
deleted file mode 100644
index ad2c4ad..0000000
--- a/src/TreeParser-Tests/TreeParserTest.class.st
+++ /dev/null
@@ -1,205 +0,0 @@
-Class {
- #name : #TreeParserTest,
- #superclass : #TestCase,
- #instVars : [
- 'memoryFS',
- 'fileSimple',
- 'fileSamePercentage',
- 'fileMultipleChildren',
- 'treeSimple',
- 'treeSamePercentage',
- 'treeMultipleChildren',
- 'testNodeSimple',
- 'testNodeSamePercentage',
- 'testNodeMultipleChildren'
- ],
- #category : #'TreeParser-Tests'
-}
-
-{ #category : #running }
-TreeParserTest >> setUp [
-
- 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.
-#
-#
-# 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
-'].
-
- memoryFS / ('perf_stock_same_percentage.txt') writeStreamDo: [:stream | stream nextPutAll: '# To display the perf.data header info, please use --header/--header-only options.
-#
-#
-# 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
- | |
-'].
-
- memoryFS / ('perf_stock_multiple_children.txt') writeStreamDo: [:stream | stream nextPutAll: '# To display the perf.data header info, please use --header/--header-only options.
-#
-#
-# 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
-'].
-
- fileSimple := memoryFS / ('perf_stock_simple.txt').
- treeSimple := TreeParse fromFile: fileSimple.
- testNodeSimple := treeSimple asNodes.
-
- fileSamePercentage := memoryFS / ('perf_stock_same_percentage.txt').
- treeSamePercentage := TreeParse fromFile: fileSamePercentage.
- testNodeSamePercentage := treeSamePercentage asNodes.
-
- fileMultipleChildren := memoryFS / ('perf_stock_multiple_children.txt').
- treeMultipleChildren := TreeParse fromFile: fileMultipleChildren.
- testNodeMultipleChildren := treeMultipleChildren asNodes.
-
-]
-
-{ #category : #running }
-TreeParserTest >> tearDown [
-
- fileSimple ensureDelete.
- fileSamePercentage ensureDelete.
- fileMultipleChildren ensureDelete.
- super tearDown
-]
-
-{ #category : #tests }
-TreeParserTest >> testClassify [
-
- | family example |
- 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'.
-
- 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 >> testFindChildrenOf [
-
- self assert:
- (testNodeMultipleChildren findChildrenOf: 3) first equals: 4.
-
- self assert:
- (testNodeMultipleChildren findChildrenOf: 3) second equals: 5.
-
- self assert:
- (testNodeMultipleChildren findChildrenOf: 3) third equals: 8
-]
-
-{ #category : #tests }
-TreeParserTest >> testFindParentOf [
-
- self assert: (testNodeMultipleChildren findParentOf: 4) equals: 3.
-
- self assert: (testNodeMultipleChildren findParentOf: 6) equals: 5
-]
-
-{ #category : #tests }
-TreeParserTest >> testNameOf [
-
- self assert: (testNodeSimple nameOf: 1) equals: 'entry_SYSCALL_64_after_hwframe'.
-
- self assert: (testNodeSamePercentage nameOf: 4) equals: '__x64_sys_read'.
-
- self assert: (testNodeSamePercentage nameOf: 6) equals: 'vfs_read'
-]
-
-{ #category : #tests }
-TreeParserTest >> testNumberOfFunctions [
-
- self assert: (testNodeSimple numberOfFunctions) equals: 4
-]
-
-{ #category : #tests }
-TreeParserTest >> testNumberOfSpaces [
-
- self assert: (testNodeSimple numberOfSpacesAt: 1) equals: 4
-]
-
-{ #category : #tests }
-TreeParserTest >> testReadALine [
-
- self assert: (treeSimple readLine: 3) equals: ' ---entry_SYSCALL_64_after_hwframe'
-]
-
-{ #category : #tests }
-TreeParserTest >> testSimplePercentageOf [
-
- self assert: (testNodeSimple percentageOf: 3) equals: 45.91
-]
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/TreeChildren.class.st b/src/TreeParser/TreeChildren.class.st
deleted file mode 100644
index 797575c..0000000
--- a/src/TreeParser/TreeChildren.class.st
+++ /dev/null
@@ -1,82 +0,0 @@
-Class {
- #name : #TreeChildren,
- #superclass : #Object,
- #instVars : [
- 'parent',
- 'children',
- 'name',
- 'percentage'
- ],
- #category : #TreeParser
-}
-
-{ #category : #accessing }
-TreeChildren >> children [
-
- ^ children
-]
-
-{ #category : #accessing }
-TreeChildren >> children: aTreeChildren [
-
- children := aTreeChildren.
-]
-
-{ #category : #accessing }
-TreeChildren >> estimatePercentage [
-
- | sumOfPercents |
- sumOfPercents := 0.
- self children collect: [ :n |
- sumOfPercents := n percentage + sumOfPercents ].
-
- percentage - sumOfPercents >= 0
- ifTrue: [ percentage := (percentage - sumOfPercents) roundUpTo: 0.01 ].
- ^ percentage
-]
-
-{ #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 >> 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
-]
diff --git a/src/TreeParser/TreeNodes.class.st b/src/TreeParser/TreeNodes.class.st
deleted file mode 100644
index 696a389..0000000
--- a/src/TreeParser/TreeNodes.class.st
+++ /dev/null
@@ -1,169 +0,0 @@
-Class {
- #name : #TreeNodes,
- #superclass : #Object,
- #instVars : [
- 'nodes'
- ],
- #category : #TreeParser
-}
-
-{ #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);
- parent: aParent.
- child children: ((self findChildrenOf: aLine) collect: [ :c |
- self classify: c withParent: child ]).
- ^ child
-]
-
-{ #category : #accessing }
-TreeNodes >> differenceOfSpacesAt: aNode [
- "Gives the difference of the number of spaces between 2 followed lines."
-
- self assert: aNode < self numberOfFunctions.
- ^ (self numberOfSpacesAt: aNode + 1) - (self numberOfSpacesAt: aNode)
-]
-
-{ #category : #accessing }
-TreeNodes >> findChildrenOf: 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 ].
-
- ((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 >> findParentOf: aNode [
- "Gives the index of the line where the parent is."
-
- | i |
- i := aNode-1.
- [ i > 1 and: [ ( (self numberOfSpacesAt: aNode) - (self numberOfSpacesAt: i) ) < 0 ] ]
- whileTrue: [ i := i - 1 ].
-
- (i > 0)
- ifTrue: [ ^ i ]
- ifFalse: [ ^ nil ]
-]
-
-{ #category : #accessing }
-TreeNodes >> lastNodeOf: aNode [
- "Give the index of the last node starting from a given node."
-
- | lastNode |
- lastNode := self numberOfFunctions.
- aNode to: lastNode - 1 do: [ :i |
- (self differenceOfSpacesAt: i) < 0 ifTrue: [ ^ i ] ].
- ^ aNode
-]
-
-{ #category : #accessing }
-TreeNodes >> lastSpaceAt: aLine [
- "Gives the index of the last space at a given line."
-
- | lastSpace line|
- line := nodes 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 |
- line := (self withoutSpaces at: aLine) copyWithout: $-.
- ^ line last: (self lastSpaceAt: aLine)
-]
-
-{ #category : #accessing }
-TreeNodes >> nodes [
-
- ^ nodes
-]
-
-{ #category : #accessing }
-TreeNodes >> nodes: aContent [
-
- nodes := aContent select: [ :c |
- ((c copyWithout: Character space) copyWithout: $|)
- isNotEmpty ]
-]
-
-{ #category : #accessing }
-TreeNodes >> numberOfFunctions [
- "Gives the number of non-unique functions mentioned in the file."
-
- ^ nodes 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 >= 1.
- 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 >> 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/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/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 }