Click here to Skip to main content
15,879,326 members
Articles / Programming Languages / CUDA

Base64 Encoding on a GPU

Rate me:
Please Sign up or sign in to vote.
4.89/5 (26 votes)
16 Sep 2013LGPL310 min read 63.6K   1.8K   56  
Performing base64 encoding on a graphics processing unit using CUDAfy.NET (CUDA in .NET).
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using System.IO;
using Cudafy;
using Cudafy.Host;
using Cudafy.Types;
using Cudafy.Translator;
using Hybrid.DSP;
namespace Base64EncodingGPUvsCPU
{
    class Program
    {
        public static int LEN = 1024 * 1024 * 36;
        static void Main(string[] args)
        {
            // Generate some random data
            Random ran = new Random(DateTime.Now.Millisecond);
            byte[] ba = new byte[LEN];
            for (int i = 0; i < LEN; i++)
                ba[i] = (byte)ran.Next(Byte.MaxValue);

            Console.WriteLine("Running tests...");

            // Get the first CUDA GPGPU
            GPGPU gpu = CudafyHost.GetDevice(eGPUType.Cuda);
            // Pass the GPGPU to the GConvert constructor
            GConvert gc = new GConvert(gpu);

            // Create streams for output
            MemoryStream cpuStream = new MemoryStream();
            MemoryStream netStream = new MemoryStream();
            MemoryStream gpuStream = new MemoryStream();

            // CPU Tests requires       
            BeginWriteDelegate beginWrite = new BeginWriteDelegate(BeginWrite);
            IAsyncResult res = null;
            string cStr = string.Empty;

            int loops = 10;

            // CPU Test
            StreamWriter cpuSW = new StreamWriter(cpuStream);
            Stopwatch sw = Stopwatch.StartNew();
            for (int j = 0; j < loops; j++)
            {
                cStr = base64_encode(ba);
                // End any previous asynchronous writing
                if (res != null)
                    beginWrite.EndInvoke(res);
                cpuStream.Position = 0;
                // Write the string to the stream in asynchronously
                res = beginWrite.BeginInvoke(cpuSW, cStr, null, null);
            }
            // End any previous asynchronous writing
            if (res != null)
                beginWrite.EndInvoke(res);
            // Flush the writer
            cpuSW.Flush();
            cpuStream.Position = 0;
            Console.WriteLine("CPU av.={0}", sw.ElapsedMilliseconds/loops);
            res = null;

            // CPU .NET ToBase64String Test
            StreamWriter netSW = new StreamWriter(netStream);
            sw.Restart();
            for (int j = 0; j < loops; j++)
            {
                cStr = Convert.ToBase64String(ba);
                // End any previous asynchronous writing
                if (res != null)
                    beginWrite.EndInvoke(res);
                netStream.Position = 0;
                // Write the string to the stream in asynchronously
                res = beginWrite.BeginInvoke(netSW, cStr, null, null);
            }
            // End any previous asynchronous writing
            if (res != null)
                beginWrite.EndInvoke(res);
            // Flush the writer
            netSW.Flush();
            netStream.Position = 0;
            Console.WriteLine(".NET av.={0}", sw.ElapsedMilliseconds / loops);

            // GPU Naive Test
            sw.Restart();
            for (int j = 0; j < loops; j++)
            {
                gc.ToBase64Naive(ba, gpuStream);
                gpuStream.Position = 0;
            }
            Console.WriteLine("GPU naive av.={0}", sw.ElapsedMilliseconds / loops);

            // GPU Test
            sw.Restart();
            for (int j = 0; j < loops; j++)
            {
                gc.ToBase64(ba, gpuStream);
                gpuStream.Position = 0;
            }
            Console.WriteLine("GPU av.={0}", sw.ElapsedMilliseconds / loops);

            // Get the outputs and compare
            byte[] netBytes = new byte[netStream.Length];
            netStream.Read(netBytes, 0, netBytes.Length);
            string netStr = Encoding.UTF8.GetString(netBytes);

            byte[] cpuBytes = new byte[cpuStream.Length];
            cpuStream.Read(cpuBytes, 0, cpuBytes.Length);
            string cpuStr = Encoding.UTF8.GetString(cpuBytes);

            Debug.Assert(netStr == cpuStr);

            byte[] gpuBytes = new byte[gpuStream.Length];
            gpuStream.Read(gpuBytes, 0, gpuBytes.Length);
            string gpuStr = Encoding.UTF8.GetString(gpuBytes);

            Debug.Assert(netStr == gpuStr);
        }

        private delegate void BeginWriteDelegate(StreamWriter sw, string text);

        public static void BeginWrite(StreamWriter sw, string text)
        {
            sw.Write(text);
            sw.Flush();
        }

        static string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

        #region  Acknowledgement

        /* 
   base64.cpp and base64.h

   Copyright (C) 2004-2008 René Nyffenegger

   This source code is provided 'as-is', without any express or implied
   warranty. In no event will the author be held liable for any damages
   arising from the use of this software.

   Permission is granted to anyone to use this software for any purpose,
   including commercial applications, and to alter it and redistribute it
   freely, subject to the following restrictions:

   1. The origin of this source code must not be misrepresented; you must not
      claim that you wrote the original source code. If you use this source code
      in a product, an acknowledgment in the product documentation would be
      appreciated but is not required.

   2. Altered source versions must be plainly marked as such, and must not be
      misrepresented as being the original source code.

   3. This notice may not be removed or altered from any source distribution.

   René Nyffenegger rene.nyffenegger@adp-gmbh.ch

*/
        #endregion

        public static string base64_encode(byte[] bytes_to_encode)
        {         
            int i = 0;
            int j = 0;
            int ctr = 0;
            // Initialize StringBuilder to required capacity.
            StringBuilder sb = new StringBuilder((bytes_to_encode.Length * 4) / 3);
            // Local array for group of three bytes
            int[] char_array_3 = new int[3];
            // Local array for output 
            int[] char_array_4 = new int[4];
            int in_len = bytes_to_encode.Length;
            // Loop until all bytes have been read
            while (in_len-- > 0)
            {
                // Read bytes into local array
                char_array_3[i++] = bytes_to_encode[ctr++];
                // Once three bytes have been read, begin encoding
                if (i == 3)
                {
                    // 1st byte: Mask most significant 6-bits and move 2 bits to the right
                    char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
                    // 1st byte: Mask least significant 2-bits and move 4 bits left
                    // 2nd byte: Mask most significant 4-bits and move 4 bits right
                    // Add values
                    char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
                    // 2nd byte: Mask least significant 4-bits and move 2 bits left
                    // 3rd byte: Mask most significant 2-bits and move 6 bits right
                    // Add values
                    char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
                    // 3rd byte: Mask least significant 6-bits
                    char_array_4[3] = char_array_3[2] & 0x3f;
                    // Select the base64 characters from the base64_chars array and write to output
                    for (i = 0; (i < 4); i++)
                    {
                        char c = base64_chars[char_array_4[i]];
                        sb.Append(c);
                    }
                    i = 0;
                }
            }
            // If the total number of bytes is not a multiple of 3 then handle the last group
            if (i != 0)
            {
                // Set remaining bytes to zero
                for (j = i; j < 3; j++)
                    char_array_3[j] = 0;
                // Handle the group as before
                char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
                char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
                char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
                char_array_4[3] = char_array_3[2] & 0x3f;

                for (j = 0; (j < i + 1); j++)
                {
                    char c = base64_chars[char_array_4[j]];
                    sb.Append(c);
                }
                // Add padding characters
                while ((i++ < 3))
                    sb.Append('=');

            }
            // Convert to string and return
            string s = sb.ToString();
            return s;
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The GNU Lesser General Public License (LGPLv3)


Written By
Systems Engineer Hybrid DSP Systems
Netherlands Netherlands
Nick is co owner of Hybrid DSP, a company specialized in high speed data acquisition, processing and storage.

CUDAfy.NET took considerable effort to develop and we ask nothing in return from users of the LGPL library other than that you please consider donating to Harmony through Education. This small charity helps handicapped children in developing countries by providing suitable schooling.

Comments and Discussions