ANU The Australian National University



____________________________________________________

[ANU] [DCS] [COMP2100/2500] [Description] [Schedule] [Lectures] [Labs] [Homework] [Assignments] [COMP2500] [Assessment] [PSP] [Java] [Reading] [Help]

____________________________________________________

COMP2100/2500
Lab 6: The Java/C Interface

Summary

This class is about learning to incorporate routines written in C into Java systems.

Aims

Preparation

Review your notes from Lecture 21, Lecture 22, Lecture 23, Lecture 24, and Lecture 26. Refresh your understanding of Design by Contract.


Exercise 1 - Getting Started

The idea is to re-implement some of the features of arrays using routines written in C. You could imagine that the performance of the standard Java arrays has been found to be unsatisfactory, and we're developing a drop-in substitute that uses C code to increase efficiency. (In the last exercise you'll get a chance to test whether this really works or not.)

We'll be working on a system with the following three components:

For simplicity, the arrays we're implementing today are not resizable, nor is this a generic class. These are fixed size arrays of integers only (hence the name).

Download the three files listed above and take a few minutes to read through them and see what they do. You'll see that class ArrayTester is complete, but with a few lines commented out; that the C language part of the array implementation is complete; but that the Java class IntegerArray is incomplete. In particular, there is no communication yet between Java and C.

(Richard's note: does this remind you of anything? We did something just like this in COMP1110 lab 2, exercise 2. Back then, we were working entirely in Java. This time, we're implementing a "back end" in C.)

You can still compile and run the program, although it won't do anything very interesting. Do this now, using the Makefile. The default target (run) compiles and runs the program interactively. Once you understand what the program does, you can also try the target out.txt, which still runs the program interactively but uses the tee command to save a copy in a file.

Right now, a sample run, with 5 for lower and 10 for upper, looks like this (you type what's in bold):

make
env LD_LIBRARY_PATH=. java ArrayTester
Lower = 
5
Upper = 
10
0

Exercise 2 - Creation

The implementation of the constructor IntegerArray() is missing, although its contract is given. In integer_array.c there is a function new_array that uses the standard library routine calloc to return a pointer to enough memory to store n integers, and sets each element to zero. There are two things for you to do:

  1. Write a private Java wrapper for new_array so that you can call it from inside class IntegerArray. You will need to use the native keyword from Lecture 26. The return type of the method will be int (because the C code has a cast to jint).

  2. Notice that this class has a private field int arrayObject. The purpose of this is so that an object can keep track of where its array elements are stored. Write an implementation for public IntegerArray(int lower, int upper) that uses new_array to set arrayObject to the location of the memory needed for the array. (Of course, the constructor will also set the other private fields lower and upper to the values of the corresponding parameters.)

    There is a precondition on this routine, given using the JML syntax. Let's assume that we're not going to use the JML tools, and we're going to write our own parameter checking. Code the precondition into a check inside the body of the constructor as per the comment.

  3. Hint: Be careful to take into account the different ranges of index values: in C (as in Java) array indices always run from 0 to n-1, but we are constructing arrays where the lower and upper bounds can be arbitrary integers.

Recompile and run the system to make sure that this works OK. It should now print out the contents of an array with the correct bounds, but with every element equal to zero.

For example, a sample run, with 5 for lower and 10 for upper, looks like this (again, you type what's in bold):

make
env LD_LIBRARY_PATH=. java ArrayTester
Lower = 
5
Upper = 
10
0
0
0
0
0
0

Exercise 3 - Access

The implementation of the access feature item is also missing. (At the moment it just returns zero.) Again there is a useful C function c_item in array.c that you can use. Write a Java wrapper for this function, and then write an implementation of item that uses this. Remember to adjust your indices so that the index you pass to the C side is the right one in the range 0..(upper-lower). Notice that c_item treats a pointer as an array; this is standard practice in C. Again, take the time to implement the precondition.

Again, recompile and run. There won't be any difference in the output yet, since we haven't implemented put.


Exercise 4 - Modification

We just need to implement put in order to have a basic working array class. Again you will find a C function c_put in array.c, that does pretty much what you need. Write a wrapper for it and a body for put.

Implement the checking of the pre- and postcondition. The precondition for put is particularly important. Without it, the C routine could try to write to just about any location in memory.

This time when you compile and run, you should get more interesting results. Once again, remember to convert your Java index to a C index in the right range.

If everything has been done right, a sample run, with 5 for lower and 10 for upper, looks like this (again, you type what's in bold):

make
env LD_LIBRARY_PATH=. java ArrayTester
Lower = 
5
Upper = 
10
5
6
7
8
9
10

Exercise 5 - Sorting with C

So far there hasn't been much chance of significant performance differences between the Java and C implementations. But with a serious computational operation like sorting, there could be a big difference.

Look at the commented-out lines in the constructor of the ArrayTester class. These lines call two built-in features of class IntegerArray: sortAscending and sortDescending. We will implement one of these in C and the other in Java.

  1. In array.c you will see two functions c_sort_descending and c_swap that together implement the Quicksort algorithm for sorting a part of an array. Write a Java wrapper for c_sort_descending.

  2. Fill in the body of sortDescending with an appropriate call to c_sort_descending.

  3. Now un-comment-out three lines so that the section of ArrayTester looks like this:

            // t.start();
            a.sortDescending();
            // t.stop();
            // System.out.println("Sort elapsed time: " + t.elapsedCPUSeconds());
            System.out.println("Descending:");
            printArray(a);
    
    then recompile and run. Make sure that this operation works correctly before continuing.

  4. If everything has been done right, a sample run, with 5 for lower and 10 for upper, looks like this (again, you type what's in bold):

    make
    env LD_LIBRARY_PATH=. java ArrayTester
    Lower = 
    5
    Upper = 
    10
    5
    6
    7
    8
    9
    10
    Descending
    10
    9
    8
    7
    6
    5
    

Exercise 6 - Sorting with Java

Now you have to write the other sorting routine sortAscending, that you are to implement in Java rather than C. Here are the steps.

  1. Write a Java procedure quicksortRegion in IntegerArray.java that takes two parameters lo and hi and sorts the part of the array between lo and hi into ascending order. The implementation of this can be an exact translation into Java of the C code for c_sort_descending, except that the direction of the inequality in the if statement inside the loop will need to be reversed.

    (Oddly enough the routine sometimes gets called (recursively) with lo > hi without it being an error, so be careful with preconditions.)

  2. Write a procedure swap that swaps two elements of the array. Don't just write a wrapper for c_swap; instead implement this completely in Java, using calls to item and put.

  3. Finally fill in the body of sortAscending so that it calls quicksortRegion in such a way that it sorts the entire array.

You should now be able to un-comment-out the appropriate lines of ArrayTester.java and compile and run the test program in its entirety. Check that it works correctly.


*Exercise 7 - Comparing the speed

Download the code for class Timer (in file Timer.java) and its C implementation part in the file timer.c. Incorporate these into your system so that you can compare the speeds of the two sorting routines. Uncomment the remaining lines of ArrayTester that create a timer and have it timing the sort procedures. Make sure to comment out all the calls to printArray(), because you will need to specify large arrays in order to get useful timings (i.e. in seconds).

Now go crazy and use everything you've learned this semester:

  1. Modify the ArrayTester class so that it reads the array bounds from the command line.

  2. Write a test script that runs your program on different sized data sets.

  3. Add a new Makefile target that automates the testing process and produces a testing report giving a table of speed comparisons between the two sorting routines.

How do you explain the difference in performance?


**Exercise 8 - Resizable generic arrays

This question goes well beyond the scope of this course. Trying to implement a solution could be time-consuming, and will certainly require good C programming skills.

The arrays we've been dealing with have been fixed size: once created, there is no possibility of changing the number of elements. Think about the issues involved in removing this restriction. This would mean implementing such operations as addLast and removing the precondition on put. What possible strategies are there? What effect might this have on efficiency? If you have time, try implementing one of your strategies.

The other restriction we have made was on the type of the array elements. Java arrays can be arrays of anything. How might you implement this? The solution is probably to have arrays of pointers, with each pointer giving the location of the array element (object). Think about the issues involved here. Do you think you can come up with a solution, or are there details you need to know of how Java objects are represented in memory?

____________________________________________________

[ANU] [DCS] [COMP2100/2500] [Description] [Schedule] [Lectures] [Labs] [Homework] [Assignments] [COMP2500] [Assessment] [PSP] [Java] [Reading] [Help]

____________________________________________________

Copyright © 2005, Ian Barnes & Richard Walker, The Australian National University
Version 2005.2, Sunday, 22 May 2005, 18:17:16 +1000
Feedback & Queries to comp2100@cs.anu.edu.au