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