1 /* 2 * Copyright (c) 2013, 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 24 /* 25 * @test 26 * @bug 6896617 27 * @summary Optimize sun.nio.cs.ISO_8859_1$Encode.encodeArrayLoop() with SSE instructions on x86 28 * @library /testlibrary 29 * @build com.oracle.java.testlibrary.* 30 * @run main/othervm/timeout=1200 -Xbatch -Xmx256m Test6896617 31 * 32 */ 33 34 import com.oracle.java.testlibrary.Utils; 35 import java.nio.ByteBuffer; 36 import java.nio.CharBuffer; 37 import java.nio.charset.Charset; 38 import java.nio.charset.CharsetDecoder; 39 import java.nio.charset.CharsetEncoder; 40 import java.nio.charset.CodingErrorAction; 41 import java.util.Arrays; 42 import java.util.Random; 43 44 public class Test6896617 { 45 final static int SIZE = 256; 46 47 public static void main(String[] args) { 48 String csn = "ISO-8859-1"; 49 Charset cs = Charset.forName(csn); 50 CharsetEncoder enc = cs.newEncoder(); 51 enc.onMalformedInput(CodingErrorAction.REPLACE) 52 .onUnmappableCharacter(CodingErrorAction.REPLACE); 53 CharsetDecoder dec = cs.newDecoder(); 54 dec.onMalformedInput(CodingErrorAction.REPLACE) 55 .onUnmappableCharacter(CodingErrorAction.REPLACE); 56 57 byte repl = (byte)'?'; 58 enc.replaceWith(new byte[] { repl }); 59 60 // Use internal API for tests. 61 sun.nio.cs.ArrayEncoder arrenc = (sun.nio.cs.ArrayEncoder)enc; 62 sun.nio.cs.ArrayDecoder arrdec = (sun.nio.cs.ArrayDecoder)dec; 63 64 // Populate char[] with chars which can be encoded by ISO_8859_1 (<= 0xFF) 65 Random rnd = Utils.getRandomInstance(); 66 int maxchar = 0xFF; 67 char[] a = new char[SIZE]; 68 byte[] b = new byte[SIZE]; 69 char[] at = new char[SIZE]; 70 byte[] bt = new byte[SIZE]; 71 for (int i = 0; i < SIZE; i++) { 72 char c = (char) rnd.nextInt(maxchar); 73 if (!enc.canEncode(c)) { 74 System.out.printf("Something wrong: can't encode c=%03x\n", (int)c); 75 System.exit(97); 76 } 77 a[i] = c; 78 b[i] = (byte)c; 79 at[i] = (char)-1; 80 bt[i] = (byte)-1; 81 } 82 if (arrenc.encode(a, 0, SIZE, bt) != SIZE || !Arrays.equals(b, bt)) { 83 System.out.println("Something wrong: ArrayEncoder.encode failed"); 84 System.exit(97); 85 } 86 if (arrdec.decode(b, 0, SIZE, at) != SIZE || !Arrays.equals(a, at)) { 87 System.out.println("Something wrong: ArrayDecoder.decode failed"); 88 System.exit(97); 89 } 90 for (int i = 0; i < SIZE; i++) { 91 at[i] = (char)-1; 92 bt[i] = (byte)-1; 93 } 94 95 ByteBuffer bb = ByteBuffer.wrap(b); 96 CharBuffer ba = CharBuffer.wrap(a); 97 ByteBuffer bbt = ByteBuffer.wrap(bt); 98 CharBuffer bat = CharBuffer.wrap(at); 99 if (!enc.encode(ba, bbt, true).isUnderflow() || !Arrays.equals(b, bt)) { 100 System.out.println("Something wrong: Encoder.encode failed"); 101 System.exit(97); 102 } 103 if (!dec.decode(bb, bat, true).isUnderflow() || !Arrays.equals(a, at)) { 104 System.out.println("Something wrong: Decoder.decode failed"); 105 System.exit(97); 106 } 107 for (int i = 0; i < SIZE; i++) { 108 at[i] = (char)-1; 109 bt[i] = (byte)-1; 110 } 111 112 // Warm up 113 boolean failed = false; 114 int result = 0; 115 for (int i = 0; i < 10000; i++) { 116 result += arrenc.encode(a, 0, SIZE, bt); 117 result -= arrdec.decode(b, 0, SIZE, at); 118 } 119 for (int i = 0; i < 10000; i++) { 120 result += arrenc.encode(a, 0, SIZE, bt); 121 result -= arrdec.decode(b, 0, SIZE, at); 122 } 123 for (int i = 0; i < 10000; i++) { 124 result += arrenc.encode(a, 0, SIZE, bt); 125 result -= arrdec.decode(b, 0, SIZE, at); 126 } 127 if (result != 0 || !Arrays.equals(b, bt) || !Arrays.equals(a, at)) { 128 failed = true; 129 System.out.println("Failed: ArrayEncoder.encode char[" + SIZE + "] and ArrayDecoder.decode byte[" + SIZE + "]"); 130 } 131 for (int i = 0; i < SIZE; i++) { 132 at[i] = (char)-1; 133 bt[i] = (byte)-1; 134 } 135 136 boolean is_underflow = true; 137 for (int i = 0; i < 10000; i++) { 138 ba.clear(); bb.clear(); bat.clear(); bbt.clear(); 139 boolean enc_res = enc.encode(ba, bbt, true).isUnderflow(); 140 boolean dec_res = dec.decode(bb, bat, true).isUnderflow(); 141 is_underflow = is_underflow && enc_res && dec_res; 142 } 143 for (int i = 0; i < SIZE; i++) { 144 at[i] = (char)-1; 145 bt[i] = (byte)-1; 146 } 147 for (int i = 0; i < 10000; i++) { 148 ba.clear(); bb.clear(); bat.clear(); bbt.clear(); 149 boolean enc_res = enc.encode(ba, bbt, true).isUnderflow(); 150 boolean dec_res = dec.decode(bb, bat, true).isUnderflow(); 151 is_underflow = is_underflow && enc_res && dec_res; 152 } 153 for (int i = 0; i < SIZE; i++) { 154 at[i] = (char)-1; 155 bt[i] = (byte)-1; 156 } 157 for (int i = 0; i < 10000; i++) { 158 ba.clear(); bb.clear(); bat.clear(); bbt.clear(); 159 boolean enc_res = enc.encode(ba, bbt, true).isUnderflow(); 160 boolean dec_res = dec.decode(bb, bat, true).isUnderflow(); 161 is_underflow = is_underflow && enc_res && dec_res; 162 } 163 if (!is_underflow || !Arrays.equals(b, bt) || !Arrays.equals(a, at)) { 164 failed = true; 165 System.out.println("Failed: Encoder.encode char[" + SIZE + "] and Decoder.decode byte[" + SIZE + "]"); 166 } 167 168 // Test encoder with different source and destination sizes 169 System.out.println("Testing different source and destination sizes"); 170 for (int i = 1; i <= SIZE; i++) { 171 for (int j = 1; j <= SIZE; j++) { 172 bt = new byte[j]; 173 // very source's SIZE 174 result = arrenc.encode(a, 0, i, bt); 175 int l = Math.min(i, j); 176 if (result != l) { 177 failed = true; 178 System.out.println("Failed: encode char[" + i + "] to byte[" + j + "]: result = " + result + ", expected " + l); 179 } 180 for (int k = 0; k < l; k++) { 181 if (bt[k] != b[k]) { 182 failed = true; 183 System.out.println("Failed: encoded byte[" + k + "] (" + bt[k] + ") != " + b[k]); 184 } 185 } 186 // very source's offset 187 int sz = SIZE - i + 1; 188 result = arrenc.encode(a, i-1, sz, bt); 189 l = Math.min(sz, j); 190 if (result != l) { 191 failed = true; 192 System.out.println("Failed: encode char[" + sz + "] to byte[" + j + "]: result = " + result + ", expected " + l); 193 } 194 for (int k = 0; k < l; k++) { 195 if (bt[k] != b[i+k-1]) { 196 failed = true; 197 System.out.println("Failed: encoded byte[" + k + "] (" + bt[k] + ") != " + b[i+k-1]); 198 } 199 } 200 } 201 } 202 203 // Test encoder with char > 0xFF 204 System.out.println("Testing big char"); 205 206 byte orig = (byte)'A'; 207 bt = new byte[SIZE]; 208 for (int i = 1; i <= SIZE; i++) { 209 for (int j = 0; j < i; j++) { 210 a[j] += 0x100; 211 // make sure to replace a different byte 212 bt[j] = orig; 213 result = arrenc.encode(a, 0, i, bt); 214 if (result != i) { 215 failed = true; 216 System.out.println("Failed: encode char[" + i + "] to byte[" + i + "]: result = " + result + ", expected " + i); 217 } 218 if (bt[j] != repl) { 219 failed = true; 220 System.out.println("Failed: encoded replace byte[" + j + "] (" + bt[j] + ") != " + repl); 221 } 222 bt[j] = b[j]; // Restore to compare whole array 223 for (int k = 0; k < i; k++) { 224 if (bt[k] != b[k]) { 225 failed = true; 226 System.out.println("Failed: encoded byte[" + k + "] (" + bt[k] + ") != " + b[k]); 227 } 228 } 229 a[j] -= 0x100; // Restore 230 } 231 } 232 233 // Test sun.nio.cs.ISO_8859_1$Encode.encodeArrayLoop() performance. 234 235 int itrs = Integer.getInteger("iterations", 1000000); 236 int size = Integer.getInteger("size", 256); 237 a = new char[size]; 238 b = new byte[size]; 239 bt = new byte[size]; 240 for (int i = 0; i < size; i++) { 241 char c = (char) rnd.nextInt(maxchar); 242 if (!enc.canEncode(c)) { 243 System.out.printf("Something wrong: can't encode c=%03x\n", (int)c); 244 System.exit(97); 245 } 246 a[i] = c; 247 b[i] = (byte)-1; 248 bt[i] = (byte)c; 249 } 250 ba = CharBuffer.wrap(a); 251 bb = ByteBuffer.wrap(b); 252 boolean enc_res = enc.encode(ba, bb, true).isUnderflow(); 253 if (!enc_res || !Arrays.equals(b, bt)) { 254 failed = true; 255 System.out.println("Failed 1: Encoder.encode char[" + size + "]"); 256 } 257 for (int i = 0; i < size; i++) { 258 b[i] = (byte)-1; 259 } 260 261 // Make sure to recompile method if needed before performance run. 262 for (int i = 0; i < 10000; i++) { 263 ba.clear(); bb.clear(); 264 enc_res = enc_res && enc.encode(ba, bb, true).isUnderflow(); 265 } 266 for (int i = 0; i < size; i++) { 267 b[i] = (byte)-1; 268 } 269 for (int i = 0; i < 10000; i++) { 270 ba.clear(); bb.clear(); 271 enc_res = enc_res && enc.encode(ba, bb, true).isUnderflow(); 272 } 273 if (!enc_res || !Arrays.equals(b, bt)) { 274 failed = true; 275 System.out.println("Failed 2: Encoder.encode char[" + size + "]"); 276 } 277 for (int i = 0; i < size; i++) { 278 b[i] = (byte)-1; 279 } 280 281 System.out.println("Testing ISO_8859_1$Encode.encodeArrayLoop() performance"); 282 long start = System.currentTimeMillis(); 283 for (int i = 0; i < itrs; i++) { 284 ba.clear(); bb.clear(); 285 enc_res = enc_res && enc.encode(ba, bb, true).isUnderflow(); 286 } 287 long end = System.currentTimeMillis(); 288 if (!enc_res || !Arrays.equals(b, bt)) { 289 failed = true; 290 System.out.println("Failed 3: Encoder.encode char[" + size + "]"); 291 } else { 292 System.out.println("size: " + size + " time: " + (end - start)); 293 } 294 295 // Test sun.nio.cs.ISO_8859_1$Encode.encode() performance. 296 297 // Make sure to recompile method if needed before performance run. 298 result = 0; 299 for (int i = 0; i < size; i++) { 300 b[i] = (byte)-1; 301 } 302 for (int i = 0; i < 10000; i++) { 303 result += arrenc.encode(a, 0, size, b); 304 } 305 for (int i = 0; i < size; i++) { 306 b[i] = (byte)-1; 307 } 308 for (int i = 0; i < 10000; i++) { 309 result += arrenc.encode(a, 0, size, b); 310 } 311 if (result != size*20000 || !Arrays.equals(b, bt)) { 312 failed = true; 313 System.out.println("Failed 1: ArrayEncoder.encode char[" + SIZE + "]"); 314 } 315 for (int i = 0; i < size; i++) { 316 b[i] = (byte)-1; 317 } 318 319 System.out.println("Testing ISO_8859_1$Encode.encode() performance"); 320 result = 0; 321 start = System.currentTimeMillis(); 322 for (int i = 0; i < itrs; i++) { 323 result += arrenc.encode(a, 0, size, b); 324 } 325 end = System.currentTimeMillis(); 326 if (!Arrays.equals(b, bt)) { 327 failed = true; 328 System.out.println("Failed 2: ArrayEncoder.encode char[" + size + "]"); 329 } else { 330 System.out.println("size: " + size + " time: " + (end - start)); 331 } 332 333 if (failed) { 334 System.out.println("FAILED"); 335 System.exit(97); 336 } 337 System.out.println("PASSED"); 338 } 339 }