From 8e75cccbe68c769a673f30c6444db15e4d01249d Mon Sep 17 00:00:00 2001
From: Lizzzka007 <gashchuk2011@mail.ru>
Date: Fri, 6 Jan 2023 23:58:25 +0300
Subject: [PATCH] Refactored Jikan timer: pre-alpha

---
 Event.cpp            | 114 ++++++++++++++++++-
 Event.cu             |  27 +++++
 Event.h              |  14 ++-
 Jikan copy.cpp       | 255 +++++++++++++++++++++++++++++++++++++++++
 Jikan copy.h         | 119 +++++++++++++++++++
 Jikan.cpp            | 234 ++------------------------------------
 Jikan.cu             |  93 ---------------
 Jikan.h              | 115 ++++---------------
 JikanDepths copy.cpp | 264 +++++++++++++++++++++++++++++++++++++++++++
 JikanDepths.cpp      | 258 +++++++++++++++++++++++++++++-------------
 JikanDepths.cu       |  36 ++++++
 JikanDepths.h        |  22 ++--
 ToJSON.cpp           |   4 +-
 13 files changed, 1045 insertions(+), 510 deletions(-)
 create mode 100644 Event.cu
 create mode 100644 Jikan copy.cpp
 create mode 100644 Jikan copy.h
 delete mode 100644 Jikan.cu
 create mode 100644 JikanDepths copy.cpp
 create mode 100644 JikanDepths.cu

diff --git a/Event.cpp b/Event.cpp
index 69fb79b..48748d7 100644
--- a/Event.cpp
+++ b/Event.cpp
@@ -1,33 +1,88 @@
+#include <iostream>
+
+#ifdef INCLUDE_OPEN_MP
+    #include <omp.h>
+#endif
+
 #include "Event.h"
-#include "Jikan-config.h"
+#include "Jikan.h"
 
 using namespace std;
 
-EventData::EventData(){}
+EventData::EventData()
+{
+    this->double_start = 0.0;
+    this->start = chrono::steady_clock::now();
+    this->elapsed_time = 0.0; 
+    this->count = 0;
+    this->ifCUDA = 0;
+    this->event_name = "Unnamed";
+    this->ifStart = false, this->ifEnd = false;
+    this->if_mode_set = false;
+
+    this->time_series = vector<double>();
+    this->mode = vector<bool>();
+    
+    #ifdef INCLUDE_GPU_TIMER
+        this->InitEventsCUDA();
+    #else
+        this->ifCUDAinit = false;
+    #endif
+}
 
 EventData::~EventData()
 {
-    this->time_series.clear();
+    #pragma omp master
+    {
+        this->time_series.clear();
+        this->mode.clear();
+
+        #ifdef INCLUDE_GPU_TIMER
+            this->DeinitEventsCUDA();
+        #endif
+    }
 }
 
 EventData::EventData(const string& name)
 {
+    this->double_start = 0.0;
     this->start = chrono::steady_clock::now();
     this->elapsed_time = 0.0; 
     this->count = 0;
     this->ifCUDA = 0;
     this->event_name = name;
     this->ifStart = false, this->ifEnd = false;
+    this->if_mode_set = false;
+
+    this->time_series = vector<double>();
+    this->mode = vector<bool>();
+
+    #ifdef INCLUDE_GPU_TIMER
+        this->InitEventsCUDA();
+    #else
+        this->ifCUDAinit = false;
+    #endif
 }
 
 EventData& EventData::operator=(const EventData& src)
 {
+    this->double_start = src.double_start;
     this->start = src.start;
     this->elapsed_time = 0.0; 
     this->count = 0;
     this->ifCUDA = 0;
     this->event_name = src.event_name;
     this->ifStart = false, this->ifEnd = false;
+    this->if_mode_set = src.if_mode_set;
+    this->ifCUDAinit = src.ifCUDAinit;
+
+    this->time_series = src.time_series;
+    this->mode = src.mode;
+
+    #ifdef INCLUDE_GPU_TIMER
+        this->gpu_start = src.gpu_start;
+        this->gpu_end   = src.gpu_end;
+    #endif
 
     return *this;
 }
@@ -36,3 +91,56 @@ double EventData::GetMeanElapsedTime()
 {
     return this->elapsed_time / this->count;
 }
+
+void EventData::GetModeVals(const int& mode)
+{   
+    if((mode == TimerMode::MPI_mode)    || (mode == TimerMode::MPI_OpenMP) || (mode == TimerMode::MPI_CUDA)    || (mode == TimerMode::MPI_OpenMP_CUDA))
+        this->mode.push_back(true);
+    else
+        this->mode.push_back(false);
+
+    if((mode == TimerMode::OpenMP_mode) || (mode == TimerMode::MPI_OpenMP) || (mode == TimerMode::OpenMP_CUDA) || (mode == TimerMode::MPI_OpenMP_CUDA))
+        this->mode.push_back(true);
+    else
+        this->mode.push_back(false);
+
+    this->if_mode_set = true;
+    
+    if((mode == TimerMode::CUDA_mode)   || (mode == TimerMode::MPI_CUDA)   || (mode == TimerMode::OpenMP_CUDA) || (mode == TimerMode::MPI_OpenMP_CUDA))
+        this->mode.push_back(true);
+    else
+        this->mode.push_back(false);
+}
+
+string EventData::GetEventModeName()
+{
+    bool ifMPI = this->mode[0], ifOpenMP = this->mode[1], ifCUDA = this->mode[2]; 
+    int flag = 0;
+
+    string EventModeName = "";
+
+    if(ifMPI)
+    {
+        EventModeName += "MPI";
+        flag = 1;
+    }
+    if(ifOpenMP)
+    {
+        if(flag == 1)
+            EventModeName += "_";
+
+        EventModeName += "OpenMP";
+        flag = 1;
+    }
+    if(ifCUDA)
+    {
+        if(flag == 1)
+            EventModeName += "_";
+
+        EventModeName += "CUDA";
+    }
+    if(!ifMPI && !ifOpenMP && !ifCUDA)
+        EventModeName += "Asynchronous";
+
+    return EventModeName;
+}
\ No newline at end of file
diff --git a/Event.cu b/Event.cu
new file mode 100644
index 0000000..75484ed
--- /dev/null
+++ b/Event.cu
@@ -0,0 +1,27 @@
+#include <iostream>
+
+#include "Event.h"
+
+using namespace std;
+
+void EventData::InitEventsCUDA()
+{
+    cudaEventCreate(&(this->gpu_start));
+    cudaEventCreate(&(this->gpu_end));
+
+    this->ifCUDAinit = true;
+}
+
+void EventData::DeinitEventsCUDA()
+{
+    if((this->ifCUDAinit))
+    {
+        // cudaError_t stat =  cudaEventDestroy(this->gpu_start);
+        // cout << "gpu_star: " << cudaGetErrorString(stat) << endl;
+
+        // stat =  cudaEventDestroy(this->gpu_end);
+        // cout << "gpu_end: " << cudaGetErrorString(stat) << endl;
+
+        this->ifCUDAinit = false;
+    }
+}
\ No newline at end of file
diff --git a/Event.h b/Event.h
index 417ddcd..233a33c 100644
--- a/Event.h
+++ b/Event.h
@@ -4,7 +4,7 @@
 #include <vector>
 #include <map>
 #include <chrono>
-#include "Jikan-config.h"
+#include "Jikan.h"
 
 #ifdef INCLUDE_GPU_TIMER
     #include <cuda_runtime.h>
@@ -14,16 +14,20 @@ typedef std::chrono::steady_clock::time_point chrono_time_type;
 
 class EventData{
 public:
+
 #ifdef INCLUDE_GPU_TIMER
     cudaEvent_t gpu_start, gpu_end;
 #endif
 
+    bool if_mode_set;
+    bool ifCUDAinit;
     chrono_time_type start;
-    double elapsed_time;      // seconds
+    double elapsed_time, double_start;               // seconds
     int count, ifCUDA;
     bool ifStart, ifEnd;
     std::vector<double> time_series;
     std::string event_name;
+    std::vector<bool> mode;            // order: mode[0] ~ if MPI, mode[1] ~ if OpenMP, mode[2] ~ if CUDA
 
     EventData();
     ~EventData();
@@ -31,4 +35,10 @@ public:
     EventData& operator=(const EventData& src);
 
     double GetMeanElapsedTime();
+    void GetModeVals(const int& mode);
+    std::string GetEventModeName();
+
+private:
+    void InitEventsCUDA();
+    void DeinitEventsCUDA();
 };
\ No newline at end of file
diff --git a/Jikan copy.cpp b/Jikan copy.cpp
new file mode 100644
index 0000000..4473ce3
--- /dev/null
+++ b/Jikan copy.cpp	
@@ -0,0 +1,255 @@
+#include "JikanDepths.h"
+#include "Jikan.h"
+
+using namespace std;
+
+void GetModeVals(bool& OpenMP, bool& MPI, bool& CUDA, const int& mode)
+{
+    if(mode == TimerMode::OpenMP) || (mode == TimerMode::MPI_OpenMP) || (mode == TimerMode::MPI_OpenMP_CUDA)
+        OpenMP = true;
+    else
+        OpenMP = false;
+}
+
+extern "C"
+{
+    extern class Jikan Timer;
+
+    void TimerStart(const char* name, int& mode)
+    {
+    #ifdef INCLUDE_OPEN_MP
+        #pragma omp master if((mode == TimerMode::OpenMP) || (mode == TimerMode::MPI_OpenMP) || (mode == TimerMode::MPI_OpenMP_CUDA))
+        {
+    #endif
+
+        if()
+        
+        string str_name = name;
+
+        Timer.Jikan_start(str_name);
+
+    #ifdef INCLUDE_OPEN_MP
+        }
+    #endif
+    }
+
+    void TimerEnd(const char* name)
+    {
+    #ifdef INCLUDE_OPEN_MP
+        #pragma omp master
+        {
+    #endif
+        
+        string str_name = name;
+
+        Timer.Jikan_end(str_name);
+
+    #ifdef INCLUDE_OPEN_MP
+        }
+    #endif
+    }
+
+#ifdef INCLUDE_MPI
+    void MPI_SyncTimerStart(const char* name)
+    {
+    #ifdef INCLUDE_OPEN_MP
+        #pragma omp master
+        {
+    #endif
+        
+        string str_name = name;
+
+        int init_flag, fin_flag;
+
+        MPI_Initialized(&init_flag);
+        MPI_Finalized(&fin_flag);
+
+        if((!fin_flag) && init_flag)
+            MPI_Barrier(MPI_COMM_WORLD);
+
+        Timer.Jikan_sync_start(str_name);
+
+    #ifdef INCLUDE_OPEN_MP
+        }
+    #endif
+    }
+
+    void MPI_SyncTimerEnd(const char* name)
+    {
+    #ifdef INCLUDE_OPEN_MP
+        #pragma omp master
+        {
+    #endif
+        string str_name = name;
+
+        int init_flag, fin_flag;
+
+        MPI_Initialized(&init_flag);
+        MPI_Finalized(&fin_flag);
+
+        if((!fin_flag) && init_flag)
+            MPI_Barrier(MPI_COMM_WORLD);
+
+        Timer.Jikan_sync_end(str_name);
+
+    #ifdef INCLUDE_OPEN_MP
+        }
+    #endif
+    }
+
+    void MPI_SyncTimerStartCustom(const char* name, MPI_Comm comm)
+    {
+    #ifdef INCLUDE_OPEN_MP
+        #pragma omp master
+        {
+    #endif
+        string str_name = name;
+
+        int init_flag, fin_flag;
+
+        MPI_Initialized(&init_flag);
+        MPI_Finalized(&fin_flag);
+
+        if((!fin_flag) && init_flag)
+            MPI_Barrier(MPI_COMM_WORLD);
+
+        Timer.Jikan_sync_start(str_name);
+
+    #ifdef INCLUDE_OPEN_MP
+        }
+    #endif
+    }
+
+    void MPI_SyncTimerEndCustom(const char* name, MPI_Comm comm)
+    {
+    #ifdef INCLUDE_OPEN_MP
+        #pragma omp master
+        {
+    #endif        
+        string str_name = name;
+
+        int init_flag, fin_flag;
+
+        MPI_Initialized(&init_flag);
+        MPI_Finalized(&fin_flag);
+
+        if((!fin_flag) && init_flag)
+            MPI_Barrier(comm);
+
+        Timer.Jikan_sync_end(str_name);
+
+    #ifdef INCLUDE_OPEN_MP
+        }
+    #endif
+    }
+
+    void WriteOutputCustom(MPI_Comm comm, int id)
+    {
+    #ifdef INCLUDE_OPEN_MP
+        #pragma omp master
+        {
+    #endif
+
+        bool ifWrite = Timer.ifWriteProc(comm, id);
+        if(ifWrite == true)
+            Timer.GenerateOutputData();
+
+        #ifdef INCLUDE_OPEN_MP
+        }
+    #endif
+    }
+
+    void WriteOutput(int id)
+    {
+    #ifdef INCLUDE_OPEN_MP
+        #pragma omp master
+        {
+    #endif
+
+        bool ifWrite = Timer.ifWriteProc(MPI_COMM_WORLD, id);
+        // cout << ifWrite << endl;
+        if(ifWrite == true)
+            Timer.GenerateOutputData();
+
+    #ifdef INCLUDE_OPEN_MP
+        }
+    #endif
+    }
+
+#else
+    void WriteOutput()
+    {
+    #ifdef INCLUDE_OPEN_MP
+        #pragma omp master
+        {
+    #endif
+    
+        bool ifWrite = Timer.ifWriteProc();
+        if(ifWrite == true)
+            Timer.GenerateOutputData();
+
+    #ifdef INCLUDE_OPEN_MP
+        }
+    #endif
+    }
+#endif
+
+#ifdef INCLUDE_OPEN_MP
+    void OpenMP_SyncTimerStart(const char* name)
+    {
+        #pragma omp barrier
+        #pragma omp master
+        {
+            string str_name = name;
+
+            Timer.Jikan_sync_start(str_name);
+        }
+    }
+
+    void OpenMP_SyncTimerEnd(const char* name)
+    {
+        #pragma omp barrier
+        #pragma omp master
+        {
+            string str_name = name;
+
+            Timer.Jikan_sync_end(str_name);
+        }
+    }
+#endif
+//--------
+
+#ifdef INCLUDE_GPU_TIMER
+    void CudaTimerStart(const char* name)
+    {
+    #ifdef INCLUDE_OPEN_MP
+        #pragma omp master
+        {
+    #endif
+
+        string str_name = name;
+
+        Timer.cuda_Jikan_start(str_name);
+
+    #ifdef INCLUDE_OPEN_MP
+        }
+    #endif
+    }
+    
+    void CudaTimerEnd(const char* name)
+    {
+    #ifdef INCLUDE_OPEN_MP
+
+        #pragma omp master
+        {
+    #endif
+        string str_name = name;
+
+        Timer.cuda_Jikan_end(str_name);
+
+    #ifdef INCLUDE_OPEN_MP
+        }
+    #endif
+    }
+#endif
+}
\ No newline at end of file
diff --git a/Jikan copy.h b/Jikan copy.h
new file mode 100644
index 0000000..38cb838
--- /dev/null
+++ b/Jikan copy.h	
@@ -0,0 +1,119 @@
+#pragma once
+
+//------------------------- Jikan-config ---------------------------------------------
+#define TIMER_ON
+#define INCLUDE_GPU_TIMER
+#define INCLUDE_MPI
+#define INCLUDE_OPEN_MP
+#define SAVE_TIME_SERIES
+
+#define OUTPUT_NAME "Jikan-output"
+//------------------------------------------------------------------------------------
+
+#ifdef INCLUDE_MPI
+        #include <mpi.h>
+#endif 
+
+#ifdef __cplusplus
+extern "C" {  
+#endif                  
+        void TimerStart(const char* name);
+        void TimerEnd(const char* name);
+
+//------------------------- Asynchronous timer mode functions -------------------------
+#ifdef TIMER_ON
+        #define START_JIKAN_TIMER(name) TimerStart(name);
+        #define END_JIKAN_TIMER(name) TimerEnd(name);
+#else
+        #define START_JIKAN_TIMER(name)
+        #define END_JIKAN_TIMER(name)
+#endif
+//-------------------------------------------------------------------------------------
+
+//------------------------- MPI-synchronous timer mode functions ----------------------
+#ifdef INCLUDE_MPI
+                void MPI_SyncTimerStart(const char* name);
+                void MPI_SyncTimerEnd(const char* name);
+
+                #define MPI_SYNC_JIKAN_TIMER_START_DEF(name) MPI_SyncTimerStart(name);
+                #define MPI_SYNC_JIKAN_TIMER_END_DEF(name) MPI_SyncTimerEnd(name);
+
+                void MPI_SyncTimerStartCustom(const char* name, MPI_Comm comm);
+                void MPI_SyncTimerEndCustom(const char* name, MPI_Comm comm);
+
+                #define MPI_SYNC_JIKAN_TIMER_START_CUSTOM(name, comm) MPI_SyncTimerStartCustom(name, comm);
+                #define MPI_SYNC_JIKAN_TIMER_END_CUSTOM(name, comm) MPI_SyncTimerEndCustom(name, comm);
+
+        #ifdef TIMER_ON
+                #define SYNC_SELECT(_1, _2, macro, ...) macro
+                #define START_JIKAN_TIMER_MPI(...) SYNC_SELECT(__VA_ARGS__, MPI_SYNC_JIKAN_TIMER_START_CUSTOM, MPI_SYNC_JIKAN_TIMER_START_DEF)(__VA_ARGS__)
+                #define END_JIKAN_TIMER_MPI(...)   SYNC_SELECT(__VA_ARGS__, MPI_SYNC_JIKAN_TIMER_END_CUSTOM,   MPI_SYNC_JIKAN_TIMER_END_DEF  )(__VA_ARGS__)
+        #else
+                #define START_JIKAN_TIMER_MPI(...) 
+                #define END_JIKAN_TIMER_MPI(...) 
+        #endif
+#else 
+        #define START_JIKAN_TIMER_MPI(...)
+        #define END_JIKAN_TIMER_MPI(...) 
+#endif
+//-------------------------------------------------------------------------------------
+
+//------------------------- OpenMP-synchronous timer mode functions -------------------
+#ifdef INCLUDE_OPEN_MP
+                void OpenMP_SyncTimerStart(const char* name);
+                void OpenMP_SyncTimerEnd(const char* name);
+
+        #ifdef TIMER_ON
+                #define START_JIKAN_TIMER_OpenMP(name) OpenMP_SyncTimerStart(name);
+                #define END_JIKAN_TIMER_OpenMP(name) OpenMP_SyncTimerEnd(name);
+        #else
+                #define START_JIKAN_TIMER_OpenMP(name) 
+                #define END_JIKAN_TIMER_OpenMP(name) 
+        #endif
+#else
+        #define START_JIKAN_TIMER_OpenMP(name) 
+        #define END_JIKAN_TIMER_OpenMP(name) 
+#endif
+//-------------------------------------------------------------------------------------
+
+//------------------------- CUDA-synchronous timer mode functions ---------------------
+#ifdef INCLUDE_GPU_TIMER
+                void CudaTimerStart(const char* name);
+                void CudaTimerEnd(const char* name);
+
+        #ifdef TIMER_ON
+                #define START_JIKAN_TIMER_CUDA(name) CudaTimerStart(name);
+                #define END_JIKAN_TIMER_CUDA(name) CudaTimerEnd(name);
+        #else
+                #define START_JIKAN_TIMER_CUDA(name)
+                #define END_JIKAN_TIMER_CUDA(name)
+        #endif
+#else
+        #define START_JIKAN_TIMER_CUDA(name)
+        #define END_JIKAN_TIMER_CUDA(name)
+#endif
+//-------------------------------------------------------------------------------------
+
+//------------------------- Dump functions --------------------------------------------
+#ifdef INCLUDE_MPI
+        void WriteOutputCustom(MPI_Comm comm, int id);
+        void WriteOutput(int id);
+
+        #ifdef TIMER_ON
+                #define JIKAN_TIMER_OUTPUT_CUSTOM(comm) WriteOutputCustom(comm, 0);
+                #define JIKAN_TIMER_OUTPUT_DEF() WriteOutput(0);
+
+                #define OUTPUT_SELECT(_0, _1, macro, ...) macro
+                #define JIKAN_TIMER_OUTPUT(...) OUTPUT_SELECT(__VA_ARGS__, JIKAN_TIMER_OUTPUT_CUSTOM, JIKAN_TIMER_OUTPUT_DEF)(__VA_ARGS__)
+        #else
+                #define JIKAN_TIMER_OUTPUT(...)
+        #endif
+#else
+        void WriteOutput();
+        #define JIKAN_TIMER_OUTPUT() WriteOutput();
+#endif
+//-------------------------------------------------------------------------------------
+
+#ifdef __cplusplus  
+} 
+#endif
\ No newline at end of file
diff --git a/Jikan.cpp b/Jikan.cpp
index c60294d..57df813 100644
--- a/Jikan.cpp
+++ b/Jikan.cpp
@@ -1,13 +1,7 @@
+#include "JikanDepths.h"
 #include "Jikan.h"
-#include "JikanWrapper.h"
 
-#ifdef INCLUDE_OPEN_MP
-    #include "omp.h"
-#endif
-
-#ifdef INCLUDE_MPI
-    #include "mpi.h"
-#endif
+#include <omp.h>
 
 using namespace std;
 
@@ -15,239 +9,27 @@ extern "C"
 {
     extern class Jikan Timer;
 
-    void TimerStart(const char* name)
+    void TimerStart(const char* name, const int& mode)
     {
-    #ifdef INCLUDE_OPEN_MP
-        #pragma omp master
-        {
-    #endif
-        
         string str_name = name;
 
-        Timer.Jikan_start(str_name);
-
-    #ifdef INCLUDE_OPEN_MP
-        }
-    #endif
+        Timer.Jikan_start(str_name, mode);
     }
 
     void TimerEnd(const char* name)
     {
-    #ifdef INCLUDE_OPEN_MP
-        #pragma omp master
-        {
-    #endif
-        
         string str_name = name;
 
         Timer.Jikan_end(str_name);
-
-    #ifdef INCLUDE_OPEN_MP
-        }
-    #endif
-    }
-
-#ifdef INCLUDE_MPI
-    void MPI_SyncTimerStart(const char* name)
-    {
-    #ifdef INCLUDE_OPEN_MP
-        #pragma omp master
-        {
-    #endif
-        
-        string str_name = name;
-
-        int init_flag, fin_flag;
-
-        MPI_Initialized(&init_flag);
-        MPI_Finalized(&fin_flag);
-
-        if((!fin_flag) && init_flag)
-            MPI_Barrier(MPI_COMM_WORLD);
-
-        Timer.Jikan_sync_start(str_name);
-
-    #ifdef INCLUDE_OPEN_MP
-        }
-    #endif
-    }
-
-    void MPI_SyncTimerEnd(const char* name)
-    {
-    #ifdef INCLUDE_OPEN_MP
-        #pragma omp master
-        {
-    #endif
-        string str_name = name;
-
-        int init_flag, fin_flag;
-
-        MPI_Initialized(&init_flag);
-        MPI_Finalized(&fin_flag);
-
-        if((!fin_flag) && init_flag)
-            MPI_Barrier(MPI_COMM_WORLD);
-
-        Timer.Jikan_sync_end(str_name);
-
-    #ifdef INCLUDE_OPEN_MP
-        }
-    #endif
-    }
-
-    void MPI_SyncTimerStartCustom(const char* name, MPI_Comm comm)
-    {
-    #ifdef INCLUDE_OPEN_MP
-        #pragma omp master
-        {
-    #endif
-        string str_name = name;
-
-        int init_flag, fin_flag;
-
-        MPI_Initialized(&init_flag);
-        MPI_Finalized(&fin_flag);
-
-        if((!fin_flag) && init_flag)
-            MPI_Barrier(MPI_COMM_WORLD);
-
-        Timer.Jikan_sync_start(str_name);
-
-    #ifdef INCLUDE_OPEN_MP
-        }
-    #endif
-    }
-
-    void MPI_SyncTimerEndCustom(const char* name, MPI_Comm comm)
-    {
-    #ifdef INCLUDE_OPEN_MP
-        #pragma omp master
-        {
-    #endif        
-        string str_name = name;
-
-        int init_flag, fin_flag;
-
-        MPI_Initialized(&init_flag);
-        MPI_Finalized(&fin_flag);
-
-        if((!fin_flag) && init_flag)
-            MPI_Barrier(comm);
-
-        Timer.Jikan_sync_end(str_name);
-
-    #ifdef INCLUDE_OPEN_MP
-        }
-    #endif
-    }
-
-    void WriteOutputCustom(MPI_Comm comm, int id)
-    {
-    #ifdef INCLUDE_OPEN_MP
-        #pragma omp master
-        {
-    #endif
-
-        bool ifWrite = Timer.ifWriteProc(comm, id);
-        if(ifWrite == true)
-            Timer.GenerateOutputData();
-
-        #ifdef INCLUDE_OPEN_MP
-        }
-    #endif
     }
 
-    void WriteOutput(int id)
-    {
-    #ifdef INCLUDE_OPEN_MP
-        #pragma omp master
-        {
-    #endif
-
-        bool ifWrite = Timer.ifWriteProc(MPI_COMM_WORLD, id);
-        // cout << ifWrite << endl;
-        if(ifWrite == true)
-            Timer.GenerateOutputData();
-
-    #ifdef INCLUDE_OPEN_MP
-        }
-    #endif
-    }
-
-#else
     void WriteOutput()
-    {
-    #ifdef INCLUDE_OPEN_MP
-        #pragma omp master
-        {
-    #endif
-    
-        bool ifWrite = Timer.ifWriteProc();
-        if(ifWrite == true)
-            Timer.GenerateOutputData();
-
-    #ifdef INCLUDE_OPEN_MP
-        }
-    #endif
-    }
-#endif
-
-#ifdef INCLUDE_OPEN_MP
-    void OpenMP_SyncTimerStart(const char* name)
-    {
-        #pragma omp barrier
+    {    
         #pragma omp master
         {
-            string str_name = name;
-
-            Timer.Jikan_sync_start(str_name);
-        }
-    }
-
-    void OpenMP_SyncTimerEnd(const char* name)
-    {
-        #pragma omp barrier
-        #pragma omp master
-        {
-            string str_name = name;
-
-            Timer.Jikan_sync_end(str_name);
-        }
-    }
-#endif
-//--------
-
-#ifdef INCLUDE_GPU_TIMER
-    void CudaTimerStart(const char* name)
-    {
-    #ifdef INCLUDE_OPEN_MP
-        #pragma omp master
-        {
-    #endif
-
-        string str_name = name;
-
-        Timer.cuda_Jikan_start(str_name);
-
-    #ifdef INCLUDE_OPEN_MP
-        }
-    #endif
-    }
-    
-    void CudaTimerEnd(const char* name)
-    {
-    #ifdef INCLUDE_OPEN_MP
-
-        #pragma omp master
-        {
-    #endif
-        string str_name = name;
-
-        Timer.cuda_Jikan_end(str_name);
-
-    #ifdef INCLUDE_OPEN_MP
+            bool ifWrite = Timer.ifWriteProc();
+            if(ifWrite == true)
+                Timer.GenerateOutputData();
         }
-    #endif
     }
-#endif
 }
\ No newline at end of file
diff --git a/Jikan.cu b/Jikan.cu
deleted file mode 100644
index 2546444..0000000
--- a/Jikan.cu
+++ /dev/null
@@ -1,93 +0,0 @@
-#include <sys/time.h>
-#include <cuda.h>
-#include <cuda_runtime.h>
-#include "Jikan.h"
-#include "Jikan-config.h"
-
-#ifdef INCLUDE_OPEN_MP
-    #include "omp.h"
-#endif
-
-using namespace std;
-
-void Jikan::cuda_Jikan_start(const string& name)
-{
-#ifdef INCLUDE_OPEN_MP
-    #pragma omp master
-    {
-#endif
-    bool ExistFlag;
-    ExistFlag = this->ifContains(name);
-
-    if(ExistFlag == false)
-    {
-        (this->Events)[name] = EventData(name);
-        this->EventType["CUDA events"].insert(name);
-        (this->Events)[name].ifCUDA = 1;
-
-        cudaEventCreate(&(((this->Events)[name]).gpu_start));
-        cudaEventCreate(&(((this->Events)[name]).gpu_end));
-    }
-    
-    (this->Events)[name].ifStart = true;
-	cudaEventRecord ((this->Events)[name].gpu_start);
-#ifdef INCLUDE_OPEN_MP
-    }
-#endif
-}
-
-void Jikan::cuda_Jikan_end(const string& name)
-{
-#ifdef INCLUDE_OPEN_MP
-    #pragma omp master
-    {
-#endif
-    bool ExistFlag, ifStart;
-    ExistFlag = this->ifContains(name);
-    ifStart = (this->Events)[name].ifStart;
-
-    if((!ExistFlag) || (!ifStart))
-        return;
-
-    float GPUtime = 0.0;
-
-    cudaEventRecord((this->Events)[name].gpu_end);
-	cudaEventSynchronize((this->Events)[name].gpu_end);
-    cudaEventElapsedTime(&GPUtime, (this->Events)[name].gpu_start, (this->Events)[name].gpu_end); //milliseconds 
-
-    GPUtime *= 1e-3;
-    (this->Events)[name].elapsed_time += GPUtime;
-    (this->Events)[name].count ++;
-
-#ifdef SAVE_TIME_SERIES
-    (this->Events)[name].time_series.push_back(GPUtime);
-#endif
-
-    (this->Events)[name].ifStart = false;
-
-#ifdef INCLUDE_OPEN_MP
-    }
-#endif
-}
-
-void Jikan::FreeCudaEvents()
-{
-#ifdef INCLUDE_OPEN_MP
-    #pragma omp master
-    {
-#endif
-
-    map<string, EventData>::iterator it;
-    for (it = this->Events.begin(); it!=this->Events.end(); ++it)
-    {
-        if((it->second).ifCUDA == 1)
-        { 
-            cudaEventDestroy((it->second).gpu_start);
-            cudaEventDestroy((it->second).gpu_end);
-        }
-    }
-
-#ifdef INCLUDE_OPEN_MP
-    }
-#endif
-}
\ No newline at end of file
diff --git a/Jikan.h b/Jikan.h
index 38cb838..bc98a66 100644
--- a/Jikan.h
+++ b/Jikan.h
@@ -14,105 +14,36 @@
         #include <mpi.h>
 #endif 
 
+enum TimerMode
+{
+    NO_SYNC =  0x01,
+    MPI_mode =    0x02,
+    OpenMP_mode = 0x03,
+    CUDA_mode =   0x04,
+
+    MPI_OpenMP       = MPI_mode * OpenMP_mode,
+    OpenMP_CUDA      = CUDA_mode * OpenMP_mode,
+    MPI_OpenMP_CUDA  = MPI_mode * OpenMP_mode * CUDA_mode,
+    MPI_CUDA         = MPI_mode * CUDA_mode,
+};
+
 #ifdef __cplusplus
 extern "C" {  
-#endif                  
-        void TimerStart(const char* name);
-        void TimerEnd(const char* name);
+#endif         
 
-//------------------------- Asynchronous timer mode functions -------------------------
+        void TimerStart(const char* name, const int& mode_t);
+        void TimerEnd(const char* name);
+        void WriteOutput();
+        
 #ifdef TIMER_ON
-        #define START_JIKAN_TIMER(name) TimerStart(name);
-        #define END_JIKAN_TIMER(name) TimerEnd(name);
+        #define START_JIKAN_TIMER(name, mode_t) TimerStart(name, mode_t);
+        #define END_JIKAN_TIMER(name)           TimerEnd(name);
+        #define JIKAN_TIMER_OUTPUT() WriteOutput();
 #else
         #define START_JIKAN_TIMER(name)
         #define END_JIKAN_TIMER(name)
-#endif
-//-------------------------------------------------------------------------------------
-
-//------------------------- MPI-synchronous timer mode functions ----------------------
-#ifdef INCLUDE_MPI
-                void MPI_SyncTimerStart(const char* name);
-                void MPI_SyncTimerEnd(const char* name);
-
-                #define MPI_SYNC_JIKAN_TIMER_START_DEF(name) MPI_SyncTimerStart(name);
-                #define MPI_SYNC_JIKAN_TIMER_END_DEF(name) MPI_SyncTimerEnd(name);
-
-                void MPI_SyncTimerStartCustom(const char* name, MPI_Comm comm);
-                void MPI_SyncTimerEndCustom(const char* name, MPI_Comm comm);
-
-                #define MPI_SYNC_JIKAN_TIMER_START_CUSTOM(name, comm) MPI_SyncTimerStartCustom(name, comm);
-                #define MPI_SYNC_JIKAN_TIMER_END_CUSTOM(name, comm) MPI_SyncTimerEndCustom(name, comm);
-
-        #ifdef TIMER_ON
-                #define SYNC_SELECT(_1, _2, macro, ...) macro
-                #define START_JIKAN_TIMER_MPI(...) SYNC_SELECT(__VA_ARGS__, MPI_SYNC_JIKAN_TIMER_START_CUSTOM, MPI_SYNC_JIKAN_TIMER_START_DEF)(__VA_ARGS__)
-                #define END_JIKAN_TIMER_MPI(...)   SYNC_SELECT(__VA_ARGS__, MPI_SYNC_JIKAN_TIMER_END_CUSTOM,   MPI_SYNC_JIKAN_TIMER_END_DEF  )(__VA_ARGS__)
-        #else
-                #define START_JIKAN_TIMER_MPI(...) 
-                #define END_JIKAN_TIMER_MPI(...) 
-        #endif
-#else 
-        #define START_JIKAN_TIMER_MPI(...)
-        #define END_JIKAN_TIMER_MPI(...) 
-#endif
-//-------------------------------------------------------------------------------------
-
-//------------------------- OpenMP-synchronous timer mode functions -------------------
-#ifdef INCLUDE_OPEN_MP
-                void OpenMP_SyncTimerStart(const char* name);
-                void OpenMP_SyncTimerEnd(const char* name);
-
-        #ifdef TIMER_ON
-                #define START_JIKAN_TIMER_OpenMP(name) OpenMP_SyncTimerStart(name);
-                #define END_JIKAN_TIMER_OpenMP(name) OpenMP_SyncTimerEnd(name);
-        #else
-                #define START_JIKAN_TIMER_OpenMP(name) 
-                #define END_JIKAN_TIMER_OpenMP(name) 
-        #endif
-#else
-        #define START_JIKAN_TIMER_OpenMP(name) 
-        #define END_JIKAN_TIMER_OpenMP(name) 
-#endif
-//-------------------------------------------------------------------------------------
-
-//------------------------- CUDA-synchronous timer mode functions ---------------------
-#ifdef INCLUDE_GPU_TIMER
-                void CudaTimerStart(const char* name);
-                void CudaTimerEnd(const char* name);
-
-        #ifdef TIMER_ON
-                #define START_JIKAN_TIMER_CUDA(name) CudaTimerStart(name);
-                #define END_JIKAN_TIMER_CUDA(name) CudaTimerEnd(name);
-        #else
-                #define START_JIKAN_TIMER_CUDA(name)
-                #define END_JIKAN_TIMER_CUDA(name)
-        #endif
-#else
-        #define START_JIKAN_TIMER_CUDA(name)
-        #define END_JIKAN_TIMER_CUDA(name)
-#endif
-//-------------------------------------------------------------------------------------
-
-//------------------------- Dump functions --------------------------------------------
-#ifdef INCLUDE_MPI
-        void WriteOutputCustom(MPI_Comm comm, int id);
-        void WriteOutput(int id);
-
-        #ifdef TIMER_ON
-                #define JIKAN_TIMER_OUTPUT_CUSTOM(comm) WriteOutputCustom(comm, 0);
-                #define JIKAN_TIMER_OUTPUT_DEF() WriteOutput(0);
-
-                #define OUTPUT_SELECT(_0, _1, macro, ...) macro
-                #define JIKAN_TIMER_OUTPUT(...) OUTPUT_SELECT(__VA_ARGS__, JIKAN_TIMER_OUTPUT_CUSTOM, JIKAN_TIMER_OUTPUT_DEF)(__VA_ARGS__)
-        #else
-                #define JIKAN_TIMER_OUTPUT(...)
-        #endif
-#else
-        void WriteOutput();
-        #define JIKAN_TIMER_OUTPUT() WriteOutput();
-#endif
-//-------------------------------------------------------------------------------------
+        #define JIKAN_TIMER_OUTPUT()
+#endif 
 
 #ifdef __cplusplus  
 } 
diff --git a/JikanDepths copy.cpp b/JikanDepths copy.cpp
new file mode 100644
index 0000000..28fd540
--- /dev/null
+++ b/JikanDepths copy.cpp	
@@ -0,0 +1,264 @@
+#include "JikanDepths.h"
+#include "ToJSON.h"
+
+#include <iostream>
+#include <map>
+#include <string>
+
+using namespace std;
+
+class Jikan Timer;
+
+Jikan::Jikan()
+{
+    this->EventType["Synchronous events"] = set<string>();
+    this->EventType["Asynchronous events"] = set<string>();
+    this->EventType["CUDA events"] = set<string>();
+
+    this->JSONname = OUTPUT_NAME + string(".json");
+    this->JSONdata = "";
+    this->Error = "";
+};
+
+#ifdef INCLUDE_MPI
+    bool Jikan::ifWriteProc(MPI_Comm comm, int id)
+    {
+        bool if_write = false;
+        int init_flag, fin_flag, iproc;
+
+        MPI_Initialized(&init_flag);
+        MPI_Finalized(&fin_flag);
+
+        bool if_MPI = (init_flag) && (!fin_flag);
+        if(if_MPI)
+        {
+            MPI_Comm_rank(comm, &iproc);
+            if( iproc == id)
+                if_write = true;
+        }
+        else
+            if_write = true;
+
+
+        return if_write;
+    }
+#else
+    bool Jikan::ifWriteProc()
+    {
+        return true;
+    }
+#endif
+
+Jikan::~Jikan()
+{
+    this->Events.clear();
+    map<string, set<string> >::iterator it;
+
+    for(it = this->EventType.begin(); it!=this->EventType.end(); ++it)
+        it->second.clear();
+    this->EventType.clear();
+}
+
+bool Jikan::ifContains(const string& Name)
+{
+    map<string, EventData>::iterator it;
+
+    it = this->Events.find(Name);
+    if (it == this->Events.end())
+        return false;
+
+    return true;
+}
+
+void Jikan::Jikan_sync_start(const string& name)
+{
+    bool ExistFlag;
+    ExistFlag = this->ifContains(name);
+
+    if(ExistFlag)
+    {
+        chrono_time_type start = chrono::steady_clock::now();
+        (this->Events)[name].start = start;
+    }
+    else
+    {
+        this->EventType["Synchronous events"].insert(name);
+
+        (this->Events)[name] = EventData(name);
+        chrono_time_type start = chrono::steady_clock::now();
+        (this->Events)[name].start = start;
+    }
+
+    (this->Events)[name].ifStart = true;
+}
+
+void Jikan::Jikan_sync_end(const string& name)
+{
+    bool ExistFlag, ifStart;
+    ExistFlag = this->ifContains(name);
+    ifStart = (this->Events)[name].ifStart;
+
+    if((!ExistFlag) || (!ifStart))
+        return;
+
+    chrono_time_type end = chrono::steady_clock::now();
+    chrono_time_type start = (this->Events)[name].start;
+
+    double main_elapsed = chrono::duration_cast<chrono::nanoseconds>(end - start).count() * 1e-9;
+
+    (this->Events)[name].elapsed_time += main_elapsed;
+    (this->Events)[name].count ++;
+
+#ifdef SAVE_TIME_SERIES
+    (this->Events)[name].time_series.push_back(main_elapsed);
+#endif
+
+    (this->Events)[name].ifStart = false;
+}
+
+void Jikan::Jikan_async_start(const string& name)
+{
+    bool ExistFlag;
+    ExistFlag = this->ifContains(name);
+
+    if(ExistFlag)
+    {
+        chrono_time_type start = chrono::steady_clock::now();
+        (this->Events)[name].start = start;
+    }
+    else
+    {
+        this->EventType["Asynchronous events"].insert(name);
+
+        (this->Events)[name] = EventData(name);
+        chrono_time_type start = chrono::steady_clock::now();
+        (this->Events)[name].start = start;
+    }
+
+    (this->Events)[name].ifStart = true;
+}
+
+void Jikan::Jikan_async_end(const string& name)
+{
+    bool ExistFlag, ifStart;
+    ExistFlag = this->ifContains(name);
+    ifStart = (this->Events)[name].ifStart;
+
+    if((!ExistFlag) || (!ifStart))
+        return;
+
+    chrono_time_type end = chrono::steady_clock::now();
+    chrono_time_type start = (this->Events)[name].start;
+
+    double main_elapsed = chrono::duration_cast<chrono::nanoseconds>(end - start).count() * 1e-9;
+
+    (this->Events)[name].elapsed_time += main_elapsed;
+    (this->Events)[name].count ++;
+
+#ifdef SAVE_TIME_SERIES
+    (this->Events)[name].time_series.push_back(main_elapsed);
+#endif
+
+    (this->Events)[name].ifStart = false;
+}
+
+void Jikan::Jikan_start(const string& name, const int& mode)
+{
+    bool ExistFlag;
+    ExistFlag = this->ifContains(name);
+
+    if(!ExistFlag)
+    {
+        (this->Events)[name] = EventData(name);
+        (this->Events)[name].GetModeVals(mode);
+    }
+    
+    bool ifMPI = (this->Events)[name].mode[0], ifOpenMP = (this->Events)[name].mode[1], ifCUDA = (this->Events)[name].mode[2];
+
+    if(ifMPI)
+    {
+        int init_flag, fin_flag;
+
+        MPI_Initialized(&init_flag);
+        MPI_Finalized(&fin_flag);
+
+        if((!fin_flag) && init_flag)
+            MPI_Barrier(MPI_COMM_WORLD);
+    }
+
+    #pragma omp master if(mode == TimerMode::OpenMP)
+    {
+        
+    }
+}
+
+void Jikan::GenerateTypedOutputData(const string& EventType, string& EventTypeString)
+{
+    const int n = this->EventType[EventType].size();
+    EventTypeString = JSON::StartTypedBlock(EventType);
+
+    if(n == 0)
+    {
+        EventTypeString += "\n\t}";
+        return;
+    }
+
+    string Row;
+    string Name;
+    set<string>::iterator it;
+    set<string>::iterator end_m = this->EventType[EventType].end();
+    --end_m;
+
+    for (it = this->EventType[EventType].begin(); it != end_m; ++it)
+    {
+        Name = *it;
+        JSON::GenerateRow(this->Events[Name], Row, JSON::SeparateRows);
+        EventTypeString += Row;
+    }
+
+    Name = *end_m;
+    JSON::GenerateRow(this->Events[Name], Row, JSON::FinishRows);
+    EventTypeString += Row;
+}
+
+void Jikan::GenerateOutputData()
+{
+    map<string, set<string> >::iterator it;
+    map<string, set<string> >::iterator end_m = this->EventType.end();
+    --end_m;
+
+    string Name;
+    string Out = "{ ";
+    string TypedOutput;
+
+    for(it = this->EventType.begin(); it!=end_m; ++it)
+    {    
+        Name = it->first;
+        TypedOutput = "";
+        this->GenerateTypedOutputData(Name, TypedOutput);
+        Out += TypedOutput + ",\n";
+    }
+
+    Name = end_m->first;
+    TypedOutput = "";
+    this->GenerateTypedOutputData(Name, TypedOutput);
+    Out += TypedOutput + "\n}";
+
+    this->JSONdata = Out;
+
+    bool OutputRes = JSON::WriteOutput(this->JSONname, this->JSONdata);
+
+    if(OutputRes != true)
+    {
+        this->Error = JSON::Error;
+    }
+
+    #ifdef INCLUDE_GPU_TIMER
+        this->FreeCudaEvents();
+    #endif
+}
+
+void Jikan::SetDumpFilename(const std::string& name)
+{
+    this->JSONname = name;
+}
\ No newline at end of file
diff --git a/JikanDepths.cpp b/JikanDepths.cpp
index c158103..6a171fa 100644
--- a/JikanDepths.cpp
+++ b/JikanDepths.cpp
@@ -1,3 +1,4 @@
+#include "Jikan.h"
 #include "JikanDepths.h"
 #include "ToJSON.h"
 
@@ -5,19 +6,23 @@
 #include <map>
 #include <string>
 
-using namespace std;
+#ifdef INCLUDE_OPEN_MP
+#include <omp.h>
+#endif
 
-class Jikan Timer;
+using namespace std;
 
 Jikan::Jikan()
 {
-    this->EventType["Synchronous events"] = set<string>();
-    this->EventType["Asynchronous events"] = set<string>();
-    this->EventType["CUDA events"] = set<string>();
+    #pragma omp master
+    {
+        this->EventType["Synchronous events"] = set<string>();
+        this->EventType["Asynchronous events"] = set<string>();
 
-    this->JSONname = OUTPUT_NAME + string(".json");
-    this->JSONdata = "";
-    this->Error = "";
+        this->JSONname = OUTPUT_NAME + string(".json");
+        this->JSONdata = "";
+        this->Error = "";
+    }
 };
 
 #ifdef INCLUDE_MPI
@@ -42,21 +47,26 @@ Jikan::Jikan()
 
         return if_write;
     }
-#else
-    bool Jikan::ifWriteProc()
-    {
-        return true;
-    }
 #endif
 
+bool Jikan::ifWriteProc()
+{
+    return true;
+}
+
 Jikan::~Jikan()
 {
-    this->Events.clear();
-    map<string, set<string> >::iterator it;
+    #pragma omp master
+    {
+        this->Events.clear();
+        
+        map<string, set<string> >::iterator it;
+
+        for(it = this->EventType.begin(); it!=this->EventType.end(); ++it)
+            it->second.clear();
 
-    for(it = this->EventType.begin(); it!=this->EventType.end(); ++it)
-        it->second.clear();
-    this->EventType.clear();
+        this->EventType.clear();
+    }
 }
 
 bool Jikan::ifContains(const string& Name)
@@ -70,96 +80,111 @@ bool Jikan::ifContains(const string& Name)
     return true;
 }
 
-void Jikan::Jikan_sync_start(const string& name)
+void Jikan::Jikan_start(const string& name, const int& mode)
 {
-    bool ExistFlag;
+    bool ExistFlag, ifMPI, ifOpenMP;
     ExistFlag = this->ifContains(name);
 
-    if(ExistFlag)
+    #pragma omp master
+    {
+        (this->Events)[name].ifStart = true;
+    }
+
+    #pragma omp barrier
+
+    if(!ExistFlag)
     {
-        chrono_time_type start = chrono::steady_clock::now();
-        (this->Events)[name].start = start;
+        #pragma omp master
+        {
+            (this->Events)[name] = EventData(name);
+            (this->Events)[name].GetModeVals(mode);
+        }
     }
     else
     {
-        this->EventType["Synchronous events"].insert(name);
+        bool ifStart = (this->Events)[name].ifStart;
 
-        (this->Events)[name] = EventData(name);
-        chrono_time_type start = chrono::steady_clock::now();
-        (this->Events)[name].start = start;
+        if(!ifStart)
+            return;
     }
 
-    (this->Events)[name].ifStart = true;
-}
+    #pragma omp barrier
+    ifMPI = (this->Events)[name].mode[0], ifOpenMP = (this->Events)[name].mode[1];
 
-void Jikan::Jikan_sync_end(const string& name)
-{
-    bool ExistFlag, ifStart;
-    ExistFlag = this->ifContains(name);
-    ifStart = (this->Events)[name].ifStart;
-
-    if((!ExistFlag) || (!ifStart))
-        return;
-
-    chrono_time_type end = chrono::steady_clock::now();
-    chrono_time_type start = (this->Events)[name].start;
-
-    double main_elapsed = chrono::duration_cast<chrono::nanoseconds>(end - start).count() * 1e-9;
-
-    (this->Events)[name].elapsed_time += main_elapsed;
-    (this->Events)[name].count ++;
+    #pragma omp master
+    {
+        if(!ExistFlag)
+        {
+            string EventTypeName;
 
-#ifdef SAVE_TIME_SERIES
-    (this->Events)[name].time_series.push_back(main_elapsed);
-#endif
+            if(mode == TimerMode::NO_SYNC)
+                EventTypeName = "Asynchronous events";
+            else
+                EventTypeName = "Synchronous events";
 
-    (this->Events)[name].ifStart = false;
-}
+            this->EventType[EventTypeName].insert(name);
+        }
 
-void Jikan::Jikan_start(const string& name)
-{
-    bool ExistFlag;
-    ExistFlag = this->ifContains(name);
+        //--------------------------- MPI synchronization ---------------------------------------
+        if(ifMPI)
+            this->BarrierMPI();
+        //---------------------------------------------------------------------------------------
+    }
 
-    if(ExistFlag)
+    //--------------------------- OpenMP synchronization --------------------------------
+    if(ifOpenMP)
     {
-        chrono_time_type start = chrono::steady_clock::now();
-        (this->Events)[name].start = start;
+        #pragma omp barrier 
     }
-    else
-    {
-        this->EventType["Asynchronous events"].insert(name);
+    //-----------------------------------------------------------------------------------
 
-        (this->Events)[name] = EventData(name);
-        chrono_time_type start = chrono::steady_clock::now();
-        (this->Events)[name].start = start;
+    #pragma omp master
+    {
+        this->StartEventTimer(name);
     }
-
-    (this->Events)[name].ifStart = true;
 }
 
 void Jikan::Jikan_end(const string& name)
-{
+{    
     bool ExistFlag, ifStart;
+    bool ifMPI, ifOpenMP, ifCUDA;
+
     ExistFlag = this->ifContains(name);
     ifStart = (this->Events)[name].ifStart;
 
     if((!ExistFlag) || (!ifStart))
         return;
 
-    chrono_time_type end = chrono::steady_clock::now();
-    chrono_time_type start = (this->Events)[name].start;
+    ifMPI = (this->Events)[name].mode[0], ifOpenMP = (this->Events)[name].mode[1], ifCUDA = (this->Events)[name].mode[2];
 
-    double main_elapsed = chrono::duration_cast<chrono::nanoseconds>(end - start).count() * 1e-9;
+    #pragma omp master
+    {
+        if((ifCUDA) && (!ifMPI) && (!ifOpenMP))
+        {    
+            #ifdef INCLUDE_GPU_TIMER
+                this->cuda_Jikan_end(name);
+            #endif
+        }
+    }
 
-    (this->Events)[name].elapsed_time += main_elapsed;
-    (this->Events)[name].count ++;
+    //--------------------------- OpenMP synchronization --------------------------------
+    if(ifOpenMP)
+    {
+        #pragma omp barrier 
+    }
+    //-----------------------------------------------------------------------------------
 
-#ifdef SAVE_TIME_SERIES
-    (this->Events)[name].time_series.push_back(main_elapsed);
-#endif
+    //--------------------------- MPI synchronization ---------------------------------------
+    #pragma omp master
+    {
+        if(ifMPI)
+            this->BarrierMPI();
 
-    (this->Events)[name].ifStart = false;
+        (this->Events)[name].ifStart = false;
+
+        this->EndEventTimer(name);
+    }
+    //---------------------------------------------------------------------------------------
 }
 
 void Jikan::GenerateTypedOutputData(const string& EventType, string& EventTypeString)
@@ -222,13 +247,86 @@ void Jikan::GenerateOutputData()
     {
         this->Error = JSON::Error;
     }
+}
 
-    #ifdef INCLUDE_GPU_TIMER
-        this->FreeCudaEvents();
+void Jikan::SetDumpFilename(const string& name)
+{
+    this->JSONname = name;
+}
+
+void Jikan::StartEventTimer(const string& name)
+{
+    bool ifMPI = (this->Events)[name].mode[0], ifOpenMP = (this->Events)[name].mode[1], ifCUDA = (this->Events)[name].mode[2];
+
+    if((ifCUDA))
+    {
+        #ifdef INCLUDE_GPU_TIMER
+            this->cuda_Jikan_start(name);
+        #endif
+    }
+
+    #ifdef INCLUDE_OPEN_MP
+        else if( (!ifMPI) && (ifOpenMP) )
+            (this->Events)[name].double_start = omp_get_wtime();
     #endif
+
+    else
+        (this->Events)[name].start = chrono::steady_clock::now();
 }
 
-void Jikan::SetDumpFilename(const std::string& name)
+void Jikan::EndEventTimer(const string& name)
 {
-    this->JSONname = name;
-}
\ No newline at end of file
+    bool ifMPI = (this->Events)[name].mode[0], ifOpenMP = (this->Events)[name].mode[1], ifCUDA = (this->Events)[name].mode[2];
+
+    if((ifCUDA))
+    {
+        #ifdef INCLUDE_GPU_TIMER
+            this->cuda_Jikan_start(name);
+        #endif
+    }
+
+    #ifdef INCLUDE_OPEN_MP
+        else if( (!ifMPI) && (ifOpenMP))
+        {
+            double end = omp_get_wtime();
+            double main_elapsed = end - (this->Events)[name].double_start;
+
+            (this->Events)[name].elapsed_time += main_elapsed;
+            (this->Events)[name].count ++;
+
+            #ifdef SAVE_TIME_SERIES
+                (this->Events)[name].time_series.push_back(main_elapsed);
+            #endif
+        }
+    #endif
+
+    else
+    {
+        chrono_time_type end = chrono::steady_clock::now();
+        chrono_time_type start = (this->Events)[name].start;
+
+        double main_elapsed = chrono::duration_cast<chrono::nanoseconds>(end - start).count() * 1e-9;
+
+        (this->Events)[name].elapsed_time += main_elapsed;
+        (this->Events)[name].count ++;
+
+        #ifdef SAVE_TIME_SERIES
+            (this->Events)[name].time_series.push_back(main_elapsed);
+        #endif
+    }
+}
+
+void Jikan::BarrierMPI()
+{
+#ifdef INCLUDE_MPI
+    int init_flag, fin_flag;
+
+    MPI_Initialized(&init_flag);
+    MPI_Finalized(&fin_flag);
+
+    if((!fin_flag) && init_flag)
+        MPI_Barrier(MPI_COMM_WORLD);
+#endif
+}
+
+class Jikan Timer;
\ No newline at end of file
diff --git a/JikanDepths.cu b/JikanDepths.cu
new file mode 100644
index 0000000..6da4fbb
--- /dev/null
+++ b/JikanDepths.cu
@@ -0,0 +1,36 @@
+#include <sys/time.h>
+#include <cuda.h>
+#include <cuda_runtime.h>
+#include "JikanDepths.h"
+
+#ifdef INCLUDE_OPEN_MP
+    #include "omp.h"
+#endif
+
+using namespace std;
+
+void Jikan::cuda_Jikan_start(const string& name)
+{
+	cudaEventRecord ((this->Events)[name].gpu_start);
+}
+
+void Jikan::cuda_Jikan_end(const string& name)
+{
+    cudaEventRecord((this->Events)[name].gpu_end);
+	cudaEventSynchronize((this->Events)[name].gpu_end);
+
+    bool ifMPI = (this->Events)[name].mode[0], ifOpenMP = (this->Events)[name].mode[1], ifCUDA = (this->Events)[name].mode[2];
+
+    if((ifCUDA) && (!ifMPI) && (!ifOpenMP))
+    {
+        float GPUtime = 0.0;
+        cudaEventElapsedTime(&GPUtime, (this->Events)[name].gpu_start, (this->Events)[name].gpu_end );
+        GPUtime *= 1e-3;
+        (this->Events)[name].elapsed_time += GPUtime;
+        (this->Events)[name].count ++;
+
+        #ifdef SAVE_TIME_SERIES
+            (this->Events)[name].time_series.push_back(GPUtime);
+        #endif
+    }
+}
\ No newline at end of file
diff --git a/JikanDepths.h b/JikanDepths.h
index b67ae99..3395fe9 100644
--- a/JikanDepths.h
+++ b/JikanDepths.h
@@ -1,12 +1,12 @@
 #pragma once
 
-#include "JikanWrapper.h"
-#include "Jikan-config.h"
+#include "Jikan.h"
 #include "Event.h"
 
 #include <iostream>
 #include <string>
 #include <set>
+
 #ifdef INCLUDE_MPI
     #include <mpi.h>
 #endif
@@ -23,10 +23,7 @@ public:
     Jikan();
     ~Jikan();
 
-    void Jikan_sync_start(const std::string& name);
-    void Jikan_sync_end(  const std::string& name);
-
-    void Jikan_start(const std::string& name);
+    void Jikan_start(const std::string& name, const int& mode);
     void Jikan_end(  const std::string& name);
 
 #ifdef INCLUDE_GPU_TIMER
@@ -42,16 +39,15 @@ public:
 
 #ifdef INCLUDE_MPI
     bool ifWriteProc(MPI_Comm comm, int id);
-#else 
-    bool ifWriteProc();
 #endif
 
+    bool ifWriteProc();
+
     void SetDumpFilename(const std::string& name);
 
 private:
-
-#ifdef INCLUDE_GPU_TIMER
-    void FreeCudaEvents();
-#endif
-
+    void StartTimer(const std::string& name);
+    void BarrierMPI();
+    void StartEventTimer(const std::string& name);
+    void EndEventTimer(const std::string& name);
 };
\ No newline at end of file
diff --git a/ToJSON.cpp b/ToJSON.cpp
index 95b0a1b..8241654 100644
--- a/ToJSON.cpp
+++ b/ToJSON.cpp
@@ -37,6 +37,8 @@ string JSON::StartTypedBlock(const string& name)
 
 bool JSON::GenerateRow(EventData Event, string &ResRow, const string& EndRowJSON)
 {
+    string EventModeName = JSON::StartSubRow("Event mode") + "\"" + Event.GetEventModeName() + "\"" + JSON::SeparateSubRows;
+
     char AccurateValue[256]; 
     sprintf(AccurateValue, "%.10e", Event.elapsed_time);
 
@@ -65,7 +67,7 @@ bool JSON::GenerateRow(EventData Event, string &ResRow, const string& EndRowJSON
     }
     TimeSeries += "]" ;
 
-    string JSONrow = JSON::StartSubRow(Event.event_name) + "{" + FullElapsedTime + MeanElapsedTime + TimeSeries + EndRowJSON;
+    string JSONrow = JSON::StartSubRow(Event.event_name) + "{" + EventModeName + FullElapsedTime + MeanElapsedTime + TimeSeries + EndRowJSON;
     
     ResRow = JSONrow;
 
-- 
GitLab