C# Task Control Example

← All NMath Code Examples

 

using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Threading.Tasks;

using CenterSpace.NMath.Core;
using CenterSpace.NMath.Matrix;

namespace CenterSpace.NMath.Core.Examples.CSharp.GPU
{
  class TaskControlExample
  {

    static void Main( string[] args )
    {
      ////////
      // Routing work routines to devices.
      ///////

      // Using the BridgeManager it's easy to route individual threaded tasks to a given device.  Remember that compute devices encompass both the CPU
      // and all installed GPU's. In this example we run a task on the CPU in parallel with a task on the GPU.  If multiple GPU's are installed the
      // same technique can be used to offload tasks to each of the GPUs to leverage all installed hardware in parallel.

      NMathConfiguration.Init();


      // Check for 32-bit process and GPU
      if ( !Environment.Is64BitProcess )
      {
        Console.WriteLine( "NMath is unable to use GPU functionality in a 32-bit process." );
      }
      else if ( BridgeManager.Instance.GPUCount == 0 )
      {
        Console.WriteLine( "NMath was unable to detect a suitable NVIDIA GPU." );
      }
      else
      {
        // Set up a string writer for logging
        using ( var writer = new StringWriter() )
        {

          // Enable the CPU/GPU bridge logging
          BridgeManager.Instance.EnableLogging( writer );

          // Build the task array and assign matrix multiply jobs to those tasks.  Any number of tasks can be
          // added here and any number of tasks can be assigned to a particular device.   Note that the task to 
          // device assignment is done in each task (below).
          Task[] tasks = new Task[2]
            {
            Task.Factory.StartNew(() => TimedMatrixMultiplyCPU(1299)),
            Task.Factory.StartNew(() => TimedMatrixMultiplyGPU(1301)),
            };

          // Block until all tasks complete
          Task.WaitAll( tasks );

          Console.WriteLine( FormatLog( writer ) );
          // Use the logging system to verify where these matrix multiplications ran. Note that dgemm is the LAPACK name for matrix multiplication.  
          // 
          //     Time                       tid   Device#  Function    Device Used  Reason
          // 2014-03-04 02:23:01.915 PM      4       0       dgemm            GPU     Above threshold; 1301x1301 = 1692601 >= 640000 (crossover 800)
          // 2014-03-04 02:23:01.915 PM      5       -1      dgemm            CPU     All computations routed to CPU
          //
          // The log file shows that one matrix multiply (1301 x 1301) was run on the GPU and a second was run on the CPU (always device -1).

          // Disable logging
          BridgeManager.Instance.DisableLogging();
        }
      }

      Console.WriteLine();
      Console.WriteLine( "Press Enter Key" );
      Console.Read();
    }

    private static void TimedMatrixMultiplyGPU( int size )
    {
      // Place this task on the GPU.
      IComputeDevice device = BridgeManager.Instance.GetComputeDevice( 0 );
      BridgeManager.Instance.SetComputeDevice( device );

      var timer = new Stopwatch();
      var A = new DoubleMatrix( size, size, 0, 1 );
      timer.Reset();
      timer.Start();
      NMathFunctions.Product( A, A );
      timer.Stop();
      Console.WriteLine( "Finished matrix multiplication of size " + size + " on the GPU  (" + timer.ElapsedMilliseconds + " ms).\n" );
    }

    private static void TimedMatrixMultiplyCPU( int size )
    {
      // Place this task on the CPU.
      BridgeManager.Instance.SetComputeDevice( BridgeManager.Instance.CPU );

      var timer = new Stopwatch();
      var A = new DoubleMatrix( size, size, 0, 1 );
      timer.Reset();
      timer.Start();
      NMathFunctions.Product( A, A );
      timer.Stop();
      Console.WriteLine( "Finished matrix multiplication of size " + size + " on the CPU  (" + timer.ElapsedMilliseconds + " ms).\n" );
    }

    // Auxiliary function for improving the readability of 
    // of the log file in the small console window.
    private static string FormatLog( StringWriter writer )
    {
      StringReader reader = new StringReader( writer.ToString() );
      string line;
      StringBuilder ret = new StringBuilder();
      ret.Append( "\nNMath Log File -----------------------------------------------------------\n" );
      ret.Append( String.Format( "Time\t\t\t\tFunction\tDevice Used\n" ) );
      reader.ReadLine();
      while ( ( line = reader.ReadLine() ) != null )
      {
        string[] parts = line.Split( '\t' );
        ret.Append( parts[0] + '\t' + parts[3] + "\t\t" + parts[5] + '\n' );
        ret.Append( "Reason: " + parts[6] + "\n\n" );
      }

      return ret.ToString();
    }
  }
}

← All NMath Code Examples
Top