2

I am experiencing the following problem. In a simplest way put I have a servlet and a java class in my web app. Now the java class iterates over the list applying some logic to each element. I also keep a counter to keep track of handled elements. I propagate the counter value to another class that servlet has access to via a setter. From my servlet I do AJAX calls to retrieve the number of handled element and show a progress bar.

int counter = 0;
...
for(SecurityForWorkflow securityForWorkflow : newSecuritiesForWorkflow) {
    ...
    WorkflowManager.getInstance().setProcessedSecurities(counter);
    counter++;
    ...
}

The problem is that the progress bar is not smooth, it may go from 1 to 56 to 100. My guess is that JIT somehow optimizes the flow by seeing that no one accesses(gets) the counter and moves the increment out of the loop. I came to this conclusion since When debugging the loop everything goes smooth(I assume JIT cant change the flow when debugging) but when I run it and output the values into a log file with timestamps, the counter increments from 0 to the overall value instantaneously/simultaneously even thou the loop runs for 20 second(170 iterations case).

My question is whether it is possible to disable JIT optimizations for a code segment(e.g. via annotations, but googling suggests that it is not) or maybe enforce non-optimization via a language construct/trick(i tried declaring the variable static, volatile, putting the loop in a synchronized block, calling the setter within a newly spawned thread every time, putting the setter in the finally block of a try-catch and some more I cant remember now and works if I put a Thread.sleep(1000) in the loop).

UPDATE: Here is the code of the loop

Also I updated the WorkflowManager.getInstance().setProcessedSecurities(counter); with WorkflowManager.getInstance().incProcessedSecurities(); bit the result is the same

for(SecurityForWorkflow securityForWorkflow : newSecuritiesForWorkflow) {
        ManualInteractionEntity manualInteractionEntity = null;
        BondEntityStatus createdBond = null;
        LegEntity createdLeg = null;
        isin = securityForWorkflow.getIsin();
        try {
          automatedSecurityBuildingStatus = securityBuilder.createBondEntity(
              isin, businessDay);
          if(automatedSecurityBuildingStatus.getBondEntityStatus()
              .getAssetType() != null
              && automatedSecurityBuildingStatus.getBondEntityStatus()
              .getEcbStatus() != null) {
            createdBond = automatedSecurityBuildingStatus.getBondEntityStatus();
          }
          else {
            removeFromSecuritiesForWorkflow.add(securityForWorkflow);
          }
        } catch(Exception e) {
          NabsLogger.getInstance().log(Level.WARNING, String.format("Exception"
              + " when creating security with isin: %s", isin), e);
          continue;
        }finally{
          WorkflowManager.getInstance().incProcessedSecurities();
        }
        try {
          createdLeg = createdBond.getLegEntities().get(0);
        } catch (Exception e) {
          createdLeg = createdBond.getLegEntityStatus();
        }

        if (createdBond.getSetupStatus().equals(
            Constants.MANUAL_INTERACTION_NEEDED)) {
          manualInteractionEntity = new ManualInteractionEntity();
          securityForWorkflow.addStatus(
              SecurityForWorkflow.STATUS_MANUAL_INTERACTION_NEEDED);
          manualInteractionEntity.setId(createdBond.getId());
          manualInteractionEntity.setCreation(true);
          Set<String> manualInteractionFields = automatedSecurityBuildingStatus
              .getManualInteractionRuleResults().keySet();
          manualInteractionEntity.setManualInteractionFields(
              new ArrayList<String>(manualInteractionFields));
          manualInteractionEntities.add(manualInteractionEntity);
        } else if (createdBond.getSetupStatus().equals(
            Constants.CREATED_AUTOMATICALLY)) {
          securityForWorkflow.addStatus(
              SecurityForWorkflow.STATUS_AUTOMATICALLY_BUILT);
        }
        PaymentDateCalculatorModel paymentDateCalculatorModel = 
            new PaymentDateCalculatorModel();
        paymentDateCalculatorModel.setAllDates(createdBond);
        PaymentProfileCalculatorModel paymentProfileCalculatorModel = 
            new PaymentProfileCalculatorModel();
        paymentProfileCalculatorModel.setAllPayments(createdBond);
        entities.add(createdBond);
        legs.add(createdLeg);
       }

Thanks.

5
  • 2
    Passing counter as a parameter to setProcessedSecurities is an access and this would not get optimized away. I would not immediately suspect anything JIT-optimization related here. Something else is going on here that involves code that is not in your snippet. E.g. if there's some kind of threading, event caching, high CPU load, something else going on, and say, the logging in debug mode provides sufficient delay for other things to happen that makes the problem "seem" to go away. I am 99.999% sure the problem is not what you think. You may have to do some serious debugging on your own. Commented Nov 26, 2014 at 7:46
  • 1
    If it isn't working as expected when JITtted you either have found a bug in the VM you are using or you have some threading issue with your code - and I strongly suspect the latter. But there is not near enough code to get a clear idea of what goes wrong. Commented Nov 26, 2014 at 7:49
  • That said see stackoverflow.com/questions/4004340/… and also oracle.com/technetwork/java/javase/tech/… (links to Java 8 options are on that page as well). If you are using a different JVM see its associated documentation for related options. stackoverflow.com/questions/7738794/add-jvm-options-in-tomcat describes how to set JVM options through Tomcat. Commented Nov 26, 2014 at 7:51
  • 1
    Thanks for your replies. I tried the option mentioned in link but it did not help so I thought decided to repost this to get more info. @JasonC I'll dig deeper in code then. This is legacy code and I am bound to java6. One of my guesses was that it is some kind of a race condition after it worked with Thread.sleep(1000). It's surely not high CPU load and I'll check for event caching but the same code gives the same results when put in a test file(no servlet/progress bar used) and tested with JUnit. Commented Nov 26, 2014 at 10:09
  • You could try and print the values of counter in the loop along with a timestamp and compare those with the values you get from the AJAX. It is possible that the AJAX calls dont materialize as often as you think. Another think to check is weather making counter volatile makes a difference. Commented Nov 26, 2014 at 17:08

1 Answer 1

-1

Try making the counter volatile or even better an AtomicInteger.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks but I tried both of them but it is not solving the issue.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.