Skip to content

Perf#269

Open
MatthewKhouzam wants to merge 2 commits into
eclipse-tracecompass-incubator:masterfrom
MatthewKhouzam:perf
Open

Perf#269
MatthewKhouzam wants to merge 2 commits into
eclipse-tracecompass-incubator:masterfrom
MatthewKhouzam:perf

Conversation

@MatthewKhouzam
Copy link
Copy Markdown
Contributor

@MatthewKhouzam MatthewKhouzam commented May 1, 2026

What it does

Adds a new perf.data trace type that parses Linux perf.data files directly, and builds flame chart / flame graph analyses on top of it.

image
  • New bundle org.eclipse.tracecompass.incubator.perf.core with PerfDataReader (random-access reader supporting PERFILE2/PERFILE1, both endiannesses, attrs, features, and data-stream records) and PerfDataTrace (TmfTrace subclass with aspects for timestamp, event type, PID, TID, CPU, IP, Address, Comm, Filename).
  • New test bundle org.eclipse.tracecompass.incubator.perf.core.tests with validation, reader, and event-iteration tests against a bundled sample perf.data file.
  • PerfDataCallchainAnalysisModule: reads callchain arrays from PERF_RECORD_SAMPLE events, strips context sentinels, reverses frames, and groups by process/thread for the Flame Chart / Flame Graph views.
  • PerfDataMmapStateProvider + PerfDataMmapAnalysisModule: tracks MMAP/MMAP2 events to map load addresses to ELF libraries.
  • PerfDataMmapSymbolProvider: resolves callchain IPs to symbols via the mmap state system and IMappingFile.
  • Additional test fixture (perf-callgraph.data) and callchain shape/content tests.

How to test

  1. Capture a trace: perf record -g (e.g. perf record -g ping 4.4.4.4 -c 3).
  2. Open the resulting perf.data file in Trace Compass — it should be recognized as a "Perf Data" trace.
  3. Verify events are listed with correct PID/TID/CPU/IP fields.
  4. Open the Flame Chart and Flame Graph views — they should populate with callchain data from the trace.
  5. Run the unit tests in org.eclipse.tracecompass.incubator.perf.core.tests.

Follow-ups

  • Symbol resolution falls back to the filename when a symbol cannot be resolved from disk — full DWARF/ELF resolution could be improved.

Review checklist

  • As an author, I have thoroughly tested my changes and carefully followed the instructions in this template

Summary by CodeRabbit

  • New Features

    • Added support for perf.data trace files as a new trace type in Eclipse Trace Compass.
    • Introduced callchain analysis module for performance profiling with callstack visualization.
    • Added automatic symbol resolution using memory mapping data for library address translation.
  • Tests

    • Added comprehensive test suite validating perf.data file parsing, callchain data integrity, and trace event handling.

Add a new trace type that parses Linux perf.data files directly,
following the layout described in perf_data_format.md.

New bundle: org.eclipse.tracecompass.incubator.perf.core
 - PerfDataReader: random-access reader for the file header
   (PERFILE2 / PERFILE1, little- and big-endian), attrs section
   (perf_event_attr + per-attr event IDs), feature sections
   (hostname, osrelease, arch, cpudesc, cpuid, cmdline, nr_cpus),
   and data-stream records (MMAP, MMAP2, COMM, FORK, EXIT, SAMPLE,
   SWITCH, SWITCH_CPU_WIDE, LOST, THROTTLE, UNTHROTTLE,
   FINISHED_ROUND, FINISHED_INIT), including the trailing sample_id
   block when sample_id_all is set. Piped headers are detected but
   their record stream is not decoded yet.
 - PerfDataTrace: TmfTrace subclass registered via plugin.xml,
   with aspects for timestamp, event type, PID, TID, CPU, IP,
   Address, Comm and Filename. Exposes trace metadata through
   ITmfPropertiesProvider.

New bundle: org.eclipse.tracecompass.incubator.perf.core.tests
 - PerfDataTraceTest with validate/reader/event-iteration tests,
   driven by a bundled sample perf.data file.

Register both bundles in tracetypes/pom.xml.

This code was written with the assistance of claude opus 4.7

Signed-off-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
Change-Id: I43f44e9f1eaef3c886c36d9eb3a4565c92bc96bc
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 1, 2026

📝 Walkthrough

Walkthrough

A new Eclipse Trace Compass plug-in is introduced for parsing and analyzing Linux perf.data trace files. The implementation spans two bundles—core parsing logic and test suite—with modules for file reading, callchain sampling analysis, and memory-mapped symbol resolution using state systems.

Changes

Cohort / File(s) Summary
Test project structure
tracetypes/org.eclipse.tracecompass.incubator.perf.core.tests/.*classpath, .gitignore, .project, .settings/*
Eclipse project configuration and IDE preferences for the test bundle (Java 17, PDE builders, encoding, compiler/formatter settings).
Test project metadata
tracetypes/org.eclipse.tracecompass.incubator.perf.core.tests/META-INF/MANIFEST.MF, about.html, build.properties, plugin.properties
OSGi bundle manifest declaring required dependencies (JUnit, perf.core, TMF modules), exported test packages, and plugin metadata.
Test code
tracetypes/org.eclipse.tracecompass.incubator.perf.core.tests/src/.../PerfDataTraceTest.java, PerfDataCallchainTest.java
JUnit test suite validating perf.data header parsing, record decoding (MMAP2 timestamps, record iteration), trace initialization, callchain presence, and IP filtering.
Core project structure
tracetypes/org.eclipse.tracecompass.incubator.perf.core/.*classpath, .gitignore, .project, .settings/*
Eclipse project configuration and comprehensive IDE preferences (Java 17, PDE/API analysis builders, code formatting, compiler strictness).
Core project metadata
tracetypes/org.eclipse.tracecompass.incubator.perf.core/META-INF/MANIFEST.MF, about.html, build.properties, plugin.properties, plugin.xml
OSGi bundle manifest, plugin descriptor registering trace type category, analysis modules (callchain/mmap), symbol provider factory, and plugin display properties.
Core infrastructure
tracetypes/org.eclipse.tracecompass.incubator.perf.core/src/.../Activator.java, PerfConstants.java, PerfFileSection.java, PerfFileHeader.java, PerfEventAttr.java, PerfRecord.java, package-info.java
Bootstrap activator, 100+ perf-format constants (magic bytes, header feature bits, record type IDs, sample bitmasks, CPU modes), and immutable data containers for file headers, sections, event attributes, and parsed records.
File reader core
tracetypes/org.eclipse.tracecompass.incubator.perf.core/src/.../PerfDataReader.java
Comprehensive random-access reader (807 lines) parsing perf.data headers, attributes, feature metadata, and records; decodes 15+ record types (MMAP/MMAP2/COMM/FORK/SAMPLE/etc.) with field extraction, endianness handling, timestamp extraction, and callchain/sample-id support.
Trace implementation
tracetypes/org.eclipse.tracecompass.incubator.perf.core/src/.../trace/PerfDataTrace.java, PerfEventType.java, package-info.java
Trace type implementing event parsing by converting PerfRecords to TmfEvents; includes timestamp mapping, event-type lookup registry, custom aspects (PID/TID/IP/CPU), and file metadata exposure.
Callchain analysis
tracetypes/org.eclipse.tracecompass.incubator.perf.core/src/.../analysis/PerfDataCallchainAnalysisModule.java, package-info.java
Analysis module filtering SAMPLE events, extracting callchains from records, filtering sentinel addresses, and building call-stack hierarchies (CallStackElement) with sampling data aggregation.
Symbol resolution
tracetypes/org.eclipse.tracecompass.incubator.perf.core/src/.../symbol/PerfDataMmapAnalysisModule.java, PerfDataMmapStateProvider.java, PerfDataMmapSymbolProvider.java, PerfDataMmapSymbolProviderFactory.java, TmfLibrarySymbol.java, package-info.java
State-system analysis tracking MMAP/MMAP2 load bases per-process; symbol provider resolving addresses via ELF file lookup with load-base adjustment and filename enrichment; factory pattern for provider instantiation.
Build configuration
tracetypes/pom.xml
Maven module registration for perf.core and perf.core.tests submodules.

Sequence Diagram

sequenceDiagram
    participant User
    participant TMF as TMF/Trace
    participant PerfDataTrace as PerfDataTrace
    participant Reader as PerfDataReader
    participant Analysis as AnalysisModule
    participant StateSystem as StateSystem
    participant SymbolProvider as SymbolProvider

    User->>TMF: Open perf.data file
    TMF->>PerfDataTrace: initTrace()
    PerfDataTrace->>Reader: new PerfDataReader(file)
    Reader->>Reader: Parse header & attrs
    Note over Reader: Extract magic, features,<br/>metadata, data offset
    
    User->>TMF: Iterate events
    TMF->>PerfDataTrace: parseEvent(context)
    PerfDataTrace->>Reader: readRecordAt(offset)
    Reader->>Reader: Decode record type<br/>(MMAP2, SAMPLE, etc.)
    Reader-->>PerfDataTrace: PerfRecord
    PerfDataTrace->>PerfDataTrace: Convert to TmfEvent
    PerfDataTrace-->>TMF: TmfEvent
    
    TMF->>Analysis: Process event
    alt SAMPLE record
        Analysis->>Analysis: Extract callchain
        Analysis->>Analysis: Build call stack
        Analysis-->>TMF: CallStackElement
    else MMAP/MMAP2 record
        Analysis->>StateSystem: Write load_base
        StateSystem-->>Analysis: State updated
    end
    
    User->>SymbolProvider: Resolve address<br/>(pid, timestamp, addr)
    SymbolProvider->>StateSystem: Query MMAP quark
    StateSystem-->>SymbolProvider: filename@timestamp
    SymbolProvider->>SymbolProvider: Load ELF & lookup symbol
    SymbolProvider-->>User: TmfLibrarySymbol
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 A perf data dream, so precise and keen,
Parsing magic bytes where the traces have been,
Callchains unwinding, addresses bright,
Symbol resolution takes flight, takes flight!
State systems building libraries' tale,
Linux profiling will never fail!

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Title check ⚠️ Warning The PR title 'Perf' is extremely vague and fails to capture the substantial scope of changes, which include adding a new perf.data trace type, reader, analysis modules, symbol resolution, and test bundles. Use a more descriptive title such as 'Add perf.data trace type support with callchain and symbol analysis' or 'Add Linux perf.data tracing support to incubator' to clearly indicate the main feature being introduced.
Docstring Coverage ⚠️ Warning Docstring coverage is 57.04% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🧹 Nitpick comments (7)
tracetypes/org.eclipse.tracecompass.incubator.perf.core/src/org/eclipse/tracecompass/incubator/internal/perf/core/symbol/PerfDataMmapSymbolProvider.java (1)

48-48: ⚖️ Poor tradeoff

Symbol mapping cache grows unbounded.

fSymbolMapping caches IMappingFile instances per filename but is never cleared. For long traces with many unique libraries, this could consume significant memory. Consider implementing a size-bounded cache or clearing on dispose.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@tracetypes/org.eclipse.tracecompass.incubator.perf.core/src/org/eclipse/tracecompass/incubator/internal/perf/core/symbol/PerfDataMmapSymbolProvider.java`
at line 48, The fSymbolMapping Map in PerfDataMmapSymbolProvider stores
IMappingFile instances indefinitely causing unbounded growth; fix this by making
the cache size-bounded or ensuring it is cleared on lifecycle end—either replace
the HashMap with an LRU-capable map (e.g., LinkedHashMap with accessOrder and
max size eviction) keyed by filename or explicitly clear fSymbolMapping in the
provider's dispose/close method (add/override dispose() in
PerfDataMmapSymbolProvider to iterate/close any IMappingFile resources if needed
and call fSymbolMapping.clear()). Ensure any IMappingFile cleanup is performed
before removing entries.
tracetypes/org.eclipse.tracecompass.incubator.perf.core.tests/src/org/eclipse/tracecompass/incubator/perf/core/tests/PerfDataTraceTest.java (2)

129-135: 💤 Low value

Potential ClassCastException on field access.

The cast (String) rec.getField("filename") on line 131 assumes the field is always a String. If the reader ever returns a different type (or the record is malformed), this will throw a ClassCastException. Since line 129 already asserts non-null, consider using instanceof before casting for robustness.

Suggested safer cast
                     assertNotNull("filename", rec.getField("filename")); //$NON-NLS-1$ //$NON-NLS-2$
-                    assertTrue("filename non-empty", //$NON-NLS-1$
-                            !((String) rec.getField("filename")).isEmpty()); //$NON-NLS-1$
+                    Object fnObj = rec.getField("filename"); //$NON-NLS-1$
+                    assertTrue("filename is a String", fnObj instanceof String); //$NON-NLS-1$
+                    assertTrue("filename non-empty", !((String) fnObj).isEmpty()); //$NON-NLS-1$
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@tracetypes/org.eclipse.tracecompass.incubator.perf.core.tests/src/org/eclipse/tracecompass/incubator/perf/core/tests/PerfDataTraceTest.java`
around lines 129 - 135, The test assumes rec.getField("filename") is a String
and casts directly, which can throw ClassCastException; change the assertion to
first verify the field is a non-null String (e.g. use instanceof to assert
rec.getField("filename") instanceof String) and only then test that ((String)
rec.getField("filename")).isEmpty() (or use
String.valueOf(rec.getField("filename")).isEmpty() if you intend to accept
non-String values), referencing the existing rec.getField("filename") usage and
the surrounding assertions so the filename check is robust against
non-String/malformed records.

198-208: 💤 Low value

Fallback path returned without existence check.

resolvePath() returns the last fallback path unconditionally (line 207) even if the file doesn't exist. This may cause tests to fail with confusing "file not found" errors rather than a clear message about the missing test fixture.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@tracetypes/org.eclipse.tracecompass.incubator.perf.core.tests/src/org/eclipse/tracecompass/incubator/perf/core/tests/PerfDataTraceTest.java`
around lines 198 - 208, resolvePath currently returns the final fallback File
unconditionally even if it doesn't exist; update resolvePath to verify the
existence of that final candidate (and the earlier candidates) and if none exist
throw an informative exception (e.g., IllegalStateException) that lists the
attempted paths (direct, bundleRel, and the fallback) so tests fail with a clear
message rather than returning a non-existent File; reference the resolvePath
method and the local variables direct and bundleRel when locating where to add
the existence check and the exception.
tracetypes/org.eclipse.tracecompass.incubator.perf.core/src/org/eclipse/tracecompass/incubator/internal/perf/core/analysis/PerfDataCallchainAnalysisModule.java (2)

296-301: ⚖️ Poor tradeoff

Linear merge loop in sampling request.

The merge logic iterates through fSites linearly for each sample. For traces with many distinct callsites, this O(n²) behavior could be slow. A Map<Object, AggregatedCallSite> keyed by sample.getObject() would provide O(1) lookups.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@tracetypes/org.eclipse.tracecompass.incubator.perf.core/src/org/eclipse/tracecompass/incubator/internal/perf/core/analysis/PerfDataCallchainAnalysisModule.java`
around lines 296 - 301, The current O(n²) merge loop using fSites should be
replaced with a Map keyed by sample.getObject() to give O(1) lookups: change the
collection type from the current List/Collection fSites to a Map<Object,
AggregatedCallSite> (or add a parallel Map) in PerfDataCallchainAnalysisModule,
populate the map from existing fSites when initializing, then in the insertion
logic replace the linear loop that checks
existing.getObject().equals(sample.getObject()) and calls existing.merge(sample)
with a direct map lookup by sample.getObject() and call merge if present or put
a new AggregatedCallSite otherwise; also update any other places that iterate
fSites to either iterate map.values() or keep a single source of truth to avoid
inconsistencies.

170-203: ⚖️ Poor tradeoff

Linear lookup on every event may impact performance.

getElement() performs a linear stream search through getRootElements() for each event (line 175-177), and another linear search through children (line 194-196). For traces with many processes/threads and millions of samples, this O(n) lookup per event could become a bottleneck.

Consider caching elements in a Map<Integer, ICallStackElement> keyed by pid (and a nested map for tid) to achieve O(1) lookups.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@tracetypes/org.eclipse.tracecompass.incubator.perf.core/src/org/eclipse/tracecompass/incubator/internal/perf/core/analysis/PerfDataCallchainAnalysisModule.java`
around lines 170 - 203, getElement currently scans getRootElements() and
processEl.getChildrenElements() on every event (using streams) which is O(n) per
event; replace that linear lookup with cached maps: add a Map<Integer,
ICallStackElement> pidToProcess and for each process a Map<Integer,
ICallStackElement> pidToTidMap (or a Map<Integer, Map<Integer,
ICallStackElement>>) keyed by pid→tid to provide O(1) lookups inside getElement;
when you create a new processEl or threadEl (the CallStackElement instances
constructed in getElement) insert them into the maps, and when adding/removing
root elements update the maps accordingly; ensure getElement consults the maps
first instead of calling getRootElements() or iterating children to preserve
existing behavior.
tracetypes/org.eclipse.tracecompass.incubator.perf.core.tests/src/org/eclipse/tracecompass/incubator/perf/core/tests/PerfDataCallchainTest.java (1)

78-80: 💤 Low value

Redundant assertion placement.

assertNotNull(file) on line 79 is placed after file has already been used multiple times (lines 49-50, 57, etc.). If the file were null, the test would have already failed. Consider moving this assertion to the beginning or removing it.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@tracetypes/org.eclipse.tracecompass.incubator.perf.core.tests/src/org/eclipse/tracecompass/incubator/perf/core/tests/PerfDataCallchainTest.java`
around lines 78 - 80, The assertNotNull(file) is redundant where it's placed
after file has already been dereferenced; either remove this late check or move
it up immediately after the code that constructs/obtains the file variable so
the null check happens before any use. Update the PerfDataCallchainTest test to
either delete the trailing assertNotNull(file) or relocate it to directly follow
the assignment/creation of file (the variable named file used earlier in the
test) so that any null-file failure occurs before calls that use file and before
assertions on samples.
tracetypes/org.eclipse.tracecompass.incubator.perf.core/src/org/eclipse/tracecompass/incubator/internal/perf/core/PerfDataReader.java (1)

684-695: 💤 Low value

Potential integer overflow in callchain size validation.

Line 686 compares nr (a long) against body.remaining() / 8, but if nr is extremely large (close to Long.MAX_VALUE), the subsequent cast to int on line 690 could overflow silently. While unlikely with valid perf data, consider clamping to Integer.MAX_VALUE.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@tracetypes/org.eclipse.tracecompass.incubator.perf.core/src/org/eclipse/tracecompass/incubator/internal/perf/core/PerfDataReader.java`
around lines 684 - 695, The callchain parsing in PerfDataReader reads nr as a
long and later casts to int without guarding against very large values; update
the validation to ensure nr is non-negative and <= Integer.MAX_VALUE and also <=
body.remaining()/8 before allocating the array and casting, e.g., clamp or fail
when nr > Integer.MAX_VALUE (and treat it as malformed), then safely cast
(int)nr for the new long[nr] and the loop that fills ips before putting
"callchain" into fields.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tracetypes/org.eclipse.tracecompass.incubator.perf.core.tests/about.html`:
- Line 19: Replace the plaintext HTTP links in the about page content with
HTTPS: locate the occurrences of "http://www.eclipse.org/legal/epl-2.0" and the
other external link using "http://" in the about.html content and change them to
"https://..." so both external links use HTTPS to avoid mixed/insecure
navigation from plugin metadata pages; ensure you update both occurrences (the
one shown and the other at the second occurrence).

In `@tracetypes/org.eclipse.tracecompass.incubator.perf.core/about.html`:
- Line 19: Update the anchor hrefs in the about.html anchors that currently use
"http://www.eclipse.org/..." (e.g., the license link
"http://www.eclipse.org/legal/epl-2.0" and the other http anchor on the page) to
use HTTPS ("https://...") so both external links use secure https URLs; edit the
anchor href attributes in the about.html markup accordingly.

In
`@tracetypes/org.eclipse.tracecompass.incubator.perf.core/src/org/eclipse/tracecompass/incubator/internal/perf/core/PerfDataReader.java`:
- Around line 81-86: In PerfDataReader (inside the fHeader.isPiped() branch)
remove the dead standalone calls to Map.of() and
Collections.unmodifiableMap(byId) (they produce values that are never assigned);
either delete these statements or replace them by assigning their results to the
appropriate fields (e.g. assign Map.of() to fFeatures or fMetadata if that was
intended) so only meaningful assignments remain for fAttrs, fDefaultAttr,
fFeatures, and fMetadata.

In
`@tracetypes/org.eclipse.tracecompass.incubator.perf.core/src/org/eclipse/tracecompass/incubator/internal/perf/core/PerfFileHeader.java`:
- Around line 135-137: getFeatures() currently returns the internal fFeatures
array from the immutable PerfFileHeader class which allows external mutation;
change getFeatures() to return a defensive copy of fFeatures (e.g., create and
return a new long[] copy or use Arrays.copyOf) so callers cannot modify the
internal state while keeping the method signature the same.

In
`@tracetypes/org.eclipse.tracecompass.incubator.perf.core/src/org/eclipse/tracecompass/incubator/internal/perf/core/symbol/PerfDataMmapStateProvider.java`:
- Around line 79-81: The current early return for pid < 0 drops kernel/module
mappings (pid == -1); instead, change the pid check so pid == -1 is NOT
discarded and is stored in a dedicated global bucket inside
PerfDataMmapStateProvider (create or reuse a globalMmaps/map for kernel
mappings) while preserving ignoring other negative pids if necessary, and update
the symbol lookup in PerfDataMmapSymbolProvider to consult that global bucket
when a per-process lookup misses; modify the mmap-handling branch where the pid
check occurs to branch on pid == -1 (store to global) vs pid >= 0 (store
per-process) and ensure lookup code queries globalMmaps as a fallback.
- Around line 56-60: The eventHandle currently filters to only MMAP/MMAP2 and
ignores PERF_RECORD_FORK and PERF_RECORD_EXIT which breaks the mmap state across
forks/exits; update eventHandle to also handle events whose type corresponds to
PERF_RECORD_FORK and PERF_RECORD_EXIT (as emitted by PerfDataReader.decodeBody),
extract parent and child PIDs from the event payload for FORK and the exiting
PID for EXIT, and on FORK copy the parent's PID subtree/mappings into the child
PID subtree in the state system, while on EXIT clear the exiting PID's
subtree/mappings so stale mappings are removed; keep existing MMAP/MMAP2
handling intact and use the same state-system API you already use for writing
mapping entries to perform the copy and clear operations.

In
`@tracetypes/org.eclipse.tracecompass.incubator.perf.core/src/org/eclipse/tracecompass/incubator/internal/perf/core/trace/PerfDataTrace.java`:
- Around line 224-229: In seekEvent(double ratio) the multiplication is done
after casting the clamped ratio to long, so (long) Math.max(...) becomes 0 for
ratios <1; change the calculation in PerfDataTrace.seekEvent so you multiply the
clamped double ratio by span first and only then cast to long (e.g. compute
(long)(clampedRatio * span) or use DoubleMath) to produce the correct offset
passed to new TmfLongLocation(offset).

In
`@tracetypes/org.eclipse.tracecompass.incubator.perf.core/src/org/eclipse/tracecompass/incubator/internal/perf/core/trace/PerfEventType.java`:
- Around line 28-29: The static TYPES map in PerfEventType is currently a
HashMap and lookup() does an unsynchronized read-then-write, causing concurrent
mutation risk; change TYPES to a ConcurrentHashMap and update lookup() to use
TYPES.computeIfAbsent(key, k -> /* create new ITmfEventType for k */) so unknown
event types are safely cached atomically; reference the PerfEventType class, the
TYPES field, and the lookup() method when making these changes.

---

Nitpick comments:
In
`@tracetypes/org.eclipse.tracecompass.incubator.perf.core.tests/src/org/eclipse/tracecompass/incubator/perf/core/tests/PerfDataCallchainTest.java`:
- Around line 78-80: The assertNotNull(file) is redundant where it's placed
after file has already been dereferenced; either remove this late check or move
it up immediately after the code that constructs/obtains the file variable so
the null check happens before any use. Update the PerfDataCallchainTest test to
either delete the trailing assertNotNull(file) or relocate it to directly follow
the assignment/creation of file (the variable named file used earlier in the
test) so that any null-file failure occurs before calls that use file and before
assertions on samples.

In
`@tracetypes/org.eclipse.tracecompass.incubator.perf.core.tests/src/org/eclipse/tracecompass/incubator/perf/core/tests/PerfDataTraceTest.java`:
- Around line 129-135: The test assumes rec.getField("filename") is a String and
casts directly, which can throw ClassCastException; change the assertion to
first verify the field is a non-null String (e.g. use instanceof to assert
rec.getField("filename") instanceof String) and only then test that ((String)
rec.getField("filename")).isEmpty() (or use
String.valueOf(rec.getField("filename")).isEmpty() if you intend to accept
non-String values), referencing the existing rec.getField("filename") usage and
the surrounding assertions so the filename check is robust against
non-String/malformed records.
- Around line 198-208: resolvePath currently returns the final fallback File
unconditionally even if it doesn't exist; update resolvePath to verify the
existence of that final candidate (and the earlier candidates) and if none exist
throw an informative exception (e.g., IllegalStateException) that lists the
attempted paths (direct, bundleRel, and the fallback) so tests fail with a clear
message rather than returning a non-existent File; reference the resolvePath
method and the local variables direct and bundleRel when locating where to add
the existence check and the exception.

In
`@tracetypes/org.eclipse.tracecompass.incubator.perf.core/src/org/eclipse/tracecompass/incubator/internal/perf/core/analysis/PerfDataCallchainAnalysisModule.java`:
- Around line 296-301: The current O(n²) merge loop using fSites should be
replaced with a Map keyed by sample.getObject() to give O(1) lookups: change the
collection type from the current List/Collection fSites to a Map<Object,
AggregatedCallSite> (or add a parallel Map) in PerfDataCallchainAnalysisModule,
populate the map from existing fSites when initializing, then in the insertion
logic replace the linear loop that checks
existing.getObject().equals(sample.getObject()) and calls existing.merge(sample)
with a direct map lookup by sample.getObject() and call merge if present or put
a new AggregatedCallSite otherwise; also update any other places that iterate
fSites to either iterate map.values() or keep a single source of truth to avoid
inconsistencies.
- Around line 170-203: getElement currently scans getRootElements() and
processEl.getChildrenElements() on every event (using streams) which is O(n) per
event; replace that linear lookup with cached maps: add a Map<Integer,
ICallStackElement> pidToProcess and for each process a Map<Integer,
ICallStackElement> pidToTidMap (or a Map<Integer, Map<Integer,
ICallStackElement>>) keyed by pid→tid to provide O(1) lookups inside getElement;
when you create a new processEl or threadEl (the CallStackElement instances
constructed in getElement) insert them into the maps, and when adding/removing
root elements update the maps accordingly; ensure getElement consults the maps
first instead of calling getRootElements() or iterating children to preserve
existing behavior.

In
`@tracetypes/org.eclipse.tracecompass.incubator.perf.core/src/org/eclipse/tracecompass/incubator/internal/perf/core/PerfDataReader.java`:
- Around line 684-695: The callchain parsing in PerfDataReader reads nr as a
long and later casts to int without guarding against very large values; update
the validation to ensure nr is non-negative and <= Integer.MAX_VALUE and also <=
body.remaining()/8 before allocating the array and casting, e.g., clamp or fail
when nr > Integer.MAX_VALUE (and treat it as malformed), then safely cast
(int)nr for the new long[nr] and the loop that fills ips before putting
"callchain" into fields.

In
`@tracetypes/org.eclipse.tracecompass.incubator.perf.core/src/org/eclipse/tracecompass/incubator/internal/perf/core/symbol/PerfDataMmapSymbolProvider.java`:
- Line 48: The fSymbolMapping Map in PerfDataMmapSymbolProvider stores
IMappingFile instances indefinitely causing unbounded growth; fix this by making
the cache size-bounded or ensuring it is cleared on lifecycle end—either replace
the HashMap with an LRU-capable map (e.g., LinkedHashMap with accessOrder and
max size eviction) keyed by filename or explicitly clear fSymbolMapping in the
provider's dispose/close method (add/override dispose() in
PerfDataMmapSymbolProvider to iterate/close any IMappingFile resources if needed
and call fSymbolMapping.clear()). Ensure any IMappingFile cleanup is performed
before removing entries.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4ce559c7-f8b7-47a5-948c-7baf52bfd7f3

📥 Commits

Reviewing files that changed from the base of the PR and between 1a22b62 and 26b2dd8.

📒 Files selected for processing (50)
  • tracetypes/org.eclipse.tracecompass.incubator.perf.core.tests/.classpath
  • tracetypes/org.eclipse.tracecompass.incubator.perf.core.tests/.gitignore
  • tracetypes/org.eclipse.tracecompass.incubator.perf.core.tests/.project
  • tracetypes/org.eclipse.tracecompass.incubator.perf.core.tests/.settings/org.eclipse.core.resources.prefs
  • tracetypes/org.eclipse.tracecompass.incubator.perf.core.tests/.settings/org.eclipse.core.runtime.prefs
  • tracetypes/org.eclipse.tracecompass.incubator.perf.core.tests/.settings/org.eclipse.jdt.core.prefs
  • tracetypes/org.eclipse.tracecompass.incubator.perf.core.tests/.settings/org.eclipse.jdt.ui.prefs
  • tracetypes/org.eclipse.tracecompass.incubator.perf.core.tests/.settings/org.eclipse.pde.prefs
  • tracetypes/org.eclipse.tracecompass.incubator.perf.core.tests/META-INF/MANIFEST.MF
  • tracetypes/org.eclipse.tracecompass.incubator.perf.core.tests/about.html
  • tracetypes/org.eclipse.tracecompass.incubator.perf.core.tests/build.properties
  • tracetypes/org.eclipse.tracecompass.incubator.perf.core.tests/plugin.properties
  • tracetypes/org.eclipse.tracecompass.incubator.perf.core.tests/src/org/eclipse/tracecompass/incubator/perf/core/tests/PerfDataCallchainTest.java
  • tracetypes/org.eclipse.tracecompass.incubator.perf.core.tests/src/org/eclipse/tracecompass/incubator/perf/core/tests/PerfDataTraceTest.java
  • tracetypes/org.eclipse.tracecompass.incubator.perf.core.tests/traces/perf-callgraph.data
  • tracetypes/org.eclipse.tracecompass.incubator.perf.core.tests/traces/perf.data
  • tracetypes/org.eclipse.tracecompass.incubator.perf.core/.classpath
  • tracetypes/org.eclipse.tracecompass.incubator.perf.core/.gitignore
  • tracetypes/org.eclipse.tracecompass.incubator.perf.core/.project
  • tracetypes/org.eclipse.tracecompass.incubator.perf.core/.settings/org.eclipse.core.resources.prefs
  • tracetypes/org.eclipse.tracecompass.incubator.perf.core/.settings/org.eclipse.core.runtime.prefs
  • tracetypes/org.eclipse.tracecompass.incubator.perf.core/.settings/org.eclipse.jdt.core.prefs
  • tracetypes/org.eclipse.tracecompass.incubator.perf.core/.settings/org.eclipse.jdt.ui.prefs
  • tracetypes/org.eclipse.tracecompass.incubator.perf.core/.settings/org.eclipse.pde.api.tools.prefs
  • tracetypes/org.eclipse.tracecompass.incubator.perf.core/.settings/org.eclipse.pde.prefs
  • tracetypes/org.eclipse.tracecompass.incubator.perf.core/META-INF/MANIFEST.MF
  • tracetypes/org.eclipse.tracecompass.incubator.perf.core/about.html
  • tracetypes/org.eclipse.tracecompass.incubator.perf.core/build.properties
  • tracetypes/org.eclipse.tracecompass.incubator.perf.core/plugin.properties
  • tracetypes/org.eclipse.tracecompass.incubator.perf.core/plugin.xml
  • tracetypes/org.eclipse.tracecompass.incubator.perf.core/src/org/eclipse/tracecompass/incubator/internal/perf/core/Activator.java
  • tracetypes/org.eclipse.tracecompass.incubator.perf.core/src/org/eclipse/tracecompass/incubator/internal/perf/core/PerfConstants.java
  • tracetypes/org.eclipse.tracecompass.incubator.perf.core/src/org/eclipse/tracecompass/incubator/internal/perf/core/PerfDataReader.java
  • tracetypes/org.eclipse.tracecompass.incubator.perf.core/src/org/eclipse/tracecompass/incubator/internal/perf/core/PerfEventAttr.java
  • tracetypes/org.eclipse.tracecompass.incubator.perf.core/src/org/eclipse/tracecompass/incubator/internal/perf/core/PerfFileHeader.java
  • tracetypes/org.eclipse.tracecompass.incubator.perf.core/src/org/eclipse/tracecompass/incubator/internal/perf/core/PerfFileSection.java
  • tracetypes/org.eclipse.tracecompass.incubator.perf.core/src/org/eclipse/tracecompass/incubator/internal/perf/core/PerfRecord.java
  • tracetypes/org.eclipse.tracecompass.incubator.perf.core/src/org/eclipse/tracecompass/incubator/internal/perf/core/analysis/PerfDataCallchainAnalysisModule.java
  • tracetypes/org.eclipse.tracecompass.incubator.perf.core/src/org/eclipse/tracecompass/incubator/internal/perf/core/analysis/package-info.java
  • tracetypes/org.eclipse.tracecompass.incubator.perf.core/src/org/eclipse/tracecompass/incubator/internal/perf/core/package-info.java
  • tracetypes/org.eclipse.tracecompass.incubator.perf.core/src/org/eclipse/tracecompass/incubator/internal/perf/core/symbol/PerfDataMmapAnalysisModule.java
  • tracetypes/org.eclipse.tracecompass.incubator.perf.core/src/org/eclipse/tracecompass/incubator/internal/perf/core/symbol/PerfDataMmapStateProvider.java
  • tracetypes/org.eclipse.tracecompass.incubator.perf.core/src/org/eclipse/tracecompass/incubator/internal/perf/core/symbol/PerfDataMmapSymbolProvider.java
  • tracetypes/org.eclipse.tracecompass.incubator.perf.core/src/org/eclipse/tracecompass/incubator/internal/perf/core/symbol/PerfDataMmapSymbolProviderFactory.java
  • tracetypes/org.eclipse.tracecompass.incubator.perf.core/src/org/eclipse/tracecompass/incubator/internal/perf/core/symbol/TmfLibrarySymbol.java
  • tracetypes/org.eclipse.tracecompass.incubator.perf.core/src/org/eclipse/tracecompass/incubator/internal/perf/core/symbol/package-info.java
  • tracetypes/org.eclipse.tracecompass.incubator.perf.core/src/org/eclipse/tracecompass/incubator/internal/perf/core/trace/PerfDataTrace.java
  • tracetypes/org.eclipse.tracecompass.incubator.perf.core/src/org/eclipse/tracecompass/incubator/internal/perf/core/trace/PerfEventType.java
  • tracetypes/org.eclipse.tracecompass.incubator.perf.core/src/org/eclipse/tracecompass/incubator/internal/perf/core/trace/package-info.java
  • tracetypes/pom.xml

(&quot;Content&quot;). Unless otherwise indicated below, the Content
is provided to you under the terms and conditions of the Eclipse
Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is
available at <a href="http://www.eclipse.org/legal/epl-2.0">http://www.eclipse.org/legal/epl-2.0</a>.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use HTTPS links in About page content.

Both external links are plaintext HTTP; switch them to HTTPS to avoid mixed/insecure navigation from plugin metadata pages.

Suggested fix
-		available at <a href="http://www.eclipse.org/legal/epl-2.0">http://www.eclipse.org/legal/epl-2.0</a>.
+		available at <a href="https://www.eclipse.org/legal/epl-2.0">https://www.eclipse.org/legal/epl-2.0</a>.
@@
-		code in the Content and such source code may be obtained at <a
-			href="http://www.eclipse.org/">http://www.eclipse.org</a>.
+		code in the Content and such source code may be obtained at <a
+			href="https://www.eclipse.org/">https://www.eclipse.org</a>.

Also applies to: 32-32

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tracetypes/org.eclipse.tracecompass.incubator.perf.core.tests/about.html` at
line 19, Replace the plaintext HTTP links in the about page content with HTTPS:
locate the occurrences of "http://www.eclipse.org/legal/epl-2.0" and the other
external link using "http://" in the about.html content and change them to
"https://..." so both external links use HTTPS to avoid mixed/insecure
navigation from plugin metadata pages; ensure you update both occurrences (the
one shown and the other at the second occurrence).

(&quot;Content&quot;). Unless otherwise indicated below, the Content
is provided to you under the terms and conditions of the Eclipse
Public License Version 2.0 (&quot;EPL&quot;). A copy of the EPL is
available at <a href="http://www.eclipse.org/legal/epl-2.0">http://www.eclipse.org/legal/epl-2.0</a>.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use HTTPS for external license/project links.

Both anchors currently point to plaintext HTTP URLs. Switch them to HTTPS to avoid mixed/insecure link targets in distributed plugin metadata pages.

Suggested patch
-		available at <a href="http://www.eclipse.org/legal/epl-2.0">http://www.eclipse.org/legal/epl-2.0</a>.
+		available at <a href="https://www.eclipse.org/legal/epl-2.0">https://www.eclipse.org/legal/epl-2.0</a>.
@@
-		code in the Content and such source code may be obtained at <a
-			href="http://www.eclipse.org/">http://www.eclipse.org</a>.
+		code in the Content and such source code may be obtained at <a
+			href="https://www.eclipse.org/">https://www.eclipse.org</a>.

Also applies to: 32-32

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tracetypes/org.eclipse.tracecompass.incubator.perf.core/about.html` at line
19, Update the anchor hrefs in the about.html anchors that currently use
"http://www.eclipse.org/..." (e.g., the license link
"http://www.eclipse.org/legal/epl-2.0" and the other http anchor on the page) to
use HTTPS ("https://...") so both external links use secure https URLs; edit the
anchor href attributes in the about.html markup accordingly.

Comment on lines +81 to +86
if (fHeader.isPiped()) {
fAttrs = List.of();
Map.of();
fDefaultAttr = null;
fFeatures = Map.of();
fMetadata = Map.of();
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Dead code statements - results not assigned.

Lines 83 and 95 call Map.of() and Collections.unmodifiableMap(byId) respectively, but their return values are not assigned to any variable. These statements have no effect.

Proposed fix - remove dead statements
         if (fHeader.isPiped()) {
             fAttrs = List.of();
-            Map.of();
             fDefaultAttr = null;
             fFeatures = Map.of();
             fMetadata = Map.of();
         } else {
             fAttrs = parseAttrs(fHeader);
             Map<Long, PerfEventAttr> byId = new LinkedHashMap<>();
             for (PerfEventAttr attr : fAttrs) {
                 for (Long id : attr.getIds()) {
                     byId.put(id, attr);
                 }
             }
-            Collections.unmodifiableMap(byId);
+            // byId is constructed but not currently used; consider removing if not needed
             fDefaultAttr = fAttrs.isEmpty() ? null : fAttrs.get(0);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@tracetypes/org.eclipse.tracecompass.incubator.perf.core/src/org/eclipse/tracecompass/incubator/internal/perf/core/PerfDataReader.java`
around lines 81 - 86, In PerfDataReader (inside the fHeader.isPiped() branch)
remove the dead standalone calls to Map.of() and
Collections.unmodifiableMap(byId) (they produce values that are never assigned);
either delete these statements or replace them by assigning their results to the
appropriate fields (e.g. assign Map.of() to fFeatures or fMetadata if that was
intended) so only meaningful assignments remain for fAttrs, fDefaultAttr,
fFeatures, and fMetadata.

Comment on lines +135 to +137
public long[] getFeatures() {
return fFeatures;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Internal array exposed breaks immutability.

getFeatures() returns the internal fFeatures array directly, allowing callers to modify its contents. Since PerfFileHeader is documented as immutable (final class, private fields), this is a contract violation.

Proposed fix - return a defensive copy
     public long[] getFeatures() {
-        return fFeatures;
+        return fFeatures.clone();
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public long[] getFeatures() {
return fFeatures;
}
public long[] getFeatures() {
return fFeatures.clone();
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@tracetypes/org.eclipse.tracecompass.incubator.perf.core/src/org/eclipse/tracecompass/incubator/internal/perf/core/PerfFileHeader.java`
around lines 135 - 137, getFeatures() currently returns the internal fFeatures
array from the immutable PerfFileHeader class which allows external mutation;
change getFeatures() to return a defensive copy of fFeatures (e.g., create and
return a new long[] copy or use Arrays.copyOf) so callers cannot modify the
internal state while keeping the method signature the same.

Comment on lines +56 to +60
protected void eventHandle(ITmfEvent event) {
String name = event.getType().getName();
if (!MMAP_NAME.equals(name) && !MMAP2_NAME.equals(name)) {
return;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Handle FORK/EXIT here as part of the mmap state model.

Filtering everything except MMAP/MMAP2 makes the state system wrong across process lifetime changes: forked children never inherit the parent's mappings, and exited PIDs keep stale mappings forever until the trace ends. Since PerfDataReader.decodeBody(...) already emits PERF_RECORD_FORK and PERF_RECORD_EXIT, this provider should copy the parent's subtree at fork time and clear the PID subtree on exit to avoid bad symbol resolution after fork or PID reuse.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@tracetypes/org.eclipse.tracecompass.incubator.perf.core/src/org/eclipse/tracecompass/incubator/internal/perf/core/symbol/PerfDataMmapStateProvider.java`
around lines 56 - 60, The eventHandle currently filters to only MMAP/MMAP2 and
ignores PERF_RECORD_FORK and PERF_RECORD_EXIT which breaks the mmap state across
forks/exits; update eventHandle to also handle events whose type corresponds to
PERF_RECORD_FORK and PERF_RECORD_EXIT (as emitted by PerfDataReader.decodeBody),
extract parent and child PIDs from the event payload for FORK and the exiting
PID for EXIT, and on FORK copy the parent's PID subtree/mappings into the child
PID subtree in the state system, while on EXIT clear the exiting PID's
subtree/mappings so stale mappings are removed; keep existing MMAP/MMAP2
handling intact and use the same state-system API you already use for writing
mapping entries to perform the copy and clear operations.

Comment on lines +79 to +81
if (pid < 0) {
// Skip kernel-synthesized MMAPs with pid = -1 ([kernel.kallsyms], modules, ...)
return;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Dropping pid == -1 removes all kernel/module mappings.

perf emits [kernel.kallsyms] and module MMAP records with pid = -1. Returning here means kernel-side callchain frames can never resolve through PerfDataMmapSymbolProvider and will fall back to raw IPs. If kernel stacks are meant to be supported, keep these mappings in a dedicated global bucket and let the symbol provider consult it when per-process lookup misses.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@tracetypes/org.eclipse.tracecompass.incubator.perf.core/src/org/eclipse/tracecompass/incubator/internal/perf/core/symbol/PerfDataMmapStateProvider.java`
around lines 79 - 81, The current early return for pid < 0 drops kernel/module
mappings (pid == -1); instead, change the pid check so pid == -1 is NOT
discarded and is stored in a dedicated global bucket inside
PerfDataMmapStateProvider (create or reuse a globalMmaps/map for kernel
mappings) while preserving ignoring other negative pids if necessary, and update
the symbol lookup in PerfDataMmapSymbolProvider to consult that global bucket
when a per-process lookup misses; modify the mmap-handling branch where the pid
check occurs to branch on pid == -1 (store to global) vs pid >= 0 (store
per-process) and ensure lookup code queries globalMmaps as a fallback.

Comment on lines +224 to +229
@Override
public ITmfContext seekEvent(double ratio) {
long span = fDataEnd - fDataStart;
long offset = fDataStart + (long) Math.max(0.0, Math.min(1.0, ratio)) * span;
return seekEvent(new TmfLongLocation(offset));
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Operator precedence causes incorrect ratio calculation.

Line 227 has incorrect operator precedence. The expression (long) Math.max(...) * span casts only the ratio result to long before multiplying by span. Since the ratio is between 0.0 and 1.0, casting it to long always yields 0, making offset always equal to fDataStart.

Proposed fix
     `@Override`
     public ITmfContext seekEvent(double ratio) {
         long span = fDataEnd - fDataStart;
-        long offset = fDataStart + (long) Math.max(0.0, Math.min(1.0, ratio)) * span;
+        long offset = fDataStart + (long) (Math.max(0.0, Math.min(1.0, ratio)) * span);
         return seekEvent(new TmfLongLocation(offset));
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@tracetypes/org.eclipse.tracecompass.incubator.perf.core/src/org/eclipse/tracecompass/incubator/internal/perf/core/trace/PerfDataTrace.java`
around lines 224 - 229, In seekEvent(double ratio) the multiplication is done
after casting the clamped ratio to long, so (long) Math.max(...) becomes 0 for
ratios <1; change the calculation in PerfDataTrace.seekEvent so you multiply the
clamped double ratio by span first and only then cast to long (e.g. compute
(long)(clampedRatio * span) or use DoubleMath) to produce the correct offset
passed to new TmfLongLocation(offset).

Comment on lines +28 to +29
private static final Map<Integer, ITmfEventType> TYPES = new HashMap<>();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

find . -name "PerfEventType.java" -type f

Repository: eclipse-tracecompass-incubator/org.eclipse.tracecompass.incubator

Length of output: 250


🏁 Script executed:

git ls-files | grep -i "PerfEventType"

Repository: eclipse-tracecompass-incubator/org.eclipse.tracecompass.incubator

Length of output: 248


🏁 Script executed:

fd "PerfEventType" --type f

Repository: eclipse-tracecompass-incubator/org.eclipse.tracecompass.incubator

Length of output: 248


🏁 Script executed:

wc -l tracetypes/org.eclipse.tracecompass.incubator.perf.core/src/org/eclipse/tracecompass/incubator/internal/perf/core/trace/PerfEventType.java

Repository: eclipse-tracecompass-incubator/org.eclipse.tracecompass.incubator

Length of output: 251


🏁 Script executed:

cat -n tracetypes/org.eclipse.tracecompass.incubator.perf.core/src/org/eclipse/tracecompass/incubator/internal/perf/core/trace/PerfEventType.java

Repository: eclipse-tracecompass-incubator/org.eclipse.tracecompass.incubator

Length of output: 4158


Protect dynamic event-type caching from concurrent mutation.

lookup() performs an unsynchronized read-then-write on TYPES for unknown types. Since this is a public static API likely called concurrently during trace processing, use ConcurrentHashMap with computeIfAbsent to safely cache unknown event types.

Suggested fix
-import java.util.HashMap;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.Map;
@@
-    private static final Map<Integer, ITmfEventType> TYPES = new HashMap<>();
+    private static final Map<Integer, ITmfEventType> TYPES = new ConcurrentHashMap<>();
@@
     public static ITmfEventType lookup(int type) {
-        ITmfEventType t = TYPES.get(type);
-        if (t == null) {
-            t = new TmfEventType("PERF_RECORD_" + type, null); //$NON-NLS-1$
-            TYPES.put(type, t);
-        }
-        return t;
+        return TYPES.computeIfAbsent(type, t -> new TmfEventType("PERF_RECORD_" + t, null)); //$NON-NLS-1$
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@tracetypes/org.eclipse.tracecompass.incubator.perf.core/src/org/eclipse/tracecompass/incubator/internal/perf/core/trace/PerfEventType.java`
around lines 28 - 29, The static TYPES map in PerfEventType is currently a
HashMap and lookup() does an unsynchronized read-then-write, causing concurrent
mutation risk; change TYPES to a ConcurrentHashMap and update lookup() to use
TYPES.computeIfAbsent(key, k -> /* create new ITmfEventType for k */) so unknown
event types are safely cached atomically; reference the PerfEventType class, the
TYPES field, and the lookup() method when making these changes.

Port the CTF-based perf-profiling analyses to the new perf.data trace
type so the Flame Chart and Flame Graph views light up on
'perf record -g' output.

New analyses (org.eclipse.tracecompass.incubator.internal.perf.core.*):
 - analysis.PerfDataCallchainAnalysisModule
     Extends ProfilingCallGraphAnalysisModule and implements
     ISamplingDataProvider. Reads the callchain long[] straight off
     the PerfRecord attached to each PERF_RECORD_SAMPLE event,
     strips the PERF_CONTEXT_* sentinels and reverses the chain
     (oldest frame first), then groups samples by process/thread.
 - symbol.PerfDataMmapStateProvider + PerfDataMmapAnalysisModule
     Tracks PERF_RECORD_MMAP / MMAP2 events and exposes
     /<pid>/<loadBase> -> filename so addresses can be resolved to
     ELF libraries. Uses addr - pgoff as the load base to match the
     offsets the callchain IPs will be compared against.
 - symbol.PerfDataMmapSymbolProvider + factory + TmfLibrarySymbol
     ISymbolProvider backed by the mmap state system and
     IMappingFile; falls back to the filename when a symbol cannot
     be resolved from disk.

Infrastructure:
 - MANIFEST.MF: require o.e.tc.statesystem.core and
   o.e.tc.analysis.profiling.core.
 - plugin.xml: register the two analyses and the symbol provider
   factory, scoped to PerfDataTrace.
 - plugin.properties: names for the two analyses.
 - PerfDataTrace: stop stringifying long[] and byte[] fields in
   fieldsFromRecord so analyses can consume the primitive arrays.

Tests: - Add a second fixture traces/perf-callgraph.data captured with
   'perf record -g ping 4.4.4.4 -c 3'.
 - PerfDataCallchainTest.hasNonTrivialCallchains checks the data
   shape on the original wget trace.
 - PerfDataCallchainTest.callgraphTraceHasRealChains walks the new
   fixture and verifies every SAMPLE exposes a long[] callchain
   with non-sentinel IPs.

This code was made with the assistance of Claude Opus 4.7
The commit message was 100% made by claude and is much better than I can do :)

Change-Id: Ibd37279cc63ce4a0bcada7a49ec2414f4e7157d2
Signed-off-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant