Skip to content

Commit b0b6589

Browse files
committed
Adds Java to the performance measurement.
1 parent fc49eac commit b0b6589

File tree

3 files changed

+245
-16
lines changed

3 files changed

+245
-16
lines changed

src/generators/java.ml

Lines changed: 136 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,6 @@ open Core.Prog
2626

2727
let runtime =
2828
{%pla|
29-
import java.util.Arrays;
30-
import java.util.Random;
3129

3230
static int clip(int x, int minv, int maxv) {
3331
if(x > maxv)
@@ -286,6 +284,15 @@ let rec print_exp e =
286284
| ECall { path = "not"; args = [ e1 ] } ->
287285
let e1 = print_exp e1 in
288286
{%pla|!(<#e1#>)|}
287+
| ECall { path = "real"; args = [ e1 ] } ->
288+
let e1 = print_exp e1 in
289+
{%pla|(float)(<#e1#>)|}
290+
| ECall { path = "int"; args = [ e1 ] } ->
291+
let e1 = print_exp e1 in
292+
{%pla|(int)(<#e1#>)|}
293+
| ECall { path = "bool"; args = [ e1 ] } ->
294+
let e1 = print_exp e1 in
295+
{%pla|((<#e1#>) != 0)|}
289296
| ECall { path; args } ->
290297
let args = Pla.map_sep Pla.commaspace print_exp args in
291298
{%pla|<#path#s>(<#args#>)|}
@@ -427,17 +434,30 @@ let print_arg ({ name; t; _ } : param) =
427434
{%pla|<#t#> <#name#s>|}
428435

429436

430-
let print_function_def (def : function_def) =
437+
let print_function_def ?(force_public = false) ?(is_performance = false) (def : function_def) =
431438
let name = def.name in
432439
let args = Pla.map_sep Pla.commaspace print_arg def.args in
433440
let ret = print_type_ (snd def.t) in
434441
let visibility =
435-
if def.info.is_root then
442+
if def.info.is_root || force_public then
436443
"public"
444+
else if is_performance && String.contains name '_' then
445+
(* Make _alloc and _default functions public for performance template *)
446+
let suffix = String.sub name (String.rindex name '_') (String.length name - String.rindex name '_') in
447+
if suffix = "_alloc" || suffix = "_default" then
448+
"public"
449+
else
450+
"private"
437451
else
438452
"private"
439453
in
440-
{%pla|<#visibility#s> static <#ret#> <#name#s>(<#args#>) {|}
454+
let static_keyword =
455+
if is_performance then
456+
""
457+
else
458+
"static "
459+
in
460+
{%pla|<#visibility#s> <#static_keyword#s><#ret#> <#name#s>(<#args#>) {|}
441461

442462

443463
let print_body body =
@@ -485,12 +505,39 @@ let print_struct_def { path; members; _ } =
485505
{%pla|public static class <#path#s> {<#members_decl#+><#default_constructor#+><#param_constructor#+>}|}
486506

487507

488-
let print_top_stmt (_args : Util.Args.args) t =
508+
(* Generate type alias as inheritance *)
509+
let print_type_alias alias_name base_name =
510+
{%pla|public static class <#alias_name#s> extends <#base_name#s> {
511+
public <#alias_name#s>() { super(); }
512+
}|}
513+
514+
515+
let print_top_stmt (args : Util.Args.args) t =
489516
match t.top with
490-
| TopFunction (def, body) ->
491-
let def = print_function_def def in
492-
let body = print_body body in
493-
{%pla|<#def#><#body#><#><#>|}
517+
| TopFunction (func_def, body) ->
518+
let is_performance = args.template = Some "performance" in
519+
let force_public = is_performance in
520+
let def = print_function_def ~force_public ~is_performance func_def in
521+
let name = func_def.name in
522+
(* Check if this is a type alias allocation function *)
523+
if String.contains name '_' && CCString.suffix ~suf:"_type_alloc" name && List.length func_def.args > 0 then
524+
let parts = String.split_on_char '_' name in
525+
let len = List.length parts in
526+
if len >= 4 then
527+
(* This is a type alias allocation function - override body to create correct type *)
528+
let name_len = String.length name in
529+
let alias_type = String.sub name 0 (name_len - 6) in
530+
(* Remove "_alloc" *)
531+
let body = {%pla|
532+
return new <#alias_type#s>();
533+
}|} in
534+
{%pla|<#def#><#body#><#><#>|}
535+
else
536+
let body = print_body body in
537+
{%pla|<#def#><#body#><#><#>|}
538+
else
539+
let body = print_body body in
540+
{%pla|<#def#><#body#><#><#>|}
494541
| TopExternal _ -> Pla.unit
495542
| TopType descr -> print_struct_def descr
496543
| TopAlias _ -> Pla.unit
@@ -500,12 +547,58 @@ let print_top_stmt (_args : Util.Args.args) t =
500547
{%pla|public static final <#t#> <#name#s> = <#rhs#>;<#>|}
501548

502549

503-
let print_prog args t = Pla.map_join (print_top_stmt args) t
550+
(* Collect type aliases needed based on function signatures *)
551+
let collect_type_aliases stmts =
552+
let aliases = ref [] in
553+
let collect_from_stmt stmt =
554+
match stmt.top with
555+
| TopFunction (def, _) ->
556+
let name = def.name in
557+
(* Look for pattern: *_function_type_alloc that takes arguments (indicating it's a type alias) *)
558+
if String.contains name '_' && CCString.suffix ~suf:"_type_alloc" name && List.length def.args > 0 then
559+
let parts = String.split_on_char '_' name in
560+
(* Handle patterns like Module_noteOn_type_alloc or Module_submodule_pulse_start_type_alloc *)
561+
let len = List.length parts in
562+
if len >= 4 then
563+
(* Check for various patterns including perf variants *)
564+
if len >= 5 && List.nth parts (len - 4) = "perf" then
565+
(* Handle perf patterns like Module_perf_noteOn_type_alloc *)
566+
let module_parts = CCList.take (len - 4) parts in
567+
let module_name = String.concat "_" module_parts in
568+
let name_len = String.length name in
569+
let alias_type = String.sub name 0 (name_len - 6) in
570+
(* Remove "_alloc" *)
571+
let base_type = module_name ^ "_perf_process_type" in
572+
aliases := (alias_type, base_type) :: !aliases
573+
else
574+
(* Handle regular patterns like Module_noteOn_type_alloc or Module_pulse_start_type_alloc *)
575+
let module_parts = CCList.take (len - 3) parts in
576+
let module_name = String.concat "_" module_parts in
577+
let name_len = String.length name in
578+
let alias_type = String.sub name 0 (name_len - 6) in
579+
(* Remove "_alloc" *)
580+
let base_type = module_name ^ "_process_type" in
581+
aliases := (alias_type, base_type) :: !aliases
582+
| _ -> ()
583+
in
584+
List.iter collect_from_stmt stmts;
585+
!aliases
586+
587+
588+
let print_prog args t =
589+
let aliases = collect_type_aliases t in
590+
let main_code = Pla.map_join (print_top_stmt args) t in
591+
let alias_code = Pla.map_sep_all Pla.newline (fun (alias, base) -> print_type_alias alias base) aliases in
592+
if aliases = [] then
593+
main_code
594+
else
595+
{%pla|<#main_code#><#alias_code#+>|}
596+
504597

505598
let getTemplateCode (args : Util.Args.args) =
506599
match args.template with
507600
| None -> Pla.unit, Pla.unit
508-
| Some "performance" -> Pla.unit, Pla.unit (* TODO: implement T_performance.generateJava *)
601+
| Some "performance" -> T_performance.generateJava args
509602
| Some name -> Util.Error.raiseErrorMsg ("Unknown template '" ^ name ^ "'")
510603

511604

@@ -523,15 +616,42 @@ let generate (args : Util.Args.args) (stmts : top_stmt list) =
523616
in
524617
let code = print_prog args stmts in
525618
let pre, post = getTemplateCode args in
526-
let full_code =
527-
{%pla|
619+
match args.template with
620+
| Some "performance" ->
621+
(* For performance template, generate two files: main class and performance test *)
622+
let main_code =
623+
{%pla|
528624
package <#package_name#s>;
529625

626+
import java.util.Arrays;
627+
import java.util.Random;
628+
629+
public class <#class_name#s> {
530630
<#runtime#>
631+
<#code#>
632+
}
633+
|}
634+
in
635+
let perf_file = Common.setExt "Perf.java" args.output in
636+
let perf_code = {%pla|
637+
package <#package_name#s>;
638+
639+
<#post#>
640+
|} in
641+
[ main_code, file; perf_code, perf_file ]
642+
| _ ->
643+
(* Regular template or no template *)
644+
let full_code =
645+
{%pla|
646+
package <#package_name#s>;
647+
648+
import java.util.Arrays;
649+
import java.util.Random;
531650

532651
public class <#class_name#s> {
652+
<#runtime#>
533653
<#pre#><#code#><#post#>
534654
}
535655
|}
536-
in
537-
[ full_code, file ]
656+
in
657+
[ full_code, file ]

src/generators/t_performance.ml

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,3 +195,54 @@ measure_performance()
195195

196196

197197
let generateJulia (args : Util.Args.args) = Pla.unit, juliaPost args
198+
199+
let javaPost (args : Util.Args.args) =
200+
let module_name =
201+
match args.files with
202+
| Util.Args.File s :: _ -> Pparser.Parse.moduleName s
203+
| _ -> "Top"
204+
in
205+
let class_name =
206+
match args.output with
207+
| Some output -> String.capitalize_ascii (Filename.basename (Filename.remove_extension output))
208+
| None -> "VultCode"
209+
in
210+
{%pla|
211+
public class <#module_name#s>Perf {
212+
public static void main(String[] args) {
213+
<#class_name#s> vult = new <#class_name#s>();
214+
<#class_name#s>.<#module_name#s>_process_type data = vult.<#module_name#s>_process_type_alloc();
215+
vult.<#module_name#s>_default(data);
216+
217+
double time = <#time#f>;
218+
int samples = (int)(44100 * time);
219+
220+
// Warm up - run iterations to allow JVM JIT compilation
221+
for (int i = 0; i < 10000; i++) {
222+
vult.<#module_name#s>_process(data, (float)0.0);
223+
}
224+
225+
// Actual performance measurement
226+
long startTime = System.nanoTime();
227+
double acc = 0.0;
228+
double ramp = 0.0;
229+
230+
for (int i = 0; i < samples; i++) {
231+
ramp += 0.001;
232+
if (ramp > 1.0) {
233+
ramp = ramp - 1.0;
234+
}
235+
acc += vult.<#module_name#s>_process(data, (float)ramp);
236+
}
237+
238+
long endTime = System.nanoTime();
239+
double elapsedSeconds = (endTime - startTime) / 1_000_000_000.0;
240+
double msPerSecond = (elapsedSeconds / time) * 1000.0;
241+
242+
System.out.printf("<#module_name#s>\tJava\t%.2f ms/s\n", msPerSecond);
243+
}
244+
}
245+
|}
246+
247+
248+
let generateJava (args : Util.Args.args) = Pla.unit, javaPost args

test/perf.ml

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,21 @@ let generateJulia (filename : string) (output : string) : unit =
165165
CCList.iter (Driver.Cli.showResult args) output
166166

167167

168+
let generateJava (filename : string) (output : string) : unit =
169+
let args =
170+
{ default_arguments with
171+
files = [ File filename ]
172+
; code = JavaCode
173+
; output = Some output
174+
; real = Float
175+
; template = Some "performance"
176+
; includes
177+
}
178+
in
179+
let output = Driver.Cli.driver args in
180+
CCList.iter (Driver.Cli.showResult args) output
181+
182+
168183
let realString f =
169184
match f with
170185
| Fixed -> "fixed"
@@ -231,6 +246,48 @@ let runJulia vultfile =
231246
| e -> showError e
232247

233248

249+
[@@@warning "-32"]
250+
251+
let runJava vultfile =
252+
try
253+
let output = Filename.chop_extension (Filename.basename vultfile) in
254+
let module_name = Pparser.Parse.moduleName vultfile in
255+
let class_name = String.capitalize_ascii output in
256+
Sys.chdir tmp_dir;
257+
generateJava vultfile output;
258+
(* Now we have two files: output.java and outputPerf.java *)
259+
let main_java_file = output ^ ".java" in
260+
let perf_java_file = output ^ "Perf.java" in
261+
let proper_main_file = class_name ^ ".java" in
262+
let proper_perf_file = module_name ^ "Perf.java" in
263+
(* Rename files to match class names *)
264+
Sys.rename main_java_file proper_main_file;
265+
Sys.rename perf_java_file proper_perf_file;
266+
(* Create package directory *)
267+
ignore (Sys.command "mkdir -p vult");
268+
(* Compile both Java files *)
269+
let compile_cmd = "javac " ^ proper_main_file ^ " " ^ proper_perf_file in
270+
if Sys.command compile_cmd <> 0 then (
271+
(* If compilation fails, print a warning but don't fail the whole test *)
272+
Printf.eprintf "Warning: Java compilation failed for %s\n%!" module_name;
273+
Printf.printf "%s\tJava\tCompilation Failed\n%!" module_name)
274+
else (
275+
(* Move class files to package directory *)
276+
ignore (Sys.command "mv *.class vult/");
277+
(* Run the performance test *)
278+
let run_cmd = "java -cp . vult." ^ module_name ^ "Perf" in
279+
ignore (Sys.command run_cmd));
280+
(* Clean up *)
281+
(try Sys.remove proper_main_file with
282+
| _ -> ());
283+
(try Sys.remove proper_perf_file with
284+
| _ -> ());
285+
ignore (Sys.command "rm -rf vult/");
286+
Sys.chdir init_dir
287+
with
288+
| e -> showError e
289+
290+
234291
let runInterpreter vultfile =
235292
try
236293
let module_name = Pparser.Parse.moduleName vultfile in
@@ -269,6 +326,7 @@ let main () =
269326
runLua f;
270327
runJs f;
271328
runJulia f;
329+
runJava f;
272330
runInterpreter f)
273331
files
274332

0 commit comments

Comments
 (0)