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