   const char *headers[] = {apply_header};
   const char *includeNames[] = {"header.h"};
 
-  std::vector<char> ptx;
-  compilePTX(src, headers, includeNames, ptx);
+  PTXPtr ptx;
+  Apply2Hash hash(op, type, A, B);
+  auto found_hash = apply2cache.find(hash);
+  if(found_hash == apply2cache.end())
+  {
+    ptx = PTXPtr(new PTX());
+    compilePTX(src, headers, includeNames, *ptx);
+    apply2cache.emplace(hash, ptx);
+  }
+  else
+    ptx = found_hash->second;
 
   void *args[] = {(void*)&aInfo, (void*)&bInfo, (void*)&totalElements};
-  launch(ptx.data(), "kernel", args, grid, block, (CUstream)stream);
+  launch(ptx->data(), "kernel", args, grid, block, (CUstream)stream);
 }
 
 

  const char *headers[] = {apply_header};
  const char *includeNames[] = {"header.h"};

  std::vector<char> ptx;
  compilePTX(src, headers, includeNames, ptx);

  void *args[] = {(void*)&aInfo, (void*)&bInfo, (void*)&cInfo, (void*)&totalElements};
  launch(ptx.data(), "kernel", args, grid, block, (CUstream)stream);
}



  bool operator == (const Apply1Hash& other) const
  {
    return op == other.op && type == other.type && Adim == other.Adim;
  }
};

struct Apply2Hash {
  std::string op;
  std::string type;
  int Adim, Bdim;

  Apply2Hash(std::string op, std::string type, int Adim, int Bdim) : op(op), type(type), Adim(Adim), Bdim(Bdim) {}

  bool operator == (const Apply2Hash& other) const
  {
    return op == other.op && type == other.type && Adim == other.Adim && Bdim == other.Bdim;
  }
};

struct Apply3Hash {
  std::string op;
  std::string type;
  int Adim, Bdim, Cdim;

  Apply3Hash(std::string op, std::string type, int Adim, int Bdim, int Cdim) :
    op(op), type(type), Adim(Adim), Bdim(Bdim), Cdim(Cdim) {}

  bool operator == (const Apply3Hash& other) const
  {
    return op == other.op && type == other.type && Adim == other.Adim && Bdim == other.Bdim && Cdim == other.Cdim;
  }
};

