简体   繁体   中英

How can I fix callable overlapping in Java?

I'm not sure whether the title is detail/correct or not but i can't figure out how to describe it in the title so I will try my best to describe it here

I've been trying to use callable in Java for concurrency, but the outcome is not correct, seem like the thread has been over lapping each other while running...below is the call function for that

@Override
public String call() {
    String result = "yay";
    long startTime = System.currentTimeMillis();
    long endTime = startTime + timeOutMiliseconds * 1000;
    while (System.currentTimeMillis() < endTime) {
        int[] currentMapping = generateTpuMappingWithRange(ia, startRange, stopRange);
        System.out.println(" current - " + Arrays.toString(currentMapping) + " - " +  ID);
        result = Arrays.toString(currentMapping);
    }
    return result;
}

generateTpuMappingWithRange() function is just generate another random integer array with the first index from startRange -> stopRange

(ie startRange = 0, stopRange = 2, then [0, 2, 1,] -> [1, 2, 1] or [2,2,1])

constructor

public MarkovTest(int ID, int startRange, int stopRange) {
    this.ID = ID;
    this.startRange = startRange;
    this.stopRange = stopRange;
    init();
}

Here is main

public static void main(String[] args) throws InterruptedException, ExecutionException {
    Callable<String> Array = new MarkovTest(1, 0, 1);
    Callable<String> Array2 = new MarkovTest(2, 2, 3);
    Callable<String> Array3 = new MarkovTest(3, 4, 5);

    List<Callable<String>> taskList = Arrays.asList(Array,Array2,Array3);

    List<Future<String>> future = executor.invokeAll(taskList);
    for(Future<String> result : future)
    {
        System.out.println(result.get());
    }
}

the number in the last is the ID variable is to check whether it's printing out the correct one or not...however here is the problem, in the console, this happen...

 current - [0, 3, 5, 0, 5, 4, 3, 2, 1, 4, 6, 1, 3, 6] - 1
 current - [1, 3, 5, 0, 5, 4, 3, 2, 1, 4, 6, 1, 3, 6] - 3
 current - [0, 3, 5, 0, 5, 4, 2, 2, 0, 4, 6, 1, 3, 6] - 1
 current - [0, 3, 5, 0, 5, 4, 3, 2, 0, 4, 6, 1, 3, 6] - 2

1st line is correct, ID 1 should print array with first index in range 0 to 1. But ID 3 and 2 should not have the 0 or 1 in the first index...this doesn't happen all the time but will appear here and there among thousand of console output

Any idea why is this happening? I'm really stressed because of this...T__T

Edit: Added generateTpuMappingWithRange

private int[] generateTpuMappingWithRange(int[] iap, int startRange, int stopRange) {
    final Logger log = Logger.getLogger(MarkovTest.class);

    int maximumNoOfCoreIndex = 6;
    int minimumNoOfCoreIndex = 0;
    int firstIndex = 0;
    int[] result = iap;
    log.debug("OLD MAPPING = " + Arrays.toString(result));
    // generate random
    Random randomNum = new Random();
    // generate number from 0 -> 13 (because last number will always be 6)
    int randomIndex = randomNum.nextInt(iap.length - 1);
    // last one will always be 6 so dont need to include that
    int minusOrPlus = 0;
    minusOrPlus = randomNum.nextBoolean() ? 1 : -1;
    Task thisTask = this.model.getSwModel().getTasks().get(randomIndex);
    PuType thisTaskPuType = domains.get(thisTask);
    int[] newIndexValueRange = this.intervals.get(thisTaskPuType);

    minimumNoOfCoreIndex = newIndexValueRange[0];
    maximumNoOfCoreIndex = newIndexValueRange[1];
    int newIndexValue = result[randomIndex] + minusOrPlus;
    // Split 0-1, 2-3, 4-5 for 3 markov chain.
    if (randomIndex == firstIndex) {
        if (newIndexValue > stopRange) {
            newIndexValue = startRange;
        } else if (newIndexValue < startRange) {
            newIndexValue = stopRange;
        }
    } else {
        if (newIndexValue > maximumNoOfCoreIndex) {
            newIndexValue = minimumNoOfCoreIndex;
        } else if (newIndexValue < minimumNoOfCoreIndex) {
            newIndexValue = maximumNoOfCoreIndex;
        }
    }
    // if the new index value generated from line above surpass our maximum no of
    // core, then it will return to number 0
    // This may resolve to infinite loop if THE SAME randomIndex appear again and
    // again and again and again, which hopefully wont be a thing for this
    // implementation

    result[randomIndex] = newIndexValue;
    log.debug("NEW MAPPING = " + Arrays.toString(result));
    log.debug(" location =" + randomIndex + " value =" + newIndexValue);
    return result;
}

Here is the full Version of the code just in case.

init() method is basically generate 2 HashMap, mainly used to determine the maxmimum and minimum value for each index.

public class MarkovTest implements Callable<String> {
static ExecutorService executor = Executors.newFixedThreadPool(3);

int startRange;
int stopRange;
long timeOutMiliseconds = 1000;
long maxIteration;
Amalthea model;
int[] ia;
int ID;
private final int nbCPUs;
private final int nbPUs;
private final HashMap<Task, PuType> domains = new HashMap<Task, PuType>();
private final HashMap<PuType, int[]> intervals = new HashMap<PuType, int[]>();   

public MarkovTest(int[] ia, Amalthea model, int ID, int startRange, int stopRange) {
    this.model = model;
    this.ia = ia;
    this.nbCPUs = CommonUtils.getNumberofCPUs(model);
    // this.nbGPUs = CommonUtils.getNumberofGPUs(this.model);
    this.nbPUs = CommonUtils.getNumberofPUs(model);
    this.ID = ID;
    this.startRange = startRange;
    this.stopRange = stopRange;
    init();
}

public static void main(String[] args) throws InterruptedException, ExecutionException {
    org.apache.log4j.BasicConfigurator.configure();
    Logger.getRootLogger().setLevel(Level.INFO);
    long startTime = System.currentTimeMillis();
    int[] ia = { 5, 2, 5, 3, 3, 1, 3, 5, 1, 0, 0, 6, 4, 6 };
    final Amalthea ama = AmaltheaLoader.loadFromFile(new File(SharedConsts.ECRTS_MODEL));

    Callable<String> Array = new MarkovTest(ia, ama, 1, 0, 1);
    Callable<String> Array2 = new MarkovTest(ia, ama, 2, 2, 3);
    Callable<String> Array3 = new MarkovTest(ia, ama, 3, 4, 5);

    List<Callable<String>> taskList = Arrays.asList(Array,Array2,Array3);

    List<Future<String>> future = executor.invokeAll(taskList);
    for(Future<String> result : future)
    {
        System.out.println(result.get());
    }
    long endTime = System.currentTimeMillis();
    long elapsedTime = endTime - startTime;
    System.out.println(" elapsed Time = " + elapsedTime);
    System.out.println("Done");
}

@Override
public String call() {
    String result = "yay";
    long startTime = System.currentTimeMillis();
    long endTime = startTime + timeOutMiliseconds * 1000;
    while (System.currentTimeMillis() < endTime) {
        int[] currentMapping = generateTpuMappingWithRange(ia, startRange, stopRange);
        System.out.println(" current - " + Arrays.toString(currentMapping) + " - " +  ID);
        result = Arrays.toString(currentMapping);
    }
    return result;
}

private int[] generateTpuMappingWithRange(int[] iap, int startRange, int stopRange) {
    final Logger log = Logger.getLogger(MarkovTest.class);

    int maximumNoOfCoreIndex = 6;
    int minimumNoOfCoreIndex = 0;
    int firstIndex = 0;
    int[] result = iap;
    log.debug("OLD MAPPING = " + Arrays.toString(result));
    // generate random
    Random randomNum = new Random();
    // generate number from 0 -> 13 (because last number will always be 6)
    int randomIndex = randomNum.nextInt(iap.length - 1);
    // last one will always be 6 so dont need to include that
    int minusOrPlus = 0;
    minusOrPlus = randomNum.nextBoolean() ? 1 : -1;
    Task thisTask = this.model.getSwModel().getTasks().get(randomIndex);
    PuType thisTaskPuType = domains.get(thisTask);
    int[] newIndexValueRange = this.intervals.get(thisTaskPuType);

    minimumNoOfCoreIndex = newIndexValueRange[0];
    maximumNoOfCoreIndex = newIndexValueRange[1];
    int newIndexValue = result[randomIndex] + minusOrPlus;
    // Split 0-4, 5-10, 11-13 for 3 markov chain.
    if (randomIndex == firstIndex) {
        if (newIndexValue > stopRange) {
            newIndexValue = startRange;
        } else if (newIndexValue < startRange) {
            newIndexValue = stopRange;
        }
    } else {
        if (newIndexValue > maximumNoOfCoreIndex) {
            newIndexValue = minimumNoOfCoreIndex;
        } else if (newIndexValue < minimumNoOfCoreIndex) {
            newIndexValue = maximumNoOfCoreIndex;
        }
    }
    // if the new index value generated from line above surpass our maximum no of
    // core, then it will return to number 0
    // This may resolve to infinite loop if THE SAME randomIndex appear again and
    // again and again and again, which hopefully wont be a thing for this
    // implementation

    result[randomIndex] = newIndexValue;
    log.debug("NEW MAPPING = " + Arrays.toString(result));
    log.debug(" location =" + randomIndex + " value =" + newIndexValue);
    return result;
}

private void init() {
    final Logger log = Logger.getLogger(CallableForMarkov.class);
    for (final Task t : this.model.getSwModel().getTasks()) {
        boolean cpu = false;
        boolean gpu = false;
        boolean defaultVal = false;
        for (final CallGraphItem geb : t.getCallGraph().getItems()) {
            if (geb instanceof Group) {
                final Group cs = (Group) geb;
                for (final CallGraphItem csi : cs.getItems()) {
                    if (csi instanceof RunnableCall) {
                        final RunnableCall trc = (RunnableCall) csi;
                        for (final CallGraphItem ri : trc.getRunnable().getRunnableItems()) {
                            if (ri instanceof Ticks) {
                                final Ticks ticks = (Ticks) ri;
                                if (null != ticks.getDefault() && ticks.getDefault().getAverage() > 0) {
                                    defaultVal = true;
                                }
                                for (final Entry<ProcessingUnitDefinition, IDiscreteValueDeviation> e : ticks
                                        .getExtended().entrySet()) {
                                    if (!gpu && e.getKey().getPuType().equals(PuType.GPU)) {
                                        gpu = true;
                                    } else if (!cpu && e.getKey().getPuType().equals(PuType.CPU)) {
                                        cpu = true;
                                    }
                                }
                            }
                        }
                        // TODO check if there are runnables with different tick vals
                    }
                }
            }
        }
        if (cpu && !gpu) {
            /* task can be mapped only to CPUs */
            log.debug(t.getName() + " can be mapped to 0 --" + (this.nbCPUs - 1));
            this.domains.put(t, PuType.CPU);
            if (!this.intervals.containsKey(PuType.CPU)) {
                this.intervals.put(PuType.CPU, new int[] { 0, this.nbCPUs - 1 });
            }
        } else if (gpu && !cpu) {
            /* task can be mapped only to GPUs */
            log.debug(t.getName() + " can be mapped to " + this.nbCPUs + "--" + (this.nbPUs - 1));
            this.domains.put(t, PuType.GPU);
            if (!this.intervals.containsKey(PuType.GPU)) {
                this.intervals.put(PuType.GPU, new int[] { this.nbCPUs, this.nbPUs - 1 });
            }
        } else if (defaultVal || (gpu && cpu)) {
            /* task can be mapped anywhere */
            log.debug(t.getName() + " can be mapped to 0 --" + (this.nbPUs - 1));
            this.domains.put(t, PuType._UNDEFINED_);
            if (!this.intervals.containsKey(PuType._UNDEFINED_)) {
                this.intervals.put(PuType._UNDEFINED_, new int[] { 0, this.nbPUs - 1 });
            }
        } else {
            /* Task can be mapped nowhere */
            log.fatal(t.getName() + " can be mapped nowhere");
        }
    }
}

}

Take a look at my inline comments within your code excerpts:

public static void main(String[] args) throws InterruptedException, ExecutionException {
    org.apache.log4j.BasicConfigurator.configure();
    Logger.getRootLogger().setLevel(Level.INFO);
    long startTime = System.currentTimeMillis();   

    //-----> You have created an instance of ia
    int[] ia = { 5, 2, 5, 3, 3, 1, 3, 5, 1, 0, 0, 6, 4, 6 };
    final Amalthea ama = AmaltheaLoader.loadFromFile(new File(SharedConsts.ECRTS_MODEL));  

//-----> You have passed the _same_ instance to all of the constructor calls
    Callable<String> Array = new MarkovTest(ia, ama, 1, 0, 1);
    Callable<String> Array2 = new MarkovTest(ia, ama, 2, 2, 3);
    Callable<String> Array3 = new MarkovTest(ia, ama, 3, 4, 5);  
    ...    

 //---->lets move a bit down to the method that's called within the Callable  

private int[] generateTpuMappingWithRange(int[] iap, int startRange, int stopRange) {  
   ...    
  int firstIndex = 0;
   ...  
   int randomIndex = random.nextInt(iap.length - 1);  
   ...  
 //---> this part should make sure what you are stating, that "ID 1 should print array with first index in range 0 to 1." and this is correct
   if (randomIndex == firstIndex) {

        if (newIndexValue > stopRange) {
            newIndexValue = startRange;
        } else if (newIndexValue < startRange) {
            newIndexValue = stopRange;
        }

    }  else {
        if (newIndexValue > maximumNoOfCoreIndex) {
            newIndexValue = minimumNoOfCoreIndex;
        } else if (newIndexValue < minimumNoOfCoreIndex) {
            newIndexValue = maximumNoOfCoreIndex;
        }
    }
       ...

However, as I mentioned in the code above, you have passed the same ia instance to all of the constructor calls.

This means that all 3 MarkovTest instance will operate on the same ia , modifying it individually, so the rule you have set regarding to the first element of the array does not work.

For example, when a MarkovTest with ID=2 got a randomIndex == firstIndex , so it modifies the ia 's first index accordingly, then it prints ia with the updated and correct new first value .

After that, a MarkovTest with ID=1 runs, which gets randomIndex != firstIndex , so it modifies the value of ia at randomIndex , then prints ia , with the previously updated and now incorrect first value , along with the untouched values as well as the correctly updated new value at randomIndex .

This cycle repeats till System.currentTimeMillis() < endTime for each MarkovTest .

Solution:

There are several solutions, as you pass the same instance to all 3 MarkovTest , you can initialize ia directly within the class, and no need for that constructor parameter.

If you insist on having the constructor parameter, then you can:

int[] ia_copy;  

public MarkovTest(int[] ia, Amalthea model, int ID, int startRange, int stopRange) {
    this.model = model;  

    //----> create a copy like this:
    ia_copy=new int[ia.length];
    System.arraycopy( ia, 0, ia_copy, 0, ia.length );  

    this.nbCPUs = CommonUtils.getNumberofCPUs(model);
    // this.nbGPUs = CommonUtils.getNumberofGPUs(this.model);
    this.nbPUs = CommonUtils.getNumberofPUs(model);
    this.ID = ID;
    this.startRange = startRange;
    this.stopRange = stopRange;
    init();
}

Just don't forget to change all the references, especially at:

@Override
public String call() {
...
while (System.currentTimeMillis() < endTime) {  
//----> ia to ia_copy 
        int[] currentMapping = generateTpuMappingWithRange(ia_copy , startRange, stopRange);  
...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM