You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@joshua.apache.org by mj...@apache.org on 2016/08/30 21:04:50 UTC

[05/17] incubator-joshua git commit: Merge branch 'master' into 7-with-master

http://git-wip-us.apache.org/repos/asf/incubator-joshua/blob/b0b70627/joshua-core/src/test/java/org/apache/joshua/packed/Benchmark.java
----------------------------------------------------------------------
diff --cc joshua-core/src/test/java/org/apache/joshua/packed/Benchmark.java
index 41cf2a0,0000000..7c4fc80
mode 100644,000000..100644
--- a/joshua-core/src/test/java/org/apache/joshua/packed/Benchmark.java
+++ b/joshua-core/src/test/java/org/apache/joshua/packed/Benchmark.java
@@@ -1,126 -1,0 +1,132 @@@
 +/*
 + * Licensed to the Apache Software Foundation (ASF) under one
 + * or more contributor license agreements.  See the NOTICE file
 + * distributed with this work for additional information
 + * regarding copyright ownership.  The ASF licenses this file
 + * to you under the Apache License, Version 2.0 (the
 + * "License"); you may not use this file except in compliance
 + * with the License.  You may obtain a copy of the License at
 + *
 + *  http://www.apache.org/licenses/LICENSE-2.0
 + *
 + * Unless required by applicable law or agreed to in writing,
 + * software distributed under the License is distributed on an
 + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 + * KIND, either express or implied.  See the License for the
 + * specific language governing permissions and limitations
 + * under the License.
 + */
 +package org.apache.joshua.packed;
 +
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- 
 +import java.io.File;
 +import java.io.FileInputStream;
 +import java.io.IOException;
 +import java.nio.IntBuffer;
 +import java.nio.MappedByteBuffer;
 +import java.nio.channels.FileChannel;
 +import java.nio.channels.FileChannel.MapMode;
 +import java.util.Random;
 +
++import org.slf4j.Logger;
++import org.slf4j.LoggerFactory;
++
 +/**
 + * This program runs a little benchmark to check reading speed on various data
 + * representations.
-  * 
++ *
 + * Usage: java Benchmark PACKED_GRAMMAR_DIR TIMES
 + */
 +
- public class Benchmark {
++public class Benchmark implements AutoCloseable{
 +
-   
 +  private static final Logger LOG = LoggerFactory.getLogger(Benchmark.class);
 +
 +  private IntBuffer intBuffer;
 +  private MappedByteBuffer byteBuffer;
 +  private int[] intArray;
++  private final FileInputStream fin;
 +
 +  public Benchmark(String dir) throws IOException {
 +    File file = new File(dir + "/slice_00000.source");
- 
-     FileChannel source_channel = new FileInputStream(file).getChannel();
++    this.fin = new FileInputStream(file);
++    FileChannel source_channel = this.fin.getChannel();
 +    int byte_size = (int) source_channel.size();
 +    int int_size = byte_size / 4;
 +
-     byteBuffer = source_channel.map(MapMode.READ_ONLY, 0, byte_size); 
++    byteBuffer = source_channel.map(MapMode.READ_ONLY, 0, byte_size);
 +    intBuffer = byteBuffer.asIntBuffer();
 +
 +    intArray = new int[int_size];
 +    intBuffer.get(intArray);
 +  }
 +
 +  public void benchmark(int times) {
 +    LOG.info("Beginning benchmark.");
 +
 +    Random r = new Random();
 +    r.setSeed(1234567890);
 +    int[] positions = new int[1000];
 +    for (int i = 0; i < positions.length; i++)
 +      positions[i] = r.nextInt(intArray.length);
 +
 +    long sum;
 +
 +    long start_time = System.currentTimeMillis();
 +
 +    sum = 0;
 +    for (int t = 0; t < times; t++)
 +      for (int i = 0; i < positions.length; i++)
 +        sum += byteBuffer.getInt(positions[i] * 4);
 +    LOG.info("Sum: {}", sum);
 +    long byte_time = System.currentTimeMillis();
 +
 +    sum = 0;
 +    for (int t = 0; t < times; t++)
 +      for (int i = 0; i < positions.length; i++)
 +        sum += intBuffer.get(positions[i]);
 +    LOG.info("Sum: {}", sum);
 +    long int_time = System.currentTimeMillis();
 +
 +    sum = 0;
 +    for (int t = 0; t < times; t++)
 +      for (int i = 0; i < positions.length; i++)
 +        sum += intArray[positions[i]];
 +    LOG.info("Sum: {}", sum);
 +    long array_time = System.currentTimeMillis();
 +
 +    sum = 0;
 +    for (int t = 0; t < times; t++)
 +      for (int i = 0; i < (intArray.length / 8); i++)
 +        sum += intArray[i * 6] + intArray[i * 6 + 2];
 +    LOG.info("Sum: {}", sum);
 +    long mult_time = System.currentTimeMillis();
 +
 +    sum = 0;
 +    for (int t = 0; t < times; t++) {
 +      int index = 0;
 +      for (int i = 0; i < (intArray.length / 8); i++) {
 +        sum += intArray[index] + intArray[index + 2];
 +        index += 6;
 +      }
 +    }
 +    LOG.info("Sum: {}", sum);
 +    long add_time = System.currentTimeMillis();
 +
 +    LOG.info("ByteBuffer: {}", (byte_time - start_time));
 +    LOG.info("IntBuffer:  {}", (int_time - byte_time));
 +    LOG.info("Array:      {}", (array_time - int_time));
 +    LOG.info("Multiply:   {}", (mult_time - array_time));
 +    LOG.info("Add:        {}", (add_time - mult_time));
 +  }
 +
 +  public static void main(String args[]) throws IOException {
-     Benchmark pr = new Benchmark(args[0]);
-     pr.benchmark( Integer.parseInt(args[1]));
++    try (Benchmark pr = new Benchmark(args[0]);) {
++      pr.benchmark( Integer.parseInt(args[1]));
++    }
++  }
++
++  @Override
++  public void close() throws IOException {
++    this.fin.close();
 +  }
 +}

http://git-wip-us.apache.org/repos/asf/incubator-joshua/blob/b0b70627/joshua-core/src/test/java/org/apache/joshua/system/MultithreadedTranslationTests.java
----------------------------------------------------------------------
diff --cc joshua-core/src/test/java/org/apache/joshua/system/MultithreadedTranslationTests.java
index 10872d0,0000000..01d3963
mode 100644,000000..100644
--- a/joshua-core/src/test/java/org/apache/joshua/system/MultithreadedTranslationTests.java
+++ b/joshua-core/src/test/java/org/apache/joshua/system/MultithreadedTranslationTests.java
@@@ -1,180 -1,0 +1,180 @@@
 +/*
 + * Licensed to the Apache Software Foundation (ASF) under one
 + * or more contributor license agreements.  See the NOTICE file
 + * distributed with this work for additional information
 + * regarding copyright ownership.  The ASF licenses this file
 + * to you under the Apache License, Version 2.0 (the
 + * "License"); you may not use this file except in compliance
 + * with the License.  You may obtain a copy of the License at
 + *
 + *  http://www.apache.org/licenses/LICENSE-2.0
 + *
 + * Unless required by applicable law or agreed to in writing,
 + * software distributed under the License is distributed on an
 + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 + * KIND, either express or implied.  See the License for the
 + * specific language governing permissions and limitations
 + * under the License.
 + */
 +package org.apache.joshua.system;
 +
++import static org.mockito.Mockito.doReturn;
++import static org.testng.Assert.assertTrue;
++
 +import java.io.BufferedReader;
 +import java.io.ByteArrayInputStream;
 +import java.io.ByteArrayOutputStream;
 +import java.io.IOException;
 +import java.io.InputStreamReader;
- import java.nio.charset.Charset;
++import java.nio.charset.StandardCharsets;
 +import java.util.ArrayList;
 +
 +import org.apache.joshua.decoder.Decoder;
 +import org.apache.joshua.decoder.JoshuaConfiguration;
 +import org.apache.joshua.decoder.Translation;
 +import org.apache.joshua.decoder.TranslationResponseStream;
 +import org.apache.joshua.decoder.io.TranslationRequestStream;
 +import org.apache.joshua.decoder.segment_file.Sentence;
 +import org.mockito.Mockito;
 +import org.testng.annotations.AfterClass;
 +import org.testng.annotations.BeforeClass;
 +import org.testng.annotations.Test;
 +
- import static org.mockito.Mockito.doReturn;
- import static org.testng.Assert.assertTrue;
- 
 +/**
 + * Integration test for multithreaded Joshua decoder tests. Grammar used is a
 + * toy packed grammar.
 + *
 + * @author Kellen Sunderland kellen.sunderland@gmail.com
 + */
 +public class MultithreadedTranslationTests {
 +
 +  private JoshuaConfiguration joshuaConfig = null;
 +  private Decoder decoder = null;
 +  private static final String INPUT = "A K B1 U Z1 Z2 B2 C";
 +  private static final String EXCEPTION_MESSAGE = "This exception should properly propagate";
 +  private int previousLogLevel;
 +  private final static long NANO_SECONDS_PER_SECOND = 1_000_000_000;
 +
 +  @BeforeClass
 +  public void setUp() throws Exception {
 +    joshuaConfig = new JoshuaConfiguration();
 +    joshuaConfig.search_algorithm = "cky";
 +    joshuaConfig.mark_oovs = false;
 +    joshuaConfig.pop_limit = 100;
 +    joshuaConfig.use_unique_nbest = false;
 +    joshuaConfig.include_align_index = false;
 +    joshuaConfig.topN = 0;
 +    joshuaConfig.tms.add("thrax -owner pt -maxspan 20 -path src/test/resources/wa_grammar.packed");
 +    joshuaConfig.tms.add("thrax -owner glue -maxspan -1 -path src/test/resources/grammar.glue");
 +    joshuaConfig.goal_symbol = "[GOAL]";
 +    joshuaConfig.default_non_terminal = "[X]";
 +    joshuaConfig.features.add("OOVPenalty");
 +    joshuaConfig.weights.add("tm_pt_0 1");
 +    joshuaConfig.weights.add("tm_pt_1 1");
 +    joshuaConfig.weights.add("tm_pt_2 1");
 +    joshuaConfig.weights.add("tm_pt_3 1");
 +    joshuaConfig.weights.add("tm_pt_4 1");
 +    joshuaConfig.weights.add("tm_pt_5 1");
 +    joshuaConfig.weights.add("tm_glue_0 1");
 +    joshuaConfig.weights.add("OOVPenalty 2");
 +    joshuaConfig.num_parallel_decoders = 500; // This will enable 500 parallel
 +                                              // decoders to run at once.
 +                                              // Useful to help flush out
 +                                              // concurrency errors in
 +                                              // underlying
 +                                              // data-structures.
 +    this.decoder = new Decoder(joshuaConfig);
 +    previousLogLevel = Decoder.VERBOSE;
 +    Decoder.VERBOSE = 0;
 +  }
 +
 +  @AfterClass
 +  public void tearDown() throws Exception {
 +    this.decoder.cleanUp();
 +    this.decoder = null;
 +    Decoder.VERBOSE = previousLogLevel;
 +  }
 +
 +
 +
 +  // This test was created specifically to reproduce a multithreaded issue
 +  // related to mapped byte array access in the PackedGrammer getAlignmentArray
 +  // function.
 +
 +  // We'll test the decoding engine using N = 10,000 identical inputs. This
 +  // should be sufficient to induce concurrent data access for many shared
 +  // data structures.
 +
 +  @Test()
 +  public void givenPackedGrammar_whenNTranslationsCalledConcurrently_thenReturnNResults() throws IOException {
 +    // GIVEN
 +
 +    int inputLines = 10000;
 +    joshuaConfig.use_structured_output = true; // Enabled alignments.
 +    StringBuilder sb = new StringBuilder();
 +    for (int i = 0; i < inputLines; i++) {
 +      sb.append(INPUT + "\n");
 +    }
 +
 +    // Append a large string together to simulate N requests to the decoding
 +    // engine.
 +    TranslationRequestStream req = new TranslationRequestStream(
 +        new BufferedReader(new InputStreamReader(new ByteArrayInputStream(sb.toString()
-         .getBytes(Charset.forName("UTF-8"))))), joshuaConfig);
-     
++        .getBytes(StandardCharsets.UTF_8)))), joshuaConfig);
++
 +    ByteArrayOutputStream output = new ByteArrayOutputStream();
 +
 +    // WHEN
 +    // Translate all segments in parallel.
 +    TranslationResponseStream translationResponseStream = this.decoder.decodeAll(req);
 +
 +    ArrayList<Translation> translationResults = new ArrayList<Translation>();
 +
 +
 +    final long translationStartTime = System.nanoTime();
 +    try {
 +      for (Translation t: translationResponseStream)
 +        translationResults.add(t);
 +    } finally {
 +      if (output != null) {
 +        try {
 +          output.close();
 +        } catch (IOException e) {
 +          e.printStackTrace();
 +        }
 +      }
 +    }
 +
 +    final long translationEndTime = System.nanoTime();
 +    final double pipelineLoadDurationInSeconds = (translationEndTime - translationStartTime)
 +            / ((double)NANO_SECONDS_PER_SECOND);
 +    System.err.println(String.format("%.2f seconds", pipelineLoadDurationInSeconds));
 +
 +    // THEN
 +    assertTrue(translationResults.size() == inputLines);
 +  }
 +
 +  @Test(expectedExceptions = RuntimeException.class,
 +          expectedExceptionsMessageRegExp = EXCEPTION_MESSAGE)
 +  public void givenDecodeAllCalled_whenRuntimeExceptionThrown_thenPropagate() throws IOException {
 +    // GIVEN
 +    // A spy request stream that will cause an exception to be thrown on a threadpool thread
 +    TranslationRequestStream spyReq = Mockito.spy(new TranslationRequestStream(null, joshuaConfig));
 +    doReturn(createSentenceSpyWithRuntimeExceptions()).when(spyReq).next();
 +
 +    // WHEN
 +    // Translate all segments in parallel.
 +    TranslationResponseStream translationResponseStream = this.decoder.decodeAll(spyReq);
 +
 +    ArrayList<Translation> translationResults = new ArrayList<>();
 +    for (Translation t: translationResponseStream)
 +      translationResults.add(t);
 +  }
 +
 +  private Sentence createSentenceSpyWithRuntimeExceptions() {
 +    Sentence sent = new Sentence(INPUT, 0, joshuaConfig);
 +    Sentence spy = Mockito.spy(sent);
 +    Mockito.when(spy.target()).thenThrow(new RuntimeException(EXCEPTION_MESSAGE));
 +    return spy;
 +  }
 +}