tmf.core: move Custom marker logic to core

Allow markers to be treated as regular annotations.
The internal notion of a max duration was removed as it should
be filtered at the request level.

This can:
* Filter on categories
* Handle multiple annotations sources

[Added] Dataprovider support for custom annotations
[Added] Server-side annotations filtering
[Deprecated] org.eclipse.tracecompass.tmf.ui.markers.IMarkerReferenceProvider

Change-Id: I0278193b1f954c5bc54e490e9feda7016a190c89
Signed-off-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
Reviewed-on: https://git.eclipse.org/r/c/tracecompass/org.eclipse.tracecompass/+/179329
Tested-by: Patrick Tasse <patrick.tasse@gmail.com>
Tested-by: Trace Compass Bot <tracecompass-bot@eclipse.org>
Reviewed-by: Patrick Tasse <patrick.tasse@gmail.com>
diff --git a/tmf/org.eclipse.tracecompass.tmf.core/META-INF/MANIFEST.MF b/tmf/org.eclipse.tracecompass.tmf.core/META-INF/MANIFEST.MF
index b99c5aa..f799b9b 100644
--- a/tmf/org.eclipse.tracecompass.tmf.core/META-INF/MANIFEST.MF
+++ b/tmf/org.eclipse.tracecompass.tmf.core/META-INF/MANIFEST.MF
@@ -16,7 +16,8 @@
  org.eclipse.cdt.core,
  org.eclipse.tracecompass.datastore.core,
  org.eclipse.tracecompass.tmf.filter.parser,
- org.eclipse.jdt.annotation;bundle-version="[2.0.0,3.0.0)";resolution:=optional
+ org.eclipse.jdt.annotation;bundle-version="[2.0.0,3.0.0)";resolution:=optional,
+ org.apache.commons.lang3
 Export-Package: org.eclipse.tracecompass.internal.provisional.tmf.core.model,
  org.eclipse.tracecompass.internal.provisional.tmf.core.model.annotations;x-internal:=true,
  org.eclipse.tracecompass.internal.provisional.tmf.core.model.events;x-friends:="org.eclipse.tracecompass.tmf.core.tests",
@@ -27,6 +28,7 @@
  org.eclipse.tracecompass.internal.tmf.core;x-friends:="org.eclipse.tracecompass.tmf.core.tests,org.eclipse.tracecompass.tmf.ui.swtbot.tests",
  org.eclipse.tracecompass.internal.tmf.core.analysis;x-friends:="org.eclipse.tracecompass.tmf.core.tests",
  org.eclipse.tracecompass.internal.tmf.core.analysis.callsite;x-friends:="org.eclipse.tracecompass.analysis.os.linux.core.tests",
+ org.eclipse.tracecompass.internal.tmf.core.annotations;x-internal:=true,
  org.eclipse.tracecompass.internal.tmf.core.aspect;x-internal:=true,
  org.eclipse.tracecompass.internal.tmf.core.callstack;x-friends:="org.eclipse.tracecompass.tmf.ui,org.eclipse.tracecompass.tmf.core.tests",
  org.eclipse.tracecompass.internal.tmf.core.component;x-friends:="org.eclipse.tracecompass.tmf.core.tests",
@@ -42,6 +44,7 @@
    org.eclipse.tracecompass.analysis.counters.core,
    org.eclipse.tracecompass.analysis.profiling.core,
    org.eclipse.tracecompass.tmf.core.tests",
+ org.eclipse.tracecompass.internal.tmf.core.model.annontations;x-internal:=true,
  org.eclipse.tracecompass.internal.tmf.core.model.filters;
   x-friends:="org.eclipse.tracecompass.analysis.counters.ui,
    org.eclipse.tracecompass.analysis.graph.core,
@@ -111,6 +114,7 @@
  org.eclipse.tracecompass.tmf.core.filter.model,
  org.eclipse.tracecompass.tmf.core.filter.xml,
  org.eclipse.tracecompass.tmf.core.io,
+ org.eclipse.tracecompass.tmf.core.markers,
  org.eclipse.tracecompass.tmf.core.model,
  org.eclipse.tracecompass.tmf.core.model.filters,
  org.eclipse.tracecompass.tmf.core.model.timegraph,
diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/model/annotations/CustomAnnotationProvider.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/model/annotations/CustomAnnotationProvider.java
new file mode 100644
index 0000000..2e575cf
--- /dev/null
+++ b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/model/annotations/CustomAnnotationProvider.java
@@ -0,0 +1,360 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License 2.0 which
+ * accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.provisional.tmf.core.model.annotations;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Objects;
+import java.util.Set;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.internal.tmf.core.markers.IMarkerConstants;
+import org.eclipse.tracecompass.internal.tmf.core.markers.Marker;
+import org.eclipse.tracecompass.internal.tmf.core.markers.Marker.PeriodicMarker;
+import org.eclipse.tracecompass.internal.tmf.core.markers.MarkerSegment;
+import org.eclipse.tracecompass.internal.tmf.core.markers.MarkerSet;
+import org.eclipse.tracecompass.internal.tmf.core.markers.SubMarker;
+import org.eclipse.tracecompass.internal.tmf.core.markers.SubMarker.SplitMarker;
+import org.eclipse.tracecompass.internal.tmf.core.markers.SubMarker.WeightedMarker;
+import org.eclipse.tracecompass.tmf.core.dataprovider.DataProviderParameterUtils;
+import org.eclipse.tracecompass.tmf.core.dataprovider.X11ColorUtils;
+import org.eclipse.tracecompass.tmf.core.markers.ITimeReference;
+import org.eclipse.tracecompass.tmf.core.markers.ITimeReferenceProvider;
+import org.eclipse.tracecompass.tmf.core.markers.TimeReference;
+import org.eclipse.tracecompass.tmf.core.model.OutputElementStyle;
+import org.eclipse.tracecompass.tmf.core.model.StyleProperties;
+import org.eclipse.tracecompass.tmf.core.presentation.RGBAColor;
+import org.eclipse.tracecompass.tmf.core.response.ITmfResponse.Status;
+import org.eclipse.tracecompass.tmf.core.response.TmfModelResponse;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+
+/**
+ * Custom Annotation Provider
+ *
+ * @author Matthew Khouzam
+ */
+public class CustomAnnotationProvider implements IOutputAnnotationProvider {
+
+    private static final String DEFAULT_COLOR = "blue"; //$NON-NLS-1$
+    private static final long MIN_PERIOD = 5; // in units of resolution
+                                              // intervals
+    private static final int ALPHA = 10;
+    private static final String COLOR_REGEX = "#[A-Fa-f0-9]{6}"; //$NON-NLS-1$
+
+    private List<IOutputAnnotationProvider> fMarkerEventSources = new ArrayList<>();
+    private Map<Marker, RGBAColor> fColors = new HashMap<>();
+    private final @Nullable ITmfTrace fTrace;
+    private @Nullable MarkerSet fMarkerSet;
+
+    /**
+     * Custom Annotation Provider for a given marker set
+     *
+     * @param trace
+     *            the trace to make the annotations on. Used to get the start
+     *            time, if null, the epoch is assumed to be the reference time.
+     * @param markerSet
+     *            the marker set, a definition of a group of configurable
+     *            markers
+     */
+    public CustomAnnotationProvider(@Nullable ITmfTrace trace, @Nullable MarkerSet markerSet) {
+        fTrace = trace;
+        fMarkerSet = markerSet;
+        fMarkerEventSources = configure(markerSet);
+    }
+
+    /**
+     * Configure the marker source from the specified marker set
+     *
+     * @param markerSet
+     *            the marker set, or null to clear the configuration
+     * @return the list of {@link IOutputAnnotationProvider}s for this marker
+     *         set
+     */
+    public List<IOutputAnnotationProvider> configure(@Nullable MarkerSet markerSet) {
+        List<IOutputAnnotationProvider> markerEventSources = new ArrayList<>();
+        if (markerSet != null) {
+            for (Marker marker : markerSet.getMarkers()) {
+                markerEventSources.add(configure(Objects.requireNonNull(marker)));
+            }
+        }
+        fMarkerEventSources = markerEventSources;
+        fMarkerSet = markerSet;
+        return markerEventSources;
+    }
+
+    private IOutputAnnotationProvider configure(Marker marker) {
+        if (marker instanceof PeriodicMarker) {
+            PeriodicMarker periodicMarker = (PeriodicMarker) marker;
+            long rollover = periodicMarker.getRange().hasUpperBound() ? (periodicMarker.getRange().upperEndpoint() - periodicMarker.getRange().lowerEndpoint() + 1) : 0;
+            RGBAColor evenColor = getColor(marker);
+            RGBAColor oddColor = getOddColor(evenColor);
+            ITmfTrace trace = fTrace;
+            double period = IMarkerConstants.convertToNanos(periodicMarker.getPeriod(), periodicMarker.getUnit(), trace);
+            String referenceId = periodicMarker.getReferenceId();
+            ITimeReference baseReference = null;
+            if (trace instanceof IAdaptable && !referenceId.isEmpty()) {
+                ITimeReferenceProvider adapter = ((IAdaptable) trace).getAdapter(ITimeReferenceProvider.class);
+                if (adapter != null) {
+                    baseReference = adapter.apply(referenceId);
+                }
+            }
+            if (baseReference == null) {
+                baseReference = ITimeReference.ZERO;
+            }
+            ITimeReference reference = new TimeReference(baseReference.getTime() + Math.round(IMarkerConstants.convertToNanos(periodicMarker.getOffset(), periodicMarker.getUnit(), trace)), baseReference.getIndex());
+            return new PeriodicAnnotationSource(marker, reference.getIndex(), reference.getTime(), period, rollover, evenColor, oddColor);
+        }
+        throw new IllegalArgumentException("Marker must be of type PeriodicMarker or SubMarker"); //$NON-NLS-1$
+
+    }
+
+    private void getSubMarkerList(SubMarker subMarker, Annotation markerEvent, Map<String, Collection<@NonNull Annotation>> markerMap, long startTime, long endTime, long minDuration, Long[] times) {
+        if (subMarker instanceof SplitMarker) {
+            getSubMarkerList((SplitMarker) subMarker, markerEvent, markerMap, startTime, endTime, minDuration, times);
+        } else if (subMarker instanceof WeightedMarker) {
+            getSubMarkerList((WeightedMarker) subMarker, markerEvent, markerMap, startTime, endTime, minDuration, times);
+        }
+    }
+
+    private void getSubMarkerList(SplitMarker splitMarker, Annotation markerEvent, Map<String, Collection<@NonNull Annotation>> annotationMap, long startTime, long endTime, long minDuration, Long[] times) {
+        if (markerEvent.getTime() > endTime || markerEvent.getTime() + markerEvent.getDuration() < startTime) {
+            return;
+        }
+        long lower = splitMarker.getRange().lowerEndpoint();
+        long upper = splitMarker.getRange().upperEndpoint();
+        long segments = upper - lower + 1;
+        long start = markerEvent.getTime();
+        List<@NonNull Annotation> annotationList = new ArrayList<>();
+        for (int i = 0; i < segments; i++) {
+            long end = markerEvent.getTime() + Math.round((double) (i + 1) / segments * markerEvent.getDuration());
+            long duration = end - start;
+            long labelIndex = lower + i;
+            if (end >= startTime && duration > minDuration && splitMarker.getIndexRange().contains(labelIndex)) {
+                RGBAColor color = (labelIndex & 1) == 0 ? getColor(splitMarker) : getOddColor(getColor(splitMarker));
+                OutputElementStyle outputStyle = getOutputStyle(splitMarker, color);
+                Annotation subAnnotation = new Annotation(start, end - start, -1, String.format(splitMarker.getLabel(), labelIndex), outputStyle);
+                for (SubMarker subMarker : splitMarker.getSubMarkers()) {
+                    getSubMarkerList(Objects.requireNonNull(subMarker), subAnnotation, annotationMap, startTime, endTime, minDuration, times);
+                }
+                annotationList.add(subAnnotation);
+            }
+            if (start >= endTime) {
+                break;
+            }
+            start = end;
+        }
+        populateMap(annotationMap, annotationList, Objects.requireNonNull(splitMarker.getName()));
+    }
+
+    private void getSubMarkerList(WeightedMarker weightedMarker, Annotation markerEvent, Map<String, Collection<@NonNull Annotation>> annotationMap, long startTime, long endTime, long minDuration, Long[] times) {
+        if (markerEvent.getTime() > endTime || markerEvent.getTime() + markerEvent.getDuration() < startTime) {
+            return;
+        }
+        long start = markerEvent.getTime();
+        long length = 0;
+        List<@NonNull Annotation> annotationsList = new ArrayList<>();
+        for (int i = 0; i < weightedMarker.getSegments().size(); i++) {
+            MarkerSegment segment = weightedMarker.getSegments().get(i);
+            length += segment.getLength();
+            long end = markerEvent.getTime() + Math.round((length / (double) weightedMarker.getTotalLength()) * markerEvent.getDuration());
+            long duration = end - start;
+            if (end >= startTime && duration > minDuration && !segment.getColor().isEmpty()) {
+                RGBAColor color = getColor(segment);
+                Annotation subAnnotation = new Annotation(start, end - start, -1, String.format(segment.getLabel(), i), getOutputStyle(segment, color));
+                for (SubMarker subMarker : segment.getSubMarkers()) {
+                    getSubMarkerList(Objects.requireNonNull(subMarker), subAnnotation, annotationMap, startTime, endTime, minDuration, times);
+                }
+                for (SubMarker subMarker : weightedMarker.getSubMarkers()) {
+                    getSubMarkerList(Objects.requireNonNull(subMarker), subAnnotation, annotationMap, startTime, endTime, minDuration, times);
+                }
+                annotationsList.add(subAnnotation);
+            }
+            if (start >= endTime) {
+                break;
+            }
+            start = end;
+        }
+        populateMap(annotationMap, annotationsList, Objects.requireNonNull(weightedMarker.getName()));
+    }
+
+    private static void populateMap(Map<String, Collection<@NonNull Annotation>> annotationMap, List<@NonNull Annotation> annotationsList, String name) {
+        Collection<@NonNull Annotation> annotations = annotationMap.get(name);
+        if (annotations != null) {
+            Set<@NonNull Annotation> annotationSet = new HashSet<>();
+            annotationSet.addAll(annotationsList);
+            annotationSet.addAll(annotations);
+            annotationMap.put(name, annotationSet);
+        } else {
+            annotationMap.put(name, annotationsList);
+        }
+    }
+
+    private RGBAColor getColor(Marker marker) {
+        RGBAColor color = fColors.get(marker);
+        if (color == null) {
+            color = parseColor(marker.getColor());
+            fColors.put(marker, color);
+        }
+        return color;
+    }
+
+    private static RGBAColor getOddColor(RGBAColor color) {
+        return new RGBAColor(color.getRed(), color.getGreen(), color.getBlue(), 0);
+    }
+
+    private static RGBAColor fromHexColor(@Nullable String color) {
+        if (color != null && color.matches(COLOR_REGEX)) {
+            return new RGBAColor(Integer.valueOf(color.substring(1, 3), 16),
+                    Integer.valueOf(color.substring(3, 5), 16),
+                    Integer.valueOf(color.substring(5, 7), 16), ALPHA);
+        }
+        return new RGBAColor(0, 0, 0, ALPHA);
+    }
+
+    private static RGBAColor parseColor(@Nullable String colorString) {
+        if (colorString == null) {
+            return fromHexColor(DEFAULT_COLOR);
+        }
+        if (colorString.matches(COLOR_REGEX)) {
+            return fromHexColor(colorString);
+        }
+        return fromHexColor(X11ColorUtils.toHexColor(colorString));
+    }
+
+    private Map<@NonNull String, @NonNull Collection<@NonNull Annotation>> getMarkers(Map<@NonNull String, @NonNull Object> fetchParams, @Nullable IProgressMonitor monitor) {
+        List<@NonNull Long> timeRequested = DataProviderParameterUtils.extractTimeRequested(fetchParams);
+        if (timeRequested == null || timeRequested.size() < 2) {
+            return Collections.emptyMap();
+        }
+        Set<@NonNull String> categoriesRequested = getCategories(fetchParams);
+        Long[] times = timeRequested.toArray(new Long[0]);
+        long starttime = timeRequested.get(0);
+        long endtime = timeRequested.get(timeRequested.size() - 1);
+        int resolution = (int) Math.min(Integer.MAX_VALUE, timeRequested.get(1) - timeRequested.get(0));
+        Map<@NonNull String, @NonNull Collection<@NonNull Annotation>> markerMap = new LinkedHashMap<>();
+        for (IOutputAnnotationProvider source : fMarkerEventSources) {
+            long minDuration = resolution * MIN_PERIOD;
+            if (source instanceof PeriodicAnnotationSource) {
+                PeriodicAnnotationSource periodicAnnotationSource = (PeriodicAnnotationSource) source;
+                long maxDuration = (long) periodicAnnotationSource.getPeriod();
+                if (maxDuration > minDuration) {
+                    AnnotationModel model = periodicAnnotationSource.fetchAnnotations(fetchParams, monitor).getModel();
+                    if (model != null) {
+                        Map<@NonNull String, @NonNull Collection<@NonNull Annotation>> annotations = model.getAnnotations();
+                        List<Annotation> markerList = new ArrayList<>();
+                        for (Entry<@NonNull String, @NonNull Collection<@NonNull Annotation>> entryAnnotation : annotations.entrySet()) {
+                            String category = Objects.requireNonNull(entryAnnotation.getKey());
+                            if (!categoriesRequested.isEmpty() && !categoriesRequested.contains(category)) {
+                                continue;
+                            }
+                            for (Annotation annotation : Objects.requireNonNull(entryAnnotation.getValue())) {
+                                markerList.add(annotation);
+                                for (SubMarker subMarker : periodicAnnotationSource.getMarker().getSubMarkers()) {
+                                    getSubMarkerList(Objects.requireNonNull(subMarker), annotation, markerMap, starttime, endtime, minDuration, times);
+
+                                }
+                            }
+                            markerMap.put(category, markerList);
+                        }
+                    }
+                }
+            }
+        }
+        return markerMap;
+    }
+
+    private static Set<String> getCategories(Map<String, Object> fetchParams) {
+        Set<String> categories = new HashSet<>();
+        Object fetched = fetchParams.getOrDefault(DataProviderParameterUtils.REQUESTED_MARKER_CATEGORIES_KEY, Collections.emptyList());
+        if (fetched instanceof Iterable<?>) {
+            for (Object key : (Iterable<?>) fetched) {
+                if (key != null) {
+                    categories.add(String.valueOf(key));
+                }
+            }
+        }
+        return categories;
+    }
+
+    private static OutputElementStyle getOutputStyle(Marker marker, RGBAColor color) {
+        Map<@NonNull String, @NonNull Object> style = new HashMap<>();
+        String name = marker.getName();
+        if (name != null) {
+            style.put(StyleProperties.STYLE_NAME, name);
+        }
+        style.put(StyleProperties.COLOR, color.toString().substring(0, 7));
+        style.put(StyleProperties.OPACITY, (float) (color.getAlpha() / 255.0));
+        return new OutputElementStyle(null, style);
+    }
+
+    @Override
+    public @NonNull TmfModelResponse<@NonNull AnnotationCategoriesModel> fetchAnnotationCategories(@NonNull Map<@NonNull String, @NonNull Object> fetchParameters, @Nullable IProgressMonitor monitor) {
+        List<@NonNull String> categories = new ArrayList<>();
+        for (IOutputAnnotationProvider source : fMarkerEventSources) {
+            TmfModelResponse<@NonNull AnnotationCategoriesModel> response = source.fetchAnnotationCategories(fetchParameters, monitor);
+            AnnotationCategoriesModel model = response.getModel();
+            if (model != null) {
+                categories.addAll(model.getAnnotationCategories());
+            }
+        }
+        return new TmfModelResponse<>(new AnnotationCategoriesModel(categories), Status.COMPLETED, ""); //$NON-NLS-1$
+    }
+
+    @Override
+    public @NonNull TmfModelResponse<@NonNull AnnotationModel> fetchAnnotations(@NonNull Map<@NonNull String, @NonNull Object> fetchParameters, @Nullable IProgressMonitor monitor) {
+        Map<@NonNull String, @NonNull Collection<@NonNull Annotation>> markers = getMarkers(fetchParameters, monitor);
+        return new TmfModelResponse<>(new AnnotationModel(markers), Status.COMPLETED, ""); //$NON-NLS-1$
+    }
+
+    /**
+     * Get Max Duration
+     *
+     * @return the maximum duration of all event sources
+     */
+    public double getMaxDuration() {
+        double duration = 0;
+        for (IOutputAnnotationProvider es : fMarkerEventSources) {
+            if (es instanceof PeriodicAnnotationSource) {
+                duration = Math.max(duration, ((PeriodicAnnotationSource) es).getPeriod());
+            }
+        }
+        return duration;
+    }
+
+    /**
+     * Get the label of the marker, may be a format string
+     *
+     * @return the label of the marker
+     */
+    public Map<String, String> getLabel() {
+        Map<String, String> labels = new HashMap<>();
+        if (fMarkerSet != null) {
+            for (Marker marker : fMarkerSet.getMarkers()) {
+                if (marker instanceof PeriodicMarker) {
+                    PeriodicMarker periodicMarker = (PeriodicMarker) marker;
+                    labels.put(Objects.requireNonNull(periodicMarker.getName()), Objects.requireNonNull(periodicMarker.getLabel()));
+                }
+            }
+        }
+        return labels;
+    }
+}
diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/model/annotations/PeriodicAnnotationSource.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/model/annotations/PeriodicAnnotationSource.java
new file mode 100644
index 0000000..db1e828
--- /dev/null
+++ b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/provisional/tmf/core/model/annotations/PeriodicAnnotationSource.java
@@ -0,0 +1,289 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License 2.0 which
+ * accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.provisional.tmf.core.model.annotations;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+import org.apache.commons.lang3.math.Fraction;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.internal.tmf.core.markers.Marker;
+import org.eclipse.tracecompass.internal.tmf.core.markers.Marker.PeriodicMarker;
+import org.eclipse.tracecompass.internal.tmf.core.markers.SubMarker;
+import org.eclipse.tracecompass.tmf.core.dataprovider.DataProviderParameterUtils;
+import org.eclipse.tracecompass.tmf.core.markers.ITimeReference;
+import org.eclipse.tracecompass.tmf.core.markers.TimeReference;
+import org.eclipse.tracecompass.tmf.core.model.OutputElementStyle;
+import org.eclipse.tracecompass.tmf.core.model.StyleProperties;
+import org.eclipse.tracecompass.tmf.core.presentation.RGBAColor;
+import org.eclipse.tracecompass.tmf.core.response.ITmfResponse.Status;
+import org.eclipse.tracecompass.tmf.core.response.TmfModelResponse;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.RangeSet;
+
+/**
+ * Data provider for Periodic Markers (frames)
+ *
+ * @author Matthew Khouzam
+ * @since 6.3
+ */
+public class PeriodicAnnotationSource implements IOutputAnnotationProvider {
+    private static final TmfModelResponse<AnnotationModel> EMPTY_MODEL_RESPONSE = new TmfModelResponse<>(new AnnotationModel(Collections.emptyMap()), Status.COMPLETED, ""); //$NON-NLS-1$
+    private final String fCategory;
+    private final double fPeriod;
+    private final long fPeriodInteger;
+    private @Nullable Fraction fPeriodFraction;
+    private final long fRollover;
+    private final RGBAColor fColor1;
+    private final @Nullable RGBAColor fColor2;
+    private ITimeReference fReference;
+    /**
+     * TODO: remove later
+     */
+    private final Marker fMarker;
+
+    /**
+     * Creates a data provider for periodic markers. They alternate in color and
+     * can have sub markers.
+     *
+     * @param category
+     *            the category marker, to reference submarkers and such
+     * @param index
+     *            the index (number) of the reference frame
+     * @param time
+     *            the time of the reference frame frame - the time of the frame refered by index.
+     * @param period
+     *            the period of the markers, in ns
+     * @param rollover
+     *            the rollover for the index. If it is 100, the indexes will
+     *            increment 98->99->0-> ...
+     * @param color1
+     *            the even color
+     * @param color2
+     *            the odd color
+     */
+    public PeriodicAnnotationSource(Marker category, long index, long time, double period, long rollover, RGBAColor color1, @Nullable RGBAColor color2) {
+        fCategory = String.valueOf(category.getName());
+        fMarker = category;
+        fReference = new TimeReference(time, index);
+        fColor1 = color1;
+        fColor2 = color2;
+        fPeriod = period;
+        fPeriodInteger = (long) period;
+        try {
+            fPeriodFraction = Fraction.getFraction(fPeriod - fPeriodInteger);
+        } catch (ArithmeticException e) {
+            /* can't convert to fraction, use floating-point arithmetic */
+            fPeriodFraction = null;
+        }
+        fRollover = rollover;
+    }
+
+    /**
+     * Creates a data provider for periodic markers. They alternate in color and
+     * can have sub markers.
+     *
+     * @param category
+     *            the category Name
+     * @param index
+     *            the index (number) of the starting frame
+     * @param time
+     *            the time of the starting frame
+     * @param period
+     *            the period of the markers, in ns
+     * @param rollover
+     *            the rollover for the index. If it is 100, the indexes will
+     *            increment 98->99->0-> ...
+     * @param color1
+     *            the even color
+     * @param color2
+     *            the odd color
+     */
+    public PeriodicAnnotationSource(String category, long index, long time, double period, long rollover, RGBAColor color1, @Nullable RGBAColor color2) {
+        this(new Marker(category, "black") {}, index, time, period, rollover, color1, color2); //$NON-NLS-1$
+    }
+
+    /*
+     * Adjust to a reference that is closer to the start time, to avoid rounding
+     * errors in floating point calculations with large numbers.
+     */
+    private ITimeReference adjustReference(ITimeReference baseReference, long time) {
+        long offsetIndex = (long) ((time - baseReference.getTime()) / fPeriod);
+        long offsetTime = 0;
+        Fraction fraction = fPeriodFraction;
+        if (fraction != null) {
+            /*
+             * If period = int num/den, find an offset index that is an exact
+             * multiple of den and calculate index * period = (index * int) +
+             * (index / den * num), all exact calculations.
+             */
+            offsetIndex = offsetIndex - offsetIndex % fraction.getDenominator();
+            offsetTime = offsetIndex * fPeriodInteger + offsetIndex / fraction.getDenominator() * fraction.getNumerator();
+        } else {
+            /*
+             * Couldn't compute fractional part as fraction, use simple
+             * multiplication but with possible rounding error.
+             */
+            offsetTime = Math.round(offsetIndex * fPeriod);
+        }
+        return new TimeReference(baseReference.getTime() + offsetTime, baseReference.getIndex() + offsetIndex);
+    }
+
+    @Override
+    public @NonNull TmfModelResponse<@NonNull AnnotationCategoriesModel> fetchAnnotationCategories(@NonNull Map<@NonNull String, @NonNull Object> fetchParameters, @Nullable IProgressMonitor monitor) {
+        List<@NonNull String> categories = new ArrayList<>();
+        categories.add(fCategory);
+        getCategories(categories, getMarker());
+        /*
+         * We can have different sub-markers of the same category, we need them
+         * to be distinct
+         */
+        categories = categories.stream().distinct().collect(Collectors.toList());
+        return new TmfModelResponse<>(
+                new AnnotationCategoriesModel(categories), Status.COMPLETED, ""); //$NON-NLS-1$
+    }
+
+    private void getCategories(List<@NonNull String> categories, Marker marker) {
+        for (SubMarker sm : marker.getSubMarkers()) {
+            categories.add(String.valueOf(sm.getName()));
+            getCategories(categories, sm);
+        }
+    }
+
+    @Override
+    public @NonNull TmfModelResponse<@NonNull AnnotationModel> fetchAnnotations(@NonNull Map<@NonNull String, @NonNull Object> fetchParameters, @Nullable IProgressMonitor monitor) {
+        List<Long> times = DataProviderParameterUtils.extractTimeRequested(fetchParameters);
+        if (times == null) {
+            return EMPTY_MODEL_RESPONSE;
+        }
+        int size = times.size() - 1;
+        long startTime = times.get(0);
+        long endTime = times.get(size);
+        long resolution = (endTime - startTime) / (size);
+        if (startTime > endTime) {
+            return EMPTY_MODEL_RESPONSE;
+        }
+        long step = Math.max(Math.round(fPeriod), resolution);
+        OutputElementStyle[] styles = new OutputElementStyle[2];
+        styles[0] = generateOutputElementStyle(fColor1);
+        RGBAColor color2 = fColor2;
+        styles[1] = color2 == null ? styles[0] : generateOutputElementStyle(color2);
+
+        Collection<Annotation> annotations = new ArrayList<>();
+        /* Subtract 1.5 periods to ensure previous marker is included */
+        long time = startTime - Math.max(Math.round(1.5 * fPeriod), resolution);
+        ITimeReference reference = adjustReference(fReference, time);
+        Annotation annotation = null;
+        while (true) {
+            long index = Math.round((time - reference.getTime()) / fPeriod) + reference.getIndex();
+            long markerTime = Math.round((index - reference.getIndex()) * fPeriod) + reference.getTime();
+            long duration = (fColor2 == null) ? 0 : Math.round((index + 1 - reference.getIndex()) * fPeriod) + reference.getTime() - markerTime;
+
+            long labelIndex = index;
+            if (fRollover != 0) {
+                labelIndex %= fRollover;
+                if (labelIndex < 0) {
+                    labelIndex += fRollover;
+                }
+            }
+            /* Add previous marker if current is visible */
+            if ((markerTime >= startTime || markerTime + duration > startTime) && annotation != null) {
+                annotations.add(annotation);
+            }
+            if (isApplicable(labelIndex)) {
+                OutputElementStyle style = Objects.requireNonNull((index % 2) == 0 ? styles[0] : styles[1]);
+                annotation = new Annotation(markerTime, duration, -1, String.valueOf(labelIndex), style);
+            } else {
+                annotation = null;
+            }
+            if (markerTime > endTime || (monitor != null && monitor.isCanceled())) {
+                if (annotation != null && isApplicable(labelIndex)) {
+                    /* The next marker out of range is included */
+                    annotations.add(annotation);
+                }
+                break;
+            }
+
+            time += step;
+        }
+        Map<String, Collection<Annotation>> model = new HashMap<>();
+        model.put(fCategory, annotations);
+        return new TmfModelResponse<>(new AnnotationModel(model), Status.COMPLETED, ""); //$NON-NLS-1$
+    }
+
+    private static OutputElementStyle generateOutputElementStyle(RGBAColor color) {
+        String colorString = color.toString().substring(0, 7);
+        return new OutputElementStyle(null,
+                ImmutableMap.of(StyleProperties.STYLE_NAME, colorString,
+                        StyleProperties.COLOR, colorString,
+                        StyleProperties.OPACITY, (float) (color.getAlpha() / 255.0)));
+    }
+
+    /**
+     * Period
+     *
+     * @return period in ns
+     */
+    public double getPeriod() {
+        return fPeriod;
+    }
+
+    /**
+     * Get the marker model
+     *
+     * @return the marker that this annotation provider is modeled on
+     */
+    public Marker getMarker() {
+        return fMarker;
+    }
+
+    /**
+     * Get the base index (starting index) for a marker
+     *
+     * @return the base index
+     */
+    public long getBaseIndex() {
+        Marker marker = getMarker();
+        if (marker instanceof PeriodicMarker) {
+            return ((PeriodicMarker) marker).getOffset();
+        }
+        return 0;
+    }
+
+    /**
+     * Is this index applicable?
+     *
+     * @param index
+     *            the index to look at
+     * @return true if it applies
+     */
+    public boolean isApplicable(long index) {
+        Marker marker = getMarker();
+        if (marker instanceof PeriodicMarker) {
+            PeriodicMarker periodicMarker = (PeriodicMarker) marker;
+            RangeSet<@Nullable Long> indexRange = periodicMarker.getIndexRange();
+            if (indexRange != null) {
+                return indexRange.contains(periodicMarker.getOffset() + index);
+            }
+        }
+        return true;
+    }
+}
diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/tmf/core/Activator.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/tmf/core/Activator.java
index 586d399..f64012e 100644
--- a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/tmf/core/Activator.java
+++ b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/tmf/core/Activator.java
@@ -19,10 +19,13 @@
 import org.eclipse.core.runtime.Plugin;
 import org.eclipse.core.runtime.Status;
 import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.tracecompass.internal.tmf.core.annotations.CustomDefinedOutputAnnotationProviderFactory;
 import org.eclipse.tracecompass.tmf.core.analysis.TmfAnalysisManager;
 import org.eclipse.tracecompass.tmf.core.dataprovider.DataProviderManager;
 import org.eclipse.tracecompass.tmf.core.signal.TmfSignalManager;
 import org.eclipse.tracecompass.tmf.core.symbols.SymbolProviderManager;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+import org.eclipse.tracecompass.tmf.core.trace.TmfTraceAdapterManager;
 import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
 import org.osgi.framework.BundleContext;
 
@@ -48,6 +51,7 @@
      * The shared instance
      */
     private static Activator fPlugin;
+    private static final CustomDefinedOutputAnnotationProviderFactory CUSTOM_DEFINED_OUTPUT_ANNOTATION_PROVIDER_FACTORY = new CustomDefinedOutputAnnotationProviderFactory();
 
     // ------------------------------------------------------------------------
     // Constructors
@@ -95,10 +99,13 @@
         SymbolProviderManager.getInstance();
         /* Initialize the data provider manager */
         DataProviderManager.getInstance();
+        TmfTraceAdapterManager.registerFactory(CUSTOM_DEFINED_OUTPUT_ANNOTATION_PROVIDER_FACTORY, ITmfTrace.class);
     }
 
     @Override
     public void stop(BundleContext context) throws Exception {
+        TmfTraceAdapterManager.unregisterFactory(CUSTOM_DEFINED_OUTPUT_ANNOTATION_PROVIDER_FACTORY);
+        CUSTOM_DEFINED_OUTPUT_ANNOTATION_PROVIDER_FACTORY.dispose();
         TmfCoreTracer.stop();
         TmfTraceManager.getInstance().dispose();
         TmfAnalysisManager.dispose();
diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/tmf/core/annotations/CustomDefinedOutputAnnotationProvider.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/tmf/core/annotations/CustomDefinedOutputAnnotationProvider.java
new file mode 100644
index 0000000..07bf048
--- /dev/null
+++ b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/tmf/core/annotations/CustomDefinedOutputAnnotationProvider.java
@@ -0,0 +1,104 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License 2.0 which
+ * accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.internal.tmf.core.annotations;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.internal.provisional.tmf.core.model.annotations.AnnotationCategoriesModel;
+import org.eclipse.tracecompass.internal.provisional.tmf.core.model.annotations.AnnotationModel;
+import org.eclipse.tracecompass.internal.provisional.tmf.core.model.annotations.CustomAnnotationProvider;
+import org.eclipse.tracecompass.internal.provisional.tmf.core.model.annotations.IOutputAnnotationProvider;
+import org.eclipse.tracecompass.internal.tmf.core.markers.MarkerConfigXmlParser;
+import org.eclipse.tracecompass.internal.tmf.core.markers.MarkerSet;
+import org.eclipse.tracecompass.tmf.core.dataprovider.DataProviderParameterUtils;
+import org.eclipse.tracecompass.tmf.core.response.ITmfResponse.Status;
+import org.eclipse.tracecompass.tmf.core.response.TmfModelResponse;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+import org.eclipse.tracecompass.tmf.core.trace.TmfTraceManager;
+
+/**
+ * Trace Annotation provider for providing custom (frame) annotations. This one
+ * is a singleton for all of trace compass, it encapsulates the individual
+ * annotation providers per trace.
+ */
+public class CustomDefinedOutputAnnotationProvider implements IOutputAnnotationProvider {
+
+    private static final String INVALID_MARKER_ID = "Invalid marker ID %s"; //$NON-NLS-1$
+    private static final String NO_MARKER_ID = "no markerID"; //$NON-NLS-1$
+    private final Map<String, Map<String, CustomAnnotationProvider>> fTraceMarkers = Collections.synchronizedMap(new HashMap<>());
+
+    /**
+     * Constructor
+     */
+    public CustomDefinedOutputAnnotationProvider() {
+        MarkerConfigXmlParser.initMarkerSets();
+    }
+
+    @Override
+    public TmfModelResponse<AnnotationCategoriesModel> fetchAnnotationCategories(Map<String, Object> fetchParameters, @Nullable IProgressMonitor monitor) {
+        Object markerID = fetchParameters.get(DataProviderParameterUtils.REQUESTED_MARKER_SET_KEY);
+        Object hostID = fetchParameters.get(DataProviderParameterUtils.REQUESTED_TRACE_KEY);
+        Optional<ITmfTrace> activeTrace = getTrace(hostID);
+        if (markerID == null) {
+            return new TmfModelResponse<>(null, Status.FAILED, NO_MARKER_ID);
+        }
+        MarkerSet ms = getMarkerSet(markerID);
+        if (ms != null) {
+            return getAnnotationProvider(String.valueOf(hostID), activeTrace.get(), ms).fetchAnnotationCategories(fetchParameters, monitor);
+        }
+        return new TmfModelResponse<>(null, Status.FAILED, formatError(markerID));
+    }
+
+    @Override
+    public TmfModelResponse<AnnotationModel> fetchAnnotations(Map<String, Object> fetchParameters, @Nullable IProgressMonitor monitor) {
+        Object markerID = fetchParameters.get(DataProviderParameterUtils.REQUESTED_MARKER_SET_KEY);
+        Object hostID = fetchParameters.get(DataProviderParameterUtils.REQUESTED_TRACE_KEY);
+        Optional<ITmfTrace> activeTrace = getTrace(hostID);
+        if (markerID == null) {
+            return new TmfModelResponse<>(null, Status.FAILED, NO_MARKER_ID);
+        }
+        MarkerSet ms = getMarkerSet(markerID);
+        if (ms != null) {
+            return getAnnotationProvider(String.valueOf(hostID), activeTrace.isPresent() ? activeTrace.get() : null, ms).fetchAnnotations(fetchParameters, monitor);
+        }
+        return new TmfModelResponse<>(null, Status.FAILED, formatError(markerID));
+    }
+
+    private CustomAnnotationProvider getAnnotationProvider(String hostID, @Nullable ITmfTrace activeTrace, MarkerSet ms) {
+        Map<String, CustomAnnotationProvider> capMap = fTraceMarkers.computeIfAbsent(hostID, e -> Collections.synchronizedMap(new HashMap<>()));
+        return capMap.computeIfAbsent(ms.getId(), a -> new CustomAnnotationProvider(activeTrace, ms));
+    }
+
+    private static @Nullable MarkerSet getMarkerSet(Object markerID) {
+        Optional<@Nullable MarkerSet> markerOptional = MarkerConfigXmlParser.getMarkerSets().stream()
+                .filter(markerSet -> Objects.equals(markerID, markerSet.getId()))
+                .findAny();
+        if (markerOptional.isPresent()) {
+            return markerOptional.get();
+        }
+        return null;
+    }
+
+    private static Optional<ITmfTrace> getTrace(Object hostID) {
+        return TmfTraceManager.getInstance().getOpenedTraces().stream().flatMap(trace -> TmfTraceManager.getTraceSetWithExperiment(trace).stream()).filter(t -> Objects.equals(t.getHostId(), hostID)).findAny();
+    }
+
+    private static String formatError(Object markerID) {
+        return String.format(INVALID_MARKER_ID, markerID);
+    }
+}
diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/tmf/core/markers/LostEventsOutputAnnotationProviderFactory.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/tmf/core/annotations/CustomDefinedOutputAnnotationProviderFactory.java
similarity index 63%
copy from tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/tmf/core/markers/LostEventsOutputAnnotationProviderFactory.java
copy to tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/tmf/core/annotations/CustomDefinedOutputAnnotationProviderFactory.java
index 86161ea..0f81ee4 100644
--- a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/tmf/core/markers/LostEventsOutputAnnotationProviderFactory.java
+++ b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/tmf/core/annotations/CustomDefinedOutputAnnotationProviderFactory.java
@@ -9,23 +9,22 @@
  * SPDX-License-Identifier: EPL-2.0
  *******************************************************************************/
 
-package org.eclipse.tracecompass.internal.tmf.core.markers;
+package org.eclipse.tracecompass.internal.tmf.core.annotations;
 
+import org.eclipse.jdt.annotation.Nullable;
 import org.eclipse.tracecompass.internal.provisional.tmf.core.model.annotations.IOutputAnnotationProvider;
-import org.eclipse.tracecompass.internal.provisional.tmf.core.model.annotations.LostEventOutputAnnotationProvider;
 import org.eclipse.tracecompass.tmf.core.trace.AbstractTmfTraceAdapterFactory;
 import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
 
 /**
- * Output annotation provider factory for trace level annotations for lost events.
+ * Output annotation provider factory for trace level annotations for custom annotations (frames).
  */
-public class LostEventsOutputAnnotationProviderFactory extends AbstractTmfTraceAdapterFactory {
+public class CustomDefinedOutputAnnotationProviderFactory extends AbstractTmfTraceAdapterFactory {
 
     @Override
-    protected <T> T getTraceAdapter(ITmfTrace trace, Class<T> adapterType) {
-        if (IOutputAnnotationProvider.class.equals(adapterType)) {
-            IOutputAnnotationProvider adapter = new LostEventOutputAnnotationProvider(trace);
-            return adapterType.cast(adapter);
+    protected @Nullable <T> T getTraceAdapter(ITmfTrace trace, @Nullable Class<T> adapterType) {
+        if (null != adapterType && IOutputAnnotationProvider.class.equals(adapterType)) {
+            return adapterType.cast(new CustomDefinedOutputAnnotationProvider());
         }
         return null;
     }
diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/tmf/core/markers/LostEventsOutputAnnotationProviderFactory.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/tmf/core/annotations/LostEventsOutputAnnotationProviderFactory.java
similarity index 82%
rename from tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/tmf/core/markers/LostEventsOutputAnnotationProviderFactory.java
rename to tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/tmf/core/annotations/LostEventsOutputAnnotationProviderFactory.java
index 86161ea..9e1c0d8 100644
--- a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/tmf/core/markers/LostEventsOutputAnnotationProviderFactory.java
+++ b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/tmf/core/annotations/LostEventsOutputAnnotationProviderFactory.java
@@ -9,8 +9,9 @@
  * SPDX-License-Identifier: EPL-2.0
  *******************************************************************************/
 
-package org.eclipse.tracecompass.internal.tmf.core.markers;
+package org.eclipse.tracecompass.internal.tmf.core.annotations;
 
+import org.eclipse.jdt.annotation.Nullable;
 import org.eclipse.tracecompass.internal.provisional.tmf.core.model.annotations.IOutputAnnotationProvider;
 import org.eclipse.tracecompass.internal.provisional.tmf.core.model.annotations.LostEventOutputAnnotationProvider;
 import org.eclipse.tracecompass.tmf.core.trace.AbstractTmfTraceAdapterFactory;
@@ -22,8 +23,8 @@
 public class LostEventsOutputAnnotationProviderFactory extends AbstractTmfTraceAdapterFactory {
 
     @Override
-    protected <T> T getTraceAdapter(ITmfTrace trace, Class<T> adapterType) {
-        if (IOutputAnnotationProvider.class.equals(adapterType)) {
+    protected <T> @Nullable T getTraceAdapter(ITmfTrace trace, @Nullable Class<T> adapterType) {
+        if (null != adapterType && IOutputAnnotationProvider.class.equals(adapterType)) {
             IOutputAnnotationProvider adapter = new LostEventOutputAnnotationProvider(trace);
             return adapterType.cast(adapter);
         }
diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/tmf/core/annotations/package-info.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/tmf/core/annotations/package-info.java
new file mode 100644
index 0000000..71eee61
--- /dev/null
+++ b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/tmf/core/annotations/package-info.java
@@ -0,0 +1,13 @@
+/**********************************************************************
+ * Copyright (c) 2021 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License 2.0 which
+ * accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ **********************************************************************/
+
+@org.eclipse.jdt.annotation.NonNullByDefault
+package org.eclipse.tracecompass.internal.tmf.core.annotations;
diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/tmf/core/markers/IMarkerConstants.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/tmf/core/markers/IMarkerConstants.java
index 9800354..dc38d3d 100644
--- a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/tmf/core/markers/IMarkerConstants.java
+++ b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/internal/tmf/core/markers/IMarkerConstants.java
@@ -14,6 +14,11 @@
 
 package org.eclipse.tracecompass.internal.tmf.core.markers;
 
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.jdt.annotation.Nullable;
+import org.eclipse.tracecompass.tmf.core.trace.ICyclesConverter;
+import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
+
 /**
  * Marker constants
  *
@@ -65,4 +70,42 @@
     String NS = "ns"; //$NON-NLS-1$
     /** Cycles unit */
     String CYCLES = "cycles"; //$NON-NLS-1$
+
+    /** Nanoseconds to milliseconds */
+    long NANO_PER_MILLI = 1000000L;
+    /** Nanoseconds to microseconds */
+    long NANO_PER_MICRO = 1000L;
+
+    /**
+     * Converter for a number with unit to
+     *
+     * @param number
+     *            the value of the time to be converted, for 314 us it would be
+     *            314.
+     * @param unit
+     *            the unit, {@link IMarkerConstants#MS},
+     *            {@link IMarkerConstants#US},{@link IMarkerConstants#NS} or
+     *            {@link IMarkerConstants#CYCLES}
+     * @param trace
+     *            needed for cycle conversion, can be {@code null}
+     * @return a double of nanoseconds. Note, will lose precision for UTC times,
+     *         but it is needed to not accumulate errors. This makes sense in
+     *         the context of "periodic markers"
+     */
+    static double convertToNanos(double number, String unit, @Nullable ITmfTrace trace) {
+        if (unit.equalsIgnoreCase(MS)) {
+            return number * NANO_PER_MILLI;
+        } else if (unit.equalsIgnoreCase(US)) {
+            return number * NANO_PER_MICRO;
+        } else if (unit.equalsIgnoreCase(NS)) {
+            return number;
+        } else if (unit.equalsIgnoreCase(CYCLES) &&
+                trace instanceof IAdaptable) {
+            ICyclesConverter adapter = ((IAdaptable) trace).getAdapter(ICyclesConverter.class);
+            if (adapter != null) {
+                return adapter.cyclesToNanos((long) number);
+            }
+        }
+        return number;
+    }
 }
diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/dataprovider/DataProviderParameterUtils.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/dataprovider/DataProviderParameterUtils.java
index 5eae25b..5389e99 100644
--- a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/dataprovider/DataProviderParameterUtils.java
+++ b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/dataprovider/DataProviderParameterUtils.java
@@ -67,6 +67,26 @@
     public static final String REQUESTED_ELEMENT_KEY = "requested_element"; //$NON-NLS-1$
 
     /**
+     * Requested marker set key
+     * @since 7.0
+     */
+    public static final String REQUESTED_MARKER_SET_KEY = "requested_marker_set"; //$NON-NLS-1$
+
+    /**
+     * Requested marker categories key
+     * @since 7.0
+     */
+    public static final String REQUESTED_MARKER_CATEGORIES_KEY = "requested_marker_categories"; //$NON-NLS-1$
+
+    /**
+     * Requested trace key, uses the hostID, as the time is the same for every
+     * trace with the same host id.
+     *
+     * @since 7.0
+     */
+    public static final String REQUESTED_TRACE_KEY = "requested_trace"; //$NON-NLS-1$
+
+    /**
      * Key to extract isFiltered from parameters map
      */
     public static final String FILTERED_KEY = "isFiltered"; //$NON-NLS-1$
@@ -193,9 +213,9 @@
     @SuppressWarnings("unchecked")
     private static @Nullable List<Long> transformToLongList(Collection<?> collectionToTransform) {
         if (!collectionToTransform.isEmpty()) {
-            if (collectionToTransform instanceof List<?> && collectionToTransform.stream().allMatch(e -> e instanceof Long)) {
+            if (collectionToTransform instanceof List<?> && collectionToTransform.stream().allMatch(Long.class::isInstance)) {
                 return (List<Long>) collectionToTransform;
-            } else if (collectionToTransform.stream().allMatch(e -> e instanceof Integer)) {
+            } else if (collectionToTransform.stream().allMatch(Integer.class::isInstance)) {
                 List<Long> list = new ArrayList<>();
                 for (Integer element : (List<Integer>) collectionToTransform) {
                     list.add(element.longValue());
diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/markers/ITimeReference.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/markers/ITimeReference.java
new file mode 100644
index 0000000..2034a59
--- /dev/null
+++ b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/markers/ITimeReference.java
@@ -0,0 +1,43 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License 2.0 which
+ * accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.core.markers;
+
+/**
+ * Time reference interface, allows one to get a time and an index. This is
+ * useful for marker locations or any correlation between gantt charts and other
+ * views.
+ *
+ * @author Matthew Khouzam
+ * @since 7.0
+ */
+public interface ITimeReference {
+
+    /**
+     * Zero reference at index 0 and time 0
+     */
+    ITimeReference ZERO = new TimeReference(0, 0);
+
+    /**
+     * Gets the reference marker time.
+     *
+     * @return the reference marker time
+     */
+    long getTime();
+
+    /**
+     * Gets the reference marker index.
+     *
+     * @return the reference marker index
+     */
+    long getIndex();
+
+}
diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/markers/ITimeReferenceProvider.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/markers/ITimeReferenceProvider.java
new file mode 100644
index 0000000..771c396
--- /dev/null
+++ b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/markers/ITimeReferenceProvider.java
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License 2.0 which
+ * accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.core.markers;
+
+import java.util.function.Function;
+
+/**
+ * Marker Reference Provider, allows one to extract a marker time reference from
+ * a given id string
+ *
+ * @author Matthew Khouzam
+ * @since 7.0
+ */
+public interface ITimeReferenceProvider extends Function<String, ITimeReference> {
+
+    /**
+     * Get the reference for the specified reference id
+     *
+     * @param referenceId
+     *            the reference id
+     * @return a reference
+     */
+    @Override
+    ITimeReference apply(String referenceId);
+
+}
diff --git a/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/markers/TimeReference.java b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/markers/TimeReference.java
new file mode 100644
index 0000000..1937b01
--- /dev/null
+++ b/tmf/org.eclipse.tracecompass.tmf.core/src/org/eclipse/tracecompass/tmf/core/markers/TimeReference.java
@@ -0,0 +1,53 @@
+/*******************************************************************************
+ * Copyright (c) 2021 Ericsson
+ *
+ * All rights reserved. This program and the accompanying materials are
+ * made available under the terms of the Eclipse Public License 2.0 which
+ * accompanies this distribution, and is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *******************************************************************************/
+
+package org.eclipse.tracecompass.tmf.core.markers;
+
+/**
+ * Time reference, contains a timestamp and an index. A simple
+ * {@link ITimeReference} implementation.
+ *
+ * @author Matthew Khouzam
+ * @since 7.0
+ */
+public class TimeReference implements ITimeReference {
+
+    private final long time;
+    private final long index;
+
+    /**
+     * Constructor
+     *
+     * @param time
+     *            the reference marker time in time units
+     * @param index
+     *            the reference marker index
+     */
+    public TimeReference(long time, long index) {
+        this.time = time;
+        this.index = index;
+    }
+
+    @Override
+    public long getTime() {
+        return time;
+    }
+
+    @Override
+    public long getIndex() {
+        return index;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("[%d, %d]", time, index); //$NON-NLS-1$
+    }
+}
diff --git a/tmf/org.eclipse.tracecompass.tmf.ui.tests/src/org/eclipse/tracecompass/tmf/ui/tests/markers/ConfigurableMarkerEventSourceTest.java b/tmf/org.eclipse.tracecompass.tmf.ui.tests/src/org/eclipse/tracecompass/tmf/ui/tests/markers/ConfigurableMarkerEventSourceTest.java
index 3531e37..2e87246 100644
--- a/tmf/org.eclipse.tracecompass.tmf.ui.tests/src/org/eclipse/tracecompass/tmf/ui/tests/markers/ConfigurableMarkerEventSourceTest.java
+++ b/tmf/org.eclipse.tracecompass.tmf.ui.tests/src/org/eclipse/tracecompass/tmf/ui/tests/markers/ConfigurableMarkerEventSourceTest.java
@@ -31,13 +31,13 @@
 import org.eclipse.tracecompass.internal.tmf.core.markers.SubMarker.SplitMarker;
 import org.eclipse.tracecompass.internal.tmf.core.markers.SubMarker.WeightedMarker;
 import org.eclipse.tracecompass.internal.tmf.ui.markers.ConfigurableMarkerEventSource;
+import org.eclipse.tracecompass.tmf.core.markers.ITimeReferenceProvider;
 import org.eclipse.tracecompass.tmf.core.tests.shared.TmfTestTrace;
 import org.eclipse.tracecompass.tmf.core.trace.AbstractTmfTraceAdapterFactory;
 import org.eclipse.tracecompass.tmf.core.trace.ICyclesConverter;
 import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
 import org.eclipse.tracecompass.tmf.core.trace.TmfTraceAdapterManager;
 import org.eclipse.tracecompass.tmf.tests.stubs.trace.TmfTraceStub;
-import org.eclipse.tracecompass.tmf.ui.markers.IMarkerReferenceProvider;
 import org.eclipse.tracecompass.tmf.ui.markers.PeriodicMarkerEventSource.Reference;
 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.IMarkerEvent;
 import org.junit.After;
@@ -71,10 +71,10 @@
                 };
                 return adapterType.cast(adapter);
             }
-            if (IMarkerReferenceProvider.class.equals(adapterType)) {
-                IMarkerReferenceProvider adapter = new IMarkerReferenceProvider() {
+            if (ITimeReferenceProvider.class.equals(adapterType)) {
+                ITimeReferenceProvider adapter = new ITimeReferenceProvider() {
                     @Override
-                    public Reference getReference(String referenceId) {
+                    public Reference apply(String referenceId) {
                         if ("ref.c".equals(referenceId)) {
                             return new Reference(1000L, 0);
                         }
@@ -90,7 +90,7 @@
         public Class<?>[] getAdapterList() {
             return new Class[] {
                     ICyclesConverter.class,
-                    IMarkerReferenceProvider.class
+                    ITimeReferenceProvider.class
             };
         }
     }
diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/Activator.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/Activator.java
index 7d89cd0..6779883 100644
--- a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/Activator.java
+++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/Activator.java
@@ -22,7 +22,6 @@
 import org.eclipse.jface.resource.ImageDescriptor;
 import org.eclipse.jface.resource.ImageRegistry;
 import org.eclipse.swt.graphics.Image;
-import org.eclipse.tracecompass.internal.tmf.ui.markers.ConfigurableMarkerEventSourceFactory;
 import org.eclipse.tracecompass.internal.tmf.ui.markers.LostEventsMarkerEventSourceFactory;
 import org.eclipse.tracecompass.internal.tmf.ui.perspectives.TmfPerspectiveManager;
 import org.eclipse.tracecompass.internal.tmf.ui.views.TmfAlignmentSynchronizer;
@@ -63,7 +62,6 @@
 
     private TmfEventAdapterFactory fTmfEventAdapterFactory;
     private LostEventsMarkerEventSourceFactory fLostEventMarkerEventSourceFactory;
-    private ConfigurableMarkerEventSourceFactory fConfigurableMarkerEventSourceFactory;
     private IPreferenceStore fCorePreferenceStore;
 
     // ------------------------------------------------------------------------
@@ -109,8 +107,6 @@
         Platform.getAdapterManager().registerAdapters(fTmfEventAdapterFactory, ITmfEvent.class);
         fLostEventMarkerEventSourceFactory = new LostEventsMarkerEventSourceFactory();
         TmfTraceAdapterManager.registerFactory(fLostEventMarkerEventSourceFactory, ITmfTrace.class);
-        fConfigurableMarkerEventSourceFactory = new ConfigurableMarkerEventSourceFactory();
-        TmfTraceAdapterManager.registerFactory(fConfigurableMarkerEventSourceFactory, ITmfTrace.class);
     }
 
     @Override
@@ -125,8 +121,6 @@
         Platform.getAdapterManager().unregisterAdapters(fTmfEventAdapterFactory);
         TmfTraceAdapterManager.unregisterFactory(fLostEventMarkerEventSourceFactory);
         fLostEventMarkerEventSourceFactory.dispose();
-        TmfTraceAdapterManager.unregisterFactory(fConfigurableMarkerEventSourceFactory);
-        fConfigurableMarkerEventSourceFactory.dispose();
         super.stop(context);
     }
 
diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/markers/ConfigurableMarkerEventSource.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/markers/ConfigurableMarkerEventSource.java
index 5cb0667..ba6f68d 100644
--- a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/markers/ConfigurableMarkerEventSource.java
+++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/internal/tmf/ui/markers/ConfigurableMarkerEventSource.java
@@ -17,59 +17,64 @@
 import static org.eclipse.tracecompass.common.core.NonNullUtils.checkNotNull;
 
 import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
 import java.util.Comparator;
-import java.util.HashMap;
+import java.util.IllegalFormatException;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
-import java.util.stream.Collectors;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
-import org.eclipse.core.runtime.IAdaptable;
 import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.NullProgressMonitor;
 import org.eclipse.jdt.annotation.NonNull;
-import org.eclipse.jdt.annotation.Nullable;
-import org.eclipse.swt.graphics.RGB;
 import org.eclipse.swt.graphics.RGBA;
-import org.eclipse.tracecompass.internal.tmf.core.markers.IMarkerConstants;
-import org.eclipse.tracecompass.internal.tmf.core.markers.Marker;
-import org.eclipse.tracecompass.internal.tmf.core.markers.Marker.PeriodicMarker;
+import org.eclipse.tracecompass.internal.provisional.tmf.core.model.annotations.Annotation;
+import org.eclipse.tracecompass.internal.provisional.tmf.core.model.annotations.AnnotationCategoriesModel;
+import org.eclipse.tracecompass.internal.provisional.tmf.core.model.annotations.AnnotationModel;
+import org.eclipse.tracecompass.internal.provisional.tmf.core.model.annotations.CustomAnnotationProvider;
+import org.eclipse.tracecompass.internal.provisional.tmf.core.model.annotations.IOutputAnnotationProvider;
+import org.eclipse.tracecompass.internal.provisional.tmf.core.model.annotations.PeriodicAnnotationSource;
 import org.eclipse.tracecompass.internal.tmf.core.markers.MarkerSegment;
 import org.eclipse.tracecompass.internal.tmf.core.markers.MarkerSet;
 import org.eclipse.tracecompass.internal.tmf.core.markers.SubMarker;
-import org.eclipse.tracecompass.internal.tmf.core.markers.SubMarker.SplitMarker;
 import org.eclipse.tracecompass.internal.tmf.core.markers.SubMarker.WeightedMarker;
+import org.eclipse.tracecompass.internal.tmf.core.model.filters.FetchParametersUtils;
+import org.eclipse.tracecompass.internal.tmf.ui.Activator;
+import org.eclipse.tracecompass.statesystem.core.StateSystemUtils;
+import org.eclipse.tracecompass.tmf.core.model.OutputElementStyle;
+import org.eclipse.tracecompass.tmf.core.model.StyleProperties;
+import org.eclipse.tracecompass.tmf.core.model.filters.TimeQueryFilter;
+import org.eclipse.tracecompass.tmf.core.presentation.RGBAColor;
+import org.eclipse.tracecompass.tmf.core.response.TmfModelResponse;
 import org.eclipse.tracecompass.tmf.core.signal.TmfMarkerEventSourceUpdatedSignal;
 import org.eclipse.tracecompass.tmf.core.signal.TmfSignalHandler;
 import org.eclipse.tracecompass.tmf.core.signal.TmfSignalManager;
 import org.eclipse.tracecompass.tmf.core.trace.AbstractTmfTraceAdapterFactory.IDisposableAdapter;
-import org.eclipse.tracecompass.tmf.core.trace.ICyclesConverter;
 import org.eclipse.tracecompass.tmf.core.trace.ITmfTrace;
-import org.eclipse.tracecompass.tmf.ui.colors.ColorUtils;
-import org.eclipse.tracecompass.tmf.ui.markers.IMarkerReferenceProvider;
-import org.eclipse.tracecompass.tmf.ui.markers.PeriodicMarkerEventSource;
-import org.eclipse.tracecompass.tmf.ui.markers.PeriodicMarkerEventSource.Reference;
+import org.eclipse.tracecompass.tmf.ui.colors.RGBAUtil;
+import org.eclipse.tracecompass.tmf.ui.model.StyleManager;
 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.IMarkerEvent;
 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.IMarkerEventSource;
 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.MarkerEvent;
 
 import com.google.common.collect.Lists;
-import com.google.common.collect.RangeSet;
 
 /**
  * Configurable marker event source.
  */
 public class ConfigurableMarkerEventSource implements IMarkerEventSource, IDisposableAdapter {
 
-    private static final long NANO_PER_MILLI = 1000000L;
-    private static final long NANO_PER_MICRO = 1000L;
     private static final int MIN_PERIOD = 5; // in units of resolution intervals
-    private static final int ALPHA = 10;
-    private static final String COLOR_REGEX = "#[A-Fa-f0-9]{6}"; //$NON-NLS-1$
+    private static final Pattern INDEX_EXTRACTOR = Pattern.compile("(%d+).*"); //$NON-NLS-1$
 
-    private List<IConfigurableMarkerEventSource> fMarkerEventSources;
-    private Map<Marker, RGBA> fColors = new HashMap<>();
     private final ITmfTrace fTrace;
+    private List<IConfigurableMarkerEventSource> fMarkerEventSources;
+    private CustomAnnotationProvider fProvider;
 
     /**
      * Constructor
@@ -78,8 +83,8 @@
      *            the trace
      */
     public ConfigurableMarkerEventSource(ITmfTrace trace) {
-        fMarkerEventSources = new ArrayList<>();
         fTrace = trace;
+        updateMarkerSet();
         TmfSignalManager.register(this);
     }
 
@@ -93,83 +98,117 @@
      *
      * @param markerSet
      *            the marker set, or null to clear the configuration
+     * @return The list of marker sources
      */
-    public void configure(MarkerSet markerSet) {
-        fMarkerEventSources.clear();
-        if (markerSet != null) {
-            for (Marker marker : markerSet.getMarkers()) {
-                configure(marker);
-            }
-        }
+    public List<IConfigurableMarkerEventSource> configure(MarkerSet markerSet) {
+        fProvider.configure(markerSet);
+        List<@NonNull IConfigurableMarkerEventSource> singletonList = Objects.requireNonNull(Collections.singletonList(new ConfigurableMarkerSource(fProvider)));
+        fMarkerEventSources = singletonList;
+        return singletonList;
     }
 
-    private void configure(Marker marker) {
-        if (marker instanceof PeriodicMarker) {
-            PeriodicMarker periodicMarker = (PeriodicMarker) marker;
-            String referenceId = periodicMarker.getReferenceId();
-            Reference baseReference = null;
-            if (fTrace instanceof IAdaptable && !referenceId.isEmpty()) {
-                @Nullable IMarkerReferenceProvider adapter = ((IAdaptable) fTrace).getAdapter(IMarkerReferenceProvider.class);
-                if (adapter != null) {
-                    baseReference = adapter.getReference(referenceId);
+    private class ConfigurableMarkerSource implements IConfigurableMarkerEventSource {
+
+        private final IOutputAnnotationProvider fAnnotationProvider;
+        private boolean fHasError = false;
+
+        public ConfigurableMarkerSource(IOutputAnnotationProvider provider) {
+            fAnnotationProvider = provider;
+        }
+
+        @Override
+        public @NonNull List<@NonNull String> getMarkerCategories() {
+            TimeQueryFilter timeQueryFilter = new TimeQueryFilter(0, Long.MAX_VALUE, 2);
+            List<@NonNull String> categories = new ArrayList<>();
+            Map<@NonNull String, @NonNull Object> fetchParameters = FetchParametersUtils.timeQueryToMap(timeQueryFilter);
+            TmfModelResponse<@NonNull AnnotationCategoriesModel> response = fAnnotationProvider.fetchAnnotationCategories(fetchParameters, new NullProgressMonitor());
+            AnnotationCategoriesModel model = response.getModel();
+            if (model != null) {
+                categories.addAll(model.getAnnotationCategories());
+            }
+            return categories;
+        }
+
+        @SuppressWarnings({"restriction"})
+        @Override
+        public @NonNull List<@NonNull IMarkerEvent> getMarkerList(@NonNull String category, long startTime, long endTime, long resolution, @NonNull IProgressMonitor monitor) {
+            if (startTime >= endTime) {
+                return Collections.emptyList();
+            }
+            TimeQueryFilter filter = new TimeQueryFilter(StateSystemUtils.getTimes(startTime, endTime, resolution));
+            TmfModelResponse<@NonNull AnnotationModel> response = fAnnotationProvider.fetchAnnotations(FetchParametersUtils.timeQueryToMap(filter), monitor);
+            AnnotationModel model = response.getModel();
+            if (model == null) {
+                return Collections.emptyList();
+            }
+            Map<@NonNull String, @NonNull Collection<@NonNull Annotation>> annotationsMap = model.getAnnotations();
+            List<@NonNull IMarkerEvent> markers = new ArrayList<>();
+            Collection<Annotation> collection = annotationsMap.get(category);
+            if (collection != null) {
+                StyleManager sm = StyleManager.empty();
+                for (Annotation annotation : collection) {
+                    OutputElementStyle style = annotation.getStyle();
+                    if (style != null) {
+                        String indexStr = annotation.getLabel();
+                        Matcher matcher = INDEX_EXTRACTOR.matcher(indexStr);
+                        long index = annotation.getStartTime();
+                        if (matcher.matches()) {
+                            index = Long.parseLong(matcher.group(1));
+                        }
+                        boolean isApplicable = true;
+                        String label = indexStr;
+                        if (fAnnotationProvider instanceof PeriodicAnnotationSource) {
+                            PeriodicAnnotationSource source = (PeriodicAnnotationSource) fAnnotationProvider;
+                            isApplicable = source.isApplicable(index);
+                            if (!fHasError) {
+                                try {
+                                    label = String.format(indexStr, source.getBaseIndex() + index);
+                                } catch (IllegalFormatException e) {
+                                    Activator.getDefault().logError("Cannot format label for periodic marker ", e); //$NON-NLS-1$
+                                    fHasError = true;
+                                }
+                            }
+                        }
+                        if (fAnnotationProvider instanceof CustomAnnotationProvider) {
+                            CustomAnnotationProvider customAnnotationProvider = (CustomAnnotationProvider) fAnnotationProvider;
+                            Map<String, String> formatters = customAnnotationProvider.getLabel();
+                            String format = formatters.get(category);
+                            if (!fHasError && format != null) {
+                                try {
+                                    long val = Long.decode(indexStr);
+                                    label = String.format(format, val);
+                                } catch (NumberFormatException | IllegalFormatException e) {
+                                    Activator.getDefault().logError("Cannot format label for custom marker ", e); //$NON-NLS-1$
+                                    fHasError = true;
+                                }
+                            }
+                        }
+                        if (isApplicable) {
+                            annotation = new Annotation(annotation.getTime(), annotation.getDuration(), annotation.getEntryId(), label, style);
+                            RGBAColor rgbaColor = sm.getColorStyle(style, StyleProperties.COLOR);
+                            if (rgbaColor != null) {
+                                RGBA color = RGBAUtil.fromRGBAColor(rgbaColor);
+                                // set to false for now
+                                MarkerEvent marker = new MarkerEvent(null, annotation.getTime(), annotation.getDuration(), category, color, label, false);
+                                markers.add(marker);
+                            }
+                        }
+                    }
                 }
             }
-            if (baseReference == null) {
-                baseReference = Reference.ZERO;
+
+            return markers;
+        }
+
+        @Override
+        public List<SubMarker> getSubMarkers() {
+            if (fAnnotationProvider instanceof PeriodicAnnotationSource) {
+                return ((PeriodicAnnotationSource) fAnnotationProvider).getMarker().getSubMarkers();
             }
-            long rollover = periodicMarker.getRange().hasUpperBound() ? (periodicMarker.getRange().upperEndpoint() - periodicMarker.getRange().lowerEndpoint() + 1) : 0;
-            RGBA evenColor = getColor(periodicMarker);
-            RGBA oddColor = getOddColor(evenColor);
-            double period = convertToNanos(periodicMarker.getPeriod(), periodicMarker.getUnit());
-            Reference reference = new Reference(baseReference.getTime() + Math.round(convertToNanos(periodicMarker.getOffset(), periodicMarker.getUnit())), baseReference.getIndex());
-            ConfigurablePeriodicMarkerEventSource markerEventSource = new ConfigurablePeriodicMarkerEventSource(marker, checkNotNull(periodicMarker.getName()), reference, period, rollover, evenColor, oddColor, false, periodicMarker.getRange().lowerEndpoint(), checkNotNull(periodicMarker.getLabel()), periodicMarker.getIndexRange());
-            fMarkerEventSources.add(markerEventSource);
+            return Collections.emptyList();
         }
     }
 
-    private double convertToNanos(double number, String unit) {
-        if (unit.equalsIgnoreCase(IMarkerConstants.MS)) {
-            return number * NANO_PER_MILLI;
-        } else if (unit.equalsIgnoreCase(IMarkerConstants.US)) {
-            return number * NANO_PER_MICRO;
-        } else if (unit.equalsIgnoreCase(IMarkerConstants.NS)) {
-            return number;
-        } else if (unit.equalsIgnoreCase(IMarkerConstants.CYCLES) &&
-                fTrace instanceof IAdaptable) {
-            ICyclesConverter adapter = ((IAdaptable) fTrace).getAdapter(ICyclesConverter.class);
-            if (adapter != null) {
-                return adapter.cyclesToNanos((long) number);
-            }
-        }
-        return number;
-    }
-
-    private @NonNull RGBA getColor(Marker marker) {
-        RGBA color = fColors.get(marker);
-        if (color == null) {
-            color = parseColor(marker.getColor());
-            fColors.put(marker, color);
-        }
-        return color;
-    }
-
-    private static @NonNull RGBA getOddColor(RGBA color) {
-        return new RGBA(color.rgb.red, color.rgb.green, color.rgb.blue, 0);
-    }
-
-    private static @NonNull RGBA parseColor(String color) {
-        RGB rgb = null;
-        if (color.matches(COLOR_REGEX)) {
-            rgb = ColorUtils.fromHexColor(color);
-        } else {
-            rgb = ColorUtils.fromX11Color(color);
-            if (rgb == null) {
-                rgb = new RGB(0, 0, 0);
-            }
-        }
-        return new RGBA(rgb.red, rgb.green, rgb.blue, ALPHA);
-    }
-
     @Override
     public List<String> getMarkerCategories() {
         Set<String> categories = new LinkedHashSet<>();
@@ -194,141 +233,40 @@
 
     @Override
     public List<IMarkerEvent> getMarkerList(String category, long startTime, long endTime, long resolution, IProgressMonitor monitor) {
-        return getMarkerList(startTime, endTime, resolution, monitor).stream()
-                .filter((marker) -> marker.getCategory().equals(category))
-                .collect(Collectors.toList());
-    }
-
-    @Override
-    public List<IMarkerEvent> getMarkerList(long startTime, long endTime, long resolution, IProgressMonitor monitor) {
-        @NonNull List<@NonNull IMarkerEvent> markerList = new ArrayList<>();
+        List<@NonNull IMarkerEvent> markerList = new ArrayList<>();
         for (IConfigurableMarkerEventSource source : fMarkerEventSources) {
             long minDuration = resolution * MIN_PERIOD;
-            if (source.getMaxDuration() > minDuration) {
-                @NonNull List<@NonNull IMarkerEvent> list = source.getMarkerList(startTime, endTime, resolution, monitor);
-                for (IMarkerEvent markerEvent : list) {
-                    for (SubMarker subMarker : source.getSubMarkers()) {
-                        getSubMarkerList(subMarker, markerEvent, markerList, startTime, endTime, minDuration);
-                    }
+            List<@NonNull IMarkerEvent> list = source.getMarkerList(category, startTime, endTime, resolution, monitor);
+            for (IMarkerEvent markerEvent : list) {
+                if (markerEvent.getDuration() > minDuration) {
                     markerList.add(markerEvent);
                 }
             }
         }
-        markerList.sort(Comparator.comparingLong(marker -> marker.getTime()));
+        markerList.sort(Comparator.comparingLong(IMarkerEvent::getTime));
         return markerList;
     }
 
-    private void getSubMarkerList(SubMarker subMarker, IMarkerEvent markerEvent, @NonNull List<@NonNull IMarkerEvent> markerList, long startTime, long endTime, long minDuration) {
-        if (subMarker instanceof SplitMarker) {
-            getSubMarkerList((SplitMarker) subMarker, markerEvent, markerList, startTime, endTime, minDuration);
-        } else if (subMarker instanceof WeightedMarker) {
-            getSubMarkerList((WeightedMarker) subMarker, markerEvent, markerList, startTime, endTime, minDuration);
-        }
-    }
-
-    private void getSubMarkerList(SplitMarker splitMarker, IMarkerEvent markerEvent, @NonNull List<@NonNull IMarkerEvent> markerList, long startTime, long endTime, long minDuration) {
-        if (markerEvent.getTime() > endTime || markerEvent.getTime() + markerEvent.getDuration() < startTime) {
-            return;
-        }
-        long lower = splitMarker.getRange().lowerEndpoint();
-        long upper = splitMarker.getRange().upperEndpoint();
-        long segments = upper - lower + 1;
-        long start = markerEvent.getTime();
-        for (int i = 0; i < segments; i++) {
-            long end = markerEvent.getTime() + Math.round((double) (i + 1) / segments * markerEvent.getDuration());
-            long duration = end - start;
-            long labelIndex = lower + i;
-            if (end >= startTime && duration > minDuration && splitMarker.getIndexRange().contains(labelIndex)) {
-                RGBA color = (labelIndex & 1) == 0 ? getColor(splitMarker) : getOddColor(getColor(splitMarker));
-                IMarkerEvent subMarkerEvent = new MarkerEvent(null, start, end - start, splitMarker.getName(), color, String.format(splitMarker.getLabel(), labelIndex), false);
-                for (SubMarker subMarker : splitMarker.getSubMarkers()) {
-                    getSubMarkerList(subMarker, subMarkerEvent, markerList, startTime, endTime, minDuration);
+    @Override
+    public List<IMarkerEvent> getMarkerList(long startTime, long endTime, long resolution, IProgressMonitor monitor) {
+        List<@NonNull IMarkerEvent> markerList = new ArrayList<>();
+        for (IConfigurableMarkerEventSource source : fMarkerEventSources) {
+            long minDuration = resolution * MIN_PERIOD;
+            List<@NonNull IMarkerEvent> list = source.getMarkerList(startTime, endTime, resolution, monitor);
+            for (IMarkerEvent markerEvent : list) {
+                if (markerEvent.getDuration() > minDuration) {
+                    markerList.add(markerEvent);
                 }
-                markerList.add(subMarkerEvent);
             }
-            if (start >= endTime) {
-                break;
-            }
-            start = end;
         }
-    }
-
-    private void getSubMarkerList(WeightedMarker weightedMarker, IMarkerEvent markerEvent, @NonNull List<@NonNull IMarkerEvent> markerList, long startTime, long endTime, long minDuration) {
-        if (markerEvent.getTime() > endTime || markerEvent.getTime() + markerEvent.getDuration() < startTime) {
-            return;
-        }
-        long start = markerEvent.getTime();
-        long length = 0;
-        for (int i = 0; i < weightedMarker.getSegments().size(); i++) {
-            MarkerSegment segment = weightedMarker.getSegments().get(i);
-            length += segment.getLength();
-            long end = markerEvent.getTime() + Math.round((length / (double) weightedMarker.getTotalLength()) * markerEvent.getDuration());
-            long duration = end - start;
-            if (end >= startTime && duration > minDuration && !segment.getColor().isEmpty()) {
-                RGBA color = getColor(segment);
-                IMarkerEvent subMarkerEvent = new MarkerEvent(null, start, end - start, weightedMarker.getName(), color, String.format(segment.getLabel(), i), false);
-                for (SubMarker subMarker : segment.getSubMarkers()) {
-                    getSubMarkerList(subMarker, subMarkerEvent, markerList, startTime, endTime, minDuration);
-                }
-                for (SubMarker subMarker : weightedMarker.getSubMarkers()) {
-                    getSubMarkerList(subMarker, subMarkerEvent, markerList, startTime, endTime, minDuration);
-                }
-                markerList.add(subMarkerEvent);
-            }
-            if (start >= endTime) {
-                break;
-            }
-            start = end;
-        }
+        markerList.sort(Comparator.comparingLong(IMarkerEvent::getTime));
+        return markerList;
     }
 
     private static interface IConfigurableMarkerEventSource extends IMarkerEventSource {
-        double getMaxDuration();
-
         public List<SubMarker> getSubMarkers();
     }
 
-    private class ConfigurablePeriodicMarkerEventSource extends PeriodicMarkerEventSource implements IConfigurableMarkerEventSource {
-
-        private final Marker fMarker;
-        private final long fStartIndex;
-        private final String fLabel;
-        private final RangeSet<Long> fIndexRange;
-        private final double fMaxDuration;
-
-        public ConfigurablePeriodicMarkerEventSource(Marker marker, @NonNull String category, @NonNull Reference reference, double period, long rollover, @NonNull RGBA evenColor, @NonNull RGBA oddColor, boolean foreground, long startIndex, @NonNull String label, RangeSet<Long> indexRange) {
-            super(category, reference, period, rollover, evenColor, oddColor, foreground);
-            fMarker = marker;
-            fStartIndex = startIndex;
-            fLabel = label;
-            fIndexRange = indexRange;
-            fMaxDuration = period;
-        }
-
-        @Override
-        public @NonNull String getMarkerLabel(long index) {
-            return checkNotNull(String.format(fLabel, fStartIndex + index));
-        }
-
-        @Override
-        public boolean isApplicable(long index) {
-            if (fIndexRange != null) {
-                return fIndexRange.contains(fStartIndex + index);
-            }
-            return true;
-        }
-
-        @Override
-        public double getMaxDuration() {
-            return fMaxDuration;
-        }
-
-        @Override
-        public List<SubMarker> getSubMarkers() {
-            return fMarker.getSubMarkers();
-        }
-    }
-
     /**
      * A marker event source has been updated
      *
@@ -337,6 +275,12 @@
      */
     @TmfSignalHandler
     public void markerEventSourceUpdated(final TmfMarkerEventSourceUpdatedSignal signal) {
-        configure(MarkerUtils.getDefaultMarkerSet());
+        updateMarkerSet();
+    }
+
+    private final void updateMarkerSet() {
+        MarkerSet defaultMarkerSet = MarkerUtils.getDefaultMarkerSet();
+        fProvider = new CustomAnnotationProvider(Objects.requireNonNull(fTrace), defaultMarkerSet);
+        fMarkerEventSources = configure(defaultMarkerSet);
     }
 }
diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/markers/IMarkerReferenceProvider.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/markers/IMarkerReferenceProvider.java
index ad05af2..2636a8b 100644
--- a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/markers/IMarkerReferenceProvider.java
+++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/markers/IMarkerReferenceProvider.java
@@ -14,6 +14,7 @@
 
 package org.eclipse.tracecompass.tmf.ui.markers;
 
+import org.eclipse.tracecompass.tmf.core.markers.ITimeReference;
 import org.eclipse.tracecompass.tmf.ui.markers.PeriodicMarkerEventSource.Reference;
 
 /**
@@ -21,8 +22,10 @@
  * reference for periodic markers.
  *
  * @since 3.0
+ * @deprecated, use {@link org.eclipse.tracecompass.tmf.core.markers.ITimeReferenceProvider} instead
  */
-public interface IMarkerReferenceProvider {
+@Deprecated
+public interface IMarkerReferenceProvider extends org.eclipse.tracecompass.tmf.core.markers.ITimeReferenceProvider {
 
     /**
      * Get the reference for the specified reference id
@@ -32,4 +35,12 @@
      * @return a reference
      */
     Reference getReference(String referenceId);
+
+    /**
+     * @since 7.0
+     */
+    @Override
+    default ITimeReference apply(String referenceId) {
+        return getReference(referenceId);
+    }
 }
diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/markers/PeriodicMarkerEventSource.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/markers/PeriodicMarkerEventSource.java
index 6eca973..ffafc35 100644
--- a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/markers/PeriodicMarkerEventSource.java
+++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/markers/PeriodicMarkerEventSource.java
@@ -18,14 +18,29 @@
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collection;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
+import java.util.Objects;
 
-import org.apache.commons.lang3.math.Fraction;
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.jdt.annotation.NonNullByDefault;
 import org.eclipse.jdt.annotation.Nullable;
 import org.eclipse.swt.graphics.RGBA;
+import org.eclipse.tracecompass.internal.provisional.tmf.core.model.annotations.Annotation;
+import org.eclipse.tracecompass.internal.provisional.tmf.core.model.annotations.AnnotationModel;
+import org.eclipse.tracecompass.internal.provisional.tmf.core.model.annotations.PeriodicAnnotationSource;
+import org.eclipse.tracecompass.statesystem.core.StateSystemUtils;
+import org.eclipse.tracecompass.tmf.core.dataprovider.DataProviderParameterUtils;
+import org.eclipse.tracecompass.tmf.core.markers.ITimeReference;
+import org.eclipse.tracecompass.tmf.core.model.OutputElementStyle;
+import org.eclipse.tracecompass.tmf.core.model.StyleProperties;
+import org.eclipse.tracecompass.tmf.core.presentation.RGBAColor;
+import org.eclipse.tracecompass.tmf.core.response.TmfModelResponse;
+import org.eclipse.tracecompass.tmf.ui.colors.RGBAUtil;
+import org.eclipse.tracecompass.tmf.ui.model.StyleManager;
 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.IMarkerEvent;
 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.IMarkerEventSource;
 import org.eclipse.tracecompass.tmf.ui.widgets.timegraph.model.MarkerEvent;
@@ -41,7 +56,7 @@
     /**
      * Reference marker time and index
      */
-    public static class Reference {
+    public static class Reference implements ITimeReference {
 
         /** Reference marker index 0 at time 0 */
         public static final Reference ZERO = new Reference(0L, 0);
@@ -76,22 +91,12 @@
             this.index = index;
         }
 
-        /**
-         * Gets the reference marker time.
-         *
-         * @return the reference marker time
-         * @since 3.0
-         */
+        @Override
         public long getTime() {
             return time;
         }
 
-        /**
-         * Gets the reference marker index.
-         *
-         * @return the reference marker index
-         * @since 3.0
-         */
+        @Override
         public long getIndex() {
             return index;
         }
@@ -103,14 +108,8 @@
     }
 
     private final String fCategory;
-    private final Reference fReference;
-    private final double fPeriod;
-    private final long fPeriodInteger;
-    private @Nullable Fraction fPeriodFraction;
-    private final long fRollover;
-    private final RGBA fColor1;
-    private final @Nullable RGBA fColor2;
     private final boolean fForeground;
+    private final PeriodicAnnotationSource fSource;
 
     /**
      * Constructs a periodic marker event source with line markers at period
@@ -144,8 +143,8 @@
      * The markers will have the given category. Periods will be shaded with the
      * first and second colors alternatively. The reference defines the marker
      * with the given index to be at the specified time. The reference will be
-     * shaded with the first color if its index is even, or the second color
-     * if it is odd.
+     * shaded with the first color if its index is even, or the second color if
+     * it is odd.
      *
      * @param category
      *            the marker category
@@ -167,7 +166,10 @@
         this(category, reference, period, rollover, foreground, color1, color2);
     }
 
-    /* Private constructor. The order of parameters is changed to make it unique. */
+    /*
+     * Private constructor. The order of parameters is changed to make it
+     * unique.
+     */
     private PeriodicMarkerEventSource(String category, Reference reference, double period, long rollover, boolean foreground, RGBA color1, @Nullable RGBA color2) {
         if (period <= 0) {
             throw new IllegalArgumentException("period cannot be less than or equal to zero"); //$NON-NLS-1$
@@ -175,22 +177,18 @@
         if (rollover < 0) {
             throw new IllegalArgumentException("rollover cannot be less than zero"); //$NON-NLS-1$
         }
+        fSource = new PeriodicAnnotationSource(category, reference.getIndex(), reference.getTime(), period, rollover, Objects.requireNonNull(wrap(color1)), wrap(color2));
         fCategory = category;
-        fReference = reference;
-        fPeriod = period;
-        fPeriodInteger = (long) period;
-        try {
-            fPeriodFraction = Fraction.getFraction(fPeriod - fPeriodInteger);
-        } catch (ArithmeticException e) {
-            /* can't convert to fraction, use floating-point arithmetic */
-            fPeriodFraction = null;
-        }
-        fRollover = rollover;
-        fColor1 = color1;
-        fColor2 = color2;
         fForeground = foreground;
     }
 
+    private static @Nullable RGBAColor wrap(@Nullable RGBA rgba) {
+        if (rgba == null) {
+            return null;
+        }
+        return new RGBAColor(rgba.rgb.red, rgba.rgb.green, rgba.rgb.blue, rgba.alpha);
+    }
+
     @Override
     public List<String> getMarkerCategories() {
         return Arrays.asList(fCategory);
@@ -201,71 +199,45 @@
         if (startTime > endTime) {
             return Collections.emptyList();
         }
+        StyleManager sm = StyleManager.empty();
         List<IMarkerEvent> markers = new ArrayList<>();
-        /* Subtract 1.5 periods to ensure previous marker is included */
-        long time = startTime - Math.max(Math.round(1.5 * fPeriod), resolution);
-        Reference reference = adjustReference(fReference, time);
-        IMarkerEvent markerEvent = null;
-        while (true) {
-            long index = Math.round((time - reference.time) / fPeriod) + reference.index;
-            long markerTime = Math.round((index - reference.index) * fPeriod) + reference.time;
-            long duration = (fColor2 == null) ? 0 : Math.round((index + 1 - reference.index) * fPeriod) + reference.time - markerTime;
-            long labelIndex = index;
-            if (fRollover != 0) {
-                labelIndex %= fRollover;
-                if (labelIndex < 0) {
-                    labelIndex += fRollover;
+        if (resolution >= Integer.MAX_VALUE) {
+            throw new IllegalArgumentException("Cannot query " + resolution + " times"); //$NON-NLS-1$ //$NON-NLS-2$
+        }
+        List<Long> times = StateSystemUtils.getTimes(startTime, endTime, resolution);
+        Map<String, Object> query = new HashMap<>();
+        query.put(DataProviderParameterUtils.REQUESTED_TIME_KEY, times);
+        query.put(DataProviderParameterUtils.REQUESTED_MARKER_CATEGORIES_KEY, Collections.singleton(category));
+        TmfModelResponse<AnnotationModel> annotations = fSource.fetchAnnotations(query, monitor);
+        AnnotationModel model = annotations.getModel();
+        if (model == null) {
+            return markers;
+        }
+        Map<String, Collection<Annotation>> annotationsMap = model.getAnnotations();
+
+        Collection<Annotation> collection = annotationsMap.get(category);
+        if (collection != null) {
+            for (Annotation annotation : collection) {
+                OutputElementStyle style = annotation.getStyle();
+                if (style != null) {
+                    String indexStr = annotation.getLabel();
+                    long index = Long.parseLong(indexStr);
+                    if (isApplicable(index)) {
+                        String label = getMarkerLabel(index);
+                        annotation = new Annotation(annotation.getTime(), annotation.getDuration(), annotation.getEntryId(), label, style);
+                        RGBAColor rgbaColor = sm.getColorStyle(style, StyleProperties.COLOR);
+                        if (rgbaColor != null) {
+                            RGBA color = RGBAUtil.fromRGBAColor(rgbaColor);
+                            MarkerEvent marker = new MarkerEvent(null, annotation.getTime(), annotation.getDuration(), category, color, label, fForeground);
+                            markers.add(marker);
+                        }
+                    }
                 }
             }
-            /* Add previous marker if current is visible */
-            if ((markerTime >= startTime || markerTime + duration > startTime) && markerEvent != null) {
-                markers.add(markerEvent);
-            }
-            if (isApplicable(labelIndex)) {
-                RGBA color = (fColor2 == null) ? fColor1 : (index % 2 == 0) ? fColor1 : fColor2;
-                markerEvent = new MarkerEvent(null, markerTime, duration, fCategory, color, getMarkerLabel(labelIndex), fForeground);
-            } else {
-                markerEvent = null;
-            }
-            if (markerTime > endTime) {
-                if (markerEvent != null) {
-                    /* The next marker out of range is included */
-                    markers.add(markerEvent);
-                }
-                break;
-            }
-            time += Math.max(Math.round(fPeriod), resolution);
         }
         return markers;
     }
 
-    /*
-     * Adjust to a reference that is closer to the start time, to avoid rounding
-     * errors in floating point calculations with large numbers.
-     */
-    private Reference adjustReference(Reference baseReference, long time) {
-        long offsetIndex = (long) ((time - baseReference.time) / fPeriod);
-        long offsetTime = 0;
-        Fraction fraction = fPeriodFraction;
-        if (fraction != null) {
-            /*
-             * If period = int num/den, find an offset index that is an exact
-             * multiple of den and calculate index * period = (index * int) +
-             * (index / den * num), all exact calculations.
-             */
-            offsetIndex = offsetIndex - offsetIndex % fraction.getDenominator();
-            offsetTime = offsetIndex * fPeriodInteger + offsetIndex / fraction.getDenominator() * fraction.getNumerator();
-        } else {
-            /*
-             * Couldn't compute fractional part as fraction, use simple
-             * multiplication but with possible rounding error.
-             */
-            offsetTime = Math.round(offsetIndex * fPeriod);
-        }
-        Reference reference = new Reference(baseReference.time + offsetTime, baseReference.index + offsetIndex);
-        return reference;
-    }
-
     /**
      * Get the marker label for the given marker index.
      * <p>
@@ -285,6 +257,9 @@
      * This method can be overridden by clients. Returning false will
      * essentially filter-out the marker.
      *
+     * @apiNote not used as far as we know, this API is not good for moving
+     *          logic to core.
+     *
      * @param index
      *            the marker index
      * @return true if the marker is applicable
diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/timegraph/AbstractTimeGraphView.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/timegraph/AbstractTimeGraphView.java
index b0a3108..dbd6ee4 100644
--- a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/timegraph/AbstractTimeGraphView.java
+++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/timegraph/AbstractTimeGraphView.java
@@ -103,6 +103,11 @@
 import org.eclipse.tracecompass.common.core.log.TraceCompassLogUtils;
 import org.eclipse.tracecompass.common.core.log.TraceCompassLogUtils.FlowScopeLog;
 import org.eclipse.tracecompass.common.core.log.TraceCompassLogUtils.FlowScopeLogBuilder;
+import org.eclipse.tracecompass.internal.provisional.tmf.core.model.annotations.Annotation;
+import org.eclipse.tracecompass.internal.provisional.tmf.core.model.annotations.AnnotationCategoriesModel;
+import org.eclipse.tracecompass.internal.provisional.tmf.core.model.annotations.AnnotationModel;
+import org.eclipse.tracecompass.internal.provisional.tmf.core.model.annotations.IAnnotation.AnnotationType;
+import org.eclipse.tracecompass.internal.provisional.tmf.core.model.annotations.IOutputAnnotationProvider;
 import org.eclipse.tracecompass.internal.provisional.tmf.core.model.filter.parser.FilterCu;
 import org.eclipse.tracecompass.internal.provisional.tmf.core.model.filter.parser.IFilterStrings;
 import org.eclipse.tracecompass.internal.provisional.tmf.core.model.filters.TmfFilterAppliedSignal;
@@ -118,9 +123,12 @@
 import org.eclipse.tracecompass.internal.tmf.ui.views.ITmfTimeZoomProvider;
 import org.eclipse.tracecompass.internal.tmf.ui.views.ITmfZoomToSelectionProvider;
 import org.eclipse.tracecompass.internal.tmf.ui.views.timegraph.TimeEventFilterDialog;
+import org.eclipse.tracecompass.statesystem.core.StateSystemUtils;
+import org.eclipse.tracecompass.tmf.core.dataprovider.DataProviderParameterUtils;
 import org.eclipse.tracecompass.tmf.core.model.CoreFilterProperty;
 import org.eclipse.tracecompass.tmf.core.model.timegraph.IElementResolver;
 import org.eclipse.tracecompass.tmf.core.resources.ITmfMarker;
+import org.eclipse.tracecompass.tmf.core.response.TmfModelResponse;
 import org.eclipse.tracecompass.tmf.core.signal.TmfDataModelSelectedSignal;
 import org.eclipse.tracecompass.tmf.core.signal.TmfMarkerEventSourceUpdatedSignal;
 import org.eclipse.tracecompass.tmf.core.signal.TmfSelectionRangeUpdatedSignal;
@@ -219,6 +227,61 @@
 
     private static final String HIDE_LABELS_KEY = "hide.labels"; //$NON-NLS-1$
 
+    private final class AnnotationMarkerEventSource implements IMarkerEventSource {
+        IOutputAnnotationProvider fProvider;
+
+        private AnnotationMarkerEventSource(IOutputAnnotationProvider ap) {
+            fProvider = ap;
+        }
+
+        @Override
+        public @NonNull List<@NonNull IMarkerEvent> getMarkerList(@NonNull String category, long startTime, long endTime, long resolution, @NonNull IProgressMonitor monitor) {
+
+            Map<@NonNull String, @NonNull Object> parameters = new HashMap<>();
+            MarkerSet defaultMarkerSet = MarkerUtils.getDefaultMarkerSet();
+            if (defaultMarkerSet != null) {
+                parameters.put(DataProviderParameterUtils.REQUESTED_MARKER_SET_KEY, defaultMarkerSet.getId());
+            }
+            parameters.put(DataProviderParameterUtils.REQUESTED_TRACE_KEY, fTrace.getHostId());
+            parameters.put(DataProviderParameterUtils.REQUESTED_TIME_KEY, StateSystemUtils.getTimes(startTime, endTime, resolution));
+            TmfModelResponse<@NonNull AnnotationModel> response = fProvider.fetchAnnotations(parameters, new NullProgressMonitor());
+            AnnotationModel model = response.getModel();
+            List<@NonNull IMarkerEvent> traceMarkerList = new ArrayList<>();
+            if (model != null) {
+                for (Entry<String, Collection<Annotation>> entry : model.getAnnotations().entrySet()) {
+                    for (Annotation annotation : entry.getValue()) {
+                        if (annotation.getType() == AnnotationType.CHART) {
+                            if (annotation.getEntryId() != -1) {
+                                Activator.getDefault().logWarning("Requesting an annotation with a bound entry. request : " + parameters + ", provider : " + fProvider.getClass().getName() + " annotation: " + annotation); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+                            }
+                            // If the annotation entry ID is -1 we want the
+                            // marker to span across all entries
+                            MarkerEvent markerEvent = new MarkerEvent(annotation, null, entry.getKey(), true);
+                            traceMarkerList.add(markerEvent);
+                        }
+                    }
+                }
+            }
+            return traceMarkerList;
+        }
+
+        @Override
+        public @NonNull List<@NonNull String> getMarkerCategories() {
+            Map<@NonNull String, @NonNull Object> parameters = new HashMap<>();
+            MarkerSet defaultMarkerSet = MarkerUtils.getDefaultMarkerSet();
+            if (defaultMarkerSet != null) {
+                parameters.put(DataProviderParameterUtils.REQUESTED_MARKER_SET_KEY, defaultMarkerSet.getId());
+            }
+            parameters.put(DataProviderParameterUtils.REQUESTED_TRACE_KEY, fTrace.getHostId());
+            TmfModelResponse<@NonNull AnnotationCategoriesModel> cats = fProvider.fetchAnnotationCategories(parameters, new NullProgressMonitor());
+            AnnotationCategoriesModel model = cats.getModel();
+            if (model != null) {
+                return model.getAnnotationCategories();
+            }
+            return Collections.emptyList();
+        }
+    }
+
     /**
      * Redraw state enum
      */
@@ -1854,7 +1917,11 @@
                         break;
                     }
                     List<@NonNull IMarkerEventSource> adapters = TmfTraceAdapterManager.getAdapters(trace, IMarkerEventSource.class);
+                    List<@NonNull IOutputAnnotationProvider> providers = TmfTraceAdapterManager.getAdapters(trace, IOutputAnnotationProvider.class);
                     markerEventSources.addAll(adapters);
+                    for (IOutputAnnotationProvider ap : providers) {
+                        markerEventSources.add(new AnnotationMarkerEventSource(ap));
+                    }
 
                     Job buildJob = new Job(getTitle() + Messages.AbstractTimeGraphView_BuildJob) {
                         @Override
diff --git a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/timegraph/BaseDataProviderTimeGraphView.java b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/timegraph/BaseDataProviderTimeGraphView.java
index 1e8e380..460be3f 100644
--- a/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/timegraph/BaseDataProviderTimeGraphView.java
+++ b/tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/timegraph/BaseDataProviderTimeGraphView.java
@@ -44,7 +44,9 @@
 import org.eclipse.tracecompass.internal.provisional.tmf.core.model.annotations.IOutputAnnotationProvider;
 import org.eclipse.tracecompass.internal.provisional.tmf.ui.widgets.ViewFilterDialog;
 import org.eclipse.tracecompass.internal.provisional.tmf.ui.widgets.timegraph.BaseDataProviderTimeGraphPresentationProvider;
+import org.eclipse.tracecompass.internal.tmf.core.markers.MarkerSet;
 import org.eclipse.tracecompass.internal.tmf.ui.Activator;
+import org.eclipse.tracecompass.internal.tmf.ui.markers.MarkerUtils;
 import org.eclipse.tracecompass.internal.tmf.ui.views.timegraph.Messages;
 import org.eclipse.tracecompass.statesystem.core.StateSystemUtils;
 import org.eclipse.tracecompass.tmf.core.TmfStrings;
@@ -437,7 +439,7 @@
             if (zoomStartTime <= entry.getEndTime() && zoomEndTime >= entry.getStartTime() && entry.hasTimeEvents()) {
                 synchronized (fEntries) {
                     if (!fEntryIds.isEmpty()) {
-                        fEntryIds.row(entry).forEach((provider, modelId) -> providersToModelIds.put(provider, modelId));
+                        fEntryIds.row(entry).forEach(providersToModelIds::put);
                     } else {
                         ITimeGraphDataProvider<? extends TimeGraphEntryModel> provider = getProvider(entry);
                         if (provider != null) {
@@ -706,7 +708,20 @@
      * @since 5.2
      */
     protected @NonNull Map<@NonNull String, @NonNull Object> getFetchAnnotationCategoriesParameters() {
-        return new HashMap<>();
+        HashMap<@NonNull String, @NonNull Object> categoriesParameters = new HashMap<>();
+        putMarkerSetParameters(categoriesParameters, getTrace());
+        return categoriesParameters;
+    }
+
+    private static void putMarkerSetParameters(Map<@NonNull String, @NonNull Object> parameters, ITmfTrace trace) {
+        MarkerSet markerSet = MarkerUtils.getDefaultMarkerSet();
+        if (markerSet != null) {
+            String markerSetID = markerSet.getId();
+            if (markerSetID != null) {
+                parameters.put(DataProviderParameterUtils.REQUESTED_MARKER_SET_KEY, markerSetID);
+                parameters.put(DataProviderParameterUtils.REQUESTED_TRACE_KEY, trace.getHostId());
+            }
+        }
     }
 
     /**
@@ -720,9 +735,10 @@
      * @since 5.2
      */
     protected @NonNull Map<@NonNull String, @NonNull Object> getFetchAnnotationsParameters(@NonNull List<Long> times, @NonNull Collection<Long> items) {
-        @NonNull Map<@NonNull String, @NonNull Object> parameters = new HashMap<>();
+        Map<@NonNull String, @NonNull Object> parameters = new HashMap<>();
         parameters.put(DataProviderParameterUtils.REQUESTED_TIME_KEY, times);
         parameters.put(DataProviderParameterUtils.REQUESTED_ITEMS_KEY, items);
+        putMarkerSetParameters(parameters, getTrace());
         return parameters;
     }