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.

Sp3c7r00M
  • 79
  • 8
  • 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. – Jason C Nov 26 '14 at 07: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. – piet.t Nov 26 '14 at 07:49
  • That said see http://stackoverflow.com/questions/4004340/disable-java-jit-for-a-specific-method-class and also http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html (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. http://stackoverflow.com/questions/7738794/add-jvm-options-in-tomcat describes how to set JVM options through Tomcat. – Jason C Nov 26 '14 at 07:51
  • 1
    Thanks for your replies. I tried the option mentioned in [link](http://stackoverflow.com/questions/4004340/disable-java-jit-for-a-specific-method-class) 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. – Sp3c7r00M Nov 26 '14 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. – David Soroko Nov 26 '14 at 17:08

1 Answers1

-1

Try making the counter volatile or even better an AtomicInteger.

David Soroko
  • 8,521
  • 2
  • 39
  • 51