0

I'm learning to use Rootbeer, but I got stuck when I ran its sample apps, and no one could answer my question : Rootbeer runtime error, how to fix?

So I downloaded the source code of Rootbeer, and took a look at the code, here is where the problem is [ CUDAContext.java:119 ]:

          public void setKernel(Kernel kernelTemplate) {
            this.kernelTemplate = kernelTemplate;
 [ 119 ]    this.compiledKernel = (CompiledKernel) kernelTemplate;
          }

And the definitions of Kernel and CompiledKernel are :

public interface Kernel
{
  public void gpuMethod();
}

public interface CompiledKernel
{
  public String getCodeUnix();

  public String getCodeWindows();

  public int getNullPointerNumber();

  public int getOutOfMemoryNumber();

  public String getCubin32();

  public int getCubin32Size();

  public boolean getCubin32Error();

  public String getCubin64();

  public int getCubin64Size();

  public boolean getCubin64Error();

  public Serializer getSerializer(Memory memory,Memory memory1);

  public boolean isUsingGarbageCollector();
}

Is the cast done properly in line 119 ? If it is, why did I get the error saying :

java.lang.ClassCastException: ArrayMult cannot be cast to org.trifort.rootbeer.runtime.CompiledKernel
    at org.trifort.rootbeer.runtime.CUDAContext.setKernel(CUDAContext.java:119)

If it's not done correctly, what's the right way to cast it ?

Edit : Here is the sample code

import java.util.List;
import java.util.ArrayList;
import org.trifort.rootbeer.runtime.Kernel;
import org.trifort.rootbeer.runtime.Rootbeer;

public class ArrayMultApp
{  
  public ArrayMultApp()
  {
    int[] array=new int[10];
    for (int i=0;i<array.length;++i) array[i]=i;
    for (int i=0;i<array.length;++i) Out("start array["+i+"]: "+array[i]);
    multArray(array);
    for (int i=0;i<array.length;++i) Out("final array["+i+"]: "+array[i]);
  }

  public void multArray(int[] array)
  {
    try
    {
      List<Kernel> jobs=new ArrayList();
      for (int i=0;i<array.length;++i) jobs.add(new ArrayMult(array,i));
      Rootbeer rootbeer=new Rootbeer();
      rootbeer.run(jobs);
    }
    catch (Exception e) { e.printStackTrace(); }
  }

  public static void main(String[] args) { ArrayMultApp app=new ArrayMultApp(); }

  private static void out(String message) { System.out.print(message); }

  private static void Out(String message) { System.out.println(message); }
}

class ArrayMult implements Kernel
{
  private int[] m_source;
  private int m_index;

  public ArrayMult(int[] source,int index)
  {
    m_source=source;
    m_index=index;
  }

  public void gpuMethod() { m_source[m_index]*=11; }
}
Community
  • 1
  • 1
Frank
  • 30,590
  • 58
  • 161
  • 244
  • The passed `Kernel` object doesn't also implement `CompiledKernel`. Did you mean for `CompiledKernel` to extend `Kernel`? – Colonel Thirty Two Dec 14 '14 at 16:29
  • You can't cast an object to a type it is not, there is no proper way to do this. It's a bit like asking, what is the proper way to turn an orange into an apple, you can't as it's not an apple. – Peter Lawrey Dec 14 '14 at 16:40
  • I think you did not init the Context in the right way. – neohope Dec 14 '14 at 17:40

3 Answers3

1

No it's not. You have two different interface.

     public void setKernel(Kernel kernelTemplate) {
        this.kernelTemplate = kernelTemplate;
 [ 119 ]    this.compiledKernel = (CompiledKernel) kernelTemplate;
      }

On 119, you are trying to cast Kernel to CompiledKernel each of them has their own hierarchy. If CompiledKernel extends Kernel, then this would work.

SMA
  • 36,381
  • 8
  • 49
  • 73
  • No, it would only work if Kernel extends CompiledKernel. – Daniel Dec 14 '14 at 17:48
  • "Kernel extends CompiledKernel" won't compile. Now I changed it to "CompiledKernel extends Kernel" copmiles OK, but still get the same runtime error. – Frank Dec 14 '14 at 20:06
1

I do not have a G card, thus I can not test your code. I looked through the source code. The author did this trick in org.trifort.rootbeer.compiler.Transform2.java

public void run(String cls){    
  OpenCLScene scene = new OpenCLScene();
  OpenCLScene.setInstance(scene);
  scene.init();

  SootClass soot_class1 = Scene.v().getSootClass(cls);
  SootMethod method = soot_class1.getMethod("void gpuMethod()");

  String uuid = getUuid();
  GenerateForKernel generator = new GenerateForKernel(method, uuid);
  try {
    generator.makeClass();
  } catch(Exception ex){
    ex.printStackTrace();
    OpenCLScene.releaseV();
    return;
  }

  //add an interface to the class
  SootClass soot_class = method.getDeclaringClass();
  SootClass iface_class = Scene.v().getSootClass("org.trifort.rootbeer.runtime.CompiledKernel");
  soot_class.addInterface(iface_class);

  System.out.println("added interface CompiledKernel");

  OpenCLScene.releaseV();
}

I also looked through his demo code, "examples\sort\src\org\trifort\rootbeer\sort\GPUSort.java". The author did init the Contex, which is quit different from your code. I suggest you to try his code first. I bet it invoke the Transform2.run function while your code does not.

public void sort(){
  //should have 192 threads per SM
  int size = 2048;
  int sizeBy2 = size / 2;
  //int numMultiProcessors = 14;
  //int blocksPerMultiProcessor = 512;
  int numMultiProcessors = 2;
  int blocksPerMultiProcessor = 256;
  int outerCount = numMultiProcessors*blocksPerMultiProcessor;
  int[][] array = new int[outerCount][];
  for(int i = 0; i < outerCount; ++i){
    array[i] = newArray(size);
  }

  Rootbeer rootbeer = new Rootbeer();
  List<GpuDevice> devices = rootbeer.getDevices();
  GpuDevice device0 = devices.get(0);
  Context context0 = device0.createContext(4212880);
  context0.setCacheConfig(CacheConfig.PREFER_SHARED);
  context0.setThreadConfig(sizeBy2, outerCount, outerCount * sizeBy2);
  context0.setKernel(new GPUSortKernel(array));
  context0.buildState();
  ......
}
neohope
  • 1,822
  • 15
  • 29
  • Thanks for the insight, seems you are on to something, but I don't quite get it, the code I ran was from his example, I found online that other people had the same issue with this code, how would you suggest I change his sample to make it work ? I've just added the code to the question. – Frank Dec 14 '14 at 19:09
  • Try to compile this example first https://github.com/pcpratts/rootbeer1/tree/master/examples/sort. Pay attention to the code around line 60-67, in GPUSort.java. – neohope Dec 15 '14 at 02:38
  • I tried, and got "GPUSortKernel cannot be cast to org.trifort.rootbeer.runtime.CompiledKernel" at line 65 [ setKernal ] – Frank Dec 15 '14 at 23:59
0

You can only cast to an interface if the actual object implements that interface. I don't know much about CUDA, but there may be a method somewhere that takes a Kernel, and returns a CompiledKernel. Simply casting isn't going to do that.

On the other hand, if you are the creator of the "ArrayMult" class, then you can solve this issue by implementing both Kernel and CompiledKernel.

Daniel
  • 4,481
  • 14
  • 34