19feebf2627346eee3a9c6a117d7f279784a51720Orion Hodson/*
29feebf2627346eee3a9c6a117d7f279784a51720Orion Hodson * Copyright (C) 2013 The Android Open Source Project
39feebf2627346eee3a9c6a117d7f279784a51720Orion Hodson *
49feebf2627346eee3a9c6a117d7f279784a51720Orion Hodson * Licensed under the Apache License, Version 2.0 (the "License");
59feebf2627346eee3a9c6a117d7f279784a51720Orion Hodson * you may not use this file except in compliance with the License.
69feebf2627346eee3a9c6a117d7f279784a51720Orion Hodson * You may obtain a copy of the License at
79feebf2627346eee3a9c6a117d7f279784a51720Orion Hodson *
89feebf2627346eee3a9c6a117d7f279784a51720Orion Hodson *      http://www.apache.org/licenses/LICENSE-2.0
99feebf2627346eee3a9c6a117d7f279784a51720Orion Hodson *
109feebf2627346eee3a9c6a117d7f279784a51720Orion Hodson * Unless required by applicable law or agreed to in writing, software
119feebf2627346eee3a9c6a117d7f279784a51720Orion Hodson * distributed under the License is distributed on an "AS IS" BASIS,
129feebf2627346eee3a9c6a117d7f279784a51720Orion Hodson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139feebf2627346eee3a9c6a117d7f279784a51720Orion Hodson * See the License for the specific language governing permissions and
149feebf2627346eee3a9c6a117d7f279784a51720Orion Hodson * limitations under the License.
159feebf2627346eee3a9c6a117d7f279784a51720Orion Hodson */
169feebf2627346eee3a9c6a117d7f279784a51720Orion Hodson
17f95ee7b39f09c13340387e5ae370b57589178b0fBenoit Lamarchepackage com.android.dx.merge;
18f95ee7b39f09c13340387e5ae370b57589178b0fBenoit Lamarche
19f95ee7b39f09c13340387e5ae370b57589178b0fBenoit Lamarcheimport com.android.dex.Dex;
20f95ee7b39f09c13340387e5ae370b57589178b0fBenoit Lamarcheimport com.android.dex.DexIndexOverflowException;
219feebf2627346eee3a9c6a117d7f279784a51720Orion Hodsonimport com.android.dx.command.dexer.DxContext;
22f95ee7b39f09c13340387e5ae370b57589178b0fBenoit Lamarche
23f95ee7b39f09c13340387e5ae370b57589178b0fBenoit Lamarcheimport java.io.File;
246b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodsonimport java.io.IOException;
256b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodson
266b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodsonimport java.util.concurrent.atomic.AtomicBoolean;
276b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodsonimport java.util.concurrent.Executors;
286b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodsonimport java.util.concurrent.ExecutorService;
296b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodsonimport java.util.concurrent.TimeUnit;
30259c2df556dd80998366fc23debb20cbd2d49be3Esteban de la Canalimport java.util.Arrays;
31259c2df556dd80998366fc23debb20cbd2d49be3Esteban de la Canalimport java.util.Random;
326b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodsonimport java.util.HashSet;
33f95ee7b39f09c13340387e5ae370b57589178b0fBenoit Lamarche
34f95ee7b39f09c13340387e5ae370b57589178b0fBenoit Lamarche/**
35259c2df556dd80998366fc23debb20cbd2d49be3Esteban de la Canal * This test tries to merge given dex files at random, a first pass at 2 by 2, followed by
36259c2df556dd80998366fc23debb20cbd2d49be3Esteban de la Canal * a second pass doing multi-way merges.
37f95ee7b39f09c13340387e5ae370b57589178b0fBenoit Lamarche */
38f95ee7b39f09c13340387e5ae370b57589178b0fBenoit Lamarchepublic class MergeTest {
39f95ee7b39f09c13340387e5ae370b57589178b0fBenoit Lamarche
40f95ee7b39f09c13340387e5ae370b57589178b0fBenoit Lamarche  private static final int NUMBER_OF_TRIES = 1000;
41f95ee7b39f09c13340387e5ae370b57589178b0fBenoit Lamarche
426b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodson  private static final int WORKER_THREADS = 4;
436b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodson
446b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodson  private static final ExecutorService executor = Executors.newFixedThreadPool(WORKER_THREADS);
456b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodson
466b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodson  // Helper task to concurrently run merge tests.
476b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodson  static class MergeTask implements Runnable {
486b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodson    private final DexMerger dexMerger;
496b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodson    private final String[] dexFiles;
506b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodson
516b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodson    MergeTask(String[] dexFiles, Dex[] dexesToMerge) throws IOException {
526b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodson      this.dexMerger = new DexMerger(dexesToMerge, CollisionPolicy.KEEP_FIRST, new DxContext());
536b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodson      this.dexFiles = dexFiles;
546b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodson    }
556b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodson
566b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodson    public void run() {
576b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodson      try {
586b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodson        dexMerger.merge();
596b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodson      } catch (DexIndexOverflowException e) {
606b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodson        // ignore index overflow
616b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodson      } catch (Throwable t) {
626b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodson        System.err.println("Exception processing DEX files: " + t);
636b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodson        System.err.println("Problem merging those dexes: " + Arrays.toString(dexFiles));
646b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodson        System.exit(1);
656b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodson      }
666b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodson    }
676b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodson  }
686b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodson
69f95ee7b39f09c13340387e5ae370b57589178b0fBenoit Lamarche  public static void main(String[] args) throws Throwable {
70259c2df556dd80998366fc23debb20cbd2d49be3Esteban de la Canal    Random random = new Random();
716b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodson    HashSet<Integer> seen = new HashSet<>();
72259c2df556dd80998366fc23debb20cbd2d49be3Esteban de la Canal    for (int pass = 0; pass < 2; pass++) {
73259c2df556dd80998366fc23debb20cbd2d49be3Esteban de la Canal      for (int i = 0; i < NUMBER_OF_TRIES; i++) {
74259c2df556dd80998366fc23debb20cbd2d49be3Esteban de la Canal        // On the first pass only do 2-way merges, then do from 3 to 10 way merges
75259c2df556dd80998366fc23debb20cbd2d49be3Esteban de la Canal        // but not more to avoid dex index overflow.
76259c2df556dd80998366fc23debb20cbd2d49be3Esteban de la Canal        int numDex = pass == 0 ? 2 : random.nextInt(8) + 3;
7714c3baea81dbf0141551446d3f83ead8d4acd8f3Tobias Thierer        numDex = Math.min(numDex, args.length);
786b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodson        String[] fileNames = new String[numDex];
796b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodson        for (int j = 0; j < numDex; ++j) {
806b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodson          int fileIndex = random.nextInt(args.length);
816b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodson          fileNames[j] = args[fileIndex];
826b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodson        }
836b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodson
846b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodson        if (!seen.add(fileNames.hashCode())) {
856b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodson          // Skip, already seen set of file names with the same hash.
866b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodson          continue;
876b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodson        }
886b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodson
896b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodson        Dex[] dexesToMerge = new Dex[numDex];
906b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodson        for (int j = 0; j < numDex; ++j) {
916b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodson          try {
926b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodson            dexesToMerge[j] = new Dex(new File(fileNames[j]));
936b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodson          } catch (IOException e) {
946b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodson            System.err.println("Error opening " + fileNames[j]);
956b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodson            System.err.println(e);
966b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodson            System.exit(1);
97259c2df556dd80998366fc23debb20cbd2d49be3Esteban de la Canal          }
98259c2df556dd80998366fc23debb20cbd2d49be3Esteban de la Canal        }
996b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodson        executor.execute(new MergeTask(fileNames, dexesToMerge));
100f95ee7b39f09c13340387e5ae370b57589178b0fBenoit Lamarche      }
101f95ee7b39f09c13340387e5ae370b57589178b0fBenoit Lamarche    }
1026b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodson    executor.shutdown();
1036b8ee006acd3ffb767808d5ca7762f90cca9bd48Orion Hodson    executor.awaitTermination(8, TimeUnit.HOURS);
104f95ee7b39f09c13340387e5ae370b57589178b0fBenoit Lamarche  }
105f95ee7b39f09c13340387e5ae370b57589178b0fBenoit Lamarche}
106