[m-rev.] for review: no native code for java
Peter Wang
novalazy at gmail.com
Fri Aug 14 11:50:05 AEST 2009
Branches: main
Make the Java backend not use native code to implement any standard library
procedures. The only such procedures were related to benchmarking and timing,
which aren't very important so I just make a best effort using methods that
the Java standard library provides.
library/benchmarking.m:
Implement `benchmarking.report_stats' for Java as closely as possible
without native code. Add real time output.
Add `benchmarking.ML_initialise' to remember the time when the
program starts up.
compiler/mlds_to_java.m:
Make the main wrapper call `benchmarking.ML_initialise' at startup.
library/time.m:
Implement `time.clock', `time.times', `time.clocks_per_sec',
`time.clk_tck' as closely as possible without native code.
library/Mmakefile:
Comment out commands to build and install Native.so.
java/runtime/Native.c:
Even though this is not used any more, update the function names for
the "jmercury" package prefix.
diff --git a/compiler/mlds_to_java.m b/compiler/mlds_to_java.m
index 4622db5..58b892a 100644
--- a/compiler/mlds_to_java.m
+++ b/compiler/mlds_to_java.m
@@ -1673,6 +1673,7 @@ write_main_driver(Indent, ClassName, !IO) :-
"jmercury.runtime.JavaInternal.progname = """ ++ ClassName ++ """;",
"jmercury.runtime.JavaInternal.args = args;",
"jmercury.runtime.JavaInternal.exit_status = 0;",
+ "benchmarking.ML_initialise();",
"try {",
" " ++ ClassName ++ ".main_2_p_0();",
" jmercury.runtime.JavaInternal.run_finalisers();",
diff --git a/java/runtime/Native.c b/java/runtime/Native.c
index 570b167..977ff6c 100644
--- a/java/runtime/Native.c
+++ b/java/runtime/Native.c
@@ -15,14 +15,14 @@
* Method: clock
* Signature: ()I
*/
-JNIEXPORT jint JNICALL Java_mercury_runtime_Native_clock(JNIEnv *, jclass);
+JNIEXPORT jint JNICALL Java_jmercury_runtime_Native_clock(JNIEnv *, jclass);
/*
* Class: Native
* Method: clocks_per_sec
* Signature: ()I
*/
-JNIEXPORT jint JNICALL Java_mercury_runtime_Native_clocks_1per_1sec(
+JNIEXPORT jint JNICALL Java_jmercury_runtime_Native_clocks_1per_1sec(
JNIEnv *, jclass);
/*
@@ -30,7 +30,7 @@ JNIEXPORT jint JNICALL Java_mercury_runtime_Native_clocks_1per_1sec(
* Method: times
* Signature: ()[I
*/
-JNIEXPORT jintArray JNICALL Java_mercury_runtime_Native_times(
+JNIEXPORT jintArray JNICALL Java_jmercury_runtime_Native_times(
JNIEnv *, jclass);
/*
@@ -38,14 +38,14 @@ JNIEXPORT jintArray JNICALL Java_mercury_runtime_Native_times(
* Method: clk_tck
* Signature: ()I
*/
-JNIEXPORT jint JNICALL Java_mercury_runtime_Native_clk_1tck(JNIEnv *, jclass);
+JNIEXPORT jint JNICALL Java_jmercury_runtime_Native_clk_1tck(JNIEnv *, jclass);
/*
* Class: Native
* Method: get_user_cpu_milliseconds
* Signature: ()I
*/
-JNIEXPORT jint JNICALL Java_mercury_runtime_Native_get_1user_1cpu_1milliseconds(
+JNIEXPORT jint JNICALL Java_jmercury_runtime_Native_get_1user_1cpu_1milliseconds(
JNIEnv *, jclass);
#include "mercury_imp.h"
@@ -63,17 +63,17 @@ JNIEXPORT jint JNICALL Java_mercury_runtime_Native_get_1user_1cpu_1milliseconds(
#endif
JNIEXPORT jint JNICALL
-Java_mercury_runtime_Native_clock(JNIEnv *env, jclass obj) {
+Java_jmercury_runtime_Native_clock(JNIEnv *env, jclass obj) {
return (MR_Integer) clock();
}
JNIEXPORT jint JNICALL
-Java_mercury_runtime_Native_clocks_1per_1sec(JNIEnv *env, jclass obj) {
+Java_jmercury_runtime_Native_clocks_1per_1sec(JNIEnv *env, jclass obj) {
return CLOCKS_PER_SEC;
}
JNIEXPORT jintArray JNICALL
-Java_mercury_runtime_Native_times(JNIEnv *env, jclass obj) {
+Java_jmercury_runtime_Native_times(JNIEnv *env, jclass obj) {
jint intarray[5];
jintArray result;
@@ -97,7 +97,7 @@ Java_mercury_runtime_Native_times(JNIEnv *env, jclass obj) {
return result;
}
-JNIEXPORT jint JNICALL Java_mercury_runtime_Native_clk_1tck(
+JNIEXPORT jint JNICALL Java_jmercury_runtime_Native_clk_1tck(
JNIEnv *env, jclass obj)
{
#if defined(MR_CLOCK_TICKS_PER_SECOND)
@@ -108,7 +108,7 @@ JNIEXPORT jint JNICALL Java_mercury_runtime_Native_clk_1tck(
}
JNIEXPORT jint JNICALL
-Java_mercury_runtime_Native_get_1user_1cpu_1milliseconds(
+Java_jmercury_runtime_Native_get_1user_1cpu_1milliseconds(
JNIEnv *env, jclass obj)
{
return MR_get_user_cpu_milliseconds();
diff --git a/library/Mmakefile b/library/Mmakefile
index a8fc2b8..293d08a 100644
--- a/library/Mmakefile
+++ b/library/Mmakefile
@@ -284,10 +284,11 @@ jars: classes
$(RM) $(STD_LIB_NAME).classes
$(JAR) $(JAR_CREATE_FLAGS) $(RT_LIB_NAME).jar jmercury/runtime/*.class
$(JAR) i $(RT_LIB_NAME).jar
- -+cd jmercury/runtime && mmake $(NATIVE_SO)
- -cp jmercury/runtime/$(NATIVE_SO) .
+ # -+cd jmercury/runtime && mmake $(NATIVE_SO)
+ # -cp jmercury/runtime/$(NATIVE_SO) .
-# This shared object is needed to run some of the standard library methods.
+# This shared object was used to implement some standard library methods,
+# but currently not.
NATIVE_SO = Native.$(EXT_FOR_SHARED_LIB)
#-----------------------------------------------------------------------------#
@@ -536,7 +537,7 @@ ifneq (,$(findstring java,$(GRADE)))
install_library: jars
mkdir -p $(INSTALL_JAVA_LIBRARY_DIR)
cp $(JARS) $(INSTALL_JAVA_LIBRARY_DIR)
- -cp $(NATIVE_SO) $(INSTALL_JAVA_LIBRARY_DIR)
+ # -cp $(NATIVE_SO) $(INSTALL_JAVA_LIBRARY_DIR)
else
diff --git a/library/benchmarking.m b/library/benchmarking.m
index ac9b7fd..d4d1ad9 100644
--- a/library/benchmarking.m
+++ b/library/benchmarking.m
@@ -27,6 +27,10 @@
% some memory and time usage statistics about the time period since
% the last call to report_stats to stderr.
%
+ % Note: in Java, this reports usage of the calling thread. You will get
+ % non-sensical results if the previous call to `report_stats' was from a
+ % different thread.
+ %
% Note: in Erlang, the benchmark_* procedures will change the apparent time
% of the last call to report_stats.
%
@@ -684,26 +688,45 @@ ML_memory_profile_compare_final(const void *i1, const void *i2)
:- pragma foreign_code("Java",
"
-private static int time_at_start = 0;
-private static int time_at_last_stat = 0;
+private static int user_time_at_start = 0;
+private static int user_time_at_last_stat = 0;
+private static long real_time_at_start;
+private static long real_time_at_last_stat;
-static {
- if (jmercury.runtime.Native.isAvailable()) {
- time_at_start = jmercury.runtime.Native.get_user_cpu_milliseconds();
- time_at_last_stat = time_at_start;
- }
+public static void
+ML_initialise()
+{
+ /*
+ ** Class initialisation may be delayed so main() must explicitly initialise
+ ** these variables at startup, otherwise the first call to `report_stats'
+ ** will show the wrong elapsed time.
+ */
+ real_time_at_start = System.currentTimeMillis();
+ real_time_at_last_stat = real_time_at_start;
}
private static void
-ML_report_stats() {
- int time_at_prev_stat = time_at_last_stat;
- time_at_last_stat = get_user_cpu_milliseconds_1_p_0();
-
- System.err.print(""[Time: "" +
- ((time_at_last_stat - time_at_prev_stat) / 1000.0) +
- "", "" +
- ((time_at_last_stat - time_at_start) / 1000.0)
- );
+ML_report_stats()
+{
+ int user_time_at_prev_stat = user_time_at_last_stat;
+ user_time_at_last_stat = ML_get_user_cpu_milliseconds();
+
+ long real_time_at_prev_stat = real_time_at_last_stat;
+ real_time_at_last_stat = System.currentTimeMillis();
+
+ System.err.print(
+ ""[User time: +"" +
+ ((user_time_at_last_stat - user_time_at_prev_stat) / 1000.0) +
+ ""s, "" +
+ ((user_time_at_last_stat - user_time_at_start) / 1000.0) +
+ ""s"");
+
+ System.err.print(
+ "" Real time: +"" +
+ ((real_time_at_last_stat - real_time_at_prev_stat) / 1000.0) +
+ ""s, "" +
+ ((real_time_at_last_stat - real_time_at_start) / 1000.0) +
+ ""s"");
/*
** XXX At this point there should be a whole bunch of memory usage
@@ -715,7 +738,8 @@ ML_report_stats() {
}
private static void
-ML_report_full_memory_stats() {
+ML_report_full_memory_stats()
+{
/*
** XXX The support for this predicate is even worse. Since we don't have
** access to memory usage statistics, all you get here is an apology.
@@ -849,6 +873,9 @@ repeat(N) :-
:- impure pred get_user_cpu_milliseconds(int::out) is det.
+:- pragma foreign_export("Java", get_user_cpu_milliseconds(out),
+ "ML_get_user_cpu_milliseconds").
+
:- pragma foreign_proc("C",
get_user_cpu_milliseconds(Time::out),
[will_not_call_mercury],
@@ -870,14 +897,19 @@ repeat(N) :-
:- pragma foreign_proc("Java",
get_user_cpu_milliseconds(Time::out),
- [will_not_call_mercury],
+ [will_not_call_mercury, may_not_duplicate],
"
- if (jmercury.runtime.Native.isAvailable()) {
- Time = jmercury.runtime.Native.get_user_cpu_milliseconds();
- } else {
- throw new java.lang.RuntimeException(
- ""get_user_cpu_milliseconds is not implemented in pure Java."" +
- ""Native dynamic link library is required."");
+ try {
+ java.lang.management.ThreadMXBean bean =
+ java.lang.management.ManagementFactory.getThreadMXBean();
+ long nsecs = bean.getCurrentThreadUserTime();
+ if (nsecs == -1) {
+ Time = -1;
+ } else {
+ Time = (int) (nsecs / 1000000L);
+ }
+ } catch (java.lang.UnsupportedOperationException e) {
+ Time = -1;
}
").
diff --git a/library/time.m b/library/time.m
index 008d034..4d5aad5 100644
--- a/library/time.m
+++ b/library/time.m
@@ -88,6 +88,8 @@
% cannot be obtained, this procedure will throw a time_error exception.
% To obtain a time in seconds, divide Result by `time.clocks_per_sec'.
%
+ % On Java the elapsed time for the calling thread is returned.
+ %
:- pred time.clock(clock_t::out, io::di, io::uo) is det.
% time.clocks_per_sec:
@@ -124,7 +126,8 @@
% On non-POSIX systems that do not support this functionality,
% this procedure may simply always throw an exception.
%
- % Currently on Win32 the child part of 'tms' is always zero.
+ % On Java the times for the calling thread are returned.
+ % On Win32 and Java the child part of 'tms' is always zero.
%
:- pred time.times(tms::out, clock_t::out, io::di, io::uo) is det.
@@ -279,13 +282,14 @@ time.clock(Result, !IO) :-
time.c_clock(Ret::out, _IO0::di, _IO::uo),
[will_not_call_mercury, promise_pure, tabled_for_io],
"
- if (jmercury.runtime.Native.isAvailable()) {
- Ret = jmercury.runtime.Native.clock();
+ java.lang.management.ThreadMXBean bean =
+ java.lang.management.ManagementFactory.getThreadMXBean();
+ long nsecs = bean.getCurrentThreadCpuTime();
+ if (nsecs == -1) {
+ Ret = -1;
} else {
- throw new java.lang.RuntimeException(
- ""time.clock is not implemented "" +
- ""in pure Java. Native dynamic link "" +
- ""library is required."");
+ /* This must match the definition of clocks_per_sec. */
+ Ret = (int) (nsecs / 1000L);
}
").
@@ -310,14 +314,8 @@ time.clock(Result, !IO) :-
time.clocks_per_sec = (Ret::out),
[will_not_call_mercury, promise_pure, thread_safe],
"
- if (jmercury.runtime.Native.isAvailable()) {
- Ret = jmercury.runtime.Native.clocks_per_sec();
- } else {
- throw new java.lang.RuntimeException(
- ""time.clocks_per_sec is not implemented "" +
- ""in pure Java. Native dynamic link "" +
- ""library is required."");
- }
+ /* Emulate the POSIX value. */
+ Ret = 1000000;
").
%-----------------------------------------------------------------------------%
@@ -390,27 +388,31 @@ time.times(Tms, Result, !IO) :-
:- pragma foreign_proc("Java",
time.c_times(Ret::out, Ut::out, St::out, CUt::out, CSt::out,
_IO0::di, _IO::uo),
- [will_not_call_mercury, promise_pure, tabled_for_io],
+ [will_not_call_mercury, promise_pure, tabled_for_io, may_not_duplicate],
"
- if (jmercury.runtime.Native.isAvailable()) {
- int[] times = jmercury.runtime.Native.times();
- if (times != null) {
- Ret = times[0];
- Ut = times[1];
- St = times[2];
- CUt = times[3];
- CSt = times[4];
+ /* We can only keep the lower 31 bits of the timestamp. */
+ Ret = (int) (System.currentTimeMillis() & 0x7fffffff);
+
+ try {
+ java.lang.management.ThreadMXBean bean =
+ java.lang.management.ManagementFactory.getThreadMXBean();
+ long user_nsecs = bean.getCurrentThreadUserTime();
+ long cpu_nsecs = bean.getCurrentThreadCpuTime();
+ if (user_nsecs == -1 || cpu_nsecs == -1) {
+ Ut = -1;
+ St = -1;
} else {
- throw new java.lang.RuntimeException(
- ""time_times failed to construct "" +
- ""integer array"");
+ /* These units must match the definition of clk_tck. */
+ Ut = (int) (user_nsecs / 1000000L);
+ St = (int) ((cpu_nsecs - user_nsecs) / 1000000L);
}
- } else {
- throw new java.lang.RuntimeException(
- ""time.times is not implemented "" +
- ""in pure Java. Native dynamic link "" +
- ""library is required."");
+ } catch (java.lang.UnsupportedOperationException e) {
+ Ut = -1;
+ St = -1;
}
+
+ CUt = 0;
+ CSt = 0;
").
%-----------------------------------------------------------------------------%
@@ -448,14 +450,11 @@ time.c_clk_tck = -1. % default is to throw an exception.
time.c_clk_tck = (Ret::out),
[will_not_call_mercury, promise_pure, thread_safe],
"
- if (jmercury.runtime.Native.isAvailable()) {
- Ret = jmercury.runtime.Native.clk_tck();
- } else {
- throw new java.lang.RuntimeException(
- ""time.clk_tck is not implemented "" +
- ""in pure Java. Native dynamic link "" +
- ""library is required."");
- }
+ /*
+ ** We use System.currentTimeMillis() to return elapsed time so say that
+ ** there are 1000 clock ticks per second.
+ */
+ Ret = 1000;
").
%-----------------------------------------------------------------------------%
--------------------------------------------------------------------------
mercury-reviews mailing list
Post messages to: mercury-reviews at csse.unimelb.edu.au
Administrative Queries: owner-mercury-reviews at csse.unimelb.edu.au
Subscriptions: mercury-reviews-request at csse.unimelb.edu.au
--------------------------------------------------------------------------
More information about the reviews
mailing list