Usage Examples¶
Real tasks you can solve with Amphimixis.
Porting an application to RISC-V¶
We use TinyXML-2 as the target project and the distributed-cross configuration below. Amphimixis builds and runs the project natively on both machines, profiles it, and produces a cross-table that compares the two builds per CPU event.
Set up the configuration¶
We build and run the project on two platforms:
platform
1— local x86 machine (baseline)platform
2— remote RISC-V machine (migration target)
# distributed.yml
platforms:
- id: 1
arch: x86
- id: 2
arch: riscv
address: 10.141.237.177
username: root
password: bianbu
recipes:
- id: 1
config_flags: "-DCMAKE_BUILD_TYPE=RelWithDebInfo"
- id: 2
config_flags: "-DCMAKE_BUILD_TYPE=RelWithDebInfo"
builds:
- build_machine: 1
run_machine: 1
recipe_id: 1
- build_machine: 2
run_machine: 2
recipe_id: 2
Each build gets an automatically generated name in the form
build_machine_run_machine_recipe_id, so our two builds are called:
1_1_1— built and run on x862_2_2— built and run on RISC-V
For the full list of supported fields, see the Configuration File Guide.
Run the pipeline¶
amixis run --config distributed.yml /path/to/tinyxml2
Amphimixis analyzes the project, builds it on both machines, profiles the
xmltest executable with perf, and saves the profiling data as
.scriptout files:
2__2__2..xmltest.scriptout # RISC-V build
1__1__1..xmltest.scriptout # x86 build
Compare the two builds¶
To compare the profiling results and see how CPU time is distributed per function, run:
amixis compare 2__2__2..xmltest.scriptout 1__1__1..xmltest.scriptout --max-rows 10
Amphimixis prints one cross-table per perf event. Each table shows, for every
function, its share of samples in each build and the difference between them.
The first file is Build A and the second is Build B.
Reading the cross-table¶
Below is the comparison output converted from the console for readability.
Build A (2_2_2) is the RISC-V build and Build B (1_1_1) is the
x86.
A positive Delta means the function takes a larger share on x86.
A negative Delta means it takes a larger share on RISC-V.
EVENT: BRANCH-MISSES¶
Symbol |
2_2_2 (RISC-V) % |
1_1_1 (x86) % |
Delta % |
|---|---|---|---|
|
0.00 |
32.97 |
+32.97 |
|
35.59 |
6.42 |
-29.17 |
|
25.75 |
0.00 |
-25.75 |
|
8.62 |
25.64 |
+17.02 |
|
0.00 |
9.72 |
+9.72 |
|
0.00 |
6.38 |
+6.38 |
|
4.67 |
0.00 |
-4.67 |
|
3.73 |
0.00 |
-3.73 |
|
0.00 |
3.26 |
+3.26 |
|
0.00 |
3.22 |
+3.22 |
The branch-miss profile clearly differs between the two platforms:
x86 uses glibc’s vectorized
__strncmp_evex(AVX-512) EVEX encoding alone accounts for 32.97% of branch misses. It does not exist on RISC‑V.On RISC-V, the same work falls on scalar glibc
strncmp(25.75%) and on unresolved samples marked[unknown](35.59%).
tinyxml2::StrPair::ParseTextis a hot spot on x86 (25.64%) but much less so on RISC-V (8.62%).
EVENT: CACHE-MISSES¶
Symbol |
2_2_2 (RISC-V) % |
1_1_1 (x86) % |
Delta % |
|---|---|---|---|
|
0.00 |
57.89 |
+57.89 |
|
0.00 |
9.04 |
+9.04 |
|
0.00 |
7.23 |
+7.23 |
|
0.00 |
5.18 |
+5.18 |
|
0.00 |
4.85 |
+4.85 |
|
0.00 |
4.75 |
+4.75 |
|
0.00 |
4.51 |
+4.51 |
|
0.00 |
2.89 |
+2.89 |
|
0.00 |
2.75 |
+2.75 |
|
0.00 |
0.91 |
+0.91 |
What do
[unknown]and0.00%mean?
The zeros in the RISC-V column do not mean there were no cache misses — the RISC-V kernel/hardware returns no samples for
cache-misses(event has not been registered on this platform), so Amphimixis had nothing to sample. The Delta column only highlights differences that appear in both builds.
[unknown]are unresolved samples (missing debug info or kernel/dynamic loader activity).
EVENT: CYCLES¶
Symbol |
2_2_2 (RISC-V) % |
1_1_1 (x86) % |
Delta % |
|---|---|---|---|
|
6.86 |
16.43 |
+9.56 |
|
12.25 |
3.27 |
-8.99 |
|
0.00 |
8.32 |
+8.32 |
|
7.35 |
0.00 |
-7.35 |
|
0.00 |
6.69 |
+6.69 |
|
6.37 |
0.00 |
-6.37 |
|
4.90 |
0.00 |
-4.90 |
|
4.41 |
0.00 |
-4.41 |
|
3.43 |
0.00 |
-3.43 |
|
8.82 |
11.53 |
+2.71 |
|
2.45 |
4.94 |
+2.48 |
|
19.61 |
21.93 |
+2.33 |
|
1.96 |
0.00 |
-1.96 |
|
3.43 |
1.53 |
-1.90 |
|
0.00 |
1.74 |
+1.74 |
|
0.00 |
1.71 |
+1.71 |
|
0.00 |
1.66 |
+1.66 |
|
0.00 |
1.66 |
+1.66 |
|
0.00 |
1.64 |
+1.64 |
|
0.00 |
1.63 |
+1.63 |
The cycle profile tells a similar story:
tinyxml2::XMLDocument::Identify— a routine that scans and compares strings — grows from 3.27% of cycles on x86 to 12.25% on RISC-V. It relies onstrncmp, and without the vectorized x86 implementation this routine becomes one of the hottest spots on RISC-V.
strncmpappears only in the RISC-V build (7.35%), confirming that string comparison is a migration cost driver.Several memory-management symbols (
_int_malloc, destructors,DeleteNode) show only on x86, while parsing and attribute routines become relatively more visible on RISC-V.
What to do next¶
The cross-table shows where you should look to find weak places in code. Common next steps, described in the Migration Readiness Methodology:
Try compiler vectorization flags (
-ftree-vectorizefor GCC/Clang) and a newer RISC-V toolchain with a vector-capablestrncmpormemcpy.Build with LTO to help the compiler inline and optimize hot routines like
XMLDocument::IdentifyandStrPair::ParseText.If needed, check
[unknown]in the full output – usually fixed by building withRelWithDebInfoandperf archive. — they often indicate missing debug info or kernel/dynamic-loader activity during profiling.
For details on every command used in this example, see the
Usage Guide. If the RISC-V machine does not support a perf
event you need, see Troubleshooting.