1 /*
2  * Copyright (c) 2014 Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 package org.openjdk.bench.vm.lambda.invoke;
24 
25 import org.openjdk.jmh.annotations.Benchmark;
26 import org.openjdk.jmh.annotations.BenchmarkMode;
27 import org.openjdk.jmh.annotations.Mode;
28 import org.openjdk.jmh.annotations.OperationsPerInvocation;
29 import org.openjdk.jmh.annotations.OutputTimeUnit;
30 
31 import java.util.concurrent.TimeUnit;
32 import java.util.function.BinaryOperator;
33 
34 /**
35  * evaluates invocation costs in case of long recursive chains
36  *
37  * @author Sergey Kuksenko (sergey.kuksenko@oracle.com)
38  */
39 @BenchmarkMode(Mode.AverageTime)
40 @OutputTimeUnit(TimeUnit.NANOSECONDS)
41 public class AckermannL {
42 
43     // ackermann(1,1748)+ ackermann(2,1897)+ ackermann(3,8); == 9999999 calls
44     public static final int Y1 = 1748;
45     public static final int Y2 = 1897;
46     public static final int Y3 = 8;
47 
ack(Integer x, Integer y)48     public static Integer ack(Integer x, Integer y) {
49         return x == 0 ?
50                 y + 1 :
51                 (y == 0 ?
52                         ack(x - 1, 1) :
53                         ack(x - 1, ack(x, y - 1)));
54     }
55 
56     @Benchmark
57     @OperationsPerInvocation(9999999)
func()58     public Integer func() {
59         return ack(1, Y1) + ack(2, Y2) + ack(3, Y3);
60     }
61 
62     public static final BinaryOperator<Integer> inner_ack =
63             new BinaryOperator<Integer>() {
64                 @Override
65                 public Integer apply(Integer x, Integer y) {
66                     return x == 0 ?
67                             y + 1 :
68                             (y == 0 ?
69                                     inner_ack.apply(x - 1, 1) :
70                                     inner_ack.apply(x - 1, inner_ack.apply(x, y - 1)));
71                 }
72             };
73 
74     @Benchmark
75     @OperationsPerInvocation(9999999)
inner()76     public Integer inner() {
77         return inner_ack.apply(1, Y1) + inner_ack.apply(2, Y2) + inner_ack.apply(3, Y3);
78     }
79 
80     public static final BinaryOperator<Integer> lambda_ack =
81             (x, y) -> x == 0 ?
82                     y + 1 :
83                     (y == 0 ?
84                             AckermannL.lambda_ack.apply(x - 1, 1) :
85                             AckermannL.lambda_ack.apply(x - 1, AckermannL.lambda_ack.apply(x, y - 1)));
86 
87 
88     @Benchmark
89     @OperationsPerInvocation(9999999)
lambda()90     public Integer lambda() {
91         return lambda_ack.apply(1, Y1) + lambda_ack.apply(2, Y2) + lambda_ack.apply(3, Y3);
92     }
93 
94     public static final BinaryOperator<Integer> mref_ack = AckermannL::mref_ack_helper;
95 
mref_ack_helper(Integer x, Integer y)96     public static Integer mref_ack_helper(Integer x, Integer y) {
97         return x == 0 ?
98                 y + 1 :
99                 (y == 0 ?
100                         mref_ack.apply(x - 1, 1) :
101                         mref_ack.apply(x - 1, mref_ack.apply(x, y - 1)));
102     }
103 
104     @Benchmark
105     @OperationsPerInvocation(9999999)
mref()106     public Integer mref() {
107         return mref_ack.apply(1, Y1) + mref_ack.apply(2, Y2) + mref_ack.apply(3, Y3);
108     }
109 
110     public static final BinaryOperator<Integer> mref_ackIII = AckermannL::mref_ack_helperIII;
111 
mref_ack_helperIII(int x, int y)112     public static int mref_ack_helperIII(int x, int y) {
113         return x == 0 ?
114                 y + 1 :
115                 (y == 0 ?
116                         mref_ackIII.apply(x - 1, 1) :
117                         mref_ackIII.apply(x - 1, mref_ackIII.apply(x, y - 1)));
118     }
119 
120     @Benchmark
121     @OperationsPerInvocation(9999999)
mrefIII()122     public Integer mrefIII() {
123         return mref_ackIII.apply(1, Y1) + mref_ackIII.apply(2, Y2) + mref_ackIII.apply(3, Y3);
124     }
125 
126 }
127 
128