Skip to content

Fractional CPU progress is discarded between processing updates #598

Open

Description

@MathiasRodriguezCastro

Fractional CPU progress is discarded between processing updates

Version: 9.0.0-SNAPSHOT, master 9bb9de25c915264740fea7ae3200303c479e19d6 (after the fix for #556).
Classes: org.cloudsimplus.schedulers.cloudlet.CloudletSchedulerAbstract, org.cloudsimplus.cloudlets.CloudletExecution
Methods: updateCloudletProcessing() (line 555), updateProcessing() (line 259), setLastOverSubscriptionDelay() (line 398).
Environment: Temurin 25.0.5+8, Maven wrapper 3.8.6, Linux x86_64. Reproduced on unmodified official sources.

What happens

The scheduler converts allocated MIPS to an integer, then truncates the work completed in each interval:

final long cloudletUsedMips = (long)getAllocatedMipsForCloudlet(cle, currentTime, true);
final long partialFinishedMI = (long)(cloudletUsedMips * processingTimeSpan);

Fractional work is not retained. Even when updateProcessing(0) returns early, the subsequent call to setLastOverSubscriptionDelay(0) advances the last-processing timestamp. The discarded work is therefore not recovered by accumulating elapsed time. See the scheduler and execution record.

The example below has one PE, one VM of 5 MIPS and one 10-MI cloudlet. Only CPU utilization is set; RAM and BW retain their default null utilization models. There is no network, competing cloudlet or resource oversubscription. It uses new CloudSimPlus(), with the default 0.1 s minimum event interval.

For a 0.125 s scheduling interval and full CPU utilization, each update represents 0.625 MI but credits zero. A second case uses a 1 s interval and 10 % CPU utilization: the positive 0.5-MIPS allocation is truncated to zero before elapsed time is considered.

Standalone reproducer and commands

Save as FractionalProgressReproducer.java in the repository root:

import ch.qos.logback.classic.Level;
import org.cloudsimplus.brokers.DatacenterBrokerSimple;
import org.cloudsimplus.core.CloudSimPlus;
import org.cloudsimplus.resources.PeSimple;
import org.cloudsimplus.schedulers.cloudlet.CloudletSchedulerTimeShared;
import org.cloudsimplus.schedulers.vm.VmSchedulerTimeShared;
import org.cloudsimplus.util.Log;
import java.util.List;
import java.util.Locale;
import org.cloudsimplus.cloudlets.CloudletSimple;
import org.cloudsimplus.datacenters.DatacenterSimple;
import org.cloudsimplus.hosts.HostSimple;
import org.cloudsimplus.utilizationmodels.UtilizationModelDynamic;
import org.cloudsimplus.vms.VmSimple;

public class FractionalProgressReproducer {
    public static void main(String[] args) {
        Log.setLevel(Level.OFF);
        progress(5, 0.125, 1);
        progress(5, 1.0, 1);
        progress(5, 1.0, 0.1);
    }

    private static void progress(double mips, double interval, double utilization) {
        var simulation = new CloudSimPlus();
        simulation.terminateAt(25);
        var host = new HostSimple(2048, 10000, 100000, List.of(new PeSimple(mips)));
        host.setVmScheduler(new VmSchedulerTimeShared());
        var dc = new DatacenterSimple(simulation, List.of(host));
        dc.setSchedulingInterval(interval);
        var broker = new DatacenterBrokerSimple(simulation);
        var vm = new VmSimple(mips, 1);
        vm.setRam(512).setBw(1000).setSize(1000).setCloudletScheduler(new CloudletSchedulerTimeShared());
        var cloudlet = new CloudletSimple(10, 1);
        cloudlet.setUtilizationModelCpu(new UtilizationModelDynamic(utilization));
        cloudlet.setFileSize(1).setOutputSize(1);
        broker.submitVm(vm);
        broker.submitCloudlet(cloudlet);
        simulation.start();
        System.out.printf(Locale.ROOT,
            "{\"mode\":\"progress\",\"mips\":%.3f,\"utilization\":%.3f,\"interval\":%.3f,\"start\":%.6f,\"finish\":%.6f,\"credited_mi\":%d,\"finished\":%s,\"clock\":%.6f}%n",
            mips, utilization, interval, cloudlet.getStartTime(), cloudlet.getFinishTime(),
            cloudlet.getFinishedLengthSoFar(), cloudlet.isFinished(), simulation.clock());
    }

}

Using JDK 25, from a checkout of the commit above:

./mvnw -q -DskipTests compile dependency:build-classpath -DincludeScope=runtime -Dmdep.outputFile=target/reproducer-classpath.txt
CLOUDSIM_REPRO_CP="target/classes:$(cat target/reproducer-classpath.txt)"
javac -cp "$CLOUDSIM_REPRO_CP" FractionalProgressReproducer.java
java -cp ".:$CLOUDSIM_REPRO_CP" FractionalProgressReproducer

Why it matters

The official-source run prints these results; the program requests termination at 25 s and also prints the final clock:

CPU utilization Scheduling interval (s) Credited MI Finish timestamp (s)
100 % 0.125 0 -1, unfinished
100 % 1.0 10 2.200
10 % 1.0 0 -1, unfinished

Changing the update interval can prevent an otherwise feasible task from making any progress. This can also arise under time sharing when individual allocations become small. The example does not require reducing the simulator's minimum event interval below its default, and 0.125 is exactly representable in binary; it isolates a concrete work-accounting mechanism rather than the general small-interval sensitivity discussed in #533.

As a diagnostic, keeping MIPS as a double and carrying the fractional MI made the first and third cases finish at 2.100 s and 20.100 s, respectively. Restoring the original sources reproduced zero progress. This is separate from the blocked-cloudlet CPU-sharing fix in #556.

Suggested fix

Keep allocated MIPS as a double and preserve the fractional work per cloudlet execution record. The basic accounting is:

double exactMI = allocatedMips * elapsedSeconds + remainderMI;
long completedMI = (long) exactMI;
remainderMI = exactMI - completedMI;

This is an accounting sketch, not a complete patch. Only eligible CPU-execution intervals should accrue work; packet waiting and resource-oversubscription delays must not. Whole-cloudlet and network-task counters must stay consistent at task boundaries and removal.

A regression should compare repeated sub-MI updates with one combined interval under constant allocation, cover positive allocations below 1 MIPS, and verify that packet-waiting cloudlets still accrue no CPU progress.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions