diff --git a/.gitignore b/.gitignore
index ff11029e86a8bd343ea6ebeb5197a0ca466b366a..27129c2ec3ef95991386f20cf38d559130a237bc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,6 +9,7 @@ install/
 benchmark/cuda_kernels.cc
 # Ignore executables
 **/linktest
+!**/linktest/
 **/linktest.mpi
 **/linktest.tcp
 **/linktest.cuda
diff --git a/ImHex_Patterns/LinkTest_2-2-0_SIONlib_1-7-7.hexpat b/ImHex_Patterns/LinkTest_2-2-0_SIONlib_1-7-7.hexpat
new file mode 100644
index 0000000000000000000000000000000000000000..55c164a283793e0dd3b42dabd2cb94ebedcd1c3e
--- /dev/null
+++ b/ImHex_Patterns/LinkTest_2-2-0_SIONlib_1-7-7.hexpat
@@ -0,0 +1,221 @@
+#include <std/sys>
+#include <std/io>
+
+// Valid for LinkTest Version 2.2.0
+// Valid for SIONlib 1.7.7
+
+// ImHex Bugs:
+//     1: Attributes applied to an array do not inherit to its elements.
+//        This makes conversion of the displayed values in case of endinaness changes impossible.
+
+// TODO: Currently only works if there is only one SION block in total and one SION chunk per task.
+
+u64 offset;
+u64 numIter;
+bool bes; //If true SION headers are big endian
+bool bel; //If true LinkTest data is big-endian
+
+struct SION_Header_{
+    if(bes){
+        be u32 Version;
+        be u32 Patchlevel;
+        be u32 File_version;
+        be u32 Block_Size;
+        be u32 Num_Tasks;
+        be u32 Num_Files;
+        be u32 File_Num;
+    }else{
+        le u32 Version;
+        le u32 Patchlevel;
+        le u32 File_version;
+        le u32 Block_Size;
+        le u32 Num_Tasks;
+        le u32 Num_Files;
+        le u32 File_Num;
+    }
+    padding[16];
+    char Filename[1024];
+    if(bes){
+        be u64 GlobalRank[Num_Tasks];
+        be u64 Chunk_Size[Num_Tasks];
+        be u32 Max_Chunks;
+        be u64 Var_Start;
+    }else{
+        le u64 GlobalRank[Num_Tasks];
+        le u64 Chunk_Size[Num_Tasks];
+        le u32 Max_Chunks;
+        le u64 Var_Start;
+    }
+    if(Block_Size>1){
+        padding[Block_Size-$];
+    }
+};
+
+struct LinkTest_Header_{
+    if(bel){
+        be u32 Major_Version;
+        be u32 Minor_Version;
+        be u32 Patchlevel;
+    }else{
+        le u32 Major_Version;
+        le u32 Minor_Version;
+        le u32 Patchlevel;
+    }
+    char Git_Hash[41];
+    if(bel){
+        be u32 Mode_Length [[hidden]];
+    }else{
+        le u32 Mode_Length [[hidden]];
+    }
+    char Mode[Mode_Length];
+    u8   A2A_Flag;
+    u8   Bidirectional_Flag;
+    u8   Unidirectional_Flag;
+    u8   Bisection_Flag;
+    u8   Step_Randomization_Flag;
+    u8   Serialize_Testing_Flag;
+    u8   No_SION_File_Flag;
+    u8   Parallel_SION_File_Flag;
+    u8   GPU_Memory_Flag;
+    u8   Multi_Buffer_Flag;
+    u8   Randomized_Buffer_Flag;
+    u8   Check_Buffer_Flag;
+    u8   Group_Hostname_Flag;
+    u8   Memory_Allocator_Type;
+    u16  Padding;
+    u8   Padding2;
+    if(bel){
+        be u64 Num_Messages;
+        be u64 Size_Messages;
+        be u64 Num_WarmUp_Messages;
+        be u64 Num_Serial_Retests;
+        be u64 Num_Multi_Buffer;
+        be u64 Buffer_Randomization_Seed;
+        be u64 Num_Randomized_Task;
+        be u64 Task_Randomization_Seed;
+        be u64 Step_Randomization_Seed;
+    }else{
+        le u64 Num_Messages;
+        le u64 Size_Messages;
+        le u64 Num_WarmUp_Messages;
+        le u64 Num_Serial_Retests;
+        le u64 Num_Multi_Buffer;
+        le u64 Buffer_Randomization_Seed;
+        le u64 Num_Randomized_Task;
+        le u64 Task_Randomization_Seed;
+        le u64 Step_Randomization_Seed;
+    }
+    char END_HEADER[10] [[hidden]];
+    std::assert(END_HEADER=="END_HEADER","LinkTest header did not end with END_HEADER");
+};
+
+struct Host_{
+    if(bel){
+        be u32 Hostname_Length [[hidden,transform("Change_Endianness_u32")]];
+    }else{
+        le u32 Hostname_Length [[hidden]];
+    }
+    char Hostname[Hostname_Length];
+    if(bel){
+        be u32 Core_ID [[format("Format_Change_Endianness_u32"),transform("Change_Endianness_u32")]];
+    }else{
+        le u32 Core_ID;
+    }
+};
+
+struct IterationData_{
+    if(rank==0){
+        char Start_Time[32];
+        if(bel){
+            be double Minimum_Time [[format("Format_Change_Endianness_double"),transform("Change_Endianness_double")]];
+            be double Average_Time [[format("Format_Change_Endianness_double"),transform("Change_Endianness_double")]];
+            be double Maximum_Time [[format("Format_Change_Endianness_double"),transform("Change_Endianness_double")]];
+            if(LinkTest_Header.A2A_Flag){
+                be double A2A_Minimum_Time [[format("Format_Change_Endianness_double"),transform("Change_Endianness_double")]];
+                be double A2A_Average_Time [[format("Format_Change_Endianness_double"),transform("Change_Endianness_double")]];
+                be double A2A_Maximum_Time [[format("Format_Change_Endianness_double"),transform("Change_Endianness_double")]];
+            }
+            be double New_Retested_Timings[LinkTest_Header.Num_Serial_Retests] [[format("Format_Change_Endianness_double"),transform("Change_Endianness_double")]];
+            be double Old_Retested_Timings[LinkTest_Header.Num_Serial_Retests] [[format("Format_Change_Endianness_double"),transform("Change_Endianness_double")]];
+            be u64    Retests_From[LinkTest_Header.Num_Serial_Retests] [[format("Format_Change_Endianness_u64"),transform("Change_Endianness_u64")]];
+            be u64    Retests_To[LinkTest_Header.Num_Serial_Retests] [[format("Format_Change_Endianness_u64"),transform("Change_Endianness_u64")]];
+        }else{
+            le double Minimum_Time;
+            le double Average_Time;
+            le double Maximum_Time;
+            if(LinkTest_Header.A2A_Flag){
+                le double A2A_Minimum_Time;
+                le double A2A_Average_Time;
+                le double A2A_Maximum_Time;
+            }
+            le double New_Retested_Timings[LinkTest_Header.Num_Serial_Retests];
+            le double Old_Retested_Timings[LinkTest_Header.Num_Serial_Retests];
+            le u64    Retests_From[LinkTest_Header.Num_Serial_Retests];
+            le u64    Retests_To[LinkTest_Header.Num_Serial_Retests];
+        }
+        char End_Time[32];
+    }
+    if(bel){
+        be double Timings[SION_Header.Num_Tasks];
+        be u64    AccessPattern[SION_Header.Num_Tasks];
+        if(LinkTest_Header.A2A_Flag){
+            be double A2A_Time;
+        }
+    }else{
+        le double Timings[SION_Header.Num_Tasks];
+        le u64    AccessPattern[SION_Header.Num_Tasks];
+        if(LinkTest_Header.A2A_Flag){
+            le double A2A_Time;
+        }
+    }
+};
+
+struct Data_{
+    Host_          Host;
+    IterationData_ Data[numIter];
+    char           END_BLOCK[9] [[hidden]];
+    std::assert(END_BLOCK=="END_BLOCK","LinkTest per-rank data did not end with END_BLOCK");
+    rank=rank+1;
+};
+    
+char SION_String[4] @ 0x0 [[hidden]];
+std::assert(SION_String=="sion","File does not start with sion!");
+u8 Endianness_Flags[4] @ $ [[hidden]];
+offset=$;
+std::assert(Endianness_Flags[0]==Endianness_Flags[3],"Endianness Flag not for SIONlib data not symmetric");
+if(Endianness_Flags[0]==1){
+    bes=true;
+}else{
+    bes=false;
+}
+std::assert(Endianness_Flags[1]==Endianness_Flags[2],"Endianness Flag not for LinkTest data not symmetric");
+if(Endianness_Flags[1]==1){
+    bel=true;
+}else{
+    bel=false;
+}
+$=offset;
+SION_Header_     SION_Header     @ $ [[comment("SIONlib File Header"), name("SIONlib Header")]];
+offset=$;
+std::assert(SION_Header.Version==1007,"SION file not from SIONlib version 1.7.6 or 1.7.7!");
+std::assert(SION_Header.Patchlevel==7,"SION file not from SIONlib version 1.7.6 or 1.7.7!");
+std::assert(SION_Header.Num_Files==1,"No support for multi-file SIONlib data!");
+std::assert(SION_Header.Num_Files==1,"No support for multiple SION chunks!");
+$=offset;
+char             ID_String[8]    @ $ [[hidden]];
+offset=$;
+std::assert_warn(ID_String=="LinkTest","Failed to match LinkTest!");
+$=offset;
+LinkTest_Header_ LinkTest_Header @ $ [[comment("LinkTest File Header"), name("LinkTest Header")]];
+offset=$;
+std::assert_warn(LinkTest_Header.No_SION_File_Flag==0,"No-SION-File Flag set!");
+if(LinkTest_Header.Num_Randomized_Task!=0){
+    numIter=LinkTest_Header.Num_Randomized_Task;
+}else{
+    numIter=1;
+}
+u64 rank;
+$=offset;
+Data_ Data[SION_Header.Num_Tasks] @ $;
+
+
diff --git a/benchmark/benchmark.cc b/benchmark/benchmark.cc
index ddb78ec98fca4a2ba0a8b190636554f52b7ea027..0a45937fdeb76eecee60b003cda5301f93eeacc5 100644
--- a/benchmark/benchmark.cc
+++ b/benchmark/benchmark.cc
@@ -659,7 +659,9 @@ int Benchmark::retest_slow_pairs(slow_pair* const sp,const int n,const int iter)
         const int to   = sp[i].to;
 
         if (0 == rank()) {
-            std::printf(" %6d: Retest %6d  <->  %6d:", i, from, to);
+            const char*  from_host = cl->hostnamesAndRanks.hostForRank[from].c_str();
+            const char*  to_host = cl->hostnamesAndRanks.hostForRank[to].c_str();
+            std::printf(" %6d: Retest %6d (%s)  <->  %6d (%s):", i, from, from_host, to, to_host);
             std::fflush(stdout);
         }
 
@@ -839,9 +841,8 @@ int Benchmark::init() {
         randomNumberEngineSteps = std::mt19937(0);
     }
 
-    if(args->do_group_processes_by_hostname > 0) {
-        cl->getHostAndLocalRank();
-    }
+    // Run it always to gather hostname information
+    cl->getHostAndLocalRank();
 
     return SUCCESS;
 }
diff --git a/benchmark/cconfig.h b/benchmark/cconfig.h
index f8e6ca60a33b6e47b0c36245e96678d57713cc8e..3b2e4c091bba842d755abc9242b1961eb2711672 100644
--- a/benchmark/cconfig.h
+++ b/benchmark/cconfig.h
@@ -28,8 +28,8 @@
 #endif
 
 #define LINKTEST_VERSION 2
-#define LINKTEST_VERSION_SUB 1
-#define LINKTEST_VERSION_PATCHLEVEL 19
+#define LINKTEST_VERSION_SUB 2
+#define LINKTEST_VERSION_PATCHLEVEL 0
 #define GIT_HASH_LEN 41
 #ifndef GIT_HASH
     #define GIT_HASH "UNKNOWN"
diff --git a/benchmark/vcluster.cc b/benchmark/vcluster.cc
index 15f8dee60965f16eaabf6390725c6a71c25508da..722d39a7caa2b62259f250aa68797c83d2c4bc58 100644
--- a/benchmark/vcluster.cc
+++ b/benchmark/vcluster.cc
@@ -514,7 +514,7 @@ const std::string& VirtualCluster::get_vcluster_impl_name(char** argv, const std
     const std::string dot{"."};
     auto pos = executableName.find(dot);
     if(pos != std::string::npos) {
-        requestedImpl = executableName.substr(pos);
+        requestedImpl = executableName.substr(pos+1);
     }
 
     // Check environment
@@ -598,7 +598,10 @@ void VirtualCluster::getHostAndLocalRank(){
         for(int i=1;i<size();i++){
             int j=uhostnames.size()-1;
             for(;j>=0;j--){ //Iterate backwards as hostnames are likely to repeat
-                if(hostnames[i]!=uhostnames[j]) continue;
+                // Compare based on c strings to avoid mistmatches due to control characters
+                if(strcmp(hostnames[i].c_str(), uhostnames[j].c_str()) != 0){
+                    continue;
+                }
                 else{
                     ranks[j].push_back(i);
                     break;
@@ -614,14 +617,25 @@ void VirtualCluster::getHostAndLocalRank(){
         std::stringstream buf;
         for(std::vector<std::string>::size_type i=0;i<uhostnames.size();i++){
             buf << uhostnames[i].c_str() << ": " << ranks[i];
-            debug("[%3d] Ranks on %s", 0, buf.str().c_str());buf.str(std::string());
+            debug("[%3d] Ranks on %s", 0, buf.str().c_str());
+            buf.str(std::string());
         }
 #endif
         /******************************************************/
         /* Check that all hosts have the same number of ranks */
         /******************************************************/
-        if(ranks.size()%2!=0) fatal("An even number of hosts is required!");
-        for(std::vector<std::vector<int>>::size_type i=0;i<ranks.size();i++) if(ranks[0].size()!=ranks[i].size()) fatal("Hosts have differing amounts of ranks!");
+        // One host is allowed for intranode testing
+        if(ranks.size()%2 != 0 and ranks.size() != 1){
+            fatal("An even number of hosts is required!");
+        }
+        else if(size()%2 != 0){
+            fatal("An even number of ranks is required!");
+        }
+        for(std::vector<std::vector<int>>::size_type i=0;i<ranks.size();i++){
+            if(ranks[0].size()!=ranks[i].size()){
+                fatal("Hosts have differing amounts of ranks!");
+            }
+        }
 
         /**************************************/
         /* Broadcast information to all ranks */
@@ -661,6 +675,17 @@ void VirtualCluster::getHostAndLocalRank(){
             }
         }
         bcast(0, hostLocalRanks_.get(), buf64x4[0]*buf64x4[2]);
+
+        /*
+         * Fill in the hostnamesAndRanks struct to be queried later on
+         */
+        for(int rank = 0; rank < size(); rank++){
+            hostnamesAndRanks.hostForRank.push_back(hostnames[rank]);
+        }
+        for(std::vector<std::string>::size_type host=0;host<uhostnames.size();host++){
+            hostnamesAndRanks.ranksForHost.push_back(ranks[host]);
+        }
+
     }else{
         gather(0, &tmp32, &tmp32, 1); //Gather hostname lengths
         send(0, hostname().c_str(), hostnameSize());  //Send hostname
diff --git a/benchmark/vcluster.h b/benchmark/vcluster.h
index b516073ed5a576c26509ecadd8bbf8856843d8d4..d2c65e5f1f29e5a2d02a40b54699fe4e5d33b30f 100644
--- a/benchmark/vcluster.h
+++ b/benchmark/vcluster.h
@@ -73,6 +73,11 @@ public:
                  int               localRank()      ;
             std::shared_ptr<int[]> hostLocalRanks() ;
 
+    struct {
+        std::vector<std::string> hostForRank;
+        std::vector<std::vector<int>> ranksForHost;
+    } hostnamesAndRanks;
+
     /*! \brief send wrapped data in buf to rank dst (communication layer undefined)
     *
     * The data may or may not be routed through the communication layer of this cluster
diff --git a/exampleBuild.sh b/exampleBuild.sh
index 07eac176bef43da8c92c99383a71a8edbd992ba5..57fb799101170f26572c336cf67fc830fba516fb 100755
--- a/exampleBuild.sh
+++ b/exampleBuild.sh
@@ -13,7 +13,7 @@
 # Minipmi is already installed in ~/.local
 
 # Set-Up Environment
-ml GCC ParaStationMPI SIONlib SciPy-Stack;
+ml GCC OpenMPI SIONlib SciPy-Stack;
 
 # Use locallly installed minipmi, needed since we build with UCX and IBVerbs support
 export LIBRARY_PATH=$LIBRARY_PATH:~/.local/lib/;
@@ -28,7 +28,7 @@ make clean
 cd ..;
 # Install linktest-report
 # FIX for JSC Systems 
-#export CPATH=/p/software/<SYSTEM>/stages/2022/software/SciPy-bundle/2021.10-gcccoremkl-11.2.0-2021.4.0/lib/python3.9/site-packages/numpy/core/include:$CPATH
+#export CPATH=$EBROOTSCIPYMINBUNDLE/lib/python3*/site-packages/numpy/core/include:$CPATH
 cd install;
 python3 -m venv linktest-report-venv;
 source linktest-report-venv/bin/activate
diff --git a/python/linktest/linktest.c b/python/linktest/linktest.c
index c5640e03533223baa1f489609e456a3c86328d7e..2a22641df02f31100bf28f6ac12bb6bc430ff5b4 100644
--- a/python/linktest/linktest.c
+++ b/python/linktest/linktest.c
@@ -30,6 +30,7 @@
 #include <linktest_2_1_17.h>
 #include <linktest_2_1_18.h>
 #include <linktest_2_1_19.h>
+#include <linktest_2_2_0.h>
 
 /* TODO: Properly handle all possible errors.
  *       Current plan is only to handle errors
@@ -177,6 +178,13 @@ static PyObject* readSION(PyObject *self, PyObject *args){
 							err=1;
 					}
 					break;
+				case 2:
+					switch(version[2]){
+						case 0:
+							err=readImport_2_2_0(&fh,swap,version,&pyLinkTestInfo,&pyLinkTestData);
+							break;
+					}
+					break;
 				default:
 					PyErr_SetString(PyExc_RuntimeError, "Unsupported Version!");
 					err=1;
diff --git a/python/linktest/linktest_2_2_0.c b/python/linktest/linktest_2_2_0.c
new file mode 100644
index 0000000000000000000000000000000000000000..e5bed1d2688e24cf1d9f1ff7c45ff1285fc0361d
--- /dev/null
+++ b/python/linktest/linktest_2_2_0.c
@@ -0,0 +1,995 @@
+/****************************************************************************
+**  LinkTest                                                               **
+*****************************************************************************
+**  Copyright (c) 2008-2025                                                **
+**  Forschungszentrum Juelich, Juelich Supercomputing Centre               **
+**                                                                         **
+**  See the file COPYRIGHT in the package base directory for details       **
+****************************************************************************/
+
+#include <linktest_DoNotIncludeInMain.h>
+#include <linktest.h>
+#include <linktest_helper.h>
+
+/*********************************/
+/* Constant File-Scope Variables */
+/*********************************/
+#define LINKTEST_OUTPUT_DATETIME_LENGTH_2_2_0          32
+#define GIT_HASH_SIZE_2_2_0                            41
+#define LINKTEST_ID_STR_2_2_0                  "LinkTest"
+#define END_HEADER_2_2_0                     "END_HEADER"
+#define END_BLOCK_2_2_0                       "END_BLOCK"
+
+/**************/
+/* Structures */
+/**************/
+struct LinkTestInfo_2_2_0{                    //Description for LinkTest 2.2.0
+	char     hash[GIT_HASH_SIZE_2_2_0];  // LinkTest Git Hash
+	char    *mode;                        // Virtual-Cluster Implementation
+	int8_t   options[14];                 /* LinkTest Options
+	                                       * Unused in Version [1.X.X & 2.0.0]
+	                                       * options[ 0]: If non-zero all-to-all
+	                                       *              tests were performed at
+	                                       *              the beginning and end of
+	                                       *              each iteration.
+	                                       * options[ 1]: If non-zero bidirectional
+	                                       *              tests were performed.
+	                                       * options[ 2]: If non-zero unidirectional
+	                                       *              tests were performed.
+	                                       * options[ 3]: If non-zero bisection
+	                                       *              tests were performed.
+	                                       * options[ 4]: If non-zero steps were
+	                                       *              mixed before tests were
+	                                       *              performed.
+	                                       * options[ 5]: If non-zero main testing
+	                                       *              was performed in serial.
+	                                       * options[ 6]: If non-zero output was
+	                                       *              written to a SION file.
+	                                       *              Always non-zero since
+	                                       *              these options were
+	                                       *              written to a SION file.
+	                                       * options[ 7]: If non-zero the SION file
+	                                       *              was generated using
+	                                       *              parallelized output.
+	                                       * options[ 8]: If non-zero messages were
+	                                       *              sent from device memory,
+	                                       *              likely GPU memory.
+	                                       * options[ 9]: If non-zero multiple
+	                                       *              buffers were used.
+	                                       * options[10]: If non-zero the buffers
+	                                       *              were filled with pseudo-
+	                                       *              random numbers.
+	                                       * options[11]: If non-zero buffers were
+	                                       *              checked after each kernel
+	                                       *              run.
+	                                       * options[12]: If non-zero processes were
+	                                       *              grouped according to hostname
+	                                       *              and testing only occurred
+	                                       *              between groups.
+	                                       * options[13]: Memory allocator type:
+	                                       *                0: Invalid - ERROR
+	                                       *                1: Default - ERROR
+	                                       *                2: Memory-aligned Malloc
+	                                       *                3: Pinned-Memory Map
+	                                       *                4: POSIX Memory-aligned Malloc
+	                                       *                5: CUDA Malloc
+	                                       */
+	uint8_t   Padding[  3];                /* Padding that is added for at the moment unknown reasons */
+	uint64_t  iInfo[   9];                /* Auxiliary Integer Information
+	                                       * iInfo[   0]: The number of messages
+	                                       *              timings were averaged
+	                                       *              over.
+	                                       * iInfo[   1]: The message size sent
+	                                       *              between tasks.
+	                                       * iInfo[   2]: The number of warm-up
+	                                       *              messages sent before
+	                                       *              beginning timing.
+	                                       * iInfo[   3]: Number of serial retests
+	                                       * iInfo[   4]: Number of memory buffers
+	                                       *              if multiple memory
+	                                       *              buffers were used.
+	                                       * iInfo[   5]: MT_19937 seed for buffer
+	                                       *              randomization.. 
+	                                       * iInfo[   6]: If non-zero indicates the
+	                                       *              number of different task
+	                                       *              permutations used for
+	                                       *              averaging communication
+	                                       *              times.
+	                                       * iInfo[   7]: MT_19937 seed for task
+	                                       *              randomization.
+	                                       * iInfo[   8]: MT_19937 seed for step
+	                                       *              randomization.
+	                                       */
+};
+
+enum OPTIONS{
+	A2A________FLAG= 0,
+	BIDIR______FLAG= 1,
+	UNIDIR_____FLAG= 2,
+	BISECT_____FLAG= 3,
+	RAND_STEP__FLAG= 4,
+	SERIAL_____FLAG= 5,
+	SION_OUT___FLAG= 6,
+	SION_PAR___FLAG= 7,
+	DEVICE_MEM_FLAG= 8,
+	MULTI_BUF__FLAG= 9,
+	RAND_BUF___FLAG=10,
+	CHECK_BUF__FLAG=11,
+	GROUP_HOST_FLAG=12,
+	MEM_ALLOC__TYPE=13
+};
+
+enum INFO{
+	NUM_MESSAGES=0,
+	MESSAGE_SIZE=1,
+	NUM_WARM__UP=2,
+	NUM___SERIAL=3,
+	NUM__MEM_BUF=4,
+	MEM_BUF_SEED=5,
+	NUM_PERMUTAT=6,
+	PERMUTA_SEED=7,
+	STEP____SEED=8
+};
+
+/*****************************/
+/* Read LinkTest Information */
+/*****************************/
+int readInfo_2_2_0(struct SionFile* const fh, const int swap, const Version version, struct LinkTestInfo_2_2_0* const linkTestInfo){
+	const size_t end_header_len=sizeof(END_HEADER_2_2_0)/sizeof(char);
+	char end_header[end_header_len];
+	size_t n;
+	int32_t strSize;
+
+	/* Git Hash */
+	n=fread(linkTestInfo->hash, sizeof(char), GIT_HASH_SIZE_2_2_0, fh->fp);
+	if (UNLIKELY(n != GIT_HASH_SIZE_2_2_0)) {
+		PyErr_SetString(PyExc_RuntimeError, "readInfo_2_2_0: Failed to read git hash.");
+		return -1;
+	}
+	sion_swap(linkTestInfo->hash, linkTestInfo->hash, sizeof(char), GIT_HASH_SIZE_2_2_0, swap);
+	if (UNLIKELY(linkTestInfo->hash[0] == '\0')){
+		PyErr_SetString(PyExc_RuntimeError, "readInfo_2_2_0: NULL git hashes are not supported.");
+		return -1;
+	}
+	linkTestInfo->hash[GIT_HASH_SIZE_2_2_0-1]='\0'; //Make sure string is null terminated
+	#ifdef DEBUG_OUTPUT
+		printf("git hash                   =%s\n",linkTestInfo->hash);fflush(stdout);
+	#endif
+
+	/* Read Virtual Cluster Implementation */
+	n=fread(&strSize, sizeof(int32_t), 1, fh->fp);
+	if (UNLIKELY(n != 1)) {
+		PyErr_SetString(PyExc_RuntimeError, "readInfo_2_2_0: Failed to read string sizes for git hash, datetime and mode.");
+		return -1;
+	}
+	sion_swap(&strSize, &strSize, sizeof(int32_t), 1, swap);
+	linkTestInfo->mode=malloc(strSize*sizeof(char)); //TODO: Dangerous if sizeof(char) mismatches between writing and reading system.
+	n=fread(linkTestInfo->mode, sizeof(char), strSize, fh->fp);
+	if (UNLIKELY((int32_t)n != strSize)) {
+		PyErr_SetString(PyExc_RuntimeError, "readInfo_2_2_0: Failed to read virtual-cluster implementation.");
+		return -1;
+	}
+	sion_swap(linkTestInfo->mode, linkTestInfo->mode, sizeof(char), strSize, swap);
+	if (UNLIKELY(linkTestInfo->mode[0] == '\0')){
+		PyErr_SetString(PyExc_RuntimeError, "readInfo_2_2_0: Virtual-cluster implementation NULL is not supported.");
+		return -1;
+	}
+	linkTestInfo->mode[strSize-1]='\0'; //Add null terminator to string
+	#ifdef DEBUG_OUTPUT
+		printf("mode                       =%s\n",linkTestInfo->mode);fflush(stdout);
+	#endif
+
+	/* Read 32-bit Integer Options */
+	n=fread(linkTestInfo->options, sizeof(int8_t), 14, fh->fp);
+	if (UNLIKELY(n != 14)) {
+		PyErr_SetString(PyExc_RuntimeError, "readInfo_2_2_0: Failed to read 32-bit integer LinkTest options.");
+		return -1;
+	}
+	sion_swap(linkTestInfo->options, linkTestInfo->options, sizeof(int8_t), 14, swap);
+	#ifdef DEBUG_OUTPUT
+		printf("do_alltoall                =%" PRId8 "\n",linkTestInfo->options[A2A________FLAG]);
+		printf("do_bidir                   =%" PRId8 "\n",linkTestInfo->options[BIDIR______FLAG]);
+		printf("do_unidir                  =%" PRId8 "\n",linkTestInfo->options[UNIDIR_____FLAG]);
+		printf("do_bisection               =%" PRId8 "\n",linkTestInfo->options[BISECT_____FLAG]);
+		printf("do_mix                     =%" PRId8 "\n",linkTestInfo->options[RAND_STEP__FLAG]);
+		printf("do_serial                  =%" PRId8 "\n",linkTestInfo->options[SERIAL_____FLAG]);
+		printf("do_nosion                  =%" PRId8 "\n",linkTestInfo->options[SION_OUT___FLAG]);
+		printf("do_sion_par                =%" PRId8 "\n",linkTestInfo->options[SION_PAR___FLAG]);
+		printf("do_use_gpus                =%" PRId8 "\n",linkTestInfo->options[DEVICE_MEM_FLAG]);
+		printf("use_multi_buf              =%" PRId8 "\n",linkTestInfo->options[MULTI_BUF__FLAG]);
+		printf("randomize_buffers          =%" PRId8 "\n",linkTestInfo->options[RAND_BUF___FLAG]);
+		printf("check_buffers              =%" PRId8 "\n",linkTestInfo->options[CHECK_BUF__FLAG]);
+		printf("group_processes_by_hostname=%" PRId8 "\n",linkTestInfo->options[GROUP_HOST_FLAG]);
+		printf("memory allocator type      =%" PRId8 "\n",linkTestInfo->options[MEM_ALLOC__TYPE]);
+		fflush(stdout);
+	#endif
+
+	/* Read padding */
+	n=fread(linkTestInfo->options, sizeof(int8_t), 3, fh->fp);
+	if (UNLIKELY(n != 3)) {
+		PyErr_SetString(PyExc_RuntimeError, "readInfo_2_2_0: Failed to read padding.");
+		return -1;
+	}
+	/* Read 32-bit Integer Information */
+	n=fread(linkTestInfo->iInfo, sizeof(uint64_t), 9, fh->fp);
+	if (UNLIKELY(n != 9)) {
+		PyErr_SetString(PyExc_RuntimeError, "readInfo_2_2_0: Failed to read 32-bit integer LinkTest information.");
+		return -1;
+	}
+	sion_swap(linkTestInfo->iInfo, linkTestInfo->iInfo, sizeof(uint64_t), 9, swap);
+	#ifdef DEBUG_OUTPUT
+		printf("num_msg                    =%" PRIu64 "\n",linkTestInfo->iInfo[NUM_MESSAGES]);
+		printf("len_msg                    =%" PRIu64 "\n",linkTestInfo->iInfo[MESSAGE_SIZE]);
+		printf("num_warmup_msg             =%" PRIu64 "\n",linkTestInfo->iInfo[NUM_WARM__UP]);
+		printf("max_stest                  =%" PRIu64 "\n",linkTestInfo->iInfo[NUM___SERIAL]);
+		printf("num_multi_buf              =%" PRIu64 "\n",linkTestInfo->iInfo[NUM__MEM_BUF]);
+		printf("buf_mt_seed                =%" PRIu64 "\n",linkTestInfo->iInfo[MEM_BUF_SEED]);
+		printf("num_randomize_tasks        =%" PRIu64 "\n",linkTestInfo->iInfo[NUM_PERMUTAT]);
+		printf("seed_randomize_tasks       =%" PRIu64 "\n",linkTestInfo->iInfo[PERMUTA_SEED]);
+		printf("seed_randomize_steps       =%" PRIu64 "\n",linkTestInfo->iInfo[STEP____SEED]);
+		fflush(stdout);
+	#endif
+
+	/* Check If 0/1 Multiple Buffer Were Specified */
+	if(linkTestInfo->options[MULTI_BUF__FLAG] != 0){
+		if(linkTestInfo->iInfo[NUM__MEM_BUF] == 0){
+			PyErr_WarnEx(NULL,"Detected that multiple buffers were used, however, an unknown (0) number of buffers were used.\n ReadSION: The number of buffers used was likely equal to the number of messages. Interpret results with caution.",(Py_ssize_t )1);
+		}else if(linkTestInfo->iInfo[NUM__MEM_BUF] == 1){
+			PyErr_WarnEx(NULL,"Detected that multiple buffers were used, however, only one buffer was used.\n ReadSION: In this scenario multiple buffers should not have been used. Interpret results with caution.",(Py_ssize_t )1);
+		}
+	}
+
+	/* Check If Mersenne Twister Seed Is Zero */
+	if(linkTestInfo->options[RAND_BUF___FLAG] != 0 && linkTestInfo->iInfo[MEM_BUF_SEED] == 0){
+		PyErr_WarnEx(NULL,"Buffer content was to be randomized, however, the stored zero Mersenne Twister seed would have filled the buffers with zero. Interpret results with caution.",(Py_ssize_t )1);
+	}
+
+	/* Check END_HEADER String */
+	n=fread(end_header,sizeof(char),end_header_len-1,fh->fp);
+	if (UNLIKELY(n != end_header_len-1)){
+		PyErr_SetString(PyExc_RuntimeError, "readImportData_2_2_0: Failed to read END_HEADER string.");
+		return -1;
+	}
+	end_header[end_header_len-1]='\0';
+	if(UNLIKELY(strcmp(end_header,END_HEADER_2_2_0))){
+		PyErr_SetString(PyExc_RuntimeError, "readImportData_2_2_0: Alignment Error Detected. \"END_HEADER\" not found at the correct location.");
+		return -1;
+	}
+
+	return 0;
+}
+
+/*******************************************/
+/* Import LinkTest Information Into Python */
+/*******************************************/
+int importInfo_2_2_0(const Version version, struct LinkTestInfo_2_2_0* const linkTestInfo, PyObject* const* const pyLinkTestInfo){
+	int err;
+
+	// Allocator Type
+	enum AllocatorType{
+		AllocatorInvalid           =0, //Invalid                     Allocator - ERROR
+		AllocatorDefault           =1, //Default                     Allocator - ERROR
+		AllocatorAlignedMalloc     =2, //Memory-aligned malloc       Allocator
+		AllocatorPinnedMmap        =3, //Pinned--memory-map          Allocator
+		AllocatorPOSIXAlignedMalloc=4, //POSIX Memory-aligned malloc Allocator
+		AllocatorCUDA              =5  //CUDA malloc                 Allocator
+	};
+
+	/* Set LinkTest Version */
+	/* TODO: There is a potential bug here. %d is used for a digit type,
+	 * however this may be insufficiently long for 32-bit version numbers.
+	 * This can cause errors. Python, however, does not support the standard
+	 * C way of using PRId32.
+	 */
+	err=PyDict_SetItem(*pyLinkTestInfo,
+	                   PyUnicode_FromString("Version"),
+	                   PyUnicode_FromFormat("%d.%d.%d",version[0],version[1],version[2])
+	                  );
+	if(err){
+		PyErr_SetString(PyExc_RuntimeError,"importInfo_2_2_0: Failed to add Version to LinkTestInfo dictionary.");
+		return -1;
+	}
+
+	/* Set LinkTest Git Hash */
+	err=PyDict_SetItem(*pyLinkTestInfo,PyUnicode_FromString("Git hash"                                  ),PyUnicode_FromString(linkTestInfo->hash                ));
+	if(err){
+		PyErr_SetString(PyExc_RuntimeError,"importInfo_2_2_0: Failed to add hash to LinkTestInfo dictionary.");
+		return -1;
+	}
+
+	/* Set Virtual-Cluster Implementation */
+	err=PyDict_SetItem(*pyLinkTestInfo,PyUnicode_FromString("Mode"                                      ),PyUnicode_FromString(linkTestInfo->mode));
+	if(err){
+		PyErr_SetString(PyExc_RuntimeError,"importInfo_2_2_0: Failed to add mode to LinkTestInfo dictionary.");
+		return -1;
+	}
+	free(linkTestInfo->mode);
+
+	/* Set Options */
+	// NOTE: Casting to a long int from an int32_t to a long int should
+	// be safe since a long int on standard compliant compilers have a
+	// minimum size of 32 bytes.
+	err=PyDict_SetItem(*pyLinkTestInfo,PyUnicode_FromString("Test MPI all-to-all?"                      ),PyLong_FromLong((long int)linkTestInfo->options[A2A________FLAG]));
+	if(err){
+		PyErr_SetString(PyExc_RuntimeError,"importInfo_2_2_0: Failed to add doAlltoall to LinkTestInfo dictionary.");
+		return -1;
+	}
+	err=PyDict_SetItem(*pyLinkTestInfo,PyUnicode_FromString("Do bidirectional tests?"                   ),PyLong_FromLong((long int)linkTestInfo->options[BIDIR______FLAG]));
+	if(err){
+		PyErr_SetString(PyExc_RuntimeError,"importInfo_2_2_0: Failed to add doBidir to LinkTestInfo dictionary.");
+		return -1;
+	}
+	err=PyDict_SetItem(*pyLinkTestInfo,PyUnicode_FromString("Do unidirectional tests?"                  ),PyLong_FromLong((long int)linkTestInfo->options[UNIDIR_____FLAG]));
+	if(err){
+		PyErr_SetString(PyExc_RuntimeError,"importInfo_2_2_0: Failed to add doUnidir to LinkTestInfo dictionary.");
+		return -1;
+	}
+	err=PyDict_SetItem(*pyLinkTestInfo,PyUnicode_FromString("Do a bisection test?"                      ),PyLong_FromLong((long int)linkTestInfo->options[BISECT_____FLAG]));
+	if(err){
+		PyErr_SetString(PyExc_RuntimeError,"importInfo_2_2_0: Failed to add doBisec to LinkTestInfo dictionary.");
+		return -1;
+	}
+	err=PyDict_SetItem(*pyLinkTestInfo,PyUnicode_FromString("Randomize step order?"                     ),PyLong_FromLong((long int)linkTestInfo->options[RAND_STEP__FLAG]));
+	if(err){
+		PyErr_SetString(PyExc_RuntimeError,"importInfo_2_2_0: Failed to add doMix to LinkTestInfo dictionary.");
+		return -1;
+	}
+	err=PyDict_SetItem(*pyLinkTestInfo,PyUnicode_FromString("Test serially?"                            ),PyLong_FromLong((long int)linkTestInfo->options[SERIAL_____FLAG]));
+	if(err){
+		PyErr_SetString(PyExc_RuntimeError,"importInfo_2_2_0: Failed to add doSerial to LinkTestInfo dictionary.");
+		return -1;
+	}
+	err=PyDict_SetItem(*pyLinkTestInfo,PyUnicode_FromString("Do not store results in a SION file?"      ),PyLong_FromLong((long int)linkTestInfo->options[SION_OUT___FLAG]));
+	if(err){
+		PyErr_SetString(PyExc_RuntimeError,"importInfo_2_2_0: Failed to add doWrite to LinkTestInfo dictionary.");
+		return -1;
+	}
+	err=PyDict_SetItem(*pyLinkTestInfo,PyUnicode_FromString("Write SION output in parallel?"            ),PyLong_FromLong((long int)linkTestInfo->options[SION_PAR___FLAG]));
+	if(err){
+		PyErr_SetString(PyExc_RuntimeError,"importInfo_2_2_0: Failed to add doParallelIO to LinkTestInfo dictionary.");
+		return -1;
+	}
+	err=PyDict_SetItem(*pyLinkTestInfo,PyUnicode_FromString("Store messages in GPU memory?"             ),PyLong_FromLong((long int)linkTestInfo->options[DEVICE_MEM_FLAG]));
+	if(err){
+		PyErr_SetString(PyExc_RuntimeError,"importInfo_2_2_0: Failed to add useGPUs to LinkTestInfo dictionary.");
+		return -1;
+	}
+	err=PyDict_SetItem(*pyLinkTestInfo,PyUnicode_FromString("Use multiple memory buffers?"              ),PyLong_FromLong((long int)linkTestInfo->options[MULTI_BUF__FLAG]));
+	if(err){
+		PyErr_SetString(PyExc_RuntimeError,"importInfo_2_2_0: Failed to add use_multi_buf to LinkTestInfo dictionary.");
+		return -1;
+	}
+	err=PyDict_SetItem(*pyLinkTestInfo,PyUnicode_FromString("Randomize memory-buffer content?"          ),PyLong_FromLong((long int)linkTestInfo->options[RAND_BUF___FLAG]));
+	if(err){
+		PyErr_SetString(PyExc_RuntimeError,"importInfo_2_2_0: Failed to add randomize_buffers to LinkTestInfo dictionary.");
+		return -1;
+	}
+	err=PyDict_SetItem(*pyLinkTestInfo,PyUnicode_FromString("Check memory-buffer content?"              ),PyLong_FromLong((long int)linkTestInfo->options[CHECK_BUF__FLAG]));
+	if(err){
+		PyErr_SetString(PyExc_RuntimeError,"importInfo_2_2_0: Failed to add check_buffers to LinkTestInfo dictionary.");
+		return -1;
+	}
+	err=PyDict_SetItem(*pyLinkTestInfo,PyUnicode_FromString("Group processes according to hostname?"    ),PyLong_FromLong((long int)linkTestInfo->options[GROUP_HOST_FLAG]));
+	if(err){
+		PyErr_SetString(PyExc_RuntimeError,"importInfo_2_2_0: Failed to add check_buffers to LinkTestInfo dictionary.");
+		return -1;
+	}
+	switch(linkTestInfo->options[MEM_ALLOC__TYPE]){
+		case AllocatorInvalid:
+			err=PyDict_SetItem(*pyLinkTestInfo,PyUnicode_FromString("Allocator type"),PyUnicode_FromString("Invalid - ERROR"            ));
+			break;
+		case AllocatorDefault:
+			err=PyDict_SetItem(*pyLinkTestInfo,PyUnicode_FromString("Allocator type"),PyUnicode_FromString("Default - ERROR"            ));
+			break;
+		case AllocatorAlignedMalloc:
+			err=PyDict_SetItem(*pyLinkTestInfo,PyUnicode_FromString("Allocator type"),PyUnicode_FromString("Memory-aligned malloc"      ));
+			break;
+		case AllocatorPinnedMmap:
+			err=PyDict_SetItem(*pyLinkTestInfo,PyUnicode_FromString("Allocator type"),PyUnicode_FromString("Pinned memory-map"         ));
+			break;
+		case AllocatorPOSIXAlignedMalloc:
+			err=PyDict_SetItem(*pyLinkTestInfo,PyUnicode_FromString("Allocator type"),PyUnicode_FromString("POSIX memory-aligned malloc"));
+			break;
+		case AllocatorCUDA:
+			err=PyDict_SetItem(*pyLinkTestInfo,PyUnicode_FromString("Allocator type"),PyUnicode_FromString("CUDA malloc"                ));
+			break;
+		default:
+			err=PyDict_SetItem(*pyLinkTestInfo,PyUnicode_FromString("Allocator type"),PyUnicode_FromString("UNKNOWN"                    ));
+			break;
+	}
+		if(err){
+		PyErr_SetString(PyExc_RuntimeError,"importInfo_2_2_0: Failed to add memory-buffer allocator to LinkTestInfo dictionary.");
+		return -1;
+	}
+
+	/* Set Integer Information */
+	err=PyDict_SetItem(*pyLinkTestInfo,PyUnicode_FromString("Number of messages"                        ),PyLong_FromLong((long int)linkTestInfo->iInfo[NUM_MESSAGES]));
+	if(err){
+		PyErr_SetString(PyExc_RuntimeError,"importInfo_2_2_0: Failed to add numberOfMessages to LinkTestInfo dictionary.");
+		return -1;
+	}
+	err=PyDict_SetItem(*pyLinkTestInfo,PyUnicode_FromString("Message size"                              ),PyLong_FromLong((long int)linkTestInfo->iInfo[MESSAGE_SIZE]));
+	if(err){
+		PyErr_SetString(PyExc_RuntimeError,"importInfo_2_2_0: Failed to add lengthOfMessages to LinkTestInfo dictionary.");
+		return -1;
+	}
+	err=PyDict_SetItem(*pyLinkTestInfo,PyUnicode_FromString("Number of warm-up messages"                ),PyLong_FromLong((long int)linkTestInfo->iInfo[NUM_WARM__UP]));
+	if(err){
+		PyErr_SetString(PyExc_RuntimeError,"importInfo_2_2_0: Failed to add numberOfWarmUpMessages to LinkTestInfo dictionary.");
+		return -1;
+	}
+	err=PyDict_SetItem(*pyLinkTestInfo,PyUnicode_FromString("Number of serial retests"                  ),PyLong_FromLong((long int)linkTestInfo->iInfo[NUM___SERIAL]));
+	if(err){
+		PyErr_SetString(PyExc_RuntimeError,"importInfo_2_2_0: Failed to add numberOfSerialRetests to LinkTestInfo dictionary.");
+		return -1;
+	}
+	if(linkTestInfo->options[MULTI_BUF__FLAG]){
+		err=PyDict_SetItem(*pyLinkTestInfo,PyUnicode_FromString("Number of multiple buffers"       ),PyLong_FromLong((long int)linkTestInfo->iInfo[NUM__MEM_BUF]));
+		if(err){
+			PyErr_SetString(PyExc_RuntimeError,"importInfo_2_2_0: Failed to add num_multi_buf to LinkTestInfo dictionary.");
+			return -1;
+		}
+	}
+	if(linkTestInfo->options[RAND_BUF___FLAG]){
+		err=PyDict_SetItem(*pyLinkTestInfo,PyUnicode_FromString("Buffer Mersenne Twister seed"     ),PyLong_FromLong((long int)linkTestInfo->iInfo[MEM_BUF_SEED]));
+		if(err){
+			PyErr_SetString(PyExc_RuntimeError,"importInfo_2_2_0: Failed to add buf_mt_seed to LinkTestInfo dictionary.");
+			return -1;
+		}
+	}
+	err=PyDict_SetItem(*pyLinkTestInfo,PyUnicode_FromString("Number of tests with randomized rank order"),PyLong_FromLong((long int)linkTestInfo->iInfo[NUM_PERMUTAT]));
+	if(err){
+		PyErr_SetString(PyExc_RuntimeError,"importInfo_2_2_0: Failed to add num_randomize_tasks to LinkTestInfo dictionary.");
+		return -1;
+	}
+	if(linkTestInfo->iInfo[NUM_PERMUTAT]){
+		err=PyDict_SetItem(*pyLinkTestInfo,PyUnicode_FromString("Seed for rank-order randomization"),PyLong_FromLong((long int)linkTestInfo->iInfo[PERMUTA_SEED]));
+		if(err){
+			PyErr_SetString(PyExc_RuntimeError,"importInfo_2_2_0: Failed to add seed_randomize_tasks to LinkTestInfo dictionary.");
+			return -1;
+		}
+	}
+	if(linkTestInfo->options[RAND_STEP__FLAG]){
+		err=PyDict_SetItem(*pyLinkTestInfo,PyUnicode_FromString("Seed for step-order randomization"),PyLong_FromLong((long int)linkTestInfo->iInfo[STEP____SEED]));
+		if(err){
+			PyErr_SetString(PyExc_RuntimeError,"importInfo_2_2_0: Failed to add seed_randomize_steps to LinkTestInfo dictionary.");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+/*******************************/
+/* Read & Import LinkTest Data */
+/*******************************/
+int readImportData_2_2_0(struct SionFile* const fh, const int swap, struct LinkTestInfo_2_2_0* const linkTestInfo, PyObject* const* const pyLinkTestInfo, PyObject** pyLinkTestData){
+	const size_t end_block_len=sizeof(END_BLOCK_2_2_0)/sizeof(char);
+	char end_block[end_block_len];
+	int err;
+	int32_t rank, hostname_len;
+	size_t n;
+	size_t i;
+	char* hostname;
+	npy_intp len[2];
+	void *ptr;
+
+	const size_t num_iterations     =(linkTestInfo->iInfo[NUM_PERMUTAT]>1)?(size_t)linkTestInfo->iInfo[NUM_PERMUTAT]:1;
+	const size_t numMinMaxAvgTimings=(linkTestInfo->options[A2A________FLAG]!=0)?6:3;
+	      double minMaxAvgTimings[num_iterations*numMinMaxAvgTimings];
+
+	//TODO: Handle Errors
+
+	/* Set Python Array Sizes */
+	len[0] = fh->size;
+	len[1] = fh->size;
+
+	/* Initialize Hostnames & Core IDs */
+	PyObject* const pyHosts = PyList_New((Py_ssize_t)fh->size);
+	PyObject* const pyCore  = NewNumericPyArray(NPY_INT, 1, len);
+
+	/* Initialize Start & End Time Strings */
+	PyObject** const pyStartTime=(PyObject**)malloc(num_iterations*sizeof(PyObject));
+	for(i=0;i<num_iterations;i++) pyStartTime[i]=PyDict_New();
+	PyObject** const pyEndTime  =(PyObject**)malloc(num_iterations*sizeof(PyObject));
+	for(i=0;i<num_iterations;i++) pyEndTime[i]  =PyDict_New();
+
+	/* Initialize Timings, Access Pattern & All-To-All Timings */
+	PyObject** const pyTimings      =(PyObject**)malloc(num_iterations*sizeof(PyObject));
+	for(i=0;i<num_iterations;i++) pyTimings[i]      =NewNumericPyArray(NPY_DOUBLE,2,len); //A python double-precision floating-point array of the LinkTest point-to-point timings
+	PyObject** const pyAccesspattern=(PyObject**)malloc(num_iterations*sizeof(PyObject));
+	for(i=0;i<num_iterations;i++) pyAccesspattern[i]=NewNumericPyArray(NPY_UINT64,2,len); //A python integer array indicating the access order
+	PyObject** const pyA2ATimings   =(linkTestInfo->options[A2A________FLAG]!=0)?(PyObject**)malloc(num_iterations*sizeof(PyObject)):NULL; //Silences maybe-used-uninitialized warning
+	if(linkTestInfo->options[A2A________FLAG]!=0) for(i=0;i<num_iterations;i++) pyA2ATimings[i]   =NewNumericPyArray(NPY_DOUBLE, 1, len); //A python double-precision floating-point array of the linkTest all-to-all imings
+
+	/* Initialize Serial Retest Timings */
+	len[0] = linkTestInfo->iInfo[NUM___SERIAL];
+	PyObject** const pySerialTimingsNew=(len[0]>0)?(PyObject**)malloc(num_iterations*sizeof(PyObject)):NULL;
+	if(len[0]>0) for(i=0;i<num_iterations;i++) pySerialTimingsNew[i] = NewNumericPyArray(NPY_DOUBLE, 1, len);
+	PyObject** const pySerialTimingsOld=(len[0]>0)?(PyObject**)malloc(num_iterations*sizeof(PyObject)):NULL;
+	if(len[0]>0) for(i=0;i<num_iterations;i++) pySerialTimingsOld[i] = NewNumericPyArray(NPY_DOUBLE, 1, len);
+	PyObject** const pySerialFrom      =(len[0]>0)?(PyObject**)malloc(num_iterations*sizeof(PyObject)):NULL;
+	if(len[0]>0) for(i=0;i<num_iterations;i++) pySerialFrom[i]       = NewNumericPyArray(NPY_UINT64, 1, len);
+	PyObject** const pySerialTo        =(len[0]>0)?(PyObject**)malloc(num_iterations*sizeof(PyObject)):NULL;
+	if(len[0]>0) for(i=0;i<num_iterations;i++) pySerialTo[i]         = NewNumericPyArray(NPY_UINT64, 1, len);
+
+	for (rank = 0; rank < fh->size; ++rank) { //Loop over the ranks, each one was saved to its own chunk
+		/* Read Host Name (Multiple Tasks May Have The Same Host Name */
+		n=fread(&hostname_len, sizeof(uint32_t), 1, fh->fp);
+		if (UNLIKELY(n != 1)) {
+			PyErr_SetString(PyExc_RuntimeError, "readImportData_2_2_0: Failed to read/import hostname length.");
+			return -1;
+		}
+		sion_swap(&hostname_len, &hostname_len, sizeof(uint32_t), 1, swap);
+		hostname=(char*)malloc(hostname_len*sizeof(char));
+		n=fread(hostname, sizeof(char), hostname_len, fh->fp);
+		if (UNLIKELY((int32_t)n != hostname_len)) {
+			PyErr_SetString(PyExc_RuntimeError, "readImportData_2_2_0: Failed to read/import Hostname.");
+			return -1;
+		}
+		sion_swap(&hostname, &hostname, sizeof(char), 1, swap);
+		#ifdef DEBUG_OUTPUT
+			printf("Hostname[%d]                =%s\n",rank,hostname);fflush(stdout);
+		#endif
+		PyList_SET_ITEM(pyHosts,(Py_ssize_t)rank,PyBytes_FromStringAndSize(hostname,(Py_ssize_t)hostname_len));
+		/* Read Pinned-Core ID */
+		ptr=PyArray_GETPTR1((PyArrayObject *)pyCore, rank);
+		n=fread(ptr, sizeof(int32_t), 1, fh->fp);
+		if (UNLIKELY(n != 1)) {
+			PyErr_SetString(PyExc_RuntimeError, "readImportData_2_2_0: Failed to read/import Pinned Core ID.");
+			return -1;
+		}
+		sion_swap(ptr, ptr, sizeof(int32_t), 1, swap);
+		#ifdef DEBUG_OUTPUT
+			printf("cpuID[%d]                   =%d\n",rank,*(int32_t*)ptr);fflush(stdout);
+		#endif
+
+		for(i=0;i<num_iterations;i++){
+			if(rank==0){
+				/* Read Start Time */
+				char datetime_string[LINKTEST_OUTPUT_DATETIME_LENGTH_2_2_0+1]; //TODO: Dangerous if sizeof(char) mismatches between writing and reading system.
+				n=fread(datetime_string, sizeof(char), LINKTEST_OUTPUT_DATETIME_LENGTH_2_2_0, fh->fp);
+				if (UNLIKELY(n != LINKTEST_OUTPUT_DATETIME_LENGTH_2_2_0)) {
+					PyErr_SetString(PyExc_RuntimeError, "readInfo_2_2_0: Failed to read startDatetime.");
+					return -1;
+				}
+				sion_swap(datetime_string, datetime_string, sizeof(char), LINKTEST_OUTPUT_DATETIME_LENGTH_2_2_0, swap);
+				if (UNLIKELY(datetime_string[0] == '\0')){
+					PyErr_SetString(PyExc_RuntimeError, "readInfo_2_2_0: startDatetime NULL is not supported.");
+					return -1;
+				}
+				datetime_string[LINKTEST_OUTPUT_DATETIME_LENGTH_2_2_0]='\0'; //Ensure string is null terminated
+				#ifdef DEBUG_OUTPUT
+					printf("startDatetime[0,%zu]          =%s",i,datetime_string);
+					fflush(stdout);
+				#endif
+				struct Datetime startDatetime;
+				n=sscanf(datetime_string,
+						"%2"SCNu8"/%2"SCNu8"/%"SCNu64" %2"SCNu8":%2"SCNu8":%2"SCNu8" UTC+0",
+						&startDatetime.day,
+						&startDatetime.month,
+						&startDatetime.year,
+						&startDatetime.hour,
+						&startDatetime.minute,
+						&startDatetime.second
+						);
+				if (UNLIKELY(n!=6)){
+					PyErr_SetString(PyExc_RuntimeError, "readInfo_2_2_0: startDatetime is not a correctly formatted string.");
+					return -1;
+				}
+				#ifdef DEBUG_OUTPUT
+					printf("startDatetime.year[0,%zu]    =%" PRIu64 "\n",i,startDatetime.year  );
+					printf("startDatetime.month[0,%zu]   =%" PRIu8  "\n",i,startDatetime.month );
+					printf("startDatetime.day[0,%zu]     =%" PRIu8  "\n",i,startDatetime.day   );
+					printf("startDatetime.hour[0,%zu]    =%" PRIu8  "\n",i,startDatetime.hour  );
+					printf("startDatetime.minute[0,%zu]  =%" PRIu8  "\n",i,startDatetime.minute);
+					printf("startDatetime.second[0,%zu]  =%" PRIu8  "\n",i,startDatetime.second);
+					printf("startDatetime.timezone[0,%zu]=UTC+0\n"     ,i                      );
+					fflush(stdout);
+				#endif
+				/* Import Start Time */
+				err=PyDict_SetItem(pyStartTime[i],PyUnicode_FromString("Year"    ),PyLong_FromLong((long int)startDatetime.year  ));
+				if(err){//TODO: Add iteration index to error message
+					PyErr_SetString(PyExc_RuntimeError,"importInfo_2_2_0: Failed to add DateTime_year to pyStartTime dictionary.");
+					return -1;
+				}
+				err=PyDict_SetItem(pyStartTime[i],PyUnicode_FromString("Month"   ),PyLong_FromLong((long int)startDatetime.month ));
+				if(err){
+					PyErr_SetString(PyExc_RuntimeError,"importInfo_2_2_0: Failed to add DateTime_month to pyStartTime dictionary.");
+					return -1;
+				}
+				err=PyDict_SetItem(pyStartTime[i],PyUnicode_FromString("Day"     ),PyLong_FromLong((long int)startDatetime.day   ));
+				if(err){
+					PyErr_SetString(PyExc_RuntimeError,"importInfo_2_2_0: Failed to add DateTime_day to pyStartTime dictionary.");
+					return -1;
+				}
+				err=PyDict_SetItem(pyStartTime[i],PyUnicode_FromString("Hour"    ),PyLong_FromLong((long int)startDatetime.hour  ));
+				if(err){
+					PyErr_SetString(PyExc_RuntimeError,"importInfo_2_2_0: Failed to add DateTime_hour to pyStartTime dictionary.");
+					return -1;
+				}
+				err=PyDict_SetItem(pyStartTime[i],PyUnicode_FromString("Minute"  ),PyLong_FromLong((long int)startDatetime.minute));
+				if(err){
+					PyErr_SetString(PyExc_RuntimeError,"importInfo_2_2_0: Failed to add DateTime_minute to pyStartTime dictionary.");
+					return -1;
+				}
+				err=PyDict_SetItem(pyStartTime[i],PyUnicode_FromString("Second"  ),PyLong_FromLong((long int)startDatetime.second));
+				if(err){
+					PyErr_SetString(PyExc_RuntimeError,"importInfo_2_2_0: Failed to add DateTime_second to pyStartTime dictionary.");
+					return -1;
+				}
+				err=PyDict_SetItem(pyStartTime[i],PyUnicode_FromString("Timezone"),PyUnicode_FromFormat("UTC+0"));
+				if(err){
+					PyErr_SetString(PyExc_RuntimeError,"importInfo_2_2_0: Failed to add DateTime_timezone to pyStartTime dictionary.");
+					return -1;
+				}
+				/* Read Minimum, Maximum & Average LinkTest Timings */
+				n=fread(&minMaxAvgTimings[i*numMinMaxAvgTimings], sizeof(double), numMinMaxAvgTimings, fh->fp);
+				if (UNLIKELY(n != numMinMaxAvgTimings)) {
+					PyErr_SetString(PyExc_RuntimeError, "readInfo_2_2_0: Failed to read minimum, maximum & average LinkTest timings.");
+					return -1;
+				}
+				sion_swap(minMaxAvgTimings, minMaxAvgTimings, sizeof(double), numMinMaxAvgTimings, swap);
+				#ifdef DEBUG_OUTPUT
+					printf("min_time[0,%zu]              =%e\n",i,minMaxAvgTimings[i*numMinMaxAvgTimings+0]);
+					printf("max_time[0,%zu]              =%e\n",i,minMaxAvgTimings[i*numMinMaxAvgTimings+1]);
+					printf("avg_time[0,%zu]              =%e\n",i,minMaxAvgTimings[i*numMinMaxAvgTimings+2]);
+					if(numMinMaxAvgTimings==6){
+						printf("min_time_a2a[0,%zu]          =%e\n",i,minMaxAvgTimings[i*numMinMaxAvgTimings+3]);
+						printf("max_time_a2a[0,%zu]          =%e\n",i,minMaxAvgTimings[i*numMinMaxAvgTimings+4]);
+						printf("avg_time_a2a[0,%zu]          =%e\n",i,minMaxAvgTimings[i*numMinMaxAvgTimings+5]);
+					}
+					fflush(stdout);
+				#endif
+				/* Read Serial Retest Data */
+				if (linkTestInfo->iInfo[NUM___SERIAL]>0){
+					/* Read New Serially Retested Timings */
+					ptr=PyArray_GETPTR1((PyArrayObject *)pySerialTimingsNew[i], 0);
+					n=fread(ptr, sizeof(double  ), linkTestInfo->iInfo[NUM___SERIAL], fh->fp);
+					if (UNLIKELY((uint64_t)n != linkTestInfo->iInfo[NUM___SERIAL])) {
+						PyErr_SetString(PyExc_RuntimeError, "readImportData_2_2_0: Failed to read/import retested serial timings.");
+						return -1;
+					}
+					sion_swap(ptr, ptr, sizeof(double  ), linkTestInfo->iInfo[NUM___SERIAL], swap);
+					#ifdef DEBUG_OUTPUT
+						printf("serialTimingsNew[0,%zu]       =%f",i,((double*)ptr)[0]);
+						for(n=1;(uint64_t)n<linkTestInfo->iInfo[NUM___SERIAL];n++) printf(",%f",((double*)ptr)[n]);
+						printf("\n");
+						fflush(stdout);
+					#endif
+					/* Read Old Serially Retested Timings */
+					ptr=PyArray_GETPTR1((PyArrayObject *)pySerialTimingsOld[i], 0);
+					n=fread(ptr, sizeof(double  ), linkTestInfo->iInfo[NUM___SERIAL], fh->fp);
+					if (UNLIKELY((uint64_t)n != linkTestInfo->iInfo[NUM___SERIAL])) {
+						PyErr_SetString(PyExc_RuntimeError, "readImportData_2_2_0: Failed to read/import retest-needed timings.");
+						return -1;
+					}
+					sion_swap(ptr, ptr, sizeof(double  ), linkTestInfo->iInfo[NUM___SERIAL], swap);
+					#ifdef DEBUG_OUTPUT
+						printf("serialTimingsOld[0,%zu]       =%f",i,((double*)ptr)[0]);
+						for(n=1;(uint64_t)n<linkTestInfo->iInfo[NUM___SERIAL];n++) printf(",%f",((double*)ptr)[n]);
+						printf("\n");
+						fflush(stdout);
+					#endif
+					/* Read Origin Partner For Serial Retests */
+					ptr=PyArray_GETPTR1((PyArrayObject *)pySerialFrom[i]      , 0);
+					n=fread(ptr, sizeof(uint64_t), linkTestInfo->iInfo[NUM___SERIAL], fh->fp);
+					if (UNLIKELY((uint64_t)n != linkTestInfo->iInfo[NUM___SERIAL])) {
+						PyErr_SetString(PyExc_RuntimeError, "readImportData_2_2_0: Failed to read/import serial retest origin.");
+						return -1;
+					}
+					#ifdef DEBUG_OUTPUT
+						printf("serialTimingsFrom[0,%zu]      =%d",i,((uint64_t*)ptr)[0]);
+						for(n=1;(uint64_t)n<linkTestInfo->iInfo[NUM___SERIAL];n++) printf(",%"PRIu64,((uint64_t*)ptr)[n]);
+						printf("\n");
+						fflush(stdout);
+					#endif
+					sion_swap(ptr, ptr, sizeof(uint64_t), linkTestInfo->iInfo[NUM___SERIAL], swap);
+					/* Read Destination Partner For Serial Retests */
+					ptr=PyArray_GETPTR1((PyArrayObject *)pySerialTo[i]        , 0);
+					n=fread(ptr, sizeof(uint64_t), linkTestInfo->iInfo[NUM___SERIAL], fh->fp);
+					if (UNLIKELY((uint64_t)n != linkTestInfo->iInfo[NUM___SERIAL])) {
+						PyErr_SetString(PyExc_RuntimeError, "readImportData_2_2_0: Failed to read/import serial retest destination.");
+						return -1;
+					}
+					sion_swap(ptr, ptr, sizeof(uint64_t), linkTestInfo->iInfo[NUM___SERIAL], swap);
+					#ifdef DEBUG_OUTPUT
+						printf("serialTimingsTo[0,%zu]        =%d",i,((uint64_t*)ptr)[0]);
+						for(n=1;(uint64_t)n<linkTestInfo->iInfo[NUM___SERIAL];n++) printf(",%"PRIu64,((uint64_t*)ptr)[n]);
+						printf("\n");
+						fflush(stdout);
+					#endif
+				}
+				/* Read End Time */
+				n=fread(datetime_string, sizeof(char), LINKTEST_OUTPUT_DATETIME_LENGTH_2_2_0, fh->fp);
+				if (UNLIKELY(n != LINKTEST_OUTPUT_DATETIME_LENGTH_2_2_0)) {
+					PyErr_SetString(PyExc_RuntimeError, "readInfo_2_2_0: Failed to read endDatetime.");
+					return -1;
+				}
+				sion_swap(datetime_string, datetime_string, sizeof(char), LINKTEST_OUTPUT_DATETIME_LENGTH_2_2_0, swap);
+				if (UNLIKELY(datetime_string[0] == '\0')){
+					PyErr_SetString(PyExc_RuntimeError, "readInfo_2_2_0: endDatetime NULL is not supported.");
+					return -1;
+				}
+				datetime_string[LINKTEST_OUTPUT_DATETIME_LENGTH_2_2_0]='\0'; //Ensure string is null terminated
+				#ifdef DEBUG_OUTPUT
+					printf("endDatetime[0,%zu]            =%s",i,datetime_string);
+					fflush(stdout);
+				#endif
+				struct Datetime endDatetime;
+				n=sscanf(datetime_string,
+						"%2"SCNu8"/%2"SCNu8"/%"SCNu64" %2"SCNu8":%2"SCNu8":%2"SCNu8" UTC+0",
+						&endDatetime.day,
+						&endDatetime.month,
+						&endDatetime.year,
+						&endDatetime.hour,
+						&endDatetime.minute,
+						&endDatetime.second
+						);
+				if (UNLIKELY(n!=6)){
+					PyErr_SetString(PyExc_RuntimeError, "readInfo_2_2_0: endDatetime is not a correctly formatted string.");
+					return -1;
+				}
+				#ifdef DEBUG_OUTPUT
+					printf("endDatetime.year[0,%zu]      =%" PRIu64 "\n",i,endDatetime.year  );
+					printf("endDatetime.month[0,%zu]     =%" PRIu8  "\n",i,endDatetime.month );
+					printf("endDatetime.day[0,%zu]       =%" PRIu8  "\n",i,endDatetime.day   );
+					printf("endDatetime.hour[0,%zu]      =%" PRIu8  "\n",i,endDatetime.hour  );
+					printf("endDatetime.minute[0,%zu]    =%" PRIu8  "\n",i,endDatetime.minute);
+					printf("endDatetime.second[0,%zu]    =%" PRIu8  "\n",i,endDatetime.second);
+					printf("endDatetime.timezone[0,%zu]  =UTC+0\n"     ,i                    );
+					fflush(stdout);
+				#endif
+				/* Import End Time */
+				err=PyDict_SetItem(pyEndTime[i],PyUnicode_FromString("Year"    ),PyLong_FromLong((long int)endDatetime.year  ));
+				if(err){//TODO: Add iteration index to error message
+					PyErr_SetString(PyExc_RuntimeError,"importInfo_2_2_0: Failed to add DateTime_year to pyEndTime dictionary.");
+					return -1;
+				}
+				err=PyDict_SetItem(pyEndTime[i],PyUnicode_FromString("Month"   ),PyLong_FromLong((long int)endDatetime.month ));
+				if(err){
+					PyErr_SetString(PyExc_RuntimeError,"importInfo_2_2_0: Failed to add DateTime_month to pyEndTime dictionary.");
+					return -1;
+				}
+				err=PyDict_SetItem(pyEndTime[i],PyUnicode_FromString("Day"     ),PyLong_FromLong((long int)endDatetime.day   ));
+				if(err){
+					PyErr_SetString(PyExc_RuntimeError,"importInfo_2_2_0: Failed to add DateTime_day to pyEndTime dictionary.");
+					return -1;
+				}
+				err=PyDict_SetItem(pyEndTime[i],PyUnicode_FromString("Hour"    ),PyLong_FromLong((long int)endDatetime.hour  ));
+				if(err){
+					PyErr_SetString(PyExc_RuntimeError,"importInfo_2_2_0: Failed to add DateTime_hour to pyEndTime dictionary.");
+					return -1;
+				}
+				err=PyDict_SetItem(pyEndTime[i],PyUnicode_FromString("Minute"  ),PyLong_FromLong((long int)endDatetime.minute));
+				if(err){
+					PyErr_SetString(PyExc_RuntimeError,"importInfo_2_2_0: Failed to add DateTime_minute to pyEndTime dictionary.");
+					return -1;
+				}
+				err=PyDict_SetItem(pyEndTime[i],PyUnicode_FromString("Second"  ),PyLong_FromLong((long int)endDatetime.second));
+				if(err){
+					PyErr_SetString(PyExc_RuntimeError,"importInfo_2_2_0: Failed to add DateTime_second to pyEndTime dictionary.");
+					return -1;
+				}
+				err=PyDict_SetItem(pyEndTime[i],PyUnicode_FromString("Timezone"),PyUnicode_FromFormat("UTC+0"));
+				if(err){
+					PyErr_SetString(PyExc_RuntimeError,"importInfo_2_2_0: Failed to add DateTime_timezone to pyEndTime dictionary.");
+					return -1;
+				}
+			}
+			/* Read LinkTest Timings */
+			ptr=PyArray_GETPTR2((PyArrayObject *)pyTimings[i]      , rank, 0);
+			n=fread(ptr, sizeof(double), fh->size, fh->fp);
+			if (UNLIKELY((int32_t)n != fh->size)) {
+				PyErr_SetString(PyExc_RuntimeError, "readImportData_2_2_0: Failed to read/import LinkTest timings.");
+				return -1;
+			}
+			sion_swap(ptr, ptr, sizeof(double), fh->size, swap);
+			#ifdef DEBUG_OUTPUT
+				printf("timings[%d,%zu]               =%e",rank,i,((double*)ptr)[0]);
+				for(n=1;(int32_t)n<fh->size;n++) printf(",%e",((double*)ptr)[n]);
+				printf("\n");
+				fflush(stdout);
+			#endif
+			/* Read LinkTest Access Pattern */
+			ptr=PyArray_GETPTR2((PyArrayObject *)pyAccesspattern[i], rank, 0);
+			n=fread(ptr, sizeof(int64_t), fh->size, fh->fp);
+			if (UNLIKELY((int64_t)n != fh->size)) {
+				PyErr_SetString(PyExc_RuntimeError, "readImportData_2_2_0: Failed to read/import LinkTest access pattern.");
+				return -1;
+			}
+			sion_swap(ptr, ptr, sizeof(uint64_t), fh->size, swap);
+			#ifdef DEBUG_OUTPUT
+				printf("accesspattern[%d,%zu]         =%" PRIu64,rank,i,((uint64_t*)ptr)[0]);
+				for(n=1;(int32_t)n<fh->size;n++) printf(",%" PRIu64,((uint64_t*)ptr)[n]);
+				printf("\n");
+				fflush(stdout);
+			#endif
+			/* Read LinkTest All-To-All Timings */
+			if (linkTestInfo->options[A2A________FLAG]){
+				ptr=PyArray_GETPTR1((PyArrayObject *)pyA2ATimings[i], rank);
+				n=fread(ptr, sizeof(double), 1, fh->fp);
+				if (UNLIKELY(n != 1)) {
+					PyErr_SetString(PyExc_RuntimeError, "readImportData_2_2_0: Failed to read/import all-to-all timing.");
+					return -1;
+				}
+				sion_swap(ptr, ptr, sizeof(double), 1, swap);
+				#ifdef DEBUG_OUTPUT
+					printf("all-to-all time[%d,%zu]       =%f\n",rank,i,((double*)ptr)[0]);fflush(stdout);
+				#endif
+			}
+		}
+
+		/* Check Alignment by Testing for END_BLOCK */
+		n=fread(end_block,sizeof(char),end_block_len-1,fh->fp);
+		if (UNLIKELY(n != end_block_len-1)){
+			PyErr_SetString(PyExc_RuntimeError, "readImportData_2_2_0: Failed to read END_BLOCK string.");
+			return -1;
+		}
+		end_block[end_block_len-1]='\0';
+		if(UNLIKELY(strcmp(end_block,END_BLOCK_2_2_0))){
+			PyErr_SetString(PyExc_RuntimeError, "readImportData_2_2_0: Alignment Error Detected. \"END_BLOCK\" not found at the correct location.");
+			return -1;
+		}
+	}
+
+	/* Close SION File */
+	sion_close(fh->sid);
+
+	/* Add Hostname To LinkTestInfo Dictionary */
+	err=PyDict_SetItem(*pyLinkTestInfo,PyUnicode_FromString("Hosts"),pyHosts);
+	if(err){
+		PyErr_SetString(PyExc_RuntimeError,"importInfo_2_2_0: Failed to add Hosts to LinkTestInfo dictionary.");
+		return -1;
+	}
+
+	/* Add Core ID To LinkTestInfo Dictionary */
+	err=PyDict_SetItem(*pyLinkTestInfo,PyUnicode_FromString("Core ID"),pyCore);
+	if(err){
+		PyErr_SetString(PyExc_RuntimeError,"importInfo_2_2_0: Failed to add Core ID to LinkTestInfo dictionary.");
+		return -1;
+	}
+
+	/* Create Data Dictionaries */
+	PyObject** const pyLinkTestDataDicts=(PyObject**)malloc(num_iterations*sizeof(PyObject));
+	for(i=0;i<num_iterations;i++) pyLinkTestDataDicts[i] = PyDict_New();
+
+	/* Fill Dictionaries */
+	for(i=0;i<num_iterations;i++){
+		err=PyDict_SetItem(pyLinkTestDataDicts[i], PyUnicode_FromString("Start Time"    ), pyStartTime[i]    );
+		if(err){
+			PyErr_SetString(PyExc_RuntimeError,"readImportData_2_2_0: Failed to add start time to LinkTestData dictionary.");
+			return -1;
+		}
+		/* Set Double-Precision Floating-Point Information */
+		err=PyDict_SetItem(pyLinkTestDataDicts[i],PyUnicode_FromString("Minimum time"                  ),PyFloat_FromDouble(minMaxAvgTimings[i*numMinMaxAvgTimings+0]));
+		if(err){
+			PyErr_SetString(PyExc_RuntimeError,"importInfo_2_1_2: Failed to add minTimeAll to LinkTestData dictionary.");
+			return -1;
+		}
+		err=PyDict_SetItem(pyLinkTestDataDicts[i],PyUnicode_FromString("Maximum time"                  ),PyFloat_FromDouble(minMaxAvgTimings[i*numMinMaxAvgTimings+1]));
+		if(err){
+			PyErr_SetString(PyExc_RuntimeError,"importInfo_2_1_2: Failed to add maxTimeAll to LinkTestData dictionary.");
+			return -1;
+		}
+		err=PyDict_SetItem(pyLinkTestDataDicts[i],PyUnicode_FromString("Average time"                  ),PyFloat_FromDouble(minMaxAvgTimings[i*numMinMaxAvgTimings+2]));
+		if(err){
+			PyErr_SetString(PyExc_RuntimeError,"importInfo_2_1_2: Failed to add avgTimeAll to LinkTestData dictionary.");
+			return -1;
+		}
+		if(numMinMaxAvgTimings==6){ //Only execute if all-to-all testing was performed
+			err=PyDict_SetItem(pyLinkTestDataDicts[i],PyUnicode_FromString("Minimum all-to-all time"),PyFloat_FromDouble(minMaxAvgTimings[i*numMinMaxAvgTimings+3]));
+			if(err){
+				PyErr_SetString(PyExc_RuntimeError,"importInfo_2_1_2: Failed to add a2aMinTimeAll to LinkTestData dictionary.");
+				return -1;
+			}
+			err=PyDict_SetItem(pyLinkTestDataDicts[i],PyUnicode_FromString("Maximum all-to-all time"),PyFloat_FromDouble(minMaxAvgTimings[i*numMinMaxAvgTimings+4]));
+			if(err){
+				PyErr_SetString(PyExc_RuntimeError,"importInfo_2_1_2: Failed to add a2aMaxTimeAll to LinkTestData dictionary.");
+				return -1;
+			}
+			err=PyDict_SetItem(pyLinkTestDataDicts[i],PyUnicode_FromString("Average all-to-all time"),PyFloat_FromDouble(minMaxAvgTimings[i*numMinMaxAvgTimings+5]));
+			if(err){
+				PyErr_SetString(PyExc_RuntimeError,"importInfo_2_1_2: Failed to add a2aAvgTimeAll to LinkTestData dictionary.");
+				return -1;
+			}
+		}
+
+		err=PyDict_SetItem(pyLinkTestDataDicts[i], PyUnicode_FromString("Timings"       ), pyTimings[i]      );
+		if(err){
+			PyErr_SetString(PyExc_RuntimeError,"readImportData_2_2_0: Failed to add timings to LinkTestData dictionary.");
+			return -1;
+		}
+		err=PyDict_SetItem(pyLinkTestDataDicts[i], PyUnicode_FromString("Access Pattern"), pyAccesspattern[i]);
+		if(err){
+			PyErr_SetString(PyExc_RuntimeError,"readImportData_2_2_0: Failed to add accessPatterns to LinkTestData dictionary.");
+			return -1;
+		}
+		if(linkTestInfo->iInfo[NUM___SERIAL]>0){
+			err=PyDict_SetItem(pyLinkTestDataDicts[i], PyUnicode_FromString("New serially retested timings"  ), pySerialTimingsNew[i]);
+			if(err){
+				PyErr_SetString(PyExc_RuntimeError,"readImportData_2_2_0: Failed to add serialTimingsNew to LinkTestData dictionary.");
+				return -1;
+			}
+			err=PyDict_SetItem(pyLinkTestDataDicts[i], PyUnicode_FromString("Old serially retested timings"  ), pySerialTimingsOld[i]);
+			if(err){
+				PyErr_SetString(PyExc_RuntimeError,"readImportData_2_2_0: Failed to add serialTimingsOld to LinkTestData dictionary.");
+				return -1;
+			}
+			err=PyDict_SetItem(pyLinkTestDataDicts[i], PyUnicode_FromString("Serial-retest origin hosts"     ), pySerialFrom[i]);
+			if(err){
+				PyErr_SetString(PyExc_RuntimeError,"readImportData_2_2_0: Failed to add serialFrom to LinkTestData dictionary.");
+				return -1;
+			}
+			err=PyDict_SetItem(pyLinkTestDataDicts[i], PyUnicode_FromString("Serial-retest destination hosts"), pySerialTo[i]);
+			if(err){
+				PyErr_SetString(PyExc_RuntimeError,"readImportData_2_2_0: Failed to add serialTo to LinkTestData dictionary.");
+				return -1;
+			}
+		}
+		if(linkTestInfo->options[A2A________FLAG]){
+			err=PyDict_SetItem(pyLinkTestDataDicts[i], PyUnicode_FromString("All-to-all timings"), pyA2ATimings[i]);
+			if(err){
+				PyErr_SetString(PyExc_RuntimeError,"readImportData_2_2_0: Failed to add a2aTimings to LinkTestData dictionary.");
+				return -1;
+			}
+		}
+		err=PyDict_SetItem(pyLinkTestDataDicts[i], PyUnicode_FromString("End Time"      ), pyEndTime[i]      );
+		if(err){
+			PyErr_SetString(PyExc_RuntimeError,"readImportData_2_2_0: Failed to add end time to LinkTestData dictionary.");
+			return -1;
+		}
+	}
+
+	/* Create Python List If Necessary */
+	if(num_iterations>1){
+		*pyLinkTestData=PyList_New(num_iterations);
+		for(i=0;i<num_iterations;i++)PyList_SET_ITEM(*pyLinkTestData,i,pyLinkTestDataDicts[i]);
+	}else{
+		*pyLinkTestData=pyLinkTestDataDicts[0];
+	}
+
+	/* Free Memory */
+	free(pyTimings      );
+	free(pyAccesspattern);
+	if(pyA2ATimings!=NULL) free(pyA2ATimings);
+	if(linkTestInfo->iInfo[NUM___SERIAL]>0){
+		free(pySerialTimingsNew);
+		free(pySerialTimingsOld);
+		free(pySerialFrom      );
+		free(pySerialTo        );
+	}
+
+	return 0;
+}
+
+/**********************/
+/* Read & Import Data */
+/**********************/
+int readImport_2_2_0(struct SionFile* const fh, const int swap, const Version version, PyObject** const pyLinkTestInfo, PyObject** const pyLinkTestData){
+	struct LinkTestInfo_2_2_0 linkTestInfo;
+	int err;
+	/* Read LinkTest Information */
+	err = readInfo_2_2_0(fh, swap, version, &linkTestInfo);
+	if(err){
+//		PyErr_SetString(PyExc_RuntimeError,"importInfo_2_2_0: Failed to read LinkTest information.");
+		return err;
+	}
+	/* Import LinkTest Information Into Python */
+	*pyLinkTestInfo = PyDict_New(); //Create LinkTest information dictionary
+	err = importInfo_2_2_0(version, &linkTestInfo, pyLinkTestInfo);
+	if(err){
+//		PyErr_SetString(PyExc_RuntimeError,"importInfo_2_2_0: Failed to populate the LinkTestInfo dictionary.");
+		//TODO: Safely Deallocate Python Dictionary
+		return err;
+	}
+	/* Read & Import LinkTest Data Into Python */
+	err = readImportData_2_2_0(fh, swap, &linkTestInfo, pyLinkTestInfo, pyLinkTestData);
+	if(err){
+//		PyErr_SetString(PyExc_RuntimeError,"importInfo_2_2_0: Failed to read LinkTest data or to populate the LinkTestData dictionary.");
+		//TODO: Safely Deallocate Python Dictionary
+		return err;
+	}
+
+	return(0);
+}
diff --git a/python/linktest/linktest_2_2_0.h b/python/linktest/linktest_2_2_0.h
new file mode 100644
index 0000000000000000000000000000000000000000..7a0b19a8167d0d795a1cf38df6792472c82d647e
--- /dev/null
+++ b/python/linktest/linktest_2_2_0.h
@@ -0,0 +1,13 @@
+/****************************************************************************
+**  LinkTest                                                               **
+*****************************************************************************
+**  Copyright (c) 2008-2025                                                **
+**  Forschungszentrum Juelich, Juelich Supercomputing Centre               **
+**                                                                         **
+**  See the file COPYRIGHT in the package base directory for details       **
+****************************************************************************/
+
+/**********************/
+/* Read & Import Data */
+/**********************/
+int readImport_2_2_0(struct SionFile* const fh, const int swap, const Version version, PyObject** const pyLinkTestInfo, PyObject** const pyLinkTestData);
diff --git a/python/linktest/report.py b/python/linktest/report.py
index 4374e386ff41de09b1a358158e393f6ebc64c027..f9ca30f18e1cb1709bc22f919153368051c2f593 100644
--- a/python/linktest/report.py
+++ b/python/linktest/report.py
@@ -93,7 +93,9 @@ def find_renderer(fig):
         #print_figure() method.)
         import io
         fig.canvas.print_figure(io.BytesIO())
-        renderer = fig._cachedRenderer
+        #_cachedRenderer does not seem to work anymore
+        #renderer = fig._cachedRenderer
+        renderer = fig._get_renderer()
     return(renderer)
 
 def max_bbox_extend_1pt(strings,fast):
@@ -1126,8 +1128,9 @@ def linktest_report(metaData,
         time1=time();
 
     # Check version
-    if metaData["Version"]!="2.0.0" and metaData["Version"]!="2.1.1" and metaData["Version"]!="2.1.2" and metaData["Version"]!="2.1.4" and metaData["Version"]!="2.1.5" and metaData["Version"]!="2.1.6" and metaData["Version"]!="2.1.7" and metaData["Version"]!="2.1.8" and metaData["Version"]!="2.1.9" and metaData["Version"]!="2.1.10" and metaData["Version"]!="2.1.11" and metaData["Version"]!="2.1.12" and metaData["Version"]!="2.1.13" and metaData["Version"]!="2.1.14" and metaData["Version"]!="2.1.15" and metaData["Version"]!="2.1.16" and metaData["Version"]!="2.1.17" and metaData["Version"]!="2.1.18" and metaData["Version"]!="2.1.19":
-        print(f"Potentially unsupported LinkTest version output detected.\nThe Supported LinkTest versions are 2.0.0 and 2.1.[1,2,4-19] while this file comes from {metaData['Version']}")
+    supported_versions = ["2.0.0"] + [f"2.1.{y}" for y in [x for x in range(1,3)] + [x for x in range(4,20)]] + ["2.2.0"]
+    if metaData["Version"] not in supported_versions:
+        print(f"Potentially unsupported LinkTest version output detected.\nThe Supported LinkTest versions are 2.0.0, 2.1.[1,2,4-19] and 2.2.0 while this file comes from {metaData['Version']}")
     if "Do a bisection test?" in metaData and metaData["Do a bisection test?"]!=0 and (metaData["Version"]=="2.0.0" or metaData["Version"]=="2.1.1" or metaData["Version"]=="2.1.2" or metaData["Version"]=="2.1.4" or metaData["Version"]=="2.1.5" or metaData["Version"]=="2.1.6" or metaData["Version"]=="2.1.7" or metaData["Version"]=="2.1.8" or metaData["Version"]=="2.1.9"):
         print("Bisection runs were not properly executed prior to LinkTest version 2.1.10. The Report may be faulty.");
 
diff --git a/python/setup.py b/python/setup.py
index b201a691585b9dddb9a8209de0ba718e1f0a6885..72cd56409ebd79cf0399e7037370a98d413da1bf 100644
--- a/python/setup.py
+++ b/python/setup.py
@@ -12,7 +12,7 @@ import codecs
 from setuptools import setup, Extension
 
 # Hard-coded LinkTest version for older pip installers
-link_ver="2.1.19"
+link_ver="2.2.0"
 # Hard-coded LinkTest git hash for older pip installers
 link_hash="UNKNOWN"
 link_hash_short="UNKNOWN"
@@ -85,7 +85,8 @@ ext_modules=[
 		           "linktest/linktest_2_1_16.c",
 		           "linktest/linktest_2_1_17.c",
 		           "linktest/linktest_2_1_18.c",
-		           "linktest/linktest_2_1_19.c"],
+		           "linktest/linktest_2_1_19.c",
+		           "linktest/linktest_2_2_0.c"],
 		include_dirs=['linktest'],
 		extra_compile_args = sionlib_compile_args, #Add `+['-DDEBUG_OUTPUT']` to turn on debug output
 		extra_link_args = sionlib_link_args