Simplify auto-tuning and benchmark routines
authorJens Steube <jens.steube@gmail.com>
Thu, 5 May 2016 21:21:15 +0000 (23:21 +0200)
committerJens Steube <jens.steube@gmail.com>
Thu, 5 May 2016 21:21:15 +0000 (23:21 +0200)
Decrease the time it takes to run a benchmark
Removed --benchmark-repeat, it creates no advantage
Fix some wording related to drivers
Dropped special 64-bit rotate() handling for NV
Cleanup SHA384
Cleanup try_run()

OpenCL/m10800_a0.cl
OpenCL/m10800_a1.cl
OpenCL/m10800_a3.cl
OpenCL/types_ocl.c
docs/changes.txt
docs/readme.txt
src/oclHashcat.c

index f28d798..78ad998 100644 (file)
@@ -116,10 +116,11 @@ void sha384_transform (const u32x w0[4], const u32x w1[4], const u32x w2[4], con
 
   ROUND_STEP (0);
 
 
   ROUND_STEP (0);
 
-  ROUND_EXPAND (); ROUND_STEP (16);
-  ROUND_EXPAND (); ROUND_STEP (32);
-  ROUND_EXPAND (); ROUND_STEP (48);
-  ROUND_EXPAND (); ROUND_STEP (64);
+  #pragma unroll
+  for (int i = 16; i < 80; i += 16)
+  {
+    ROUND_EXPAND (); ROUND_STEP (i);
+  }
 
   /* rev
   digest[0] += a;
 
   /* rev
   digest[0] += a;
index 0e0e864..24762c0 100644 (file)
@@ -114,10 +114,11 @@ void sha384_transform (const u32x w0[4], const u32x w1[4], const u32x w2[4], con
 
   ROUND_STEP (0);
 
 
   ROUND_STEP (0);
 
-  ROUND_EXPAND (); ROUND_STEP (16);
-  ROUND_EXPAND (); ROUND_STEP (32);
-  ROUND_EXPAND (); ROUND_STEP (48);
-  ROUND_EXPAND (); ROUND_STEP (64);
+  #pragma unroll
+  for (int i = 16; i < 80; i += 16)
+  {
+    ROUND_EXPAND (); ROUND_STEP (i);
+  }
 
   /* rev
   digest[0] += a;
 
   /* rev
   digest[0] += a;
index 3ffe5a0..c6df671 100644 (file)
@@ -114,10 +114,11 @@ void sha384_transform (const u32x w0[4], const u32x w1[4], const u32x w2[4], con
 
   ROUND_STEP (0);
 
 
   ROUND_STEP (0);
 
-  ROUND_EXPAND (); ROUND_STEP (16);
-  ROUND_EXPAND (); ROUND_STEP (32);
-  ROUND_EXPAND (); ROUND_STEP (48);
-  ROUND_EXPAND (); ROUND_STEP (64);
+  #pragma unroll
+  for (int i = 16; i < 80; i += 16)
+  {
+    ROUND_EXPAND (); ROUND_STEP (i);
+  }
 
   /* rev
   digest[0] += a;
 
   /* rev
   digest[0] += a;
index ff464f3..c41c526 100644 (file)
@@ -311,40 +311,10 @@ inline u32 rotl32_S (const u32 a, const u32 n)
   return rotate (a, n);
 }
 
   return rotate (a, n);
 }
 
-#if CUDA_ARCH >= 350
-inline u64 rotr64_S (const u64 a, const u32 n)
-{
-  u32 il;
-  u32 ir;
-
-  asm ("mov.b64 {%0, %1}, %2;" : "=r"(il), "=r"(ir) : "l"(a));
-
-  u32 tl;
-  u32 tr;
-
-  if (n >= 32)
-  {
-    asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tl) : "r"(ir), "r"(il), "r"(n - 32));
-    asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tr) : "r"(il), "r"(ir), "r"(n - 32));
-  }
-  else
-  {
-    asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tl) : "r"(il), "r"(ir), "r"(n));
-    asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tr) : "r"(ir), "r"(il), "r"(n));
-  }
-
-  u64 r;
-
-  asm ("mov.b64 %0, {%1, %2};" : "=l"(r) : "r"(tl), "r"(tr));
-
-  return r;
-}
-#else
 inline u64 rotr64_S (const u64 a, const u32 n)
 {
   return rotate (a, (u64) 64 - n);
 }
 inline u64 rotr64_S (const u64 a, const u32 n)
 {
   return rotate (a, (u64) 64 - n);
 }
-#endif
 
 inline u64 rotl64_S (const u64 a, const u32 n)
 {
 
 inline u64 rotl64_S (const u64 a, const u32 n)
 {
@@ -390,335 +360,14 @@ inline u32x rotl32 (const u32x a, const u32 n)
   return rotate (a, n);
 }
 
   return rotate (a, n);
 }
 
-#if CUDA_ARCH >= 350
-inline u64x rotr64 (const u64x a, const u32 n)
-{
-  u64x r;
-
-  u32 il;
-  u32 ir;
-  u32 tl;
-  u32 tr;
-
-  #if VECT_SIZE == 1
-
-  asm ("mov.b64 {%0, %1}, %2;" : "=r"(il), "=r"(ir) : "l"(a));
-
-  if (n >= 32)
-  {
-    asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tl) : "r"(ir), "r"(il), "r"(n - 32));
-    asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tr) : "r"(il), "r"(ir), "r"(n - 32));
-  }
-  else
-  {
-    asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tl) : "r"(il), "r"(ir), "r"(n));
-    asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tr) : "r"(ir), "r"(il), "r"(n));
-  }
-
-  asm ("mov.b64 %0, {%1, %2};" : "=l"(r) : "r"(tl), "r"(tr));
-
-  #endif
-
-  #if VECT_SIZE >= 2
-
-  {
-    asm ("mov.b64 {%0, %1}, %2;" : "=r"(il), "=r"(ir) : "l"(a.s0));
-
-    if (n >= 32)
-    {
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tl) : "r"(ir), "r"(il), "r"(n - 32));
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tr) : "r"(il), "r"(ir), "r"(n - 32));
-    }
-    else
-    {
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tl) : "r"(il), "r"(ir), "r"(n));
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tr) : "r"(ir), "r"(il), "r"(n));
-    }
-
-    asm ("mov.b64 %0, {%1, %2};" : "=l"(r.s0) : "r"(tl), "r"(tr));
-  }
-
-  {
-    asm ("mov.b64 {%0, %1}, %2;" : "=r"(il), "=r"(ir) : "l"(a.s1));
-
-    if (n >= 32)
-    {
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tl) : "r"(ir), "r"(il), "r"(n - 32));
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tr) : "r"(il), "r"(ir), "r"(n - 32));
-    }
-    else
-    {
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tl) : "r"(il), "r"(ir), "r"(n));
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tr) : "r"(ir), "r"(il), "r"(n));
-    }
-
-    asm ("mov.b64 %0, {%1, %2};" : "=l"(r.s1) : "r"(tl), "r"(tr));
-  }
-
-  #endif
-
-  #if VECT_SIZE >= 4
-
-  {
-    asm ("mov.b64 {%0, %1}, %2;" : "=r"(il), "=r"(ir) : "l"(a.s2));
-
-    if (n >= 32)
-    {
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tl) : "r"(ir), "r"(il), "r"(n - 32));
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tr) : "r"(il), "r"(ir), "r"(n - 32));
-    }
-    else
-    {
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tl) : "r"(il), "r"(ir), "r"(n));
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tr) : "r"(ir), "r"(il), "r"(n));
-    }
-
-    asm ("mov.b64 %0, {%1, %2};" : "=l"(r.s2) : "r"(tl), "r"(tr));
-  }
-
-  {
-    asm ("mov.b64 {%0, %1}, %2;" : "=r"(il), "=r"(ir) : "l"(a.s3));
-
-    if (n >= 32)
-    {
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tl) : "r"(ir), "r"(il), "r"(n - 32));
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tr) : "r"(il), "r"(ir), "r"(n - 32));
-    }
-    else
-    {
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tl) : "r"(il), "r"(ir), "r"(n));
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tr) : "r"(ir), "r"(il), "r"(n));
-    }
-
-    asm ("mov.b64 %0, {%1, %2};" : "=l"(r.s3) : "r"(tl), "r"(tr));
-  }
-
-  #endif
-
-  #if VECT_SIZE >= 8
-
-  {
-    asm ("mov.b64 {%0, %1}, %2;" : "=r"(il), "=r"(ir) : "l"(a.s4));
-
-    if (n >= 32)
-    {
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tl) : "r"(ir), "r"(il), "r"(n - 32));
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tr) : "r"(il), "r"(ir), "r"(n - 32));
-    }
-    else
-    {
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tl) : "r"(il), "r"(ir), "r"(n));
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tr) : "r"(ir), "r"(il), "r"(n));
-    }
-
-    asm ("mov.b64 %0, {%1, %2};" : "=l"(r.s4) : "r"(tl), "r"(tr));
-  }
-
-  {
-    asm ("mov.b64 {%0, %1}, %2;" : "=r"(il), "=r"(ir) : "l"(a.s5));
-
-    if (n >= 32)
-    {
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tl) : "r"(ir), "r"(il), "r"(n - 32));
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tr) : "r"(il), "r"(ir), "r"(n - 32));
-    }
-    else
-    {
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tl) : "r"(il), "r"(ir), "r"(n));
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tr) : "r"(ir), "r"(il), "r"(n));
-    }
-
-    asm ("mov.b64 %0, {%1, %2};" : "=l"(r.s5) : "r"(tl), "r"(tr));
-  }
-
-  {
-    asm ("mov.b64 {%0, %1}, %2;" : "=r"(il), "=r"(ir) : "l"(a.s6));
-
-    if (n >= 32)
-    {
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tl) : "r"(ir), "r"(il), "r"(n - 32));
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tr) : "r"(il), "r"(ir), "r"(n - 32));
-    }
-    else
-    {
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tl) : "r"(il), "r"(ir), "r"(n));
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tr) : "r"(ir), "r"(il), "r"(n));
-    }
-
-    asm ("mov.b64 %0, {%1, %2};" : "=l"(r.s6) : "r"(tl), "r"(tr));
-  }
-
-  {
-    asm ("mov.b64 {%0, %1}, %2;" : "=r"(il), "=r"(ir) : "l"(a.s7));
-
-    if (n >= 32)
-    {
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tl) : "r"(ir), "r"(il), "r"(n - 32));
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tr) : "r"(il), "r"(ir), "r"(n - 32));
-    }
-    else
-    {
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tl) : "r"(il), "r"(ir), "r"(n));
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tr) : "r"(ir), "r"(il), "r"(n));
-    }
-
-    asm ("mov.b64 %0, {%1, %2};" : "=l"(r.s7) : "r"(tl), "r"(tr));
-  }
-
-  #endif
-
-  #if VECT_SIZE >= 16
-
-  {
-    asm ("mov.b64 {%0, %1}, %2;" : "=r"(il), "=r"(ir) : "l"(a.s8));
-
-    if (n >= 32)
-    {
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tl) : "r"(ir), "r"(il), "r"(n - 32));
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tr) : "r"(il), "r"(ir), "r"(n - 32));
-    }
-    else
-    {
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tl) : "r"(il), "r"(ir), "r"(n));
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tr) : "r"(ir), "r"(il), "r"(n));
-    }
-
-    asm ("mov.b64 %0, {%1, %2};" : "=l"(r.s8) : "r"(tl), "r"(tr));
-  }
-
-  {
-    asm ("mov.b64 {%0, %1}, %2;" : "=r"(il), "=r"(ir) : "l"(a.s9));
-
-    if (n >= 32)
-    {
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tl) : "r"(ir), "r"(il), "r"(n - 32));
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tr) : "r"(il), "r"(ir), "r"(n - 32));
-    }
-    else
-    {
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tl) : "r"(il), "r"(ir), "r"(n));
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tr) : "r"(ir), "r"(il), "r"(n));
-    }
-
-    asm ("mov.b64 %0, {%1, %2};" : "=l"(r.s9) : "r"(tl), "r"(tr));
-  }
-
-  {
-    asm ("mov.b64 {%0, %1}, %2;" : "=r"(il), "=r"(ir) : "l"(a.sa));
-
-    if (n >= 32)
-    {
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tl) : "r"(ir), "r"(il), "r"(n - 32));
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tr) : "r"(il), "r"(ir), "r"(n - 32));
-    }
-    else
-    {
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tl) : "r"(il), "r"(ir), "r"(n));
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tr) : "r"(ir), "r"(il), "r"(n));
-    }
-
-    asm ("mov.b64 %0, {%1, %2};" : "=l"(r.sa) : "r"(tl), "r"(tr));
-  }
-
-  {
-    asm ("mov.b64 {%0, %1}, %2;" : "=r"(il), "=r"(ir) : "l"(a.sb));
-
-    if (n >= 32)
-    {
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tl) : "r"(ir), "r"(il), "r"(n - 32));
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tr) : "r"(il), "r"(ir), "r"(n - 32));
-    }
-    else
-    {
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tl) : "r"(il), "r"(ir), "r"(n));
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tr) : "r"(ir), "r"(il), "r"(n));
-    }
-
-    asm ("mov.b64 %0, {%1, %2};" : "=l"(r.sb) : "r"(tl), "r"(tr));
-  }
-
-  {
-    asm ("mov.b64 {%0, %1}, %2;" : "=r"(il), "=r"(ir) : "l"(a.sc));
-
-    if (n >= 32)
-    {
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tl) : "r"(ir), "r"(il), "r"(n - 32));
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tr) : "r"(il), "r"(ir), "r"(n - 32));
-    }
-    else
-    {
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tl) : "r"(il), "r"(ir), "r"(n));
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tr) : "r"(ir), "r"(il), "r"(n));
-    }
-
-    asm ("mov.b64 %0, {%1, %2};" : "=l"(r.sc) : "r"(tl), "r"(tr));
-  }
-
-  {
-    asm ("mov.b64 {%0, %1}, %2;" : "=r"(il), "=r"(ir) : "l"(a.sd));
-
-    if (n >= 32)
-    {
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tl) : "r"(ir), "r"(il), "r"(n - 32));
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tr) : "r"(il), "r"(ir), "r"(n - 32));
-    }
-    else
-    {
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tl) : "r"(il), "r"(ir), "r"(n));
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tr) : "r"(ir), "r"(il), "r"(n));
-    }
-
-    asm ("mov.b64 %0, {%1, %2};" : "=l"(r.sd) : "r"(tl), "r"(tr));
-  }
-
-  {
-    asm ("mov.b64 {%0, %1}, %2;" : "=r"(il), "=r"(ir) : "l"(a.se));
-
-    if (n >= 32)
-    {
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tl) : "r"(ir), "r"(il), "r"(n - 32));
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tr) : "r"(il), "r"(ir), "r"(n - 32));
-    }
-    else
-    {
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tl) : "r"(il), "r"(ir), "r"(n));
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tr) : "r"(ir), "r"(il), "r"(n));
-    }
-
-    asm ("mov.b64 %0, {%1, %2};" : "=l"(r.se) : "r"(tl), "r"(tr));
-  }
-
-  {
-    asm ("mov.b64 {%0, %1}, %2;" : "=r"(il), "=r"(ir) : "l"(a.sf));
-
-    if (n >= 32)
-    {
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tl) : "r"(ir), "r"(il), "r"(n - 32));
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tr) : "r"(il), "r"(ir), "r"(n - 32));
-    }
-    else
-    {
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tl) : "r"(il), "r"(ir), "r"(n));
-      asm ("shf.r.wrap.b32 %0, %1, %2, %3;" : "=r"(tr) : "r"(ir), "r"(il), "r"(n));
-    }
-
-    asm ("mov.b64 %0, {%1, %2};" : "=l"(r.sf) : "r"(tl), "r"(tr));
-  }
-
-  #endif
-
-  return r;
-}
-#else
 inline u64x rotr64 (const u64x a, const u32 n)
 {
   return rotate (a, (u64) 64 - n);
 }
 inline u64x rotr64 (const u64x a, const u32 n)
 {
   return rotate (a, (u64) 64 - n);
 }
-#endif
 
 inline u64x rotl64 (const u64x a, const u32 n)
 {
 
 inline u64x rotl64 (const u64x a, const u32 n)
 {
-  return rotr64 (a, (u64) 64 - n);
+  return rotate (a, (u64) n);
 }
 
 inline u32x __byte_perm (const u32x a, const u32x b, const u32x c)
 }
 
 inline u32x __byte_perm (const u32x a, const u32x b, const u32x c)
index f6ec3b5..e69b45f 100644 (file)
@@ -118,3 +118,4 @@ It combines all features of all hashcat projects in one project.
 - Added -cl-std=CL1.1 to all kernel build options
 - Created environment variable to inform NVidia OpenCL runtime to not create its own kernel cache
 - Created environment variable to inform pocl OpenCL runtime to not create its own kernel cache
 - Added -cl-std=CL1.1 to all kernel build options
 - Created environment variable to inform NVidia OpenCL runtime to not create its own kernel cache
 - Created environment variable to inform pocl OpenCL runtime to not create its own kernel cache
+- Dropped special 64-bit rotate() handling for NV, it seems that they've added it to their OpenCL runtime
index fabead1..2dc7ec5 100644 (file)
@@ -1,9 +1,9 @@
 oclHashcat v2.10
 ================
 
 oclHashcat v2.10
 ================
 
-AMD users require Catalyst 14.9 or later (recommended 15.12 or later)
+AMD users require AMD drivers 14.9 or later (recommended 15.12 or later)
 Intel users require Intel OpenCL Runtime 14.2 or later (recommended 15.1 or later)
 Intel users require Intel OpenCL Runtime 14.2 or later (recommended 15.1 or later)
-NVidia users require ForceWare 346.59 or later (recommended 358.09 or later)
+NVidia users require NVidia drivers 346.59 or later (recommended 361.x or later)
 
 ##
 ## Features
 
 ##
 ## Features
index 55525f3..114cb3d 100644 (file)
@@ -33,7 +33,6 @@ double TARGET_MS_PROFILE[3]     = { 8, 16, 96 };
 #define MARKOV_DISABLE          0
 #define MARKOV_CLASSIC          0
 #define BENCHMARK               0
 #define MARKOV_DISABLE          0
 #define MARKOV_CLASSIC          0
 #define BENCHMARK               0
-#define BENCHMARK_REPEATS       100
 #define RESTORE                 0
 #define RESTORE_TIMER           60
 #define RESTORE_DISABLE         0
 #define RESTORE                 0
 #define RESTORE_TIMER           60
 #define RESTORE_DISABLE         0
@@ -2612,7 +2611,7 @@ static void run_kernel_bzero (hc_device_param_t *device_param, cl_mem buf, const
   if (rc != 0)
   {
     // NOTE: clEnqueueFillBuffer () always fails with -59
   if (rc != 0)
   {
     // NOTE: clEnqueueFillBuffer () always fails with -59
-    //       IOW, it's not supported by Nvidia ForceWare <= 352.21, also pocl segfaults, also on apple
+    //       IOW, it's not supported by Nvidia drivers <= 352.21, also pocl segfaults, also on apple
     //       How's that possible, OpenCL 1.2 support is advertised??
     //       We need to workaround...
 
     //       How's that possible, OpenCL 1.2 support is advertised??
     //       We need to workaround...
 
@@ -2788,62 +2787,57 @@ static void run_copy (hc_device_param_t *device_param, const uint pws_cnt)
   }
 }
 
   }
 }
 
-static double try_run (hc_device_param_t *device_param, const u32 kernel_accel, const u32 kernel_loops, const int repeat)
+static double try_run (hc_device_param_t *device_param, const u32 kernel_accel, const u32 kernel_loops)
 {
   const u32 kernel_power = device_param->device_processors * device_param->kernel_threads * kernel_accel;
 
 {
   const u32 kernel_power = device_param->device_processors * device_param->kernel_threads * kernel_accel;
 
-  device_param->kernel_params_buf32[26] = kernel_loops;
-  device_param->kernel_params_buf32[27] = kernel_loops;
+  device_param->kernel_params_buf32[25] = 0;
+  device_param->kernel_params_buf32[26] = kernel_loops; // not a bug, both need to be set
+  device_param->kernel_params_buf32[27] = kernel_loops; // because there's two variables for inner iters for slow and fast hashes
 
   // init some fake words
 
 
   // init some fake words
 
-  for (u32 i = 0; i < kernel_power; i++)
+  if (data.hash_mode == 10700)
   {
   {
-    device_param->pws_buf[i].i[0]   = i;
-    device_param->pws_buf[i].i[1]   = 0x01234567;
-    device_param->pws_buf[i].pw_len = 4 + (i & 3);
-  }
+    // hash mode 10700 hangs on length 0 (unlimited loop)
 
 
-  hc_clEnqueueWriteBuffer (data.ocl, device_param->command_queue, device_param->d_pws_buf, CL_TRUE, 0, kernel_power * sizeof (pw_t), device_param->pws_buf, 0, NULL, NULL);
+    for (u32 i = 0; i < kernel_power; i++)
+    {
+      device_param->pws_buf[i].i[0]   = i;
+      device_param->pws_buf[i].i[1]   = i + 0x01234567;
+      device_param->pws_buf[i].i[2]   = i + 0x89abcdef;
+      device_param->pws_buf[i].i[3]   = 0xffffffff;
+      device_param->pws_buf[i].pw_len = 4 + (i & 3);
+    }
 
 
-  if (data.attack_exec == ATTACK_EXEC_OUTSIDE_KERNEL)
-  {
-    run_kernel_amp (device_param, kernel_power);
-  }
+    hc_clEnqueueWriteBuffer (data.ocl, device_param->command_queue, device_param->d_pws_buf, CL_TRUE, 0, kernel_power * sizeof (pw_t), device_param->pws_buf, 0, NULL, NULL);
 
 
-  // caching run
+    if (data.attack_exec == ATTACK_EXEC_OUTSIDE_KERNEL)
+    {
+      run_kernel_amp (device_param, kernel_power);
+    }
+  }
 
   if (data.attack_exec == ATTACK_EXEC_INSIDE_KERNEL)
   {
 
   if (data.attack_exec == ATTACK_EXEC_INSIDE_KERNEL)
   {
-    run_kernel (KERN_RUN_1, device_param, kernel_power, false);
+    run_kernel (KERN_RUN_1, device_param, kernel_power, true);
   }
   else
   {
   }
   else
   {
-    run_kernel (KERN_RUN_2, device_param, kernel_power, false);
+    run_kernel (KERN_RUN_2, device_param, kernel_power, true);
   }
 
   }
 
-  // now user repeats
-
-  for (int i = 0; i < repeat; i++)
-  {
-    if (data.attack_exec == ATTACK_EXEC_INSIDE_KERNEL)
-    {
-      run_kernel (KERN_RUN_1, device_param, kernel_power, true);
-    }
-    else
-    {
-      run_kernel (KERN_RUN_2, device_param, kernel_power, true);
-    }
-  }
-
-  const double exec_ms_prev = get_avg_exec_time (device_param, repeat);
+  const double exec_ms_prev = get_avg_exec_time (device_param, 1);
 
   // reset fake words
 
 
   // reset fake words
 
-  memset (device_param->pws_buf, 0, kernel_power * sizeof (pw_t));
+  if (data.hash_mode == 10700)
+  {
+    memset (device_param->pws_buf, 0, kernel_power * sizeof (pw_t));
 
 
-  hc_clEnqueueWriteBuffer (data.ocl, device_param->command_queue, device_param->d_pws_buf,     CL_TRUE, 0, kernel_power * sizeof (pw_t), device_param->pws_buf, 0, NULL, NULL);
-  hc_clEnqueueWriteBuffer (data.ocl, device_param->command_queue, device_param->d_pws_amp_buf, CL_TRUE, 0, kernel_power * sizeof (pw_t), device_param->pws_buf, 0, NULL, NULL);
+    hc_clEnqueueWriteBuffer (data.ocl, device_param->command_queue, device_param->d_pws_buf,     CL_TRUE, 0, kernel_power * sizeof (pw_t), device_param->pws_buf, 0, NULL, NULL);
+    hc_clEnqueueWriteBuffer (data.ocl, device_param->command_queue, device_param->d_pws_amp_buf, CL_TRUE, 0, kernel_power * sizeof (pw_t), device_param->pws_buf, 0, NULL, NULL);
+  }
 
   return exec_ms_prev;
 }
 
   return exec_ms_prev;
 }
@@ -2861,183 +2855,96 @@ static void autotune (hc_device_param_t *device_param)
   u32 kernel_accel = kernel_accel_min;
   u32 kernel_loops = kernel_loops_min;
 
   u32 kernel_accel = kernel_accel_min;
   u32 kernel_loops = kernel_loops_min;
 
-  // steps
-
   #define STEPS_CNT 10
 
   #define STEPS_CNT 10
 
-  #define STEPS_ACCEL_CNT (STEPS_CNT + 2)
-  #define STEPS_LOOPS_CNT (STEPS_CNT + 2)
+  #define MAX_RETRIES 1
 
 
-  u32 steps_accel[STEPS_ACCEL_CNT];
-  u32 steps_loops[STEPS_LOOPS_CNT];
+  double exec_ms_final = 0;
 
 
-  for (int i = 0; i < STEPS_ACCEL_CNT; i++)
-  {
-    steps_accel[i] = 1 << i;
-  }
+  // first find out highest kernel-loops that stays below target_ms
 
 
-  for (int i = 0; i < STEPS_LOOPS_CNT; i++)
+  for (kernel_loops = kernel_loops_max; kernel_loops > kernel_loops_min; kernel_loops >>= 1)
   {
   {
-    steps_loops[i] = 1 << i;
-  }
-
-  steps_accel[STEPS_CNT + 0] = kernel_accel_min;
-  steps_accel[STEPS_CNT + 1] = kernel_accel_max;
-
-  steps_loops[STEPS_CNT + 0] = kernel_loops_min;
-  steps_loops[STEPS_CNT + 1] = kernel_loops_max;
+    double exec_ms_best = try_run (device_param, kernel_accel_min, kernel_loops);
 
 
-  qsort (steps_accel, STEPS_ACCEL_CNT, sizeof (u32), sort_by_u32);
-  qsort (steps_loops, STEPS_LOOPS_CNT, sizeof (u32), sort_by_u32);
-
-  // find out highest kernel-loops that stays below target_ms, we can use it later for multiplication as this is a linear function
+    for (int i = 0; i < MAX_RETRIES; i++)
+    {
+      const double exec_ms_cur = try_run (device_param, kernel_accel_min, kernel_loops);
 
 
-  u32 kernel_loops_tmp;
+      exec_ms_best = MIN (exec_ms_best, exec_ms_cur);
+    }
 
 
-  for (kernel_loops_tmp = kernel_loops_max; kernel_loops_tmp > kernel_loops_min; kernel_loops_tmp >>= 1)
-  {
-    const double exec_ms = try_run (device_param, kernel_accel_min, kernel_loops_tmp, 1);
+    if (exec_ms_final == 0) exec_ms_final = exec_ms_best;
 
 
-    if (exec_ms < target_ms) break;
+    if (exec_ms_best < target_ms) break;
   }
 
   }
 
-  // kernel-accel
+  // now the same for kernel-accel but with the new kernel-loops from previous loop set
 
   if (kernel_accel_min < kernel_accel_max)
   {
 
   if (kernel_accel_min < kernel_accel_max)
   {
-    double e_best = 0;
-
-    for (int i = 0; i < STEPS_ACCEL_CNT; i++)
+    for (int i = 0; i < STEPS_CNT; i++)
     {
     {
-      const u32 kernel_accel_try = steps_accel[i];
+      const u32 kernel_accel_try = 1 << i;
 
       if (kernel_accel_try < kernel_accel_min) continue;
       if (kernel_accel_try > kernel_accel_max) break;
 
 
       if (kernel_accel_try < kernel_accel_min) continue;
       if (kernel_accel_try > kernel_accel_max) break;
 
-      const double exec_ms = try_run (device_param, kernel_accel_try, kernel_loops_tmp, 1);
-
-      if (exec_ms > target_ms) break;
+      double exec_ms_best = try_run (device_param, kernel_accel_try, kernel_loops);
 
 
-      const double e = kernel_accel_try / exec_ms;
-
-      if (e > e_best)
+      for (int i = 0; i < MAX_RETRIES; i++)
       {
       {
-        kernel_accel = kernel_accel_try;
+        const double exec_ms_cur = try_run (device_param, kernel_accel_try, kernel_loops);
 
 
-        e_best = e;
+        exec_ms_best = MIN (exec_ms_best, exec_ms_cur);
       }
       }
-    }
-  }
 
 
-  // kernel-loops final
+      if (exec_ms_best > target_ms) break;
 
 
-  if (kernel_loops_min < kernel_loops_max)
-  {
-    double e_best = 0;
-
-    for (int i = 0; i < STEPS_LOOPS_CNT; i++)
-    {
-      const u32 kernel_loops_try = steps_loops[i];
-
-      if (kernel_loops_try < kernel_loops_min) continue;
-      if (kernel_loops_try > kernel_loops_max) break;
-
-      const double exec_ms = try_run (device_param, kernel_accel, kernel_loops_try, 1);
-
-      if (exec_ms > target_ms) break;
+      exec_ms_final = exec_ms_best;
 
 
-      const double e = kernel_loops_try / exec_ms;
-
-      if (e > e_best)
-      {
-        kernel_loops = kernel_loops_try;
-
-        e_best = e;
-      }
+      kernel_accel = kernel_accel_try;
     }
   }
 
     }
   }
 
-  // final balance
-
-  u32 kernel_accel_best = kernel_accel;
-  u32 kernel_loops_best = kernel_loops;
-
-  u32 exec_best = -1;
-
-  if ((kernel_accel_min < kernel_accel_max) || (kernel_loops_min < kernel_loops_max))
-  {
-    const double exec_ms = try_run (device_param, kernel_accel_best, kernel_loops_best, 1);
-
-    exec_best = exec_ms;
-  }
-
-  // reset
+  // sometimes we're in a bad situation that the algorithm is so slow that we can not
+  // create enough kernel_accel to do both, keep the gpu busy and stay below target_ms.
+  // however, we need to have a minimum kernel_accel of 8.
+  // luckily, at this level of workload, it became a linear function
 
 
-  if (kernel_accel_min < kernel_accel_max)
+  while (kernel_accel < 8)
   {
   {
-    u32 kernel_accel_try = kernel_accel;
-    u32 kernel_loops_try = kernel_loops;
-
-    for (int i = 0; i < 2; i++)
-    {
-      kernel_accel_try >>= 1;
-      kernel_loops_try <<= 1;
+    const u32 kernel_accel_try = kernel_accel * 2;
+    const u32 kernel_loops_try = kernel_loops / 2;
 
 
-      if (kernel_accel_try < kernel_accel_min) break;
-      if (kernel_loops_try > kernel_loops_max) break;
-
-      const double exec_ms = try_run (device_param, kernel_accel_try, kernel_loops_try, 1);
-
-      if (exec_ms < exec_best)
-      {
-        kernel_accel_best = kernel_accel_try;
-        kernel_loops_best = kernel_loops_try;
+    if (kernel_accel_try > kernel_accel_max) break;
+    if (kernel_loops_try < kernel_loops_min) break;
 
 
-        exec_best = exec_ms;
-      }
-    }
+    kernel_accel = kernel_accel_try;
+    kernel_loops = kernel_loops_try;
   }
 
   }
 
-  // reset
+  // finally there's a chance that we have a fixed kernel_loops but not a fixed kernel_accel
+  // in such a case the above function would not create any change
+  // we'll use the runtime to find out if we're allow to do last improvement
 
 
-  if (kernel_loops_min < kernel_loops_max)
+  if (exec_ms_final > 0)
   {
   {
-    u32 kernel_accel_try = kernel_accel;
-    u32 kernel_loops_try = kernel_loops;
-
-    for (int i = 0; i < 2; i++)
+    if (exec_ms_final < target_ms)
     {
     {
-      kernel_accel_try <<= 1;
-      kernel_loops_try >>= 1;
+      const double exec_left = target_ms / exec_ms_final;
 
 
-      if (kernel_accel_try > kernel_accel_max) break;
-      if (kernel_loops_try < kernel_loops_min) break;
+      const double accel_left = kernel_accel_max / kernel_accel;
 
 
-      const double exec_ms = try_run (device_param, kernel_accel_try, kernel_loops_try, 1);
+      const double exec_accel_min = MIN (exec_left, accel_left);
 
 
-      if (exec_ms < exec_best)
+      if (exec_accel_min >= 2)
       {
       {
-        kernel_accel_best = kernel_accel_try;
-        kernel_loops_best = kernel_loops_try;
-
-        exec_best = exec_ms;
+        kernel_accel *= exec_accel_min;
       }
     }
   }
 
       }
     }
   }
 
-  // because of the balance we may have some free space left!
-
-  const int exec_left = target_ms / exec_best;
-
-  const int accel_left = kernel_accel_max / kernel_accel_best;
-
-  const int exec_accel_min = MIN (exec_left, accel_left);
-
-  if (exec_accel_min)
-  {
-    kernel_accel_best *= exec_accel_min;
-  }
-
   // reset timer
 
   device_param->exec_pos = 0;
   // reset timer
 
   device_param->exec_pos = 0;
@@ -3046,9 +2953,6 @@ static void autotune (hc_device_param_t *device_param)
 
   // store
 
 
   // store
 
-  kernel_accel = kernel_accel_best;
-  kernel_loops = kernel_loops_best;
-
   device_param->kernel_accel = kernel_accel;
   device_param->kernel_loops = kernel_loops;
 
   device_param->kernel_accel = kernel_accel;
   device_param->kernel_loops = kernel_loops;
 
@@ -3064,12 +2968,11 @@ static void autotune (hc_device_param_t *device_param)
 
     log_info ("Device #%u: autotuned kernel-accel to %u\n"
               "Device #%u: autotuned kernel-loops to %u\n",
 
     log_info ("Device #%u: autotuned kernel-accel to %u\n"
               "Device #%u: autotuned kernel-loops to %u\n",
-              device_param->device_id + 1,
-              kernel_accel,
-              device_param->device_id + 1,
-              kernel_loops);
+              device_param->device_id + 1, kernel_accel,
+              device_param->device_id + 1, kernel_loops);
 
     fprintf (stdout, "%s", PROMPT);
 
     fprintf (stdout, "%s", PROMPT);
+
     fflush (stdout);
   }
 
     fflush (stdout);
   }
 
@@ -3320,41 +3223,13 @@ static void run_cracker (hc_device_param_t *device_param, const uint pws_cnt)
         hc_clEnqueueCopyBuffer (data.ocl, device_param->command_queue, device_param->d_combs, device_param->d_combs_c, 0, 0, innerloop_left * sizeof (comb_t), 0, NULL, NULL);
       }
 
         hc_clEnqueueCopyBuffer (data.ocl, device_param->command_queue, device_param->d_combs, device_param->d_combs_c, 0, 0, innerloop_left * sizeof (comb_t), 0, NULL, NULL);
       }
 
-      choose_kernel (device_param, data.attack_exec, data.attack_mode, data.opts_type, salt_buf, highest_pw_len, pws_cnt);
-
       if (data.benchmark == 1)
       {
       if (data.benchmark == 1)
       {
-        double exec_ms_avg_prev = get_avg_exec_time (device_param, EXEC_CACHE);
-
-        // a few caching rounds
-
-        for (u32 i = 0; i < 2; i++)
-        {
-          hc_timer_set (&device_param->timer_speed);
-
-          choose_kernel (device_param, data.attack_exec, data.attack_mode, data.opts_type, salt_buf, highest_pw_len, pws_cnt);
-
-          double exec_ms_avg = get_avg_exec_time (device_param, EXEC_CACHE);
-
-          exec_ms_avg_prev = exec_ms_avg;
-        }
-
-        // benchmark_repeats became a maximum possible repeats
-
-        for (u32 i = 2; i < data.benchmark_repeats; i++)
-        {
-          hc_timer_set (&device_param->timer_speed);
-
-          choose_kernel (device_param, data.attack_exec, data.attack_mode, data.opts_type, salt_buf, highest_pw_len, pws_cnt);
-
-          double exec_ms_avg = get_avg_exec_time (device_param, EXEC_CACHE);
-
-          if ((exec_ms_avg_prev / exec_ms_avg) < 1.001) break;
-
-          exec_ms_avg_prev = exec_ms_avg;
-        }
+        hc_timer_set (&device_param->timer_speed);
       }
 
       }
 
+      choose_kernel (device_param, data.attack_exec, data.attack_mode, data.opts_type, salt_buf, highest_pw_len, pws_cnt);
+
       if (data.devices_status == STATUS_STOP_AT_CHECKPOINT) check_checkpoint ();
 
       if (data.devices_status == STATUS_CRACKED) break;
       if (data.devices_status == STATUS_STOP_AT_CHECKPOINT) check_checkpoint ();
 
       if (data.devices_status == STATUS_CRACKED) break;
@@ -5374,7 +5249,6 @@ int main (int argc, char **argv)
   uint  version           = VERSION;
   uint  quiet             = QUIET;
   uint  benchmark         = BENCHMARK;
   uint  version           = VERSION;
   uint  quiet             = QUIET;
   uint  benchmark         = BENCHMARK;
-  uint  benchmark_repeats = BENCHMARK_REPEATS;
   uint  show              = SHOW;
   uint  left              = LEFT;
   uint  username          = USERNAME;
   uint  show              = SHOW;
   uint  left              = LEFT;
   uint  username          = USERNAME;
@@ -5472,7 +5346,6 @@ int main (int argc, char **argv)
   #define IDX_FORCE             0xff08
   #define IDX_RUNTIME           0xff09
   #define IDX_BENCHMARK         'b'
   #define IDX_FORCE             0xff08
   #define IDX_RUNTIME           0xff09
   #define IDX_BENCHMARK         'b'
-  #define IDX_BENCHMARK_REPEATS 0xff78
   #define IDX_HASH_MODE         'm'
   #define IDX_ATTACK_MODE       'a'
   #define IDX_RP_FILE           'r'
   #define IDX_HASH_MODE         'm'
   #define IDX_ATTACK_MODE       'a'
   #define IDX_RP_FILE           'r'
@@ -5551,7 +5424,6 @@ int main (int argc, char **argv)
     {"outfile-check-dir", required_argument, 0, IDX_OUTFILE_CHECK_DIR},
     {"force",             no_argument,       0, IDX_FORCE},
     {"benchmark",         no_argument,       0, IDX_BENCHMARK},
     {"outfile-check-dir", required_argument, 0, IDX_OUTFILE_CHECK_DIR},
     {"force",             no_argument,       0, IDX_FORCE},
     {"benchmark",         no_argument,       0, IDX_BENCHMARK},
-    {"benchmark-repeats", required_argument, 0, IDX_BENCHMARK_REPEATS},
     {"restore",           no_argument,       0, IDX_RESTORE},
     {"restore-disable",   no_argument,       0, IDX_RESTORE_DISABLE},
     {"status",            no_argument,       0, IDX_STATUS},
     {"restore",           no_argument,       0, IDX_RESTORE},
     {"restore-disable",   no_argument,       0, IDX_RESTORE_DISABLE},
     {"status",            no_argument,       0, IDX_STATUS},
@@ -5861,7 +5733,6 @@ int main (int argc, char **argv)
       case IDX_LIMIT:             limit             = atoll (optarg);  break;
       case IDX_KEYSPACE:          keyspace          = 1;               break;
       case IDX_BENCHMARK:         benchmark         = 1;               break;
       case IDX_LIMIT:             limit             = atoll (optarg);  break;
       case IDX_KEYSPACE:          keyspace          = 1;               break;
       case IDX_BENCHMARK:         benchmark         = 1;               break;
-      case IDX_BENCHMARK_REPEATS: benchmark_repeats = atoi (optarg);   break;
       case IDX_RESTORE:                                                break;
       case IDX_RESTORE_DISABLE:   restore_disable   = 1;               break;
       case IDX_STATUS:            status            = 1;               break;
       case IDX_RESTORE:                                                break;
       case IDX_RESTORE_DISABLE:   restore_disable   = 1;               break;
       case IDX_STATUS:            status            = 1;               break;
@@ -6604,7 +6475,6 @@ int main (int argc, char **argv)
   data.rp_gen_seed       = rp_gen_seed;
   data.force             = force;
   data.benchmark         = benchmark;
   data.rp_gen_seed       = rp_gen_seed;
   data.force             = force;
   data.benchmark         = benchmark;
-  data.benchmark_repeats = benchmark_repeats;
   data.skip              = skip;
   data.limit             = limit;
   #if defined(HAVE_HWMON) && defined(HAVE_ADL)
   data.skip              = skip;
   data.limit             = limit;
   #if defined(HAVE_HWMON) && defined(HAVE_ADL)
@@ -6679,7 +6549,6 @@ int main (int argc, char **argv)
   logfile_top_uint   (attack_mode);
   logfile_top_uint   (attack_kern);
   logfile_top_uint   (benchmark);
   logfile_top_uint   (attack_mode);
   logfile_top_uint   (attack_kern);
   logfile_top_uint   (benchmark);
-  logfile_top_uint   (benchmark_repeats);
   logfile_top_uint   (bitmap_min);
   logfile_top_uint   (bitmap_max);
   logfile_top_uint   (debug_mode);
   logfile_top_uint   (bitmap_min);
   logfile_top_uint   (bitmap_max);
   logfile_top_uint   (debug_mode);
@@ -10338,7 +10207,7 @@ int main (int argc, char **argv)
                    attack_exec = ATTACK_EXEC_INSIDE_KERNEL;
                    opts_type   = OPTS_TYPE_PT_GENERATE_BE
                                | OPTS_TYPE_PT_UNICODE
                    attack_exec = ATTACK_EXEC_INSIDE_KERNEL;
                    opts_type   = OPTS_TYPE_PT_GENERATE_BE
                                | OPTS_TYPE_PT_UNICODE
-                                                | OPTS_TYPE_PT_ADD80;
+                               | OPTS_TYPE_PT_ADD80;
                    kern_type   = KERN_TYPE_PSTOKEN;
                    dgst_size   = DGST_SIZE_4_5;
                    parse_func  = pstoken_parse_hash;
                    kern_type   = KERN_TYPE_PSTOKEN;
                    dgst_size   = DGST_SIZE_4_5;
                    parse_func  = pstoken_parse_hash;