diff --git a/bench.py b/bench.py
index 7875955814dee8f3f89f7cbeb81769dc96216b4a..6b2c10fca5e737f7d236ef244149bc928eb8c75d 100755
--- a/bench.py
+++ b/bench.py
@@ -221,10 +221,10 @@ def main():
                 continue
             end_time = datetime.datetime.now()
             bench.results['facts']['end-time'] = end_time.isoformat()
-            bench.results['facts']['duration'] = end_time - start_time
+            bench.results['facts']['duration'] = (end_time - start_time).total_seconds()
 
         # Save results in resultdir
-        bench.save(os.path.join(src.globalvars.resdir, f"{bench.name}.save"))
+        bench.save(src.globalvars.resdir)
 
         if hasattr(bench, "cleanup"):
             print_status("Cleaning up", bench.name, "...")
diff --git a/merge.py b/merge.py
index a8b2afb54991916df8349c328da42103f285d0c0..f3376fa2414ae0bfdb077a1a8f363e8420a74ee1 100755
--- a/merge.py
+++ b/merge.py
@@ -20,12 +20,21 @@
 """Merge two compatible results of an allocbench run"""
 
 import argparse
+import json
 import os
 import pickle
 import sys
 
 from src.util import print_license_and_exit, print_version_and_exit
 
+def load_file(filename):
+    if filename.endswith("json"):
+        with open(filename, "r") as f:
+            return json.load(f)
+    else:
+        with open(filename, "rb") as f:
+            return pickle.load(f)
+
 
 def main():
     if "--license" in sys.argv:
@@ -61,11 +70,9 @@ def main():
             print(f"Can't merge {src_save} because {os.path.basename(src_save)} not in {args.dest}")
             continue
 
-        with open(src_save, "rb") as src_file:
-            src_results = pickle.load(src_file)
+        src_results = load_file(src_file)
 
-        with open(dest_save, "rb") as dest_file:
-            dest_results = pickle.load(dest_file)
+        dest_results = load_file(dest_file)
 
         for alloc in src_results["allocators"]:
             if alloc in dest_results["allocators"]:
@@ -77,8 +84,8 @@ def main():
             dest_results[alloc] = src_results[alloc]
             dest_results["stats"][alloc] = src_results["stats"][alloc]
 
-        with open(dest_save, "wb") as result_file:
-            pickle.dump(dest_results, result_file)
+        with open(os.path.splitext(dest_save)[0] + ".json", "w") as result_file:
+            json.dump(dest_results, result_file)
 
 
 if __name__ == "__main__":
diff --git a/src/benchmark.py b/src/benchmark.py
index adf84c8fae07344de85964b0c7e2e5e3ba951209..e1b598fe56a48acd662589d5118f9ca7f81b9265 100644
--- a/src/benchmark.py
+++ b/src/benchmark.py
@@ -1,11 +1,11 @@
 import atexit
 from collections import namedtuple
+import errno
 import copy
 import csv
 import itertools
 import multiprocessing
 import os
-import pickle
 import subprocess
 from time import sleep
 
@@ -145,10 +145,15 @@ class Benchmark:
         print_debug("Results directory:", self.result_dir)
 
     def save(self, path=None):
-        """Save benchmark results to a pickle file"""
-        f = path if path else self.name + ".save"
-        print_info("Saving results to:", f)
-        # Pickle can't handle namedtuples so convert the dicts of namedtuples
+        """Save benchmark results to a json file"""
+        import json
+        if not path:
+            path = self.name + ".json"
+        elif os.path.isdir(path):
+            path = os.path.join(path, self.name + ".json")
+
+        print_info(f"Saving results to: {path}")
+        # JSON can't handle namedtuples so convert the dicts of namedtuples
         # into lists of dicts.
         save_data = {}
         save_data.update(self.results)
@@ -172,22 +177,34 @@ class Benchmark:
             if "stats" in self.results:
                 save_data["stats"][allocator] = stats
 
-        with open(f, "wb") as f:
-            pickle.dump(save_data, f)
+        with open(path, "w") as f:
+            json.dump(save_data, f)
 
     def load(self, path=None):
-        """Load benchmark results from a pickle file"""
+        """Load benchmark results from file"""
         if not path:
-            f = self.name + ".save"
+            filename = self.name
         else:
             if os.path.isdir(path):
-                f = os.path.join(path, self.name + ".save")
+                filename = os.path.join(path, self.name)
             else:
-                f = path
+                filename = os.path.splitext(path)
+
+        if os.path.exists(filename + ".json"):
+            import json
+            filename += ".json"
+            with open(filename, "w") as f:
+                self.results = json.load(f)
+        if os.path.exists(filename + ".save"):
+            import pickle
+            filename += ".save"
+            with open(filename, "wb") as f:
+                self.results = pickle.load(f)
+        else:
+            raise FileNotFoundError(errno.ENOENT, os.strerror(errno.ENOENT), filename)
+
+        print_info(f"Loading results from: {filename}")
 
-        print_info("Loading results from:", f)
-        with open(f, "rb") as f:
-            self.results = pickle.load(f)
         # Build new named tuples
         for allocator in self.results["allocators"]:
             d = {}