diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
index 76cfb3487d71bedba057afd008efa24e2576bf24..d4744fce4687fdc1750ded1726dc587cb538ab0b 100644
--- a/CONTRIBUTORS.md
+++ b/CONTRIBUTORS.md
@@ -46,6 +46,7 @@ It is likely incomplete...
 - Victor Olesen
 - Evangelos Papoutsis-Kiachagias
 - Juho Peltola
+- Josep Pocurull
 - Johan Roenby
 - Henrik Rusche
 - Bruno Santos
diff --git a/src/OpenFOAM/Make/options b/src/OpenFOAM/Make/options
index a214db6653f3413c162052c319ac739514294bd5..14c87912a7c98edc51c46ed618f63642fa15ba86 100644
--- a/src/OpenFOAM/Make/options
+++ b/src/OpenFOAM/Make/options
@@ -10,6 +10,12 @@ ifeq (,$(findstring ~libz,$(WM_COMPILE_CONTROL)))
     LIB_LIBS += -lz
 endif
 
+/* extrae profiling hooks [https://tools.bsc.es/extrae] */
+ifeq (,$(findstring windows,$(WM_OSTYPE)))
+ifeq (,$(findstring ~extrae,$(WM_COMPILE_CONTROL)))
+    EXE_INC  += -DHAVE_EXTRAE
+endif
+endif
 
 /* Never self-link (WM_PROJECT == OpenFOAM), but do link to Pstream */
 
diff --git a/src/OpenFOAM/global/profiling/profilingTrigger.C b/src/OpenFOAM/global/profiling/profilingTrigger.C
index 341baae0a83edd1b67da4333febf4dffe7299d80..95d6fadc63f033777b4f8fee878cf757dcc41a43 100644
--- a/src/OpenFOAM/global/profiling/profilingTrigger.C
+++ b/src/OpenFOAM/global/profiling/profilingTrigger.C
@@ -7,6 +7,7 @@
 -------------------------------------------------------------------------------
     Copyright (C) 2009-2016 Bernhard Gschaider
     Copyright (C) 2016-2023 OpenCFD Ltd.
+    Copyright (C) 2023 Josep Pocurull Serra, Barcelona Supercomputing Center
 -------------------------------------------------------------------------------
 License
     This file is part of OpenFOAM.
@@ -30,6 +31,115 @@ License
 #include "profilingTrigger.H"
 #include "profilingInformation.H"
 
+// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
+
+// Extrae profiling hooks
+// ----------------------
+// https://tools.bsc.es/extrae
+// ----------------------
+
+#ifdef HAVE_EXTRAE
+#include <map>
+#include <utility>
+
+// Weak functions for Extrae C api
+extern "C"
+{
+    typedef unsigned extrae_type_t;
+    typedef unsigned long long extrae_value_t;
+
+    // Adds to the Paraver Configuration File human readable information
+    // regarding type and its values.
+    void Extrae_define_event_type
+    (
+        extrae_type_t *type,
+        char *type_description,
+        unsigned *nvalues,
+        extrae_value_t *values,
+        char **values_description
+    ) __attribute__((weak));
+
+    // Adds a single timestamped event into the tracefile
+    void Extrae_event
+    (
+        extrae_type_t type,
+        extrae_value_t value
+    ) __attribute__((weak));
+
+}  // End extern "C"
+
+
+// Descriptor for the events
+static char myExtrae_description[] = "OpenFOAM Extrae Profiling";
+
+static void open_extrae_region(const std::string& name)
+{
+    // Event history (by name) of profiling triggers
+    static std::map<std::string, extrae_value_t> event_history;
+
+    // Scratch space for transcribing map -> flat lists
+    static Foam::DynamicList<char*> eventNames;
+    static Foam::DynamicList<extrae_value_t> eventValues;
+
+
+    if (event_history.empty())
+    {
+        event_history.insert(std::make_pair("End", 0));
+    }
+
+    extrae_type_t event_type = 7000;
+    extrae_value_t event_name;
+
+    // Check if there is already an event with that name
+    auto iter = event_history.find(name);
+    if (iter != event_history.end())
+    {
+        event_name = iter->second;
+    }
+    else
+    {
+        // Update extrae defined events
+
+        event_name = static_cast<extrae_value_t>(event_history.size());
+        event_history.insert(std::make_pair(name, event_name));
+
+        unsigned numEvents = event_history.size();
+
+        const Foam::label len(numEvents);
+
+        eventNames.resize_nocopy(len);
+        eventValues.resize_nocopy(len);
+
+        Foam::label i = 0;
+        for (const auto& iter : event_history)
+        {
+            eventNames[i]  = const_cast<char*>(iter.first.data());
+            eventValues[i] = iter.second;
+            ++i;
+        }
+
+        Extrae_define_event_type
+        (
+            &event_type,
+            myExtrae_description,
+            &numEvents,
+            eventValues.data(),
+            eventNames.data()
+        );
+    }
+
+    Extrae_event(event_type, event_name);
+}
+
+
+static void close_extrae_region()
+{
+    Extrae_event(7000, 0);
+}
+
+#endif  /* HAVE_EXTRAE */
+
+
 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
 
 Foam::profilingTrigger::profilingTrigger() noexcept
@@ -48,6 +158,9 @@ Foam::profilingTrigger::profilingTrigger(const std::string& name)
 :
     ptr_(profiling::New(name))
 {
+    #ifdef HAVE_EXTRAE
+    if (Extrae_event) open_extrae_region(std::string(name));
+    #endif
 }
 
 
@@ -69,6 +182,10 @@ bool Foam::profilingTrigger::running() const noexcept
 
 void Foam::profilingTrigger::stop()
 {
+    #ifdef HAVE_EXTRAE
+    if (Extrae_event) close_extrae_region();
+    #endif
+
     if (ptr_)
     {
         // profiling info pointer managed by pool storage, so no delete here