]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
Make Reed-Solomon faster by using power of generator representation of
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Sun, 13 Nov 2011 13:48:19 +0000 (14:48 +0100)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Sun, 13 Nov 2011 13:48:19 +0000 (14:48 +0100)
GF(256)*.

* grub-core/lib/reed_solomon.c (grub_uint16_t) [TEST]: Removed.
(gf_double_t): Likewise.
(gf_invert): Removed.
(gf_powx): New array.
(gf_powx_inv): Likewise.
(scratch): Move higher.
(gf_reduce): Removed.
(gf_mul): Use powx.
(gf_invert): Likewise.
(init_inverts): Replaced with ...
(init_powx): ...this. All users updated.
(pol_evaluate): Replace multiplications with additions.
(rs_encode): Likewise.
(gauss_eliminate): Call gf_invert.
(grub_reed_solomon_add_redundancy): Call init_powx.
(grub_reed_solomon_recover): Call init_powx unconditionally.

ChangeLog
grub-core/lib/reed_solomon.c

index 623313b3ce082ad9d029d05120eee7a421870acf..2295670146a2a7ae5116536e3fd0ac91a0948be2 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,25 @@
+2011-11-13  Vladimir Serbinenko  <phcoder@gmail.com>
+
+       Make Reed-Solomon faster by using power of generator representation of
+       GF(256)*.
+
+       * grub-core/lib/reed_solomon.c (grub_uint16_t) [TEST]: Removed.
+       (gf_double_t): Likewise.
+       (gf_invert): Removed.
+       (gf_powx): New array.
+       (gf_powx_inv): Likewise.
+       (scratch): Move higher.
+       (gf_reduce): Removed.
+       (gf_mul): Use powx.
+       (gf_invert): Likewise.
+       (init_inverts): Replaced with ...
+       (init_powx): ...this. All users updated.
+       (pol_evaluate): Replace multiplications with additions.
+       (rs_encode): Likewise.
+       (gauss_eliminate): Call gf_invert.
+       (grub_reed_solomon_add_redundancy): Call init_powx.
+       (grub_reed_solomon_recover): Call init_powx unconditionally.
+
 2011-11-12  Vladimir Serbinenko  <phcoder@gmail.com>
 
        * grub-core/partmap/gpt.c (gpt_partition_map_embed): Fix spelling.
index 78d249c2f379b72e59d292949c22b8a8a17a45bc..7da5f204c749aede26a315ac96a839b745b244ed 100644 (file)
@@ -29,7 +29,6 @@
 #ifdef TEST
 typedef unsigned int grub_size_t;
 typedef unsigned char grub_uint8_t;
-typedef unsigned short grub_uint16_t;
 #else
 #include <grub/types.h>
 #include <grub/reed_solomon.h>
@@ -42,7 +41,6 @@ typedef unsigned short grub_uint16_t;
 #ifdef TEST
 typedef unsigned int grub_size_t;
 typedef unsigned char grub_uint8_t;
-typedef unsigned short grub_uint16_t;
 #else
 #include <grub/types.h>
 #include <grub/misc.h>
@@ -53,65 +51,72 @@ grub_reed_solomon_recover (void *ptr_, grub_size_t s, grub_size_t rs);
 
 #define GF_SIZE 8
 typedef grub_uint8_t gf_single_t;
-typedef grub_uint16_t gf_double_t;
 #define GF_POLYNOMIAL 0x1d
 #define GF_INVERT2 0x8e
 #if defined (STANDALONE) && !defined (TEST)
-static gf_single_t * const gf_invert __attribute__ ((section(".text"))) = (void *) 0x100000;
-static char *scratch __attribute__ ((section(".text"))) = (void *) 0x100100;
+static gf_single_t * const gf_powx __attribute__ ((section(".text"))) = (void *) 0x100000;
+static gf_single_t * const gf_powx_inv __attribute__ ((section(".text"))) = (void *) 0x100200;
+
+static char *scratch __attribute__ ((section(".text"))) = (void *) 0x100300;
 #else
 #if defined (STANDALONE)
 static char *scratch;
 #endif
-static gf_single_t gf_invert[256];
+static gf_single_t gf_powx[255 * 2];
+static gf_single_t gf_powx_inv[256];
 #endif
 
 #define SECTOR_SIZE 512
 #define MAX_BLOCK_SIZE (200 * SECTOR_SIZE)
 
 static gf_single_t
-gf_reduce (gf_double_t a)
+gf_mul (gf_single_t a, gf_single_t b)
 {
-  int i;
-  for (i = GF_SIZE - 1; i >= 0; i--)
-    if (a & (1ULL << (i + GF_SIZE)))
-      a ^= (((gf_double_t) GF_POLYNOMIAL) << i);
-  return a & ((1ULL << GF_SIZE) - 1);
+  if (a == 0 || b == 0)
+    return 0;
+  return gf_powx[(int) gf_powx_inv[a] + (int) gf_powx_inv[b]];
 }
 
-static gf_single_t
-gf_mul (gf_single_t a, gf_single_t b)
+static inline gf_single_t
+gf_invert (gf_single_t a)
 {
-  gf_double_t res = 0;
-  int i;
-  for (i = 0; i < GF_SIZE; i++)
-    if (b & (1 << i))
-      res ^= ((gf_double_t) a) << i;
-  return gf_reduce (res);
+  return gf_powx[255 - (int) gf_powx_inv[a]];
 }
 
 static void
-init_inverts (void)
+init_powx (void)
 {
-  gf_single_t a = 1, ai = 1;
-  do
+  int i;
+  grub_uint8_t cur = 1;
+
+  for (i = 0; i < 255; i++)
     {
-      a = gf_mul (a, 2);
-      ai = gf_mul (ai, GF_INVERT2);
-      gf_invert[a] = ai;
+      gf_powx[i] = cur;
+      gf_powx[i + 255] = cur;
+      gf_powx_inv[cur] = i;
+      if (cur & (1ULL << (GF_SIZE - 1)))
+       cur = (cur << 1) ^ GF_POLYNOMIAL;
+      else
+       cur <<= 1;
     }
-  while (a != 1);
 }
 
 static gf_single_t
 pol_evaluate (gf_single_t *pol, grub_size_t degree, gf_single_t x)
 {
   int i;
-  gf_single_t xn = 1, s = 0;
+  gf_single_t s = 0;
+  int log_xn = 0, log_x;
+  if (x == 0)
+    return pol[0];
+  log_x = gf_powx_inv[x];
   for (i = degree; i >= 0; i--)
     {
-      s ^= gf_mul (pol[i], xn);
-      xn = gf_mul (x, xn);
+      if (pol[i])
+       s ^= gf_powx[(int) gf_powx_inv[pol[i]] + log_xn];
+      log_xn += log_x;
+      if (log_xn >= ((1 << GF_SIZE) - 1))
+       log_xn -= ((1 << GF_SIZE) - 1);
     }
   return s;
 }
@@ -120,7 +125,7 @@ pol_evaluate (gf_single_t *pol, grub_size_t degree, gf_single_t x)
 static void
 rs_encode (gf_single_t *data, grub_size_t s, grub_size_t rs)
 {
-  gf_single_t *rs_polynomial, a = 1;
+  gf_single_t *rs_polynomial;
   int i, j;
   gf_single_t *m;
   m = xmalloc ((s + rs) * sizeof (gf_single_t));
@@ -132,16 +137,14 @@ rs_encode (gf_single_t *data, grub_size_t s, grub_size_t rs)
   /* Multiply with X - a^r */
   for (j = 0; j < rs; j++)
     {
-      if (a & (1 << (GF_SIZE - 1)))
-       {
-         a <<= 1;
-         a ^= GF_POLYNOMIAL;
-       }
-      else
-       a <<= 1;
       for (i = 0; i < rs; i++)
-       rs_polynomial[i] = rs_polynomial[i + 1] ^ gf_mul (a, rs_polynomial[i]);
-      rs_polynomial[rs] = gf_mul (a, rs_polynomial[rs]);
+       if (rs_polynomial[i])
+         rs_polynomial[i] = (rs_polynomial[i + 1]
+                             ^ gf_powx[j + (int) gf_powx_inv[rs_polynomial[i]]]);
+       else
+         rs_polynomial[i] = rs_polynomial[i + 1];
+      if (rs_polynomial[rs])
+       rs_polynomial[rs] = gf_powx[j + (int) gf_powx_inv[rs_polynomial[rs]]];
     }
   for (j = 0; j < s; j++)
     if (m[j])
@@ -190,7 +193,7 @@ gauss_eliminate (gf_single_t *eq, int n, int m, int *chosen)
       if (nzidx == m)
        continue;
       chosen[i] = nzidx;
-      r = gf_invert [eq[i * (m + 1) + nzidx]];
+      r = gf_invert (eq[i * (m + 1) + nzidx]);
       for (j = 0; j < m + 1; j++)
        eq[i * (m + 1) + j] = gf_mul (eq[i * (m + 1) + j], r);
       for (j = i + 1; j < n; j++)
@@ -437,6 +440,8 @@ grub_reed_solomon_add_redundancy (void *buffer, grub_size_t data_size,
   if (!rs)
     return;
 
+  init_powx ();
+
   while (s > 0)
     {
       grub_size_t tt;
@@ -468,9 +473,7 @@ grub_reed_solomon_recover (void *ptr_, grub_size_t s, grub_size_t rs)
   if (!rs)
     return;
 
-#if defined (STANDALONE)
-  init_inverts ();
-#endif
+  init_powx ();
 
   while (s > 0)
     {
@@ -500,12 +503,15 @@ main (int argc, char **argv)
   grub_size_t s, rs;
   char *buf;
 
+  grub_memset (gf_powx, 0xee, sizeof (gf_powx));
+  grub_memset (gf_powx_inv, 0xdd, sizeof (gf_powx_inv));
+
 #ifdef STANDALONE
   scratch = xmalloc (1048576);
 #endif
 
 #ifndef STANDALONE
-  init_inverts ();
+  init_powx ();
 #endif
 
   in = fopen ("tst.bin", "rb");
@@ -514,7 +520,7 @@ main (int argc, char **argv)
   fseek (in, 0, SEEK_END);
   s = ftell (in);
   fseek (in, 0, SEEK_SET);
-  rs = s / 3;
+  rs = 0x7007;
   buf = xmalloc (s + rs + SECTOR_SIZE);
   fread (buf, 1, s, in);
   fclose (in);
@@ -524,8 +530,9 @@ main (int argc, char **argv)
   out = fopen ("tst_rs.bin", "wb");
   fwrite (buf, 1, s + rs, out);
   fclose (out);
-
+#if 0
   grub_memset (buf + 512 * 15, 0, 512);
+#endif
 
   out = fopen ("tst_dam.bin", "wb");
   fwrite (buf, 1, s + rs, out);